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
82 lines
4.3 KiB
Markdown
82 lines
4.3 KiB
Markdown
# 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 from `package.json`.
|
|
- Enriches output with deterministic scope signals (`dev`, `optional`, `peer`, `scopeUnknown`), patch attribution, and bounded sha256 evidence.
|
|
|
|
## Inputs and precedence
|
|
1. **Installed inventory** (`node_modules/` present): traverse installed packages and emit components from installed `package.json` (uses `bun.lock` for resolved/integrity + scope enrichment when present).
|
|
2. **Lockfile-only** (`bun.lock` present, no install): parse `bun.lock` and emit components from lock entries.
|
|
3. **Declared-only fallback** (project markers present but no `bun.lock`/install): emit explicit-key components from `package.json` dependency sections.
|
|
4. **Unsupported** (`bun.lockb` only): emit a remediation record explaining how to produce `bun.lock`.
|
|
|
|
## Project discovery (including container roots)
|
|
The analyzer discovers Bun project roots under:
|
|
- The analysis root (`context.RootPath`)
|
|
- Common OCI unpack layouts: `layers/*`, `.layers/*`, and `layer*` (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 `version` is 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.json` only when size is within 1 MiB; when skipped, metadata includes:
|
|
- `packageJson.hashSkipped=true`
|
|
- `packageJson.hashSkipReason=<missing|unauthorized|io|size>...`
|
|
|
|
### Lockfile entry evidence
|
|
- Locator format: `<lockfileRelativePath>:packages[<name>@<version>]`
|
|
- Example: `bun.lock:packages[lodash@4.17.21]`
|
|
- Hashing: sha256 is computed for `bun.lock` only when size is within 50 MiB; when skipped, metadata includes:
|
|
- `bunLock.hashSkipped=true`
|
|
- `bunLock.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=true` only when dev reachability is provable.
|
|
- `optional=true` and `peer=true` are 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=true`
|
|
- `dev=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 `patchedDependencies` and patch directories.
|
|
- Patch keys preserve version specificity (`name@version`) and patch paths are emitted as deterministic project-relative paths.
|
|
- Patch matching precedence: `name@version` first; 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 `bun` and 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`
|
|
|