/** * Install-time guard (v5.5, roadmap Bet 2). * * Blocks known-bad packages BEFORE the package manager runs their lifecycle * scripts: `supply-chain-guard guard npm install ` checks every package * spec on the command line against the OFFLINE IOC sources (bundled threat * feed + refreshed .scg-cache feed + known-bad-version blocklist + typosquat * heuristics) and only invokes the real package manager when nothing matches. * * Everything is auditable in git history, works offline, needs no account. * No network calls are made by this module. */ import { type FeedIOC } from "./threat-intel.js"; import type { Finding } from "./types.js"; export declare const SUPPORTED_MANAGERS: readonly ["npm", "pnpm", "yarn", "bun"]; export type PackageManager = (typeof SUPPORTED_MANAGERS)[number]; /** * The four managers are shipped as .cmd shims on Windows; spawn needs the * shim name there. The platform parameter exists for tests only. */ export declare function resolveManagerBinary(manager: PackageManager, platform?: NodeJS.Platform): string; export interface InstallPackageSpec { /** Token exactly as given on the command line */ raw: string; /** Package name ("lodash", "@scope/name") */ name: string; /** Version/range/tag after the last "@", if present ("1.2.3", "^1.0.0", "latest") */ version?: string; } /** * Parse one command-line token into a package spec. Returns null for flags * and for tokens that are not plain registry specs. */ export declare function parseSpecToken(token: string): InstallPackageSpec | null; /** * Extract package specs from manager args. * * The install verb is the first bare token that IS a known install verb, * found by scanning positionally while skipping flags, flag values, and the * `global` positional modifier. This defeats two confirmed bypasses (v5.6.0 * gate M3): a value-taking global flag shifting the apparent verb * (`npm --prefix ./x install evil`) and Yarn's `global add` form * (`yarn global add evil`). If no install verb is present the command * installs nothing new and passes through unscanned. */ export declare function extractInstallSpecs(manager: PackageManager, args: string[]): { verb?: string; installVerb: boolean; specs: InstallPackageSpec[]; }; export interface InstallGuardVerdict { spec: InstallPackageSpec; findings: Finding[]; } export interface InstallCommandAnalysis { manager: PackageManager; /** First non-flag manager arg (undefined when args are all flags/empty) */ verb?: string; /** True when the verb adds new packages from the command line */ installVerb: boolean; specs: InstallPackageSpec[]; /** One verdict per spec; findings empty = clean */ verdicts: InstallGuardVerdict[]; /** True when at least one spec has findings */ blocked: boolean; } /** * npm package IOCs in the feed carry no ecosystem prefix (only ruby:/composer:/ * nuget:/go:/jenkins: entries do - see matchPackageIOC). Same companion * matcher as mcp-server.ts matchBarePackageIOC. */ export declare function matchBareNpmIOC(name: string, version: string | undefined, feed: FeedIOC[]): FeedIOC | null; /** * Pure analysis of an install command: no spawn, no network, no filesystem * writes (loadThreatIntel reads the local feed cache when no feed is given). */ export declare function analyzeInstallCommand(manager: string, args: string[], feed?: FeedIOC[]): InstallCommandAnalysis; /** Injectable spawn signature - tests replace this so nothing is executed. */ export type SpawnLike = (command: string, args: string[], options: { stdio: "inherit"; shell: false; }) => { status: number | null; error?: Error; }; /** * ^-escape a bare command name for cmd.exe (never quoted). The .cmd/.bat shim * re-expands the whole line through cmd once more via `%*`, so metacharacters * must be ^-escaped TWICE (doubleEscapeMetaChars in cross-spawn). Single * escaping is a command-injection hole: v5.6.0 gate finding M1 proved * `x"&echo INJECTED&"` broke out during the %* re-parse with one escape and * did not with two. */ export declare function escapeCmdShellCommand(command: string): string; /** * Quote + double-^-escape one argument for cmd.exe (cross-spawn technique for * .cmd/.bat targets): backslash-double the sequences before quotes, wrap in * double quotes, then ^-escape every cmd metacharacter twice because the shim * re-parses the line. See escapeCmdShellCommand for why two passes. */ export declare function escapeCmdShellArg(arg: string): string; export interface InstallGuardOptions { /** Proceed despite findings (loud warning). */ force?: boolean; /** Check only; never invoke the package manager. */ dryRun?: boolean; /** Injected feed (tests); defaults to loadThreatIntel(). */ feed?: FeedIOC[]; /** Injected spawn (tests); defaults to node:child_process spawnSync. */ spawn?: SpawnLike; /** Injected output sink; defaults to console.log. */ log?: (line: string) => void; } /** * Analyze the command, print findings, and (unless blocked or --dry-run) * invoke the package manager with the args untouched. Returns the process * exit code: manager's own code on pass-through, 2 when blocked, 0 for a * clean --dry-run. * * Execution is spawn-without-shell on every platform; the manager name is * restricted to the four known binaries, so no shell string is ever built * from user input. */ export declare function runInstallGuard(manager: string, managerArgs: string[], options?: InstallGuardOptions): number; //# sourceMappingURL=install-guard.d.ts.map