Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67f3292117 | ||
|
|
3f420ae88d | ||
|
|
b242ddf67a | ||
|
|
3349f8c032 | ||
|
|
2517c7a607 | ||
|
|
2efc7af7df | ||
|
|
6d56d2b42c | ||
|
|
0de0af1352 | ||
|
|
4daccf7142 | ||
|
|
caa69e181f | ||
|
|
ef571d5a84 | ||
|
|
0eb73668fa | ||
|
|
7a168cbdc4 | ||
|
|
04aaaf6193 | ||
|
|
0f3b6aecc6 | ||
|
|
348257c874 | ||
|
|
779e8387fd | ||
|
|
d5fd67e101 | ||
|
|
27e6d82755 | ||
|
|
3d11e5a0f7 | ||
|
|
e0dcc85667 | ||
|
|
4f5a06217d | ||
|
|
81fde650c2 | ||
|
|
786fb5fe93 | ||
|
|
550b6f27ed | ||
|
|
51ef6b3995 |
@@ -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
@@ -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'
|
||||
|
||||
@@ -68,3 +68,114 @@ describe("ComponentDetection.makePackageUrl", () => {
|
||||
expect(packageUrl).toBe("");
|
||||
});
|
||||
});
|
||||
|
||||
describe("ComponentDetection.processComponentsToManifests", () => {
|
||||
test("adds package as direct dependency when no top level referrers", () => {
|
||||
const componentsFound = [
|
||||
{
|
||||
component: {
|
||||
name: "test-package",
|
||||
version: "1.0.0",
|
||||
packageUrl: {
|
||||
Scheme: "pkg",
|
||||
Type: "npm",
|
||||
Name: "test-package",
|
||||
Version: "1.0.0"
|
||||
},
|
||||
id: "test-package 1.0.0 - npm"
|
||||
},
|
||||
isDevelopmentDependency: false,
|
||||
topLevelReferrers: [], // Empty = direct dependency
|
||||
locationsFoundAt: ["package.json"]
|
||||
}
|
||||
];
|
||||
|
||||
const manifests = ComponentDetection.processComponentsToManifests(componentsFound);
|
||||
|
||||
expect(manifests).toHaveLength(1);
|
||||
expect(manifests[0].name).toBe("package.json");
|
||||
expect(manifests[0].directDependencies()).toHaveLength(1);
|
||||
expect(manifests[0].indirectDependencies()).toHaveLength(0);
|
||||
expect(manifests[0].countDependencies()).toBe(1);
|
||||
});
|
||||
|
||||
test("adds package as indirect dependency when has top level referrers", () => {
|
||||
const componentsFound = [
|
||||
{
|
||||
component: {
|
||||
name: "test-package",
|
||||
version: "1.0.0",
|
||||
packageUrl: {
|
||||
Scheme: "pkg",
|
||||
Type: "npm",
|
||||
Name: "test-package",
|
||||
Version: "1.0.0"
|
||||
},
|
||||
id: "test-package 1.0.0 - npm"
|
||||
},
|
||||
isDevelopmentDependency: false,
|
||||
topLevelReferrers: [
|
||||
{
|
||||
name: "parent-package",
|
||||
version: "1.0.0",
|
||||
packageUrl: {
|
||||
Scheme: "pkg",
|
||||
Type: "npm",
|
||||
Name: "parent-package",
|
||||
Version: "1.0.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
locationsFoundAt: ["package.json"]
|
||||
}
|
||||
];
|
||||
|
||||
const manifests = ComponentDetection.processComponentsToManifests(componentsFound);
|
||||
|
||||
expect(manifests).toHaveLength(1);
|
||||
expect(manifests[0].name).toBe("package.json");
|
||||
expect(manifests[0].directDependencies()).toHaveLength(0);
|
||||
expect(manifests[0].indirectDependencies()).toHaveLength(1);
|
||||
expect(manifests[0].countDependencies()).toBe(1);
|
||||
});
|
||||
|
||||
test("adds package as direct dependency when top level referrer is itself", () => {
|
||||
const componentsFound = [
|
||||
{
|
||||
component: {
|
||||
name: "test-package",
|
||||
version: "1.0.0",
|
||||
packageUrl: {
|
||||
Scheme: "pkg",
|
||||
Type: "npm",
|
||||
Name: "test-package",
|
||||
Version: "1.0.0"
|
||||
},
|
||||
id: "test-package 1.0.0 - npm"
|
||||
},
|
||||
isDevelopmentDependency: false,
|
||||
topLevelReferrers: [
|
||||
{
|
||||
name: "test-package",
|
||||
version: "1.0.0",
|
||||
packageUrl: {
|
||||
Scheme: "pkg",
|
||||
Type: "npm",
|
||||
Name: "test-package",
|
||||
Version: "1.0.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
locationsFoundAt: ["package.json"]
|
||||
}
|
||||
];
|
||||
|
||||
const manifests = ComponentDetection.processComponentsToManifests(componentsFound);
|
||||
|
||||
expect(manifests).toHaveLength(1);
|
||||
expect(manifests[0].name).toBe("package.json");
|
||||
expect(manifests[0].directDependencies()).toHaveLength(1);
|
||||
expect(manifests[0].indirectDependencies()).toHaveLength(0);
|
||||
expect(manifests[0].countDependencies()).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
+36
-17
@@ -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,20 +61,24 @@ 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;
|
||||
}
|
||||
|
||||
public static async getManifestsFromResults(): Promise<Manifest[] | undefined> {
|
||||
core.info("Getting manifests from results");
|
||||
const results = await fs.readFileSync(this.outputPath, 'utf8');
|
||||
var json: any = JSON.parse(results);
|
||||
return this.processComponentsToManifests(json.componentsFound);
|
||||
}
|
||||
|
||||
public static processComponentsToManifests(componentsFound: any[]): Manifest[] {
|
||||
// Parse the result file and add the packages to the package cache
|
||||
const packageCache = new PackageCache();
|
||||
const packages: Array<ComponentDetectionPackage> = [];
|
||||
|
||||
const results = await fs.readFileSync(this.outputPath, 'utf8');
|
||||
|
||||
var json: any = JSON.parse(results);
|
||||
json.componentsFound.forEach(async (component: any) => {
|
||||
componentsFound.forEach(async (component: any) => {
|
||||
// Skip components without packageUrl
|
||||
if (!component.component.packageUrl) {
|
||||
core.debug(`Skipping component detected without packageUrl: ${JSON.stringify({
|
||||
@@ -86,7 +90,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 +114,16 @@ export default class ComponentDetection {
|
||||
core.debug(`Skipping referrer without packageUrl for component: ${pkg.id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const referrerUrl = ComponentDetection.makePackageUrl(referrer.packageUrl);
|
||||
|
||||
referrer.packageUrlString = referrerUrl
|
||||
|
||||
// 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) {
|
||||
@@ -134,20 +139,32 @@ export default class ComponentDetection {
|
||||
const manifests: Array<Manifest> = [];
|
||||
|
||||
// Check the locationsFoundAt for every package and add each as a manifest
|
||||
packages.forEach(async (pkg: ComponentDetectionPackage) => {
|
||||
pkg.locationsFoundAt.forEach(async (location: any) => {
|
||||
this.addPackagesToManifests(packages, manifests);
|
||||
|
||||
return manifests;
|
||||
}
|
||||
|
||||
private static addPackagesToManifests(packages: Array<ComponentDetectionPackage>, manifests: Array<Manifest>): void {
|
||||
packages.forEach((pkg: ComponentDetectionPackage) => {
|
||||
pkg.locationsFoundAt.forEach((location: any) => {
|
||||
if (!manifests.find((manifest: Manifest) => manifest.name == location)) {
|
||||
const manifest = new Manifest(location, location);
|
||||
manifests.push(manifest);
|
||||
}
|
||||
if (pkg.topLevelReferrers.length == 0) {
|
||||
|
||||
// Filter out self-references from topLevelReferrers
|
||||
const nonSelfReferrers = pkg.topLevelReferrers.filter((referrer: any) => {
|
||||
if (!referrer.packageUrlString) return false;
|
||||
return referrer.packageUrlString !== pkg.packageUrlString;
|
||||
});
|
||||
|
||||
if (nonSelfReferrers.length == 0) {
|
||||
manifests.find((manifest: Manifest) => manifest.name == location)?.addDirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
|
||||
} else {
|
||||
manifests.find((manifest: Manifest) => manifest.name == location)?.addIndirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
|
||||
}
|
||||
});
|
||||
});
|
||||
return manifests;
|
||||
}
|
||||
|
||||
private static getDependencyScope(pkg: ComponentDetectionPackage) {
|
||||
@@ -195,10 +212,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 +230,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,16 +246,18 @@ 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ComponentDetectionPackage extends Package {
|
||||
public packageUrlString: string;
|
||||
|
||||
constructor(packageUrl: string, public id: string, public isDevelopmentDependency: boolean, public topLevelReferrers: [],
|
||||
public locationsFoundAt: [], public containerDetailIds: [], public containerLayerIds: []) {
|
||||
super(packageUrl);
|
||||
this.packageUrlString = packageUrl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -7,6 +7,8 @@ export default class ComponentDetection {
|
||||
static runComponentDetection(path: string): Promise<void>;
|
||||
private static getComponentDetectionParameters;
|
||||
static getManifestsFromResults(): Promise<Manifest[] | undefined>;
|
||||
static processComponentsToManifests(componentsFound: any[]): Manifest[];
|
||||
private static addPackagesToManifests;
|
||||
private static getDependencyScope;
|
||||
static makePackageUrl(packageUrlJson: any): string;
|
||||
private static getLatestReleaseURL;
|
||||
|
||||
+119
-76
@@ -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,84 +36047,98 @@ 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;
|
||||
}
|
||||
static getManifestsFromResults() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
core.info("Getting manifests from results");
|
||||
// Parse the result file and add the packages to the package cache
|
||||
const packageCache = new dependency_submission_toolkit_1.PackageCache();
|
||||
const packages = [];
|
||||
const results = yield fs_1.default.readFileSync(this.outputPath, 'utf8');
|
||||
var json = JSON.parse(results);
|
||||
json.componentsFound.forEach((component) => __awaiter(this, void 0, void 0, function* () {
|
||||
// Skip components without packageUrl
|
||||
if (!component.component.packageUrl) {
|
||||
core.debug(`Skipping component detected without packageUrl: ${JSON.stringify({
|
||||
id: component.component.id,
|
||||
name: component.component.name || 'unnamed',
|
||||
type: component.component.type || 'unknown'
|
||||
}, null, 2)}`);
|
||||
return this.processComponentsToManifests(json.componentsFound);
|
||||
});
|
||||
}
|
||||
static processComponentsToManifests(componentsFound) {
|
||||
// Parse the result file and add the packages to the package cache
|
||||
const packageCache = new dependency_submission_toolkit_1.PackageCache();
|
||||
const packages = [];
|
||||
componentsFound.forEach((component) => __awaiter(this, void 0, void 0, function* () {
|
||||
// Skip components without packageUrl
|
||||
if (!component.component.packageUrl) {
|
||||
core.debug(`Skipping component detected without packageUrl: ${JSON.stringify({
|
||||
id: component.component.id,
|
||||
name: component.component.name || 'unnamed',
|
||||
type: component.component.type || 'unknown'
|
||||
}, null, 2)}`);
|
||||
return;
|
||||
}
|
||||
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}`);
|
||||
return;
|
||||
}
|
||||
if (!packageCache.hasPackage(packageUrl)) {
|
||||
const pkg = new ComponentDetectionPackage(packageUrl, component.component.id, component.isDevelopmentDependency, component.topLevelReferrers, component.locationsFoundAt, component.containerDetailIds, component.containerLayerIds);
|
||||
packageCache.addPackage(pkg);
|
||||
packages.push(pkg);
|
||||
}
|
||||
}));
|
||||
// Set the transitive dependencies
|
||||
core.debug("Sorting out transitive dependencies");
|
||||
packages.forEach((pkg) => __awaiter(this, void 0, void 0, function* () {
|
||||
pkg.topLevelReferrers.forEach((referrer) => __awaiter(this, void 0, void 0, function* () {
|
||||
// Skip if referrer doesn't have a valid packageUrl
|
||||
if (!referrer.packageUrl) {
|
||||
core.debug(`Skipping referrer without packageUrl for component: ${pkg.id}`);
|
||||
return;
|
||||
}
|
||||
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}`);
|
||||
const referrerUrl = ComponentDetection.makePackageUrl(referrer.packageUrl);
|
||||
referrer.packageUrlString = referrerUrl;
|
||||
// Skip if the generated packageUrl is empty
|
||||
if (!referrerUrl) {
|
||||
core.debug(`Skipping referrer with invalid packageUrl for component: ${pkg.id}`);
|
||||
return;
|
||||
}
|
||||
if (!packageCache.hasPackage(packageUrl)) {
|
||||
const pkg = new ComponentDetectionPackage(packageUrl, component.component.id, component.isDevelopmentDependency, component.topLevelReferrers, component.locationsFoundAt, component.containerDetailIds, component.containerLayerIds);
|
||||
packageCache.addPackage(pkg);
|
||||
packages.push(pkg);
|
||||
try {
|
||||
const referrerPackage = packageCache.lookupPackage(referrerUrl);
|
||||
if (referrerPackage) {
|
||||
referrerPackage.dependsOn(pkg);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
core.debug(`Error looking up referrer package: ${error}`);
|
||||
}
|
||||
}));
|
||||
// Set the transitive dependencies
|
||||
core.debug("Sorting out transitive dependencies");
|
||||
packages.forEach((pkg) => __awaiter(this, void 0, void 0, function* () {
|
||||
pkg.topLevelReferrers.forEach((referrer) => __awaiter(this, void 0, void 0, function* () {
|
||||
// Skip if referrer doesn't have a valid packageUrl
|
||||
if (!referrer.packageUrl) {
|
||||
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) {
|
||||
referrerPackage.dependsOn(pkg);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
core.debug(`Error looking up referrer package: ${error}`);
|
||||
}
|
||||
}));
|
||||
}));
|
||||
// Create manifests
|
||||
const manifests = [];
|
||||
// Check the locationsFoundAt for every package and add each as a manifest
|
||||
packages.forEach((pkg) => __awaiter(this, void 0, void 0, function* () {
|
||||
pkg.locationsFoundAt.forEach((location) => __awaiter(this, void 0, void 0, function* () {
|
||||
var _a, _b;
|
||||
if (!manifests.find((manifest) => manifest.name == location)) {
|
||||
const manifest = new dependency_submission_toolkit_1.Manifest(location, location);
|
||||
manifests.push(manifest);
|
||||
}
|
||||
if (pkg.topLevelReferrers.length == 0) {
|
||||
(_a = manifests.find((manifest) => manifest.name == location)) === null || _a === void 0 ? void 0 : _a.addDirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
|
||||
}
|
||||
else {
|
||||
(_b = manifests.find((manifest) => manifest.name == location)) === null || _b === void 0 ? void 0 : _b.addIndirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
|
||||
}
|
||||
}));
|
||||
}));
|
||||
return manifests;
|
||||
}));
|
||||
// Create manifests
|
||||
const manifests = [];
|
||||
// Check the locationsFoundAt for every package and add each as a manifest
|
||||
this.addPackagesToManifests(packages, manifests);
|
||||
return manifests;
|
||||
}
|
||||
static addPackagesToManifests(packages, manifests) {
|
||||
packages.forEach((pkg) => {
|
||||
pkg.locationsFoundAt.forEach((location) => {
|
||||
var _a, _b;
|
||||
if (!manifests.find((manifest) => manifest.name == location)) {
|
||||
const manifest = new dependency_submission_toolkit_1.Manifest(location, location);
|
||||
manifests.push(manifest);
|
||||
}
|
||||
// Filter out self-references from topLevelReferrers
|
||||
const nonSelfReferrers = pkg.topLevelReferrers.filter((referrer) => {
|
||||
if (!referrer.packageUrlString)
|
||||
return false;
|
||||
return referrer.packageUrlString !== pkg.packageUrlString;
|
||||
});
|
||||
if (nonSelfReferrers.length == 0) {
|
||||
(_a = manifests.find((manifest) => manifest.name == location)) === null || _a === void 0 ? void 0 : _a.addDirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
|
||||
}
|
||||
else {
|
||||
(_b = manifests.find((manifest) => manifest.name == location)) === null || _b === void 0 ? void 0 : _b.addIndirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
static getDependencyScope(pkg) {
|
||||
@@ -36170,7 +36184,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 = "";
|
||||
}
|
||||
@@ -36215,6 +36229,7 @@ class ComponentDetectionPackage extends dependency_submission_toolkit_1.Package
|
||||
this.locationsFoundAt = locationsFoundAt;
|
||||
this.containerDetailIds = containerDetailIds;
|
||||
this.containerLayerIds = containerLayerIds;
|
||||
this.packageUrlString = packageUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36266,23 +36281,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);
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user