coderifts 4.2.0 → 4.3.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,51 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.3.0
4
+
5
+ **Behaviour change (minor-worthy)** — `coderifts deploy-gate` is fail-closed
6
+ by default. Same hook pattern as P0-3 (`claude-hook`): a deterministic wall
7
+ plus first-message WHY beats an ambiguous advisory (853 evidence).
8
+
9
+ ### Changed
10
+ - **`deploy-gate` default is fail-closed.** Missing / invalid / expired
11
+ receipt, scope mismatch, or deny-class → **exit 1**. stderr prints WHY
12
+ (gate reason + `renderDecisionWhy` when a decision body exists) and
13
+ `set CODERIFTS_DEPLOY_ADVISORY=1 to soften`. Pending `no_receipt` is a
14
+ policy fail, not an allow.
15
+ - **`--enforce` / `CODERIFTS_DEPLOY_ENFORCE=true` is a silent no-op for
16
+ exit** (default is already fail-closed). It still attests ENFORCING for
17
+ the `inescapable_deploy` claim.
18
+ - **Infra-failure is distinct from policy BLOCK.** Missing `--env` /
19
+ `--artifact` or malformed receipt JSON → `INFRA <site> — <why>` plus
20
+ `retryable: true` and `this is not a policy BLOCK`. Still fail-closed
21
+ by default. There is no network verify step in this command.
22
+
23
+ ### Added
24
+ - **`CODERIFTS_DEPLOY_ADVISORY=1|true`** (also `CODERIFTS_ADVISORY=1|true`)
25
+ is the explicit exception: print the verdict, always print
26
+ `ADVISORY MODE — this gate did not block`, exit 0. Softens both policy
27
+ and infra failures.
28
+
29
+ ### Migration
30
+ - Pipelines that relied on phase-1 advisory (deny exits 0 unless
31
+ `--enforce`) will now **fail the deploy step** on a failing chain.
32
+ Explicit opt-out: `CODERIFTS_DEPLOY_ADVISORY=1`. `--enforce` remains
33
+ accepted so existing workflow YAML does not break.
34
+
35
+ ## 4.2.1
36
+
37
+ ### Added
38
+
39
+ - **`claude-hook` exit-0 proof block (S4).** On a governed write that is
40
+ ALLOW / CONTINUE_WITH_MONITORING (sink wired), stderr prints a compact
41
+ 3–5 line AUTHORIZED block: `decision` + `execution_action` + `decision_id`
42
+ + receipt fingerprint prefix + the boundary sentence
43
+ `authorized; execution/commit not proven by this hook`. Reuses the
44
+ `renderFinalAnswerProof` wording class. **Never stdout.** Non-governed
45
+ paths (docs-only skip, identical content) stay silent. JSONL
46
+ `hook_continue` gains additive `proof: { decision_id, fp_prefix }`.
47
+ Exit codes unchanged.
48
+
3
49
  ## 4.1.1
4
50
 
5
51
  ### Fixed
package/README.md CHANGED
@@ -98,15 +98,29 @@ On success the command prints a **receipt reference** when the preflight path is
98
98
  ### `coderifts deploy-gate`
99
99
 
100
100
  Gate a **deploy** on the current `{ environment, artifact }` using a preflight
101
- receipt (phase-1 advisory). The CD sibling of `publish-gate` / the merge-gate
102
- App check. Composes the validated `deployGate` from `@coderifts/agent-guard` —
103
- the CLI only binds env + artifact + receipt + observed CD enforcement. No
104
- scoring is reimplemented here.
101
+ receipt. Fail-closed by default (842 / hook pattern). The CD sibling of
102
+ `publish-gate` / the merge-gate App check. Composes the validated `deployGate`
103
+ from `@coderifts/agent-guard` — the CLI only binds env + artifact + receipt +
104
+ observed CD enforcement. No scoring is reimplemented here.
105
105
 
106
- Phase 1 **reports** and exits **0** even on a gate deny, unless the step is
107
- marked enforcing (`--enforce` or `CODERIFTS_DEPLOY_ENFORCE=true`), in which
108
- case a failure exits **1**. Missing `--env` / `--artifact` is a usage error
109
- (exit **1**). No receipt → pending (never a fabricated allow).
106
+ **Default:** a failing chain (missing / invalid / expired receipt, scope
107
+ mismatch, deny-class) exits **1**. stderr prints WHY (gate reason + decision
108
+ body when present) and `set CODERIFTS_DEPLOY_ADVISORY=1 to soften`.
109
+
110
+ **Advisory opt-out:** `CODERIFTS_DEPLOY_ADVISORY=1|true` (also
111
+ `CODERIFTS_ADVISORY=1|true`) prints the verdict, always prints
112
+ `ADVISORY MODE — this gate did not block`, and exits **0**.
113
+
114
+ **`--enforce` / `CODERIFTS_DEPLOY_ENFORCE=true`:** accepted silently (no-op
115
+ for exit — default is already fail-closed). Still attests ENFORCING for the
116
+ `inescapable_deploy` claim.
117
+
118
+ **Infra vs policy:** missing `--env` / `--artifact` or malformed receipt JSON
119
+ prints distinct `INFRA` wording plus `retryable: true` and
120
+ `this is not a policy BLOCK`. Still fail-closed by default; advisory softens
121
+ it too. A missing receipt is a **policy** fail (`no_receipt`), not infra.
122
+
123
+ Happy path (receipt authorizes this env+artifact) exits **0**.
110
124
 
111
125
  | Flag | Description | Default |
112
126
  |------|-------------|---------|
@@ -114,11 +128,11 @@ case a failure exits **1**. Missing `--env` / `--artifact` is a usage error
114
128
  | `--artifact <artifact_id>` | Immutable artifact identity (content digest or commit SHA) | required |
115
129
  | `--receipt <file>` | Path to the deploy-scoped receipt JSON from preflight | none |
116
130
  | `--json` | Binding result as JSON | `false` |
117
- | `--enforce` | Attest ENFORCING and exit non-zero on a gate failure | `false` |
131
+ | `--enforce` | Accepted silently (exit already fail-closed). Still attests ENFORCING. | `false` |
118
132
 
119
133
  ```bash
120
134
  coderifts deploy-gate --env production --artifact "$SHA" --receipt receipt.json
121
- coderifts deploy-gate --env production --artifact "$SHA" --receipt receipt.json --enforce
135
+ CODERIFTS_DEPLOY_ADVISORY=1 coderifts deploy-gate --env production --artifact "$SHA" --receipt receipt.json
122
136
  ```
123
137
 
124
138
  ### `coderifts outcome <kind>`
@@ -510,17 +524,18 @@ Two honest modes:
510
524
  | `CODERIFTS_API_KEY` | API key (alternative to `coderifts login`) |
511
525
  | `CODERIFTS_OASDIFF_BIN` | Explicit path to the `oasdiff` binary (overrides auto-detect) |
512
526
  | `CODERIFTS_STRICT` | `claude-hook`: `1` or `true` pins fail-closed (cannot be weakened by `CODERIFTS_ADVISORY`). Default is already fail-closed. |
513
- | `CODERIFTS_ADVISORY` | `claude-hook`: `1` or `true` is the **explicit** soft-allow opt-out on “governance could not run” sites. Absence of a key is not this flag. |
527
+ | `CODERIFTS_ADVISORY` | `claude-hook`: `1` or `true` is the **explicit** soft-allow opt-out on “governance could not run” sites. Absence of a key is not this flag. Also accepted by `deploy-gate` as the same opt-out as `CODERIFTS_DEPLOY_ADVISORY`. |
514
528
  | `CODERIFTS_MONITORING_SINK_WIRED` | `claude-hook`: `1` or `true` host-asserts a monitoring sink so `CONTINUE_WITH_MONITORING` may exit 0. Not delivery proof. |
515
- | `CODERIFTS_DEPLOY_ENFORCE` | `deploy-gate`: `true` marks the step enforcing (same as `--enforce`); `unknown` is explicitly unobservable (never assume ENFORCING) |
529
+ | `CODERIFTS_DEPLOY_ADVISORY` | `deploy-gate`: `1` or `true` is the **explicit** opt-out print the verdict, print `ADVISORY MODE this gate did not block`, exit 0. |
530
+ | `CODERIFTS_DEPLOY_ENFORCE` | `deploy-gate`: `true` attests ENFORCING (same as `--enforce`; no-op for exit — default is already fail-closed); `unknown` is explicitly unobservable (never assume ENFORCING) |
516
531
  | `NO_COLOR` | Disable colored output |
517
532
 
518
533
  ## Exit Codes
519
534
 
520
535
  | Code | Meaning |
521
536
  |------|---------|
522
- | `0` | Success: no breaking changes (or below threshold); advisory `deploy-gate`; `lock --check` unchanged; `adopt` / `status` / `outcome` success |
523
- | `1` | Breaking changes (CI mode), analysis/usage/API failure, or `deploy-gate` deny **when enforcing** |
537
+ | `0` | Success: no breaking changes (or below threshold); `deploy-gate` allow, or advisory opt-out; `lock --check` unchanged; `adopt` / `status` / `outcome` success |
538
+ | `1` | Breaking changes (CI mode), analysis/usage/API failure, or `deploy-gate` policy/infra fail (fail-closed default) |
524
539
  | `2` | `claude-hook` BLOCK (Claude Code cancel); `lock --check` unreachable / missing locked or live |
525
540
  | `3` | `lock --check` drift detected (monitor only — does not block the package) |
526
541
 
package/bin/coderifts.js CHANGED
@@ -25,18 +25,18 @@ program
25
25
  await diff(oldSpec, newSpec, options);
26
26
  });
27
27
 
28
- // ── deploy-gate command (deploy-gate #8, phase-1 ADVISORY) ──
29
- // Gates a deploy on the current { environment, artifact } via a preflight receipt. Phase 1 is
30
- // advisory: it reports but exits 0 even on deny unless the step is marked --enforce /
31
- // CODERIFTS_DEPLOY_ENFORCE=true. Composes the validated pure deployGate (@coderifts/agent-guard).
28
+ // ── deploy-gate command (deploy-gate #8) ──
29
+ // Gates a deploy on the current { environment, artifact } via a preflight receipt.
30
+ // DEFAULT fail-closed (842 / hook pattern). CODERIFTS_DEPLOY_ADVISORY=1 is the explicit
31
+ // opt-out. --enforce is accepted silently (no-op for exit; still attests ENFORCING).
32
32
  program
33
33
  .command('deploy-gate')
34
- .description('Gate a deploy on the current { environment, artifact } using a preflight receipt (phase-1 advisory)')
34
+ .description('Gate a deploy on the current { environment, artifact } using a preflight receipt (fail-closed by default; CODERIFTS_DEPLOY_ADVISORY=1 to soften)')
35
35
  .option('--env <environment>', 'Target environment (e.g. production, staging)')
36
36
  .option('--artifact <artifact_id>', 'Immutable artifact identity being deployed (content digest or commit SHA)')
37
37
  .option('--receipt <file>', 'Path to the deploy-scoped receipt JSON produced by preflight')
38
38
  .option('--json', 'Output the binding result as JSON')
39
- .option('--enforce', 'Treat the step as enforcing: attest ENFORCING and exit non-zero on a gate failure')
39
+ .option('--enforce', 'Accepted silently (exit is fail-closed by default). Still attests ENFORCING for inescapable_deploy.')
40
40
  .action(async (options) => {
41
41
  const { runDeployGate } = require('../src/commands/deploy-gate');
42
42
  await runDeployGate(options);