From 85035646d16d8a843d621be70cca70c5db4141a4 Mon Sep 17 00:00:00 2001 From: Zack Whitson Date: Thu, 6 Aug 2026 22:17:52 -0500 Subject: [PATCH 1/3] Release CodeTruss CLI v0.2.30 Bring the public mirror up to the shipped release. The mirror had been sitting at 0.2.24 while the website served 0.2.30. Source is mirrored from the 0.2.30 release commit, not from in-progress work. `pnpm release:artifact` rebuilds the bundle to the exact published digest 9c97f573aa7e7a052fe8d4c578efda6a8d43f2bcfec9a74ab7d2fdf6b53eccdc, and `pnpm release:verify` confirms it byte-for-byte against the immutable website archive now recorded in release-reference.json. - Mirror packages/cli and packages/analyzer-engine at 0.2.30, including the 0.2.25 through 0.2.30 changelog entries. - Add the immutable 0.2.30 archive, checksum, and SBOM to public/downloads and repoint the latest.* aliases and manifest. - Update release-reference.json to the published archive, SBOM, and bundle digests. README rewrite, corrected against the shipped 0.2.30 binary: - Lead with the current positioning, the deterministic first-pass verification gate for AI-written code. Receipt stays the mechanism noun. - Drop the stale "reports hosted Health scores as N/A" line. Since 0.2.29 the receipt carries a "What did not run" section, and the README now shows it from a real run and states plainly that a local run never performs injection or taint analysis. - Document `verify-policy trust-key`, which the CLI accepts but leaves out of its own --help banner. - Lead the install section with the channels that actually serve 0.2.30, and say that the npm registry package still trails at 0.2.24 because publication is a separate manual dispatch. - Add the benchmark result and link, and the free-forever CLI pledge with the hosted pricing line. Co-Authored-By: Claude Opus 5 --- CHANGELOG.md | 104 ++++++- README.md | 285 +++++++++++------- docs/RELEASE.md | 8 +- packages/analyzer-engine/package.json | 1 - packages/analyzer-engine/src/coverage.ts | 83 ++++- packages/analyzer-engine/src/dead-code.ts | 38 ++- packages/analyzer-engine/src/detect.ts | 41 ++- packages/analyzer-engine/src/env-vars.ts | 20 +- packages/analyzer-engine/src/indexer.ts | 2 + packages/analyzer-engine/src/runner.ts | 12 +- packages/analyzer-engine/src/secrets.ts | 100 +++++- packages/analyzer-engine/src/structure.ts | 18 +- packages/analyzer-engine/src/types.ts | 23 +- packages/cli/CHANGELOG.md | 96 ++++++ packages/cli/package.json | 2 +- packages/cli/scripts/build-release.mjs | 116 ++++--- .../cli/scripts/test-release-verifier.mjs | 107 +++---- packages/cli/scripts/verify-release.mjs | 103 +++---- packages/cli/src/analysis.ts | 69 ++++- packages/cli/src/cli.ts | 43 ++- packages/cli/src/config.ts | 72 ++++- packages/cli/src/hook-runtime.ts | 78 ++++- packages/cli/src/receipt.ts | 92 +++++- packages/cli/src/setup.ts | 23 +- packages/cli/src/signing.ts | 20 +- packages/cli/src/types.ts | 8 +- packages/cli/test/analysis-profile.test.ts | 30 ++ packages/cli/test/command-e2e.test.ts | 32 ++ packages/cli/test/config.test.ts | 52 ++++ packages/cli/test/hooks.test.ts | 66 +++- packages/cli/test/policy-fingerprint.test.ts | 2 +- packages/cli/test/policy-verdict.test.ts | 59 +++- packages/cli/test/receipt.test.ts | 55 +++- .../codetruss-cli-0.2.30.sbom.cdx.json | 170 +++++++++++ public/downloads/codetruss-cli-0.2.30.tgz | Bin 0 -> 778830 bytes .../downloads/codetruss-cli-0.2.30.tgz.sha256 | 1 + public/downloads/codetruss-cli-latest.json | 14 +- .../codetruss-cli-latest.sbom.cdx.json | 10 +- public/downloads/codetruss-cli-latest.tgz | Bin 758350 -> 778830 bytes .../downloads/codetruss-cli-latest.tgz.sha256 | 2 +- release-reference.json | 10 +- 41 files changed, 1671 insertions(+), 396 deletions(-) create mode 100644 public/downloads/codetruss-cli-0.2.30.sbom.cdx.json create mode 100644 public/downloads/codetruss-cli-0.2.30.tgz create mode 100644 public/downloads/codetruss-cli-0.2.30.tgz.sha256 diff --git a/CHANGELOG.md b/CHANGELOG.md index 49547e5..b882ccf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,12 @@ CodeTruss CLI follows semantic versioning. Release artifacts and their SHA-256 checksums are published at . -The current public release is [v0.2.24 on GitHub](https://github.com/DeliriumPulse/codetruss-cli/releases/tag/v0.2.24) -and [`@codetruss/cli@0.2.24` on npm](https://www.npmjs.com/package/@codetruss/cli/v/0.2.24). +The current public release is [v0.2.30 on GitHub](https://github.com/DeliriumPulse/codetruss-cli/releases/tag/v0.2.30), +distributed from . +The npm `latest` tag is still +[`@codetruss/cli@0.2.24`](https://www.npmjs.com/package/@codetruss/cli/v/0.2.24): +npm publication is a separate, manually dispatched step, so npm can trail the +website and the GitHub release. Entries explicitly marked `(unpublished)` are retained release candidates that were superseded before distribution. @@ -12,6 +16,102 @@ were superseded before distribution. No unreleased changes. +## 0.2.30 — 2026-08-06 + +- Publish the 0.2.25 through 0.2.29 release history, which shipped without + changelog entries. No CLI behaviour changed. `CHANGELOG.md` is one of the eight + published files and is byte-compared against the immutable release archive, so + documenting those releases requires a new version rather than an edit in place. + +## 0.2.29 — 2026-08-06 + +- Say plainly that a local run never checks for injection. The coverage + analyzer had stayed silent for TypeScript, JavaScript, and Python because the + SAST engine supports those languages — a fact about the engine, not about a + run that never executes it. Analyzers now receive the non-registry passes in + effect, defaulting to none, and a repository holding at least 300 lines that + pass would have covered gets one INFO finding naming the classes nobody + looked for: SQL injection, command injection, code injection, path traversal, + SSRF, open redirect, XSS, and insecure deserialization. +- Replace the receipt's "Hosted Health scores: N/A" footnote with a "What did + not run" section naming SAST, the hosted symbol graph, the scores, and — when + no model read the diff — the optional LLM review as detection gaps, and + stating that a PASS verdict is not a claim the change is secure. +- Keep receipts written by 0.2.28 and earlier verifiable. No signed field + changed, only the rendering, so each superseded wording stays byte-reproducible + for verification. + +## 0.2.28 — 2026-08-06 + +- Let `codetruss setup --yes` finish protecting an ordinary repository instead + of exiting 3 with a policy file and no guardrail. Conventional source roots + that exist on disk are now adopted unattended, never a repository-wide glob, + and the adopted list is printed so the decision stays auditable. With nothing + detectable the run still stops and asks. +- Leave auto-detected verification commands out of the policy on an unattended + run instead of aborting, and print how to enable them. A recorded but + untrusted command list makes every later review exit 3 with no receipt, so the + previous behaviour produced a repository that was configured, hooked, and + permanently blocked. Withholding applies only when hooks are being installed; + `--hooks none` still records the commands for inspect-then-trust. + +## 0.2.27 — 2026-08-06 + +- Deduplicate the PostToolUse fast scope check per turn. The first notice for a + path arrives exactly as before, repeats are silent, and a new path still + speaks immediately; a turn that touched one out-of-scope file a dozen times + previously emitted a dozen identical warnings. +- Keep that deduplication fail-soft: when session or turn state cannot be read + or written, every warning is emitted as it was before. + +## 0.2.26 — 2026-08-06 + +- Keep the receipt's Task line readable when an agent harness delivers a machine + event — a background-task notification or a tool result — on the same prompt + channel as human instructions. A human prompt is preserved exactly as written; + a structured event is reduced to its event tag and summary. Derivation stays + deterministic, so prompt-time turn binding is unaffected. +- Report credential-shaped placeholders at INFO instead of skipping them in + silence, so a deliberate skip is not mistaken for a scanner that detects + nothing. Only values that announce themselves as fake qualify; runtime + credential references such as `process.env`, `{{...}}`, and `ENV[]` stay + silent, because that is how a credential is supposed to be written. + +## 0.2.25 — 2026-08-06 + +- Stop an immaterial index-coverage gap from failing a receipt. When the index + measurably covered at least 95% of its analyzable input, the remaining + limitations — an oversized lockfile, an unreadable file — are reported as + review-level context instead of incomplete evidence. Larger losses, and a + truncated file walk, still fail closed. +- Accept a set of pinned signers. `signing.publicKeys` holds one key per + developer, `codetruss verify-policy trust-key` appends the local key to it, + and receipt verification accepts any trusted signer, so a teammate signs as + themselves instead of sharing a private key and destroying attribution. +- Report the verification commands `codetruss init` detected and state that they + are not trusted until approved. Without that notice the next `review` exits 3 + with no receipt at all. +- Stop reporting test and seed credentials as HIGH: Go, Python, and Ruby test + file conventions are recognized, and a database seed script gets its own + MEDIUM finding about the seed path reaching a production database rather than + a rotate-immediately instruction. +- Stop reporting prose as a credential. Values carrying internal whitespace + under a credential-shaped key (validation messages, translations, UI labels), + SCREAMING_SNAKE enum members, `{{...}}` templates, and environment reads are + no longer leaks. +- Exclude minified and bundled assets by mean line width rather than filename, + and report the excluded volume in KB as well as LOC, since packed output + understates its size in lines. Excluding a file no longer manufactures dead + code for the files it imports. +- Recognize more convention-loaded entry points as reachable: Pages Router + routes, Storybook stories, tooling dotfiles, and `package.json` script targets + are no longer reported as orphaned. +- Suppress the duplicate "no `.env.example`" nudge when a committed runtime + `.env` already produces the structure analyzer's version of that finding, and + reword the per-language security caveat from "surface-only" to "coverage is + partial", since pattern and dataflow rules do apply beyond TypeScript, + JavaScript, and Python. + ## 0.2.24 — 2026-07-15 - Ship the guided setup, local evidence privacy, invocation provenance, diff --git a/README.md b/README.md index 843382e..a8e440f 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,32 @@ # CodeTruss CLI -Review tools ask whether code looks wrong. CodeTruss proves whether the agent -stayed inside its task contract and whether the exact final Git state passed -your checks. +The deterministic first-pass verification gate for AI-written code. -CodeTruss is a local-first guardrail for coding agents. It captures an exact -before/after Git evidence pair, checks task scope and sensitive surfaces, runs -the shared CodeTruss analyzers and repository verification commands, then writes -a signed `PASS`, `REVIEW_REQUIRED`, or `FAILED` receipt before a pull request. +An agent finishes a change. Something has to look at it before a human does. +CodeTruss Boundary is that first pass: it captures an exact before/after Git +evidence pair, checks the change against the task contract you declared, runs 13 +deterministic analyzers and your own project checks, then signs a `PASS`, +`REVIEW_REQUIRED`, or `FAILED` receipt you can re-verify later. -## Quickstart +Routine changes clear the checks and pass. Material changes escalate for human +sign-off. Every verdict leaves a receipt that records the reasons, and the +receipt also names what never ran. -Install from npm with Node.js 20.9 or newer: +It is local-first. Nothing is uploaded unless you explicitly run `codetruss sync`. -```bash -npm install --global @codetruss/cli -codetruss setup -``` +## Install -Or run one review without a global install: +Node.js 20.9 or newer. macOS or Linux: ```bash -npx --yes @codetruss/cli review --task "Review my current agent changes" +curl -fsSL https://codetruss.com/install.sh | sh +codetruss setup ``` -macOS or Linux shell installer: +Homebrew on macOS: ```bash -curl -fsSL https://codetruss.com/install.sh | sh -codetruss setup +brew install DeliriumPulse/codetruss/codetruss ``` Windows PowerShell: @@ -38,79 +36,106 @@ irm https://codetruss.com/install.ps1 | iex codetruss setup ``` -Homebrew on macOS: +The shell installers resolve the versioned artifact named in +[`codetruss-cli-latest.json`](https://codetruss.com/downloads/codetruss-cli-latest.json) +and verify its published SHA-256 digest before installing. + +To pin an exact version, install the immutable archive directly: ```bash -brew install DeliriumPulse/codetruss/codetruss +npm install --global --ignore-scripts --no-audit --no-fund \ + https://codetruss.com/downloads/codetruss-cli-0.2.30.tgz ``` -## Claude Code, Codex, and Agent Skills +The `@codetruss/cli` package on the npm registry is published as a separate, +manually dispatched step and currently trails the website at `0.2.24`. Use the +installers or the versioned archive above for the current release. + +## First run + +```bash +codetruss review --task "Review my current agent changes" +codetruss verify latest +``` + +That first receipt needs no account and no configuration. Without an allow +policy every changed file is deliberately unexpected, so the review exits `1` +with `REVIEW_REQUIRED` and still writes valid signed evidence. + +Run `codetruss setup` once at the Git root to make it automatic. It proposes +conventional source roots rather than repository-wide access, shows any detected +verification commands with their exact trust fingerprint before you trust them, +installs the hooks you pick, and runs diagnostics. It uploads nothing. Codex asks +for one final project-hook approval in `/hooks`. + +To wrap an agent so the task and both Git states are captured together: + +```bash +codetruss run --task "Fix auth" --allow "src/auth/**" --verify "pnpm test" -- codex exec "Fix auth" +``` -The official open integration wrappers teach coding agents to configure and -operate the separately installed local CLI. They do not contain another -analyzer, add an MCP server, or create a new upload path. +## Claude Code, Codex, and Agent Skills -Claude Code: +The open integration wrappers teach coding agents to configure and operate the +separately installed CLI. They contain no second analyzer, add no MCP server, and +create no new upload path. ```bash claude plugin marketplace add DeliriumPulse/codetruss-plugins claude plugin install codetruss@codetruss ``` -Codex: - ```bash codex plugin marketplace add DeliriumPulse/codetruss-plugins codex plugin add codetruss@codetruss ``` -Agent Skills clients can install the same canonical skill for both Claude Code -and Codex from the public wrapper repository: +Agent Skills clients can install the same canonical skill for both agents: ```bash npx --yes skills add DeliriumPulse/codetruss-plugins \ --skill codetruss --agent claude-code codex -y ``` -See the [live skills.sh listing](https://skills.sh/deliriumpulse/codetruss-plugins/codetruss) +See the [skills.sh listing](https://skills.sh/deliriumpulse/codetruss-plugins/codetruss) or [DeliriumPulse/codetruss-plugins](https://github.com/DeliriumPulse/codetruss-plugins) -for the MIT-licensed manifests, skill instructions, privacy guardrails, and -marketplace source. - -Run `codetruss setup` once at the Git root. It proposes conventional source -roots without defaulting to repository-wide access, shows detected verification -commands and their exact trust fingerprint, installs the hooks you select, and -runs diagnostics. It uploads nothing. Codex asks for one final project-hook -approval in `/hooks`. +for the MIT-licensed manifests, skill instructions, and marketplace source. -To review an existing change before configuring automation: +## Commands -```bash -codetruss review --task "Review my current agent changes" -codetruss verify latest ``` - -That first receipt needs no account or configuration. Without an allow policy, -changed files are deliberately unexpected, so the review exits `1` with -`REVIEW_REQUIRED` and still writes valid signed evidence. - -Wrap an agent command when you want the task and exact before/after Git states -captured together: - -```bash -codetruss run --task "Fix auth" --allow "src/auth/**" --verify "pnpm test" -- codex exec "Fix auth" +codetruss run --task "..." [--allow GLOB] [--deny GLOB] [--verify CMD] [--no-verify] + [--llm] [--provider anthropic|openai|claude] -- +codetruss review [--staged] --task "..." [--allow GLOB] [--deny GLOB] [--verify CMD] + [--no-verify] [--llm] [--provider anthropic|openai|claude] +codetruss report [id|latest] [--json] +codetruss list [--json] +codetruss metrics [--json] +codetruss setup [--allow GLOB] [--deny GLOB] [--hooks all|pre-commit|claude|codex|none] + [--trust-verify] [--yes] +codetruss init [--allow GLOB] [--deny GLOB] [--force] +codetruss verify [id|latest] +codetruss sync [id|latest] [--dry-run] +codetruss auth login|status|logout +codetruss verify-policy [status|trust|trust-key|revoke] +codetruss hooks install|status|doctor|uninstall [pre-commit|claude|codex|all] ``` -Manual hook controls remain available through `codetruss hooks install`, -`status`, `doctor`, and `uninstall`. +`verify-policy status`, `trust`, and `revoke` govern whether the repository's +detected verification commands are trusted to run. `verify-policy trust-key` +is separate: it appends your local signing key to `signing.publicKeys` so a +teammate can sign receipts as themselves instead of sharing a private key. +Commit `.codetruss.yml` afterwards so the rest of the team inherits the change. +It is accepted by the CLI but omitted from the built-in `--help` banner in +0.2.30. ## Fail-closed policy -CodeTruss cannot return `PASS` until the approved scope is explicit. Guided -setup requires at least one useful allow glob; lower-level `codetruss init` -intentionally starts empty unless `--allow` is supplied. Deny rules win over -allow rules, and sensitive surfaces such as CI, infrastructure, migrations, -secrets, dependencies, and lockfiles are flagged independently of scope. +CodeTruss cannot return `PASS` until the approved scope is explicit. Guided setup +requires at least one useful allow glob. Lower-level `codetruss init` +intentionally starts empty unless `--allow` is supplied. Deny rules beat allow +rules, and sensitive surfaces such as CI, infrastructure, migrations, secrets, +dependencies, and lockfiles are flagged independently of scope. ```yaml # .codetruss.yml @@ -130,8 +155,8 @@ llm: maxDiffBytes: 200000 ``` -Command-line `--allow`, `--deny`, and `--verify` values can supply the policy for -one run. Repository configuration cannot redirect authenticated sync traffic; +Command-line `--allow`, `--deny`, and `--verify` supply the policy for a single +run. Repository configuration cannot redirect authenticated sync traffic; production sync is fixed to `https://codetruss.com`. ## Verdicts and exit codes @@ -139,76 +164,107 @@ production sync is fixed to `https://codetruss.com`. | Verdict | Exit | Meaning | |---|---:|---| | `PASS` | 0 | No blocking or review signal was found; any configured verification commands passed. | -| `REVIEW_REQUIRED` | 1 | Scope drift, a denied or sensitive surface, dependency changes, uncertain attribution, a medium-or-higher finding, or optional local LLM review needs human judgment. | +| `REVIEW_REQUIRED` | 1 | Scope drift, a denied or sensitive surface, dependency changes, uncertain attribution, a medium-or-higher finding, or optional LLM review needs human judgment. | | `FAILED` | 2 | The agent or a verification command failed, evidence is incomplete, or a high/critical security or dependency finding blocks the result. | -Usage and environment errors exit `3`. A receipt records every explicit reason; -the verdict is not a confidence score. +Usage and environment errors exit `3`. A receipt records every explicit reason. +The verdict is not a confidence score. -## Illustrative receipt +## What a receipt says, including what it did not check -The shortened IDs and hashes below are illustrative sample data, not a customer -result or validation claim. +Receipts are written as Markdown and JSON next to hashed patch evidence, and can +be rechecked later with `codetruss verify latest`. Every receipt states the +detection gaps in its own body, so a `PASS` is never mistaken for a security +clearance. Abridged from a real 0.2.30 run: ```markdown # CodeTruss receipt — REVIEW_REQUIRED -- Task: Fix auth callback validation -- Evidence trees: `a1b2c3…` → `d4e5f6…` -- Policy SHA-256: `91f0ab…` +- **Task:** Fix auth callback validation +- **Evidence trees:** `f8c28a26…` → `52fdebbe…` +- **Policy SHA-256:** `368f88df…` ## Verdict: REVIEW_REQUIRED -- 1 file changed outside approved scope: infra/main.tf +- 1 file(s) changed outside approved scope: infra/main.tf - sensitive surfaces changed: infra/main.tf (iac) -## Verification +## Analysis profile + +Profile: `local-registry-v1`. + +The 13 deterministic registry analyzers ran locally on this machine. -- `pnpm test` — exit 0 +### What did not run -Diff evidence: complete, SHA-256 `7bc21e…`. +- **Security static analysis (SAST).** No injection or taint analysis was + performed. SQL injection, command injection, code injection, path traversal, + SSRF, open redirect, XSS and insecure deserialization were never checked. +- **Hosted symbol graph.** No cross-file call or data-flow graph was built. +- **Hosted Health scores.** Not calculated, reported as **N/A**. + +A PASS verdict means the passes listed above never ran and the passes that did +run found nothing new. It is not a statement that this change is secure. ``` -Receipts are written as Markdown and JSON alongside the hashed patch evidence -and can be checked later with `codetruss verify latest`. +SAST and the symbol graph are hosted-only. A local run never performs injection +or taint analysis. + +## Measured accuracy + +On a nine-case adversarial corpus of AI-agent bug classes, the analyzers caught +five at the exact file and line, with zero false positives across eight +repositories. The four misses are named, each with the reason it needs dataflow +analysis the local passes do not perform. + +Method, per-case reasoning, and the misses are published at +[codetruss.com/benchmark](https://codetruss.com/benchmark). ## Privacy -Deterministic `run`, `review`, `report`, `list`, `metrics`, `init`, `setup`, -`verify`, `verify-policy`, and hook checks run locally without contacting -CodeTruss. Installing through npm fetches the package from the npm registry; the -shell installers fetch release metadata and package bytes from CodeTruss. -Optional review with `--llm --provider anthropic|openai|claude` sends the -bounded task and diff directly to the -selected provider using the developer's API key or authenticated local Claude -Code. CodeTruss receives no receipt unless the developer explicitly runs -`codetruss sync`; there is no background telemetry or synchronization. - -`codetruss auth login` contacts CodeTruss device/session endpoints but uploads -no source, patch, or receipt. `auth status` contacts the session endpoint to -verify the saved credential. `auth logout` revokes the server-side credential -before deleting the local copy; if revocation fails, the local copy is retained -for retry. Neither command sends source, patches, or receipts. Local receipts -identify the 13-pass `local-registry-v1` analyzer profile and report hosted -Health scores as N/A; graph and SAST analysis remain part of the hosted full -audit. +`run`, `review`, `report`, `list`, `metrics`, `init`, `setup`, `verify`, +`verify-policy`, and the hook checks are deterministic and run locally without +contacting CodeTruss. Installing fetches release metadata and package bytes from +CodeTruss or npm. + +Optional `--llm --provider anthropic|openai|claude` sends the bounded task and +diff straight to that provider using your own API key or authenticated local +Claude Code. It never crosses CodeTruss servers, and it is force-disabled under +agent hooks so hook receipts stay deterministic. The receipt discloses reviewed +versus total diff bytes, and truncation prevents `PASS`. + +`codetruss sync` is the only command that uploads a receipt, and it strips the +patch, absolute local path, agent command, raw verification commands and output, +and signing secrets. There is no background telemetry. `auth login`, `status`, +and `logout` contact CodeTruss session endpoints only and send no source, patch, +or receipt. Agent-turn evidence is held in a private per-turn Git object store under Git -metadata, is unavailable to ordinary repository Git commands, and is removed -after the receipt is complete. Synced receipts omit the patch, absolute local -path, agent command, raw verification commands/output, and signing secrets. +metadata, is invisible to ordinary repository Git commands, and is removed once +the receipt is complete. `.codetruss.yml` is reviewable repository policy and may be committed. -`.codetruss/` contains local receipts, patches, signatures, snapshots, and -generated hook runners. CodeTruss adds that evidence root to the -repository-local Git exclude and refuses future operations if evidence becomes -tracked or is routed through an unsafe path. +`.codetruss/` holds local receipts, patches, signatures, snapshots, and generated +hook runners. CodeTruss adds that evidence root to the repository-local Git +exclude and refuses to operate if evidence becomes tracked or is routed through +an unsafe path. + +## Pricing + +The CLI is free forever. Installing it, running every command above, and +producing signed receipts cost nothing and always will. There is no seat count, +no trial clock, and no feature that stops working once you depend on it. + +The paid line sits at the network boundary: local stays free, hosted is billed. +Hosted plans start at $19 per seat, with a $9 receipt-history tier, $15 per seat +for teams, and $249 for agencies. See +[codetruss.com/pricing](https://codetruss.com/pricing). ## Source and development -This repository contains the CLI and its DB-free analyzer engine. The published -npm package and GitHub release archive contain the same bundled executable with -no runtime npm dependencies. +This repository mirrors the released CLI and its DB-free analyzer engine. The +published archive contains one bundled executable with no runtime npm +dependencies. ```bash corepack enable @@ -217,22 +273,21 @@ pnpm install --frozen-lockfile pnpm validate ``` -`pnpm validate` typechecks, builds the deterministic release, runs the source -and adversarial release tests, verifies the exact website reference, and -exercises a clean global install. +`pnpm validate` typechecks, builds the deterministic release, runs the source and +adversarial release tests, verifies the result byte-for-byte against the exact +published website artifact recorded in `release-reference.json`, and exercises a +clean global install. -Release output is written to `release/`. Verify a GitHub release attestation -with: +Verify a downloaded release yourself: ```bash -gh attestation verify codetruss-cli-VERSION.tgz --repo DeliriumPulse/codetruss-cli +gh attestation verify codetruss-cli-0.2.30.tgz --repo DeliriumPulse/codetruss-cli +shasum -a 256 -c codetruss-cli-0.2.30.tgz.sha256 ``` -Tag-driven GitHub releases and attestations do not depend on npm credentials. -The public `@codetruss/cli` package is published by an explicitly confirmed -workflow that sends the already-attested release bytes to npm. Maintainers -should follow [docs/RELEASE.md](docs/RELEASE.md) for the trusted-publishing -controls. +Maintainers should follow [docs/RELEASE.md](docs/RELEASE.md). Tag-driven GitHub +releases and attestations do not depend on npm credentials; npm publication is a +separate, explicitly confirmed workflow that sends the already-attested bytes. ## License and support diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 5786a1a..9e98ff8 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -10,8 +10,8 @@ account, npm token, package access, or npm environment approval. Update `release-reference.json` from the immutable website candidate. The verifier rejects any archive, SBOM, or executable digest that differs from that checked-in reference. -2. Create and push the matching annotated tag, for example `v0.2.24` for package - version `0.2.24`. +2. Create and push the matching annotated tag, for example `v0.2.30` for package + version `0.2.30`. 3. `.github/workflows/release.yml` installs the locked dependency graph, runs typechecking and tests, builds the package, verifies a clean global install, creates GitHub build-provenance and SBOM attestations, and finally creates the @@ -19,8 +19,8 @@ account, npm token, package access, or npm environment approval. 4. Verify the downloaded archive independently: ```bash - gh attestation verify codetruss-cli-0.2.24.tgz --repo DeliriumPulse/codetruss-cli - shasum -a 256 -c codetruss-cli-0.2.24.tgz.sha256 + gh attestation verify codetruss-cli-0.2.30.tgz --repo DeliriumPulse/codetruss-cli + shasum -a 256 -c codetruss-cli-0.2.30.tgz.sha256 ``` The release workflow intentionally has no npm environment, npm credentials, or diff --git a/packages/analyzer-engine/package.json b/packages/analyzer-engine/package.json index 3e5faf5..66b32a7 100644 --- a/packages/analyzer-engine/package.json +++ b/packages/analyzer-engine/package.json @@ -2,7 +2,6 @@ "name": "@codetruss/analyzer-engine", "version": "0.1.0", "private": true, - "license": "SEE LICENSE IN ../../LICENSE", "type": "module", "main": "./src/index.ts", "types": "./src/index.ts", diff --git a/packages/analyzer-engine/src/coverage.ts b/packages/analyzer-engine/src/coverage.ts index 8896d52..4dcb99f 100644 --- a/packages/analyzer-engine/src/coverage.ts +++ b/packages/analyzer-engine/src/coverage.ts @@ -1,5 +1,6 @@ -import type { Analyzer, AnalyzerFinding } from './types' +import type { Analyzer, AnalyzerContext, AnalyzerFinding } from './types' import type { RepoIndex } from './types' +import { REGISTRY_ONLY_ANALYSIS } from './types' import { SUPPORTED_TREESITTER_LANGS } from './support' import { SAST_COVERED_LANGUAGES } from './support' @@ -18,10 +19,18 @@ import { SAST_COVERED_LANGUAGES } from './support' * * - SECURITY (injection, untrusted-input, deserialization): a real SAST engine * (rules + taint tracking) runs for the languages it covers - * (SAST_COVERED_LANGUAGES). For those languages the security axis is EARNED — - * real vulns lower it, genuinely clean code scores high. For every other - * language we run only regex secret scanning — that is not a security review, - * so a clean security axis there means "we didn't look", not "it's safe". + * (SAST_COVERED_LANGUAGES) IN THE PROFILES THAT INCLUDE THAT PASS. For those + * languages the security axis is EARNED — real vulns lower it, genuinely + * clean code scores high. For every other language we run only regex secret + * scanning — that is not a security review, so a clean security axis there + * means "we didn't look", not "it's safe". + * + * Language support is only half of that premise. The SAST pass lives outside + * this registry, so whether it runs at all is a property of the caller + * (AnalyzerContext.sast), not of the languages present: a hosted QUICK scan + * and every local CLI run execute the registry without it. When the pass did + * not run, "TypeScript is SAST-covered" says nothing about this analysis, and + * staying silent would be the blind spot the module exists to prevent. * * Everything outside the structure set is *surface-scanned* — structure regex, * secrets, file size, docs — with no architecture, flow, or complexity @@ -160,6 +169,8 @@ export function analysisCoverage(index: RepoIndex): AnalysisCoverage { * * - Genuinely unsupported language (no extractor, no tree-sitter): the strong * "limited analysis" caveat — architecture/flow/complexity were NOT analyzed. + * - SAST pass absent from this profile while the repo has code it would have + * covered: the pass-level caveat — the injection classes were never examined. * - Tree-sitter language (structure fully analyzed, security surface-only): the * nuanced caveat — structure is real, security is secret-scanning only. */ @@ -168,7 +179,7 @@ export const coverageAnalyzer: Analyzer = { name: 'Analysis coverage', description: 'Discloses the depth of analysis per language so a clean report is not misread as a full architecture + security review.', - async run(index: RepoIndex): Promise { + async run(index: RepoIndex, context: AnalyzerContext = REGISTRY_ONLY_ANALYSIS): Promise { const coverage = analysisCoverage(index) if (coverage.structureLimited) { @@ -204,6 +215,48 @@ export const coverageAnalyzer: Analyzer = { ] } + // The SAST pass is not in this registry, so a profile can omit it entirely. + // When it did and the repo holds a meaningful amount of code that pass + // covers, silence would read as "nothing found" for classes nobody looked + // for — the exact misreading the language caveats below exist to prevent. + if (!context.sast && coverage.securityLoc >= MIN_ANALYZABLE_LOC) { + const sastLanguages = Object.entries(index.languages) + .filter(([lang]) => isSecurityDeep(lang)) + .sort((a, b) => b[1] - a[1]) + .map(([lang]) => lang) + return [ + { + category: 'SECURITY_HYGIENE', + severity: 'INFO', + title: 'Security static analysis did not run in this analysis profile', + description: + `This analysis ran the deterministic registry analyzers only. The SAST pass — the ` + + `security rule pack plus taint tracking from untrusted source to dangerous sink — is ` + + `not part of this profile, so it never examined the ${sastLanguages.join(', ')} code ` + + `here (${coverage.securityLoc} lines). The classes that pass owns were not checked at ` + + `all: SQL injection, command injection, code injection, path traversal, SSRF, open ` + + `redirect, XSS and insecure deserialization, plus the pattern rules for hardcoded ` + + `credentials, disabled TLS validation, weak hashes and ciphers, and insecure ` + + `randomness. Secret scanning, dependency advisories and every other registry pass did ` + + `run and their results stand. Read the absence of injection findings as "that analysis ` + + `did not run", not "this code is clean" — this says nothing either way about whether ` + + `the code is vulnerable.`, + suggestion: + `Do not treat this run as an injection-class security review. A hosted SECURITY or ` + + `FULL_AUDIT scan runs the SAST pass over the same code and reports what it finds.`, + impactScore: 20, + effort: 'low', + metadata: { + sastPassRan: false, + securityRatio: coverage.securityRatio, + securityLoc: coverage.securityLoc, + totalLoc: coverage.totalLoc, + sastLanguages, + }, + }, + ] + } + if (coverage.securityLimited) { const lang = coverage.primaryLanguage ?? coverage.structureOnlyLanguages[0] ?? 'this language' @@ -211,18 +264,18 @@ export const coverageAnalyzer: Analyzer = { { category: 'SECURITY_HYGIENE', severity: 'INFO', - title: `Security is surface-only for ${lang}`, + title: `Security coverage is partial for ${lang}`, description: `Structure and complexity for ${lang} are fully analyzed via AST parsing — the ` + - `architecture, call-graph and health scores reflect the real code. Security, however, ` + - `is surface-only: CodeTruss ran secret scanning (regex) over ${lang}, NOT a full ` + - `security review. CodeTruss's SAST engine (security rules + taint tracking for ` + - `injection, untrusted-input and deserialization) runs only for TypeScript, JavaScript ` + - `and Python. Read the security score as "no leaked secrets found", not "this code is ` + - `secure".`, + `architecture, call-graph and health scores reflect the real code. Security coverage ` + + `is partial, not absent: CodeTruss ran secret scanning plus the pattern and dataflow ` + + `rules that apply to ${lang}, but its untrusted-input catalog is tuned for TypeScript, ` + + `JavaScript and Python, so injection and deserialization coverage for ${lang} is ` + + `narrower than for those languages. Read the security score as "nothing found by the ` + + `checks that ran", not "this code is secure".`, suggestion: - `Treat the security score as secret-scanning coverage only for ${lang}. A manual ` + - `security review is still warranted for injection, untrusted input and deserialization.`, + `Treat the security score for ${lang} as partial coverage. A manual security review ` + + `is still warranted for injection, untrusted input and deserialization.`, impactScore: 20, effort: 'low', metadata: { diff --git a/packages/analyzer-engine/src/dead-code.ts b/packages/analyzer-engine/src/dead-code.ts index 35a8560..46e7985 100644 --- a/packages/analyzer-engine/src/dead-code.ts +++ b/packages/analyzer-engine/src/dead-code.ts @@ -29,23 +29,55 @@ export const deadCodeAnalyzer: Analyzer = { // Entry-point-ish files that are loaded by convention, not by import // (proxy.ts is Next 16's middleware — deleting it would drop the auth gate) - const CONVENTION = /(page|layout|route|loading|error|not-found|template|default|middleware|proxy|instrumentation|opengraph-image|twitter-image|icon|apple-icon|sitemap|robots|manifest|index|main|app|server|config|next-env|globals)\.[jt]sx?$|\.(d|config|test|spec)\.[cm]?[jt]s$/ + // `instrumentation-client` / `instrumentation.edge` are the suffixed + // variants Next.js and Sentry install; `*.stories.tsx` is collected by + // Storybook's glob. Neither is ever imported. + const CONVENTION = /(page|layout|route|loading|error|not-found|template|default|middleware|proxy|instrumentation|opengraph-image|twitter-image|icon|apple-icon|sitemap|robots|manifest|index|main|app|server|config|next-env|globals)\.[jt]sx?$|^instrumentation[-.][a-z]+\.[jt]sx?$|\.(stories|story)\.[jt]sx?$|\.(d|config|test|spec)\.[cm]?[jt]s$/ - const allContent = haystackFiles.map((f) => f.content!).join('\n') + // package.json script values reference runner entrypoints ("npx tsx + // lib/db/seed.ts") — raw manifest JSON satisfies the quoted-ref needle. + const manifests = index.files.filter( + (f) => f.content && /(^|\/)package\.json$/.test(f.path), + ) + const allContent = haystackFiles + .concat(manifests) + .map((f) => f.content!) + .join('\n') + + // Generated files are indexed with null content, so their imports are + // invisible to the needle below. A generated OpenAPI client importing + // `core/request.ts` would make that file look orphaned — excluding a file + // must never manufacture dead code for the files it uses. Treat everything + // under a directory that holds generated output as reachable. + const generatedDirs = Object.keys(index.generatedFiles ?? {}).map((p) => + p.includes('/') ? p.slice(0, p.lastIndexOf('/') + 1) : '', + ) + const nearGeneratedOutput = (path: string) => + generatedDirs.some((dir) => (dir === '' ? !path.includes('/') : path.startsWith(dir))) const candidateLimit = 1500 for (const file of jsFiles.slice(0, candidateLimit)) { + if (nearGeneratedOutput(file.path)) continue // CLI/tooling entry points are invoked by runners, not imports if (/(^|\/)(scripts|bin|tools)\//.test(file.path)) continue + // Next.js Pages Router: the PATH is the route, so nothing imports these. + // Anchored at the project root so a `components/pages/` folder is unaffected. + if (/^(src\/)?pages\//.test(file.path)) continue const base = file.path.split('/').pop()! if (CONVENTION.test(base)) continue + // Tooling dotfiles (.prettierrc.js, .eslintrc.js) are loaded by name. + if (base.startsWith('.')) continue const stem = base.replace(/\.[cm]?[jt]sx?$/, '') if (stem.length < 3) continue // too ambiguous to match safely // Imported anywhere? look for `/stem'`, `/stem"`, or `from './stem`-style // refs — or a bare quoted `stem.ext` (a spawn-by-string worker path built // from segments, e.g. join(cwd, 'src', 'lib', 'batch-process.ts')). + // The final alternative catches a path embedded in a longer command + // string — `"sync-stripe": "node --env-file .env sync-stripe.js"` — where + // the quote does not directly abut the path. const needle = new RegExp( - `['"\`](?:[^'"\`]*/${escapeRegExp(stem)}(\\.[cm]?[jt]sx?)?|${escapeRegExp(stem)}\\.[cm]?[jt]sx?)['"\`]`, + `['"\`](?:[^'"\`]*/${escapeRegExp(stem)}(\\.[cm]?[jt]sx?)?|${escapeRegExp(stem)}\\.[cm]?[jt]sx?)['"\`]` + + `|[\\s/]${escapeRegExp(stem)}\\.[cm]?[jt]sx?(?=[\\s'"\`])`, ) if (!needle.test(allContent)) { findings.push({ diff --git a/packages/analyzer-engine/src/detect.ts b/packages/analyzer-engine/src/detect.ts index f4c5b9d..8387a3c 100644 --- a/packages/analyzer-engine/src/detect.ts +++ b/packages/analyzer-engine/src/detect.ts @@ -49,7 +49,16 @@ export function classifyFile(path: string): string { const p = path.toLowerCase() const base = p.split('/').pop() ?? p - if (/\.(test|spec)\.[jt]sx?$/.test(base) || p.includes('__tests__/') || p.startsWith('test/') || p.startsWith('tests/')) + if ( + /\.(test|spec)\.[jt]sx?$/.test(base) || + /_(test|spec)\.(go|py|rb|exs?)$/.test(base) || + /^test_[^/]*\.py$/.test(base) || + p.includes('__tests__/') || + p.includes('__mocks__/') || + /(^|\/)tests?\//.test(p) || + // spec/ dirs are RSpec only for Ruby files — OpenAPI specs live there too + (/(^|\/)specs?\//.test(p) && base.endsWith('.rb')) + ) return 'test' if (p.includes('/migrations/') || p.includes('/migrate/')) return 'migration' if (base === 'dockerfile' || base === 'package.json' || /\.(ya?ml|toml|ini|env\.example)$/.test(base) || base.startsWith('.env')) @@ -237,6 +246,36 @@ export function looksGenerated(content: string): boolean { return /auto-?generated|@generated|generated by|do not edit/i.test(head) } +/** Below this many bytes a file produces too few findings to be worth excluding. */ +const MIN_MINIFIED_BYTES = 2_000 +/** + * AVERAGE line width separating packed build output from authored code. + * Measured across real repos: authored files top out around 62 chars/line + * (a 639-line React/Tailwind route) and 27 (a 50KB app.js), while every + * minified bundle observed started at 2,556 (jQuery 16,849; Ace 22,069). + * + * Deliberately NOT max line width: real React/Tailwind source carries the odd + * 1,000+ char className string or inline SVG path, and excluding a whole file + * for one long line silently hides authored code from every analyzer. + */ +const MINIFIED_MEAN_LINE_WIDTH = 200 + +/** + * Minified/bundled output: a build artifact or vendored library, not authored + * source. Analyzing it reports "deep nesting" and "oversized file" against code + * the team never wrote and cannot fix — on one real audit these were 41% of all + * findings. Detected by shape rather than filename so bundles that are not + * named `.min.js` are caught too. + */ +export function looksMinified(content: string): boolean { + if (content.length < MIN_MINIFIED_BYTES) return false + let newlines = 0 + for (let i = 0; i < content.length; i++) { + if (content.charCodeAt(i) === 10 /* \n */) newlines++ + } + return content.length / (newlines + 1) >= MINIFIED_MEAN_LINE_WIDTH +} + export function detectDatabases(deps: Set, paths: string[]): string[] { const dbs: string[] = [] if (deps.has('pg') || deps.has('postgres')) dbs.push('PostgreSQL') diff --git a/packages/analyzer-engine/src/env-vars.ts b/packages/analyzer-engine/src/env-vars.ts index 372e072..07e523a 100644 --- a/packages/analyzer-engine/src/env-vars.ts +++ b/packages/analyzer-engine/src/env-vars.ts @@ -1,5 +1,19 @@ import type { Analyzer, AnalyzerFinding } from './types' +/** + * A committed runtime .env file (test fixtures excluded, mirroring the + * structure analyzer's own gate). Its presence means the structure analyzer + * already owns the "missing .env.example" finding for this repository. + */ +function hasRuntimeEnvFile(index: { files: Array<{ path: string }> }): boolean { + return index.files.some( + (f) => + /\.env(\.|$)/.test(f.path.split('/').pop() ?? '') && + !/^\.env\.example$/.test(f.path) && + !/(^|\/)(tests?|__tests__|__mocks__|fixtures)\//i.test(f.path), + ) +} + /** Environment variable usage vs. documentation drift. */ export const envVarsAnalyzer: Analyzer = { id: 'env-vars', @@ -78,9 +92,13 @@ export const envVarsAnalyzer: Analyzer = { effort: 'low', metadata: { variables: undocumented.slice(0, 50) }, }) - } else if (index.repoType !== 'library') { + } else if (index.repoType !== 'library' && !hasRuntimeEnvFile(index)) { // No template at all: one LOW nudge, not a per-var wall. Libraries have // no deploy environment, so skip them entirely. + // + // Suppressed when a runtime .env file exists, because the structure + // analyzer already reports the missing template for that case — the + // reader was otherwise shown two rows demanding the same single action. findings.push({ category: 'DOCUMENTATION', severity: 'LOW', diff --git a/packages/analyzer-engine/src/indexer.ts b/packages/analyzer-engine/src/indexer.ts index 01dba44..23f8756 100644 --- a/packages/analyzer-engine/src/indexer.ts +++ b/packages/analyzer-engine/src/indexer.ts @@ -10,6 +10,7 @@ import { detectPackageManagers, detectRepoType, looksGenerated, + looksMinified, parsePyprojectDeps, parseRequirementsTxt, } from './detect' @@ -66,6 +67,7 @@ export function vendoredRoot(path: string): string | null { */ export function generatedLabel(content: string): string | null { if (looksGenerated(content)) return 'self-declared generated file' + if (looksMinified(content)) return 'minified or bundled asset' const head = content.slice(0, 4000) // Supabase `supabase gen types typescript` — large, header-less, generated. if (/\b__InternalSupabase\b/.test(head) && /\bexport type Database\b/.test(head)) { diff --git a/packages/analyzer-engine/src/runner.ts b/packages/analyzer-engine/src/runner.ts index 4f3b4fc..c169a18 100644 --- a/packages/analyzer-engine/src/runner.ts +++ b/packages/analyzer-engine/src/runner.ts @@ -1,5 +1,12 @@ import { getAnalyzers } from './registry' -import { analyzerResult, type AnalyzerFinding, type AnalyzerRunResult, type RepoIndex } from './types' +import { + analyzerResult, + REGISTRY_ONLY_ANALYSIS, + type AnalyzerContext, + type AnalyzerFinding, + type AnalyzerRunResult, + type RepoIndex, +} from './types' export interface AnalyzerPass { id: string @@ -10,12 +17,13 @@ export interface AnalyzerPass { /** Run every deterministic analyzer without allowing one failed pass to abort the suite. */ export async function runAnalyzers( index: RepoIndex, + context: AnalyzerContext = REGISTRY_ONLY_ANALYSIS, ): Promise<{ findings: AnalyzerFinding[]; passes: AnalyzerPass[] }> { const findings: AnalyzerFinding[] = [] const passes: AnalyzerPass[] = [] for (const analyzer of getAnalyzers()) { try { - const raw = analyzerResult(await analyzer.run(index)) + const raw = analyzerResult(await analyzer.run(index, context)) const result = { ...raw, findings: raw.findings.map((finding) => ({ ...finding, analyzerId: analyzer.id })), diff --git a/packages/analyzer-engine/src/secrets.ts b/packages/analyzer-engine/src/secrets.ts index ba07887..9dd47fd 100644 --- a/packages/analyzer-engine/src/secrets.ts +++ b/packages/analyzer-engine/src/secrets.ts @@ -23,14 +23,34 @@ const SECRET_PATTERNS: Array<{ name: string; re: RegExp }> = [ const SKIP_FILES = /(\.env\.example|\.md|\.lock|package-lock\.json|pnpm-lock\.yaml)$/i const PLACEHOLDER = /(example|placeholder|your[-_]|xxx|changeme|dummy|<[^>]+>|\$\{)/i -/** Placeholder shapes inside the matched value itself. */ -const PLACEHOLDER_VALUE = /(example|sample|dummy|fake|placeholder|changeme|your[-_]?(key|token|secret)|abc123|xxx+)/i +/** + * Runtime credential REFERENCES — `process.env.X`, `{{...}}`, `${VAR}`, `ENV[]`. + * This is how a credential is *supposed* to be written, so it is skipped in + * silence; annotating correct code would be noise. + */ +const RUNTIME_CREDENTIAL_REFERENCE = /(\{\{|\$\{|process\.env|os\.environ|os\.getenv|\bgetenv\b|ENV\[)/i + +/** + * Literals that announce themselves as fake. Skipping these silently is + * correct, but a silent skip looks exactly like a scanner that detects nothing + * — which is what a developer concludes when they test it with a dummy key. + * Reported at INFO so the skip is visible and explained. + */ +const FAKE_LITERAL_VALUE = + /(example|sample|dummy|fake|placeholder|changeme|your[-_]?(key|token|secret)|abc123|xxx+)/i + +/** SCREAMING_SNAKE values are constant identifiers, not credentials — + * `UPDATE_PASSWORD = 'UPDATE_PASSWORD'` is an enum member. */ +const CONSTANT_IDENTIFIER_VALUE = /^[A-Z0-9]+(_[A-Z0-9]+)+$/ /** Dev/CI dummy hosts — credentials pointing here are not real secrets. */ const DUMMY_HOSTS = new Set(['localhost', '127.0.0.1', '0.0.0.0', '::1', 'host.docker.internal']) -/** Test/fixture locations: findings here are downgraded, not silenced. */ -const TEST_PATH_RE = /(^|\/)(tests?|__tests__|__mocks__|fixtures)\/|\.(test|spec)\./ +/** Test/fixture locations: findings here are downgraded, not silenced. + * Covers JS (.test./.spec., __tests__/), Go (_test.go), Python (test_*.py, + * *_test.py), and Ruby (spec/, *_spec.rb) conventions. */ +const TEST_PATH_RE = + /(^|\/)(tests?|__tests__|__mocks__|fixtures|spec)\/|\.(test|spec)\.|_(test|spec)\.(go|py|rb|exs?)$|(^|\/)(test|spec)_[^/]+\.(py|rb)$/ /** * Only the fuzzy generic-password pattern is eligible for the test-fixture @@ -39,6 +59,13 @@ const TEST_PATH_RE = /(^|\/)(tests?|__tests__|__mocks__|fixtures)\/|\.(test|spec */ const TEST_DOWNGRADEABLE = new Set(['Generic password assignment']) +/** + * Database seed / fixture scripts. Their credentials are deliberate, documented + * dev defaults, so "treat as compromised, rotate immediately" is the wrong + * instruction — the real risk is the seed path reaching a production database. + */ +const SEED_PATH_RE = /(^|\/)(seed|seeds|seeders?)(\/|\.|$)|(^|\/)seed[-_.][^/]*$/i + export const secretsAnalyzer: Analyzer = { id: 'secrets', name: 'Exposed Secrets', @@ -50,6 +77,7 @@ export const secretsAnalyzer: Analyzer = { for (const file of index.files) { if (!file.content || SKIP_FILES.test(file.path)) continue const isTestContext = TEST_PATH_RE.test(file.path) + const isSeedScript = SEED_PATH_RE.test(file.path) const lines = file.content.split('\n') for (let i = 0; i < lines.length && findings.length < findingLimit; i++) { const line = lines[i] @@ -57,7 +85,33 @@ export const secretsAnalyzer: Analyzer = { for (const { name, re } of SECRET_PATTERNS) { const match = line.match(re) if (!match) continue - if (PLACEHOLDER_VALUE.test(match[0])) continue + if (RUNTIME_CREDENTIAL_REFERENCE.test(match[0])) continue + if (FAKE_LITERAL_VALUE.test(match[0])) { + findings.push({ + category: 'SECURITY_HYGIENE', + severity: 'INFO', + title: `Credential-shaped placeholder ignored in ${file.path.split('/').pop()}`, + description: `Line ${i + 1} of ${file.path} matches a ${name} pattern, but the value announces itself as a placeholder, so it is NOT reported as a leak. Shown only to confirm the scanner read this line — a real credential in the same position would be reported.`, + filePath: file.path, + line: i + 1, + suggestion: 'No action needed. This entry exists so a deliberate skip is never mistaken for a missed detection.', + impactScore: 5, + effort: 'low', + metadata: { credentialType: name, placeholder: true }, + }) + break + } + // A credential committed to source is a single token. Internal + // whitespace means the value is display text — a validation message, + // an i18n string, a UI label — which nearly every repo has under a + // `password:` key. Reported HIGH it would say "rotate immediately" + // about a translation, and drag the security score with it. + let messageString = false + if (name === 'Generic password assignment') { + const value = /['"]([^'"]+)['"]/.exec(match[0])?.[1] + if (value && CONSTANT_IDENTIFIER_VALUE.test(value)) continue + if (value && /\s/.test(value)) messageString = true + } if (name === 'Database URL with credentials') { const hostPort = match[3] const host = hostPort.replace(/:\d+$/, '').replace(/^\[|\]$/g, '') @@ -65,20 +119,42 @@ export const secretsAnalyzer: Analyzer = { // (postgres:postgres, admin:admin) on a real host still are. if (DUMMY_HOSTS.has(host)) continue } + // Committed .env files always escalate, even under tests/ or a seed path. const isEnvFile = /(^|\/)\.env/.test(file.path) - // Committed .env files always escalate, even under tests/. - if (isTestContext && TEST_DOWNGRADEABLE.has(name) && !isEnvFile) { + const baseName = file.path.split('/').pop() + if (!isEnvFile && !messageString && isSeedScript && TEST_DOWNGRADEABLE.has(name)) { + findings.push({ + category: 'SECURITY_HYGIENE', + severity: 'MEDIUM', + title: `Seed-script credential in ${baseName}`, + description: `Line ${i + 1} of ${file.path} sets a ${name} inside a database seed script. Seed defaults are usually intentional, but anyone who can read the repository knows this login, so it becomes a real account the moment seeding runs anywhere reachable.`, + filePath: file.path, + line: i + 1, + suggestion: 'Confirm this seed cannot execute against a production or shared database (guard it on NODE_ENV, keep it out of deploy and migration steps), and generate the value at runtime instead of committing it.', + impactScore: 45, + effort: 'low', + metadata: { credentialType: name, seedScript: true }, + }) + break + } + if (!isEnvFile && (messageString || (isTestContext && TEST_DOWNGRADEABLE.has(name)))) { findings.push({ category: 'SECURITY_HYGIENE', severity: 'LOW', - title: `Test fixture resembling a secret: ${name} in ${file.path.split('/').pop()}`, - description: `Line ${i + 1} of ${file.path} contains a value shaped like a ${name}. It sits in test/fixture code and does not match a production key format, so it is most likely a fixture — but confirm no real credential was pasted.`, + title: messageString + ? `Message text under a credential-shaped key in ${baseName}` + : `Test fixture resembling a secret: ${name} in ${baseName}`, + description: messageString + ? `Line ${i + 1} of ${file.path} assigns a credential-shaped key a value containing spaces, which reads as display text (a validation message, translation, or label) rather than a credential. Reported for awareness only — confirm no real passphrase was pasted here.` + : `Line ${i + 1} of ${file.path} contains a value shaped like a ${name}. It sits in test/fixture code and does not match a production key format, so it is most likely a fixture — but confirm no real credential was pasted.`, filePath: file.path, line: i + 1, - suggestion: 'Use an obviously fake placeholder (e.g. "test-not-a-real-key") so scanners and reviewers can dismiss it at a glance.', - impactScore: 25, + suggestion: messageString + ? 'No action needed if this is user-facing copy. If a real passphrase was pasted here, rotate it and move it to environment configuration.' + : 'Use an obviously fake placeholder (e.g. "test-not-a-real-key") so scanners and reviewers can dismiss it at a glance.', + impactScore: messageString ? 10 : 25, effort: 'low', - metadata: { credentialType: name, testContext: true }, + metadata: { credentialType: name, testContext: isTestContext, messageString }, }) } else { findings.push({ diff --git a/packages/analyzer-engine/src/structure.ts b/packages/analyzer-engine/src/structure.ts index d0b8845..4e84591 100644 --- a/packages/analyzer-engine/src/structure.ts +++ b/packages/analyzer-engine/src/structure.ts @@ -107,18 +107,26 @@ export const structureAnalyzer: Analyzer = { const generatedFiles = index.generatedFiles ?? {} const generatedPaths = Object.keys(generatedFiles) const generatedLoc = Object.values(generatedFiles).reduce((a, b) => a + b, 0) - if (generatedPaths.length > 0 && generatedLoc >= 500) { + // Minified bundles pack thousands of statements onto a handful of lines, so + // their LOC understates the excluded volume by orders of magnitude. Gate and + // report on BYTES too, or a 570KB vendored payload disappears silently. + const generatedBytes = index.files + .filter((f) => f.kind === 'generated') + .reduce((total, f) => total + (f.sizeBytes ?? 0), 0) + const generatedKb = Math.round(generatedBytes / 1024) + if (generatedPaths.length > 0 && (generatedLoc >= 500 || generatedBytes >= 50_000)) { const plural = generatedPaths.length > 1 + const volume = `~${generatedLoc.toLocaleString()} LOC, ${generatedKb.toLocaleString()} KB` findings.push({ category: 'STRUCTURE', severity: 'LOW', - title: `Generated code excluded from analysis (${generatedPaths.length} file${plural ? 's' : ''}, ~${generatedLoc.toLocaleString()} LOC)`, - description: `CodeTruss detected ${generatedPaths.length} machine-generated file${plural ? 's' : ''} (~${generatedLoc.toLocaleString()} LOC, e.g. \`${generatedPaths[0]}\`) and excluded ${plural ? 'them' : 'it'} from LOC totals, scores, and the architecture graph so ${plural ? 'they' : 'it'} don't inflate metrics or produce spurious "oversized file" / "duplicated logic" findings.`, + title: `Generated code excluded from analysis (${generatedPaths.length} file${plural ? 's' : ''}, ${generatedKb.toLocaleString()} KB)`, + description: `CodeTruss detected ${generatedPaths.length} machine-generated or minified file${plural ? 's' : ''} (${volume}, e.g. \`${generatedPaths[0]}\`) and excluded ${plural ? 'them' : 'it'} from LOC totals, scores, and the architecture graph so ${plural ? 'they' : 'it'} don't inflate metrics or produce spurious "oversized file" / "duplicated logic" findings. Minified bundles report few lines for their size, so the KB figure is the honest measure of what was skipped.`, filePath: generatedPaths[0], - suggestion: 'Keep generated files out of review scope — regenerate them at build time, or mark them linguist-generated in .gitattributes.', + suggestion: 'Keep generated and vendored bundles out of review scope — regenerate them at build time, or mark them linguist-generated in .gitattributes.', impactScore: 20, effort: 'low', - metadata: { files: generatedPaths.length, loc: generatedLoc }, + metadata: { files: generatedPaths.length, loc: generatedLoc, bytes: generatedBytes }, }) } diff --git a/packages/analyzer-engine/src/types.ts b/packages/analyzer-engine/src/types.ts index 30937d2..ace0118 100644 --- a/packages/analyzer-engine/src/types.ts +++ b/packages/analyzer-engine/src/types.ts @@ -107,9 +107,30 @@ export function analyzerResult(output: AnalyzerFinding[]): AnalyzerRunResult { return { findings: output, complete: status?.complete ?? true, ...status } } +/** + * Which passes OUTSIDE the registry run alongside the analyzers in this + * execution. The registry is shared, but the passes around it are not: the + * hosted pipeline runs SAST for the scan types whose policy includes it, and + * the local CLI never runs it at all. An analyzer that discloses coverage has + * to be told, because "the SAST engine covers TypeScript" is a fact about the + * engine, not about this run. + */ +export interface AnalyzerContext { + /** The SAST pass (security rules + taint tracking) runs for this analysis. */ + sast: boolean +} + +/** + * Fail-honest default: a caller that does not declare its non-registry passes + * is treated as running none of them. A front-end that omits the declaration + * therefore over-discloses rather than inheriting a caveat written for a pass + * it never executes. + */ +export const REGISTRY_ONLY_ANALYSIS: AnalyzerContext = { sast: false } + export interface Analyzer { id: string name: string description: string - run(index: RepoIndex): Promise + run(index: RepoIndex, context?: AnalyzerContext): Promise } diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 091a752..ead7df3 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -5,6 +5,102 @@ checksums are published at createHash('sha256').update(value).digest('hex') async function writeRelease(archivePackageDir = packageDir) { - await rm(releaseDir, { recursive: true, force: true }) - await mkdir(releaseDir, { recursive: true }) - const pkg = JSON.parse(await readFile(join(archivePackageDir, 'package.json'), 'utf8')) - const archiveName = `codetruss-cli-${pkg.version}.tgz` - const sbomName = `codetruss-cli-${pkg.version}.sbom.cdx.json` - const archive = await buildDeterministicPackageArchive(archivePackageDir, join(releaseDir, archiveName)) - const entries = verifyDeterministicPackageArchive(archive) - const bundle = entries.get('package/dist/cli.cjs') - if (!bundle) throw new Error('fixture archive does not contain the CLI executable') + const pkg = JSON.parse(await readFile(join(packageDir, 'package.json'), 'utf8')) + const versionedName = `codetruss-cli-${pkg.version}.tgz` + const latestName = 'codetruss-cli-latest.tgz' + const versionedSbomName = `codetruss-cli-${pkg.version}.sbom.cdx.json` + const archive = await buildDeterministicPackageArchive(archivePackageDir, join(downloadDir, versionedName)) + const sha256 = digest(archive) const sbom = await readFile(join(archivePackageDir, 'SBOM.cdx.json')) - const archiveSha256 = digest(archive) const sbomSha256 = digest(sbom) - await writeFile(join(releaseDir, sbomName), sbom) - await writeFile(join(releaseDir, `${archiveName}.sha256`), `${archiveSha256} ${archiveName}\n`) - await writeFile(join(releaseDir, 'release-manifest.json'), `${JSON.stringify({ - schemaVersion: 1, - package: pkg.name, - version: pkg.version, - tag: `v${pkg.version}`, - repository: 'https://github.com/DeliriumPulse/codetruss-cli', - node: pkg.engines.node, - artifacts: [ - { name: archiveName, mediaType: 'application/gzip', sha256: archiveSha256 }, - { name: sbomName, mediaType: 'application/vnd.cyclonedx+json', sha256: sbomSha256 }, - ], - }, null, 2)}\n`) - await writeFile(referencePath, `${JSON.stringify({ - schemaVersion: 1, + await writeFile(join(downloadDir, latestName), archive) + await writeFile(join(downloadDir, versionedSbomName), sbom) + await writeFile(join(downloadDir, 'codetruss-cli-latest.sbom.cdx.json'), sbom) + await writeFile(join(downloadDir, `${versionedName}.sha256`), `${sha256} ${versionedName}\n`) + await writeFile(join(downloadDir, `${latestName}.sha256`), `${sha256} ${latestName}\n`) + await writeFile(join(downloadDir, 'codetruss-cli-latest.json'), `${JSON.stringify({ + name: pkg.name, version: pkg.version, - websiteArchive: `https://codetruss.com/downloads/${archiveName}`, - archiveSha256, + url: `/downloads/${versionedName}`, + latestUrl: `/downloads/${latestName}`, + sha256, + sbomUrl: `/downloads/${versionedSbomName}`, sbomSha256, - bundleSha256: digest(bundle), + node: pkg.engines.node, + repository: 'https://github.com/DeliriumPulse/codetruss-cli', + releaseUrl: `https://github.com/DeliriumPulse/codetruss-cli/releases/tag/v${pkg.version}`, + attestationCommand: `gh attestation verify ${versionedName} --repo DeliriumPulse/codetruss-cli`, }, null, 2)}\n`) -} - -async function verify(packagePath = packageDir) { - return verifyRelease({ packageDir: packagePath, releaseDir, referencePath }) + return { versionedName, latestName } } try { - await writeRelease() - await verify() + await mkdir(downloadDir, { recursive: true }) + const names = await writeRelease() + await verifyRelease({ packageDir, downloadDir }) for (const file of PACKAGE_ARCHIVE_FILES) { const target = join(tamperedPackageDir, file.source) @@ -69,14 +57,20 @@ try { maliciousManifest.scripts = { ...maliciousManifest.scripts, postinstall: 'node -e "process.exit(99)"' } await writeFile(join(tamperedPackageDir, 'package.json'), `${JSON.stringify(maliciousManifest, null, 2)}\n`) await writeRelease(tamperedPackageDir) - await assert.rejects(() => verify(), /does not contain the current package\.json/) - await assert.rejects(() => verify(tamperedPackageDir), /postinstall install lifecycle script/) + await assert.rejects(() => verifyRelease({ packageDir, downloadDir }), /current package\.json/) + await assert.rejects( + () => verifyRelease({ packageDir: tamperedPackageDir, downloadDir }), + /postinstall install lifecycle script/, + ) delete maliciousManifest.scripts.postinstall maliciousManifest.dependencies = { 'runtime-surprise': '1.0.0' } await writeFile(join(tamperedPackageDir, 'package.json'), `${JSON.stringify(maliciousManifest, null, 2)}\n`) await writeRelease(tamperedPackageDir) - await assert.rejects(() => verify(tamperedPackageDir), /must not declare dependencies/) + await assert.rejects( + () => verifyRelease({ packageDir: tamperedPackageDir, downloadDir }), + /must not declare dependencies/, + ) delete maliciousManifest.dependencies for (const [field, value] of [ @@ -86,25 +80,22 @@ try { maliciousManifest.publishConfig = { access: 'public', [field]: value } await writeFile(join(tamperedPackageDir, 'package.json'), `${JSON.stringify(maliciousManifest, null, 2)}\n`) await writeRelease(tamperedPackageDir) - await assert.rejects(() => verify(tamperedPackageDir), /package access or supported Node policy is invalid/) + await assert.rejects( + () => verifyRelease({ packageDir: tamperedPackageDir, downloadDir }), + /package access or supported Node policy is invalid/, + ) } await writeRelease() - const reference = JSON.parse(await readFile(referencePath, 'utf8')) - await writeFile(referencePath, `${JSON.stringify({ ...reference, unexpected: true }, null, 2)}\n`) - await assert.rejects(() => verify(), /reference is not the canonical website metadata/) - - await writeRelease() - const manifestPath = join(releaseDir, 'release-manifest.json') - const manifest = JSON.parse(await readFile(manifestPath, 'utf8')) - await writeFile(manifestPath, `${JSON.stringify({ ...manifest, unexpected: true }, null, 2)}\n`) - await assert.rejects(() => verify(), /release manifest is not canonical/) + const metadataPath = join(downloadDir, 'codetruss-cli-latest.json') + const metadata = JSON.parse(await readFile(metadataPath, 'utf8')) + await writeFile(metadataPath, `${JSON.stringify({ ...metadata, unexpected: true }, null, 2)}\n`) + await assert.rejects(() => verifyRelease({ packageDir, downloadDir }), /metadata is not the canonical manifest/) await writeRelease() - const pkg = JSON.parse(await readFile(join(packageDir, 'package.json'), 'utf8')) - const sidecarPath = join(releaseDir, `codetruss-cli-${pkg.version}.tgz.sha256`) - await writeFile(sidecarPath, `${await readFile(sidecarPath, 'utf8')}untrusted trailing bytes\n`) - await assert.rejects(() => verify(), /not the canonical checksum/) + const latestSidecar = join(downloadDir, `${names.latestName}.sha256`) + await writeFile(latestSidecar, `${await readFile(latestSidecar, 'utf8')}untrusted trailing bytes\n`) + await assert.rejects(() => verifyRelease({ packageDir, downloadDir }), /not the canonical checksum/) for (const file of PACKAGE_ARCHIVE_FILES) { await copyFile(join(packageDir, file.source), join(tamperedPackageDir, file.source)) @@ -114,11 +105,11 @@ try { await writeFile(join(tamperedPackageDir, 'SBOM.cdx.json'), `${JSON.stringify(noncanonicalSbom, null, 2)}\n`) await writeRelease(tamperedPackageDir) await assert.rejects( - () => verify(tamperedPackageDir), + () => verifyRelease({ packageDir: tamperedPackageDir, downloadDir }), /does not have the canonical CycloneDX identity/, ) } finally { await rm(scratch, { recursive: true, force: true }) } -process.stdout.write('Public release integrity verifier tests passed.\n') +process.stdout.write('Release integrity verifier tests passed.\n') diff --git a/packages/cli/scripts/verify-release.mjs b/packages/cli/scripts/verify-release.mjs index 31d99fb..534e571 100644 --- a/packages/cli/scripts/verify-release.mjs +++ b/packages/cli/scripts/verify-release.mjs @@ -8,70 +8,57 @@ import { verifyDeterministicPackageArchive } from './verify-deterministic-packag const scriptPath = fileURLToPath(import.meta.url) const defaultPackageDir = resolve(dirname(scriptPath), '..') -const defaultRepoRoot = resolve(defaultPackageDir, '../..') -const defaultReleaseDir = join(defaultRepoRoot, 'release') -const defaultReferencePath = join(defaultRepoRoot, 'release-reference.json') +const defaultDownloadDir = join(resolve(defaultPackageDir, '../..'), 'public', 'downloads') const digest = (value) => createHash('sha256').update(value).digest('hex') -export async function verifyRelease({ - packageDir = defaultPackageDir, - releaseDir = defaultReleaseDir, - referencePath = defaultReferencePath, -} = {}) { +export async function verifyRelease({ packageDir = defaultPackageDir, downloadDir = defaultDownloadDir } = {}) { const pkgBytes = await readFile(join(packageDir, 'package.json')) const pkg = JSON.parse(pkgBytes.toString('utf8')) assertReleasePackagePolicy(pkg) - const archiveName = `codetruss-cli-${pkg.version}.tgz` - const sbomName = `codetruss-cli-${pkg.version}.sbom.cdx.json` - const archive = await readFile(join(releaseDir, archiveName)) - const sbom = await readFile(join(releaseDir, sbomName)) - const archiveSha256 = digest(archive) - const sbomSha256 = digest(sbom) - const entries = verifyDeterministicPackageArchive(archive) - const bundle = entries.get('package/dist/cli.cjs') - if (!bundle) throw new Error('release archive does not contain the CLI executable') - const bundleSha256 = digest(bundle) - - const expectedReference = { - schemaVersion: 1, + const versionedName = `codetruss-cli-${pkg.version}.tgz` + const latestName = 'codetruss-cli-latest.tgz' + const versionedSbomName = `codetruss-cli-${pkg.version}.sbom.cdx.json` + const versioned = await readFile(join(downloadDir, versionedName)) + const latest = await readFile(join(downloadDir, latestName)) + const versionedSbom = await readFile(join(downloadDir, versionedSbomName)) + const latestSbom = await readFile(join(downloadDir, 'codetruss-cli-latest.sbom.cdx.json')) + const versionedSha = digest(versioned) + const sbomSha = digest(versionedSbom) + const expectedMetadata = { + name: pkg.name, version: pkg.version, - websiteArchive: `https://codetruss.com/downloads/${archiveName}`, - archiveSha256, - sbomSha256, - bundleSha256, - } - const referenceBytes = await readFile(referencePath) - const expectedReferenceBytes = Buffer.from(`${JSON.stringify(expectedReference, null, 2)}\n`, 'utf8') - if (!referenceBytes.equals(expectedReferenceBytes)) { - throw new Error(`release reference is not the canonical website metadata for ${pkg.version}`) - } - - const expectedManifest = { - schemaVersion: 1, - package: pkg.name, - version: pkg.version, - tag: `v${pkg.version}`, - repository: 'https://github.com/DeliriumPulse/codetruss-cli', + url: `/downloads/${versionedName}`, + latestUrl: `/downloads/${latestName}`, + sha256: versionedSha, + sbomUrl: `/downloads/${versionedSbomName}`, + sbomSha256: sbomSha, node: pkg.engines.node, - artifacts: [ - { name: archiveName, mediaType: 'application/gzip', sha256: archiveSha256 }, - { name: sbomName, mediaType: 'application/vnd.cyclonedx+json', sha256: sbomSha256 }, - ], + repository: 'https://github.com/DeliriumPulse/codetruss-cli', + releaseUrl: `https://github.com/DeliriumPulse/codetruss-cli/releases/tag/v${pkg.version}`, + attestationCommand: `gh attestation verify ${versionedName} --repo DeliriumPulse/codetruss-cli`, } - const manifestBytes = await readFile(join(releaseDir, 'release-manifest.json')) - const expectedManifestBytes = Buffer.from(`${JSON.stringify(expectedManifest, null, 2)}\n`, 'utf8') - if (!manifestBytes.equals(expectedManifestBytes)) { - throw new Error(`release manifest is not canonical for ${archiveName}`) + const metadataBytes = await readFile(join(downloadDir, 'codetruss-cli-latest.json')) + const expectedMetadataBytes = Buffer.from(`${JSON.stringify(expectedMetadata, null, 2)}\n`, 'utf8') + if (!metadataBytes.equals(expectedMetadataBytes)) { + throw new Error(`release metadata is not the canonical manifest for CLI ${pkg.version}; run pnpm cli:release`) } + if (!latest.equals(versioned)) throw new Error(`${latestName} does not match immutable ${versionedName}`) + if (!latestSbom.equals(versionedSbom)) throw new Error(`latest release SBOM does not match ${versionedSbomName}`) - const sidecar = await readFile(join(releaseDir, `${archiveName}.sha256`), 'utf8') - if (sidecar !== `${archiveSha256} ${archiveName}\n`) { - throw new Error(`${archiveName}.sha256 is not the canonical checksum for ${archiveName}`) + const expectedSidecars = new Map([ + [`${versionedName}.sha256`, `${versionedSha} ${versionedName}\n`], + [`${latestName}.sha256`, `${versionedSha} ${latestName}\n`], + ]) + for (const [name, expected] of expectedSidecars) { + const sidecar = await readFile(join(downloadDir, name), 'utf8') + if (sidecar !== expected) throw new Error(`${name} is not the canonical checksum for ${versionedName}`) } // A checksum can prove that a hosted tarball is immutable without proving // that it contains the source being released. Compare every package byte, - // including package.json lifecycle scripts and dependency metadata. + // including package.json lifecycle scripts and dependency metadata, before a + // site build may advertise this artifact. + const entries = verifyDeterministicPackageArchive(versioned) for (const name of [ 'CHANGELOG.md', 'LICENSE', @@ -85,28 +72,28 @@ export async function verifyRelease({ const local = name === 'package.json' ? pkgBytes : await readFile(join(packageDir, name)) const packed = entries.get(`package/${name}`) if (!packed || !local.equals(packed)) { - throw new Error(`${archiveName} does not contain the current ${name}`) + throw new Error(`${versionedName} does not contain the current ${name}; bump the CLI version and run pnpm cli:release`) } } - if (!entries.get('package/SBOM.cdx.json').equals(sbom)) { - throw new Error(`${sbomName} does not describe the SBOM included in ${archiveName}`) + if (!entries.get('package/SBOM.cdx.json').equals(versionedSbom)) { + throw new Error(`${versionedSbomName} does not describe the SBOM included in ${versionedName}`) } - const packagedSbom = JSON.parse(sbom.toString('utf8')) + const packagedSbom = JSON.parse(versionedSbom.toString('utf8')) if (packagedSbom.metadata?.component?.name !== pkg.name || packagedSbom.metadata?.component?.version !== pkg.version) { - throw new Error(`${sbomName} does not identify ${pkg.name}@${pkg.version}`) + throw new Error(`${versionedSbomName} does not identify ${pkg.name}@${pkg.version}`) } const expectedSerialNumber = cycloneDxSerialNumber(pkg.name, pkg.version) if (packagedSbom.bomFormat !== 'CycloneDX' || packagedSbom.specVersion !== '1.6' || packagedSbom.serialNumber !== expectedSerialNumber) { - throw new Error(`${sbomName} does not have the canonical CycloneDX identity ${expectedSerialNumber}`) + throw new Error(`${versionedSbomName} does not have the canonical CycloneDX identity ${expectedSerialNumber}`) } - return { version: pkg.version, sha256: archiveSha256 } + return { version: pkg.version, sha256: versionedSha } } const invokedPath = process.argv[1] ? pathToFileURL(resolve(process.argv[1])).href : undefined if (invokedPath === import.meta.url) { const result = await verifyRelease() - process.stdout.write(`Verified ${result.version} release (${result.sha256})\n`) + process.stdout.write(`Verified immutable CodeTruss CLI ${result.version} release (${result.sha256})\n`) } diff --git a/packages/cli/src/analysis.ts b/packages/cli/src/analysis.ts index 0bcb853..ab4597e 100644 --- a/packages/cli/src/analysis.ts +++ b/packages/cli/src/analysis.ts @@ -8,7 +8,10 @@ export async function analyzeRepository(root: string) { const priorOffline = process.env.CODETRUSS_OFFLINE process.env.CODETRUSS_OFFLINE = '1' try { - const result = await runAnalyzers(index) + // LOCAL_ANALYSIS_PROFILE omits the SAST pass. Declaring it here is what + // makes the coverage analyzer disclose the gap instead of inheriting the + // hosted premise that TypeScript/JavaScript/Python were security-reviewed. + const result = await runAnalyzers(index, { sast: false }) return { ...result, index } } finally { if (priorOffline === undefined) delete process.env.CODETRUSS_OFFLINE @@ -80,7 +83,53 @@ export function diffFindings( return { introduced, worsened, recurring, resolved } } -/** Offline vulnerability lookup is advisory; every deterministic pass and index byte is required. */ +/** + * A partially-read index still counts as authoritative when it measurably + * covered at least this fraction of its analyzable input. Mirrors + * AUTHORITATIVE_COVERAGE_RATIO in the hosted pipeline (src/lib/scans/analysis.ts): + * an immaterial cap (one oversized lockfile) must not void the receipt, while a + * real coverage loss still withholds one. + */ +export const AUTHORITATIVE_COVERAGE_RATIO = 0.95 + +/** + * Text files loaded over analyzable text candidates. Binary files masquerading + * as text are not analyzable and never count against coverage. The file-walk + * cap has no measurable denominator — unwalked files are unknown — so a + * truncated walk claims no ratio. + */ +export function indexCoverageRatio(coverage: IndexCoverage | undefined): number | undefined { + if (!coverage || coverage.truncated) return undefined + const analyzable = coverage.textCandidates - coverage.binaryTextFiles + if (analyzable <= 0) return 1 + return coverage.contentLoaded / analyzable +} + +function coverageIsAuthoritative(coverage: IndexCoverage | undefined): boolean { + const ratio = indexCoverageRatio(coverage) + return ratio !== undefined && ratio >= AUTHORITATIVE_COVERAGE_RATIO +} + +/** Content-loading limitations, worded so the reader learns the fix, not just the symptom. */ +function coverageLimitations(coverage: IndexCoverage): string[] { + const limitations: string[] = [] + if (coverage.oversizedTextFiles > 0) { + limitations.push( + `${coverage.oversizedTextFiles} oversized analyzable file(s) were not read — raise CODETRUSS_MAX_INDEX_FILE_BYTES to include them`, + ) + } + if (coverage.unreadableTextFiles > 0) limitations.push(`${coverage.unreadableTextFiles} analyzable file(s) could not be read`) + if (coverage.binaryTextFiles > 0) limitations.push(`${coverage.binaryTextFiles} apparent text file(s) contained binary data`) + return limitations +} + +/** + * Offline vulnerability lookup is advisory; every deterministic pass is + * required. Index limitations are required too, EXCEPT when the index still + * measurably covered >= AUTHORITATIVE_COVERAGE_RATIO of its analyzable input — + * those are returned by analysisCoverageNotes() as review-level instead, so a + * single large lockfile cannot fail an otherwise clean receipt. + */ export function analysisEvidenceIssues( passes: AnalyzerPass[], coverage: IndexCoverage | undefined, @@ -96,13 +145,21 @@ export function analysisEvidenceIssues( if (!coverage) issues.push('repository index did not report coverage') else { if (coverage.truncated) issues.push(`repository index reached its ${coverage.maxFiles}-file bound`) - if (coverage.oversizedTextFiles > 0) issues.push(`${coverage.oversizedTextFiles} oversized analyzable file(s) were not read`) - if (coverage.unreadableTextFiles > 0) issues.push(`${coverage.unreadableTextFiles} analyzable file(s) could not be read`) - if (coverage.binaryTextFiles > 0) issues.push(`${coverage.binaryTextFiles} apparent text file(s) contained binary data`) + if (!coverageIsAuthoritative(coverage)) issues.push(...coverageLimitations(coverage)) } return issues } +/** + * Index limitations small enough to leave the evidence authoritative. Surfaced + * on the receipt as review-level context rather than suppressed — the reader + * still learns exactly what was not read. + */ +export function analysisCoverageNotes(coverage: IndexCoverage | undefined): string[] { + if (!coverage || !coverageIsAuthoritative(coverage)) return [] + return coverageLimitations(coverage) +} + export function changedFindings(findings: AnalyzerFinding[], files: ChangedFile[]): AnalyzerFinding[] { const changed = new Set(files.flatMap((file) => [file.path, file.oldPath].filter(Boolean) as string[])) return findings.filter((finding) => { @@ -120,6 +177,7 @@ export function computeVerdict(input: { llm?: LlmReview evidenceIssues?: string[] baselineEvidenceIssues?: string[] + advisoryEvidenceIssues?: string[] }): { verdict: Verdict; reasons: string[] } { const failed: string[] = [] const review: string[] = [] @@ -127,6 +185,7 @@ export function computeVerdict(input: { if (input.agentExitCode !== undefined && input.agentExitCode !== 0) failed.push(`agent command exited with code ${input.agentExitCode}`) for (const issue of input.evidenceIssues ?? []) failed.push(`evidence incomplete: ${issue}`) for (const issue of input.baselineEvidenceIssues ?? []) review.push(`baseline evidence limitation resolved in the final tree: ${issue}`) + for (const issue of input.advisoryEvidenceIssues ?? []) review.push(`index coverage was partial but authoritative: ${issue}`) for (const verification of input.verifications.filter((item) => item.exitCode !== 0)) failed.push(`verification command failed: ${verification.command}`) const blocking = input.findings.filter((finding) => severityRank[finding.severity] >= severityRank.HIGH && (finding.category === 'SECURITY_HYGIENE' || finding.category === 'DEPENDENCY')) if (blocking.length) failed.push(`${blocking.length} high/critical security or dependency finding(s) affect changed files`) diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index f95b11f..22461e5 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -2,9 +2,9 @@ import { createHash, randomUUID } from 'node:crypto' import { realpath, rmdir } from 'node:fs/promises' import { dirname, isAbsolute, join, resolve } from 'node:path' -import { analyzeRepository, analysisEvidenceIssues, analyzerReceipt, computeVerdict, diffFindings } from './analysis.js' +import { analyzeRepository, analysisCoverageNotes, analysisEvidenceIssues, analyzerReceipt, computeVerdict, diffFindings } from './analysis.js' import { loadSyncAuthentication } from './auth-storage.js' -import { initialize, loadConfig, receiptDir } from './config.js' +import { CONFIG_FILE, initialize, loadConfig, receiptDir, trustLocalSigningKey } from './config.js' import { allocatedVerificationTimeout, captureDiffEvidence, @@ -356,7 +356,7 @@ async function executeReview(parsed: Parsed, root: string, liveConfig: CliConfig if (requestedProvider && config.llm.model && config.llm.provider && config.llm.provider !== requestedProvider) { throw new Error(`--provider ${requestedProvider} conflicts with model ${config.llm.model} configured for ${config.llm.provider}`) } - await requireTrustedSigningKey(config.signing.publicKey) + await requireTrustedSigningKey(config.signing.publicKeys) const options: ReviewOptions = { mode, task, allow: many(parsed, 'allow', config.allow), @@ -461,6 +461,8 @@ async function executeReview(parsed: Parsed, root: string, liveConfig: CliConfig ...finalEvidenceIssues.map((issue) => `final ${issue}`), ...(diff.truncated ? [`diff capture retained ${diff.capturedBytes} of ${diff.totalBytes} bytes`] : []), ] + // Coverage gaps small enough to leave the index authoritative: reported, not fatal. + const advisoryEvidenceIssues = analysisCoverageNotes(analysis.index.coverage).map((issue) => `final ${issue}`) const verifications = [] for (const [commandIndex, command] of options.verify.entries()) { @@ -536,6 +538,7 @@ async function executeReview(parsed: Parsed, root: string, liveConfig: CliConfig llm, evidenceIssues, baselineEvidenceIssues: finalEvidenceIssues.length === 0 ? baselineEvidenceIssues : [], + advisoryEvidenceIssues, }) if (llmFailure) { outcome.verdict = 'FAILED'; outcome.reasons.unshift(`requested LLM review failed: ${llmFailure}`) } const finishedAt = new Date() @@ -711,6 +714,16 @@ async function main(argv = process.argv.slice(2)): Promise { const deny = many(parsed, 'deny', []) const path = await initialize(root, parsed.booleans.has('force'), { allow, deny }) process.stdout.write(`${path}\n`) + // init auto-detects verification commands, but running them requires an + // explicit trust decision. Without this notice the next `review` exits 3 + // with no receipt at all — a dead end on the very first run. + const detectedVerify = (await loadConfig(root)).verify + if (detectedVerify.length > 0) { + process.stdout.write( + `Detected verification commands (${detectedVerify.join(', ')}). They are not trusted until you approve them.\n` + + 'Run: codetruss verify-policy trust\n', + ) + } if (allow.length === 0) { process.stdout.write( 'No allow globs configured: changed paths remain unexpected, and agent hooks cannot be installed until .codetruss.yml defines at least one allow glob.\n' @@ -723,7 +736,7 @@ async function main(argv = process.argv.slice(2)): Promise { const dir = receiptDir(root, config) if (parsed.command === 'run' || parsed.command === 'review') return executeReview(parsed, root, config) if (parsed.command === 'report') { - const receipt = await verifyReceipt(dir, parsed.positionals[0] ?? 'latest', config.signing.publicKey) + const receipt = await verifyReceipt(dir, parsed.positionals[0] ?? 'latest', config.signing.publicKeys) process.stdout.write(parsed.booleans.has('json') ? `${JSON.stringify(receipt, null, 2)}\n` : renderMarkdown(receipt)) return 0 } @@ -736,12 +749,26 @@ async function main(argv = process.argv.slice(2)): Promise { } if (parsed.command === 'metrics') { const metrics = await collectLocalMetrics(root, dir, config.signing.publicKey) - process.stdout.write(parsed.booleans.has('json') ? `${JSON.stringify(metrics, null, 2)}\n` : renderLocalMetrics(metrics)) + process.stdout.write(parsed.booleans.has('json') ? `${JSON.stringify(metrics, null, 2)} +` : renderLocalMetrics(metrics)) return 0 } - if (parsed.command === 'verify') { const receipt = await verifyReceipt(dir, parsed.positionals[0] ?? 'latest', config.signing.publicKey); process.stdout.write(`verified ${receipt.sessionId} (${receipt.verdict})\n`); return 0 } + if (parsed.command === 'verify') { const receipt = await verifyReceipt(dir, parsed.positionals[0] ?? 'latest', config.signing.publicKeys); process.stdout.write(`verified ${receipt.sessionId} (${receipt.verdict}) +`); return 0 } if (parsed.command === 'verify-policy') { const action = parsed.positionals[0] ?? 'status' + // Key trust is independent of verification commands: a repository with no + // verify commands still pins signers, and a blocked teammate must be able + // to add their key here. + if (action === 'trust-key') { + const result = await trustLocalSigningKey(root) + process.stdout.write( + result.status === 'added' + ? `added signing key ${result.fingerprint}; this repository now trusts ${result.total} signer(s)\nCommit ${CONFIG_FILE} so your teammates inherit the change.\n` + : `signing key ${result.fingerprint} is already trusted by this repository\n`, + ) + return 0 + } if (!config.verify.length) { process.stdout.write('No repository verification commands are configured.\n'); return 0 } if (action === 'status') { const trust = await verifyCommandTrustStatus(root, config.verify) @@ -758,10 +785,10 @@ async function main(argv = process.argv.slice(2)): Promise { process.stdout.write(`revoked ${trust.hash}\n`) return 0 } - throw new Error(`unknown verify-policy action ${action}; expected status, trust, or revoke`) + throw new Error(`unknown verify-policy action ${action}; expected status, trust, trust-key, or revoke`) } if (parsed.command === 'sync') { - const receipt = await verifyReceipt(dir, parsed.positionals[0] ?? 'latest', config.signing.publicKey) + const receipt = await verifyReceipt(dir, parsed.positionals[0] ?? 'latest', config.signing.publicKeys) const envelope = await createSyncEnvelope(receipt) if (parsed.booleans.has('dry-run')) { process.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`); return 0 } const authentication = await loadSyncAuthentication() diff --git a/packages/cli/src/config.ts b/packages/cli/src/config.ts index 3dc21d2..d25bd1e 100644 --- a/packages/cli/src/config.ts +++ b/packages/cli/src/config.ts @@ -9,6 +9,26 @@ export const CONFIG_FILE = '.codetruss.yml' export const PRODUCTION_SYNC_ORIGIN = 'https://codetruss.com' export const DEV_SYNC_ORIGIN_ENV = 'CODETRUSS_DEV_SYNC_ORIGIN' export const APPROVED_RECEIPT_DIR = '.codetruss/receipts' +/** + * Normalize the signing pin into a set. Accepts a single `publicKey` (what + * `init` writes) and/or a `publicKeys` list, so a team can add each developer's + * key without any one of them being blocked. Duplicates collapse; order is + * preserved so `publicKey` stays stable for existing single-signer configs. + */ +function signingPins(signing: Record): { publicKey?: string; publicKeys: string[] } { + const raw: unknown[] = [ + signing.publicKey, + ...(Array.isArray(signing.publicKeys) ? signing.publicKeys : []), + ] + const publicKeys: string[] = [] + for (const entry of raw) { + if (typeof entry !== 'string' || !entry.trim()) continue + const normalized = normalizePublicKey(entry) + if (!publicKeys.includes(normalized)) publicKeys.push(normalized) + } + return { publicKey: publicKeys[0], publicKeys } +} + export const DEFAULT_CONFIG: CliConfig = { version: 1, allow: [], @@ -16,13 +36,20 @@ export const DEFAULT_CONFIG: CliConfig = { verify: [], receipts: { dir: APPROVED_RECEIPT_DIR }, llm: { maxDiffBytes: 200_000 }, - signing: {}, + signing: { publicKeys: [] }, sync: { url: PRODUCTION_SYNC_ORIGIN }, } export interface InitializeOptions { allow?: string[] deny?: string[] + /** + * Override the auto-detected verification commands. Unattended setup passes + * an empty list so a repository is never configured with commands it has not + * been given permission to run — a review would otherwise refuse to produce + * any receipt at all. + */ + verify?: string[] } function objectValue(value: unknown, key: string): Record { @@ -86,11 +113,7 @@ export async function loadConfig(root: string): Promise { // only when --llm is actually requested. maxDiffBytes: typeof maxDiffBytes === 'number' && maxDiffBytes > 0 ? maxDiffBytes : DEFAULT_CONFIG.llm.maxDiffBytes, }, - signing: { - publicKey: typeof signing.publicKey === 'string' && signing.publicKey.trim() - ? normalizePublicKey(signing.publicKey) - : undefined, - }, + signing: signingPins(signing), // This value is an application invariant, never repository configuration. sync: { url: PRODUCTION_SYNC_ORIGIN }, } @@ -160,7 +183,7 @@ export async function initialize(root: string, force = false, options: Initializ if (!force) { try { await access(path); throw new Error(`${CONFIG_FILE} already exists; pass --force to replace it`) } catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error } } - const detected = await detectVerify(root) + const detected = options.verify ?? (await detectVerify(root)) const key = await loadSigningKey(true) const value = { version: DEFAULT_CONFIG.version, @@ -228,3 +251,38 @@ async function detectVerify(root: string): Promise { if (((await exists('pyproject.toml')) || (await exists('requirements.txt'))) && await available('pytest')) return ['pytest'] return [] } + +/** + * Append the local signing key to the repository's trusted set so a teammate + * can produce receipts under their OWN identity. The alternative the old error + * implied — sharing a private key — would destroy per-signer attribution, which + * is the entire point of signing the receipt. + */ +export async function trustLocalSigningKey( + root: string, +): Promise<{ status: 'added' | 'already-trusted'; fingerprint: string; total: number }> { + const key = await loadSigningKey(true) + const path = join(root, CONFIG_FILE) + let text: string + try { + text = await readFile(path, 'utf8') + } catch (error) { + if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error + throw new Error(`no ${CONFIG_FILE} in this repository; run codetruss init first`) + } + const parsed = parse(text) + const document = parsed && typeof parsed === 'object' && !Array.isArray(parsed) + ? (parsed as Record) + : {} + const existing = signingPins(objectValue(document.signing, 'signing')) + const mine = normalizePublicKey(key.publicKey) + if (existing.publicKeys.includes(mine)) { + return { status: 'already-trusted', fingerprint: key.fingerprint, total: existing.publicKeys.length } + } + const publicKeys = [...existing.publicKeys, mine] + document.signing = { publicKeys } + // Preserve the leading header comment; `stringify` would otherwise drop it. + const header = text.startsWith('#') ? `${text.slice(0, text.indexOf('\n') + 1)}` : '' + await writeFile(path, `${header}${stringify(document)}`, 'utf8') + return { status: 'added', fingerprint: key.fingerprint, total: publicKeys.length } +} diff --git a/packages/cli/src/hook-runtime.ts b/packages/cli/src/hook-runtime.ts index 89418e5..eddb61b 100644 --- a/packages/cli/src/hook-runtime.ts +++ b/packages/cli/src/hook-runtime.ts @@ -365,7 +365,11 @@ function frozenConfig(config: CliConfig): CliConfig { ...(config.llm.model ? { model: config.llm.model } : {}), maxDiffBytes: config.llm.maxDiffBytes, }, - signing: { ...(config.signing.publicKey ? { publicKey: config.signing.publicKey } : {}) }, + signing: { + ...(config.signing.publicKey ? { publicKey: config.signing.publicKey } : {}), + // Freeze the whole trusted set: a repository may pin one key per developer. + publicKeys: [...config.signing.publicKeys], + }, sync: { url: config.sync.url }, } } @@ -390,6 +394,7 @@ function validateHookTurnContext(value: unknown): HookTurnContext { || (config.llm.provider !== undefined && !['anthropic', 'openai', 'claude', 'codex'].includes(config.llm.provider)) || (config.llm.model !== undefined && typeof config.llm.model !== 'string') || !config.signing || (config.signing.publicKey !== undefined && typeof config.signing.publicKey !== 'string') + || !isStringArray(config.signing.publicKeys) || !config.sync || typeof config.sync.url !== 'string' || !isStringArray(context.baselineDirtyFiles)) { throw new Error('hook turn context is invalid') @@ -1214,9 +1219,30 @@ function inputTurnId(input: HookInput): string | undefined { return turnId } +/** + * The receipt's Task line is its primary human-readable field, and the first + * thing a reviewer (or a client receiving the receipt) reads. Agent harnesses + * deliver machine events — background-task notifications, tool results — on the + * same prompt channel as human instructions, and reproducing that XML verbatim + * leaves the headline field unreadable. Keep human prompts exactly as written; + * reduce a structured system event to its summary, labelled by its event tag. + * + * Deterministic: capture and prompt-time verification derive the task the same + * way, so turn binding is unaffected. + */ +function readableTask(prompt: string): string { + const trimmed = prompt.trim() + if (!trimmed.startsWith('<')) return trimmed + const tag = /^<([A-Za-z][\w-]*)/.exec(trimmed)?.[1] + if (!tag) return trimmed + const summary = /([\s\S]*?)<\/summary>/i.exec(trimmed)?.[1]?.replace(/\s+/g, ' ').trim() + return summary ? `[${tag}] ${summary}` : `[${tag}]` +} + function inputTask(input: HookInput): string | undefined { const prompt = asNonEmptyString(input.prompt) - return prompt?.slice(0, MAX_TASK_CHARS) + if (!prompt) return undefined + return asNonEmptyString(readableTask(prompt).slice(0, MAX_TASK_CHARS)) } type NamedLockName = 'capture.lock' | 'stop.lock' | 'migration.lock' @@ -1507,11 +1533,48 @@ function normalizeHookPath(root: string, cwd: string | undefined, inputPath: str return { path: candidate } } -function fastPathFeedback( +/** + * Warnings already surfaced during this turn. An always-on guardrail earns its + * place by being felt, not heard: repeating an identical notice on every tool + * call is what makes a developer uninstall it. Fail-soft by design — if turn + * state cannot be read or written, every warning is emitted as before, because + * a missed warning is worse than a duplicated one. + */ +async function alreadyNotified( root: string, + surface: AgentHookSurface, + input: HookInput, + warnings: string[], +): Promise<{ fresh: string[]; persist?: () => Promise }> { + const sessionId = asNonEmptyString(input.session_id) + if (!sessionId) return { fresh: warnings } + try { + const prepared = await gitStateRoot(root, surface, sessionId) + if (prepared.legacyBlockReason) return { fresh: warnings } + const sessionDir = sessionStateDir(prepared.base, surface, sessionId) + const { turnDir } = await readStopSelector(sessionDir) + const file = join(turnDir, 'fast-path-notified.json') + const seen = (await readBoundedRegularJson(file, MAX_SELECTOR_BYTES)) as unknown + const previous = isStringArray(seen) ? seen : [] + const fresh = warnings.filter((warning) => !previous.includes(warning)) + if (fresh.length === 0) return { fresh } + return { + fresh, + persist: async () => { + await writePrivateJson(file, [...previous, ...fresh].slice(-200)) + }, + } + } catch { + return { fresh: warnings } + } +} + +async function fastPathFeedback( + root: string, + surface: AgentHookSurface, input: HookInput, config: CliConfig, -): HookOutput | undefined { +): Promise { const cwd = asNonEmptyString(input.cwd) const rawPaths = [ ...stringsAtKnownPathKeys(input.tool_input), @@ -1533,7 +1596,10 @@ function fastPathFeedback( } for (const path of outside) warnings.push(`${path}: resolves outside the repository`) if (warnings.length === 0) return undefined - return postToolFeedback(`CodeTruss fast scope check:\n${warnings.map((warning) => `- ${warning}`).join('\n')}\nA full analyzer receipt will run once when this turn stops.`) + const { fresh, persist } = await alreadyNotified(root, surface, input, warnings) + if (fresh.length === 0) return undefined + await persist?.().catch(() => undefined) + return postToolFeedback(`CodeTruss fast scope check:\n${fresh.map((warning) => `- ${warning}`).join('\n')}\nA full analyzer receipt will run once when this turn stops.`) } export function hookReviewEnvironment( @@ -2046,7 +2112,7 @@ export async function handleAgentHook( ): Promise { const event = hookEvent(input) if (event === 'UserPromptSubmit') return capturePromptBaseline(root, surface, input, config, dependencies) - if (event === 'PostToolUse') return fastPathFeedback(root, input, config) + if (event === 'PostToolUse') return fastPathFeedback(root, surface, input, config) if (event === 'Stop') { try { return await reviewAtStop(root, surface, input, dependencies) diff --git a/packages/cli/src/receipt.ts b/packages/cli/src/receipt.ts index e5003d8..ecc9a0f 100644 --- a/packages/cli/src/receipt.ts +++ b/packages/cli/src/receipt.ts @@ -81,7 +81,48 @@ function legacyScoreLines(receipt: Receipt): string[] { ] } +/** + * The omitted passes named as detection gaps, not as a scoring footnote. + * + * Earlier wording reported the omission only through "Hosted Health scores: + * N/A", which a developer reads as "no score" — not as "injection was never + * checked". A receipt is evidence of what ran, so the absent passes get their + * own section, named as the detection they cost rather than the number. + */ function analysisProfileLines(receipt: Receipt): string[] { + const current = 'analysisProfile' in receipt.analyzers && receipt.analyzers.analysisProfile + return [ + '## Analysis profile', + '', + ...(current ? [ + `Profile: \`${current.id}\`.`, + '', + 'The 13 deterministic registry analyzers ran locally on this machine.', + ] : [ + 'Legacy local receipt. Earlier CLI versions emitted numeric scores without hosted graph and SAST; those values are suppressed.', + ]), + '', + '### What did not run', + '', + '- **Security static analysis (SAST).** No injection or taint analysis was performed. SQL injection, command injection, code injection, path traversal, SSRF, open redirect, XSS and insecure deserialization were never checked, so this receipt says nothing either way about those classes.', + '- **Hosted symbol graph.** No cross-file call or data-flow graph was built, so architecture and dead-code conclusions cover only what the local passes can see in isolation.', + ...(receipt.llm ? [] : [ + '- **Optional LLM review.** No model read this diff. It is opt-in via `--llm` and is force-disabled under agent hooks, so a hook receipt is always deterministic evidence only.', + ]), + '- **Hosted Health scores.** Not calculated, reported as **N/A**. The scores are defined over the graph and SAST passes; a number derived from this pass set would overstate what ran.', + '', + 'A PASS verdict means the passes listed above never ran and the passes that did run found nothing new. It is not a statement that this change is secure.', + '', + '[Run a hosted full audit](https://codetruss.com/dashboard/repos/new?source=cli-receipt).', + ] +} + +/** + * The profile block exactly as CLI 0.2.28 and earlier wrote it. Kept verbatim + * so `codetruss verify` still reproduces Markdown that was signed before the + * disclosure was reworded; the signed JSON is unchanged, only its rendering. + */ +function priorProfileLines(receipt: Receipt): string[] { const current = 'analysisProfile' in receipt.analyzers && receipt.analyzers.analysisProfile return [ '## Analysis profile', @@ -100,7 +141,16 @@ function analysisProfileLines(receipt: Receipt): string[] { ] } -function renderMarkdownInternal(receipt: Receipt, preserveLegacyScores: boolean): string { +/** Which historical rendering of the analysis block to reproduce. */ +type ReceiptMarkdownVariant = 'current' | 'legacy-scores' | 'prior-profile' + +function analysisLines(receipt: Receipt, variant: ReceiptMarkdownVariant): string[] { + if (variant === 'legacy-scores') return legacyScoreLines(receipt) + if (variant === 'prior-profile') return priorProfileLines(receipt) + return analysisProfileLines(receipt) +} + +function renderMarkdownInternal(receipt: Receipt, variant: ReceiptMarkdownVariant): string { const lines = [ `# CodeTruss receipt — ${receipt.verdict}`, '', @@ -130,7 +180,7 @@ function renderMarkdownInternal(receipt: Receipt, preserveLegacyScores: boolean) '|---|---|---|---|', ...receipt.analyzers.findings.slice(0, 100).map((finding) => `| ${finding.severity} | ${finding.analyzerId ?? 'unknown'} | ${finding.filePath ? `\`${finding.filePath}${finding.line ? `:${finding.line}` : ''}\`` : 'repository'} | ${finding.title.replaceAll('|', '\\|')} |`), '', - ...(preserveLegacyScores ? legacyScoreLines(receipt) : analysisProfileLines(receipt)), + ...analysisLines(receipt, variant), ...(receipt.analyzers.delta ? [ `Finding delta: ${receipt.analyzers.delta.introduced} introduced, ${receipt.analyzers.delta.worsened} worsened, ${receipt.analyzers.delta.recurring} recurring, ${receipt.analyzers.delta.resolved} resolved.`, ] : []), @@ -159,12 +209,17 @@ function renderMarkdownInternal(receipt: Receipt, preserveLegacyScores: boolean) /** Render the current honest local profile, including when displaying a legacy receipt. */ export function renderMarkdown(receipt: Receipt): string { - return renderMarkdownInternal(receipt, false) + return renderMarkdownInternal(receipt, 'current') } /** Byte-compatible renderer used only to verify Markdown written by older receipt-v1 clients. */ export function renderLegacyMarkdown(receipt: Receipt): string { - return renderMarkdownInternal(receipt, true) + return renderMarkdownInternal(receipt, 'legacy-scores') +} + +/** Byte-compatible renderer for profile receipts signed before the disclosure was reworded. */ +export function renderPriorProfileMarkdown(receipt: Receipt): string { + return renderMarkdownInternal(receipt, 'prior-profile') } async function writePrivateAtomic(path: string, value: string | Buffer): Promise { @@ -216,7 +271,7 @@ export async function resolveReceipt(dir: string, id = 'latest'): Promise<{ rece return { receipt: JSON.parse(await readFile(jsonPath, 'utf8')) as Receipt, jsonPath } } -export async function verifyReceipt(dir: string, id = 'latest', pinnedPublicKey?: string): Promise { +export async function verifyReceipt(dir: string, id = 'latest', pinnedPublicKey?: string | string[]): Promise { const { receipt, jsonPath } = await resolveReceipt(dir, id) if (receipt.git && ![receipt.git.baselineTree, receipt.git.finalTree].every((oid) => /^[0-9a-f]{40}(?:[0-9a-f]{24})?$/.test(oid))) { throw new Error('receipt evidence tree object id is invalid') @@ -225,21 +280,34 @@ export async function verifyReceipt(dir: string, id = 'latest', pinnedPublicKey? throw new Error('receipt policy SHA-256 is invalid') } if (!receipt.evidence.publicKey || !receipt.evidence.signatureFile) throw new Error('receipt is unsigned') - const trustedPublicKey = pinnedPublicKey ? normalizePublicKey(pinnedPublicKey) : (await loadSigningKey()).publicKey + // A repository may trust several signers (one per developer). The receipt is + // valid when its embedded key is one of them, and the signature is then + // checked against that exact key — so a teammate's receipt verifies without + // anyone sharing a private key. + const pins = Array.isArray(pinnedPublicKey) ? pinnedPublicKey : pinnedPublicKey ? [pinnedPublicKey] : [] + const trustedPublicKeys = pins.length > 0 + ? pins.map((pin) => normalizePublicKey(pin)) + : [(await loadSigningKey()).publicKey] const embeddedPublicKey = normalizePublicKey(receipt.evidence.publicKey) const embeddedFingerprint = publicKeyFingerprint(embeddedPublicKey) - const trustedFingerprint = publicKeyFingerprint(trustedPublicKey) + const trustedFingerprints = trustedPublicKeys.map((key) => publicKeyFingerprint(key)) if (receipt.evidence.keyFingerprint !== embeddedFingerprint) throw new Error('receipt signing fingerprint does not match its public key') - if (embeddedFingerprint !== trustedFingerprint) { - throw new Error(`receipt signer ${embeddedFingerprint} does not match trusted key ${trustedFingerprint}`) + if (!trustedFingerprints.includes(embeddedFingerprint)) { + throw new Error(`receipt signer ${embeddedFingerprint} does not match trusted key ${trustedFingerprints.join(', ')}`) } + const trustedPublicKey = trustedPublicKeys[trustedFingerprints.indexOf(embeddedFingerprint)] const jsonBytes = await readFile(jsonPath) const signature = (await readFile(join(dir, receipt.evidence.signatureFile), 'utf8')).trim() if (!verifyBytes(jsonBytes, trustedPublicKey, signature)) throw new Error('receipt signature does not match') const markdown = await readFile(join(dir, `${receipt.sessionId}.md`), 'utf8') - const currentMarkdown = renderMarkdown(receipt) - const legacyMarkdown = !('analysisProfile' in receipt.analyzers) ? renderLegacyMarkdown(receipt) : null - if (markdown !== currentMarkdown && markdown !== legacyMarkdown) throw new Error('Markdown receipt does not match the signed JSON') + // Every rendering this exact signed JSON could legitimately have produced. + // Rewording a disclosure must not invalidate receipts already on disk, so + // each superseded wording stays reproducible for verification only. + const accepted = [ + renderMarkdown(receipt), + 'analysisProfile' in receipt.analyzers ? renderPriorProfileMarkdown(receipt) : renderLegacyMarkdown(receipt), + ] + if (!accepted.includes(markdown)) throw new Error('Markdown receipt does not match the signed JSON') if (sha256(markdown) !== receipt.evidence.markdownSha256) throw new Error('Markdown receipt hash does not match') if (receipt.evidence.patchFile) { const patch = await readFile(join(dir, receipt.evidence.patchFile)) diff --git a/packages/cli/src/setup.ts b/packages/cli/src/setup.ts index 7e133e6..3ebbbca 100644 --- a/packages/cli/src/setup.ts +++ b/packages/cli/src/setup.ts @@ -88,7 +88,18 @@ async function resolveAllowGlobs( if (explicit?.length) return explicit const suggestions = await suggestedAllowGlobs(root) if (yes) { - throw new Error('non-interactive setup requires at least one explicit --allow "src/**" value') + // Plug and play: an unattended run on an ordinary repository should end up + // protected rather than stopped to look up glob syntax. Only conventional + // roots that actually exist on disk are adopted, never a repository-wide + // glob, and the choice is printed so an unattended decision stays + // auditable. Verification-command trust is the genuinely dangerous + // decision and is still withheld unless --trust-verify is passed. + const detected = suggestions.filter((glob) => !repositoryWide(glob)) + if (!detected.length) { + throw new Error('non-interactive setup requires at least one explicit --allow "src/**" value') + } + write(`Adopted detected allowed change roots: ${detected.join(', ')}\n`) + return detected } if (suggestions.length) { @@ -164,9 +175,17 @@ export async function guidedSetup(root: string, options: GuidedSetupOptions = {} } else { const selectedAllow = await resolveAllowGlobs(root, allow, yes, ask, write) const selectedDeny = deny ?? [] + // Unattended setup must never record commands it has no permission to + // run: an untrusted verify list makes every later review exit 3 with no + // receipt, which is worse than having no verification configured. + // Only when hooks will actually be installed: with --hooks none there is + // nothing to block, and recording untrusted commands for later inspection + // is the point of that flow. + const withheldVerify = yes && !options.trustVerify && requestedHooks !== 'none' const path = await initialize(root, false, { allow: selectedAllow, deny: selectedDeny, + ...(withheldVerify ? { verify: [] } : {}), }) write(`Saved policy: ${path}\n`) } @@ -199,7 +218,7 @@ export async function guidedSetup(root: string, options: GuidedSetupOptions = {} await trustVerifyCommands(root, config.verify) write('Trusted the exact verification command list shown above.\n') } else if (yes) { - throw new Error('automatic setup will not trust repository commands via --yes; inspect the commands above and rerun with --trust-verify') + write('Verification commands are NOT trusted and were left out of the policy; inspect them, then run codetruss verify-policy trust (or rerun setup with --trust-verify) to enable them.\n') } else { const approval = await ask('Type "trust" to approve this exact command list for automatic checks: ') if (approval.trim().toLowerCase() !== 'trust') { diff --git a/packages/cli/src/signing.ts b/packages/cli/src/signing.ts index c4a4046..892bc35 100644 --- a/packages/cli/src/signing.ts +++ b/packages/cli/src/signing.ts @@ -55,13 +55,23 @@ export async function loadSigningKey(create = false): Promise { return { privateKey, publicKey, fingerprint: publicKeyFingerprint(publicKey) } } -export async function requireTrustedSigningKey(pinnedPublicKey?: string): Promise { +/** + * The repository pin is a SET of trusted signers, so each developer signs with + * their own key and keeps per-signer attribution. The failure message must + * never suggest obtaining someone else's private key — that would destroy the + * attribution the receipt exists to provide. + */ +export async function requireTrustedSigningKey(pinnedPublicKey?: string | string[]): Promise { const key = await loadSigningKey(true) - if (pinnedPublicKey) { - const pinnedFingerprint = publicKeyFingerprint(pinnedPublicKey) - if (pinnedFingerprint !== key.fingerprint) { + const pins = (Array.isArray(pinnedPublicKey) ? pinnedPublicKey : [pinnedPublicKey]).filter( + (pin): pin is string => typeof pin === 'string' && pin.trim().length > 0, + ) + if (pins.length > 0) { + const fingerprints = pins.map((pin) => publicKeyFingerprint(pin)) + if (!fingerprints.includes(key.fingerprint)) { throw new Error( - `local signing key ${key.fingerprint} does not match repository pin ${pinnedFingerprint}; set CODETRUSS_SIGNING_KEY to the trusted private key`, + `this repository trusts ${fingerprints.join(', ')} but your local signing key is ${key.fingerprint}; ` + + 'add yours with codetruss verify-policy trust-key (or have a maintainer append it to signing.publicKeys)', ) } } diff --git a/packages/cli/src/types.ts b/packages/cli/src/types.ts index b04d8a0..0cee623 100644 --- a/packages/cli/src/types.ts +++ b/packages/cli/src/types.ts @@ -32,7 +32,13 @@ export interface CliConfig { model?: string maxDiffBytes: number } - signing: { publicKey?: string } + /** + * Pinned signer identities. A repository is worked on by more than one + * developer, so the pin is a SET: `publicKeys` lists every trusted signer and + * `publicKey` is its first entry, kept for the single-signer config shape and + * for the hook turn context. + */ + signing: { publicKey?: string; publicKeys: string[] } sync: { url: string } } diff --git a/packages/cli/test/analysis-profile.test.ts b/packages/cli/test/analysis-profile.test.ts index 552201a..1733652 100644 --- a/packages/cli/test/analysis-profile.test.ts +++ b/packages/cli/test/analysis-profile.test.ts @@ -41,4 +41,34 @@ describe('honest local analysis profile', () => { expect(evidence).not.toHaveProperty('baselineScores') expect(JSON.stringify(evidence)).not.toContain('"security"') }) + + it('discloses the absent SAST pass on the TypeScript repos where it used to stay silent', async () => { + const root = await mkdtemp(join(tmpdir(), 'codetruss-local-sast-gap-')) + cleanup.push(root) + await mkdir(join(root, 'src')) + // A repo large enough to draw coverage conclusions, entirely in a language + // the SAST engine covers — the exact shape that produced zero coverage + // findings while the injection rules never ran. + for (let unit = 0; unit < 8; unit += 1) { + const body = Array.from({ length: 50 }, (_, line) => ` const value${line} = ${line} * ${unit + 1}`) + await writeFile( + join(root, 'src', `unit-${unit}.ts`), + [`export function unit${unit}(): number {`, ...body, ' return value0', '}', ''].join('\n'), + ) + } + + const analysis = await analyzeRepository(root) + const coverage = analysis.passes.find((pass) => pass.id === 'coverage') + expect(coverage?.result.findings).toHaveLength(1) + const finding = coverage!.result.findings[0] + expect(finding.category).toBe('SECURITY_HYGIENE') + expect(finding.severity).toBe('INFO') + expect(finding.title).toMatch(/did not run/i) + expect(finding.description).toMatch(/SQL injection/) + expect(finding.metadata).toMatchObject({ sastPassRan: false, sastLanguages: ['TypeScript'] }) + // A disclosure, never a blocking accusation: the local verdict must not + // fail a change because a pass was absent. + expect(finding.severity).not.toBe('HIGH') + expect(finding.severity).not.toBe('CRITICAL') + }) }) diff --git a/packages/cli/test/command-e2e.test.ts b/packages/cli/test/command-e2e.test.ts index 2ffc5e9..f478bff 100644 --- a/packages/cli/test/command-e2e.test.ts +++ b/packages/cli/test/command-e2e.test.ts @@ -83,6 +83,38 @@ describe('CLI snapshot and delta enforcement', () => { expect(config).toMatch(/allow:\n\s+- src\/\*\*\n\s+- tests\/\*\*/) }, 30_000) + it('adopts detected source roots for unattended setup instead of demanding a flag', async () => { + // Plug and play: a developer who runs `codetruss setup --yes` on an ordinary + // repo should end up protected, not stopped to look up glob syntax. The + // chosen scope is printed so an unattended decision stays auditable. + const root = await repository() + await mkdir(join(root, 'src')) + await mkdir(join(root, 'tests')) + await installPersistentCliFixture(root) + await writeFile(join(root, '.gitignore'), '/node_modules\n') + + const setup = runCli(root, ['setup', '--yes'], {}) + + expect(setup.status, `${setup.stderr}\n${setup.stdout}`).toBe(0) + expect(setup.stdout).toContain('src/**') + const config = await readFile(join(root, '.codetruss.yml'), 'utf8') + expect(config).toMatch(/allow:\n\s+- src\/\*\*\n\s+- tests\/\*\*/) + // Command trust is the genuinely dangerous decision and must NOT be implied. + expect(config).not.toMatch(/^verify:\n\s+-/m) + }, 30_000) + + it('still refuses unattended setup when no conventional source root exists', async () => { + // With nothing to detect, guessing would be worse than asking. + const root = await repository() + await installPersistentCliFixture(root) + await writeFile(join(root, '.gitignore'), '/node_modules\n') + + const setup = runCli(root, ['setup', '--yes'], {}) + + expect(setup.status).toBe(3) + expect(`${setup.stderr}${setup.stdout}`).toContain('--allow') + }, 30_000) + it('completes idempotent local-only setup and keeps generated evidence out of normal staging', async () => { const root = await repository() await mkdir(join(root, 'src')) diff --git a/packages/cli/test/config.test.ts b/packages/cli/test/config.test.ts index 8b48d16..cb3559d 100644 --- a/packages/cli/test/config.test.ts +++ b/packages/cli/test/config.test.ts @@ -1,7 +1,9 @@ import { mkdir, mkdtemp, readFile, symlink, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { generateKeyPairSync } from 'node:crypto' import { afterEach, describe, expect, it } from 'vitest' +import { loadSigningKey, requireTrustedSigningKey } from '../src/signing.js' import { APPROVED_RECEIPT_DIR, PRODUCTION_SYNC_ORIGIN, @@ -120,3 +122,53 @@ describe('initialization', () => { } }) }) + +/** + * A committed .codetruss.yml pins the signing key. With a single-key pin, every + * teammate who clones gets exit 3 and no receipt, and the old error told them to + * "set CODETRUSS_SIGNING_KEY to the trusted private key" — i.e. to obtain a + * colleague's private key, which destroys the per-signer attribution the receipt + * exists to provide. Bad advice from a security product. + */ +describe('multi-developer signing pins', () => { + it('accepts a publicKeys list and keeps publicKey as the first entry', async () => { + const root = await mkdtemp(join(tmpdir(), 'codetruss-multikey-')) + process.env.CODETRUSS_SIGNING_KEY = join(root, 'signing.pem') + const a = generateKeyPairSync('ed25519').publicKey.export({ type: 'spki', format: 'pem' }).toString() + const b = generateKeyPairSync('ed25519').publicKey.export({ type: 'spki', format: 'pem' }).toString() + await writeFile( + join(root, '.codetruss.yml'), + `allow: ["src/**"]\nsigning:\n publicKeys:\n - |\n${a.trimEnd().split('\n').map((l) => ` ${l}`).join('\n')}\n - |\n${b.trimEnd().split('\n').map((l) => ` ${l}`).join('\n')}\n`, + 'utf8', + ) + const config = await loadConfig(root) + expect(config.signing.publicKeys).toHaveLength(2) + expect(config.signing.publicKey).toBe(config.signing.publicKeys[0]) + }) + + it('still accepts a single legacy publicKey', async () => { + const root = await mkdtemp(join(tmpdir(), 'codetruss-singlekey-')) + process.env.CODETRUSS_SIGNING_KEY = join(root, 'signing.pem') + await initialize(root) + const config = await loadConfig(root) + expect(config.signing.publicKeys).toHaveLength(1) + expect(config.signing.publicKeys[0]).toContain('BEGIN PUBLIC KEY') + expect(config.signing.publicKey).toBe(config.signing.publicKeys[0]) + }) + + it('trusts any pinned key and never tells the reader to obtain a private key', async () => { + const root = await mkdtemp(join(tmpdir(), 'codetruss-trust-')) + process.env.CODETRUSS_SIGNING_KEY = join(root, 'signing.pem') + const mine = await loadSigningKey(true) + const teammate = generateKeyPairSync('ed25519').publicKey.export({ type: 'spki', format: 'pem' }).toString() + + // My key is in the pinned set alongside a teammate's: allowed. + await expect(requireTrustedSigningKey([teammate, mine.publicKey])).resolves.toMatchObject({ + fingerprint: mine.fingerprint, + }) + + // My key is absent: rejected, but the guidance must not be "get their key". + await expect(requireTrustedSigningKey([teammate])).rejects.toThrow(/verify-policy trust-key/) + await expect(requireTrustedSigningKey([teammate])).rejects.not.toThrow(/private key/) + }) +}) diff --git a/packages/cli/test/hooks.test.ts b/packages/cli/test/hooks.test.ts index 9e55b06..8fd9f3b 100644 --- a/packages/cli/test/hooks.test.ts +++ b/packages/cli/test/hooks.test.ts @@ -824,7 +824,8 @@ describe('exact immutable hook snapshots', () => { [CODETRUSS_HOOK_SURFACE_ENV]: 'codex', CODETRUSS_HOOK_START_COMMIT: git(root, 'rev-parse', 'HEAD'), CODETRUSS_HOOK_END_COMMIT: git(root, 'rev-parse', 'HEAD'), - CODETRUSS_HOOK_STARTED_AT: '2026-07-14T10:00:00.000Z', + // the spawned CLI checks this against the real clock, so it must stay recent + CODETRUSS_HOOK_STARTED_AT: new Date(Date.now() - 5 * 60_000).toISOString(), [CODETRUSS_EVIDENCE_OBJECT_DIRECTORY_ENV]: store.objectDirectory, [CODETRUSS_HOOK_CONTEXT_PATH_ENV]: contextPath, [CODETRUSS_HOOK_CONTEXT_SHA256_ENV]: contextSha256, @@ -1000,6 +1001,69 @@ describe('agent hook runtime', () => { }, config())).resolves.toBeUndefined() }) + it('reports each scope warning once per turn instead of on every tool call', async () => { + // The guardrail should be felt, not heard. Repeating the identical warning + // on every edit is what makes an always-on hook annoying enough to remove — + // but the first notice must still arrive, and a NEW path must still speak. + const root = await repo() + await writeConfig(root) + const prompt = { session_id: 'session-quiet', turn_id: 'turn-q', hook_event_name: 'UserPromptSubmit', prompt: 'Edit things', cwd: root } + await handleAgentHook(root, 'claude', prompt, config(['src/**'])) + + const edit = (file: string) => handleAgentHook(root, 'claude', { + session_id: 'session-quiet', turn_id: 'turn-q', hook_event_name: 'PostToolUse', cwd: root, + tool_input: { file_path: file }, + }, config(['src/**'])) + + const first = await edit(join(root, 'infra', 'deploy.tf')) + expect(JSON.stringify(first)).toContain('outside the allowed task scope') + + // Same path again in the same turn: already said, stay quiet. + const repeat = await edit(join(root, 'infra', 'deploy.tf')) + expect(repeat).toBeUndefined() + + // A different out-of-scope path is new information and must be surfaced. + const other = await edit(join(root, 'infra', 'secrets.tf')) + expect(JSON.stringify(other)).toContain('secrets.tf') + }) + + it('records a readable task when the harness delivers a machine event, not a human prompt', async () => { + // Agent harnesses push background-task notifications and tool results down + // the same prompt channel. Dumping that XML verbatim makes the receipt's + // headline Task field unreadable — the exact thing a reviewer reads first. + const root = await repo() + await writeConfig(root) + const receipt = join(root, '.codetruss', 'receipts', 'hook.md') + await mkdir(join(root, '.codetruss', 'receipts'), { recursive: true }) + await writeFile(receipt, '# receipt\n') + const requests: HookReviewRequest[] = [] + const runReview = vi.fn(async (request: HookReviewRequest) => { + requests.push(request) + return hookReviewResponse(request, 'PASS', 0, receipt) + }) + const dependencies = { runReview, now: () => new Date() } + await mkdir(join(root, 'src'), { recursive: true }) + await writeFile(join(root, 'src', 'value.ts'), 'export const value = "before"\n') + const notification = [ + '', + 'b2eypo7jv', + 'toolu_01Pqm3pu4ubbnSdKf4jJtCjR', + 'completed', + 'Background command "Wait for production to serve CLI 0.2.25" completed (exit code 0)', + '', + ].join('\n') + const prompt = { session_id: 'session-evt', turn_id: 'turn-evt', hook_event_name: 'UserPromptSubmit', prompt: notification, cwd: root } + await expect(handleAgentHook(root, 'codex', prompt, config(['src/**']), dependencies)).resolves.toBeUndefined() + await writeFile(join(root, 'src', 'value.ts'), 'export const value = "after"\n') + await handleAgentHook(root, 'codex', { ...prompt, hook_event_name: 'Stop', background_tasks: [] }, config(['src/**']), dependencies) + + expect(runReview).toHaveBeenCalledTimes(1) + const task = requests[0]!.context.task + expect(task).not.toContain('') + expect(task).not.toContain('toolu_') + expect(task).toContain('Wait for production to serve CLI 0.2.25') + }) + it('captures once, waits for background tasks, reviews immutable final evidence once, and lets PASS stop quietly', async () => { const root = await repo() await writeConfig(root) diff --git a/packages/cli/test/policy-fingerprint.test.ts b/packages/cli/test/policy-fingerprint.test.ts index 3df5edc..eeb1353 100644 --- a/packages/cli/test/policy-fingerprint.test.ts +++ b/packages/cli/test/policy-fingerprint.test.ts @@ -9,7 +9,7 @@ const config: CliConfig = { verify: [], receipts: { dir: '.codetruss/receipts' }, llm: { provider: 'claude', model: 'default', maxDiffBytes: 100_000 }, - signing: {}, + signing: { publicKeys: [] }, sync: { url: 'https://codetruss.com' }, } diff --git a/packages/cli/test/policy-verdict.test.ts b/packages/cli/test/policy-verdict.test.ts index 3fe90e1..85970e7 100644 --- a/packages/cli/test/policy-verdict.test.ts +++ b/packages/cli/test/policy-verdict.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest' import { classifyPath, isDependencyFile, sensitiveCategory } from '../src/policy.js' -import { analysisEvidenceIssues, computeVerdict, diffFindings } from '../src/analysis.js' -import type { AnalyzerFinding, AnalyzerPass } from '@codetruss/analyzer-engine' +import { analysisCoverageNotes, analysisEvidenceIssues, computeVerdict, diffFindings } from '../src/analysis.js' +import type { AnalyzerFinding, AnalyzerPass, IndexCoverage } from '@codetruss/analyzer-engine' describe('scope and sensitive policy', () => { it('is fail closed, gives deny precedence, and protects rename origins', () => { @@ -113,3 +113,58 @@ describe('analyzer finding deltas', () => { }) }) }) + +/** + * A >1MB lockfile is ordinary in real repos. Failing a developer's FIRST + * receipt over one file the agent never touched — with a reason naming no file + * and no fix — reads as "this tool is broken". The hosted pipeline already + * solved this (AUTHORITATIVE_COVERAGE_RATIO in src/lib/scans/analysis.ts); the + * CLI applied zero tolerance to the identical IndexCoverage signal. + */ +describe('immaterial index coverage loss', () => { + const coverage = (over: Partial): IndexCoverage => ({ + discoveredFiles: 100, + maxFiles: 5000, + truncated: false, + textCandidates: 100, + contentLoaded: 100, + oversizedTextFiles: 0, + unreadableTextFiles: 0, + binaryTextFiles: 0, + ...over, + }) + const passes = [{ id: 'secrets', result: { findings: [], complete: true } }] satisfies AnalyzerPass[] + const inScope = { path: 'src/a.ts', change: 'modified', classification: 'allowed', dependency: false, additions: 1, deletions: 0 } as const + + it('does not block on one oversized file in an otherwise fully read repo', () => { + const c = coverage({ contentLoaded: 99, oversizedTextFiles: 1 }) + expect(analysisEvidenceIssues(passes, c)).toEqual([]) + const notes = analysisCoverageNotes(c) + expect(notes).toHaveLength(1) + // The reason must name the escape hatch, not just the symptom. + expect(notes[0]).toContain('CODETRUSS_MAX_INDEX_FILE_BYTES') + }) + + it('still blocks when a real share of the repo went unread', () => { + const c = coverage({ contentLoaded: 50, oversizedTextFiles: 50 }) + expect(analysisEvidenceIssues(passes, c).length).toBeGreaterThan(0) + expect(analysisCoverageNotes(c)).toEqual([]) + }) + + it('still blocks when the file walk hit its bound (no measurable denominator)', () => { + const c = coverage({ truncated: true }) + expect(analysisEvidenceIssues(passes, c).length).toBeGreaterThan(0) + }) + + it('routes an immaterial coverage note to REVIEW_REQUIRED, not FAILED', () => { + const result = computeVerdict({ + agentExitCode: 0, + verifications: [], + files: [inScope], + startDirty: false, + findings: [], + advisoryEvidenceIssues: analysisCoverageNotes(coverage({ contentLoaded: 99, oversizedTextFiles: 1 })), + }) + expect(result.verdict).toBe('REVIEW_REQUIRED') + }) +}) diff --git a/packages/cli/test/receipt.test.ts b/packages/cli/test/receipt.test.ts index 8076491..4a00974 100644 --- a/packages/cli/test/receipt.test.ts +++ b/packages/cli/test/receipt.test.ts @@ -3,7 +3,7 @@ import { mkdtemp, readFile, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { basename, join } from 'node:path' import { afterEach, describe, expect, it } from 'vitest' -import { createSyncEnvelope, hookSessionId, newSessionId, renderLegacyMarkdown, renderMarkdown, verifyReceipt, writeReceipt } from '../src/receipt.js' +import { createSyncEnvelope, hookSessionId, newSessionId, renderLegacyMarkdown, renderMarkdown, renderPriorProfileMarkdown, verifyReceipt, writeReceipt } from '../src/receipt.js' import { loadSigningKey, sha256, signBytes, verifyBytes } from '../src/signing.js' import { LOCAL_ANALYSIS_PROFILE, type Receipt } from '../src/types.js' @@ -59,8 +59,6 @@ describe('signed receipts', () => { const markdown = await readFile(paths.markdown, 'utf8') expect(markdown).toContain('Policy SHA-256') expect(markdown).toContain('Profile: `local-registry-v1`') - expect(markdown).toContain('Hosted Health scores: **N/A**') - expect(markdown).toContain('Hosted graph and SAST passes were omitted') expect(markdown).not.toContain('Final scores:') await writeFile(paths.markdown, `${await readFile(paths.markdown, 'utf8')}tampered`) await expect(verifyReceipt(dir, receipt.sessionId)).rejects.toThrow('Markdown receipt does not match') @@ -83,10 +81,59 @@ describe('signed receipts', () => { const verified = await verifyReceipt(dir, receipt.sessionId) expect(oldMarkdown).toContain('Final scores: health 100') expect(renderMarkdown(verified)).toContain('Legacy local receipt') - expect(renderMarkdown(verified)).toContain('Hosted Health scores: **N/A**') + expect(renderMarkdown(verified)).toContain('**Hosted Health scores.** Not calculated, reported as **N/A**') expect(renderMarkdown(verified)).not.toContain('security 100') }) + it('names the omitted passes as detection gaps rather than a missing score', () => { + const markdown = renderMarkdown(fixture('/tmp/repo')) + const disclosure = markdown.slice(markdown.indexOf('### What did not run')) + + expect(markdown).toContain('### What did not run') + // The gap a developer must not misread: injection was never examined. + expect(disclosure).toContain('**Security static analysis (SAST).**') + expect(disclosure).toMatch(/SQL injection.*command injection.*path traversal/) + expect(disclosure).toContain('says nothing either way about those classes') + expect(disclosure).toContain('**Hosted symbol graph.**') + expect(disclosure).toContain('**Optional LLM review.**') + expect(disclosure).toContain('force-disabled under agent hooks') + // Never an accusation: the receipt reports what ran, not a verdict on the code. + expect(disclosure).not.toMatch(/vulnerab|insecure code|unsafe/i) + expect(markdown).toContain('It is not a statement that this change is secure.') + }) + + it('does not list the LLM review as omitted when a model actually reviewed the diff', () => { + const receipt = fixture('/tmp/repo') + receipt.llm = { + provider: 'anthropic', transmittedBytes: 10, + diffCoverage: { reviewedBytes: 13, totalBytes: 13, truncated: false }, + verdict: 'clean', summary: 'Nothing notable.', findings: [], + } + const markdown = renderMarkdown(receipt) + expect(markdown).toContain('### What did not run') + expect(markdown).not.toContain('**Optional LLM review.** No model read this diff') + expect(markdown).toContain('## Optional LLM review') + }) + + it('still verifies a profile receipt whose Markdown carries the superseded wording', async () => { + const root = await mkdtemp(join(tmpdir(), 'codetruss-prior-profile-receipt-')) + const dir = join(root, 'receipts') + process.env.CODETRUSS_SIGNING_KEY = join(root, 'signing.pem') + const receipt = fixture(root) + const paths = await writeReceipt(dir, receipt, 'diff evidence') + const priorMarkdown = renderPriorProfileMarkdown(receipt) + receipt.evidence.markdownSha256 = sha256(priorMarkdown) + const jsonText = `${JSON.stringify(receipt, null, 2)}\n` + const key = await loadSigningKey() + await writeFile(paths.json, jsonText) + await writeFile(paths.markdown, priorMarkdown) + await writeFile(paths.signature, `${signBytes(jsonText, key.privateKey)}\n`) + + expect(priorMarkdown).toContain('Hosted Health scores: **N/A**.') + expect(priorMarkdown).not.toContain('### What did not run') + await expect(verifyReceipt(dir, receipt.sessionId)).resolves.toMatchObject({ verdict: 'PASS' }) + }) + it('renders explicit optional LLM diff coverage', () => { const receipt = fixture('/tmp/repo') receipt.llm = { diff --git a/public/downloads/codetruss-cli-0.2.30.sbom.cdx.json b/public/downloads/codetruss-cli-0.2.30.sbom.cdx.json new file mode 100644 index 0000000..4725dea --- /dev/null +++ b/public/downloads/codetruss-cli-0.2.30.sbom.cdx.json @@ -0,0 +1,170 @@ +{ + "$schema": "https://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "serialNumber": "urn:uuid:b2765fa3-4817-59b8-8f08-7350aedbf1ca", + "specVersion": "1.6", + "version": 1, + "metadata": { + "component": { + "type": "application", + "bom-ref": "pkg:npm/%40codetruss/cli@0.2.30", + "name": "@codetruss/cli", + "version": "0.2.30", + "description": "Local-first scope, quality, and verification receipts for coding agents", + "licenses": [ + { + "license": { + "name": "CodeTruss CLI Proprietary License" + } + } + ], + "purl": "pkg:npm/%40codetruss/cli@0.2.30" + }, + "properties": [ + { + "name": "codetruss:distribution", + "value": "single-file JavaScript bundle" + }, + { + "name": "codetruss:runtimeDependencies", + "value": "0" + } + ] + }, + "components": [ + { + "type": "library", + "bom-ref": "pkg:npm/%40codetruss/analyzer-engine@0.1.0", + "name": "@codetruss/analyzer-engine", + "version": "0.1.0", + "licenses": [ + { + "license": { + "name": "CodeTruss CLI Proprietary License" + } + } + ], + "purl": "pkg:npm/%40codetruss/analyzer-engine@0.1.0", + "properties": [ + { + "name": "codetruss:bundled", + "value": "true" + } + ] + }, + { + "type": "library", + "bom-ref": "pkg:npm/balanced-match@4.0.4", + "name": "balanced-match", + "version": "4.0.4", + "licenses": [ + { + "license": { + "id": "MIT" + } + } + ], + "purl": "pkg:npm/balanced-match@4.0.4", + "properties": [ + { + "name": "codetruss:bundled", + "value": "true" + } + ] + }, + { + "type": "library", + "bom-ref": "pkg:npm/brace-expansion@5.0.7", + "name": "brace-expansion", + "version": "5.0.7", + "licenses": [ + { + "license": { + "id": "MIT" + } + } + ], + "purl": "pkg:npm/brace-expansion@5.0.7", + "properties": [ + { + "name": "codetruss:bundled", + "value": "true" + } + ] + }, + { + "type": "library", + "bom-ref": "pkg:npm/minimatch@10.2.5", + "name": "minimatch", + "version": "10.2.5", + "licenses": [ + { + "license": { + "id": "BlueOak-1.0.0" + } + } + ], + "purl": "pkg:npm/minimatch@10.2.5", + "properties": [ + { + "name": "codetruss:bundled", + "value": "true" + } + ] + }, + { + "type": "library", + "bom-ref": "pkg:npm/yaml@2.9.0", + "name": "yaml", + "version": "2.9.0", + "licenses": [ + { + "license": { + "id": "ISC" + } + } + ], + "purl": "pkg:npm/yaml@2.9.0", + "properties": [ + { + "name": "codetruss:bundled", + "value": "true" + } + ] + } + ], + "dependencies": [ + { + "ref": "pkg:npm/%40codetruss/analyzer-engine@0.1.0", + "dependsOn": [] + }, + { + "ref": "pkg:npm/%40codetruss/cli@0.2.30", + "dependsOn": [ + "pkg:npm/%40codetruss/analyzer-engine@0.1.0", + "pkg:npm/minimatch@10.2.5", + "pkg:npm/yaml@2.9.0" + ] + }, + { + "ref": "pkg:npm/balanced-match@4.0.4", + "dependsOn": [] + }, + { + "ref": "pkg:npm/brace-expansion@5.0.7", + "dependsOn": [ + "pkg:npm/balanced-match@4.0.4" + ] + }, + { + "ref": "pkg:npm/minimatch@10.2.5", + "dependsOn": [ + "pkg:npm/brace-expansion@5.0.7" + ] + }, + { + "ref": "pkg:npm/yaml@2.9.0", + "dependsOn": [] + } + ] +} diff --git a/public/downloads/codetruss-cli-0.2.30.tgz b/public/downloads/codetruss-cli-0.2.30.tgz new file mode 100644 index 0000000000000000000000000000000000000000..9ca20d83954c34159022d0cb181b0c93e86c688f GIT binary patch literal 778830 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 z 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

)S}>7Ww`wQaU7*N2_hEyWzG8wQ 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 wv~q0-vw)h~AO&*=&*4*lY)H4hs|oPd{aP-_haE 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 P=fD2pPapjEKYsAP5|X!Y literal 0 HcmV?d00001 diff --git a/public/downloads/codetruss-cli-0.2.30.tgz.sha256 b/public/downloads/codetruss-cli-0.2.30.tgz.sha256 new file mode 100644 index 0000000..fa9c0c6 --- /dev/null +++ b/public/downloads/codetruss-cli-0.2.30.tgz.sha256 @@ -0,0 +1 @@ +9c97f573aa7e7a052fe8d4c578efda6a8d43f2bcfec9a74ab7d2fdf6b53eccdc codetruss-cli-0.2.30.tgz diff --git a/public/downloads/codetruss-cli-latest.json b/public/downloads/codetruss-cli-latest.json index 2186497..818e0a0 100644 --- a/public/downloads/codetruss-cli-latest.json +++ b/public/downloads/codetruss-cli-latest.json @@ -1,13 +1,13 @@ { "name": "@codetruss/cli", - "version": "0.2.24", - "url": "/downloads/codetruss-cli-0.2.24.tgz", + "version": "0.2.30", + "url": "/downloads/codetruss-cli-0.2.30.tgz", "latestUrl": "/downloads/codetruss-cli-latest.tgz", - "sha256": "793895784552e5d59540ffcc9dc2acf6bff6f778b59f9010bd901e4d4c3fa712", - "sbomUrl": "/downloads/codetruss-cli-0.2.24.sbom.cdx.json", - "sbomSha256": "29d5d38b5cca75a393a95465487aaaa7e74eee5c656fa8f843e4d5f37d7eeb42", + "sha256": "9c97f573aa7e7a052fe8d4c578efda6a8d43f2bcfec9a74ab7d2fdf6b53eccdc", + "sbomUrl": "/downloads/codetruss-cli-0.2.30.sbom.cdx.json", + "sbomSha256": "3a01c0977bfe3dc4407d39fd38af8e47521d06fe952570838bd4f011308a6b6d", "node": ">=20.9.0", "repository": "https://github.com/DeliriumPulse/codetruss-cli", - "releaseUrl": "https://github.com/DeliriumPulse/codetruss-cli/releases/tag/v0.2.24", - "attestationCommand": "gh attestation verify codetruss-cli-0.2.24.tgz --repo DeliriumPulse/codetruss-cli" + "releaseUrl": "https://github.com/DeliriumPulse/codetruss-cli/releases/tag/v0.2.30", + "attestationCommand": "gh attestation verify codetruss-cli-0.2.30.tgz --repo DeliriumPulse/codetruss-cli" } diff --git a/public/downloads/codetruss-cli-latest.sbom.cdx.json b/public/downloads/codetruss-cli-latest.sbom.cdx.json index dd8c1d6..4725dea 100644 --- a/public/downloads/codetruss-cli-latest.sbom.cdx.json +++ b/public/downloads/codetruss-cli-latest.sbom.cdx.json @@ -1,15 +1,15 @@ { "$schema": "https://cyclonedx.org/schema/bom-1.6.schema.json", "bomFormat": "CycloneDX", - "serialNumber": "urn:uuid:749dc75b-10d5-5c8c-9c04-9410333a0c4a", + "serialNumber": "urn:uuid:b2765fa3-4817-59b8-8f08-7350aedbf1ca", "specVersion": "1.6", "version": 1, "metadata": { "component": { "type": "application", - "bom-ref": "pkg:npm/%40codetruss/cli@0.2.24", + "bom-ref": "pkg:npm/%40codetruss/cli@0.2.30", "name": "@codetruss/cli", - "version": "0.2.24", + "version": "0.2.30", "description": "Local-first scope, quality, and verification receipts for coding agents", "licenses": [ { @@ -18,7 +18,7 @@ } } ], - "purl": "pkg:npm/%40codetruss/cli@0.2.24" + "purl": "pkg:npm/%40codetruss/cli@0.2.30" }, "properties": [ { @@ -139,7 +139,7 @@ "dependsOn": [] }, { - "ref": "pkg:npm/%40codetruss/cli@0.2.24", + "ref": "pkg:npm/%40codetruss/cli@0.2.30", "dependsOn": [ "pkg:npm/%40codetruss/analyzer-engine@0.1.0", "pkg:npm/minimatch@10.2.5", diff --git a/public/downloads/codetruss-cli-latest.tgz b/public/downloads/codetruss-cli-latest.tgz index c2e9f9813ccd0e6c2316de37dd528ff4328ad71c..9ca20d83954c34159022d0cb181b0c93e86c688f 100644 GIT binary patch delta 19231 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 delta 2641 zcmZuze^3BD^mM4sZ)(L#u;nX!1+q!FlbGyF;#1rOgb?JZKtDSonUOzMBAb703~s{|LpGj ze!uU1e|G;V%jfnuXL)kn)22=Hx_zFm6Yam$=Xtu8bn&SCm&%jUW!>`3nZVEZ{!SjV>8(e;z<&voHlY27z=_1Kc8&+xdX&|;x)$EjZy>NBj3AJu___w`GO-)cBR z6~8nvko~}5fdhw_ct{&EB*Nwg24`pw^RqE^GSSLp9fhC&4Y|p&vrI`0Bi3O%#9U<( z6Wur?1J?_Zpm;UGUncwT+(JCv?S^l!Fa;1f4^4ts`k9GvZGdim?<(^nSa6k@0-YZ+ z$*}zzGZ#L(M!)DB1_|0|ZACTLK5=j5YOrH%LUo$*>^)>Sn z?Ei*2ZgJG+wAH%onxJZJYC!NgYF%*P-^`jwRq!c-rb6dR6i0mDGCOr(?$sILY!$+! z^bwPxi(XMyRJ?FWMOn$h%Jr*@%2vUy$4nNi8)mrBt0+}B8sQ*9&ZuyJHc?$DwJZ{w z1c+i$JKSKA8(#kpQ$rLZ)rP4Y>VmevGf^Piu3(AI@ai|ugcr*_N?-^OR7mun(zho;KBs&vOzj>^li!;%+q%#Z9ULIEVGfps< zqI8HZL}s`-z!*tjh~gLb|d_fT@mVq%?>P66+C%slUJ(WmW|6Rs<9W>1)G{MO>R&TwN|VM zEuyf=g^OjsP^|=2HB-e^MOD>Ukm^NA!1i&?V3VNYEUbA&NyD1r^)=GohT$HRG{q@O zfuM%Hk{|m8RZv84leopJiL&ItN>Ebqi0cQtQ3lw05RS)9g11rdhusL*7}v=`$q&9B zv?AL};~iObsy?qI(Ic=g9EP`E7}R=p>*&O7y z@$qCwFB)Va)Q{4#RL!es>Isf)CLta0J)})a+w@@DofzOx( zQgsKVCP4czIvmPmA4ihp3G91%kU2Jm$8)jUL5rXU1<2)D3vA}tx$Fk&0>&`Rv3B%S zRtX(EJ9+%y0_S;l0ocrJ8u`S`eySrmv22ZXN*I>`QIZ7zir~g3(N`+8h9eAflTVgZ z4Tpu0)5A@H=$o9?F|NOeW=l{4O1MC_!b03Aw7TlX*P!F1DH-O+@{y?+Z)lQzUfKv^ z{YZ|fDs7Yz1LzHLDPBbg$f~HxN^AH$DjRj_dq-@WO)I70;);@m)s?HNs@7L6U0lAj zeDV6yg)d@F##)0w+a#z`O2O2p7RoJQk2Z`%LbJ1S$Y>?!r?R{CfO6Qk4U~A{cmZoC zw{qBr#xdXw%wz+)siVfeUbpEc&r~bOex^0`{LgS-pt;(*$z<1=fEIzC@8pp_0gfIb)6`7DmSY z0m@FW+xI;*T4Cq}n;81SSU4trH?`1M$Y7Vt1@q7Gi74t}k9vR9OWt z-(=&6#+Y_G;KN)KCJ%E>ml>$I$woqBzR7Leyvbc=t^Y@?(o`4h=aTif0NQtRX>h2IOCi=n++Bp~yiKYA=k{}P zkb0CW)@ur!PT;I?>KKQ}!=v1Pd5Af~Sz?~Sz-aN};fS4$))!zn)y<{D$KBjXnA5{0 zMvrycQ^>%nUM?9v?cv%$32~N$5kQP7eXoh(^lB~%4u-f@#%-gh-9{SDa94D2-)f5F zmV1>(zr0Dpg%IfD6Q2*mdK83BBe@utW1Afc_i-79aF@j&ntzK9%m@GrA)@W;BCL~l@&n<+K>!r%=C@FtOt14-6k z-CL&Q65JwsvD4WqsI##sh37G)dWvJ8+}uprUB%vwl#EA+UJ)p>Q**6>8jK{?NoiWF zYXw`1-qLmIs|j$>qhrYtL=a*#?Imp{$3G)V@!ILFj{7?p2_db78 z4>jlbGWgYTE{;fjJjaCpQ(@nEzDH*R+YM7Hy!m@RflT~>Z!o~#i~IqSbBRyjN#F)w mNw0ymMp8b&+x3WE Date: Thu, 6 Aug 2026 22:23:41 -0500 Subject: [PATCH 2/3] Fix two README lint nits from review - Tag the command-reference fence as `text` (markdownlint MD040). - Use the American spelling "afterward". Co-Authored-By: Claude Opus 5 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a8e440f..e0d0f37 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ for the MIT-licensed manifests, skill instructions, and marketplace source. ## Commands -``` +```text codetruss run --task "..." [--allow GLOB] [--deny GLOB] [--verify CMD] [--no-verify] [--llm] [--provider anthropic|openai|claude] -- codetruss review [--staged] --task "..." [--allow GLOB] [--deny GLOB] [--verify CMD] @@ -125,7 +125,7 @@ codetruss hooks install|status|doctor|uninstall [pre-commit|claude|codex|all] detected verification commands are trusted to run. `verify-policy trust-key` is separate: it appends your local signing key to `signing.publicKeys` so a teammate can sign receipts as themselves instead of sharing a private key. -Commit `.codetruss.yml` afterwards so the rest of the team inherits the change. +Commit `.codetruss.yml` afterward so the rest of the team inherits the change. It is accepted by the CLI but omitted from the built-in `--help` banner in 0.2.30. From f11587129eee747c20c2a7e3e58404bb530bf60e Mon Sep 17 00:00:00 2001 From: Zack Whitson Date: Thu, 6 Aug 2026 22:25:48 -0500 Subject: [PATCH 3/3] Correct the hosted pricing line "Plans start at $19 per seat" contradicted the $9 History tier named in the same sentence. Match the pricing page: free, History $9/mo, Pro $19/seat, Team $15/seat with a 5-seat minimum, Agency $249/mo with 15 client workspaces. Co-Authored-By: Claude Opus 5 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e0d0f37..92ebbcb 100644 --- a/README.md +++ b/README.md @@ -256,9 +256,9 @@ producing signed receipts cost nothing and always will. There is no seat count, no trial clock, and no feature that stops working once you depend on it. The paid line sits at the network boundary: local stays free, hosted is billed. -Hosted plans start at $19 per seat, with a $9 receipt-history tier, $15 per seat -for teams, and $249 for agencies. See -[codetruss.com/pricing](https://codetruss.com/pricing). +The hosted side starts free, then receipt History at $9/mo, Pro at $19 per seat, +Team at $15 per seat with a 5-seat minimum, and Agency at $249/mo including 15 +client workspaces. See [codetruss.com/pricing](https://codetruss.com/pricing). ## Source and development