Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .github/workflows/bump.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,15 @@ concurrency:
cancel-in-progress: false

jobs:
# Never tag a tree that fails the FULL quality gate (not just tests) — P0-11.
gate:
if: >-
github.actor != 'github-actions[bot]' &&
!startsWith(github.event.head_commit.message, 'chore(release):')
uses: ./.github/workflows/reusable-quality-gate.yml

bump:
needs: gate
runs-on: ubuntu-latest
# Never react to our own release commit (belt-and-suspenders behind GitHub's recursion guard).
if: >-
Expand All @@ -54,7 +62,6 @@ jobs:
node-version: 22
cache: npm
- run: npm ci
- run: npm test # never tag a broken tree
- name: Bump version fields + rotate CHANGELOG
id: bump
# On push, always "auto"; on manual dispatch, honor the chosen input.
Expand Down
63 changes: 7 additions & 56 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# CI gate for every push and PR: test matrix (Node 20/22 — matches the ">=20" engines
# field; 18 is EOL), Biome lint+format, ShellCheck, the zero-runtime-dependency assertion,
# the version-drift guard, and dependency review. All must pass to merge.
# CI gate for every push and PR: the Node 20/22 test matrix (matches the ">=20" engines
# field; 18 is EOL) plus the shared quality gate (Biome, typecheck, ShellCheck, zero-dep
# assertion, version-drift, docs-drift, pack). The quality gate is the SAME reusable workflow
# the version bump and release require, so none of the three can drift from the others.
name: CI

on:
Expand Down Expand Up @@ -28,59 +29,9 @@ jobs:
- run: npm ci
- run: npm test

lint:
name: Lint & format (Biome)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run check
- run: npm run typecheck
- run: npm audit --audit-level=critical

shellcheck:
name: ShellCheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# Fail only on errors; the guards trip style/warning false-positives (e.g. SC2034 on
# vars used cross-file via the sourced _guardlib.sh).
- run: shellcheck --severity=error $(git ls-files '*.sh')

no-runtime-deps:
name: Assert zero runtime dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: node -e "process.exit(Object.keys(require('./package.json').dependencies||{}).length)"
- run: npm pack --dry-run

version-drift:
name: Version fields agree
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# package.json, package-lock.json, .claude-plugin/plugin.json, .codex-plugin/plugin.json,
# and CITATION.cff must all carry the same version (scripts/bump.mjs keeps them in sync).
- run: node scripts/bump.mjs check

docs-drift:
name: Docs match code
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # the CHANGELOG check compares src vs CHANGELOG.md commit times
- uses: actions/setup-node@v6
with:
node-version: 22
# Commands, env vars, MCP tools, and CHANGELOG reconciled against the code —
# a feature can't merge with its docs missing (src/docs_check.js).
- run: node src/cli.js docs check
quality-gate:
name: Quality gate
uses: ./.github/workflows/reusable-quality-gate.yml

dependency-review:
name: Dependency review
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ permissions:
contents: read

jobs:
# Publish only after the FULL quality gate passes — not just `npm test` (P0-11).
gate:
uses: ./.github/workflows/reusable-quality-gate.yml

release:
needs: gate
runs-on: ubuntu-latest
permissions:
contents: write # create the GitHub Release
Expand All @@ -40,7 +45,6 @@ jobs:
registry-url: "https://registry.npmjs.org"
cache: npm
- run: npm ci
- run: npm test
- name: Assert tag matches package.json version
env:
TAG: ${{ github.ref_name }}
Expand Down
36 changes: 36 additions & 0 deletions .github/workflows/reusable-quality-gate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# The single quality gate required before merge, tag, AND npm publish (P0-11). CI, the
# version bump, and the release all call this reusable workflow, so a release can no longer
# ship on `npm test` alone while lint/typecheck/shellcheck/docs/pack quietly fail — every
# path runs the exact same checks from one source of truth.
name: Quality gate

on:
workflow_call:

permissions:
contents: read

jobs:
gate:
name: Full quality gate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # the docs CHANGELOG check compares src vs CHANGELOG.md commit times
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm test
- run: npm run check
- run: npm run typecheck
- run: npm audit --audit-level=critical
- name: ShellCheck
run: shellcheck --severity=error $(git ls-files '*.sh')
- name: Assert zero runtime dependencies
run: node -e "process.exit(Object.keys(require('./package.json').dependencies||{}).length)"
- run: node scripts/bump.mjs check
- run: node src/cli.js docs check
- run: npm pack --dry-run
5 changes: 5 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@ paths = [
'''^research/formal-synthesis/graded_reference_set\.json$''',
'''^research/formal-synthesis/merged_references\.json$''',
]
# Obvious placeholder credentials used as test fixtures to exercise the secret
# redactor/scanner — sequential-hex tokens that are unmistakably fake, not real secrets.
regexes = [
'''ghp_0123456789abcdef0123456789abcdef0123''',
]
67 changes: 67 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,73 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Fixed (audit remediation)

- **Onboarding & state safety.** `forge init` no longer silently replaces a
present-but-unparseable `~/.claude/settings.json` (it refuses and preserves the
original), backs the file up before changing it, and writes atomically
(temp + rename). Hook/statusline commands now resolve to the installed package
(`~/.forge/…` → `<pkg>/global/…`) so npm-global installs don't reference an
unmaterialized `~/.forge`. Personal recall moved to the XDG state dir instead of
the source tree; `install.sh` separates read-only assets from mutable state,
migrates any `global/recall/facts`, and no longer routes path ops through `eval`.
- **Security defaults.** Removed broad default Bash read allows
(`cat`/`head`/`tail`/`rg`/`git show`/`git log`) so secret-file reads prompt
instead of auto-approving, and moved dependency installs (`npm ci`/`npm install`/…)
to `ask`. `protect-paths` now blocks reading a protected path via Bash
(e.g. `cat .env`, `git show HEAD:.env`). Secret redaction is reimplemented in Node
(`secret-redact.mjs`) with no `jq` dependency and prints a visible DEGRADED warning
rather than silently no-op'ing; `forge doctor` treats missing `node` as a failure.
- **Managed-file integrity.** `writeIfChanged` and `forge doctor` now compare the full
file body against the canonical source instead of trusting the embedded `forge:sync`
marker, so a hand-edited managed file (`AGENTS.md`, etc.) with an intact marker is
detected and restored on `forge sync` (P0-08).
- **Third-party MCP is opt-in.** `context7` is no longer installed by default; `forge
init` wires only forge's own server. New `forge integrations` command adds an optional
server (e.g. `context7`) after showing its package, network behaviour, and the files it
touches, writing only with `--yes` (P0-06). MCP emitters now refresh a drifted
forge-owned entry instead of leaving a stale one (user servers untouched).
- **Core correctness.** Atlas staleness is inventory-aware (a new/removed file now
invalidates the graph), and `forge impact`/`substrate` report "impact unavailable" on a
stale/missing atlas instead of presenting 0 impacted files as trustworthy (P0-07).
`forge verify` returns `PASS | FAIL | INCOMPLETE | NOT_CONFIGURED` (never "pass" when no
verifier ran), drives real test commands off the stack detector, and includes untracked
files in provenance (P0-09). Ledger evidence refs are validated — a typed `git:<sha>`
ref must resolve before it can affect confidence (P0-10).
- **Effective-date pricing.** Model prices support scheduled `{effectiveFrom,
effectiveUntil}` windows resolved by `priceOf(model, date)`; Sonnet 5 now carries its
$2/$10 introductory rate (through 2026-08-31) and the $3/$15 successor, and `forge route`
shows the current effective price (P0-12).
- **Release integrity.** A reusable `quality-gate` workflow (tests, Biome, typecheck,
ShellCheck, zero-dep assertion, version-drift, docs check, `npm pack`) is now required by
CI, the version bump, and the release — a tag/publish can no longer proceed on `npm test`
alone while other gates fail (P0-11).
- **Honest claims & wording.** Dropped scanner "ok to install" certification language
(S-01); renamed `P(defect)`→`defectRiskScore` and `residual`→`remainingUncheckedWeight`
in output; reframed the preflight score as a heuristic; qualified "proof-carrying
memory" as evidence-referenced and "zero-config" as guided/low-configuration across the
docs; added a beta status block and per-benchmark sample sizes.

### Added / changed (product)

- **Policy profiles & repo config.** `forge init --profile minimal|standard|web-app|
backend-service|library|regulated` writes `.forge/forge.config.json`; the `minimal`
profile emits only the five core-safety rules instead of the full engineering pack
(P1-02). `forge.config.json` gives explicit override semantics — `profile`,
`disableSections` (drop by id/title), and `rules` (append) with deterministic order
(P1-03).
- **Change-obligation guidance.** The completion gate now spells out change-type
obligations (code → docs + a test, config → config docs; test-only owes nothing) so it
points at the right artifact instead of accepting any doc/state touch as done (P1-05).
- **Subsystem health.** `forge doctor` reports each key subsystem (secret-redaction,
guards, atlas, managed-config, pricing) in a standard `ACTIVE|DEGRADED|UNAVAILABLE|
FAILED` vocabulary so a degraded control stays visible (P1-06).
- **Help grouping.** Experimental commands are grouped under "Labs (experimental)" in
`forge --help`, separating the core reliability loop from experiments (P1-01).
- **UI rule.** Replaced the "make chain-of-thought visible" AI-UX rule with safe-rationale
guidance (assumptions, tool actions, sources, verification evidence — no hidden reasoning
traces) (P1-04).

## [0.21.1] - 2026-07-17

### Fixed
Expand Down
Loading
Loading