coderifts 4.4.1 → 4.7.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 +75 -0
- package/README.md +72 -2
- package/bin/coderifts.js +72 -5
- package/dist/cli.js +2264 -655
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,80 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.7.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **`coderifts enforce --check`** — provider-native CD enforcement evidence.
|
|
7
|
+
Queries GitHub (and local workflow files) and reports, per layer,
|
|
8
|
+
`VERIFIED` / `NOT_VERIFIED` / `UNVERIFIABLE(reason)`:
|
|
9
|
+
1. required check `CodeRifts / contract-gate` on default-branch protection
|
|
10
|
+
2. `enforce_admins` (admin bypass)
|
|
11
|
+
3. `required_status_checks.strict`
|
|
12
|
+
4. GitHub Environment protection rules (`--env`)
|
|
13
|
+
5. workflow references `coderifts/contract-gate@v0` (local)
|
|
14
|
+
6. workflow runs `coderifts deploy-gate` (local)
|
|
15
|
+
|
|
16
|
+
`inescapable_deploy` is **true only when every layer is VERIFIED**. Otherwise
|
|
17
|
+
the field stays false and the JSON carries the queried facts. `--json`
|
|
18
|
+
includes each layer's status, the API endpoint consulted, and `queried_at`.
|
|
19
|
+
|
|
20
|
+
Auth: `GITHUB_TOKEN` / `GH_TOKEN` (user). App installation token
|
|
21
|
+
(`GITHUB_APP_TOKEN`) is accepted but **cannot** query branch protection —
|
|
22
|
+
the GitHub App permission set is contents:read, pull_requests, checks
|
|
23
|
+
(AUDIT.md §2.4); `GET .../protection` needs `administration:read`. No
|
|
24
|
+
token → `UNVERIFIABLE` with the exact instruction. Token values are never
|
|
25
|
+
printed. GitLab/Bitbucket: no adapter (UNVERIFIABLE, never stubbed).
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- **`observeCDEnforcement`:** `CODERIFTS_DEPLOY_NO_BYPASS` is recorded as
|
|
29
|
+
`host_claim_no_bypass` and no longer sets `bypass_possible: false`.
|
|
30
|
+
`--enforce` still marks the step ENFORCING (exit is already fail-closed)
|
|
31
|
+
but is a **host claim**. `bypass_possible` is false only when
|
|
32
|
+
`providerEvidence.inescapable_deploy === true` from `enforce --check`.
|
|
33
|
+
Guard `deployGate` still consumes `{ enforcement, bypass_possible }` — the
|
|
34
|
+
CLI must not pass a flag-derived “no bypass”.
|
|
35
|
+
|
|
36
|
+
## 4.6.0
|
|
37
|
+
|
|
38
|
+
**Version pick:** the parallel Cursor-hook round claimed **4.5.0**
|
|
39
|
+
(`8eab5f9`, `packages/cli/package.json` 4.5.0). This command takes the next
|
|
40
|
+
free minor. (4.5.0's CHANGELOG entry was not written in that round; the
|
|
41
|
+
commit message is the record of `coderifts cursor-hook` + `hook install
|
|
42
|
+
--cursor`.)
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
- **`coderifts init --agents`** — one command that wires a repository for
|
|
46
|
+
governed agent work. Four pieces:
|
|
47
|
+
1. repo-level MCP config per host (never one file for all):
|
|
48
|
+
Claude Code `.mcp.json` uses `mcpServers.coderifts` with **`type":"http"`
|
|
49
|
+
+ `url`** (a `url` without `type` is skipped — measured
|
|
50
|
+
code.claude.com/docs/en/mcp 2026-08-22); Cursor `.cursor/mcp.json` uses
|
|
51
|
+
**`url` and no `type`** (measured docs.cursor.com). Gemini `httpUrl` is
|
|
52
|
+
extension-level — this command does not write it.
|
|
53
|
+
2. generated agent rule files, via **`writeAgentHostFiles`** extracted from
|
|
54
|
+
`agent-setup` (not a second copy). Cursor `.mdc` is included because the
|
|
55
|
+
4.5.0 round landed it.
|
|
56
|
+
3. host hook where one exists: `installClaudeHook` and (4.5.0)
|
|
57
|
+
`installCursorHook` — JSON-merge, `.bak`, idempotent. `--no-hook` skips.
|
|
58
|
+
4. `.github/workflows/coderifts.yml` at `coderifts/contract-gate@v0`, with
|
|
59
|
+
`require-verified-monitoring` commented (honest default: false).
|
|
60
|
+
`--no-workflow` skips. Existing workflow files are never clobbered.
|
|
61
|
+
- `--hosts=claude,cursor,all` (default `all`), `--dry-run` (plan, no write),
|
|
62
|
+
`--check` (which of the four pieces are present).
|
|
63
|
+
- Idempotent re-run: unchanged files are skipped; JSON MCP configs are merged
|
|
64
|
+
(other servers preserved, `.bak` alongside any file it modifies).
|
|
65
|
+
- Summary names created / merged / skipped and WHY, the next manual step
|
|
66
|
+
(add `CODERIFTS_API_KEY` to repo secrets — the CLI never writes a key),
|
|
67
|
+
and what this does **not** do: enable branch protection
|
|
68
|
+
(ENFORCEMENT.md), make raw host tools inescapable, or enforce the
|
|
69
|
+
workflow until the required check is turned on in repo settings.
|
|
70
|
+
|
|
71
|
+
### Shared vs new
|
|
72
|
+
- **Shared:** `writeAgentHostFiles` (extracted from `agent-setup`);
|
|
73
|
+
`installClaudeHook` / `installCursorHook` (`silent` + `dryRun` passed
|
|
74
|
+
through).
|
|
75
|
+
- **New:** `src/mcp-repo-config.js`, `src/contract-gate-workflow.js`,
|
|
76
|
+
`src/commands/init-agents.js`.
|
|
77
|
+
|
|
3
78
|
## 4.4.1
|
|
4
79
|
|
|
5
80
|
**Sequencing:** `@coderifts/agent-guard` **9.0.0** is the verifier of record
|
package/README.md
CHANGED
|
@@ -61,6 +61,42 @@ Interactive configuration generator. Creates a `.coderifts.yml` file with indust
|
|
|
61
61
|
- `microservices-internal`
|
|
62
62
|
- `ai-agent-platform`
|
|
63
63
|
|
|
64
|
+
### `coderifts init --agents`
|
|
65
|
+
|
|
66
|
+
One command that wires **this repository** for governed agent work. Re-run is
|
|
67
|
+
a no-op. Existing JSON is merged (never clobbered); a `.bak` sits next to any
|
|
68
|
+
file it modifies.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
coderifts init --agents # all hosts, all four pieces
|
|
72
|
+
coderifts init --agents --dry-run # plan only — writes nothing
|
|
73
|
+
coderifts init --agents --hosts=claude # Claude Code only
|
|
74
|
+
coderifts init --agents --hosts=cursor # Cursor only
|
|
75
|
+
coderifts init --agents --no-hook # skip host hook install
|
|
76
|
+
coderifts init --agents --no-workflow # skip .github/workflows/coderifts.yml
|
|
77
|
+
coderifts init --agents --check # which of the four pieces are present
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
| Piece | What it writes | Host-specific shape |
|
|
81
|
+
|-------|----------------|---------------------|
|
|
82
|
+
| **MCP config** | `.mcp.json` (Claude Code), `.cursor/mcp.json` (Cursor) | Claude: `mcpServers.coderifts` with `type: "http"` + `url`. Cursor: `url` only (no `type`). Never `httpUrl` (that is Gemini, extension-level — this command does not write it). |
|
|
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 Copilot, LangGraph, and OpenAI instructions. (`coderifts init agent` is a different command — it writes a `.coderifts.yml` template.) |
|
|
84
|
+
| **Host hook** | `.claude/settings.json`, `.cursor/hooks.json` | Reuses `hook install --claude` / `--cursor` (JSON-merge, backup, idempotent) |
|
|
85
|
+
| **CI workflow** | `.github/workflows/coderifts.yml` | `coderifts/contract-gate@v0`. `require-verified-monitoring` is commented (honest default: **false**) |
|
|
86
|
+
|
|
87
|
+
**Next manual step:** add `CODERIFTS_API_KEY` to the repository secrets. The
|
|
88
|
+
CLI never writes a key anywhere.
|
|
89
|
+
|
|
90
|
+
**This command does not:** enable branch protection (see
|
|
91
|
+
[ENFORCEMENT.md](https://github.com/coderifts/contract-gate/blob/main/ENFORCEMENT.md)),
|
|
92
|
+
make raw host tools inescapable, or enforce the workflow until
|
|
93
|
+
`CodeRifts / contract-gate` is a required check in repo settings.
|
|
94
|
+
|
|
95
|
+
The three separate commands this replaces for a fresh repo: `coderifts
|
|
96
|
+
agent-setup`, `coderifts hook install --claude` (and `--cursor`), plus a
|
|
97
|
+
hand-copied workflow file. Repo-level MCP config was generated by nothing
|
|
98
|
+
before 4.6.0.
|
|
99
|
+
|
|
64
100
|
### `coderifts login`
|
|
65
101
|
|
|
66
102
|
Save your CodeRifts API key for cloud features. Get a free key at [app.coderifts.com/api/signup](https://app.coderifts.com/api/signup).
|
|
@@ -132,8 +168,11 @@ gate reason + `renderDecisionWhy` when a body exists) and
|
|
|
132
168
|
unsigned file still prints the unsigned-receipt truth loudly.
|
|
133
169
|
|
|
134
170
|
**`--enforce` / `CODERIFTS_DEPLOY_ENFORCE=true`:** accepted silently (no-op
|
|
135
|
-
for exit — default is already fail-closed).
|
|
136
|
-
`inescapable_deploy
|
|
171
|
+
for exit — default is already fail-closed). This is a **host claim** that the
|
|
172
|
+
step is ENFORCING. It does **not** set `inescapable_deploy`. That field is
|
|
173
|
+
true only from queried pipeline protection (`coderifts enforce --check`).
|
|
174
|
+
`CODERIFTS_DEPLOY_NO_BYPASS` is recorded as a host claim and does not clear
|
|
175
|
+
`bypass_possible`.
|
|
137
176
|
|
|
138
177
|
**Infra vs policy:** missing `--env` / `--artifact`, malformed receipt JSON, or
|
|
139
178
|
an unreachable `--keys` registry prints distinct `INFRA` wording plus
|
|
@@ -346,13 +385,44 @@ failed, **1** on missing repo/key, API error, or any apply failure.
|
|
|
346
385
|
|------|-------------|---------|
|
|
347
386
|
| `[repo]` / `--repo <owner/repo>` | Repository | none (required) |
|
|
348
387
|
| `--apply` | Run underlying setup commands | dry-run |
|
|
388
|
+
| `--check` | Query GitHub + local workflows (read-only evidence) | `false` |
|
|
389
|
+
| `--env <name>` | With `--check`: GitHub Environment to query | none |
|
|
390
|
+
| `--branch <name>` | With `--check`: branch (default: repo default) | default branch |
|
|
349
391
|
| `--json` | Machine-readable JSON result | `false` |
|
|
350
392
|
|
|
351
393
|
```bash
|
|
352
394
|
coderifts enforce owner/repo
|
|
353
395
|
coderifts enforce --repo owner/repo --apply
|
|
396
|
+
coderifts enforce --check --repo owner/repo --env production --json
|
|
354
397
|
```
|
|
355
398
|
|
|
399
|
+
### `coderifts enforce --check`
|
|
400
|
+
|
|
401
|
+
Provider-native pipeline-protection evidence. This is **not** a host claim:
|
|
402
|
+
`--enforce` and `CODERIFTS_DEPLOY_NO_BYPASS` do **not** set
|
|
403
|
+
`inescapable_deploy`. The field is true only when every layer below is
|
|
404
|
+
`VERIFIED`.
|
|
405
|
+
|
|
406
|
+
| Layer | VERIFIED when |
|
|
407
|
+
|-------|----------------|
|
|
408
|
+
| `required_check` | Default-branch protection requires `CodeRifts / contract-gate` |
|
|
409
|
+
| `enforce_admins` | `enforce_admins.enabled` is **true** (admins cannot bypass). `false` = NOT_VERIFIED (admin bypass open) |
|
|
410
|
+
| `strict_status_checks` | `required_status_checks.strict` is true |
|
|
411
|
+
| `environment_protection` | `--env` names a GitHub Environment with protection rules or a deployment branch policy |
|
|
412
|
+
| `workflow_contract_gate` | a local `.github/workflows` file references `coderifts/contract-gate@v0` |
|
|
413
|
+
| `workflow_deploy_gate` | a local workflow runs `coderifts deploy-gate` |
|
|
414
|
+
|
|
415
|
+
Statuses: `VERIFIED` / `NOT_VERIFIED` / `UNVERIFIABLE(reason)`. Auth:
|
|
416
|
+
`GITHUB_TOKEN` (never printed). **No token** → API layers `UNVERIFIABLE` with
|
|
417
|
+
the instruction to set `GITHUB_TOKEN` (repo + `administration:read`). The
|
|
418
|
+
CodeRifts GitHub App **cannot** query branch protection (permissions are
|
|
419
|
+
contents / pull requests / checks — not `administration:read`).
|
|
420
|
+
|
|
421
|
+
`--json` is the quotable evidence document (`spec`:
|
|
422
|
+
`provider-enforcement-evidence.v1`): each layer's status, the API endpoint
|
|
423
|
+
consulted, `queried_at`. Exit **0** when a report was produced (evidence, not
|
|
424
|
+
a gate). GitLab/Bitbucket: no adapter — `UNVERIFIABLE`, never stubbed.
|
|
425
|
+
|
|
356
426
|
### Agent host files (`coderifts agent-setup`)
|
|
357
427
|
|
|
358
428
|
Writes the six CodeRifts agent-host rule files **plus** the Claude Code
|
package/bin/coderifts.js
CHANGED
|
@@ -86,10 +86,49 @@ program
|
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
// ── init command ──
|
|
89
|
+
// `init [template]` writes a policy YAML. `init --agents` is a different path:
|
|
90
|
+
// it wires MCP config + agent rules + host hook + the CI gate workflow.
|
|
89
91
|
program
|
|
90
92
|
.command('init [template]')
|
|
91
|
-
.description('Generate a .coderifts.yml from a policy template
|
|
92
|
-
.
|
|
93
|
+
.description('Generate a .coderifts.yml from a policy template, or wire governed agent work (--agents)')
|
|
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')
|
|
96
|
+
.option('--no-hook', 'With --agents: skip host hook install')
|
|
97
|
+
.option('--no-workflow', 'With --agents: skip writing .github/workflows/coderifts.yml')
|
|
98
|
+
.option('--dry-run', 'With --agents: print the plan without writing')
|
|
99
|
+
.option('--check', 'With --agents: report which of the four pieces are present (no write)')
|
|
100
|
+
.option('--out <dir>', 'With --agents: target directory (default: cwd)')
|
|
101
|
+
.action(async (template, options) => {
|
|
102
|
+
const {
|
|
103
|
+
runInitAgents,
|
|
104
|
+
agentFlagsRequireAgents,
|
|
105
|
+
AGENT_FLAGS_REQUIRE_AGENTS,
|
|
106
|
+
AGENTS_NO_TEMPLATE,
|
|
107
|
+
} = require('../src/commands/init-agents');
|
|
108
|
+
if (options.agents) {
|
|
109
|
+
if (template) {
|
|
110
|
+
console.error(AGENTS_NO_TEMPLATE);
|
|
111
|
+
process.exitCode = 1;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const result = runInitAgents({
|
|
115
|
+
hosts: options.hosts,
|
|
116
|
+
hook: options.hook,
|
|
117
|
+
workflow: options.workflow,
|
|
118
|
+
dryRun: !!options.dryRun,
|
|
119
|
+
check: !!options.check,
|
|
120
|
+
out: options.out,
|
|
121
|
+
});
|
|
122
|
+
if (result && typeof result.exitCode === 'number') {
|
|
123
|
+
process.exitCode = result.exitCode;
|
|
124
|
+
}
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (agentFlagsRequireAgents(options)) {
|
|
128
|
+
console.error(AGENT_FLAGS_REQUIRE_AGENTS);
|
|
129
|
+
process.exitCode = 1;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
93
132
|
const { init } = require('../src/commands/init');
|
|
94
133
|
await init(template);
|
|
95
134
|
});
|
|
@@ -145,9 +184,13 @@ program
|
|
|
145
184
|
// No new GitHub writes with the CodeRifts API key (user's gh for merge; local fs for hook).
|
|
146
185
|
program
|
|
147
186
|
.command('enforce [repo]')
|
|
148
|
-
.description('Close enforcement gaps
|
|
187
|
+
.description('Close enforcement gaps (dry-run default), or --check to query provider-native pipeline protection evidence')
|
|
149
188
|
.option('--repo <owner/repo>', 'Repository (owner/repo); also accepted as a positional argument')
|
|
150
189
|
.option('--apply', 'Actually run underlying setup commands (default: dry-run only)')
|
|
190
|
+
.option('--check', 'Query GitHub + local workflows; report VERIFIED / NOT_VERIFIED / UNVERIFIABLE (read-only)')
|
|
191
|
+
.option('--env <name>', 'With --check: GitHub Environment name to query for protection rules')
|
|
192
|
+
.option('--branch <name>', 'With --check: branch to query (default: repository default branch)')
|
|
193
|
+
.option('--provider <name>', 'With --check: provider adapter (github only; others UNVERIFIABLE, never stubbed)', 'github')
|
|
151
194
|
.option('--json', 'Machine-readable JSON result')
|
|
152
195
|
.action(async (repoPositional, options) => {
|
|
153
196
|
const { runEnforce } = require('../src/commands/enforce');
|
|
@@ -155,6 +198,7 @@ program
|
|
|
155
198
|
...options,
|
|
156
199
|
repo: options.repo || repoPositional || null,
|
|
157
200
|
apply: !!options.apply,
|
|
201
|
+
check: !!options.check,
|
|
158
202
|
});
|
|
159
203
|
if (result && typeof result.exitCode === 'number') {
|
|
160
204
|
process.exitCode = result.exitCode;
|
|
@@ -278,6 +322,27 @@ program
|
|
|
278
322
|
}
|
|
279
323
|
});
|
|
280
324
|
|
|
325
|
+
// ── cursor-hook — Cursor preToolUse ({"permission":"deny"} on stdout; also exit 2) ──
|
|
326
|
+
program
|
|
327
|
+
.command('cursor-hook')
|
|
328
|
+
.description(
|
|
329
|
+
'Cursor preToolUse gate: deny contract-touching Write|Delete on BLOCK/STOP/REQUEST_APPROVAL. '
|
|
330
|
+
+ 'Emits {permission,user_message,agent_message} on stdout. Cursor does not enforce "ask" for '
|
|
331
|
+
+ 'preToolUse, so REQUEST_APPROVAL maps to deny. Fail-closed on unparseable stdin.',
|
|
332
|
+
)
|
|
333
|
+
.addHelpText('after', () => {
|
|
334
|
+
const { USAGE } = require('../src/commands/cursor-hook');
|
|
335
|
+
return `\n${USAGE}\n`;
|
|
336
|
+
})
|
|
337
|
+
.action(async () => {
|
|
338
|
+
const { runCursorHook } = require('../src/commands/cursor-hook');
|
|
339
|
+
const fsMod = require('fs');
|
|
340
|
+
let stdin = '';
|
|
341
|
+
try { stdin = fsMod.readFileSync(0, 'utf8'); } catch { stdin = ''; }
|
|
342
|
+
const code = await runCursorHook({ argv: process.argv.slice(3), stdin });
|
|
343
|
+
if (typeof code === 'number') process.exitCode = code;
|
|
344
|
+
});
|
|
345
|
+
|
|
281
346
|
// ── hook command group ──
|
|
282
347
|
const hookCmd = program
|
|
283
348
|
.command('hook')
|
|
@@ -287,12 +352,14 @@ hookCmd
|
|
|
287
352
|
.command('install')
|
|
288
353
|
.description('Install the CodeRifts pre-push hook in the current Git repo')
|
|
289
354
|
.option('--claude', 'Write Claude Code PreToolUse hook to .claude/settings.json (JSON-merge)')
|
|
290
|
-
.option('--
|
|
291
|
-
.option('--
|
|
355
|
+
.option('--cursor', 'Write Cursor preToolUse hook to .cursor/hooks.json (JSON-merge, failClosed:true)')
|
|
356
|
+
.option('--global', 'With --claude/--cursor: write the ~/ config instead of the project file')
|
|
357
|
+
.option('--log <path>', 'With --claude/--cursor: embed CODERIFTS_GUARD_EVENT_LOG and CODERIFTS_SESSION_ID in the command')
|
|
292
358
|
.action((options) => {
|
|
293
359
|
const { install } = require('../src/commands/hook');
|
|
294
360
|
install({
|
|
295
361
|
claude: !!options.claude,
|
|
362
|
+
cursor: !!options.cursor,
|
|
296
363
|
global: !!options.global,
|
|
297
364
|
log: options.log,
|
|
298
365
|
});
|