Compare commits

..
Author SHA1 Message Date
github-actions[bot] 0eb73668fa Empty commit to open PR 2025-06-16 12:04:03 +00:00
github-actions[bot] 7a168cbdc4 Merge upstream:main 2025-06-16 12:04:03 +00:00
Lewis Jones 04aaaf6193 Merge pull request #118 from advanced-security/ljones140/add-snapshot-inputs
Add Snapshot inputs
2025-06-16 13:03:18 +01:00
Lewis Jones 0f3b6aecc6 Generate dist 2025-06-16 11:17:06 +01:00
Lewis Jones 348257c874 Add sha and ref snapshot inputs 2025-06-16 11:15:10 +01:00
Lewis Jones 779e8387fd Add detector inputs
Optional but if any are provided, then all are required
2025-06-16 11:03:28 +01:00
Lewis Jones d5fd67e101 Merge pull request #2 from actions/weekly-sync-branch-15612676798
Sync Fork with Upstream
2025-06-12 15:02:36 +01:00
github-actions[bot] 27e6d82755 Empty commit to open PR 2025-06-12 14:01:47 +00:00
github-actions[bot] 3d11e5a0f7 Merge upstream:main 2025-06-12 14:01:47 +00:00
Lewis Jones e0dcc85667 Merge pull request #117 from actions/ljones140/clean-detector-categories-pr
Add DetectorCategories input So we can run by ecosystem
2025-06-12 13:26:39 +01:00
Lewis Jones 4f5a06217d Remove examples
As not confirmed they are correct.

For example PIp doesn't work but Python does
2025-06-12 12:23:38 +01:00
Lewis Jones 81fde650c2 Add new input to readme 2025-06-12 12:10:17 +01:00
Lewis Jones 786fb5fe93 dist generated code 2025-06-12 12:10:06 +01:00
Lewis Jones 550b6f27ed Pass detectorCategories
As we want to use for specific ecosystems.
2025-06-12 12:09:54 +01:00
Lewis Jones 51ef6b3995 Merge pull request #1 from actions/ljones140/setup-fork
Setup fork Codeowners and sync
2025-06-10 15:35:24 +01:00
6 changed files with 130 additions and 44 deletions
+8 -7
View File
@@ -1,6 +1,6 @@
# Component detection dependency submission action
This GitHub Action runs the [microsoft/component-detection](https://github.com/microsoft/component-detection) library to automate dependency extraction at build time. It uses a combination of static and dynamic scanning to build a dependency tree and then uploads that to GitHub's dependency graph via the dependency submission API. This gives you more accurate Dependabot alerts, and support for a bunch of additional ecosystems.
This GitHub Action runs the [microsoft/component-detection](https://github.com/microsoft/component-detection) library to automate dependency extraction at build time. It uses a combination of static and dynamic scanning to build a dependency tree and then uploads that to GitHub's dependency graph via the dependency submission API. This gives you more accurate Dependabot alerts, and support for a bunch of additional ecosystems.
### Example workflow
@@ -12,7 +12,7 @@ on:
workflow_dispatch:
push:
permissions:
permissions:
id-token: write
contents: write
@@ -21,19 +21,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Component detection
- name: Component detection
uses: advanced-security/[email protected]
```
```
### Configuration options
| Parameter | Description | Example |
| --- | --- | --- |
| Parameter | Description | Example |
| --- | --- | --- |
filePath | The path to the directory containing the environment files to upload. Defaults to Actions working directory. | `'.'`
directoryExclusionList | Filters out specific directories following a minimatch pattern. | `test`
detectorArgs | Comma separated list of properties that can affect the detectors execution, like EnableIfDefaultOff that allows a specific detector that is in beta to run, the format for this property is DetectorId=EnableIfDefaultOff, for example Pip=EnableIfDefaultOff. | `Pip=EnableIfDefaultOff`
dockerImagesToScan |Comma separated list of docker image names or hashes to execute container scanning on | ubuntu:16.04,56bab49eef2ef07505f6a1b0d5bd3a601dfc3c76ad4460f24c91d6fa298369ab |
dockerImagesToScan |Comma separated list of docker image names or hashes to execute container scanning on | ubuntu:16.04,56bab49eef2ef07505f6a1b0d5bd3a601dfc3c76ad4460f24c91d6fa298369ab |
detectorsFilter | A comma separated list with the identifiers of the specific detectors to be used. | `Pip, RustCrateDetector`
detectorsCategories | A comma separated list with the categories of components that are going to be scanned. The detectors that are going to run are the ones that belongs to the categories. | `NuGet,Npm`
correlator | An optional identifier to distinguish between multiple dependency snapshots of the same type. Defaults to the [job_id](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_id) of the current job | `csharp-backend`
For more information: https://github.com/microsoft/component-detection
+20 -3
View File
@@ -5,7 +5,7 @@ inputs:
description: "GitHub Personal Access Token (PAT). Defaults to PAT provided by Actions runner."
required: false
default: ${{ github.token }}
filePath:
filePath:
description: 'The path to the directory containing the environment files to upload. Defaults to Actions working directory.'
required: false
default: '.'
@@ -18,12 +18,29 @@ inputs:
dockerImagesToScan:
description: 'Comma separated list of docker image names or hashes to execute container scanning on, ex: ubuntu:16.04,56bab49eef2ef07505f6a1b0d5bd3a601dfc3c76ad4460f24c91d6fa298369ab'
required: false
detectorsFilter:
detectorsFilter:
description: 'A comma separated list with the identifiers of the specific detectors to be used. This is meant to be used for testing purposes only.'
required: false
detectorsCategories:
description: 'A comma separated list with the categories of components that are going to be scanned. The detectors that are going to run are the ones that belongs to the categories. The possible values are: Npm, NuGet, Maven, RubyGems, Cargo, Pip, GoMod, CocoaPods, Linux.'
required: false
correlator:
description: 'An optional identifier to distinguish between multiple dependency snapshots of the same type.'
type: string
required: false
detector-name:
description: 'The name of the detector. If provided, detector-version and detector-url must also be provided.'
required: false
detector-version:
description: 'The version of the detector. If provided, detector-name and detector-url must also be provided.'
required: false
detector-url:
description: 'The URL of the detector. If provided, detector-name and detector-version must also be provided.'
required: false
snapshot-sha:
description: 'The SHA of the commit to associate with the snapshot. If provided, snapshot-ref must also be provided.'
required: false
snapshot-ref:
description: 'The Git reference to associate with the snapshot. If provided, snapshot-sha must also be provided.'
required: false
runs:
using: 'node20'
+10 -9
View File
@@ -22,7 +22,7 @@ export default class ComponentDetection {
public static componentDetectionPath = process.platform === "win32" ? './component-detection.exe' : './component-detection';
public static outputPath = './output.json';
// This is the default entry point for this class.
// This is the default entry point for this class.
static async scanAndGetManifests(path: string): Promise<Manifest[] | undefined> {
await this.downloadLatestRelease();
await this.runComponentDetection(path);
@@ -61,6 +61,7 @@ export default class ComponentDetection {
parameters += (core.getInput('directoryExclusionList')) ? ` --DirectoryExclusionList ${core.getInput('directoryExclusionList')}` : "";
parameters += (core.getInput('detectorArgs')) ? ` --DetectorArgs ${core.getInput('detectorArgs')}` : "";
parameters += (core.getInput('detectorsFilter')) ? ` --DetectorsFilter ${core.getInput('detectorsFilter')}` : "";
parameters += (core.getInput('detectorsCategories')) ? ` --DetectorCategories ${core.getInput('detectorsCategories')}` : "";
parameters += (core.getInput('dockerImagesToScan')) ? ` --DockerImagesToScan ${core.getInput('dockerImagesToScan')}` : "";
return parameters;
}
@@ -86,7 +87,7 @@ export default class ComponentDetection {
}
const packageUrl = ComponentDetection.makePackageUrl(component.component.packageUrl);
// Skip if the packageUrl is empty (indicates an invalid or missing packageUrl)
if (!packageUrl) {
core.debug(`Skipping component with invalid packageUrl: ${component.component.id}`);
@@ -110,15 +111,15 @@ export default class ComponentDetection {
core.debug(`Skipping referrer without packageUrl for component: ${pkg.id}`);
return;
}
const referrerUrl = ComponentDetection.makePackageUrl(referrer.packageUrl);
// Skip if the generated packageUrl is empty
if (!referrerUrl) {
core.debug(`Skipping referrer with invalid packageUrl for component: ${pkg.id}`);
return;
}
try {
const referrerPackage = packageCache.lookupPackage(referrerUrl);
if (referrerPackage) {
@@ -195,10 +196,10 @@ export default class ComponentDetection {
private static async getLatestReleaseURL(): Promise<string> {
let githubToken = core.getInput('token') || process.env.GITHUB_TOKEN || "";
const githubAPIURL = 'https://api.github.com'
const githubAPIURL = 'https://api.github.com'
let ghesMode = github.context.apiUrl != githubAPIURL;
// If the we're running in GHES, then use an empty string as the token
// If the we're running in GHES, then use an empty string as the token
if (ghesMode) {
githubToken = "";
}
@@ -213,7 +214,7 @@ export default class ComponentDetection {
const repo = "component-detection";
core.debug("Attempting to download latest release from " + githubAPIURL);
try {
try {
const latestRelease = await octokit.request("GET /repos/{owner}/{repo}/releases/latest", {owner, repo});
var downloadURL: string = "";
@@ -229,7 +230,7 @@ export default class ComponentDetection {
core.error(error);
core.debug(error.message);
core.debug(error.stack);
throw new Error("Failed to download latest release");
throw new Error("Failed to download latest release");
}
}
}
Generated Vendored
+41 -12
View File
@@ -36004,7 +36004,7 @@ const exec = __importStar(__nccwpck_require__(5236));
const dotenv_1 = __importDefault(__nccwpck_require__(8889));
dotenv_1.default.config();
class ComponentDetection {
// This is the default entry point for this class.
// This is the default entry point for this class.
static scanAndGetManifests(path) {
return __awaiter(this, void 0, void 0, function* () {
yield this.downloadLatestRelease();
@@ -36047,6 +36047,7 @@ class ComponentDetection {
parameters += (core.getInput('directoryExclusionList')) ? ` --DirectoryExclusionList ${core.getInput('directoryExclusionList')}` : "";
parameters += (core.getInput('detectorArgs')) ? ` --DetectorArgs ${core.getInput('detectorArgs')}` : "";
parameters += (core.getInput('detectorsFilter')) ? ` --DetectorsFilter ${core.getInput('detectorsFilter')}` : "";
parameters += (core.getInput('detectorsCategories')) ? ` --DetectorCategories ${core.getInput('detectorsCategories')}` : "";
parameters += (core.getInput('dockerImagesToScan')) ? ` --DockerImagesToScan ${core.getInput('dockerImagesToScan')}` : "";
return parameters;
}
@@ -36170,7 +36171,7 @@ class ComponentDetection {
let githubToken = core.getInput('token') || process.env.GITHUB_TOKEN || "";
const githubAPIURL = 'https://api.github.com';
let ghesMode = github.context.apiUrl != githubAPIURL;
// If the we're running in GHES, then use an empty string as the token
// If the we're running in GHES, then use an empty string as the token
if (ghesMode) {
githubToken = "";
}
@@ -36266,23 +36267,51 @@ const github = __importStar(__nccwpck_require__(3228));
const dependency_submission_toolkit_1 = __nccwpck_require__(3323);
const componentDetection_1 = __importDefault(__nccwpck_require__(3202));
function run() {
var _a;
var _a, _b, _c, _d, _e, _f;
return __awaiter(this, void 0, void 0, function* () {
let manifests = yield componentDetection_1.default.scanAndGetManifests(core.getInput('filePath'));
const correlatorInput = ((_a = core.getInput('correlator')) === null || _a === void 0 ? void 0 : _a.trim()) || github.context.job;
let snapshot = new dependency_submission_toolkit_1.Snapshot({
name: "Component Detection",
version: "0.0.1",
url: "https://github.com/advanced-security/component-detection-dependency-submission-action",
}, github.context, {
let manifests = yield componentDetection_1.default.scanAndGetManifests(core.getInput("filePath"));
const correlatorInput = ((_a = core.getInput("correlator")) === null || _a === void 0 ? void 0 : _a.trim()) || github.context.job;
// Get detector configuration inputs
const detectorName = (_b = core.getInput("detector-name")) === null || _b === void 0 ? void 0 : _b.trim();
const detectorVersion = (_c = core.getInput("detector-version")) === null || _c === void 0 ? void 0 : _c.trim();
const detectorUrl = (_d = core.getInput("detector-url")) === null || _d === void 0 ? void 0 : _d.trim();
// Validate that if any detector config is provided, all must be provided
const hasAnyDetectorInput = detectorName || detectorVersion || detectorUrl;
const hasAllDetectorInputs = detectorName && detectorVersion && detectorUrl;
if (hasAnyDetectorInput && !hasAllDetectorInputs) {
core.setFailed("If any detector configuration is provided (detector-name, detector-version, detector-url), all three must be provided.");
return;
}
// Use provided detector config or defaults
const detector = hasAllDetectorInputs
? {
name: detectorName,
version: detectorVersion,
url: detectorUrl,
}
: {
name: "Component Detection",
version: "0.0.1",
url: "https://github.com/advanced-security/component-detection-dependency-submission-action",
};
let snapshot = new dependency_submission_toolkit_1.Snapshot(detector, github.context, {
correlator: correlatorInput,
id: github.context.runId.toString()
id: github.context.runId.toString(),
});
core.debug(`Manifests: ${manifests === null || manifests === void 0 ? void 0 : manifests.length}`);
manifests === null || manifests === void 0 ? void 0 : manifests.forEach(manifest => {
manifests === null || manifests === void 0 ? void 0 : manifests.forEach((manifest) => {
core.debug(`Manifest: ${JSON.stringify(manifest)}`);
snapshot.addManifest(manifest);
});
// Override snapshot ref and sha if provided
const snapshotSha = (_e = core.getInput("snapshot-sha")) === null || _e === void 0 ? void 0 : _e.trim();
const snapshotRef = (_f = core.getInput("snapshot-ref")) === null || _f === void 0 ? void 0 : _f.trim();
if (snapshotSha) {
snapshot.sha = snapshotSha;
}
if (snapshotRef) {
snapshot.ref = snapshotRef;
}
(0, dependency_submission_toolkit_1.submitSnapshot)(snapshot);
});
}
Generated Vendored
+1 -1
View File
File diff suppressed because one or more lines are too long
+50 -12
View File
@@ -13,27 +13,65 @@ import {
import ComponentDetection from './componentDetection';
async function run() {
let manifests = await ComponentDetection.scanAndGetManifests(core.getInput('filePath'));
const correlatorInput = core.getInput('correlator')?.trim() || github.context.job;
let snapshot = new Snapshot({
name: "Component Detection",
version: "0.0.1",
url: "https://github.com/advanced-security/component-detection-dependency-submission-action",
},
github.context,
{
let manifests = await ComponentDetection.scanAndGetManifests(
core.getInput("filePath")
);
const correlatorInput =
core.getInput("correlator")?.trim() || github.context.job;
// Get detector configuration inputs
const detectorName = core.getInput("detector-name")?.trim();
const detectorVersion = core.getInput("detector-version")?.trim();
const detectorUrl = core.getInput("detector-url")?.trim();
// Validate that if any detector config is provided, all must be provided
const hasAnyDetectorInput = detectorName || detectorVersion || detectorUrl;
const hasAllDetectorInputs = detectorName && detectorVersion && detectorUrl;
if (hasAnyDetectorInput && !hasAllDetectorInputs) {
core.setFailed(
"If any detector configuration is provided (detector-name, detector-version, detector-url), all three must be provided."
);
return;
}
// Use provided detector config or defaults
const detector = hasAllDetectorInputs
? {
name: detectorName,
version: detectorVersion,
url: detectorUrl,
}
: {
name: "Component Detection",
version: "0.0.1",
url: "https://github.com/advanced-security/component-detection-dependency-submission-action",
};
let snapshot = new Snapshot(detector, github.context, {
correlator: correlatorInput,
id: github.context.runId.toString()
id: github.context.runId.toString(),
});
core.debug(`Manifests: ${manifests?.length}`);
manifests?.forEach(manifest => {
manifests?.forEach((manifest) => {
core.debug(`Manifest: ${JSON.stringify(manifest)}`);
snapshot.addManifest(manifest);
});
// Override snapshot ref and sha if provided
const snapshotSha = core.getInput("snapshot-sha")?.trim();
const snapshotRef = core.getInput("snapshot-ref")?.trim();
if (snapshotSha) {
snapshot.sha = snapshotSha;
}
if (snapshotRef) {
snapshot.ref = snapshotRef;
}
submitSnapshot(snapshot);
}