Compare commits
58
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f1bb09ad2 | ||
|
|
81be972b70 | ||
|
|
51ff88ad10 | ||
|
|
d93866d127 | ||
|
|
7dde1e29d3 | ||
|
|
98ddec4efe | ||
|
|
6ca39f38ce | ||
|
|
333866abe4 | ||
|
|
f59e294eca | ||
|
|
376d6250d1 | ||
|
|
caf2b08649 | ||
|
|
eb91e65da4 | ||
|
|
3517f8f1f0 | ||
|
|
9b429e3d82 | ||
|
|
d434719693 | ||
|
|
ec00348b72 | ||
|
|
c7cb2bbc93 | ||
|
|
601c613aa3 | ||
|
|
374343effe | ||
|
|
5a79ab0fa4 | ||
|
|
0c3e582042 | ||
|
|
d433c2f467 | ||
|
|
96c59aebfe | ||
|
|
6dd7b2dc55 | ||
|
|
496691092b | ||
|
|
e6ad22924a | ||
|
|
0b0b651777 | ||
|
|
914cb6dc5e | ||
|
|
28905c6bc0 | ||
|
|
f89d41905d | ||
|
|
4e2fbd91ff | ||
|
|
6d25ae13f5 | ||
|
|
7d147e8b5f | ||
|
|
5789c204e4 | ||
|
|
98b7e66125 | ||
|
|
b2779b0030 | ||
|
|
876b304ec0 | ||
|
|
3104f6d51c | ||
|
|
5d8c040f29 | ||
|
|
64db6d9d15 | ||
|
|
a44e08867f | ||
|
|
fc216b239a | ||
|
|
5b2736e4f4 | ||
|
|
bbe83e8988 | ||
|
|
c936885d12 | ||
|
|
5f4db12f7b | ||
|
|
466989c808 | ||
|
|
67f3292117 | ||
|
|
3f420ae88d | ||
|
|
b242ddf67a | ||
|
|
3349f8c032 | ||
|
|
2517c7a607 | ||
|
|
2efc7af7df | ||
|
|
6d56d2b42c | ||
|
|
0de0af1352 | ||
|
|
4daccf7142 | ||
|
|
caa69e181f | ||
|
|
ef571d5a84 |
@@ -22,7 +22,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Component detection
|
- name: Component detection
|
||||||
uses: advanced-security/component-detection-dependency-submission-action@v0.0.3
|
uses: advanced-security/component-detection-dependency-submission-action@v0.1.0
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configuration options
|
### Configuration options
|
||||||
|
|||||||
+215
-1
@@ -1,4 +1,4 @@
|
|||||||
import ComponentDetection from "./componentDetection";
|
import ComponentDetection, { DependencyGraphs } from "./componentDetection";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
||||||
test("Downloads CLI", async () => {
|
test("Downloads CLI", async () => {
|
||||||
@@ -68,3 +68,217 @@ describe("ComponentDetection.makePackageUrl", () => {
|
|||||||
expect(packageUrl).toBe("");
|
expect(packageUrl).toBe("");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("ComponentDetection.processComponentsToManifests", () => {
|
||||||
|
test("adds package as direct dependency when it is listed as an explicitlyReferencedComponentIds", () => {
|
||||||
|
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 dependencyGraphs: DependencyGraphs = {
|
||||||
|
"package.json": {
|
||||||
|
graph: { "test-package": null },
|
||||||
|
explicitlyReferencedComponentIds: ["test-package 1.0.0 - npm"],
|
||||||
|
developmentDependencies: [],
|
||||||
|
dependencies: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const manifests = ComponentDetection.processComponentsToManifests(componentsFound, dependencyGraphs);
|
||||||
|
|
||||||
|
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 it is not in explicitlyReferencedComponentIds", () => {
|
||||||
|
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 dependencyGraphs: DependencyGraphs = {
|
||||||
|
"package.json": {
|
||||||
|
graph: { "parent-package": null },
|
||||||
|
explicitlyReferencedComponentIds: [],
|
||||||
|
developmentDependencies: [],
|
||||||
|
dependencies: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const manifests = ComponentDetection.processComponentsToManifests(componentsFound, dependencyGraphs);
|
||||||
|
|
||||||
|
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("un-escapes URL-encoded locationsFoundAt", () => {
|
||||||
|
const componentsFound = [
|
||||||
|
{
|
||||||
|
component: {
|
||||||
|
name: "test-package",
|
||||||
|
version: "1.0.0",
|
||||||
|
packageUrl: {
|
||||||
|
Scheme: "pkg",
|
||||||
|
Type: "nuget",
|
||||||
|
Name: "test-package",
|
||||||
|
Version: "1.0.0"
|
||||||
|
},
|
||||||
|
id: "test-package 1.0.0 - nuget"
|
||||||
|
},
|
||||||
|
isDevelopmentDependency: false,
|
||||||
|
topLevelReferrers: [], // Empty = direct dependency
|
||||||
|
locationsFoundAt: ["/my%20project/my%20project.csproj"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const dependencyGraphs: DependencyGraphs = {
|
||||||
|
"my project/my project.csproj": {
|
||||||
|
graph: { "test-package": null },
|
||||||
|
explicitlyReferencedComponentIds: ["test-package 1.0.0 - nuget"],
|
||||||
|
developmentDependencies: [],
|
||||||
|
dependencies: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const manifests = ComponentDetection.processComponentsToManifests(componentsFound, dependencyGraphs);
|
||||||
|
|
||||||
|
expect(manifests).toHaveLength(1);
|
||||||
|
expect(manifests[0].name).toBe("my project/my project.csproj");
|
||||||
|
expect(manifests[0].directDependencies()).toHaveLength(1);
|
||||||
|
expect(manifests[0].indirectDependencies()).toHaveLength(0);
|
||||||
|
expect(manifests[0].countDependencies()).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('normalizeDependencyGraphPaths', () => {
|
||||||
|
test('converts absolute paths to relative paths based on filePath input', () => {
|
||||||
|
// Simulate a repo at /repo and a scan root at /repo/packages
|
||||||
|
const fakeCwd = '/workspaces';
|
||||||
|
const filePathInput = 'my-super-cool-repo';
|
||||||
|
const absBase = '/workspaces/my-super-cool-repo';
|
||||||
|
const dependencyGraphs: DependencyGraphs = {
|
||||||
|
'/workspaces/my-super-cool-repo/a/package.json': {
|
||||||
|
graph: { 'foo': null },
|
||||||
|
explicitlyReferencedComponentIds: [],
|
||||||
|
developmentDependencies: [],
|
||||||
|
dependencies: []
|
||||||
|
},
|
||||||
|
'/workspaces/my-super-cool-repo/b/package.json': {
|
||||||
|
graph: { 'bar': null },
|
||||||
|
explicitlyReferencedComponentIds: [],
|
||||||
|
developmentDependencies: [],
|
||||||
|
dependencies: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Patch process.cwd for this test
|
||||||
|
const originalCwd = process.cwd;
|
||||||
|
(process as any).cwd = () => fakeCwd;
|
||||||
|
const normalized = ComponentDetection.normalizeDependencyGraphPaths(dependencyGraphs, filePathInput);
|
||||||
|
// Restore process.cwd
|
||||||
|
(process as any).cwd = originalCwd;
|
||||||
|
expect(Object.keys(normalized)).toContain('a/package.json');
|
||||||
|
expect(Object.keys(normalized)).toContain('b/package.json');
|
||||||
|
expect(normalized['a/package.json'].graph).toEqual({ 'foo': null });
|
||||||
|
expect(normalized['b/package.json'].graph).toEqual({ 'bar': null });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('normalizeDependencyGraphPaths with real output.json', () => {
|
||||||
|
test('converts absolute paths in output.json to relative paths using current cwd and filePath', () => {
|
||||||
|
const output = JSON.parse(fs.readFileSync('./output.json', 'utf8'));
|
||||||
|
const dependencyGraphs = output.dependencyGraphs;
|
||||||
|
// Use the same filePath as the action default (".")
|
||||||
|
const normalized = ComponentDetection.normalizeDependencyGraphPaths(dependencyGraphs, 'test');
|
||||||
|
|
||||||
|
// Should contain root level manifests without leading slashes
|
||||||
|
expect(Object.keys(normalized)).toContain('package.json');
|
||||||
|
expect(Object.keys(normalized)).toContain('package-lock.json');
|
||||||
|
|
||||||
|
// Should contain nested manifests with relative paths (no leading slashes)
|
||||||
|
expect(Object.keys(normalized)).toContain('nested/package.json');
|
||||||
|
expect(Object.keys(normalized)).toContain('nested/package-lock.json');
|
||||||
|
|
||||||
|
// All keys should be relative paths without leading slashes
|
||||||
|
for (const key of Object.keys(normalized)) {
|
||||||
|
expect(key.startsWith('/')).toBe(false); // No leading slashes
|
||||||
|
expect(key).not.toMatch(/^\w:\\|^\/\/|^\.{1,2}\//); // Not windows absolute, not network, not relative
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('full action scan creates manifests with correct names and file source locations', async () => {
|
||||||
|
await ComponentDetection.downloadLatestRelease();
|
||||||
|
const manifests = await ComponentDetection.scanAndGetManifests('./test');
|
||||||
|
|
||||||
|
expect(manifests).toBeDefined();
|
||||||
|
expect(manifests!.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
for (const manifest of manifests!) {
|
||||||
|
expect(manifest.name.startsWith('/')).toBe(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const expectedManifestNames = [
|
||||||
|
'package.json',
|
||||||
|
'package-lock.json',
|
||||||
|
'nested/package.json',
|
||||||
|
'nested/package-lock.json',
|
||||||
|
];
|
||||||
|
|
||||||
|
const manifestsByName = manifests!.reduce((acc, manifest) => {
|
||||||
|
acc[manifest.name] = manifest;
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<string, any>);
|
||||||
|
|
||||||
|
for (const expectedName of expectedManifestNames) {
|
||||||
|
const manifest = manifestsByName[expectedName];
|
||||||
|
expect(manifest).toBeDefined();
|
||||||
|
expect(manifest.name).toBe(expectedName);
|
||||||
|
expect(manifest.file?.source_location).toBe(expectedName);
|
||||||
|
}
|
||||||
|
}, 15000);
|
||||||
|
|||||||
+101
-13
@@ -7,7 +7,7 @@ import {
|
|||||||
Package,
|
Package,
|
||||||
Snapshot,
|
Snapshot,
|
||||||
Manifest,
|
Manifest,
|
||||||
submitSnapshot
|
submitSnapshot,
|
||||||
} from '@github/dependency-submission-toolkit'
|
} from '@github/dependency-submission-toolkit'
|
||||||
import fetch from 'cross-fetch'
|
import fetch from 'cross-fetch'
|
||||||
import tar from 'tar'
|
import tar from 'tar'
|
||||||
@@ -16,6 +16,7 @@ import * as exec from '@actions/exec';
|
|||||||
import dotenv from 'dotenv'
|
import dotenv from 'dotenv'
|
||||||
import { Context } from '@actions/github/lib/context'
|
import { Context } from '@actions/github/lib/context'
|
||||||
import { unmockedModulePathPatterns } from './jest.config'
|
import { unmockedModulePathPatterns } from './jest.config'
|
||||||
|
import path from 'path';
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
export default class ComponentDetection {
|
export default class ComponentDetection {
|
||||||
@@ -68,14 +69,18 @@ export default class ComponentDetection {
|
|||||||
|
|
||||||
public static async getManifestsFromResults(): Promise<Manifest[] | undefined> {
|
public static async getManifestsFromResults(): Promise<Manifest[] | undefined> {
|
||||||
core.info("Getting manifests from results");
|
core.info("Getting manifests from results");
|
||||||
|
const results = await fs.readFileSync(this.outputPath, 'utf8');
|
||||||
|
var json: any = JSON.parse(results);
|
||||||
|
let dependencyGraphs: DependencyGraphs = this.normalizeDependencyGraphPaths(json.dependencyGraphs, core.getInput('filePath'));
|
||||||
|
return this.processComponentsToManifests(json.componentsFound, dependencyGraphs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static processComponentsToManifests(componentsFound: any[], dependencyGraphs: DependencyGraphs): Manifest[] {
|
||||||
// Parse the result file and add the packages to the package cache
|
// Parse the result file and add the packages to the package cache
|
||||||
const packageCache = new PackageCache();
|
const packageCache = new PackageCache();
|
||||||
const packages: Array<ComponentDetectionPackage> = [];
|
const packages: Array<ComponentDetectionPackage> = [];
|
||||||
|
|
||||||
const results = await fs.readFileSync(this.outputPath, 'utf8');
|
componentsFound.forEach(async (component: any) => {
|
||||||
|
|
||||||
var json: any = JSON.parse(results);
|
|
||||||
json.componentsFound.forEach(async (component: any) => {
|
|
||||||
// Skip components without packageUrl
|
// Skip components without packageUrl
|
||||||
if (!component.component.packageUrl) {
|
if (!component.component.packageUrl) {
|
||||||
core.debug(`Skipping component detected without packageUrl: ${JSON.stringify({
|
core.debug(`Skipping component detected without packageUrl: ${JSON.stringify({
|
||||||
@@ -113,6 +118,7 @@ export default class ComponentDetection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const referrerUrl = ComponentDetection.makePackageUrl(referrer.packageUrl);
|
const referrerUrl = ComponentDetection.makePackageUrl(referrer.packageUrl);
|
||||||
|
referrer.packageUrlString = referrerUrl
|
||||||
|
|
||||||
// Skip if the generated packageUrl is empty
|
// Skip if the generated packageUrl is empty
|
||||||
if (!referrerUrl) {
|
if (!referrerUrl) {
|
||||||
@@ -122,6 +128,10 @@ export default class ComponentDetection {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const referrerPackage = packageCache.lookupPackage(referrerUrl);
|
const referrerPackage = packageCache.lookupPackage(referrerUrl);
|
||||||
|
if (referrerPackage === pkg) {
|
||||||
|
core.debug(`Skipping self-reference for package: ${pkg.id}`);
|
||||||
|
return; // Skip self-references
|
||||||
|
}
|
||||||
if (referrerPackage) {
|
if (referrerPackage) {
|
||||||
referrerPackage.dependsOn(pkg);
|
referrerPackage.dependsOn(pkg);
|
||||||
}
|
}
|
||||||
@@ -135,20 +145,48 @@ export default class ComponentDetection {
|
|||||||
const manifests: Array<Manifest> = [];
|
const manifests: Array<Manifest> = [];
|
||||||
|
|
||||||
// Check the locationsFoundAt for every package and add each as a manifest
|
// Check the locationsFoundAt for every package and add each as a manifest
|
||||||
packages.forEach(async (pkg: ComponentDetectionPackage) => {
|
this.addPackagesToManifests(packages, manifests, dependencyGraphs);
|
||||||
pkg.locationsFoundAt.forEach(async (location: any) => {
|
|
||||||
if (!manifests.find((manifest: Manifest) => manifest.name == location)) {
|
return manifests;
|
||||||
const manifest = new Manifest(location, location);
|
}
|
||||||
|
|
||||||
|
private static addPackagesToManifests(packages: Array<ComponentDetectionPackage>, manifests: Array<Manifest>, dependencyGraphs: DependencyGraphs): void {
|
||||||
|
packages.forEach((pkg: ComponentDetectionPackage) => {
|
||||||
|
pkg.locationsFoundAt.forEach((location: any) => {
|
||||||
|
// Use the normalized path (remove leading slash if present)
|
||||||
|
let normalizedLocation = location.startsWith('/') ? location.substring(1) : location;
|
||||||
|
// Unescape the path, as upstream ComponentDetection emits locationsFoundAt in URL-encoded form
|
||||||
|
normalizedLocation = decodeURIComponent(normalizedLocation);
|
||||||
|
|
||||||
|
if (!manifests.find((manifest: Manifest) => manifest.name == normalizedLocation)) {
|
||||||
|
const manifest = new Manifest(normalizedLocation, normalizedLocation);
|
||||||
manifests.push(manifest);
|
manifests.push(manifest);
|
||||||
}
|
}
|
||||||
if (pkg.topLevelReferrers.length == 0) {
|
|
||||||
manifests.find((manifest: Manifest) => manifest.name == location)?.addDirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
|
const depGraphEntry = dependencyGraphs[normalizedLocation];
|
||||||
|
if (!depGraphEntry) {
|
||||||
|
core.warning(`No dependency graph entry found for manifest location: ${normalizedLocation}`);
|
||||||
|
return; // Skip this location if not found in dependencyGraphs
|
||||||
|
}
|
||||||
|
|
||||||
|
const directDependencies = depGraphEntry.explicitlyReferencedComponentIds;
|
||||||
|
if (directDependencies.includes(pkg.id)) {
|
||||||
|
manifests
|
||||||
|
.find((manifest: Manifest) => manifest.name == normalizedLocation)
|
||||||
|
?.addDirectDependency(
|
||||||
|
pkg,
|
||||||
|
ComponentDetection.getDependencyScope(pkg)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
manifests.find((manifest: Manifest) => manifest.name == location)?.addIndirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
|
manifests
|
||||||
|
.find((manifest: Manifest) => manifest.name == normalizedLocation)
|
||||||
|
?.addIndirectDependency(
|
||||||
|
pkg,
|
||||||
|
ComponentDetection.getDependencyScope(pkg)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return manifests;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static getDependencyScope(pkg: ComponentDetectionPackage) {
|
private static getDependencyScope(pkg: ComponentDetectionPackage) {
|
||||||
@@ -233,16 +271,66 @@ export default class ComponentDetection {
|
|||||||
throw new Error("Failed to download latest release");
|
throw new Error("Failed to download latest release");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes the keys of a DependencyGraphs object to be relative paths from the resolved filePath input.
|
||||||
|
* @param dependencyGraphs The DependencyGraphs object to normalize.
|
||||||
|
* @param filePathInput The filePath input (relative or absolute) from the action configuration.
|
||||||
|
* @returns A new DependencyGraphs object with relative path keys.
|
||||||
|
*/
|
||||||
|
public static normalizeDependencyGraphPaths(
|
||||||
|
dependencyGraphs: DependencyGraphs,
|
||||||
|
filePathInput: string
|
||||||
|
): DependencyGraphs {
|
||||||
|
// Resolve the base directory from filePathInput (relative to cwd if not absolute)
|
||||||
|
const baseDir = path.resolve(process.cwd(), filePathInput);
|
||||||
|
const normalized: DependencyGraphs = {};
|
||||||
|
for (const absPath in dependencyGraphs) {
|
||||||
|
// Make the path relative to the baseDir
|
||||||
|
let relPath = path.relative(baseDir, absPath).replace(/\\/g, '/');
|
||||||
|
normalized[relPath] = dependencyGraphs[absPath];
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComponentDetectionPackage extends Package {
|
class ComponentDetectionPackage extends Package {
|
||||||
|
public packageUrlString: string;
|
||||||
|
|
||||||
constructor(packageUrl: string, public id: string, public isDevelopmentDependency: boolean, public topLevelReferrers: [],
|
constructor(packageUrl: string, public id: string, public isDevelopmentDependency: boolean, public topLevelReferrers: [],
|
||||||
public locationsFoundAt: [], public containerDetailIds: [], public containerLayerIds: []) {
|
public locationsFoundAt: [], public containerDetailIds: [], public containerLayerIds: []) {
|
||||||
super(packageUrl);
|
super(packageUrl);
|
||||||
|
this.packageUrlString = packageUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types for the dependencyGraphs section of output.json
|
||||||
|
*/
|
||||||
|
export type DependencyGraph = {
|
||||||
|
/**
|
||||||
|
* The dependency graph: keys are component IDs, values are either null (no dependencies) or an array of component IDs (dependencies)
|
||||||
|
*/
|
||||||
|
graph: Record<string, string[] | null>;
|
||||||
|
/**
|
||||||
|
* Explicitly referenced component IDs
|
||||||
|
*/
|
||||||
|
explicitlyReferencedComponentIds: string[];
|
||||||
|
/**
|
||||||
|
* Development dependencies
|
||||||
|
*/
|
||||||
|
developmentDependencies: string[];
|
||||||
|
/**
|
||||||
|
* Regular dependencies
|
||||||
|
*/
|
||||||
|
dependencies: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The top-level dependencyGraphs object: keys are manifest file paths, values are DependencyGraph objects
|
||||||
|
*/
|
||||||
|
export type DependencyGraphs = Record<string, DependencyGraph>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+34
@@ -7,7 +7,41 @@ export default class ComponentDetection {
|
|||||||
static runComponentDetection(path: string): Promise<void>;
|
static runComponentDetection(path: string): Promise<void>;
|
||||||
private static getComponentDetectionParameters;
|
private static getComponentDetectionParameters;
|
||||||
static getManifestsFromResults(): Promise<Manifest[] | undefined>;
|
static getManifestsFromResults(): Promise<Manifest[] | undefined>;
|
||||||
|
static processComponentsToManifests(componentsFound: any[], dependencyGraphs: DependencyGraphs): Manifest[];
|
||||||
|
private static addPackagesToManifests;
|
||||||
private static getDependencyScope;
|
private static getDependencyScope;
|
||||||
static makePackageUrl(packageUrlJson: any): string;
|
static makePackageUrl(packageUrlJson: any): string;
|
||||||
private static getLatestReleaseURL;
|
private static getLatestReleaseURL;
|
||||||
|
/**
|
||||||
|
* Normalizes the keys of a DependencyGraphs object to be relative paths from the resolved filePath input.
|
||||||
|
* @param dependencyGraphs The DependencyGraphs object to normalize.
|
||||||
|
* @param filePathInput The filePath input (relative or absolute) from the action configuration.
|
||||||
|
* @returns A new DependencyGraphs object with relative path keys.
|
||||||
|
*/
|
||||||
|
static normalizeDependencyGraphPaths(dependencyGraphs: DependencyGraphs, filePathInput: string): DependencyGraphs;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Types for the dependencyGraphs section of output.json
|
||||||
|
*/
|
||||||
|
export type DependencyGraph = {
|
||||||
|
/**
|
||||||
|
* The dependency graph: keys are component IDs, values are either null (no dependencies) or an array of component IDs (dependencies)
|
||||||
|
*/
|
||||||
|
graph: Record<string, string[] | null>;
|
||||||
|
/**
|
||||||
|
* Explicitly referenced component IDs
|
||||||
|
*/
|
||||||
|
explicitlyReferencedComponentIds: string[];
|
||||||
|
/**
|
||||||
|
* Development dependencies
|
||||||
|
*/
|
||||||
|
developmentDependencies: string[];
|
||||||
|
/**
|
||||||
|
* Regular dependencies
|
||||||
|
*/
|
||||||
|
dependencies: string[];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* The top-level dependencyGraphs object: keys are manifest file paths, values are DependencyGraph objects
|
||||||
|
*/
|
||||||
|
export type DependencyGraphs = Record<string, DependencyGraph>;
|
||||||
|
|||||||
+56
-13
@@ -36002,6 +36002,7 @@ const cross_fetch_1 = __importDefault(__nccwpck_require__(3304));
|
|||||||
const fs_1 = __importDefault(__nccwpck_require__(9896));
|
const fs_1 = __importDefault(__nccwpck_require__(9896));
|
||||||
const exec = __importStar(__nccwpck_require__(5236));
|
const exec = __importStar(__nccwpck_require__(5236));
|
||||||
const dotenv_1 = __importDefault(__nccwpck_require__(8889));
|
const dotenv_1 = __importDefault(__nccwpck_require__(8889));
|
||||||
|
const path_1 = __importDefault(__nccwpck_require__(6928));
|
||||||
dotenv_1.default.config();
|
dotenv_1.default.config();
|
||||||
class ComponentDetection {
|
class ComponentDetection {
|
||||||
// This is the default entry point for this class.
|
// This is the default entry point for this class.
|
||||||
@@ -36054,12 +36055,17 @@ class ComponentDetection {
|
|||||||
static getManifestsFromResults() {
|
static getManifestsFromResults() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
core.info("Getting manifests from results");
|
core.info("Getting manifests from results");
|
||||||
|
const results = yield fs_1.default.readFileSync(this.outputPath, 'utf8');
|
||||||
|
var json = JSON.parse(results);
|
||||||
|
let dependencyGraphs = this.normalizeDependencyGraphPaths(json.dependencyGraphs, core.getInput('filePath'));
|
||||||
|
return this.processComponentsToManifests(json.componentsFound, dependencyGraphs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static processComponentsToManifests(componentsFound, dependencyGraphs) {
|
||||||
// Parse the result file and add the packages to the package cache
|
// Parse the result file and add the packages to the package cache
|
||||||
const packageCache = new dependency_submission_toolkit_1.PackageCache();
|
const packageCache = new dependency_submission_toolkit_1.PackageCache();
|
||||||
const packages = [];
|
const packages = [];
|
||||||
const results = yield fs_1.default.readFileSync(this.outputPath, 'utf8');
|
componentsFound.forEach((component) => __awaiter(this, void 0, void 0, function* () {
|
||||||
var json = JSON.parse(results);
|
|
||||||
json.componentsFound.forEach((component) => __awaiter(this, void 0, void 0, function* () {
|
|
||||||
// Skip components without packageUrl
|
// Skip components without packageUrl
|
||||||
if (!component.component.packageUrl) {
|
if (!component.component.packageUrl) {
|
||||||
core.debug(`Skipping component detected without packageUrl: ${JSON.stringify({
|
core.debug(`Skipping component detected without packageUrl: ${JSON.stringify({
|
||||||
@@ -36091,6 +36097,7 @@ class ComponentDetection {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const referrerUrl = ComponentDetection.makePackageUrl(referrer.packageUrl);
|
const referrerUrl = ComponentDetection.makePackageUrl(referrer.packageUrl);
|
||||||
|
referrer.packageUrlString = referrerUrl;
|
||||||
// Skip if the generated packageUrl is empty
|
// Skip if the generated packageUrl is empty
|
||||||
if (!referrerUrl) {
|
if (!referrerUrl) {
|
||||||
core.debug(`Skipping referrer with invalid packageUrl for component: ${pkg.id}`);
|
core.debug(`Skipping referrer with invalid packageUrl for component: ${pkg.id}`);
|
||||||
@@ -36098,6 +36105,10 @@ class ComponentDetection {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const referrerPackage = packageCache.lookupPackage(referrerUrl);
|
const referrerPackage = packageCache.lookupPackage(referrerUrl);
|
||||||
|
if (referrerPackage === pkg) {
|
||||||
|
core.debug(`Skipping self-reference for package: ${pkg.id}`);
|
||||||
|
return; // Skip self-references
|
||||||
|
}
|
||||||
if (referrerPackage) {
|
if (referrerPackage) {
|
||||||
referrerPackage.dependsOn(pkg);
|
referrerPackage.dependsOn(pkg);
|
||||||
}
|
}
|
||||||
@@ -36110,22 +36121,36 @@ class ComponentDetection {
|
|||||||
// Create manifests
|
// Create manifests
|
||||||
const manifests = [];
|
const manifests = [];
|
||||||
// Check the locationsFoundAt for every package and add each as a manifest
|
// Check the locationsFoundAt for every package and add each as a manifest
|
||||||
packages.forEach((pkg) => __awaiter(this, void 0, void 0, function* () {
|
this.addPackagesToManifests(packages, manifests, dependencyGraphs);
|
||||||
pkg.locationsFoundAt.forEach((location) => __awaiter(this, void 0, void 0, function* () {
|
return manifests;
|
||||||
|
}
|
||||||
|
static addPackagesToManifests(packages, manifests, dependencyGraphs) {
|
||||||
|
packages.forEach((pkg) => {
|
||||||
|
pkg.locationsFoundAt.forEach((location) => {
|
||||||
var _a, _b;
|
var _a, _b;
|
||||||
if (!manifests.find((manifest) => manifest.name == location)) {
|
// Use the normalized path (remove leading slash if present)
|
||||||
const manifest = new dependency_submission_toolkit_1.Manifest(location, location);
|
let normalizedLocation = location.startsWith('/') ? location.substring(1) : location;
|
||||||
|
// Unescape the path, as upstream ComponentDetection emits locationsFoundAt in URL-encoded form
|
||||||
|
normalizedLocation = decodeURIComponent(normalizedLocation);
|
||||||
|
if (!manifests.find((manifest) => manifest.name == normalizedLocation)) {
|
||||||
|
const manifest = new dependency_submission_toolkit_1.Manifest(normalizedLocation, normalizedLocation);
|
||||||
manifests.push(manifest);
|
manifests.push(manifest);
|
||||||
}
|
}
|
||||||
if (pkg.topLevelReferrers.length == 0) {
|
const depGraphEntry = dependencyGraphs[normalizedLocation];
|
||||||
(_a = manifests.find((manifest) => manifest.name == location)) === null || _a === void 0 ? void 0 : _a.addDirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
|
if (!depGraphEntry) {
|
||||||
|
core.warning(`No dependency graph entry found for manifest location: ${normalizedLocation}`);
|
||||||
|
return; // Skip this location if not found in dependencyGraphs
|
||||||
|
}
|
||||||
|
const directDependencies = depGraphEntry.explicitlyReferencedComponentIds;
|
||||||
|
if (directDependencies.includes(pkg.id)) {
|
||||||
|
(_a = manifests
|
||||||
|
.find((manifest) => manifest.name == normalizedLocation)) === null || _a === void 0 ? void 0 : _a.addDirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
(_b = manifests.find((manifest) => manifest.name == location)) === null || _b === void 0 ? void 0 : _b.addIndirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
|
(_b = manifests
|
||||||
|
.find((manifest) => manifest.name == normalizedLocation)) === null || _b === void 0 ? void 0 : _b.addIndirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
}));
|
|
||||||
return manifests;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
static getDependencyScope(pkg) {
|
static getDependencyScope(pkg) {
|
||||||
@@ -36203,6 +36228,23 @@ class ComponentDetection {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Normalizes the keys of a DependencyGraphs object to be relative paths from the resolved filePath input.
|
||||||
|
* @param dependencyGraphs The DependencyGraphs object to normalize.
|
||||||
|
* @param filePathInput The filePath input (relative or absolute) from the action configuration.
|
||||||
|
* @returns A new DependencyGraphs object with relative path keys.
|
||||||
|
*/
|
||||||
|
static normalizeDependencyGraphPaths(dependencyGraphs, filePathInput) {
|
||||||
|
// Resolve the base directory from filePathInput (relative to cwd if not absolute)
|
||||||
|
const baseDir = path_1.default.resolve(process.cwd(), filePathInput);
|
||||||
|
const normalized = {};
|
||||||
|
for (const absPath in dependencyGraphs) {
|
||||||
|
// Make the path relative to the baseDir
|
||||||
|
let relPath = path_1.default.relative(baseDir, absPath).replace(/\\/g, '/');
|
||||||
|
normalized[relPath] = dependencyGraphs[absPath];
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports["default"] = ComponentDetection;
|
exports["default"] = ComponentDetection;
|
||||||
ComponentDetection.componentDetectionPath = process.platform === "win32" ? './component-detection.exe' : './component-detection';
|
ComponentDetection.componentDetectionPath = process.platform === "win32" ? './component-detection.exe' : './component-detection';
|
||||||
@@ -36216,6 +36258,7 @@ class ComponentDetectionPackage extends dependency_submission_toolkit_1.Package
|
|||||||
this.locationsFoundAt = locationsFoundAt;
|
this.locationsFoundAt = locationsFoundAt;
|
||||||
this.containerDetailIds = containerDetailIds;
|
this.containerDetailIds = containerDetailIds;
|
||||||
this.containerLayerIds = containerLayerIds;
|
this.containerLayerIds = containerLayerIds;
|
||||||
|
this.packageUrlString = packageUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
Generated
+8719
-4773
File diff suppressed because it is too large
Load Diff
+14
-14
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "component-detection-action",
|
"name": "component-detection-action",
|
||||||
"version": "1.0.0",
|
"version": "0.1.0",
|
||||||
"description": "Component detection action",
|
"description": "Component detection action",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -30,22 +30,22 @@
|
|||||||
"@actions/github": "^6.0.1",
|
"@actions/github": "^6.0.1",
|
||||||
"@github/dependency-submission-toolkit": "^2.0.5",
|
"@github/dependency-submission-toolkit": "^2.0.5",
|
||||||
"cross-fetch": "^4.1.0",
|
"cross-fetch": "^4.1.0",
|
||||||
"dotenv": "^16.5.0",
|
"dotenv": "^17.2.3",
|
||||||
"fs": "^0.0.1-security",
|
"fs": "^0.0.1-security",
|
||||||
"octokit": "^4.1.3",
|
"octokit": "^5.0.5",
|
||||||
"tar": "^7.4.3",
|
"tar": "^7.5.2",
|
||||||
"yaml": "^2.7.1"
|
"yaml": "^2.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/preset-env": "^7.27.2",
|
"@babel/preset-env": "^7.28.5",
|
||||||
"@babel/preset-typescript": "^7.27.1",
|
"@babel/preset-typescript": "^7.28.5",
|
||||||
"@eslint/js": "^9.26.0",
|
"@eslint/js": "^9.39.1",
|
||||||
"@types/glob": "^8.1.0",
|
"@types/glob": "^9.0.0",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^30.0.0",
|
||||||
"@vercel/ncc": "^0.38.3",
|
"@vercel/ncc": "^0.38.4",
|
||||||
"eslint": "^9.26.0",
|
"eslint": "^9.39.1",
|
||||||
"jest": "^29.7.0",
|
"jest": "^30.2.0",
|
||||||
"jest-transform-stub": "^2.0.0",
|
"jest-transform-stub": "^2.0.0",
|
||||||
"ts-jest": "^29.3.2"
|
"ts-jest": "^29.4.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+45
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"name": "nested-test-package",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "nested-test-package",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash": "^4.17.21"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"jest": "^29.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lodash": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
|
},
|
||||||
|
"node_modules/jest": {
|
||||||
|
"version": "29.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
|
||||||
|
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"jest": "bin/jest.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"lodash": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
|
},
|
||||||
|
"jest": {
|
||||||
|
"version": "29.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
|
||||||
|
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "nested-test-package",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A nested test package for component detection testing",
|
||||||
|
"main": "index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash": "^4.17.21"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"jest": "^29.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+18
-18
@@ -685,9 +685,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/eslintrc/node_modules/js-yaml": {
|
"node_modules/@eslint/eslintrc/node_modules/js-yaml": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
@@ -2273,9 +2273,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint/node_modules/js-yaml": {
|
"node_modules/eslint/node_modules/js-yaml": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
@@ -3541,9 +3541,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
"version": "3.14.1",
|
"version": "3.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
||||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^1.0.7",
|
"argparse": "^1.0.7",
|
||||||
@@ -5338,9 +5338,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"js-yaml": {
|
"js-yaml": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
@@ -6538,9 +6538,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"js-yaml": {
|
"js-yaml": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
@@ -7525,9 +7525,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"js-yaml": {
|
"js-yaml": {
|
||||||
"version": "3.14.1",
|
"version": "3.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
||||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"argparse": "^1.0.7",
|
"argparse": "^1.0.7",
|
||||||
|
|||||||
Reference in New Issue
Block a user