Some checks failed
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
4.3 KiB
4.3 KiB
Bun Analyzer (Scanner)
What it does
- Inventories npm-ecosystem dependencies from Bun-managed projects without executing
bun. - Supports installed inventory (
node_modules/**/package.json), lockfile-only inventory (bun.lock), and declared-only fallback frompackage.json. - Enriches output with deterministic scope signals (
dev,optional,peer,scopeUnknown), patch attribution, and bounded sha256 evidence.
Inputs and precedence
- Installed inventory (
node_modules/present): traverse installed packages and emit components from installedpackage.json(usesbun.lockfor resolved/integrity + scope enrichment when present). - Lockfile-only (
bun.lockpresent, no install): parsebun.lockand emit components from lock entries. - Declared-only fallback (project markers present but no
bun.lock/install): emit explicit-key components frompackage.jsondependency sections. - Unsupported (
bun.lockbonly): emit a remediation record explaining how to producebun.lock.
Project discovery (including container roots)
The analyzer discovers Bun project roots under:
- The analysis root (
context.RootPath) - Common OCI unpack layouts:
layers/*,.layers/*, andlayer*(direct children)
Discovery is bounded and deterministic:
- Sorted directory enumeration
- Explicit depth and root caps
- Never recurses into
node_modules/
Identity rules (PURL vs explicit key)
Concrete versions emit a PURL:
purl = pkg:npm/<name>@<version>- Concrete versions follow the Node-style guardrail (no ranges/tags/paths embedded as a "version"; see
Internal/BunVersionSpec.IsConcreteNpmVersion).
Non-concrete versions emit an explicit key:
componentKey = explicit::<analyzerId>::npm::<name>::sha256:<digest>purl = null,version = null- Used for declared-only dependencies and any lock/installed records whose
versionis not concrete (e.g.,workspace:*,link:../...,file:../...).
Explicit-key digest input (canonical, UTF-8):
npm\n<name>\n<spec>\n<originLocator>
Generated via LanguageExplicitKey.Create(...) and aligned with docs/modules/scanner/language-analyzers-contract.md.
Evidence and locators
All evidence locators are relative and use / separators.
File evidence
- Installed packages:
node_modules/.../package.json - Hashing: sha256 is computed for
package.jsononly when size is within 1 MiB; when skipped, metadata includes:packageJson.hashSkipped=truepackageJson.hashSkipReason=<missing|unauthorized|io|size>...
Lockfile entry evidence
- Locator format:
<lockfileRelativePath>:packages[<name>@<version>]- Example:
bun.lock:packages[lodash@4.17.21]
- Example:
- Hashing: sha256 is computed for
bun.lockonly when size is within 50 MiB; when skipped, metadata includes:bunLock.hashSkipped=truebunLock.hashSkipReason=<missing|unauthorized|io|size>...
Scope semantics (dev/optional/peer)
Scope is derived deterministically from the bun.lock dependency graph rooted at package.json declarations:
dev=trueonly when dev reachability is provable.optional=trueandpeer=trueare preserved when present in lock data or derived from declared scopes.- If the graph cannot disambiguate (multiple candidates/specifier mismatch), the record is marked:
scopeUnknown=truedev=false(do not guess)
includeDev=false filters only packages proven to be dev-only; unknown-scope packages are kept but marked scopeUnknown=true.
Patches and workspaces
- Workspace patterns come from root
package.json(workspaces). - Patch attribution supports Bun's
patchedDependenciesand patch directories. - Patch keys preserve version specificity (
name@version) and patch paths are emitted as deterministic project-relative paths. - Patch matching precedence:
name@versionfirst; then name-only only when unambiguous.
Known limitations
bun.lockb(binary lockfile) is not parsed; a remediation record is emitted instead.- The analyzer does not execute
bunand does not fetch registries; offline-only behavior is enforced.
References
- Sprint:
docs/implplan/SPRINT_0407_0001_0001_scanner_bun_detection_gaps.md - Cross-analyzer contract:
docs/modules/scanner/language-analyzers-contract.md - Design notes:
docs/modules/scanner/prep/bun-analyzer-design.md - Gotchas:
docs/modules/scanner/bun-analyzer-gotchas.md