diff --git a/dist/attachReleaseAssets/index.js b/dist/attachReleaseAssets/index.js index 5d245d9b..72b00f2a 100644 --- a/dist/attachReleaseAssets/index.js +++ b/dist/attachReleaseAssets/index.js @@ -125790,7 +125790,7 @@ const exeSuffix = process.platform == "win32" ? ".exe" : ""; * Tries to get a unique artifact name or otherwise as appropriate as possible */ function getArtifactName() { - const fileName = core.getInput("artifact-name"); + const fileName = getArtifactNameInput(); // if there is an explicit filename just return it, this could cause issues // where earlier sboms are overwritten by later ones if (fileName) { @@ -125839,6 +125839,12 @@ function getArtifactName() { return `${repo}-${job}${stepName}.${extension}`; } exports.getArtifactName = getArtifactName; +/** + * Returns the artifact-name input value + */ +function getArtifactNameInput() { + return core.getInput("artifact-name"); +} /** * Gets a reference to the syft command and executes the syft action * @param input syft input parameters @@ -126143,9 +126149,18 @@ function uploadDependencySnapshot() { const sha = getSha(); const client = (0, GithubClient_1.getClient)(repo, core.getInput("github-token")); const snapshot = JSON.parse(fs.readFileSync(githubDependencySnapshotFile).toString("utf8")); + let correlator = `${workflow}_${job}`; + // if running in a matrix build, it is not possible to determine a unique value, + // so a user must explicitly specify the artifact-name input, there isn't any + // other indicator of being run within a matrix build, so we must use that + // here in order to properly correlate dependency snapshots + const artifactInput = getArtifactNameInput(); + if (artifactInput) { + correlator += `_${artifactInput}`; + } // Need to add the job and repo details snapshot.job = { - correlator: core.getInput("dependency-snapshot-correlator") || `${workflow}_${job}`, + correlator: core.getInput("dependency-snapshot-correlator") || correlator, id: `${runId}`, }; snapshot.sha = sha; diff --git a/dist/downloadSyft/index.js b/dist/downloadSyft/index.js index 0c69e185..e80a918b 100644 --- a/dist/downloadSyft/index.js +++ b/dist/downloadSyft/index.js @@ -125838,7 +125838,7 @@ const exeSuffix = process.platform == "win32" ? ".exe" : ""; * Tries to get a unique artifact name or otherwise as appropriate as possible */ function getArtifactName() { - const fileName = core.getInput("artifact-name"); + const fileName = getArtifactNameInput(); // if there is an explicit filename just return it, this could cause issues // where earlier sboms are overwritten by later ones if (fileName) { @@ -125887,6 +125887,12 @@ function getArtifactName() { return `${repo}-${job}${stepName}.${extension}`; } exports.getArtifactName = getArtifactName; +/** + * Returns the artifact-name input value + */ +function getArtifactNameInput() { + return core.getInput("artifact-name"); +} /** * Gets a reference to the syft command and executes the syft action * @param input syft input parameters @@ -126191,9 +126197,18 @@ function uploadDependencySnapshot() { const sha = getSha(); const client = (0, GithubClient_1.getClient)(repo, core.getInput("github-token")); const snapshot = JSON.parse(fs.readFileSync(githubDependencySnapshotFile).toString("utf8")); + let correlator = `${workflow}_${job}`; + // if running in a matrix build, it is not possible to determine a unique value, + // so a user must explicitly specify the artifact-name input, there isn't any + // other indicator of being run within a matrix build, so we must use that + // here in order to properly correlate dependency snapshots + const artifactInput = getArtifactNameInput(); + if (artifactInput) { + correlator += `_${artifactInput}`; + } // Need to add the job and repo details snapshot.job = { - correlator: core.getInput("dependency-snapshot-correlator") || `${workflow}_${job}`, + correlator: core.getInput("dependency-snapshot-correlator") || correlator, id: `${runId}`, }; snapshot.sha = sha; diff --git a/dist/runSyftAction/index.js b/dist/runSyftAction/index.js index 9519feda..70d9ef3d 100644 --- a/dist/runSyftAction/index.js +++ b/dist/runSyftAction/index.js @@ -125790,7 +125790,7 @@ const exeSuffix = process.platform == "win32" ? ".exe" : ""; * Tries to get a unique artifact name or otherwise as appropriate as possible */ function getArtifactName() { - const fileName = core.getInput("artifact-name"); + const fileName = getArtifactNameInput(); // if there is an explicit filename just return it, this could cause issues // where earlier sboms are overwritten by later ones if (fileName) { @@ -125839,6 +125839,12 @@ function getArtifactName() { return `${repo}-${job}${stepName}.${extension}`; } exports.getArtifactName = getArtifactName; +/** + * Returns the artifact-name input value + */ +function getArtifactNameInput() { + return core.getInput("artifact-name"); +} /** * Gets a reference to the syft command and executes the syft action * @param input syft input parameters @@ -126143,9 +126149,18 @@ function uploadDependencySnapshot() { const sha = getSha(); const client = (0, GithubClient_1.getClient)(repo, core.getInput("github-token")); const snapshot = JSON.parse(fs.readFileSync(githubDependencySnapshotFile).toString("utf8")); + let correlator = `${workflow}_${job}`; + // if running in a matrix build, it is not possible to determine a unique value, + // so a user must explicitly specify the artifact-name input, there isn't any + // other indicator of being run within a matrix build, so we must use that + // here in order to properly correlate dependency snapshots + const artifactInput = getArtifactNameInput(); + if (artifactInput) { + correlator += `_${artifactInput}`; + } // Need to add the job and repo details snapshot.job = { - correlator: core.getInput("dependency-snapshot-correlator") || `${workflow}_${job}`, + correlator: core.getInput("dependency-snapshot-correlator") || correlator, id: `${runId}`, }; snapshot.sha = sha; diff --git a/src/github/SyftGithubAction.ts b/src/github/SyftGithubAction.ts index 65012a24..ce08b0ad 100644 --- a/src/github/SyftGithubAction.ts +++ b/src/github/SyftGithubAction.ts @@ -36,7 +36,7 @@ const exeSuffix = process.platform == "win32" ? ".exe" : ""; * Tries to get a unique artifact name or otherwise as appropriate as possible */ export function getArtifactName(): string { - const fileName = core.getInput("artifact-name"); + const fileName = getArtifactNameInput(); // if there is an explicit filename just return it, this could cause issues // where earlier sboms are overwritten by later ones @@ -93,6 +93,13 @@ export function getArtifactName(): string { return `${repo}-${job}${stepName}.${extension}`; } +/** + * Returns the artifact-name input value + */ +function getArtifactNameInput() { + return core.getInput("artifact-name"); +} + /** * Gets a reference to the syft command and executes the syft action * @param input syft input parameters @@ -443,10 +450,19 @@ export async function uploadDependencySnapshot(): Promise { fs.readFileSync(githubDependencySnapshotFile).toString("utf8") ) as DependencySnapshot; + let correlator = `${workflow}_${job}`; + // if running in a matrix build, it is not possible to determine a unique value, + // so a user must explicitly specify the artifact-name input, there isn't any + // other indicator of being run within a matrix build, so we must use that + // here in order to properly correlate dependency snapshots + const artifactInput = getArtifactNameInput(); + if (artifactInput) { + correlator += `_${artifactInput}`; + } + // Need to add the job and repo details snapshot.job = { - correlator: - core.getInput("dependency-snapshot-correlator") || `${workflow}_${job}`, + correlator: core.getInput("dependency-snapshot-correlator") || correlator, id: `${runId}`, }; snapshot.sha = sha; diff --git a/tests/integration/GitHubSnapshot.test.ts b/tests/integration/GitHubSnapshot.test.ts index 747c9f3d..17fb1eb8 100644 --- a/tests/integration/GitHubSnapshot.test.ts +++ b/tests/integration/GitHubSnapshot.test.ts @@ -67,6 +67,7 @@ describe("GitHub Snapshot", () => { const data = requestArgs[1].data; const submission = JSON.parse(data); + expect(submission.job.correlator).toEqual("my-workflow_default-import-job") expect(submission.scanned).toBeDefined(); // redact changing data @@ -75,4 +76,90 @@ describe("GitHub Snapshot", () => { expect(submission).toMatchSnapshot(); }); + + it("runs with artifact-name input", async () => { + setData({ + inputs: { + path: "tests/fixtures/npm-project", + "dependency-snapshot": "true", + "upload-artifact": "false", + "artifact-name": "my-matrix-build-1", + }, + context: { + ...context.push({ + ref: "main", + }), + sha: "f293f09uaw90gwa09f9wea", + workflow: "my-workflow", + job: "default-import-job", + action: "__anchore_sbom-action", + }, + }); + + await action.runSyftAction(); + await action.uploadDependencySnapshot(); + + // validate the request was made + expect(requestArgs).toBeDefined(); + expect(requestArgs).toHaveLength(2); + expect(requestArgs[0]).toBe("POST /repos/test-org/test-repo/dependency-graph/snapshots"); + + // check the resulting snapshot file + const data = requestArgs[1].data; + const submission = JSON.parse(data); + + expect(submission.scanned).toBeDefined(); + + // redact changing data + submission.scanned = ""; + submission.detector.version = ""; + + expect(submission.job).toBeDefined() + expect(submission.job.correlator).toEqual("my-workflow_default-import-job_my-matrix-build-1") + + expect(submission).toMatchSnapshot(); + }); + + it("runs with dependency-snapshot-correlator defined", async () => { + setData({ + inputs: { + path: "tests/fixtures/npm-project", + "dependency-snapshot": "true", + "upload-artifact": "false", + "dependency-snapshot-correlator": "some-correlator", + }, + context: { + ...context.push({ + ref: "main", + }), + sha: "f293f09uaw90gwa09f9wea", + workflow: "my-workflow", + job: "default-import-job", + action: "__anchore_sbom-action", + }, + }); + + await action.runSyftAction(); + await action.uploadDependencySnapshot(); + + // validate the request was made + expect(requestArgs).toBeDefined(); + expect(requestArgs).toHaveLength(2); + expect(requestArgs[0]).toBe("POST /repos/test-org/test-repo/dependency-graph/snapshots"); + + // check the resulting snapshot file + const data = requestArgs[1].data; + const submission = JSON.parse(data); + + expect(submission.scanned).toBeDefined(); + + // redact changing data + submission.scanned = ""; + submission.detector.version = ""; + + expect(submission.job).toBeDefined() + expect(submission.job.correlator).toEqual("some-correlator") + + expect(submission).toMatchSnapshot(); + }); }); diff --git a/tests/integration/__snapshots__/GitHubSnapshot.test.ts.snap b/tests/integration/__snapshots__/GitHubSnapshot.test.ts.snap index d82d1fd4..06404dec 100644 --- a/tests/integration/__snapshots__/GitHubSnapshot.test.ts.snap +++ b/tests/integration/__snapshots__/GitHubSnapshot.test.ts.snap @@ -1,5 +1,98 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`GitHub Snapshot runs with artifact-name input 1`] = ` +{ + "detector": { + "name": "syft", + "url": "https://github.com/anchore/syft", + "version": "", + }, + "job": { + "correlator": "my-workflow_default-import-job_my-matrix-build-1", + "id": "1", + }, + "manifests": { + "tests/fixtures/npm-project/package-lock.json": { + "file": { + "source_location": "tests/fixtures/npm-project/package-lock.json", + }, + "name": "tests/fixtures/npm-project/package-lock.json", + "resolved": { + "pkg:npm/chownr@2.0.0": { + "package_url": "pkg:npm/chownr@2.0.0", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/fs-minipass@2.1.0": { + "package_url": "pkg:npm/fs-minipass@2.1.0", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/js-tokens@4.0.0": { + "package_url": "pkg:npm/js-tokens@4.0.0", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/loose-envify@1.4.0": { + "package_url": "pkg:npm/loose-envify@1.4.0", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/minipass@3.1.3": { + "package_url": "pkg:npm/minipass@3.1.3", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/minizlib@2.1.2": { + "package_url": "pkg:npm/minizlib@2.1.2", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/mkdirp@1.0.4": { + "package_url": "pkg:npm/mkdirp@1.0.4", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/object-assign@4.1.1": { + "package_url": "pkg:npm/object-assign@4.1.1", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/prop-types@15.7.2": { + "package_url": "pkg:npm/prop-types@15.7.2", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/react-is@16.13.1": { + "package_url": "pkg:npm/react-is@16.13.1", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/react@16.14.0": { + "package_url": "pkg:npm/react@16.14.0", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/tar@6.1.0": { + "package_url": "pkg:npm/tar@6.1.0", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/yallist@4.0.0": { + "package_url": "pkg:npm/yallist@4.0.0", + "relationship": "direct", + "scope": "runtime", + }, + }, + }, + }, + "ref": "v0.0.0", + "scanned": "", + "sha": "f293f09uaw90gwa09f9wea", + "version": 0, +} +`; + exports[`GitHub Snapshot runs with default inputs 1`] = ` { "detector": { @@ -92,3 +185,96 @@ exports[`GitHub Snapshot runs with default inputs 1`] = ` "version": 0, } `; + +exports[`GitHub Snapshot runs with dependency-snapshot-correlator defined 1`] = ` +{ + "detector": { + "name": "syft", + "url": "https://github.com/anchore/syft", + "version": "", + }, + "job": { + "correlator": "some-correlator", + "id": "1", + }, + "manifests": { + "tests/fixtures/npm-project/package-lock.json": { + "file": { + "source_location": "tests/fixtures/npm-project/package-lock.json", + }, + "name": "tests/fixtures/npm-project/package-lock.json", + "resolved": { + "pkg:npm/chownr@2.0.0": { + "package_url": "pkg:npm/chownr@2.0.0", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/fs-minipass@2.1.0": { + "package_url": "pkg:npm/fs-minipass@2.1.0", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/js-tokens@4.0.0": { + "package_url": "pkg:npm/js-tokens@4.0.0", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/loose-envify@1.4.0": { + "package_url": "pkg:npm/loose-envify@1.4.0", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/minipass@3.1.3": { + "package_url": "pkg:npm/minipass@3.1.3", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/minizlib@2.1.2": { + "package_url": "pkg:npm/minizlib@2.1.2", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/mkdirp@1.0.4": { + "package_url": "pkg:npm/mkdirp@1.0.4", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/object-assign@4.1.1": { + "package_url": "pkg:npm/object-assign@4.1.1", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/prop-types@15.7.2": { + "package_url": "pkg:npm/prop-types@15.7.2", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/react-is@16.13.1": { + "package_url": "pkg:npm/react-is@16.13.1", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/react@16.14.0": { + "package_url": "pkg:npm/react@16.14.0", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/tar@6.1.0": { + "package_url": "pkg:npm/tar@6.1.0", + "relationship": "direct", + "scope": "runtime", + }, + "pkg:npm/yallist@4.0.0": { + "package_url": "pkg:npm/yallist@4.0.0", + "relationship": "direct", + "scope": "runtime", + }, + }, + }, + }, + "ref": "v0.0.0", + "scanned": "", + "sha": "f293f09uaw90gwa09f9wea", + "version": 0, +} +`;