Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/six-clowns-punch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nodesecure/scanner": minor
---

Add integrity as second argument of cacheLookup for workingDir API.
3 changes: 2 additions & 1 deletion workspaces/scanner/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ type WorkingDirOptions = Options & {
* Optional cache lookup called after reading the local package.json.
*/
cacheLookup?: (
packageJSON: PackageJSON
packageJSON: PackageJSON,
integrity: string | null
) => Promise<Payload | null>;
};

Expand Down
3 changes: 2 additions & 1 deletion workspaces/scanner/docs/workingDir.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ export type WorkingDirOptions = Options & {
* If it returns a non-null Payload, the dependency walker is skipped entirely.
*/
cacheLookup?: (
packageJSON: PackageJSON
packageJSON: PackageJSON,
integrity: string | null
) => Promise<Payload | null>;
};

Expand Down
20 changes: 15 additions & 5 deletions workspaces/scanner/src/depWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ type WalkerOptions = Omit<Options, "registry"> & {
location?: string;
npmRcConfig?: Config;
npmRcEntries?: Record<string, string>;
integrity?: string | null;
};

type InitialPayload =
Expand Down Expand Up @@ -124,7 +125,8 @@ export async function depWalker(
npmRcConfig,
npmRcEntries = {},
maxConcurrency = 8,
workers
workers,
integrity: manifestIntegrity = null
} = options;

const statsCollector = new StatsCollector({ logger }, { isVerbose });
Expand Down Expand Up @@ -274,10 +276,7 @@ export async function depWalker(
payload.rootDependency.integrity = integrity;
}
else if (isRoot) {
const isWorkspace = options.location && "workspaces" in manifest;
payload.rootDependency.integrity = isWorkspace ?
null :
fromData(JSON.stringify(manifest), { algorithms: ["sha512"] }).toString();
payload.rootDependency.integrity = manifestIntegrity ?? getManifestIntegrity(manifest);
}

// If the dependency is a DevDependencies we ignore it.
Expand Down Expand Up @@ -432,6 +431,17 @@ export async function depWalker(
}
}

export function getManifestIntegrity(
manifest: PackageJSON | WorkspacesPackageJSON
): string | null {
const isWorkspace = "workspaces" in manifest;
const integrity = isWorkspace ?
null :
fromData(JSON.stringify(manifest), { algorithms: ["sha512"] }).toString();

return integrity;
}

function extractHighlightedIdentifiers(
collectables: DefaultCollectableSet<Metadata>[],
identifiersToHighlight: Set<string>
Expand Down
14 changes: 10 additions & 4 deletions workspaces/scanner/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import type { PackageJSON } from "@nodesecure/npm-types";
import type Config from "@npmcli/config";

// Import Internal Dependencies
import { depWalker } from "./depWalker.ts";
import {
depWalker,
getManifestIntegrity
} from "./depWalker.ts";
import {
NPM_TOKEN,
urlToString,
Expand Down Expand Up @@ -44,7 +47,8 @@ export type WorkingDirOptions = Options & {
*/
npmRcConfig?: Config;
cacheLookup?: (
packageJSON: PackageJSON
packageJSON: PackageJSON,
integrity: string | null
) => Promise<Payload | null>;
};

Expand Down Expand Up @@ -80,14 +84,16 @@ export async function workingDir(
logger.end(ScannerLoggerEvents.manifest.read);

const packageJSON = JSON.parse(str) as PackageJSON;
const cachedPayload = await options.cacheLookup?.(packageJSON);

const integrity = getManifestIntegrity(packageJSON);
const cachedPayload = await options.cacheLookup?.(packageJSON, integrity);
if (cachedPayload) {
return cachedPayload;
}

return depWalker(
packageJSON,
finalizedOptions,
Object.assign(finalizedOptions, { integrity }),
logger
);
}
Expand Down
10 changes: 9 additions & 1 deletion workspaces/scanner/test/workingDir.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,11 @@ describe("scanner.workingDir()", { concurrency: 2 }, () => {
const file = path.join(kFixturePath, "non-npm-package");

const capturedPackageJSONs: PackageJSON[] = [];
const capturedIntegrities: (string | null)[] = [];
const result = await workingDir(file, {
cacheLookup: async(packageJSON) => {
cacheLookup: async(packageJSON, integrity) => {
capturedPackageJSONs.push(packageJSON);
capturedIntegrities.push(integrity);

return fakePayload;
}
Expand All @@ -141,6 +143,12 @@ describe("scanner.workingDir()", { concurrency: 2 }, () => {
assert.strictEqual(capturedPackageJSONs.length, 1);
assert.strictEqual(capturedPackageJSONs[0].name, "non-npm-package");
assert.strictEqual(capturedPackageJSONs[0].version, "1.0.0");
assert.strictEqual(capturedIntegrities.length, 1);
assert.strictEqual(
typeof capturedIntegrities[0],
"string",
"integrity should be a non-null string for non-workspace packages"
);
});

it("should proceed with a full scan when null is returned", async() => {
Expand Down
Loading