coderifts 6.1.0 → 8.0.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 +35 -0
- package/README.md +108 -3
- package/bin/coderifts.js +60 -0
- package/dist/cli.js +4728 -2314
- package/package.json +3 -2
- package/scripts/assert-guard-major.js +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 8.0.0
|
|
4
|
+
|
|
5
|
+
### Security
|
|
6
|
+
|
|
7
|
+
- **Installs from `coderifts@7.0.0` pinned contract-gate v0.5.0.** That action's vendored verifier accepted receipts signed by revoked keys. Fixed in contract-gate **0.7.0**. The strict install now pins **0.7.0 / `90de4be`**.
|
|
8
|
+
|
|
9
|
+
### Breaking
|
|
10
|
+
|
|
11
|
+
- **`@coderifts/agent-guard` declared `^15.0.0`** (`MIN_GUARD_MAJOR` 15). There is no `peerDependencies` entry — this is a **direct** dependency, so a fresh `npm i -g coderifts` resolves 15.x, not 14.x. The CLI still uses only `deployGate`, `asVerifiedDeployReceiptView`, `DEPLOY_RECEIPT_VIEW_SPEC`, and `matchGlob`.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **Claude Code PreToolUse hook governs a path family**, not a single `coderifts.specPath`. Default globs cover OpenAPI/Swagger, GraphQL, `*.proto`, AsyncAPI, MCP manifests, and `*tool-schema*.json`. `git config --add coderifts.specPath` is additive (never drops the family). `coderifts.specPathExclude` opts one path out. A not-governed Write/Edit/MultiEdit exits 0 and prints `coderifts claude-hook: not governed: <path>` — the hook is never silent on those tools.
|
|
16
|
+
|
|
17
|
+
### Docs
|
|
18
|
+
|
|
19
|
+
- README **Grant versions** table: `cr.exec.v1` is the reference/teaching grant the demo and strict install use; the Atomic V2 request contract (`execution-grant-request.v2` fields) is what the SDK/Guard/executor speak; `ENFORCING_STRICT` is the current profile name and will become a versioned name.
|
|
20
|
+
|
|
21
|
+
## 7.0.0
|
|
22
|
+
|
|
23
|
+
### Breaking
|
|
24
|
+
|
|
25
|
+
- **`provider-canary`** — proves the gate BLOCKS by attempting a merge that must be refused, creating and cleaning up a real PR; on a non-blocking repo it reverts the probe commit in the same run (`base_reverted`). A successful merge yields `NOT_VERIFIED` and exit 1 — the honest finding, not a bug.
|
|
26
|
+
- **`enforce --check`** gains `--bind-workflow` (writes and reads back the SHA-pinned required-workflow rule), `--require-workflow-binding`, `--head-sha`, and `--env`; runtime read-back covers the rule-suite result, check-run app id, and check-run head_sha. Status vocabulary is VERIFIED / NOT_VERIFIED / UNVERIFIABLE.
|
|
27
|
+
- Thin diff routes (`/api/v1/{grpc,graphql,asyncapi}/diff`) return `422 ANALYSIS_FAILED` on parse errors instead of a generic 500.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- `setup-required-check --bind-workflow` and the provider-enforcement evidence envelope (`provider-enforcement-evidence.v2`).
|
|
32
|
+
- Provider adapter shape with GitLab/Bitbucket read-back (plan only; apply is GitHub).
|
|
33
|
+
|
|
34
|
+
### Note
|
|
35
|
+
|
|
36
|
+
- Requires `@coderifts/agent-guard` 13 or 14 (declared `^13.0.0`; the CLI uses base guard APIs, not the ATOMIC profile).
|
|
37
|
+
|
|
3
38
|
## 6.1.0
|
|
4
39
|
|
|
5
40
|
### Added
|
package/README.md
CHANGED
|
@@ -86,6 +86,16 @@ coderifts init --agents --check # which of the four pieces are present
|
|
|
86
86
|
| **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. |
|
|
87
87
|
| **CI workflow** | `.github/workflows/coderifts.yml` | `coderifts/contract-gate@v0`. Default: `require-verified-monitoring` commented (honest default: **false**). `--strict`: the same file with `require-verified-monitoring: 'true'` |
|
|
88
88
|
|
|
89
|
+
**Grant versions** (these names are not interchangeable):
|
|
90
|
+
|
|
91
|
+
| What | Who uses it | What it proves |
|
|
92
|
+
|------|-------------|----------------|
|
|
93
|
+
| `cr.exec.v1` | capability-demo and the strict-install workflow (`require-grant`) | A reference/teaching execution grant bound to `operation ∥ target_id ∥ after_payload`. The demo and `coderifts init --agents --strict` use this form. |
|
|
94
|
+
| Atomic V2 request (`execution-grant-request.v2` fields) | SDK, Guard, executor | The request contract those three speak when minting/verifying a grant. Not the same bytes as a `cr.exec.v1` token. |
|
|
95
|
+
| `ENFORCING_STRICT` | Guard `withCodeRifts({ profile })` | The current **profile name**. It is unsuffixed today and will become a versioned name; it is not a grant format and not Atomic V1. |
|
|
96
|
+
|
|
97
|
+
`--strict` turns on `require-grant` and `require-verified-monitoring` in the workflow; it does not rename those three things.
|
|
98
|
+
|
|
89
99
|
**Next manual step:** add `CODERIFTS_API_KEY` to the repository secrets. The
|
|
90
100
|
CLI never writes a key anywhere.
|
|
91
101
|
|
|
@@ -287,7 +297,26 @@ Unparseable settings JSON → refuse, no write.
|
|
|
287
297
|
### Claude Code PreToolUse (`coderifts claude-hook`) — ID824
|
|
288
298
|
|
|
289
299
|
Tool-call-time gate for **Claude Code**: blocks contract-touching `Write` /
|
|
290
|
-
`Edit` / `MultiEdit` when authorize preflight returns **BLOCK/STOP**.
|
|
300
|
+
`Edit` / `MultiEdit` when authorize preflight returns **BLOCK/STOP**. The
|
|
301
|
+
matcher is tool-level (`Write|Edit|MultiEdit`); the **path family** is
|
|
302
|
+
enforced inside the hook.
|
|
303
|
+
|
|
304
|
+
**Default governed family** (from `SUPPORTED_TYPES` + `@coderifts/contract-path`
|
|
305
|
+
`looksLikeContractPath` / `CONTRACT_EXT`; `agent_tools` via `*tool-schema*.json`):
|
|
306
|
+
|
|
307
|
+
- `**/*openapi*.{yaml,yml,json}` and `**/*swagger*.{yaml,yml,json}` (openapi)
|
|
308
|
+
- `**/*.{graphql,gql}` (graphql)
|
|
309
|
+
- `**/*.proto` (grpc)
|
|
310
|
+
- `**/*asyncapi*.{yaml,yml,json}` (asyncapi)
|
|
311
|
+
- `**/*mcp*.{json,yaml,yml}` (mcp_manifest)
|
|
312
|
+
- `**/*tool-schema*.json` (agent_tools)
|
|
313
|
+
|
|
314
|
+
`node_modules/` and `vendor/` are not governed (same as the path detector).
|
|
315
|
+
`git config --add coderifts.specPath <path-or-glob>` is **additive** (never
|
|
316
|
+
replaces the family). `git config --add coderifts.specPathExclude <path-or-glob>`
|
|
317
|
+
opts one path out. A not-governed path exits 0 and prints
|
|
318
|
+
`coderifts claude-hook: not governed: <path>` on stderr — the hook is never silent
|
|
319
|
+
on a write/edit.
|
|
291
320
|
|
|
292
321
|
**Exit map (Claude Code semantics — fixed):**
|
|
293
322
|
|
|
@@ -299,11 +328,12 @@ Tool-call-time gate for **Claude Code**: blocks contract-touching `Write` /
|
|
|
299
328
|
|
|
300
329
|
Push-time equivalent (git exit **1** on BLOCK): `coderifts hook install`.
|
|
301
330
|
|
|
302
|
-
**Install path:** `coderifts hook install --claude` (or `agent-setup` writes project `.claude/settings.json` when absent). Then set key
|
|
331
|
+
**Install path:** `coderifts hook install --claude` (or `agent-setup` writes project `.claude/settings.json` when absent). Then set key; spec path is optional and additive:
|
|
303
332
|
|
|
304
333
|
```bash
|
|
305
334
|
git config coderifts.apiKey 'cr_live_…' # or: coderifts login / CODERIFTS_API_KEY
|
|
306
|
-
git config coderifts.specPath
|
|
335
|
+
git config --add coderifts.specPath extra/spec.yaml # additive; does not drop the family
|
|
336
|
+
git config --add coderifts.specPathExclude docs/openapi.yaml # opt out one false positive
|
|
307
337
|
```
|
|
308
338
|
|
|
309
339
|
**Recipe — project** (`.claude/settings.json`) **or user** (`~/.claude/settings.json`):
|
|
@@ -421,6 +451,9 @@ failed, **1** on missing repo/key, API error, or any apply failure.
|
|
|
421
451
|
| `--check` | Query GitHub + local workflows (read-only evidence) | `false` |
|
|
422
452
|
| `--env <name>` | With `--check`: GitHub Environment to query | none |
|
|
423
453
|
| `--branch <name>` | With `--check`: branch (default: repo default) | default branch |
|
|
454
|
+
| `--provider <name>` | With `--check`: provider adapter. `github` only; others report UNVERIFIABLE and are never stubbed | `github` |
|
|
455
|
+
| `--head-sha <sha>` | With `--check`: pull-request head commit, so the required-workflow pin can be compared with the bytes being merged | none |
|
|
456
|
+
| `--require-workflow-binding` | With `--check`: also require a sha-pinned required workflow matching the head. **Default OFF** — without it the evidence still gains a `workflow_binding` section and neither the verdict nor the exit code changes | `false` |
|
|
424
457
|
| `--json` | Machine-readable JSON result | `false` |
|
|
425
458
|
|
|
426
459
|
```bash
|
|
@@ -460,6 +493,58 @@ VERIFIED): each layer's status, `reason_code`, the API endpoint consulted,
|
|
|
460
493
|
`queried_at`. Exit **0** when a report was produced (evidence, not a gate).
|
|
461
494
|
GitLab/Bitbucket: no adapter — `UNVERIFIABLE`, never stubbed.
|
|
462
495
|
|
|
496
|
+
### `coderifts provider-canary [repo]`
|
|
497
|
+
|
|
498
|
+
Negative canary: open an ephemeral PR with the contract-gate check failing or
|
|
499
|
+
absent and ask GitHub to merge it. **Blocked is the healthy result.** On a
|
|
500
|
+
repository that does **not** block, the canary leaves a merge+revert commit
|
|
501
|
+
pair on base (that is the finding, stated) — an admin token's revert bypasses
|
|
502
|
+
required checks.
|
|
503
|
+
|
|
504
|
+
| Flag | Description | Default |
|
|
505
|
+
|------|-------------|---------|
|
|
506
|
+
| `[repo]` / `--repo <owner/repo>` | Repository | none (required) |
|
|
507
|
+
| `--confirm` | Required for a real run: this creates a branch and a pull request | none — without it (and without `--dry-run`) the command exits **2** rather than touching the repo |
|
|
508
|
+
| `--dry-run` | Do not touch the provider; report the shape only | `false` |
|
|
509
|
+
| `--json` | Machine-readable evidence document | `false` |
|
|
510
|
+
|
|
511
|
+
Exit **0** only when the provider refused the merge. A merge that **succeeds**
|
|
512
|
+
is the finding: `blocked:false`, status `NOT_VERIFIED`, exit **1**.
|
|
513
|
+
|
|
514
|
+
```bash
|
|
515
|
+
coderifts provider-canary --repo owner/repo --dry-run
|
|
516
|
+
coderifts provider-canary --repo owner/repo --confirm
|
|
517
|
+
coderifts provider-canary --repo owner/repo --confirm --json
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### `coderifts grant publish`
|
|
521
|
+
|
|
522
|
+
Encodes an **already-signed** execution grant plus the PR head sha into a
|
|
523
|
+
comment marker on stdout, for the 1094 PR-comment delivery slot. **It does not
|
|
524
|
+
mint a grant** (`src/commands/grant-publish.js:4`) — the token must already be a
|
|
525
|
+
signed `cr.exec.v1` or `cr.exec.v2` (see **Grant versions** above).
|
|
526
|
+
|
|
527
|
+
| Flag | Description | Default |
|
|
528
|
+
|------|-------------|---------|
|
|
529
|
+
| `--head-sha <sha>` | **Required.** 40-hex PR head sha the grant binds | none |
|
|
530
|
+
| `--grant <token>` | **Required.** `cr.exec.v1` or `cr.exec.v2` token | none |
|
|
531
|
+
| `--after-payload-hash <hash>` | `sha256:…` of the after-payload | empty string |
|
|
532
|
+
|
|
533
|
+
Writes `<!-- coderifts-grant-v2 -->` followed by one JSON line. Pipe it to
|
|
534
|
+
`gh api` or post it as a PR comment. Bad `--head-sha` or a missing `--grant`
|
|
535
|
+
exits **2** with usage.
|
|
536
|
+
|
|
537
|
+
```bash
|
|
538
|
+
coderifts grant publish --head-sha "$HEAD" --grant "$TOKEN" > /tmp/marker.txt
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
**Reaching the gate today:** the contract-gate Action reads a grant from its
|
|
542
|
+
`execution-grant:` input, not from PR comments — `main()` in the gate does not
|
|
543
|
+
pass `grantComments`, so the comment path is not yet wired end to end. Until it
|
|
544
|
+
is, deliver the token through the `CODERIFTS_EXECUTION_GRANT` repository
|
|
545
|
+
variable, and note that a grant binds one after-payload, so a pinned variable
|
|
546
|
+
covers exactly one diff.
|
|
547
|
+
|
|
463
548
|
### Agent host files (`coderifts agent-setup`)
|
|
464
549
|
|
|
465
550
|
Writes the six CodeRifts agent-host rule files **plus** the Claude Code
|
|
@@ -534,6 +619,11 @@ via `coderifts registry-gate`). The wizard:
|
|
|
534
619
|
existing protection settings
|
|
535
620
|
5. **`--apply`:** runs that PUT with your credentials, then **re-reads** and
|
|
536
621
|
only reports success if the check is required
|
|
622
|
+
6. **`--bind-workflow`:** create/update a repository ruleset `workflows` rule
|
|
623
|
+
pinning `.github/workflows/coderifts.yml` (the STRICT template filename)
|
|
624
|
+
to its current **blob sha** on the target branch (`enforcement: active`,
|
|
625
|
+
`bypass_actors: []`). Dry-run unless combined with `--apply`. Read-back
|
|
626
|
+
uses `github-workflow-pin.js`; reports `APPLIED` only on `VERIFIED`.
|
|
537
627
|
|
|
538
628
|
**Why the App never writes protection:** mutating branch protection needs
|
|
539
629
|
`administration:write` — a trust jump we refuse. Your credentials do the write.
|
|
@@ -542,6 +632,15 @@ via `coderifts registry-gate`). The wizard:
|
|
|
542
632
|
`merge_group` webhook (`checks_requested`) and posts **CodeRifts / contract-gate**
|
|
543
633
|
on the merge group head (same gate as PR heads), so the queue does not stall.
|
|
544
634
|
|
|
635
|
+
| Flag | Description | Default |
|
|
636
|
+
|------|-------------|---------|
|
|
637
|
+
| `--repo <owner/repo>` | Override owner/repo | `git remote origin` |
|
|
638
|
+
| `--branch <name>` | Branch to protect | repo default branch |
|
|
639
|
+
| `--apply` | Apply the protection change | print the `gh` command only |
|
|
640
|
+
| `--bind-workflow` | Create/update a ruleset `workflows` rule pinning `.github/workflows/coderifts.yml` (STRICT template) by blob sha | `false` |
|
|
641
|
+
| `--enforce-admins` | Set `enforce_admins:true` on create | `false` — admins can bypass; the gate reports `admin_bypass_open` |
|
|
642
|
+
| `--json` | Machine-readable JSON result | `false` |
|
|
643
|
+
|
|
545
644
|
```bash
|
|
546
645
|
# Observe + print command (safe default)
|
|
547
646
|
coderifts setup-required-check
|
|
@@ -549,6 +648,12 @@ coderifts setup-required-check
|
|
|
549
648
|
# Apply + re-verify
|
|
550
649
|
coderifts setup-required-check --apply
|
|
551
650
|
|
|
651
|
+
# Pin the STRICT workflow by blob sha (ruleset `workflows` rule)
|
|
652
|
+
coderifts setup-required-check --bind-workflow --apply
|
|
653
|
+
|
|
654
|
+
# Admins cannot bypass either (opt-in; NOT the default)
|
|
655
|
+
coderifts setup-required-check --apply --enforce-admins
|
|
656
|
+
|
|
552
657
|
# One-liner for CI docs
|
|
553
658
|
coderifts setup-required-check --branch main
|
|
554
659
|
```
|
package/bin/coderifts.js
CHANGED
|
@@ -85,6 +85,60 @@ program
|
|
|
85
85
|
process.exit(code);
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
+
// ── provider canary (1105 negative enforcement proof) ──
|
|
89
|
+
//
|
|
90
|
+
// NOT read-only, and deliberately not hidden behind --apply: it creates a branch and a pull request
|
|
91
|
+
// on the named repository and asks the provider to merge them. --dry-run is the safe default the
|
|
92
|
+
// tests drive; a real run needs --confirm so nobody discovers this command by tab-completion.
|
|
93
|
+
program
|
|
94
|
+
.command('provider-canary [repo]')
|
|
95
|
+
.description('Prove the gate BLOCKS by attempting a merge that must be refused (creates + cleans up a real PR). On a non-blocking repo the canary leaves a merge+revert commit pair on base (the finding); an admin token\'s revert bypasses required checks.')
|
|
96
|
+
.option('--repo <owner/repo>', 'Repository (owner/repo); also accepted as a positional argument')
|
|
97
|
+
.option('--dry-run', 'Do not touch the provider; report the shape only', false)
|
|
98
|
+
.option('--confirm', 'Required for a real run: this creates a branch and a pull request')
|
|
99
|
+
.option('--json', 'Machine-readable evidence document')
|
|
100
|
+
.action(async (repoPositional, options) => {
|
|
101
|
+
const { runProviderCanary } = require('../src/commands/provider-canary');
|
|
102
|
+
if (!options.dryRun && !options.confirm) {
|
|
103
|
+
console.error(
|
|
104
|
+
'provider-canary creates a real branch and pull request on the target repository and then '
|
|
105
|
+
+ 'asks GitHub to merge it. Re-run with --confirm, or with --dry-run to see the shape.',
|
|
106
|
+
);
|
|
107
|
+
process.exit(2);
|
|
108
|
+
}
|
|
109
|
+
const result = await runProviderCanary(
|
|
110
|
+
{ ...options, repo: options.repo || repoPositional },
|
|
111
|
+
{},
|
|
112
|
+
);
|
|
113
|
+
// The command prints (JSON or human) exactly once, after cleanup — see report() there.
|
|
114
|
+
process.exit(result.exitCode);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// ── grant publish (1094 PR-comment delivery) ──
|
|
118
|
+
program
|
|
119
|
+
.command('grant')
|
|
120
|
+
.description('Execution-grant helpers')
|
|
121
|
+
.command('publish')
|
|
122
|
+
.description('Encode a signed grant + head_sha as a PR-comment marker (stdout)')
|
|
123
|
+
.requiredOption('--head-sha <sha>', '40-hex PR head SHA the grant binds')
|
|
124
|
+
.requiredOption('--grant <token>', 'cr.exec.v1 or cr.exec.v2 token')
|
|
125
|
+
.option('--after-payload-hash <hash>', 'sha256:… of the after-payload')
|
|
126
|
+
.action((options) => {
|
|
127
|
+
const { runGrantPublish } = require('../src/commands/grant-publish');
|
|
128
|
+
const result = runGrantPublish({
|
|
129
|
+
headSha: options.headSha,
|
|
130
|
+
grant: options.grant,
|
|
131
|
+
afterPayloadHash: options.afterPayloadHash,
|
|
132
|
+
});
|
|
133
|
+
if (!result.ok) {
|
|
134
|
+
console.error(result.error);
|
|
135
|
+
if (result.usage) console.error(result.usage);
|
|
136
|
+
process.exitCode = result.exitCode;
|
|
137
|
+
process.exit(result.exitCode);
|
|
138
|
+
}
|
|
139
|
+
process.stdout.write(result.text + '\n');
|
|
140
|
+
});
|
|
141
|
+
|
|
88
142
|
// ── init command ──
|
|
89
143
|
// `init [template]` writes a policy YAML. `init --agents` is a different path:
|
|
90
144
|
// it wires MCP config + agent rules + host hook + the CI gate workflow.
|
|
@@ -153,6 +207,7 @@ program
|
|
|
153
207
|
.option('--branch <name>', 'Branch to protect (default: repo default branch)')
|
|
154
208
|
.option('--repo <owner/repo>', 'Override owner/repo (default: git remote origin)')
|
|
155
209
|
.option('--apply', 'Apply the protection change (default: print the exact gh command only)')
|
|
210
|
+
.option('--bind-workflow', 'Create/update a ruleset workflows rule pinning .github/workflows/coderifts.yml (STRICT template) by blob sha; dry-run unless --apply')
|
|
156
211
|
.option('--enforce-admins', 'Set enforce_admins:true on create (default: false — admins can bypass; gate reports admin_bypass_open)')
|
|
157
212
|
.option('--json', 'Machine-readable JSON result')
|
|
158
213
|
.action(async (options) => {
|
|
@@ -193,6 +248,11 @@ program
|
|
|
193
248
|
.option('--env <name>', 'With --check: GitHub Environment name to query for protection rules')
|
|
194
249
|
.option('--branch <name>', 'With --check: branch to query (default: repository default branch)')
|
|
195
250
|
.option('--provider <name>', 'With --check: provider adapter (github only; others UNVERIFIABLE, never stubbed)', 'github')
|
|
251
|
+
// 1102 — DEFAULT OFF ON PURPOSE. With the flag absent the evidence gains a workflow_binding
|
|
252
|
+
// section and NOTHING about the verdict or the exit code changes. Turning it on is a decision
|
|
253
|
+
// about how strong a claim this repository is willing to make, not a bug fix, so it is Peter's.
|
|
254
|
+
.option('--require-workflow-binding', 'With --check: also require a sha-pinned required workflow matching the head (default: off)')
|
|
255
|
+
.option('--head-sha <sha>', 'With --check: pull-request head commit, so the workflow pin can be compared with the bytes being merged')
|
|
196
256
|
.option('--json', 'Machine-readable JSON result')
|
|
197
257
|
.action(async (repoPositional, options) => {
|
|
198
258
|
const { runEnforce } = require('../src/commands/enforce');
|