From b9f1ad3b2d1cf4a8f077084271a9740b8d745f24 Mon Sep 17 00:00:00 2001 From: fraxken Date: Fri, 30 May 2025 00:56:21 +0200 Subject: [PATCH] feat(scanner): implement FlagsExtractor --- .changeset/little-suns-grow.md | 5 +++ workspaces/scanner/docs/extractors.md | 3 ++ .../extractors/probes/FlagsExtractor.class.ts | 33 +++++++++++++++++++ .../scanner/src/extractors/probes/index.ts | 1 + .../scanner/test/extractors/payload.spec.ts | 24 ++++++++++++++ 5 files changed, 66 insertions(+) create mode 100644 .changeset/little-suns-grow.md create mode 100644 workspaces/scanner/src/extractors/probes/FlagsExtractor.class.ts diff --git a/.changeset/little-suns-grow.md b/.changeset/little-suns-grow.md new file mode 100644 index 00000000..d4d716b4 --- /dev/null +++ b/.changeset/little-suns-grow.md @@ -0,0 +1,5 @@ +--- +"@nodesecure/scanner": minor +--- + +Implement a new Probe extractor for flags diff --git a/workspaces/scanner/docs/extractors.md b/workspaces/scanner/docs/extractors.md index 258b8656..c257e67f 100644 --- a/workspaces/scanner/docs/extractors.md +++ b/workspaces/scanner/docs/extractors.md @@ -34,6 +34,9 @@ Available probes include: | ContactExtractor | manifest | | LicensesExtractor | manifest | | SizeExtractor | manifest | +| FlagsExtractor | manifest | +| VulnerabilitiesExtractor | packument | +| WarningsExtractor | manifest | All probes follow the same `ProbeExtractor` interface, which acts as an iterator-like contract: diff --git a/workspaces/scanner/src/extractors/probes/FlagsExtractor.class.ts b/workspaces/scanner/src/extractors/probes/FlagsExtractor.class.ts new file mode 100644 index 00000000..bc32a2dc --- /dev/null +++ b/workspaces/scanner/src/extractors/probes/FlagsExtractor.class.ts @@ -0,0 +1,33 @@ +// Import Third-party Dependencies +import FrequencySet from "frequency-set"; + +// Import Internal Dependencies +import type { + ManifestProbeExtractor +} from "../payload.js"; +import type { DependencyVersion } from "../../types.js"; + +export type FlagsExtractorResult = { + flags: Record; +}; + +export class FlagsExtractor implements ManifestProbeExtractor { + level = "manifest" as const; + + #flags = new FrequencySet(); + + next( + _: string, + version: DependencyVersion + ) { + const { flags } = version; + + flags.forEach((flagName) => this.#flags.add(flagName)); + } + + done() { + return { + flags: Object.fromEntries(this.#flags) + }; + } +} diff --git a/workspaces/scanner/src/extractors/probes/index.ts b/workspaces/scanner/src/extractors/probes/index.ts index d9771c76..420b6a98 100644 --- a/workspaces/scanner/src/extractors/probes/index.ts +++ b/workspaces/scanner/src/extractors/probes/index.ts @@ -3,3 +3,4 @@ export * from "./LicensesExtractor.class.js"; export * from "./ContactExtractor.class.js"; export * from "./WarningsExtractor.class.js"; export * from "./VulnerabilitiesExtractor.class.js"; +export * from "./FlagsExtractor.class.js"; diff --git a/workspaces/scanner/test/extractors/payload.spec.ts b/workspaces/scanner/test/extractors/payload.spec.ts index a2da4505..d9481612 100644 --- a/workspaces/scanner/test/extractors/payload.spec.ts +++ b/workspaces/scanner/test/extractors/payload.spec.ts @@ -179,6 +179,30 @@ describe("Extractors.Probes", () => { }); }); + describe("FlagsExtractor", () => { + it("should extract strnum flags", () => { + const extractor = new Extractors.Payload( + strnumNodesecurePayload, + [ + new Extractors.Probes.FlagsExtractor() + ] + ); + + const { + flags + } = extractor.extractAndMerge(); + + assert.deepEqual( + flags, + { + hasWarnings: 1, + isOutdated: 1, + hasManyPublishers: 1 + } + ); + }); + }); + describe("VulnerabilitiesExtractor", () => { it("should extract strnum warnings", () => { const fakePayload: any = {