From 070b29482a4696f01dd1b34d30e6669595c5df09 Mon Sep 17 00:00:00 2001 From: kulturman Date: Wed, 15 Apr 2026 15:54:01 +0000 Subject: [PATCH] feat(tarball): allow AstAnalyser injection in NpmTarball --- .changeset/all-chairs-camp.md | 5 ++ .../tarball/src/class/NpmTarball.class.ts | 11 ++-- workspaces/tarball/test/NpmTarball.spec.ts | 54 ++++++++++++++++++- 3 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 .changeset/all-chairs-camp.md diff --git a/.changeset/all-chairs-camp.md b/.changeset/all-chairs-camp.md new file mode 100644 index 00000000..a75e37ac --- /dev/null +++ b/.changeset/all-chairs-camp.md @@ -0,0 +1,5 @@ +--- +"@nodesecure/tarball": minor +--- + +Allow injecting an AstAnalyser instance into NpmTarball. diff --git a/workspaces/tarball/src/class/NpmTarball.class.ts b/workspaces/tarball/src/class/NpmTarball.class.ts index 47bcdbea..ff8a7a7c 100644 --- a/workspaces/tarball/src/class/NpmTarball.class.ts +++ b/workspaces/tarball/src/class/NpmTarball.class.ts @@ -42,6 +42,7 @@ export interface NpmTarballScanFilesOptions { export type NpmTarballOptions = { resolver?: Resolver; + astAnalyser?: AstAnalyser; }; export class NpmTarball { @@ -53,6 +54,7 @@ export class NpmTarball { manifest: LocatedManifestManager; #resolver: Resolver; + #astAnalyser: AstAnalyser | null; constructor( mama: ManifestManager, @@ -64,6 +66,7 @@ export class NpmTarball { this.manifest = mama; this.#resolver = options?.resolver ?? new DnsResolver(); + this.#astAnalyser = options?.astAnalyser ?? null; } async scanFiles( @@ -90,11 +93,11 @@ export class NpmTarball { astAnalyserOptions ?? {} ); - const hostNameSet = options?.collectables?.find( - (collectable) => collectable.type === "hostname" - )!; + const astAnalyser = this.#astAnalyser ?? new AstAnalyser(options); - const astAnalyser = new AstAnalyser(options); + const hostNameSet = astAnalyser.getCollectableSet("hostname") as + | DefaultCollectableSet + | undefined; code = await new SourceCodeScanner(this.manifest, { astAnalyser }).iterate({ manifest: [...this.manifest.getEntryFiles()] diff --git a/workspaces/tarball/test/NpmTarball.spec.ts b/workspaces/tarball/test/NpmTarball.spec.ts index ba06ce2f..5c7eac9e 100644 --- a/workspaces/tarball/test/NpmTarball.spec.ts +++ b/workspaces/tarball/test/NpmTarball.spec.ts @@ -4,7 +4,7 @@ import { describe, test } from "node:test"; import assert from "node:assert"; // Import Third-party Dependencies -import { DefaultCollectableSet, warnings, type Warning } from "@nodesecure/js-x-ray"; +import { DefaultCollectableSet, warnings, type Warning, AstAnalyser } from "@nodesecure/js-x-ray"; import { ManifestManager } from "@nodesecure/mama"; type SourceArrayLocation = [[number, number], [number, number]]; @@ -78,6 +78,58 @@ describe("NpmTarball", () => { ); }); + test("it should emit shady-link warnings with an injected AstAnalyser", async() => { + const mama = await ManifestManager.fromPackageJSON(path.join(kFixturePath, "shady-link", "package.json")); + + const npmTarball = new NpmTarball(mama, { + astAnalyser: new AstAnalyser({ + collectables: [new DefaultCollectableSet("hostname")] + }) + }); + + const result = await npmTarball.scanFiles(); + + assert.deepEqual( + result.code.warnings.sort(compareWarning), + [{ + ...warnings["shady-link"], + kind: "shady-link", + location: [[[1, 18], [1, 50]]] as SourceArrayLocation[], + source: "Scanner", + value: "10.0.0.1.sslip.io", + file: path.join(kShadyLinkPath, "private-ip-1") + }, + { + ...warnings["shady-link"], + kind: "shady-link", + location: [[[3, 19], [3, 51]]] as SourceArrayLocation[], + source: "Scanner", + value: "10.0.0.1.sslip.io", + file: path.join(kShadyLinkPath, "private-ip-2") + }, + { + ...warnings["shady-link"], + kind: "shady-link", + location: [[[1, 18], [1, 50]]] as SourceArrayLocation[], + source: "Scanner", + file: path.join(kShadyLinkPath, "private-ip-2"), + value: "192-168-1-250.sslip.io" + }].sort(compareWarning) + ); + }); + + test("it should ignore astAnalyserOptions when an AstAnalyser is injected", async() => { + const mama = await ManifestManager.fromPackageJSON(path.join(kFixturePath, "shady-link", "package.json")); + const npmTarball = new NpmTarball(mama, { + astAnalyser: new AstAnalyser() + }); + + const result = await npmTarball.scanFiles({ + collectables: [new DefaultCollectableSet("hostname")] + }); + assert.equal(result.code.warnings.length, 0); + }); + test("it should have a shady-link warning when a hostname resolve a private ip address without options", async() => { const mama = await ManifestManager.fromPackageJSON(path.join(kFixturePath, "shady-link", "package.json")); const npmTarball = new NpmTarball(mama);