coderifts 4.7.0 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +64 -0
- package/README.md +46 -10
- package/bin/coderifts.js +1 -1
- package/dist/cli.js +620 -97
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,69 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.9.0
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **P0 / ID621 — `enforce --check` no longer reports `inescapable_deploy: true`
|
|
7
|
+
for an unenforced configuration.** External audit 2026-08-24 reproduced two
|
|
8
|
+
holes on the published CLI: (a) the required check matched by **name only**
|
|
9
|
+
(`required_status_checks.checks[]` with no `app_id`), so any repository
|
|
10
|
+
writer could satisfy it with a same-named success status; (b) the two local
|
|
11
|
+
workflow checks were **text searches**, so `# uses: coderifts/contract-gate@v0`
|
|
12
|
+
in a comment counted as VERIFIED. Both now fail closed.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- **`--json` spec `provider-enforcement-evidence.v2`.** The meaning of
|
|
16
|
+
`VERIFIED` changed. A layer whose evidence cannot be bound to an issuer
|
|
17
|
+
(CodeRifts GitHub App id, public `GET /apps/coderifts`) or to an **active**
|
|
18
|
+
workflow job is `NOT_VERIFIED` or `UNVERIFIABLE` — never `VERIFIED`.
|
|
19
|
+
`inescapable_deploy` is true only when every layer is VERIFIED under these
|
|
20
|
+
rules.
|
|
21
|
+
- **Issuer binding:** `required_check` is VERIFIED only when `checks[]`
|
|
22
|
+
carries our App's numeric `app_id`. Legacy `contexts: string[]` is
|
|
23
|
+
`legacy_contexts_no_issuer_binding`. Name-only `checks[]` is
|
|
24
|
+
`no_issuer_binding`. A different `app_id` is `issuer_app_id_mismatch`.
|
|
25
|
+
- **YAML AST, not grep:** workflow files are parsed with `js-yaml` (already a
|
|
26
|
+
CLI dependency — no new package). VERIFIED requires a job that is not
|
|
27
|
+
`if: false` and a step whose `uses:` is `coderifts/contract-gate` at a
|
|
28
|
+
pinned major, or a `run:` that actually invokes `coderifts deploy-gate`.
|
|
29
|
+
Comments, string literals in other keys, and commented-out steps fail.
|
|
30
|
+
- **Environment correlation:** `environment_protection` is VERIFIED only when
|
|
31
|
+
`--env` names a protected GitHub Environment **and** an active deploy-gate
|
|
32
|
+
job sets that same `environment:` key (`environment_mismatch` otherwise).
|
|
33
|
+
|
|
34
|
+
## 4.8.0
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
- **VS Code / Copilot PreToolUse camelCase (DRIFT 1).** VS Code Agent hooks
|
|
38
|
+
pass `toolName` / `toolInput` / `filePath` (and `targetFile`). The hook
|
|
39
|
+
already tolerated `toolName`/`toolInput` but missed several property
|
|
40
|
+
aliases, so flattened camelCase payloads and `targetFile` were refused as
|
|
41
|
+
unparseable (fail-closed, safe, unusable). Every Claude-shaped read site
|
|
42
|
+
now accepts snake_case and camelCase: `tool_name`/`toolName`,
|
|
43
|
+
`tool_input`/`toolInput`, `file_path`/`filePath`/`path`/`target_file`/`targetFile`,
|
|
44
|
+
`content`/`contents`. Snake_case behaviour is unchanged. Garbage is still
|
|
45
|
+
fail-closed.
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
- **Matcher-inert hosts (DRIFT 2, documented, not a host fix).** VS Code
|
|
49
|
+
parses hook matchers but does not apply them — the hook fires on every
|
|
50
|
+
tool call. Non-Write/Edit/MultiEdit tools now exit **0** silently with no
|
|
51
|
+
network and **without requiring an API key** (parse → skip → key, so a
|
|
52
|
+
missing key cannot brick Read/Bash). Non-contract Write paths skip before
|
|
53
|
+
the key gate too. Garbage is still fail-closed (`stdin_unparseable`).
|
|
54
|
+
Spec-path Write/Edit/MultiEdit without a key is still fail-closed.
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
- **`copilot` MCP host (DRIFT 3).** `MCP_HOSTS` grows a third entry:
|
|
58
|
+
`.vscode/mcp.json`, root key **`servers`** (not `mcpServers`),
|
|
59
|
+
`type: "http"` + `url`. The writer special-cases the root key; Claude and
|
|
60
|
+
Cursor stay on `mcpServers`. `coderifts init --agents --hosts` accepts
|
|
61
|
+
`copilot` and includes it in `all`. Merge preserves other `servers` (and
|
|
62
|
+
any leftover keys). `--check` uses the same predicate.
|
|
63
|
+
- README Copilot section: `hook install --claude` arms VS Code agent mode
|
|
64
|
+
(measured), matcher-inert behaviour, honest boundary (hooks gate the
|
|
65
|
+
agent, not the human; inline completions are not tool calls).
|
|
66
|
+
|
|
3
67
|
## 4.7.0
|
|
4
68
|
|
|
5
69
|
### Added
|
package/README.md
CHANGED
|
@@ -72,6 +72,7 @@ coderifts init --agents # all hosts, all four pieces
|
|
|
72
72
|
coderifts init --agents --dry-run # plan only — writes nothing
|
|
73
73
|
coderifts init --agents --hosts=claude # Claude Code only
|
|
74
74
|
coderifts init --agents --hosts=cursor # Cursor only
|
|
75
|
+
coderifts init --agents --hosts=copilot # GitHub Copilot / VS Code only
|
|
75
76
|
coderifts init --agents --no-hook # skip host hook install
|
|
76
77
|
coderifts init --agents --no-workflow # skip .github/workflows/coderifts.yml
|
|
77
78
|
coderifts init --agents --check # which of the four pieces are present
|
|
@@ -79,9 +80,9 @@ coderifts init --agents --check # which of the four pieces are present
|
|
|
79
80
|
|
|
80
81
|
| Piece | What it writes | Host-specific shape |
|
|
81
82
|
|-------|----------------|---------------------|
|
|
82
|
-
| **MCP config** | `.mcp.json` (Claude Code), `.cursor/mcp.json` (Cursor) |
|
|
83
|
-
| **Agent rules** | generated host files via `agent-setup`'s writer | `AGENTS.md` is always written. Claude also gets `CLAUDE.md`; Cursor also gets `.cursor/rules/coderifts.mdc`. `--hosts=all` adds
|
|
84
|
-
| **Host hook** | `.claude/settings.json`, `.cursor/hooks.json` | Reuses `hook install --claude` / `--cursor` (JSON-merge, backup, idempotent) |
|
|
83
|
+
| **MCP config** | `.mcp.json` (Claude Code), `.cursor/mcp.json` (Cursor), `.vscode/mcp.json` (Copilot / VS Code) | Three shapes, never normalised into one: Claude `mcpServers` + `type: "http"` + `url`; Cursor `mcpServers` + `url` only (no `type`); Copilot **`servers`** (not `mcpServers`) + `type: "http"` + `url`. Never `httpUrl` (that is Gemini, extension-level — this command does not write it). |
|
|
84
|
+
| **Agent rules** | generated host files via `agent-setup`'s writer | `AGENTS.md` is always written. Claude also gets `CLAUDE.md`; Cursor also gets `.cursor/rules/coderifts.mdc`; Copilot also gets `.github/copilot-instructions.md`. `--hosts=all` adds LangGraph and OpenAI instructions. (`coderifts init agent` is a different command — it writes a `.coderifts.yml` template.) |
|
|
85
|
+
| **Host hook** | `.claude/settings.json`, `.cursor/hooks.json` | Reuses `hook install --claude` / `--cursor` (JSON-merge, backup, idempotent). Copilot shares Claude's `.claude/settings.json` — VS Code reads it by default. |
|
|
85
86
|
| **CI workflow** | `.github/workflows/coderifts.yml` | `coderifts/contract-gate@v0`. `require-verified-monitoring` is commented (honest default: **false**) |
|
|
86
87
|
|
|
87
88
|
**Next manual step:** add `CODERIFTS_API_KEY` to the repository secrets. The
|
|
@@ -347,6 +348,37 @@ weakened by `CODERIFTS_ADVISORY`.
|
|
|
347
348
|
CODERIFTS_ADVISORY=1 coderifts claude-hook
|
|
348
349
|
```
|
|
349
350
|
|
|
351
|
+
### GitHub Copilot / VS Code agent mode
|
|
352
|
+
|
|
353
|
+
Measured (VS Code **1.110**, Agent hooks Preview, 2026-08-24): VS Code **reads
|
|
354
|
+
`.claude/settings.json` by default**. `coderifts hook install --claude`
|
|
355
|
+
therefore arms Copilot agent mode — there is no separate `--copilot` hook
|
|
356
|
+
installer. VS Code Agent hooks **are deny-capable**: PreToolUse honours
|
|
357
|
+
`permissionDecision` allow|deny|ask and **exit 2**.
|
|
358
|
+
|
|
359
|
+
**Property names (CLI 4.8.0):** VS Code passes camelCase (`toolName` /
|
|
360
|
+
`toolInput` / `filePath` / `targetFile`). The hook accepts those alongside
|
|
361
|
+
Claude's snake_case (`tool_name` / `tool_input` / `file_path`). Flattened
|
|
362
|
+
payloads (path on the root object) are accepted. Garbage input is still
|
|
363
|
+
fail-closed.
|
|
364
|
+
|
|
365
|
+
**Matcher limitation (host behaviour, not a CLI bug):** VS Code **parses** hook
|
|
366
|
+
matchers (`Write|Edit|MultiEdit`) but **does not apply them**. The hook fires
|
|
367
|
+
on every tool call. Non-governed tools (Read, Bash, …) and non-contract paths
|
|
368
|
+
exit **0** silently with **no network** and **no API key required** — cheap
|
|
369
|
+
and fail-open for anything that is not a Write/Edit/MultiEdit of the spec. It
|
|
370
|
+
is noisy (every tool call invokes the process) and safe (irrelevant tools are
|
|
371
|
+
not blocked). A spec-path write without a key is still fail-closed.
|
|
372
|
+
|
|
373
|
+
**Honest boundary:** hooks gate the **agent**, not the human. Inline
|
|
374
|
+
completions (ghost text) are not tool calls and are not governed. A developer
|
|
375
|
+
typing in the editor is not a PreToolUse event.
|
|
376
|
+
|
|
377
|
+
**MCP:** `coderifts init --agents` (and `--hosts=copilot`) writes
|
|
378
|
+
`.vscode/mcp.json` with root key **`servers`** — a third shape. Claude Code and
|
|
379
|
+
Cursor use `mcpServers`; Copilot cloud Settings paste also uses `mcpServers`.
|
|
380
|
+
Do not copy one file onto another host.
|
|
381
|
+
|
|
350
382
|
### `coderifts status [repo]`
|
|
351
383
|
|
|
352
384
|
**Read-only** cross-layer enforcement report (Runtime / Merge / Deploy, plus
|
|
@@ -405,12 +437,14 @@ Provider-native pipeline-protection evidence. This is **not** a host claim:
|
|
|
405
437
|
|
|
406
438
|
| Layer | VERIFIED when |
|
|
407
439
|
|-------|----------------|
|
|
408
|
-
| `required_check` | Default-branch protection
|
|
440
|
+
| `required_check` | Default-branch protection `required_status_checks.checks[]` lists `CodeRifts / contract-gate` **bound to the CodeRifts GitHub App `app_id`** (public metadata: `GET https://api.github.com/apps/coderifts`). Name-only `checks[]` (`app_id` null) is `no_issuer_binding`. The legacy `contexts` array has no issuer field → `legacy_contexts_no_issuer_binding`. Both are **NOT_VERIFIED** (ID621). |
|
|
409
441
|
| `enforce_admins` | `enforce_admins.enabled` is **true** (admins cannot bypass). `false` = NOT_VERIFIED (admin bypass open) |
|
|
410
442
|
| `strict_status_checks` | `required_status_checks.strict` is true |
|
|
411
|
-
| `environment_protection` | `--env` names a GitHub Environment with protection rules
|
|
412
|
-
| `workflow_contract_gate` |
|
|
413
|
-
| `workflow_deploy_gate` |
|
|
443
|
+
| `environment_protection` | `--env` names a GitHub Environment with protection rules **and** an active deploy-gate job sets that same `environment:` (mismatch → `environment_mismatch`) |
|
|
444
|
+
| `workflow_contract_gate` | an **active** job (not `if: false`) has a step whose `uses:` is `coderifts/contract-gate` at a pinned major. Comments, string literals, and commented-out steps are **NOT_VERIFIED** |
|
|
445
|
+
| `workflow_deploy_gate` | an **active** job step **invokes** `coderifts deploy-gate` (not `echo` of the string; not a comment) |
|
|
446
|
+
|
|
447
|
+
**Invariant:** any layer whose evidence cannot be bound to an issuer (our GitHub App id) or to an active job is `NOT_VERIFIED` or `UNVERIFIABLE` — never `VERIFIED`. `inescapable_deploy` remains true only when every layer is `VERIFIED` under that rule.
|
|
414
448
|
|
|
415
449
|
Statuses: `VERIFIED` / `NOT_VERIFIED` / `UNVERIFIABLE(reason)`. Auth:
|
|
416
450
|
`GITHUB_TOKEN` (never printed). **No token** → API layers `UNVERIFIABLE` with
|
|
@@ -419,9 +453,11 @@ CodeRifts GitHub App **cannot** query branch protection (permissions are
|
|
|
419
453
|
contents / pull requests / checks — not `administration:read`).
|
|
420
454
|
|
|
421
455
|
`--json` is the quotable evidence document (`spec`:
|
|
422
|
-
`provider-enforcement-evidence.
|
|
423
|
-
|
|
424
|
-
|
|
456
|
+
`provider-enforcement-evidence.v2` — VERIFIED now requires issuer binding and
|
|
457
|
+
an active YAML-AST job; v1 treated name-only checks and text search as
|
|
458
|
+
VERIFIED): each layer's status, `reason_code`, the API endpoint consulted,
|
|
459
|
+
`queried_at`. Exit **0** when a report was produced (evidence, not a gate).
|
|
460
|
+
GitLab/Bitbucket: no adapter — `UNVERIFIABLE`, never stubbed.
|
|
425
461
|
|
|
426
462
|
### Agent host files (`coderifts agent-setup`)
|
|
427
463
|
|
package/bin/coderifts.js
CHANGED
|
@@ -92,7 +92,7 @@ program
|
|
|
92
92
|
.command('init [template]')
|
|
93
93
|
.description('Generate a .coderifts.yml from a policy template, or wire governed agent work (--agents)')
|
|
94
94
|
.option('--agents', 'Wire this repo for governed agent work (MCP config, rule files, host hook, CI gate)')
|
|
95
|
-
.option('--hosts <list>', 'With --agents: claude, cursor, or all (default: all)', 'all')
|
|
95
|
+
.option('--hosts <list>', 'With --agents: claude, cursor, copilot, or all (default: all)', 'all')
|
|
96
96
|
.option('--no-hook', 'With --agents: skip host hook install')
|
|
97
97
|
.option('--no-workflow', 'With --agents: skip writing .github/workflows/coderifts.yml')
|
|
98
98
|
.option('--dry-run', 'With --agents: print the plan without writing')
|