trawly 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/scanner.ts","../src/extractors/npm-package-lock.ts","../src/sources/osv.ts","../src/types.ts"],"sourcesContent":["import { existsSync, statSync } from \"node:fs\";\nimport { resolve, join } from \"node:path\";\nimport { parseNpmPackageLock } from \"./extractors/npm-package-lock.js\";\nimport { queryOsv } from \"./sources/osv.js\";\nimport { SEVERITY_RANK } from \"./types.js\";\nimport type {\n Finding,\n PackageInstance,\n ScanError,\n ScanLockfileOptions,\n ScanProjectOptions,\n ScanResult,\n Severity,\n} from \"./types.js\";\n\nexport async function scanProject(\n options: ScanProjectOptions = {},\n): Promise<ScanResult> {\n const cwd = resolve(options.cwd ?? process.cwd());\n const lockfilePath = options.lockfile\n ? resolve(cwd, options.lockfile)\n : detectLockfile(cwd);\n\n if (!lockfilePath) {\n throw new ScanInputError(\n `No npm lockfile found in ${cwd}. Pass --lockfile or run in a directory with package-lock.json.`,\n );\n }\n\n return scanLockfile({\n lockfilePath,\n includeDev: options.includeDev,\n prodOnly: options.prodOnly,\n fetchImpl: options.fetchImpl,\n });\n}\n\nexport async function scanLockfile(\n options: ScanLockfileOptions,\n): Promise<ScanResult> {\n const { lockfilePath } = options;\n if (!existsSync(lockfilePath)) {\n throw new ScanInputError(`Lockfile does not exist: ${lockfilePath}`);\n }\n const stat = statSync(lockfilePath);\n if (!stat.isFile()) {\n throw new ScanInputError(`Lockfile path is not a file: ${lockfilePath}`);\n }\n\n const allInstances = parseNpmPackageLock(lockfilePath);\n const instances = filterInstances(allInstances, options);\n const errors: ScanError[] = [];\n\n let findings: Finding[] = [];\n try {\n findings = await queryOsv(instances, { fetchImpl: options.fetchImpl });\n } catch (err) {\n errors.push({\n message: \"Failed to query OSV advisory database\",\n cause: (err as Error).message,\n });\n }\n\n findings.sort(compareFindings);\n\n return {\n scannedAt: new Date().toISOString(),\n packagesScanned: instances.length,\n findings,\n summary: summarize(findings),\n errors,\n };\n}\n\nexport class ScanInputError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ScanInputError\";\n }\n}\n\nfunction detectLockfile(cwd: string): string | undefined {\n const candidate = join(cwd, \"package-lock.json\");\n return existsSync(candidate) ? candidate : undefined;\n}\n\nfunction filterInstances(\n instances: PackageInstance[],\n options: { includeDev?: boolean; prodOnly?: boolean },\n): PackageInstance[] {\n const includeDev = options.prodOnly ? false : options.includeDev !== false;\n if (includeDev) return instances;\n return instances.filter((p) => !p.dev);\n}\n\nexport function compareFindings(a: Finding, b: Finding): number {\n const sev = SEVERITY_RANK[b.severity] - SEVERITY_RANK[a.severity];\n if (sev !== 0) return sev;\n if (a.packageName !== b.packageName) {\n return a.packageName.localeCompare(b.packageName);\n }\n if (a.installedVersion !== b.installedVersion) {\n return a.installedVersion.localeCompare(b.installedVersion);\n }\n return a.id.localeCompare(b.id);\n}\n\nexport function summarize(findings: Finding[]): Record<Severity, number> {\n const summary: Record<Severity, number> = {\n critical: 0,\n high: 0,\n moderate: 0,\n low: 0,\n unknown: 0,\n };\n for (const f of findings) summary[f.severity]++;\n return summary;\n}\n\n/**\n * Returns true when any finding meets or exceeds the given severity threshold.\n * \"none\" means never fail.\n */\nexport function meetsThreshold(\n findings: Finding[],\n threshold: Severity | \"none\",\n): boolean {\n if (threshold === \"none\") return false;\n const min = SEVERITY_RANK[threshold];\n return findings.some((f) => SEVERITY_RANK[f.severity] >= min);\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { PackageInstance } from \"../types.js\";\n\ninterface NpmLockEntry {\n version?: string;\n resolved?: string;\n integrity?: string;\n dev?: boolean;\n devOptional?: boolean;\n optional?: boolean;\n peer?: boolean;\n link?: boolean;\n // Present on the root (\"\") entry only.\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\ninterface NpmLockfile {\n name?: string;\n lockfileVersion?: number;\n packages?: Record<string, NpmLockEntry>;\n}\n\n/**\n * Parse an npm `package-lock.json` (v2 or v3) and return one\n * PackageInstance per node in the `packages` map.\n *\n * The empty-string key represents the root project and is skipped.\n */\nexport function parseNpmPackageLock(filePath: string): PackageInstance[] {\n const absolute = resolve(filePath);\n const raw = readFileSync(absolute, \"utf8\");\n let parsed: NpmLockfile;\n try {\n parsed = JSON.parse(raw) as NpmLockfile;\n } catch (err) {\n throw new Error(\n `Failed to parse ${absolute}: ${(err as Error).message}`,\n );\n }\n\n if (parsed.lockfileVersion !== 2 && parsed.lockfileVersion !== 3) {\n throw new Error(\n `Unsupported npm lockfileVersion ${String(\n parsed.lockfileVersion,\n )} in ${absolute}. Only v2 and v3 are supported.`,\n );\n }\n\n const packages = parsed.packages;\n if (!packages || typeof packages !== \"object\") {\n throw new Error(\n `Lockfile ${absolute} has no \"packages\" map; cannot extract installed versions.`,\n );\n }\n\n const directDeps = collectDirectDependencyNames(packages[\"\"] ?? {});\n const instances: PackageInstance[] = [];\n\n for (const [path, entry] of Object.entries(packages)) {\n if (path === \"\") continue;\n if (entry.link) continue; // workspace symlink, not a real install\n const name = packagePathToName(path);\n if (!name) continue;\n if (!entry.version) continue;\n\n instances.push({\n name,\n version: entry.version,\n ecosystem: \"npm\",\n path,\n direct: directDeps.has(name) && isTopLevelInstance(path),\n dev: Boolean(entry.dev || entry.devOptional),\n optional: Boolean(entry.optional || entry.devOptional),\n resolved: entry.resolved,\n integrity: entry.integrity,\n });\n }\n\n return instances;\n}\n\nfunction collectDirectDependencyNames(rootEntry: NpmLockEntry): Set<string> {\n const names = new Set<string>();\n for (const key of [\n \"dependencies\",\n \"devDependencies\",\n \"optionalDependencies\",\n \"peerDependencies\",\n ] as const) {\n const block = rootEntry[key];\n if (!block) continue;\n for (const name of Object.keys(block)) names.add(name);\n }\n return names;\n}\n\n/**\n * \"node_modules/foo\" -> \"foo\"\n * \"node_modules/@scope/bar\" -> \"@scope/bar\"\n * \"node_modules/foo/node_modules/bar\" -> \"bar\"\n */\nexport function packagePathToName(path: string): string | null {\n const marker = \"node_modules/\";\n const idx = path.lastIndexOf(marker);\n if (idx === -1) return null;\n const tail = path.slice(idx + marker.length);\n if (!tail) return null;\n if (tail.startsWith(\"@\")) {\n const firstSlash = tail.indexOf(\"/\");\n if (firstSlash === -1) return null;\n const secondSlash = tail.indexOf(\"/\", firstSlash + 1);\n return secondSlash === -1 ? tail : tail.slice(0, secondSlash);\n }\n const next = tail.indexOf(\"/\");\n return next === -1 ? tail : tail.slice(0, next);\n}\n\n/** A direct-install path has exactly one `node_modules/` segment. */\nfunction isTopLevelInstance(path: string): boolean {\n const first = path.indexOf(\"node_modules/\");\n if (first === -1) return false;\n return path.indexOf(\"node_modules/\", first + 1) === -1;\n}\n","import type { Finding, PackageInstance, Severity } from \"../types.js\";\n\nconst OSV_QUERYBATCH_URL = \"https://api.osv.dev/v1/querybatch\";\nconst OSV_VULN_URL = \"https://api.osv.dev/v1/vulns\";\nconst QUERY_CHUNK_SIZE = 500;\nconst REQUEST_TIMEOUT_MS = 15_000;\nconst MAX_RETRIES = 2;\n\ninterface OsvQueryBatchResponse {\n results: Array<{ vulns?: Array<{ id: string; modified?: string }> }>;\n}\n\ninterface OsvSeverity {\n type: string;\n score: string;\n}\n\ninterface OsvAffectedRange {\n type: string;\n events: Array<{ introduced?: string; fixed?: string; last_affected?: string }>;\n}\n\ninterface OsvAffectedPackage {\n package?: { ecosystem?: string; name?: string };\n ranges?: OsvAffectedRange[];\n versions?: string[];\n}\n\ninterface OsvVulnDetail {\n id: string;\n summary?: string;\n details?: string;\n references?: Array<{ type?: string; url?: string }>;\n severity?: OsvSeverity[];\n database_specific?: { severity?: string };\n affected?: OsvAffectedPackage[];\n}\n\nexport interface OsvQueryDeps {\n fetchImpl?: typeof fetch;\n}\n\ninterface UniquePackage {\n name: string;\n version: string;\n}\n\n/**\n * Build the deduplicated list of unique name@version pairs to query OSV with.\n */\nexport function dedupeForQuery(\n packages: PackageInstance[],\n): UniquePackage[] {\n const seen = new Set<string>();\n const out: UniquePackage[] = [];\n for (const pkg of packages) {\n const key = `${pkg.name}@${pkg.version}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push({ name: pkg.name, version: pkg.version });\n }\n return out;\n}\n\n/**\n * Query OSV for the given installed packages and return one Finding per\n * (advisory, affected package instance) pair.\n */\nexport async function queryOsv(\n packages: PackageInstance[],\n deps: OsvQueryDeps = {},\n): Promise<Finding[]> {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const unique = dedupeForQuery(packages);\n if (unique.length === 0) return [];\n\n const idsByPackage = new Map<string, Set<string>>();\n for (const chunk of chunked(unique, QUERY_CHUNK_SIZE)) {\n const body = {\n queries: chunk.map((q) => ({\n package: { ecosystem: \"npm\", name: q.name },\n version: q.version,\n })),\n };\n const res = await postJson<OsvQueryBatchResponse>(\n fetchImpl,\n OSV_QUERYBATCH_URL,\n body,\n );\n res.results.forEach((result, i) => {\n const q = chunk[i];\n if (!q) return;\n const key = `${q.name}@${q.version}`;\n if (!result.vulns || result.vulns.length === 0) return;\n const ids = idsByPackage.get(key) ?? new Set<string>();\n for (const v of result.vulns) ids.add(v.id);\n idsByPackage.set(key, ids);\n });\n }\n\n const allIds = new Set<string>();\n for (const ids of idsByPackage.values()) {\n for (const id of ids) allIds.add(id);\n }\n\n const detailsById = new Map<string, OsvVulnDetail>();\n for (const id of allIds) {\n try {\n const detail = await getJson<OsvVulnDetail>(\n fetchImpl,\n `${OSV_VULN_URL}/${encodeURIComponent(id)}`,\n );\n detailsById.set(id, detail);\n } catch {\n // Skip missing/broken records; we still have the id reported below.\n }\n }\n\n const findings: Finding[] = [];\n for (const pkg of packages) {\n const key = `${pkg.name}@${pkg.version}`;\n const ids = idsByPackage.get(key);\n if (!ids) continue;\n for (const id of ids) {\n const detail = detailsById.get(id);\n findings.push(buildFinding(pkg, id, detail));\n }\n }\n return findings;\n}\n\nfunction buildFinding(\n pkg: PackageInstance,\n id: string,\n detail: OsvVulnDetail | undefined,\n): Finding {\n const severity = detail ? parseSeverity(detail) : \"unknown\";\n const summary = detail?.summary ?? detail?.details ?? id;\n return {\n id,\n source: \"osv\",\n type: \"vulnerability\",\n severity,\n packageName: pkg.name,\n installedVersion: pkg.version,\n summary: truncate(summary, 240),\n url: pickAdvisoryUrl(detail) ?? `https://osv.dev/vulnerability/${id}`,\n fixedVersions: detail ? collectFixedVersions(detail, pkg.name) : [],\n affectedPaths: [pkg.path],\n };\n}\n\nexport function parseSeverity(detail: OsvVulnDetail): Severity {\n // GHSA records expose a normalized severity in database_specific.severity.\n const dbSpecific = detail.database_specific?.severity?.toLowerCase();\n if (\n dbSpecific === \"critical\" ||\n dbSpecific === \"high\" ||\n dbSpecific === \"moderate\" ||\n dbSpecific === \"low\"\n ) {\n return dbSpecific;\n }\n if (dbSpecific === \"medium\") return \"moderate\";\n\n const cvss = detail.severity?.find((s) => s.type?.startsWith(\"CVSS_\"));\n if (cvss) {\n const score = parseCvssScore(cvss.score);\n if (score === undefined) return \"unknown\";\n if (score >= 9.0) return \"critical\";\n if (score >= 7.0) return \"high\";\n if (score >= 4.0) return \"moderate\";\n if (score > 0) return \"low\";\n }\n return \"unknown\";\n}\n\nfunction parseCvssScore(vector: string): number | undefined {\n const direct = Number.parseFloat(vector);\n if (!Number.isNaN(direct) && vector.trim() !== \"\") return direct;\n // Some entries store the full CVSS vector string; we don't compute it here.\n return undefined;\n}\n\nfunction pickAdvisoryUrl(detail: OsvVulnDetail | undefined): string | undefined {\n if (!detail?.references) return undefined;\n const advisory = detail.references.find((r) => r.type === \"ADVISORY\");\n return advisory?.url ?? detail.references[0]?.url;\n}\n\nexport function collectFixedVersions(\n detail: OsvVulnDetail,\n packageName: string,\n): string[] {\n const out = new Set<string>();\n for (const aff of detail.affected ?? []) {\n if (aff.package?.name && aff.package.name !== packageName) continue;\n for (const range of aff.ranges ?? []) {\n for (const event of range.events ?? []) {\n if (event.fixed) out.add(event.fixed);\n }\n }\n }\n return [...out];\n}\n\nfunction* chunked<T>(items: T[], size: number): Generator<T[]> {\n for (let i = 0; i < items.length; i += size) {\n yield items.slice(i, i + size);\n }\n}\n\nasync function postJson<T>(\n fetchImpl: typeof fetch,\n url: string,\n body: unknown,\n): Promise<T> {\n return withRetry(async () => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n try {\n const res = await fetchImpl(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n throw new HttpError(`OSV ${res.status}: ${res.statusText}`, res.status);\n }\n return (await res.json()) as T;\n } finally {\n clearTimeout(timer);\n }\n });\n}\n\nasync function getJson<T>(fetchImpl: typeof fetch, url: string): Promise<T> {\n return withRetry(async () => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n try {\n const res = await fetchImpl(url, { signal: controller.signal });\n if (!res.ok) {\n throw new HttpError(`OSV ${res.status}: ${res.statusText}`, res.status);\n }\n return (await res.json()) as T;\n } finally {\n clearTimeout(timer);\n }\n });\n}\n\nclass HttpError extends Error {\n constructor(message: string, public readonly status: number) {\n super(message);\n }\n}\n\nasync function withRetry<T>(fn: () => Promise<T>): Promise<T> {\n let lastErr: unknown;\n for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastErr = err;\n if (!isRetryable(err) || attempt === MAX_RETRIES) break;\n await new Promise((r) => setTimeout(r, 250 * 2 ** attempt));\n }\n }\n throw lastErr;\n}\n\nfunction isRetryable(err: unknown): boolean {\n if (err instanceof HttpError) return err.status >= 500;\n // AbortError (timeout) and network errors are retryable.\n return true;\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s;\n return `${s.slice(0, max - 1)}…`;\n}\n","export type Severity = \"critical\" | \"high\" | \"moderate\" | \"low\" | \"unknown\";\n\nexport type Ecosystem = \"npm\";\n\nexport type FindingType =\n | \"vulnerability\"\n | \"malware\"\n | \"risk-signal\"\n | \"integrity\";\n\nexport const SEVERITY_RANK: Record<Severity, number> = {\n critical: 4,\n high: 3,\n moderate: 2,\n low: 1,\n unknown: 0,\n};\n\nexport interface PackageInstance {\n name: string;\n version: string;\n ecosystem: Ecosystem;\n /** Path within the lockfile's `packages` map (e.g. \"node_modules/foo\"). */\n path: string;\n direct: boolean;\n dev: boolean;\n optional: boolean;\n resolved?: string;\n integrity?: string;\n}\n\nexport interface Finding {\n id: string;\n source: \"osv\";\n type: FindingType;\n severity: Severity;\n packageName: string;\n installedVersion: string;\n summary: string;\n url?: string;\n fixedVersions: string[];\n affectedPaths: string[];\n}\n\nexport interface ScanError {\n message: string;\n cause?: string;\n}\n\nexport interface ScanResult {\n scannedAt: string;\n packagesScanned: number;\n findings: Finding[];\n summary: Record<Severity, number>;\n errors: ScanError[];\n}\n\nexport interface ScanProjectOptions {\n cwd?: string;\n lockfile?: string;\n includeDev?: boolean;\n prodOnly?: boolean;\n cache?: boolean;\n fetchImpl?: typeof fetch;\n}\n\nexport interface ScanLockfileOptions {\n lockfilePath: string;\n includeDev?: boolean;\n prodOnly?: boolean;\n fetchImpl?: typeof fetch;\n}\n\nexport type FailOnLevel = Severity | \"none\";\n"],"mappings":"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","names":["resolve","resolve"]}
1
+ {"version":3,"sources":["../src/scanner.ts","../src/baseline.ts","../src/config.ts","../src/env.ts","../src/fingerprint.ts","../src/extractors/lockfile.ts","../src/extractors/npm-package-lock.ts","../src/extractors/pnpm-lock.ts","../src/extractors/package-json.ts","../src/extractors/yarn-lock.ts","../src/extractors/sbom.ts","../src/ignore.ts","../src/policy.ts","../src/risk.ts","../src/sources/osv.ts","../src/types.ts","../src/env-scan.ts","../src/init.ts","../src/why.ts","../src/version.ts"],"sourcesContent":["import { existsSync, statSync } from \"node:fs\";\nimport { dirname, resolve, join } from \"node:path\";\nimport { applyBaseline, writeBaseline } from \"./baseline.js\";\nimport { loadConfig } from \"./config.js\";\nimport { scanEnvFiles } from \"./env.js\";\nimport { parseLockfile } from \"./extractors/lockfile.js\";\nimport { parseSbom } from \"./extractors/sbom.js\";\nimport { applyIgnores } from \"./ignore.js\";\nimport { resolvePolicy } from \"./policy.js\";\nimport { collectRiskSignals } from \"./risk.js\";\nimport { queryOsv } from \"./sources/osv.js\";\nimport { SEVERITY_RANK } from \"./types.js\";\nimport type {\n Finding,\n PackageInstance,\n ScanError,\n ScanLockfileOptions,\n ScanProjectOptions,\n ScanResult,\n Severity,\n} from \"./types.js\";\n\nconst DEFAULT_ALLOWED_REGISTRIES = [\n \"https://registry.npmjs.org\",\n \"https://registry.yarnpkg.com\",\n];\n\nexport async function scanProject(\n options: ScanProjectOptions = {},\n): Promise<ScanResult> {\n const cwd = resolve(options.cwd ?? process.cwd());\n const loadedConfig = loadConfig(cwd, options.config);\n const policy = resolvePolicy(options.policy, loadedConfig.config.policy);\n const lockfilePaths = options.lockfile\n ? normalizePaths(cwd, options.lockfile)\n : detectLockfiles(cwd);\n const sbomPaths = normalizePaths(cwd, options.sbom);\n const envEnabled = options.env ?? loadedConfig.config.env ?? policy?.env ?? false;\n\n if (lockfilePaths.length === 0 && sbomPaths.length === 0 && !envEnabled) {\n throw new ScanInputError(\n `No supported lockfile or SBOM found in ${cwd}. Pass --lockfile/--sbom or run in a directory with package-lock.json, pnpm-lock.yaml, or yarn.lock.`,\n );\n }\n\n return scanLockfile({\n lockfilePath: lockfilePaths,\n sbom: sbomPaths,\n cwd,\n config: options.config,\n policy: options.policy,\n baseline: options.baseline,\n writeBaseline: options.writeBaseline,\n risk: options.risk ?? loadedConfig.config.risk ?? policy?.risk,\n env: envEnabled,\n allowedRegistries:\n options.allowedRegistries ?? loadedConfig.config.allowedRegistries,\n includeDev: options.includeDev ?? policy?.includeDev,\n prodOnly: options.prodOnly,\n fetchImpl: options.fetchImpl,\n now: options.now,\n });\n}\n\nexport async function scanLockfile(\n options: ScanLockfileOptions,\n): Promise<ScanResult> {\n const initialCwd = resolve(options.cwd ?? process.cwd());\n const lockfilePaths = normalizePaths(initialCwd, options.lockfilePath);\n const sbomPaths = normalizePaths(initialCwd, options.sbom);\n const cwd = options.cwd\n ? initialCwd\n : deriveCwdFromInputs(lockfilePaths, sbomPaths, initialCwd);\n const now = options.now ?? new Date();\n const loadedConfig = loadConfig(cwd, options.config);\n const policy = resolvePolicy(options.policy, loadedConfig.config.policy);\n const envEnabled = options.env ?? loadedConfig.config.env ?? policy?.env ?? false;\n\n for (const path of [...lockfilePaths, ...sbomPaths]) validateFile(path);\n\n const allInstances = [\n ...lockfilePaths.flatMap((path) => parseLockfile(path)),\n ...sbomPaths.flatMap((path) => parseSbom(path)),\n ];\n const instances = filterInstances(allInstances, {\n ...options,\n includeDev: options.includeDev ?? policy?.includeDev,\n });\n const errors: ScanError[] = [];\n const warnings: string[] = [];\n const envResult = envEnabled\n ? scanEnvFiles(cwd)\n : { findings: [], warnings: [], filesScanned: 0 };\n warnings.push(...envResult.warnings);\n\n let findings: Finding[] = [...envResult.findings];\n try {\n findings.push(...(await queryOsv(instances, { fetchImpl: options.fetchImpl })));\n } catch (err) {\n errors.push({\n message: \"Failed to query OSV advisory database\",\n cause: (err as Error).message,\n });\n }\n\n const riskEnabled =\n options.risk ?? loadedConfig.config.risk ?? policy?.risk ?? true;\n const risk = await collectRiskSignals(instances, {\n enabled: riskEnabled,\n allowedRegistries:\n options.allowedRegistries ??\n loadedConfig.config.allowedRegistries ??\n DEFAULT_ALLOWED_REGISTRIES,\n fetchImpl: options.fetchImpl,\n now,\n });\n findings.push(...risk.findings);\n warnings.push(...risk.warnings);\n\n const ignoreResult = applyIgnores(\n findings,\n loadedConfig.config.ignore,\n now,\n );\n warnings.push(...ignoreResult.warnings);\n findings = ignoreResult.active;\n\n findings.sort(compareFindings);\n ignoreResult.ignored.sort(compareFindings);\n\n const appliedBaseline = applyBaseline(findings, cwd, options.baseline);\n let baseline = appliedBaseline?.result;\n if (appliedBaseline) {\n findings = appliedBaseline.findings;\n }\n if (options.writeBaseline) {\n baseline = writeBaseline(findings, cwd, options.writeBaseline, baseline);\n }\n\n return {\n scannedAt: now.toISOString(),\n packagesScanned: instances.length,\n findings,\n ignoredFindings: ignoreResult.ignored,\n summary: summarize(findings),\n errors,\n warnings,\n baseline,\n };\n}\n\nfunction deriveCwdFromInputs(\n lockfilePaths: string[],\n sbomPaths: string[],\n fallback: string,\n): string {\n const firstInput = lockfilePaths[0] ?? sbomPaths[0];\n return firstInput ? dirname(firstInput) : fallback;\n}\n\nexport class ScanInputError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ScanInputError\";\n }\n}\n\nfunction detectLockfiles(cwd: string): string[] {\n const candidates = [\n \"package-lock.json\",\n \"npm-shrinkwrap.json\",\n \"pnpm-lock.yaml\",\n \"yarn.lock\",\n ].map((file) => join(cwd, file));\n return candidates.filter((candidate) => existsSync(candidate));\n}\n\nfunction filterInstances(\n instances: PackageInstance[],\n options: { includeDev?: boolean; prodOnly?: boolean },\n): PackageInstance[] {\n const includeDev = options.prodOnly ? false : options.includeDev !== false;\n if (includeDev) return instances;\n return instances.filter((p) => !p.dev);\n}\n\nexport function compareFindings(a: Finding, b: Finding): number {\n const sev = SEVERITY_RANK[b.severity] - SEVERITY_RANK[a.severity];\n if (sev !== 0) return sev;\n if (a.source !== b.source) return a.source.localeCompare(b.source);\n if (a.packageName !== b.packageName) {\n return a.packageName.localeCompare(b.packageName);\n }\n if (a.installedVersion !== b.installedVersion) {\n return a.installedVersion.localeCompare(b.installedVersion);\n }\n return a.id.localeCompare(b.id);\n}\n\nexport function summarize(findings: Finding[]): Record<Severity, number> {\n const summary: Record<Severity, number> = {\n critical: 0,\n high: 0,\n moderate: 0,\n low: 0,\n unknown: 0,\n };\n for (const f of findings) summary[f.severity]++;\n return summary;\n}\n\n/**\n * Returns true when any finding meets or exceeds the given severity threshold.\n * \"none\" means never fail.\n */\nexport function meetsThreshold(\n findings: Finding[],\n threshold: Severity | \"none\",\n): boolean {\n if (threshold === \"none\") return false;\n const min = SEVERITY_RANK[threshold];\n return findings.some(\n (f) => f.baseline !== \"existing\" && SEVERITY_RANK[f.severity] >= min,\n );\n}\n\nfunction normalizePaths(\n cwd: string,\n value: string | string[] | undefined,\n): string[] {\n if (!value) return [];\n const values = Array.isArray(value) ? value : [value];\n return [...new Set(values.map((path) => resolve(cwd, path)))];\n}\n\nfunction validateFile(path: string): void {\n if (!existsSync(path)) {\n throw new ScanInputError(`Input file does not exist: ${path}`);\n }\n const stat = statSync(path);\n if (!stat.isFile()) {\n throw new ScanInputError(`Input path is not a file: ${path}`);\n }\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport type { BaselineFile, BaselineResult, Finding } from \"./types.js\";\n\nexport interface AppliedBaseline {\n result: BaselineResult;\n findings: Finding[];\n}\n\nexport class BaselineError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BaselineError\";\n }\n}\n\nexport function applyBaseline(\n findings: Finding[],\n cwd: string,\n baselinePath?: string,\n): AppliedBaseline | undefined {\n if (!baselinePath) return undefined;\n const absolute = resolve(cwd, baselinePath);\n const loaded = readBaseline(absolute);\n const fingerprints = new Set(loaded.findings);\n let existing = 0;\n let fresh = 0;\n const marked = findings.map((finding) => {\n if (fingerprints.has(finding.fingerprint)) {\n existing++;\n return { ...finding, baseline: \"existing\" as const };\n }\n fresh++;\n return { ...finding, baseline: \"new\" as const };\n });\n return {\n result: {\n path: absolute,\n loaded: true,\n total: findings.length,\n existing,\n new: fresh,\n },\n findings: marked,\n };\n}\n\nexport function writeBaseline(\n findings: Finding[],\n cwd: string,\n baselinePath: string,\n existing?: BaselineResult,\n): BaselineResult {\n const absolute = resolve(cwd, baselinePath);\n const unique = [...new Set(findings.map((f) => f.fingerprint))].sort();\n const payload: BaselineFile = {\n version: 1,\n generatedAt: new Date().toISOString(),\n findings: unique,\n };\n mkdirSync(dirname(absolute), { recursive: true });\n writeFileSync(absolute, `${JSON.stringify(payload, null, 2)}\\n`);\n return {\n path: existing?.path,\n loaded: existing?.loaded ?? false,\n written: absolute,\n total: findings.length,\n existing: existing?.existing ?? 0,\n new: existing?.new ?? findings.length,\n };\n}\n\nfunction readBaseline(path: string): BaselineFile {\n if (!existsSync(path)) {\n throw new BaselineError(`Baseline file does not exist: ${path}`);\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(readFileSync(path, \"utf8\")) as unknown;\n } catch (err) {\n throw new BaselineError(\n `Failed to parse baseline ${path}: ${(err as Error).message}`,\n );\n }\n if (!isRecord(parsed) || parsed.version !== 1) {\n throw new BaselineError(`${path}: unsupported baseline format.`);\n }\n if (!Array.isArray(parsed.findings)) {\n throw new BaselineError(`${path}: findings must be an array.`);\n }\n const findings = parsed.findings.filter((v): v is string => typeof v === \"string\");\n return {\n version: 1,\n generatedAt:\n typeof parsed.generatedAt === \"string\" ? parsed.generatedAt : \"\",\n findings,\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve, join } from \"node:path\";\nimport { parse as parseToml } from \"smol-toml\";\nimport type {\n FailOnLevel,\n IgnoreEntry,\n PolicyPresetName,\n TrawlyConfig,\n} from \"./types.js\";\n\nconst CONFIG_NAME = \"trawly.toml\";\nconst FAIL_ON_VALUES = new Set<FailOnLevel>([\n \"critical\",\n \"high\",\n \"moderate\",\n \"low\",\n \"none\",\n]);\nconst POLICY_VALUES = new Set<PolicyPresetName>([\n \"ci\",\n \"strict\",\n \"library\",\n \"app\",\n]);\n\nexport interface LoadedConfig {\n path?: string;\n config: TrawlyConfig;\n}\n\nexport class ConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigError\";\n }\n}\n\nexport function loadConfig(cwd: string, explicitPath?: string): LoadedConfig {\n const configPath = explicitPath\n ? resolve(cwd, explicitPath)\n : findConfig(cwd);\n\n if (!configPath) return { config: { ignore: [] } };\n if (!existsSync(configPath)) {\n throw new ConfigError(`Config file does not exist: ${configPath}`);\n }\n\n let raw: unknown;\n try {\n raw = parseToml(readFileSync(configPath, \"utf8\"));\n } catch (err) {\n throw new ConfigError(\n `Failed to parse ${configPath}: ${(err as Error).message}`,\n );\n }\n\n return { path: configPath, config: normalizeConfig(raw, configPath) };\n}\n\nfunction findConfig(cwd: string): string | undefined {\n const candidate = join(cwd, CONFIG_NAME);\n return existsSync(candidate) ? candidate : undefined;\n}\n\nfunction normalizeConfig(raw: unknown, path: string): TrawlyConfig {\n if (!isRecord(raw)) throw new ConfigError(`${path} must be a TOML table.`);\n\n const failOn = optionalString(raw.failOn, \"failOn\", path);\n if (failOn !== undefined && !FAIL_ON_VALUES.has(failOn as FailOnLevel)) {\n throw new ConfigError(\n `${path}: failOn must be one of ${[...FAIL_ON_VALUES].join(\", \")}.`,\n );\n }\n\n const policy = optionalString(raw.policy, \"policy\", path);\n if (policy !== undefined && !POLICY_VALUES.has(policy as PolicyPresetName)) {\n throw new ConfigError(\n `${path}: policy must be one of ${[...POLICY_VALUES].join(\", \")}.`,\n );\n }\n\n const risk = optionalBoolean(raw.risk, \"risk\", path);\n const env = optionalBoolean(raw.env, \"env\", path);\n const allowedRegistries = normalizeStringArray(\n raw.allowedRegistries,\n \"allowedRegistries\",\n path,\n );\n if (raw.ignore !== undefined && raw.IgnoredVulns !== undefined) {\n console.warn(\n `${path}: both \"ignore\" and legacy \"IgnoredVulns\" are defined; using \"ignore\".`,\n );\n }\n const ignore = normalizeIgnore(raw.ignore ?? raw.IgnoredVulns ?? [], path);\n\n return {\n failOn: failOn as FailOnLevel | undefined,\n policy: policy as PolicyPresetName | undefined,\n risk,\n env,\n allowedRegistries,\n ignore,\n };\n}\n\nfunction normalizeIgnore(raw: unknown, path: string): IgnoreEntry[] {\n if (raw === undefined) return [];\n if (!Array.isArray(raw)) {\n throw new ConfigError(`${path}: ignore must be an array of tables.`);\n }\n return raw.map((item, idx) => {\n if (!isRecord(item)) {\n throw new ConfigError(`${path}: ignore[${idx}] must be a table.`);\n }\n const id = requiredString(item.id, `ignore[${idx}].id`, path);\n const expires = requiredDateString(\n item.expires,\n `ignore[${idx}].expires`,\n path,\n );\n const reason = requiredString(item.reason, `ignore[${idx}].reason`, path);\n return {\n id,\n expires,\n reason,\n package: optionalString(item.package, `ignore[${idx}].package`, path),\n ecosystem: optionalString(item.ecosystem, `ignore[${idx}].ecosystem`, path),\n version: optionalString(item.version, `ignore[${idx}].version`, path),\n };\n });\n}\n\nfunction normalizeStringArray(\n raw: unknown,\n field: string,\n path: string,\n): string[] | undefined {\n if (raw === undefined) return undefined;\n if (!Array.isArray(raw) || raw.some((v) => typeof v !== \"string\")) {\n throw new ConfigError(`${path}: ${field} must be an array of strings.`);\n }\n return raw;\n}\n\nfunction requiredDateString(raw: unknown, field: string, path: string): string {\n const value = requiredString(raw, field, path);\n if (!isIsoDate(value)) {\n throw new ConfigError(`${path}: ${field} must be YYYY-MM-DD.`);\n }\n return value;\n}\n\nfunction requiredString(raw: unknown, field: string, path: string): string {\n if (typeof raw !== \"string\" || raw.trim() === \"\") {\n throw new ConfigError(`${path}: ${field} is required.`);\n }\n return raw;\n}\n\nfunction optionalString(\n raw: unknown,\n field: string,\n path: string,\n): string | undefined {\n if (raw === undefined) return undefined;\n if (typeof raw !== \"string\") {\n throw new ConfigError(`${path}: ${field} must be a string.`);\n }\n return raw;\n}\n\nfunction optionalBoolean(\n raw: unknown,\n field: string,\n path: string,\n): boolean | undefined {\n if (raw === undefined) return undefined;\n if (typeof raw !== \"boolean\") {\n throw new ConfigError(`${path}: ${field} must be true or false.`);\n }\n return raw;\n}\n\nfunction isIsoDate(s: string): boolean {\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(s)) return false;\n const date = new Date(`${s}T00:00:00.000Z`);\n return !Number.isNaN(date.getTime()) && date.toISOString().startsWith(s);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import {\n lstatSync,\n readdirSync,\n readFileSync,\n statSync,\n} from \"node:fs\";\nimport { basename, join, relative } from \"node:path\";\nimport { fingerprintFinding } from \"./fingerprint.js\";\nimport type { Finding } from \"./types.js\";\n\nconst MAX_ENV_FILE_BYTES = 1024 * 1024;\nconst SKIP_DIRS = new Set([\n \".git\",\n \".hg\",\n \".svn\",\n \"coverage\",\n \"dist\",\n \"node_modules\",\n \"vendor\",\n]);\nconst SAFE_ENV_SUFFIXES = new Set([\n \"default\",\n \"defaults\",\n \"dist\",\n \"example\",\n \"sample\",\n \"template\",\n]);\nconst SECRET_KEY_RE =\n /(?:^|_)(?:SECRET|TOKEN|PASSWORD|PASS|PWD|PRIVATE_KEY|API_KEY|ACCESS_KEY|AUTH|CREDENTIAL|DATABASE_URL|DB_URL|REDIS_URL|MONGO_URI|CONNECTION_STRING|WEBHOOK|CLIENT_SECRET)(?:$|_)/i;\nconst PRIVATE_KEY_RE = /PRIVATE_KEY|BEGIN_[A-Z0-9_]+_PRIVATE_KEY/i;\nconst PLACEHOLDER_RE =\n /^(?:|changeme|change_me|change-me|example|example-value|placeholder|replace_me|replace-me|todo|test|dummy|your_.+|<.+>|\\$\\{.+\\}|x+)$/i;\n\nexport interface EnvScanResult {\n findings: Finding[];\n warnings: string[];\n filesScanned: number;\n}\n\ninterface EnvAssignment {\n key: string;\n value: string;\n line: number;\n}\n\nexport function scanEnvFiles(cwd: string): EnvScanResult {\n const warnings: string[] = [];\n const findings: Finding[] = [];\n let filesScanned = 0;\n\n for (const file of findEnvFiles(cwd)) {\n let raw: string;\n try {\n const stat = statSync(file);\n if (stat.size > MAX_ENV_FILE_BYTES) {\n warnings.push(\n `Skipped env file ${relative(cwd, file)} because it is larger than 1 MiB.`,\n );\n continue;\n }\n raw = readFileSync(file, \"utf8\");\n } catch (err) {\n warnings.push(\n `Could not read env file ${relative(cwd, file)}: ${(err as Error).message}`,\n );\n continue;\n }\n\n filesScanned++;\n const rel = normalizePath(relative(cwd, file));\n findings.push(envFileFinding(file, rel));\n\n for (const assignment of parseEnvAssignments(raw)) {\n if (!isSensitiveAssignment(assignment)) continue;\n findings.push(envSecretFinding(file, rel, assignment));\n }\n }\n\n return { findings, warnings, filesScanned };\n}\n\nfunction findEnvFiles(root: string): string[] {\n const out: string[] = [];\n const stack = [root];\n while (stack.length > 0) {\n const dir = stack.pop()!;\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n continue;\n }\n for (const entry of entries) {\n const path = join(dir, entry);\n let stat;\n try {\n stat = lstatSync(path);\n } catch {\n continue;\n }\n if (stat.isSymbolicLink()) continue;\n if (stat.isDirectory()) {\n if (!SKIP_DIRS.has(entry)) stack.push(path);\n continue;\n }\n if (stat.isFile() && isEnvFile(entry)) out.push(path);\n }\n }\n return out.sort();\n}\n\nfunction isEnvFile(name: string): boolean {\n if (name === \".env\") return true;\n if (!name.startsWith(\".env.\")) return false;\n const suffixes = name\n .slice(\".env.\".length)\n .toLowerCase()\n .split(\".\")\n .filter(Boolean);\n return !suffixes.some((suffix) => SAFE_ENV_SUFFIXES.has(suffix));\n}\n\nfunction parseEnvAssignments(raw: string): EnvAssignment[] {\n const out: EnvAssignment[] = [];\n raw.split(/\\r?\\n/).forEach((line, index) => {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) return;\n const match = /^(?:export\\s+)?([A-Za-z_][A-Za-z0-9_]*)\\s*=\\s*(.*)$/.exec(\n trimmed,\n );\n if (!match) return;\n const key = match[1]!;\n const value = unquote(match[2]!.trim());\n out.push({ key, value, line: index + 1 });\n });\n return out;\n}\n\nfunction isSensitiveAssignment(assignment: EnvAssignment): boolean {\n if (!SECRET_KEY_RE.test(assignment.key)) return false;\n return !PLACEHOLDER_RE.test(assignment.value.trim());\n}\n\nfunction envFileFinding(sourceFile: string, rel: string): Finding {\n const id = \"TRAWLY-ENV-FILE\";\n return {\n id,\n source: \"trawly\",\n type: \"secret\",\n severity: \"moderate\",\n ecosystem: \"env\",\n packageName: \".env file\",\n installedVersion: rel,\n summary:\n \"Committed env file detected. Verify it does not contain secrets and prefer committing an example/template file instead.\",\n fixedVersions: [],\n affectedPaths: [rel],\n fingerprint: fingerprintFinding({\n source: \"trawly\",\n type: \"secret\",\n id,\n ecosystem: \"env\",\n packageName: \".env file\",\n installedVersion: rel,\n }),\n aliases: [],\n sourceFile,\n line: 1,\n };\n}\n\nfunction envSecretFinding(\n sourceFile: string,\n rel: string,\n assignment: EnvAssignment,\n): Finding {\n const id = \"TRAWLY-ENV-SECRET\";\n return {\n id,\n source: \"trawly\",\n type: \"secret\",\n severity: PRIVATE_KEY_RE.test(assignment.key) ? \"critical\" : \"high\",\n ecosystem: \"env\",\n packageName: assignment.key,\n installedVersion: rel,\n summary:\n \"Committed env file contains a secret-like variable. The value is intentionally omitted from this report.\",\n fixedVersions: [],\n affectedPaths: [rel],\n fingerprint: fingerprintFinding({\n source: \"trawly\",\n type: \"secret\",\n id,\n ecosystem: \"env\",\n packageName: assignment.key,\n installedVersion: rel,\n }),\n aliases: [],\n sourceFile,\n line: assignment.line,\n };\n}\n\nfunction unquote(value: string): string {\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n return value.slice(1, -1);\n }\n return value;\n}\n\nfunction normalizePath(path: string): string {\n return path.split(/[\\\\/]/).join(\"/\");\n}\n","import { createHash } from \"node:crypto\";\nimport type { Finding, PackageInstance } from \"./types.js\";\n\nexport function fingerprintFinding(input: {\n source: Finding[\"source\"];\n id: string;\n ecosystem: string;\n packageName: string;\n installedVersion: string;\n type: Finding[\"type\"];\n}): string {\n return stableHash([\n input.source,\n input.type,\n input.id,\n input.ecosystem,\n input.packageName,\n input.installedVersion,\n ]);\n}\n\nexport function packageKey(pkg: PackageInstance): string {\n return pkg.purl ?? `${pkg.ecosystem}:${pkg.name}@${pkg.version}`;\n}\n\nfunction stableHash(parts: string[]): string {\n return createHash(\"sha256\").update(parts.join(\"\\0\")).digest(\"hex\");\n}\n","import { basename } from \"node:path\";\nimport type { PackageInstance } from \"../types.js\";\nimport { parseNpmPackageLock } from \"./npm-package-lock.js\";\nimport { parsePnpmLock } from \"./pnpm-lock.js\";\nimport { parseYarnLock } from \"./yarn-lock.js\";\n\nexport function parseLockfile(filePath: string): PackageInstance[] {\n const file = basename(filePath);\n if (file === \"package-lock.json\" || file === \"npm-shrinkwrap.json\") {\n return parseNpmPackageLock(filePath);\n }\n if (file === \"pnpm-lock.yaml\") return parsePnpmLock(filePath);\n if (file === \"yarn.lock\") return parseYarnLock(filePath);\n throw new Error(\n `Unsupported lockfile ${filePath}. Supported: package-lock.json, npm-shrinkwrap.json, pnpm-lock.yaml, yarn.lock.`,\n );\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { PackageInstance } from \"../types.js\";\n\ninterface NpmLockEntry {\n version?: string;\n resolved?: string;\n integrity?: string;\n hasInstallScript?: boolean;\n dev?: boolean;\n devOptional?: boolean;\n optional?: boolean;\n peer?: boolean;\n link?: boolean;\n // Present on the root (\"\") entry only.\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\ninterface NpmLockfile {\n name?: string;\n lockfileVersion?: number;\n packages?: Record<string, NpmLockEntry>;\n}\n\n/**\n * Parse an npm `package-lock.json` (v2 or v3) and return one\n * PackageInstance per node in the `packages` map.\n *\n * The empty-string key represents the root project and is skipped.\n */\nexport function parseNpmPackageLock(filePath: string): PackageInstance[] {\n const absolute = resolve(filePath);\n const raw = readFileSync(absolute, \"utf8\");\n let parsed: NpmLockfile;\n try {\n parsed = JSON.parse(raw) as NpmLockfile;\n } catch (err) {\n throw new Error(\n `Failed to parse ${absolute}: ${(err as Error).message}`,\n );\n }\n\n if (parsed.lockfileVersion !== 2 && parsed.lockfileVersion !== 3) {\n throw new Error(\n `Unsupported npm lockfileVersion ${String(\n parsed.lockfileVersion,\n )} in ${absolute}. Only v2 and v3 are supported.`,\n );\n }\n\n const packages = parsed.packages;\n if (!packages || typeof packages !== \"object\") {\n throw new Error(\n `Lockfile ${absolute} has no \"packages\" map; cannot extract installed versions.`,\n );\n }\n\n const directDeps = collectDirectDependencyNames(packages[\"\"] ?? {});\n const instances: PackageInstance[] = [];\n\n for (const [path, entry] of Object.entries(packages)) {\n if (path === \"\") continue;\n if (entry.link) continue; // workspace symlink, not a real install\n const name = packagePathToName(path);\n if (!name) continue;\n if (!entry.version) continue;\n\n instances.push({\n name,\n version: entry.version,\n ecosystem: \"npm\",\n path,\n direct: directDeps.has(name) && isTopLevelInstance(path),\n dev: Boolean(entry.dev || entry.devOptional),\n optional: Boolean(entry.optional || entry.devOptional),\n inputKind: \"lockfile\",\n sourceFile: absolute,\n line: lineOf(raw, JSON.stringify(path)),\n manager: \"npm\",\n resolved: entry.resolved,\n integrity: entry.integrity,\n registry: registryFromResolved(entry.resolved),\n hasInstallScript: Boolean(entry.hasInstallScript),\n });\n }\n\n return instances;\n}\n\nfunction collectDirectDependencyNames(rootEntry: NpmLockEntry): Set<string> {\n const names = new Set<string>();\n for (const key of [\n \"dependencies\",\n \"devDependencies\",\n \"optionalDependencies\",\n \"peerDependencies\",\n ] as const) {\n const block = rootEntry[key];\n if (!block) continue;\n for (const name of Object.keys(block)) names.add(name);\n }\n return names;\n}\n\n/**\n * \"node_modules/foo\" -> \"foo\"\n * \"node_modules/@scope/bar\" -> \"@scope/bar\"\n * \"node_modules/foo/node_modules/bar\" -> \"bar\"\n */\nexport function packagePathToName(path: string): string | null {\n const marker = \"node_modules/\";\n const idx = path.lastIndexOf(marker);\n if (idx === -1) return null;\n const tail = path.slice(idx + marker.length);\n if (!tail) return null;\n if (tail.startsWith(\"@\")) {\n const firstSlash = tail.indexOf(\"/\");\n if (firstSlash === -1) return null;\n const secondSlash = tail.indexOf(\"/\", firstSlash + 1);\n return secondSlash === -1 ? tail : tail.slice(0, secondSlash);\n }\n const next = tail.indexOf(\"/\");\n return next === -1 ? tail : tail.slice(0, next);\n}\n\n/** A direct-install path has exactly one `node_modules/` segment. */\nfunction isTopLevelInstance(path: string): boolean {\n const first = path.indexOf(\"node_modules/\");\n if (first === -1) return false;\n return path.indexOf(\"node_modules/\", first + 1) === -1;\n}\n\nfunction registryFromResolved(resolved: string | undefined): string | undefined {\n if (!resolved) return undefined;\n try {\n const url = new URL(resolved);\n return `${url.protocol}//${url.host}`;\n } catch {\n return undefined;\n }\n}\n\nfunction lineOf(raw: string, needle: string): number | undefined {\n const idx = raw.indexOf(needle);\n if (idx === -1) return undefined;\n return raw.slice(0, idx).split(/\\r?\\n/).length;\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { PackageInstance } from \"../types.js\";\nimport { readPackageJsonInfoFrom } from \"./package-json.js\";\n\ninterface PnpmDepRef {\n version?: string;\n specifier?: string;\n}\n\ninterface PnpmPackageEntry {\n resolution?: { integrity?: string; tarball?: string };\n dev?: boolean;\n optional?: boolean;\n requiresBuild?: boolean;\n}\n\ninterface PnpmLockfile {\n lockfileVersion?: string | number;\n importers?: Record<\n string,\n {\n dependencies?: Record<string, string | PnpmDepRef>;\n devDependencies?: Record<string, string | PnpmDepRef>;\n optionalDependencies?: Record<string, string | PnpmDepRef>;\n }\n >;\n packages?: Record<string, PnpmPackageEntry>;\n dependencies?: Record<string, string | PnpmDepRef>;\n devDependencies?: Record<string, string | PnpmDepRef>;\n optionalDependencies?: Record<string, string | PnpmDepRef>;\n}\n\nconst SUPPORTED_MAJOR_VERSIONS = new Set([6, 9]);\n\nexport function parsePnpmLock(filePath: string): PackageInstance[] {\n const absolute = resolve(filePath);\n const raw = readFileSync(absolute, \"utf8\");\n let parsed: PnpmLockfile;\n try {\n parsed = parseYaml(raw) as PnpmLockfile;\n } catch (err) {\n throw new Error(\n `Failed to parse ${absolute}: ${(err as Error).message}`,\n );\n }\n\n const major = parseLockfileMajor(parsed.lockfileVersion);\n if (major === null || !SUPPORTED_MAJOR_VERSIONS.has(major)) {\n throw new Error(\n `Unsupported pnpm lockfileVersion ${String(parsed.lockfileVersion)} in ${absolute}. Supported: 6.x, 9.x.`,\n );\n }\n\n if (!parsed.packages || typeof parsed.packages !== \"object\") {\n throw new Error(`Lockfile ${absolute} has no \"packages\" map.`);\n }\n\n const rootInfo = readPackageJsonInfoFrom(absolute);\n const importerDirect = collectImporterDirect(parsed);\n const directDeps =\n importerDirect.all.size > 0 ? importerDirect.all : rootInfo.allDirect;\n const devDeps =\n importerDirect.dev.size > 0 ? importerDirect.dev : rootInfo.devDependencies;\n const optionalDeps =\n importerDirect.optional.size > 0\n ? importerDirect.optional\n : rootInfo.optionalDependencies;\n\n const instances: PackageInstance[] = [];\n for (const [key, entry] of Object.entries(parsed.packages)) {\n const parsedKey = parsePnpmPackageKey(key);\n if (!parsedKey) continue;\n const direct = directDeps.has(parsedKey.name);\n instances.push({\n name: parsedKey.name,\n version: parsedKey.version,\n ecosystem: \"npm\",\n path: key,\n direct,\n dev: direct ? devDeps.has(parsedKey.name) : Boolean(entry.dev),\n optional: direct\n ? optionalDeps.has(parsedKey.name)\n : Boolean(entry.optional),\n inputKind: \"lockfile\",\n sourceFile: absolute,\n line: lineOf(raw, key),\n manager: \"pnpm\",\n resolved: entry.resolution?.tarball,\n integrity: entry.resolution?.integrity,\n registry: registryFromResolved(entry.resolution?.tarball),\n hasInstallScript: Boolean(entry.requiresBuild),\n });\n }\n return instances;\n}\n\nexport function parsePnpmPackageKey(\n key: string,\n): { name: string; version: string } | null {\n let normalized = key.replace(/^\\/+/, \"\");\n const peerStart = normalized.indexOf(\"(\");\n if (peerStart !== -1) normalized = normalized.slice(0, peerStart);\n normalized = normalized.split(\"_\")[0] ?? normalized;\n const at = normalized.lastIndexOf(\"@\");\n if (at <= 0) return null;\n const name = normalized.slice(0, at);\n const version = normalized.slice(at + 1);\n if (!name || !version) return null;\n return { name, version };\n}\n\nfunction collectImporterDirect(lock: PnpmLockfile): {\n all: Set<string>;\n dev: Set<string>;\n optional: Set<string>;\n} {\n const all = new Set<string>();\n const dev = new Set<string>();\n const optional = new Set<string>();\n const importers = lock.importers ?? {\n \".\": {\n dependencies: lock.dependencies,\n devDependencies: lock.devDependencies,\n optionalDependencies: lock.optionalDependencies,\n },\n };\n for (const importer of Object.values(importers)) {\n addKeys(importer.dependencies, all);\n addKeys(importer.devDependencies, all, dev);\n addKeys(importer.optionalDependencies, all, optional);\n }\n return { all, dev, optional };\n}\n\nfunction parseLockfileMajor(value: unknown): number | null {\n if (typeof value === \"number\") return Math.trunc(value);\n if (typeof value === \"string\") {\n const major = Number.parseInt(value, 10);\n return Number.isNaN(major) ? null : major;\n }\n return null;\n}\n\nfunction addKeys(\n value: Record<string, string | PnpmDepRef> | undefined,\n all: Set<string>,\n bucket?: Set<string>,\n): void {\n if (!value) return;\n for (const name of Object.keys(value)) {\n all.add(name);\n bucket?.add(name);\n }\n}\n\nfunction registryFromResolved(resolved: string | undefined): string | undefined {\n if (!resolved) return undefined;\n try {\n const url = new URL(resolved);\n return `${url.protocol}//${url.host}`;\n } catch {\n return undefined;\n }\n}\n\nfunction lineOf(raw: string, needle: string): number | undefined {\n const idx = raw.indexOf(needle);\n if (idx === -1) return undefined;\n return raw.slice(0, idx).split(/\\r?\\n/).length;\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport interface PackageJsonInfo {\n dependencies: Set<string>;\n devDependencies: Set<string>;\n optionalDependencies: Set<string>;\n allDirect: Set<string>;\n}\n\nexport function readPackageJsonInfoFrom(filePath: string): PackageJsonInfo {\n return readPackageJsonInfo(dirname(filePath));\n}\n\nexport function readPackageJsonInfo(cwd: string): PackageJsonInfo {\n const info: PackageJsonInfo = {\n dependencies: new Set(),\n devDependencies: new Set(),\n optionalDependencies: new Set(),\n allDirect: new Set(),\n };\n const path = join(cwd, \"package.json\");\n if (!existsSync(path)) return info;\n try {\n const raw = JSON.parse(readFileSync(path, \"utf8\")) as Record<string, unknown>;\n collect(raw.dependencies, info.dependencies, info.allDirect);\n collect(raw.devDependencies, info.devDependencies, info.allDirect);\n collect(raw.optionalDependencies, info.optionalDependencies, info.allDirect);\n collect(raw.peerDependencies, info.dependencies, info.allDirect);\n } catch {\n return info;\n }\n return info;\n}\n\nfunction collect(\n value: unknown,\n target: Set<string>,\n allDirect: Set<string>,\n): void {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return;\n for (const name of Object.keys(value)) {\n target.add(name);\n allDirect.add(name);\n }\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport * as yarnClassicModule from \"@yarnpkg/lockfile\";\nimport type { PackageInstance } from \"../types.js\";\nimport { readPackageJsonInfoFrom } from \"./package-json.js\";\n\nconst yarnClassic = (\n \"parse\" in yarnClassicModule\n ? yarnClassicModule\n : (yarnClassicModule as { default: typeof yarnClassicModule }).default\n) as { parse(input: string): { type: string; object: Record<string, unknown> } };\n\ninterface YarnClassicEntry {\n version?: string;\n resolved?: string;\n integrity?: string;\n optionalDependencies?: Record<string, string>;\n}\n\ninterface YarnBerryEntry {\n version?: string;\n resolution?: string;\n checksum?: string;\n languageName?: string;\n linkType?: string;\n}\n\nconst LOCAL_YARN_PROTOCOLS = [\"workspace:\", \"patch:\", \"portal:\", \"file:\"];\n\nexport interface ParsedYarnClassicEntry {\n specs: string[];\n fields: Record<string, string>;\n}\n\nexport function parseYarnLock(filePath: string): PackageInstance[] {\n const absolute = resolve(filePath);\n const raw = readFileSync(absolute, \"utf8\");\n return isBerryLock(raw)\n ? parseYarnBerryLock(absolute, raw)\n : parseYarnClassicLock(absolute, raw);\n}\n\nexport function parseYarnClassicLock(\n absolute: string,\n raw: string,\n): PackageInstance[] {\n const parsed = yarnClassic.parse(raw);\n if (parsed.type === \"conflict\") {\n throw new Error(`Yarn lockfile ${absolute} contains merge conflicts.`);\n }\n const rootInfo = readPackageJsonInfoFrom(absolute);\n const instances: PackageInstance[] = [];\n for (const [descriptor, value] of Object.entries(parsed.object)) {\n if (!isRecord(value)) continue;\n const entry = value as YarnClassicEntry;\n if (!entry.version) continue;\n const name = parseYarnDescriptorName(descriptor);\n if (!name) continue;\n const direct = rootInfo.allDirect.has(name);\n instances.push({\n name,\n version: entry.version,\n ecosystem: \"npm\",\n path: descriptor,\n direct,\n dev: direct ? rootInfo.devDependencies.has(name) : false,\n optional: direct ? rootInfo.optionalDependencies.has(name) : false,\n inputKind: \"lockfile\",\n sourceFile: absolute,\n line: lineOf(raw, descriptor),\n manager: \"yarn\",\n resolved: entry.resolved,\n integrity: entry.integrity,\n registry: registryFromResolved(entry.resolved),\n hasInstallScript: false,\n });\n }\n return dedupeInstances(instances);\n}\n\nexport function parseYarnBerryLock(\n absolute: string,\n raw: string,\n): PackageInstance[] {\n let parsed: Record<string, unknown>;\n try {\n parsed = parseYaml(raw) as Record<string, unknown>;\n } catch (err) {\n throw new Error(\n `Failed to parse ${absolute}: ${(err as Error).message}`,\n );\n }\n const rootInfo = readPackageJsonInfoFrom(absolute);\n const instances: PackageInstance[] = [];\n for (const [descriptor, value] of Object.entries(parsed)) {\n if (descriptor === \"__metadata\" || !isRecord(value)) continue;\n const entry = value as YarnBerryEntry;\n if (!entry.version) continue;\n const resolution = entry.resolution ?? descriptor;\n if (hasLocalYarnProtocol(resolution) || hasLocalYarnProtocol(descriptor)) {\n continue;\n }\n const name =\n parseYarnDescriptorName(resolution) ?? parseYarnDescriptorName(descriptor);\n if (!name) continue;\n const direct = rootInfo.allDirect.has(name);\n instances.push({\n name,\n version: entry.version,\n ecosystem: \"npm\",\n path: descriptor,\n direct,\n dev: direct ? rootInfo.devDependencies.has(name) : false,\n optional: direct ? rootInfo.optionalDependencies.has(name) : false,\n inputKind: \"lockfile\",\n sourceFile: absolute,\n line: lineOf(raw, descriptor),\n manager: \"yarn\",\n integrity: entry.checksum,\n hasInstallScript: false,\n });\n }\n return dedupeInstances(instances);\n}\n\nfunction hasLocalYarnProtocol(value: string): boolean {\n const normalized = value.trim().replace(/^\"|\"$/g, \"\");\n return LOCAL_YARN_PROTOCOLS.some(\n (protocol) =>\n normalized.startsWith(protocol) || normalized.includes(`@${protocol}`),\n );\n}\n\nexport function parseClassicEntries(raw: string): ParsedYarnClassicEntry[] {\n const entries: ParsedYarnClassicEntry[] = [];\n let current: ParsedYarnClassicEntry | null = null;\n\n for (const line of raw.split(/\\r?\\n/)) {\n if (line === \"\" || line.trimStart().startsWith(\"#\")) continue;\n if (!/^\\s/.test(line)) {\n if (current) entries.push(current);\n current = {\n specs: splitClassicSpecs(line.replace(/:\\s*$/, \"\")),\n fields: {},\n };\n continue;\n }\n if (!current) continue;\n const indent = line.match(/^ +/)?.[0].length ?? 0;\n if (indent !== 2) continue;\n const trimmed = line.trim();\n const match =\n /^([^\\s\"]+)\\s+\"((?:[^\"\\\\]|\\\\.)*)\"$/.exec(trimmed) ??\n /^([^\\s\"]+)\\s+(\\S+)$/.exec(trimmed);\n if (!match) continue;\n current.fields[match[1]!] = match[2]!;\n }\n\n if (current) entries.push(current);\n return entries;\n}\n\nexport function parseYarnDescriptorName(descriptor: string): string | null {\n const first = descriptor.split(\",\")[0]?.trim().replace(/^\"|\"$/g, \"\");\n if (!first) return null;\n for (const marker of [\"@npm:\", \"@patch:\", \"@workspace:\", \"@portal:\", \"@file:\"]) {\n const idx = first.lastIndexOf(marker);\n if (idx > 0) return first.slice(0, idx);\n }\n if (first.startsWith(\"@\")) {\n const slash = first.indexOf(\"/\");\n if (slash === -1) return null;\n const at = first.indexOf(\"@\", slash + 1);\n return at === -1 ? first : first.slice(0, at);\n }\n const at = first.indexOf(\"@\");\n return at === -1 ? first : first.slice(0, at);\n}\n\nexport function parseYarnSpec(spec: string): { name: string; selector: string } {\n const normalized = spec.trim().replace(/^\"|\"$/g, \"\");\n const startSearch = normalized.startsWith(\"@\") ? 1 : 0;\n const at = normalized.indexOf(\"@\", startSearch);\n if (at <= 0) return { name: normalized, selector: \"\" };\n let selector = normalized.slice(at + 1);\n if (selector.startsWith(\"npm:\")) selector = selector.slice(4);\n return { name: normalized.slice(0, at), selector };\n}\n\nfunction splitClassicSpecs(header: string): string[] {\n const specs: string[] = [];\n let current = \"\";\n let quoted = false;\n for (const char of header) {\n if (char === '\"') {\n quoted = !quoted;\n continue;\n }\n if (char === \",\" && !quoted) {\n const spec = current.trim();\n if (spec) specs.push(spec);\n current = \"\";\n continue;\n }\n current += char;\n }\n const tail = current.trim();\n if (tail) specs.push(tail);\n return specs;\n}\n\nfunction isBerryLock(raw: string): boolean {\n return raw.includes(\"__metadata:\") || raw.includes(\"cacheKey:\");\n}\n\nfunction dedupeInstances(instances: PackageInstance[]): PackageInstance[] {\n const seen = new Set<string>();\n const out: PackageInstance[] = [];\n for (const instance of instances) {\n const key = `${instance.name}@${instance.version}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(instance);\n }\n return out;\n}\n\nfunction registryFromResolved(resolved: string | undefined): string | undefined {\n if (!resolved) return undefined;\n try {\n const url = new URL(resolved);\n return `${url.protocol}//${url.host}`;\n } catch {\n return undefined;\n }\n}\n\nfunction lineOf(raw: string, needle: string): number | undefined {\n const idx = raw.indexOf(needle);\n if (idx === -1) return undefined;\n return raw.slice(0, idx).split(/\\r?\\n/).length;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { readFileSync } from \"node:fs\";\nimport { basename, resolve } from \"node:path\";\nimport { XMLParser } from \"fast-xml-parser\";\nimport { PackageURL } from \"packageurl-js\";\nimport type { Ecosystem, PackageInstance } from \"../types.js\";\n\ninterface PurlPackage {\n name: string;\n version: string;\n ecosystem: Ecosystem;\n purl: string;\n}\n\nexport function parseSbom(filePath: string): PackageInstance[] {\n const absolute = resolve(filePath);\n const raw = readFileSync(absolute, \"utf8\");\n const trimmed = raw.trimStart();\n if (trimmed.startsWith(\"{\")) return parseJsonSbom(absolute, raw);\n if (trimmed.startsWith(\"<\")) return parseCycloneDxXml(absolute, raw);\n return parseSpdxTagValue(absolute, raw);\n}\n\nfunction parseJsonSbom(absolute: string, raw: string): PackageInstance[] {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw) as unknown;\n } catch (err) {\n throw new Error(\n `Failed to parse ${absolute}: ${(err as Error).message}`,\n );\n }\n if (!isRecord(parsed)) {\n throw new Error(`SBOM ${absolute} must contain a JSON object.`);\n }\n if (Array.isArray(parsed.components)) {\n return parseCycloneDxJson(absolute, raw, parsed.components);\n }\n if (Array.isArray(parsed.packages)) {\n return parseSpdxJson(absolute, raw, parsed.packages);\n }\n throw new Error(\n `Could not detect SBOM format for ${absolute}; expected CycloneDX or SPDX.`,\n );\n}\n\nfunction parseCycloneDxJson(\n absolute: string,\n raw: string,\n components: unknown[],\n): PackageInstance[] {\n const instances: PackageInstance[] = [];\n for (const component of components) {\n if (!isRecord(component) || typeof component.purl !== \"string\") continue;\n const pkg = parsePurlPackage(component.purl);\n if (!pkg) continue;\n instances.push(sbomPackage(pkg, absolute, raw, component.purl));\n }\n return dedupe(instances);\n}\n\nfunction parseCycloneDxXml(absolute: string, raw: string): PackageInstance[] {\n const parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: \"\",\n textNodeName: \"#text\",\n });\n let parsed: unknown;\n try {\n parsed = parser.parse(raw);\n } catch (err) {\n throw new Error(\n `Failed to parse ${absolute}: ${(err as Error).message}`,\n );\n }\n const bom = isRecord(parsed) ? parsed.bom : undefined;\n const components = isRecord(bom) && isRecord(bom.components)\n ? arrayify(bom.components.component)\n : [];\n const instances: PackageInstance[] = [];\n for (const component of components) {\n if (!isRecord(component) || typeof component.purl !== \"string\") continue;\n const pkg = parsePurlPackage(component.purl);\n if (!pkg) continue;\n instances.push(sbomPackage(pkg, absolute, raw, component.purl));\n }\n return dedupe(instances);\n}\n\nfunction parseSpdxJson(\n absolute: string,\n raw: string,\n packages: unknown[],\n): PackageInstance[] {\n const instances: PackageInstance[] = [];\n for (const pkgRecord of packages) {\n if (!isRecord(pkgRecord)) continue;\n const externalRefs = Array.isArray(pkgRecord.externalRefs)\n ? pkgRecord.externalRefs\n : [];\n for (const ref of externalRefs) {\n if (!isRecord(ref)) continue;\n const locator = ref.referenceLocator;\n const type = String(ref.referenceType ?? \"\").toLowerCase();\n if (type !== \"purl\" || typeof locator !== \"string\") continue;\n const pkg = parsePurlPackage(locator);\n if (!pkg) continue;\n instances.push(sbomPackage(pkg, absolute, raw, locator));\n }\n }\n return dedupe(instances);\n}\n\nfunction parseSpdxTagValue(absolute: string, raw: string): PackageInstance[] {\n if (!raw.includes(\"SPDXVersion:\")) {\n throw new Error(\n `Could not detect SBOM format for ${absolute}; expected CycloneDX or SPDX.`,\n );\n }\n const instances: PackageInstance[] = [];\n for (const line of raw.split(/\\r?\\n/)) {\n const match = line.match(/^ExternalRef:\\s+PACKAGE-MANAGER\\s+purl\\s+(\\S+)/);\n if (!match?.[1]) continue;\n const pkg = parsePurlPackage(match[1]);\n if (!pkg) continue;\n instances.push(sbomPackage(pkg, absolute, raw, match[1]));\n }\n return dedupe(instances);\n}\n\nexport function parsePurlPackage(purl: string): PurlPackage | null {\n let parsed: PackageURL;\n try {\n parsed = PackageURL.fromString(purl);\n } catch {\n return null;\n }\n if (!parsed.version) return null;\n const ecosystem = purlTypeToOsvEcosystem(parsed.type);\n if (!ecosystem) return null;\n return {\n name: purlName(parsed),\n version: parsed.version,\n ecosystem,\n purl,\n };\n}\n\nfunction sbomPackage(\n pkg: PurlPackage,\n absolute: string,\n raw: string,\n needle: string,\n): PackageInstance {\n return {\n name: pkg.name,\n version: pkg.version,\n ecosystem: pkg.ecosystem,\n path: `${basename(absolute)}:${pkg.purl}`,\n direct: false,\n dev: false,\n optional: false,\n inputKind: \"sbom\",\n purl: pkg.purl,\n sourceFile: absolute,\n line: lineOf(raw, needle),\n manager: \"sbom\",\n };\n}\n\nfunction purlTypeToOsvEcosystem(type: string): string | null {\n switch (type.toLowerCase()) {\n case \"npm\":\n return \"npm\";\n case \"pypi\":\n return \"PyPI\";\n case \"maven\":\n return \"Maven\";\n case \"gem\":\n return \"RubyGems\";\n case \"nuget\":\n return \"NuGet\";\n case \"golang\":\n case \"go\":\n return \"Go\";\n case \"cargo\":\n return \"crates.io\";\n case \"composer\":\n return \"Packagist\";\n case \"deb\":\n return \"Debian\";\n case \"apk\":\n return \"Alpine\";\n default:\n return null;\n }\n}\n\nfunction purlName(purl: PackageURL): string {\n if (purl.type.toLowerCase() === \"npm\" && purl.namespace) {\n const scope = purl.namespace.startsWith(\"@\")\n ? purl.namespace\n : `@${purl.namespace}`;\n return `${scope}/${purl.name}`;\n }\n if (purl.type.toLowerCase() === \"maven\" && purl.namespace) {\n return `${purl.namespace}:${purl.name}`;\n }\n return purl.namespace ? `${purl.namespace}/${purl.name}` : purl.name;\n}\n\nfunction dedupe(instances: PackageInstance[]): PackageInstance[] {\n const seen = new Set<string>();\n const out: PackageInstance[] = [];\n for (const instance of instances) {\n const key = instance.purl ?? `${instance.ecosystem}:${instance.name}@${instance.version}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(instance);\n }\n return out;\n}\n\nfunction arrayify(value: unknown): unknown[] {\n if (value === undefined) return [];\n return Array.isArray(value) ? value : [value];\n}\n\nfunction lineOf(raw: string, needle: string): number | undefined {\n const idx = raw.indexOf(needle);\n if (idx === -1) return undefined;\n return raw.slice(0, idx).split(/\\r?\\n/).length;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import type { Finding, IgnoreEntry } from \"./types.js\";\n\nexport interface IgnoreResult {\n active: Finding[];\n ignored: Finding[];\n warnings: string[];\n}\n\nexport function applyIgnores(\n findings: Finding[],\n ignores: IgnoreEntry[],\n now: Date,\n): IgnoreResult {\n if (ignores.length === 0) return { active: findings, ignored: [], warnings: [] };\n\n const warnings: string[] = [];\n const activeIgnores = ignores.filter((entry) => {\n const expires = new Date(`${entry.expires}T23:59:59.999Z`);\n if (Number.isNaN(expires.getTime()) || expires < now) {\n warnings.push(\n `Ignore for ${entry.id} expired on ${entry.expires} and was not applied.`,\n );\n return false;\n }\n return true;\n });\n\n const active: Finding[] = [];\n const ignored: Finding[] = [];\n for (const finding of findings) {\n const matched = activeIgnores.some((entry) => matchesIgnore(finding, entry));\n if (matched) {\n ignored.push({ ...finding, ignored: true });\n } else {\n active.push(finding);\n }\n }\n return { active, ignored, warnings };\n}\n\nfunction matchesIgnore(finding: Finding, entry: IgnoreEntry): boolean {\n const ids = new Set([finding.id, ...finding.aliases]);\n if (!ids.has(entry.id)) return false;\n if (entry.package && entry.package !== finding.packageName) return false;\n if (entry.ecosystem && entry.ecosystem !== finding.ecosystem) return false;\n if (entry.version && entry.version !== finding.installedVersion) return false;\n return true;\n}\n","import type { FailOnLevel, PolicyPresetName } from \"./types.js\";\n\nexport interface PolicyPreset {\n failOn: FailOnLevel;\n risk: boolean;\n env: boolean;\n includeDev: boolean;\n}\n\nexport const POLICY_PRESETS: Record<PolicyPresetName, PolicyPreset> = {\n ci: {\n failOn: \"high\",\n risk: true,\n env: false,\n includeDev: true,\n },\n strict: {\n failOn: \"moderate\",\n risk: true,\n env: true,\n includeDev: true,\n },\n library: {\n failOn: \"moderate\",\n risk: true,\n env: false,\n includeDev: false,\n },\n app: {\n failOn: \"high\",\n risk: true,\n env: true,\n includeDev: true,\n },\n};\n\nexport function resolvePolicy(\n requested: PolicyPresetName | undefined,\n configured: PolicyPresetName | undefined,\n): PolicyPreset | undefined {\n const name = requested ?? configured;\n return name ? POLICY_PRESETS[name] : undefined;\n}\n\n","import { fingerprintFinding } from \"./fingerprint.js\";\nimport type { Finding, PackageInstance } from \"./types.js\";\n\nconst REGISTRY_URL = \"https://registry.npmjs.org\";\nconst REGISTRY_ENV = \"TRAWLY_NPM_REGISTRY_URL\";\nconst REQUEST_TIMEOUT_MS = 15_000;\nconst NEW_VERSION_DAYS = 30;\nconst NEW_PACKAGE_DAYS = 90;\nconst PACKUMENT_CONCURRENCY = 8;\nconst PACKUMENT_MAX_RETRIES = 3;\nconst PACKUMENT_BACKOFF_MS = 250;\n\nexport interface RiskOptions {\n enabled: boolean;\n allowedRegistries: string[];\n fetchImpl?: typeof fetch;\n now: Date;\n}\n\ninterface Packument {\n time?: Record<string, string>;\n versions?: Record<string, { deprecated?: string }>;\n}\n\nexport interface RiskResult {\n findings: Finding[];\n warnings: string[];\n}\n\nexport async function collectRiskSignals(\n packages: PackageInstance[],\n options: RiskOptions,\n): Promise<RiskResult> {\n if (!options.enabled) return { findings: [], warnings: [] };\n\n const findings: Finding[] = [];\n const warnings: string[] = [];\n for (const pkg of packages) {\n if (pkg.hasInstallScript) {\n findings.push(riskFinding(pkg, {\n id: \"TRAWLY-INSTALL-SCRIPT\",\n severity: \"moderate\",\n summary: `${pkg.name}@${pkg.version} declares install-time scripts or requires a build step.`,\n }));\n }\n\n const registry = normalizeRegistry(pkg.registry);\n if (registry && !isAllowedRegistry(registry, options.allowedRegistries)) {\n findings.push(riskFinding(pkg, {\n id: \"TRAWLY-UNEXPECTED-REGISTRY\",\n severity: \"moderate\",\n summary: `${pkg.name}@${pkg.version} was resolved from unexpected registry ${registry}.`,\n }));\n }\n }\n\n const npmPackageGroups = groupNpmPackages(packages);\n const fetchImpl = options.fetchImpl ?? fetch;\n // One packument per package name covers every installed version, so fetch\n // by name and reuse across version groups.\n const groupsByName = new Map<string, PackageInstance[][]>();\n for (const group of npmPackageGroups) {\n const name = group[0]?.name;\n if (!name) continue;\n const list = groupsByName.get(name) ?? [];\n list.push(group);\n groupsByName.set(name, list);\n }\n\n await mapWithConcurrency(\n [...groupsByName.entries()],\n PACKUMENT_CONCURRENCY,\n async ([name, groups]) => {\n let packument: Packument;\n try {\n packument = await fetchPackument(fetchImpl, name);\n } catch (err) {\n warnings.push(\n `Could not fetch npm publish metadata for ${name}: ${(err as Error).message}`,\n );\n return;\n }\n const createdAt = parseDate(packument.time?.created);\n const isNewPackage =\n !!createdAt && daysBetween(createdAt, options.now) < NEW_PACKAGE_DAYS;\n\n for (const group of groups) {\n const representative = group[0];\n if (!representative) continue;\n const versionAt = parseDate(packument.time?.[representative.version]);\n const deprecated = packument.versions?.[representative.version]?.deprecated;\n if (isNewPackage) {\n for (const pkg of group) {\n findings.push(\n riskFinding(pkg, {\n id: \"TRAWLY-NEW-PACKAGE\",\n severity: \"moderate\",\n summary: `${pkg.name} was first published less than ${NEW_PACKAGE_DAYS} days ago.`,\n }),\n );\n }\n }\n if (deprecated) {\n for (const pkg of group) {\n findings.push(\n riskFinding(pkg, {\n id: \"TRAWLY-DEPRECATED-PACKAGE\",\n severity: \"moderate\",\n summary: `${pkg.name}@${pkg.version} is deprecated: ${deprecated}`,\n }),\n );\n }\n }\n if (versionAt && daysBetween(versionAt, options.now) < NEW_VERSION_DAYS) {\n for (const pkg of group) {\n findings.push(\n riskFinding(pkg, {\n id: \"TRAWLY-NEW-VERSION\",\n severity: \"low\",\n summary: `${pkg.name}@${pkg.version} was published less than ${NEW_VERSION_DAYS} days ago.`,\n }),\n );\n }\n }\n }\n },\n );\n\n return { findings, warnings };\n}\n\nfunction riskFinding(\n pkg: PackageInstance,\n input: { id: string; severity: Finding[\"severity\"]; summary: string },\n): Finding {\n return {\n id: input.id,\n source: \"trawly\",\n type: \"risk-signal\",\n severity: input.severity,\n ecosystem: pkg.ecosystem,\n packageName: pkg.name,\n installedVersion: pkg.version,\n summary: input.summary,\n fixedVersions: [],\n affectedPaths: [pkg.path],\n fingerprint: fingerprintFinding({\n source: \"trawly\",\n type: \"risk-signal\",\n id: input.id,\n ecosystem: pkg.ecosystem,\n packageName: pkg.name,\n installedVersion: pkg.version,\n }),\n aliases: [],\n sourceFile: pkg.sourceFile,\n line: pkg.line,\n };\n}\n\nfunction groupNpmPackages(packages: PackageInstance[]): PackageInstance[][] {\n const groups = new Map<string, PackageInstance[]>();\n for (const pkg of packages) {\n if (pkg.ecosystem !== \"npm\") continue;\n const key = `${pkg.name}@${pkg.version}`;\n const group = groups.get(key) ?? [];\n group.push(pkg);\n groups.set(key, group);\n }\n return [...groups.values()];\n}\n\nasync function fetchPackument(\n fetchImpl: typeof fetch,\n name: string,\n): Promise<Packument> {\n const registry = (process.env[REGISTRY_ENV] ?? REGISTRY_URL).replace(/\\/+$/, \"\");\n const url = `${registry}/${encodePackageName(name)}`;\n let lastErr: unknown;\n\n for (let attempt = 0; attempt <= PACKUMENT_MAX_RETRIES; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n try {\n const res = await fetchImpl(url, {\n signal: controller.signal,\n headers: { accept: \"application/json\" },\n });\n if (res.ok) return (await res.json()) as Packument;\n\n const err = new RegistryHttpError(\n `registry ${res.status}: ${res.statusText}`,\n res.status,\n retryAfterMs(res.headers),\n );\n if (!isRetryableRegistryError(err) || attempt === PACKUMENT_MAX_RETRIES) {\n throw err;\n }\n lastErr = err;\n await sleep(retryDelayMs(err, attempt));\n } catch (err) {\n if (err instanceof RegistryHttpError) throw err;\n lastErr = err;\n if (attempt === PACKUMENT_MAX_RETRIES) break;\n await sleep(retryDelayMs(undefined, attempt));\n } finally {\n clearTimeout(timer);\n }\n }\n throw lastErr;\n}\n\nasync function mapWithConcurrency<T>(\n items: T[],\n concurrency: number,\n worker: (item: T) => Promise<void>,\n): Promise<void> {\n let next = 0;\n const workers = Array.from(\n { length: Math.min(concurrency, items.length) },\n async () => {\n while (next < items.length) {\n const item = items[next++];\n if (item !== undefined) await worker(item);\n }\n },\n );\n await Promise.all(workers);\n}\n\nclass RegistryHttpError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly retryAfterMs?: number,\n ) {\n super(message);\n }\n}\n\nfunction isRetryableRegistryError(err: RegistryHttpError): boolean {\n return err.status === 429 || err.status >= 500;\n}\n\nfunction retryDelayMs(\n err: RegistryHttpError | undefined,\n attempt: number,\n): number {\n if (err?.retryAfterMs !== undefined) return err.retryAfterMs;\n const base = PACKUMENT_BACKOFF_MS * 2 ** attempt;\n return base + Math.floor(Math.random() * Math.min(base, 100));\n}\n\nfunction retryAfterMs(headers: Headers): number | undefined {\n const value = headers.get(\"retry-after\");\n if (!value) return undefined;\n const seconds = Number(value);\n if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1000;\n const date = Date.parse(value);\n if (Number.isNaN(date)) return undefined;\n return Math.max(0, date - Date.now());\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction isAllowedRegistry(registry: string, allowed: string[]): boolean {\n const normalizedAllowed = allowed.map(normalizeRegistry).filter(isString);\n return normalizedAllowed.includes(registry);\n}\n\nfunction normalizeRegistry(value: string | undefined): string | undefined {\n if (!value) return undefined;\n try {\n const url = new URL(value);\n return `${url.protocol}//${url.host}`;\n } catch {\n return value.replace(/\\/+$/, \"\");\n }\n}\n\nfunction encodePackageName(name: string): string {\n if (name.startsWith(\"@\")) {\n const slash = name.indexOf(\"/\");\n if (slash !== -1) {\n return `${encodeURIComponent(name.slice(0, slash))}%2F${encodeURIComponent(name.slice(slash + 1))}`;\n }\n }\n return encodeURIComponent(name);\n}\n\nfunction parseDate(value: string | undefined): Date | undefined {\n if (!value) return undefined;\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\nfunction daysBetween(a: Date, b: Date): number {\n return (b.getTime() - a.getTime()) / 86_400_000;\n}\n\nfunction isString(value: string | undefined): value is string {\n return typeof value === \"string\";\n}\n","import { fingerprintFinding, packageKey } from \"../fingerprint.js\";\nimport type { Ecosystem, Finding, PackageInstance, Severity } from \"../types.js\";\n\nconst OSV_QUERYBATCH_URL = \"https://api.osv.dev/v1/querybatch\";\nconst OSV_VULN_URL = \"https://api.osv.dev/v1/vulns\";\nconst QUERY_CHUNK_SIZE = 500;\nconst REQUEST_TIMEOUT_MS = 15_000;\nconst MAX_RETRIES = 2;\nconst DETAIL_CONCURRENCY = 8;\n\ninterface OsvQueryBatchResponse {\n results: Array<{\n vulns?: Array<{ id: string; modified?: string }>;\n next_page_token?: string;\n }>;\n}\n\ninterface OsvSeverity {\n type: string;\n score: string;\n}\n\ninterface OsvAffectedRange {\n type: string;\n events: Array<{ introduced?: string; fixed?: string; last_affected?: string }>;\n}\n\ninterface OsvAffectedPackage {\n package?: { ecosystem?: string; name?: string; purl?: string };\n ranges?: OsvAffectedRange[];\n versions?: string[];\n ecosystem_specific?: { severity?: string };\n}\n\ninterface OsvVulnDetail {\n id: string;\n aliases?: string[];\n summary?: string;\n details?: string;\n references?: Array<{ type?: string; url?: string }>;\n severity?: OsvSeverity[];\n database_specific?: { severity?: string };\n affected?: OsvAffectedPackage[];\n}\n\nexport interface OsvQueryDeps {\n fetchImpl?: typeof fetch;\n}\n\ninterface UniquePackage {\n name: string;\n version: string;\n ecosystem?: Ecosystem;\n purl?: string;\n}\n\n/**\n * Build the deduplicated list of unique name@version pairs to query OSV with.\n */\nexport function dedupeForQuery(\n packages: PackageInstance[],\n): UniquePackage[] {\n const seen = new Set<string>();\n const out: UniquePackage[] = [];\n for (const pkg of packages) {\n const key = packageKey(pkg);\n if (seen.has(key)) continue;\n seen.add(key);\n if (pkg.purl) out.push({ name: pkg.name, version: pkg.version, purl: pkg.purl });\n else if (pkg.ecosystem === \"npm\") out.push({ name: pkg.name, version: pkg.version });\n else {\n out.push({\n name: pkg.name,\n version: pkg.version,\n ecosystem: pkg.ecosystem,\n });\n }\n }\n return out;\n}\n\n/**\n * Query OSV for the given installed packages and return one Finding per\n * (advisory, affected package instance) pair.\n */\nexport async function queryOsv(\n packages: PackageInstance[],\n deps: OsvQueryDeps = {},\n): Promise<Finding[]> {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const unique = dedupeForQuery(packages);\n if (unique.length === 0) return [];\n\n const idsByPackage = new Map<string, Set<string>>();\n for (const chunk of chunked(unique, QUERY_CHUNK_SIZE)) {\n await queryBatchWithPagination(fetchImpl, chunk, idsByPackage);\n }\n\n const allIds = new Set<string>();\n for (const ids of idsByPackage.values()) {\n for (const id of ids) allIds.add(id);\n }\n\n const detailsById = new Map<string, OsvVulnDetail>();\n await mapWithConcurrency([...allIds], DETAIL_CONCURRENCY, async (id) => {\n try {\n const detail = await getJson<OsvVulnDetail>(\n fetchImpl,\n `${OSV_VULN_URL}/${encodeURIComponent(id)}`,\n );\n detailsById.set(id, detail);\n } catch {\n // Skip missing/broken records; we still have the id reported below.\n }\n });\n\n const findings: Finding[] = [];\n for (const pkg of packages) {\n const key = packageKey(pkg);\n const ids = idsByPackage.get(key);\n if (!ids) continue;\n for (const id of ids) {\n const detail = detailsById.get(id);\n findings.push(buildFinding(pkg, id, detail));\n }\n }\n return findings;\n}\n\nasync function queryBatchWithPagination(\n fetchImpl: typeof fetch,\n initial: UniquePackage[],\n idsByPackage: Map<string, Set<string>>,\n): Promise<void> {\n let pending = initial;\n const pageTokens = new Map<string, string>();\n\n while (pending.length > 0) {\n const res = await postJson<OsvQueryBatchResponse>(\n fetchImpl,\n OSV_QUERYBATCH_URL,\n { queries: pending.map((q) => toOsvQuery(q, pageTokens.get(queryKey(q)))) },\n );\n\n const next: UniquePackage[] = [];\n res.results.forEach((result, i) => {\n const q = pending[i];\n if (!q) return;\n const key = queryKey(q);\n if (result.vulns && result.vulns.length > 0) {\n const ids = idsByPackage.get(key) ?? new Set<string>();\n for (const v of result.vulns) ids.add(v.id);\n idsByPackage.set(key, ids);\n }\n if (result.next_page_token) {\n pageTokens.set(key, result.next_page_token);\n next.push(q);\n } else {\n pageTokens.delete(key);\n }\n });\n pending = next;\n }\n}\n\nfunction toOsvQuery(\n q: UniquePackage,\n pageToken: string | undefined,\n): Record<string, unknown> {\n const query = q.purl\n ? { package: { purl: q.purl } }\n : {\n package: { ecosystem: q.ecosystem ?? \"npm\", name: q.name },\n version: q.version,\n };\n return pageToken ? { ...query, page_token: pageToken } : query;\n}\n\nfunction queryKey(q: UniquePackage): string {\n return q.purl ?? `${q.ecosystem ?? \"npm\"}:${q.name}@${q.version}`;\n}\n\nfunction buildFinding(\n pkg: PackageInstance,\n id: string,\n detail: OsvVulnDetail | undefined,\n): Finding {\n const severity = detail ? parseSeverity(detail, pkg.name) : \"unknown\";\n const summary = detail?.summary ?? detail?.details ?? id;\n const aliases = detail?.aliases ?? [];\n const fingerprint = fingerprintFinding({\n source: \"osv\",\n type: \"vulnerability\",\n id,\n ecosystem: pkg.ecosystem,\n packageName: pkg.name,\n installedVersion: pkg.version,\n });\n return {\n id,\n source: \"osv\",\n type: \"vulnerability\",\n severity,\n ecosystem: pkg.ecosystem,\n packageName: pkg.name,\n installedVersion: pkg.version,\n summary: truncate(summary, 240),\n url: pickAdvisoryUrl(detail) ?? `https://osv.dev/vulnerability/${id}`,\n fixedVersions: detail ? collectFixedVersions(detail, pkg.name) : [],\n affectedPaths: [pkg.path],\n fingerprint,\n aliases,\n sourceFile: pkg.sourceFile,\n line: pkg.line,\n };\n}\n\nexport function parseSeverity(\n detail: OsvVulnDetail,\n packageName?: string,\n): Severity {\n // GHSA records expose a normalized severity in database_specific.severity.\n const dbSpecific = detail.database_specific?.severity?.toLowerCase();\n if (\n dbSpecific === \"critical\" ||\n dbSpecific === \"high\" ||\n dbSpecific === \"moderate\" ||\n dbSpecific === \"low\"\n ) {\n return dbSpecific;\n }\n if (dbSpecific === \"medium\") return \"moderate\";\n\n for (const aff of matchingAffected(detail, packageName)) {\n const ecosystemSeverity = aff.ecosystem_specific?.severity?.toLowerCase();\n if (\n ecosystemSeverity === \"critical\" ||\n ecosystemSeverity === \"high\" ||\n ecosystemSeverity === \"moderate\" ||\n ecosystemSeverity === \"low\"\n ) {\n return ecosystemSeverity;\n }\n if (ecosystemSeverity === \"medium\") return \"moderate\";\n }\n\n const cvss = detail.severity?.find((s) => s.type?.startsWith(\"CVSS_\"));\n if (cvss) {\n const score = parseCvssScore(cvss.score);\n if (score === undefined) return \"unknown\";\n if (score >= 9.0) return \"critical\";\n if (score >= 7.0) return \"high\";\n if (score >= 4.0) return \"moderate\";\n if (score > 0) return \"low\";\n }\n return \"unknown\";\n}\n\nfunction parseCvssScore(vector: string): number | undefined {\n const direct = Number.parseFloat(vector);\n if (!Number.isNaN(direct) && vector.trim() !== \"\") return direct;\n // Some entries store the full CVSS vector string; we don't compute it here.\n return undefined;\n}\n\nfunction pickAdvisoryUrl(detail: OsvVulnDetail | undefined): string | undefined {\n if (!detail?.references) return undefined;\n const advisory = detail.references.find((r) => r.type === \"ADVISORY\");\n return advisory?.url ?? detail.references[0]?.url;\n}\n\nexport function collectFixedVersions(\n detail: OsvVulnDetail,\n packageName: string,\n): string[] {\n const out = new Set<string>();\n for (const aff of matchingAffected(detail, packageName)) {\n for (const range of aff.ranges ?? []) {\n for (const event of range.events ?? []) {\n if (event.fixed) out.add(event.fixed);\n }\n }\n }\n return [...out];\n}\n\nfunction matchingAffected(\n detail: OsvVulnDetail,\n packageName: string | undefined,\n): OsvAffectedPackage[] {\n if (!packageName) return detail.affected ?? [];\n return (detail.affected ?? []).filter((aff) => {\n const affectedName = aff.package?.name;\n return !affectedName || affectedName === packageName;\n });\n}\n\nfunction* chunked<T>(items: T[], size: number): Generator<T[]> {\n for (let i = 0; i < items.length; i += size) {\n yield items.slice(i, i + size);\n }\n}\n\nasync function mapWithConcurrency<T>(\n items: T[],\n concurrency: number,\n worker: (item: T) => Promise<void>,\n): Promise<void> {\n let next = 0;\n const workers = Array.from(\n { length: Math.min(concurrency, items.length) },\n async () => {\n while (next < items.length) {\n const item = items[next++];\n if (item !== undefined) await worker(item);\n }\n },\n );\n await Promise.all(workers);\n}\n\nasync function postJson<T>(\n fetchImpl: typeof fetch,\n url: string,\n body: unknown,\n): Promise<T> {\n return withRetry(async () => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n try {\n const res = await fetchImpl(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n throw new HttpError(\n `OSV ${res.status}: ${res.statusText}`,\n res.status,\n retryAfterMs(res.headers),\n );\n }\n return (await res.json()) as T;\n } finally {\n clearTimeout(timer);\n }\n });\n}\n\nasync function getJson<T>(fetchImpl: typeof fetch, url: string): Promise<T> {\n return withRetry(async () => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n try {\n const res = await fetchImpl(url, { signal: controller.signal });\n if (!res.ok) {\n throw new HttpError(\n `OSV ${res.status}: ${res.statusText}`,\n res.status,\n retryAfterMs(res.headers),\n );\n }\n return (await res.json()) as T;\n } finally {\n clearTimeout(timer);\n }\n });\n}\n\nclass HttpError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly retryAfterMs?: number,\n ) {\n super(message);\n }\n}\n\nasync function withRetry<T>(fn: () => Promise<T>): Promise<T> {\n let lastErr: unknown;\n for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastErr = err;\n if (!isRetryable(err) || attempt === MAX_RETRIES) break;\n const delay = err instanceof HttpError && err.retryAfterMs !== undefined\n ? err.retryAfterMs\n : 250 * 2 ** attempt;\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n throw lastErr;\n}\n\nfunction isRetryable(err: unknown): boolean {\n if (err instanceof HttpError) return err.status === 429 || err.status >= 500;\n // AbortError (timeout) and network errors are retryable.\n return true;\n}\n\nfunction retryAfterMs(headers: Headers): number | undefined {\n const value = headers.get(\"retry-after\");\n if (!value) return undefined;\n const seconds = Number(value);\n if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1000;\n const date = Date.parse(value);\n if (Number.isNaN(date)) return undefined;\n return Math.max(0, date - Date.now());\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s;\n return `${s.slice(0, max - 1)}…`;\n}\n","export type Severity = \"critical\" | \"high\" | \"moderate\" | \"low\" | \"unknown\";\n\nexport type Ecosystem = string;\n\nexport type FindingType =\n | \"vulnerability\"\n | \"malware\"\n | \"secret\"\n | \"risk-signal\"\n | \"integrity\";\n\nexport type FindingSource = \"osv\" | \"trawly\";\n\nexport type InputKind = \"lockfile\" | \"sbom\" | \"adhoc\";\n\nexport const SEVERITY_RANK: Record<Severity, number> = {\n critical: 4,\n high: 3,\n moderate: 2,\n low: 1,\n unknown: 0,\n};\n\nexport interface PackageInstance {\n name: string;\n version: string;\n ecosystem: Ecosystem;\n /** Path within the source manifest, e.g. \"node_modules/foo\" or an SBOM ref. */\n path: string;\n direct: boolean;\n dev: boolean;\n optional: boolean;\n inputKind?: InputKind;\n purl?: string;\n sourceFile?: string;\n line?: number;\n manager?: \"npm\" | \"pnpm\" | \"yarn\" | \"sbom\" | string;\n resolved?: string;\n integrity?: string;\n registry?: string;\n hasInstallScript?: boolean;\n publishedAt?: string;\n packagePublishedAt?: string;\n}\n\nexport interface Finding {\n id: string;\n source: FindingSource;\n type: FindingType;\n severity: Severity;\n ecosystem: Ecosystem;\n packageName: string;\n installedVersion: string;\n summary: string;\n url?: string;\n fixedVersions: string[];\n affectedPaths: string[];\n fingerprint: string;\n aliases: string[];\n sourceFile?: string;\n line?: number;\n ignored?: boolean;\n baseline?: \"new\" | \"existing\";\n}\n\nexport interface ScanError {\n message: string;\n cause?: string;\n}\n\nexport interface ScanResult {\n scannedAt: string;\n packagesScanned: number;\n findings: Finding[];\n ignoredFindings: Finding[];\n summary: Record<Severity, number>;\n errors: ScanError[];\n warnings: string[];\n baseline?: BaselineResult;\n}\n\nexport interface IgnoreEntry {\n id: string;\n package?: string;\n ecosystem?: string;\n version?: string;\n expires: string;\n reason: string;\n}\n\nexport interface TrawlyConfig {\n failOn?: FailOnLevel;\n policy?: PolicyPresetName;\n risk?: boolean;\n env?: boolean;\n allowedRegistries?: string[];\n ignore: IgnoreEntry[];\n}\n\nexport interface BaselineFile {\n version: 1;\n generatedAt: string;\n findings: string[];\n}\n\nexport interface BaselineResult {\n path?: string;\n loaded: boolean;\n written?: string;\n total: number;\n existing: number;\n new: number;\n}\n\nexport interface ScanProjectOptions {\n cwd?: string;\n lockfile?: string | string[];\n sbom?: string | string[];\n config?: string;\n policy?: PolicyPresetName;\n baseline?: string;\n writeBaseline?: string;\n risk?: boolean;\n env?: boolean;\n allowedRegistries?: string[];\n includeDev?: boolean;\n prodOnly?: boolean;\n fetchImpl?: typeof fetch;\n now?: Date;\n}\n\nexport interface ScanLockfileOptions {\n lockfilePath: string | string[];\n sbom?: string | string[];\n cwd?: string;\n config?: string;\n policy?: PolicyPresetName;\n baseline?: string;\n writeBaseline?: string;\n risk?: boolean;\n env?: boolean;\n allowedRegistries?: string[];\n includeDev?: boolean;\n prodOnly?: boolean;\n fetchImpl?: typeof fetch;\n now?: Date;\n}\n\nexport type FailOnLevel = Severity | \"none\";\n\nexport type PolicyPresetName = \"ci\" | \"strict\" | \"library\" | \"app\";\n","import { spawn } from \"node:child_process\";\nimport { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { join, relative, resolve, sep } from \"node:path\";\nimport type { Severity } from \"./types.js\";\n\nexport type EnvIssueKind =\n | \"tracked-by-git\"\n | \"not-gitignored\"\n | \"would-be-published\"\n | \"secret-in-example\"\n | \"no-gitignore\";\n\nexport interface EnvIssue {\n kind: EnvIssueKind;\n severity: Severity;\n file: string;\n message: string;\n detail?: string;\n}\n\nexport interface EnvScanResult {\n scannedAt: string;\n cwd: string;\n envFiles: string[];\n issues: EnvIssue[];\n summary: Record<Severity, number>;\n errors: { message: string; cause?: string }[];\n}\n\nexport interface EnvScanOptions {\n cwd?: string;\n /** Cap on directory recursion depth from cwd. Default 6. */\n maxDepth?: number;\n /** Override directory skip list (replaces the default). */\n skipDirs?: string[];\n}\n\nconst DEFAULT_SKIP_DIRS = new Set([\n \"node_modules\",\n \".git\",\n \"dist\",\n \"build\",\n \".next\",\n \".nuxt\",\n \".svelte-kit\",\n \".turbo\",\n \".cache\",\n \"coverage\",\n \"out\",\n \".vercel\",\n \".output\",\n]);\n\nconst EXAMPLE_NAME = /^\\.env(\\.[^.]+)*\\.(example|sample|template|dist)$/i;\nconst EXAMPLE_SUFFIX_NAME = /(\\.|^)(example|sample|template)$/i;\n\nexport async function scanEnv(\n options: EnvScanOptions = {},\n): Promise<EnvScanResult> {\n const cwd = resolve(options.cwd ?? process.cwd());\n const skipDirs = options.skipDirs\n ? new Set(options.skipDirs)\n : DEFAULT_SKIP_DIRS;\n const maxDepth = options.maxDepth ?? 6;\n\n const errors: { message: string; cause?: string }[] = [];\n const envFiles = discoverEnvFiles(cwd, skipDirs, maxDepth);\n\n const inGit = isGitRepo(cwd);\n const gitignorePath = join(cwd, \".gitignore\");\n const hasGitignore = existsSync(gitignorePath);\n const exampleFiles = envFiles.filter(isExampleFile);\n const realEnvFiles = envFiles.filter((f) => !isExampleFile(f));\n\n const [trackedSet, ignoredMap, publishCheck, exampleSecrets] =\n await Promise.all([\n inGit ? gitTracked(cwd, envFiles) : Promise.resolve(new Set<string>()),\n inGit\n ? gitCheckIgnore(cwd, envFiles)\n : Promise.resolve(fallbackIgnoreMap(cwd, envFiles)),\n checkPublishExposure(cwd, realEnvFiles),\n scanExampleFilesForSecrets(cwd, exampleFiles),\n ]).catch((err) => {\n errors.push({\n message: \"env scan: parallel checks failed\",\n cause: (err as Error).message,\n });\n return [\n new Set<string>(),\n new Map<string, boolean>(),\n [] as PublishFinding[],\n [] as SecretFinding[],\n ] as const;\n });\n\n const issues: EnvIssue[] = [];\n\n if (envFiles.length > 0 && !hasGitignore) {\n issues.push({\n kind: \"no-gitignore\",\n severity: \"moderate\",\n file: \".gitignore\",\n message: \"Project has env files but no .gitignore.\",\n detail:\n \"Add a .gitignore that includes .env and .env.* before committing.\",\n });\n }\n\n for (const file of realEnvFiles) {\n if (trackedSet.has(file)) {\n issues.push({\n kind: \"tracked-by-git\",\n severity: \"critical\",\n file,\n message: `${file} is tracked by git.`,\n detail:\n \"This file is committed to the repo. Run `git rm --cached` and rotate any secrets that were exposed.\",\n });\n continue;\n }\n const ignored = ignoredMap.get(file);\n if (hasGitignore && ignored === false) {\n issues.push({\n kind: \"not-gitignored\",\n severity: \"high\",\n file,\n message: `${file} exists but is not covered by .gitignore.`,\n detail: \"Add a matching pattern (e.g. `.env*`) to .gitignore.\",\n });\n }\n }\n\n for (const f of publishCheck) {\n issues.push({\n kind: \"would-be-published\",\n severity: \"critical\",\n file: f.file,\n message: `${f.file} would be included in the published npm tarball.`,\n detail: f.reason,\n });\n }\n\n for (const f of exampleSecrets) {\n issues.push({\n kind: \"secret-in-example\",\n severity: \"high\",\n file: f.file,\n message: `${f.file} appears to contain a real secret.`,\n detail: `Matched pattern: ${f.pattern} on key \\`${f.key}\\`. Example files should hold placeholder values only.`,\n });\n }\n\n issues.sort(compareIssues);\n\n return {\n scannedAt: new Date().toISOString(),\n cwd,\n envFiles,\n issues,\n summary: summarizeIssues(issues),\n errors,\n };\n}\n\nfunction compareIssues(a: EnvIssue, b: EnvIssue): number {\n const rank: Record<Severity, number> = {\n critical: 4,\n high: 3,\n moderate: 2,\n low: 1,\n unknown: 0,\n };\n const sev = rank[b.severity] - rank[a.severity];\n if (sev !== 0) return sev;\n if (a.file !== b.file) return a.file.localeCompare(b.file);\n return a.kind.localeCompare(b.kind);\n}\n\nfunction summarizeIssues(issues: EnvIssue[]): Record<Severity, number> {\n const out: Record<Severity, number> = {\n critical: 0,\n high: 0,\n moderate: 0,\n low: 0,\n unknown: 0,\n };\n for (const i of issues) out[i.severity]++;\n return out;\n}\n\nfunction discoverEnvFiles(\n cwd: string,\n skipDirs: Set<string>,\n maxDepth: number,\n): string[] {\n const found: string[] = [];\n walk(cwd, cwd, 0);\n found.sort();\n return found;\n\n function walk(dir: string, root: string, depth: number): void {\n if (depth > maxDepth) return;\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (skipDirs.has(entry.name) || entry.name.startsWith(\".git\")) continue;\n walk(join(dir, entry.name), root, depth + 1);\n continue;\n }\n if (!entry.isFile() && !entry.isSymbolicLink()) continue;\n if (isEnvFilename(entry.name)) {\n found.push(toPosix(relative(root, join(dir, entry.name))));\n }\n }\n }\n}\n\nfunction isEnvFilename(name: string): boolean {\n if (name === \".env\") return true;\n if (name.startsWith(\".env.\")) return true;\n return false;\n}\n\nfunction isExampleFile(file: string): boolean {\n const base = file.split(\"/\").pop() ?? file;\n if (EXAMPLE_NAME.test(base)) return true;\n // Catch `.env.example` and similar where the suffix is the last segment.\n const segments = base.split(\".\");\n const last = segments[segments.length - 1] ?? \"\";\n return EXAMPLE_SUFFIX_NAME.test(last);\n}\n\nfunction toPosix(p: string): string {\n return sep === \"/\" ? p : p.split(sep).join(\"/\");\n}\n\nfunction isGitRepo(cwd: string): boolean {\n let dir = cwd;\n for (let i = 0; i < 32; i++) {\n if (existsSync(join(dir, \".git\"))) return true;\n const parent = resolve(dir, \"..\");\n if (parent === dir) return false;\n dir = parent;\n }\n return false;\n}\n\nasync function gitTracked(\n cwd: string,\n files: string[],\n): Promise<Set<string>> {\n if (files.length === 0) return new Set();\n const { stdout, code } = await runGit(cwd, [\"ls-files\", \"-z\", \"--\", ...files]);\n if (code !== 0) return new Set();\n const tracked = stdout.split(\"\\0\").filter(Boolean).map(toPosix);\n return new Set(tracked);\n}\n\nasync function gitCheckIgnore(\n cwd: string,\n files: string[],\n): Promise<Map<string, boolean>> {\n const result = new Map<string, boolean>();\n if (files.length === 0) return result;\n // -z is only valid with --stdin. We pipe NUL-separated paths to a single\n // process — one spawn for any number of files.\n const stdin = `${files.join(\"\\0\")}\\0`;\n const { stdout, code } = await runGit(\n cwd,\n [\"check-ignore\", \"--no-index\", \"-v\", \"-n\", \"-z\", \"--stdin\"],\n stdin,\n );\n if (code !== 0 && code !== 1) {\n // Operational failure; treat all as unknown (false).\n for (const f of files) result.set(f, false);\n return result;\n }\n // -z -v -n format: for each input path, three NUL-separated fields:\n // <source>\\0<linenum>\\0<pattern>\\0<pathname>\\0\n // For non-matching paths: source/linenum/pattern are empty strings.\n const parts = stdout.split(\"\\0\");\n for (let i = 0; i + 3 < parts.length; i += 4) {\n const source = parts[i];\n const pathname = toPosix(parts[i + 3] ?? \"\");\n if (!pathname) continue;\n result.set(pathname, source !== \"\");\n }\n for (const f of files) {\n if (!result.has(f)) result.set(f, false);\n }\n return result;\n}\n\nfunction fallbackIgnoreMap(\n cwd: string,\n files: string[],\n): Map<string, boolean> {\n // Not a git repo: do best-effort matching on a literal .gitignore.\n const result = new Map<string, boolean>();\n const patterns = readIgnoreFile(join(cwd, \".gitignore\"));\n for (const f of files) result.set(f, matchesAny(f, patterns));\n return result;\n}\n\nfunction runGit(\n cwd: string,\n args: string[],\n stdin?: string,\n): Promise<{ stdout: string; stderr: string; code: number }> {\n return new Promise((resolveP) => {\n const child = spawn(\"git\", args, {\n cwd,\n stdio: [stdin === undefined ? \"ignore\" : \"pipe\", \"pipe\", \"pipe\"],\n });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout?.on(\"data\", (d) => {\n stdout += d.toString(\"utf8\");\n });\n child.stderr?.on(\"data\", (d) => {\n stderr += d.toString(\"utf8\");\n });\n child.on(\"error\", () => resolveP({ stdout, stderr, code: -1 }));\n child.on(\"close\", (code) =>\n resolveP({ stdout, stderr, code: code ?? -1 }),\n );\n if (stdin !== undefined && child.stdin) {\n child.stdin.end(stdin);\n }\n });\n}\n\ninterface PublishFinding {\n file: string;\n reason: string;\n}\n\nasync function checkPublishExposure(\n cwd: string,\n envFiles: string[],\n): Promise<PublishFinding[]> {\n if (envFiles.length === 0) return [];\n const pkgPath = join(cwd, \"package.json\");\n if (!existsSync(pkgPath)) return [];\n let pkg: { files?: unknown; private?: unknown };\n try {\n pkg = JSON.parse(readFileSync(pkgPath, \"utf8\"));\n } catch {\n return [];\n }\n // Private packages are never published; skip the check.\n if (pkg.private === true) return [];\n\n const findings: PublishFinding[] = [];\n\n if (Array.isArray(pkg.files)) {\n const allowList = pkg.files.filter((x): x is string => typeof x === \"string\");\n for (const file of envFiles) {\n if (matchesAny(file, allowList)) {\n findings.push({\n file,\n reason: `package.json \"files\" allowlist matches this path. Remove the entry or move the file.`,\n });\n }\n }\n return findings;\n }\n\n // No `files` allowlist: npm uses .npmignore, falling back to .gitignore.\n const npmignorePath = join(cwd, \".npmignore\");\n const ignorePath = existsSync(npmignorePath)\n ? npmignorePath\n : join(cwd, \".gitignore\");\n const ignoreSource = existsSync(ignorePath)\n ? ignorePath === npmignorePath\n ? \".npmignore\"\n : \".gitignore\"\n : null;\n const patterns = ignoreSource ? readIgnoreFile(ignorePath) : [];\n\n for (const file of envFiles) {\n if (!matchesAny(file, patterns)) {\n findings.push({\n file,\n reason: ignoreSource\n ? `Not matched by any pattern in ${ignoreSource}. Add an entry like \\`.env*\\`.`\n : `No .npmignore or .gitignore present, so npm will include this file in the published tarball. Add an .npmignore.`,\n });\n }\n }\n return findings;\n}\n\nfunction readIgnoreFile(path: string): string[] {\n if (!existsSync(path)) return [];\n try {\n return readFileSync(path, \"utf8\")\n .split(/\\r?\\n/)\n .map((l) => l.trim())\n .filter((l) => l.length > 0 && !l.startsWith(\"#\"));\n } catch {\n return [];\n }\n}\n\n/**\n * Simplified gitignore-style matcher. Supports:\n * - exact filename / path match\n * - leading `/` anchors to repo root\n * - `*` wildcard within a single path segment\n * - `**` matches any number of segments\n * - leading `!` negation\n * Patterns without a slash match against the basename at any depth.\n */\nexport function matchesAny(file: string, patterns: string[]): boolean {\n let matched = false;\n for (const raw of patterns) {\n let pattern = raw;\n let negate = false;\n if (pattern.startsWith(\"!\")) {\n negate = true;\n pattern = pattern.slice(1);\n }\n if (pattern.endsWith(\"/\")) pattern = pattern.slice(0, -1);\n if (matchesPattern(file, pattern)) matched = !negate;\n }\n return matched;\n}\n\nfunction matchesPattern(file: string, pattern: string): boolean {\n if (!pattern) return false;\n const anchored = pattern.startsWith(\"/\");\n const pat = anchored ? pattern.slice(1) : pattern;\n const hasSlash = pat.includes(\"/\");\n const candidates = anchored\n ? [file]\n : hasSlash\n ? [file]\n : [file, file.split(\"/\").pop() ?? file];\n const re = globToRegex(pat);\n return candidates.some((c) => re.test(c));\n}\n\nfunction globToRegex(pattern: string): RegExp {\n let re = \"^\";\n for (let i = 0; i < pattern.length; i++) {\n const ch = pattern[i];\n if (ch === \"*\") {\n if (pattern[i + 1] === \"*\") {\n re += \".*\";\n i++;\n if (pattern[i + 1] === \"/\") i++;\n } else {\n re += \"[^/]*\";\n }\n } else if (ch === \"?\") {\n re += \"[^/]\";\n } else if (ch === \".\") {\n re += \"\\\\.\";\n } else if (/[\\\\^$+()=!|{}[\\]]/.test(ch ?? \"\")) {\n re += `\\\\${ch}`;\n } else {\n re += ch;\n }\n }\n re += \"$\";\n return new RegExp(re);\n}\n\ninterface SecretFinding {\n file: string;\n key: string;\n pattern: string;\n}\n\nconst SECRET_PATTERNS: { name: string; re: RegExp }[] = [\n { name: \"AWS access key id\", re: /\\bAKIA[0-9A-Z]{16}\\b/ },\n { name: \"GitHub token\", re: /\\bgh[pousr]_[A-Za-z0-9]{36,}\\b/ },\n { name: \"Slack token\", re: /\\bxox[abprs]-[A-Za-z0-9-]{10,}\\b/ },\n { name: \"Stripe live key\", re: /\\bsk_live_[A-Za-z0-9]{16,}\\b/ },\n { name: \"Google API key\", re: /\\bAIza[0-9A-Za-z_-]{35}\\b/ },\n { name: \"Generic JWT\", re: /\\beyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\b/ },\n { name: \"Private key block\", re: /-----BEGIN (RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----/ },\n];\n\nconst PLACEHOLDER_RE = /^(?:|x+|y+|<.*>|\\{.*\\}|change[-_ ]?me|todo|placeholder|your[-_ ].+|example|dummy|fake|test)$/i;\n\nasync function scanExampleFilesForSecrets(\n cwd: string,\n files: string[],\n): Promise<SecretFinding[]> {\n const findings: SecretFinding[] = [];\n await Promise.all(\n files.map(async (file) => {\n let content: string;\n try {\n content = readFileSync(join(cwd, file), \"utf8\");\n } catch {\n return;\n }\n const lines = content.split(/\\r?\\n/);\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n const eq = trimmed.indexOf(\"=\");\n if (eq <= 0) continue;\n const key = trimmed.slice(0, eq).trim();\n let value = trimmed.slice(eq + 1).trim();\n // Strip wrapping quotes and inline comment.\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n } else {\n const hashIdx = value.indexOf(\" #\");\n if (hashIdx >= 0) value = value.slice(0, hashIdx).trim();\n }\n if (!value || PLACEHOLDER_RE.test(value)) continue;\n for (const pat of SECRET_PATTERNS) {\n if (pat.re.test(value)) {\n findings.push({ file, key, pattern: pat.name });\n break;\n }\n }\n }\n }),\n );\n return findings;\n}\n\nexport function envIssuesMeetThreshold(\n issues: EnvIssue[],\n threshold: Severity | \"none\",\n): boolean {\n if (threshold === \"none\") return false;\n const rank: Record<Severity, number> = {\n critical: 4,\n high: 3,\n moderate: 2,\n low: 1,\n unknown: 0,\n };\n const min = rank[threshold];\n return issues.some((i) => rank[i.severity] >= min);\n}\n\n","import { existsSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { POLICY_PRESETS } from \"./policy.js\";\nimport { scanProject, ScanInputError } from \"./scanner.js\";\nimport type { PolicyPresetName, ScanResult } from \"./types.js\";\n\nexport interface InitOptions {\n cwd?: string;\n config?: string;\n baseline?: string;\n policy?: PolicyPresetName;\n risk?: boolean;\n env?: boolean;\n writeBaseline?: boolean;\n overwrite?: boolean;\n fetchImpl?: typeof fetch;\n}\n\nexport interface InitResult {\n configPath: string;\n configWritten: boolean;\n baselinePath?: string;\n baselineWritten: boolean;\n scan?: ScanResult;\n warnings: string[];\n}\n\nexport async function initProject(\n options: InitOptions = {},\n): Promise<InitResult> {\n const cwd = resolve(options.cwd ?? process.cwd());\n const policy = options.policy ?? \"ci\";\n const configPath = resolve(cwd, options.config ?? \"trawly.toml\");\n const baselinePath = options.baseline ?? \"trawly-baseline.json\";\n const warnings: string[] = [];\n\n let configWritten = false;\n if (options.overwrite || !existsSync(configPath)) {\n writeFileSync(configPath, renderConfig(policy, baselinePath));\n configWritten = true;\n } else {\n warnings.push(`${configPath} already exists; leaving it unchanged.`);\n }\n\n let scan: ScanResult | undefined;\n let baselineWritten = false;\n if (options.writeBaseline !== false) {\n try {\n scan = await scanProject({\n cwd,\n config: configPath,\n policy,\n risk: options.risk,\n env: options.env,\n writeBaseline: baselinePath,\n fetchImpl: options.fetchImpl,\n });\n baselineWritten = scan.baseline?.written !== undefined;\n } catch (err) {\n if (err instanceof ScanInputError) {\n warnings.push(\n \"No supported lockfile or SBOM was found, so no baseline was written.\",\n );\n } else {\n throw err;\n }\n }\n }\n\n return {\n configPath,\n configWritten,\n baselinePath: resolve(cwd, baselinePath),\n baselineWritten,\n scan,\n warnings,\n };\n}\n\nfunction renderConfig(\n policy: PolicyPresetName,\n baselinePath: string,\n): string {\n const preset = POLICY_PRESETS[policy];\n return [\n `policy = \"${policy}\"`,\n `failOn = \"${preset.failOn}\"`,\n `risk = ${String(preset.risk)}`,\n `env = ${String(preset.env)}`,\n 'allowedRegistries = [\"https://registry.npmjs.org\", \"https://registry.yarnpkg.com\"]',\n \"\",\n `# Existing findings are tracked in ${baselinePath}.`,\n \"# Ignore entries must expire.\",\n \"# [[ignore]]\",\n '# id = \"GHSA-example\"',\n '# package = \"example-package\"',\n '# expires = \"2026-06-30\"',\n '# reason = \"Not reachable in this application\"',\n \"\",\n ].join(\"\\n\");\n}\n","import { existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { parseLockfile } from \"./extractors/lockfile.js\";\nimport type { PackageInstance } from \"./types.js\";\n\nexport interface WhyOptions {\n cwd?: string;\n lockfile?: string | string[];\n}\n\nexport interface WhyMatch {\n package: PackageInstance;\n chain: string[];\n note?: string;\n}\n\nexport interface WhyResult {\n packageName: string;\n lockfiles: string[];\n matches: WhyMatch[];\n}\n\nexport function explainWhy(\n packageName: string,\n options: WhyOptions = {},\n): WhyResult {\n const cwd = resolve(options.cwd ?? process.cwd());\n const lockfiles = options.lockfile\n ? normalizePaths(cwd, options.lockfile)\n : detectLockfiles(cwd);\n const packages = lockfiles.flatMap((path) => parseLockfile(path));\n const matches = packages\n .filter((pkg) => pkg.name === packageName)\n .map((pkg) => ({\n package: pkg,\n chain: inferChain(pkg),\n note: graphNote(pkg),\n }))\n .sort((a, b) => {\n const source = (a.package.sourceFile ?? \"\").localeCompare(\n b.package.sourceFile ?? \"\",\n );\n if (source !== 0) return source;\n return a.package.path.localeCompare(b.package.path);\n });\n\n return { packageName, lockfiles, matches };\n}\n\nfunction inferChain(pkg: PackageInstance): string[] {\n if (pkg.manager === \"npm\") {\n const chain = packageNamesFromNodeModulesPath(pkg.path);\n if (chain.length > 0) return chain;\n }\n return [pkg.name];\n}\n\nfunction graphNote(pkg: PackageInstance): string | undefined {\n if (pkg.manager === \"npm\") return undefined;\n if (pkg.direct) return \"direct dependency\";\n return `${pkg.manager ?? \"lockfile\"} lock entry; full parent chain is not available yet`;\n}\n\nfunction packageNamesFromNodeModulesPath(path: string): string[] {\n const parts = path.split(\"/\");\n const names: string[] = [];\n for (let i = 0; i < parts.length; i++) {\n if (parts[i] !== \"node_modules\") continue;\n const first = parts[i + 1];\n if (!first) continue;\n if (first.startsWith(\"@\")) {\n const second = parts[i + 2];\n if (!second) continue;\n names.push(`${first}/${second}`);\n i += 2;\n } else {\n names.push(first);\n i += 1;\n }\n }\n return names;\n}\n\nfunction detectLockfiles(cwd: string): string[] {\n const candidates = [\n \"package-lock.json\",\n \"npm-shrinkwrap.json\",\n \"pnpm-lock.yaml\",\n \"yarn.lock\",\n ].map((file) => join(cwd, file));\n return candidates.filter((candidate) => existsSync(candidate));\n}\n\nfunction normalizePaths(\n cwd: string,\n value: string | string[] | undefined,\n): string[] {\n if (!value) return [];\n const values = Array.isArray(value) ? value : [value];\n return [...new Set(values.map((path) => resolve(cwd, path)))];\n}\n\n","import { readFileSync } from \"node:fs\";\n\nconst FALLBACK_VERSION = \"0.1.0\";\n\nexport const TRAWLY_VERSION = readPackageVersion();\n\nfunction readPackageVersion(): string {\n try {\n const packageJson = JSON.parse(\n readFileSync(new URL(\"../package.json\", import.meta.url), \"utf8\"),\n ) as { version?: unknown };\n return typeof packageJson.version === \"string\"\n ? packageJson.version\n : FALLBACK_VERSION;\n } catch {\n return FALLBACK_VERSION;\n }\n}\n"],"mappings":"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","names":["existsSync","statSync","dirname","resolve","join","existsSync","readFileSync","resolve","isRecord","readFileSync","join","readFileSync","join","basename","readFileSync","resolve","readFileSync","resolve","existsSync","readFileSync","dirname","join","resolve","readFileSync","lineOf","registryFromResolved","readFileSync","resolve","parseYaml","resolve","readFileSync","isRecord","lineOf","registryFromResolved","parseYaml","at","registryFromResolved","lineOf","isRecord","basename","readFileSync","basename","resolve","isRecord","lineOf","retryAfterMs","resolve","REQUEST_TIMEOUT_MS","mapWithConcurrency","retryAfterMs","resolve","dirname","join","existsSync","statSync","existsSync","readdirSync","readFileSync","join","relative","resolve","PLACEHOLDER_RE","existsSync","writeFileSync","resolve","resolve","existsSync","writeFileSync","existsSync","join","resolve","resolve","normalizePaths","detectLockfiles","join","existsSync","readFileSync"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "trawly",
3
- "version": "0.0.1",
4
- "description": "Dependency sanity scanner for npm projects. Scans installed package versions against OSV and reports known vulnerabilities.",
3
+ "version": "0.1.1",
4
+ "description": "Dependency risk gate for JavaScript projects: OSV advisories, SBOM scans, baselines, install blocking, and supply-chain risk signals.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
7
7
  "engines": {
@@ -28,8 +28,12 @@
28
28
  "build": "tsup",
29
29
  "dev": "tsup --watch",
30
30
  "test": "vitest run",
31
+ "test:corpus": "vitest run tests/corpus-edge-cases.test.ts tests/property-generated.test.ts",
32
+ "test:differential": "TRAWLY_DIFFERENTIAL=1 vitest run tests/differential-package-managers.test.ts",
33
+ "test:stress": "TRAWLY_STRESS=1 vitest run tests/stress-reliability.test.ts",
31
34
  "test:watch": "vitest",
32
35
  "typecheck": "tsc --noEmit",
36
+ "typecheck:test": "tsc --noEmit -p tsconfig.test.json",
33
37
  "scan": "node --import tsx/esm src/cli.ts scan",
34
38
  "prepublishOnly": "npm run build"
35
39
  },
@@ -44,8 +48,13 @@
44
48
  "audit"
45
49
  ],
46
50
  "dependencies": {
51
+ "@yarnpkg/lockfile": "^1.1.0",
47
52
  "commander": "^12.1.0",
53
+ "fast-xml-parser": "^5.7.3",
48
54
  "kleur": "^4.1.5",
55
+ "packageurl-js": "^2.0.1",
56
+ "smol-toml": "^1.6.1",
57
+ "yaml": "^2.8.4",
49
58
  "zod": "^3.23.8"
50
59
  },
51
60
  "devDependencies": {