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 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). Still attests ENFORCING for the
136
- `inescapable_deploy` claim.
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 (startup, growth, fintech, public-api, microservices)')
92
- .action(async (template) => {
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 by chaining setup-required-check / hook / deploy guidance (dry-run default; use --apply to mutate)')
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('--global', 'With --claude: write ~/.claude/settings.json instead of the project file')
291
- .option('--log <path>', 'With --claude: embed CODERIFTS_GUARD_EVENT_LOG and CODERIFTS_SESSION_ID in the command')
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
  });