diff --git a/.changeset/tidy-rams-dart.md b/.changeset/tidy-rams-dart.md new file mode 100644 index 000000000..0b66a8f36 --- /dev/null +++ b/.changeset/tidy-rams-dart.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 2536 +--- +**`/gsd-review`'s codex lane no longer passes the hook-trust bypass flag or runs its capability probe** — host-harness safety classifiers denied invocations carrying them, and flagless invocations work in steady state. A genuine untrusted-hook failure still surfaces as a dropped lane with diagnosable stderr. (#2479) diff --git a/gsd-core/workflows/review.md b/gsd-core/workflows/review.md index e1e67e223..45c9c8bb5 100644 --- a/gsd-core/workflows/review.md +++ b/gsd-core/workflows/review.md @@ -255,18 +255,20 @@ AGY_MODEL=$(gsd_run query config-get review.models.agy 2>/dev/null | jq -r '.' 2 CLAUDE_EFFORT_ARGS=$(gsd_run query resolve-execution gsd-plan-checker --host claude 2>/dev/null | jq -r '.effort_argv_string // ""' 2>/dev/null || true) CODEX_EFFORT_ARGS=$(gsd_run query resolve-execution gsd-plan-checker --host codex 2>/dev/null | jq -r '.effort_argv_string // ""' 2>/dev/null || true) OPENCODE_EFFORT_ARGS=$(gsd_run query resolve-execution gsd-plan-checker --host opencode 2>/dev/null | jq -r '.effort_argv_string // ""' 2>/dev/null || true) - -# #1115: `--dangerously-bypass-hook-trust` only exists on codex-cli >= 0.137.0. -# Capability-probe it so older installs don't fail with "unexpected argument" -# (which, with stderr suppressed, produced a silent empty review). The codex -# invocation works fine without the flag on older versions. -if codex exec --help 2>/dev/null | grep -q -- '--dangerously-bypass-hook-trust'; then - CODEX_BYPASS_FLAG="--dangerously-bypass-hook-trust" -else - CODEX_BYPASS_FLAG="" -fi ``` +**No hook-trust bypass (#2479):** the codex invocations below deliberately pass no +hook-trust bypass flag and run no capability probe for one (#1115's former gate). +That flag only bypasses *persisted* hook trust (a first-run condition) and flagless +invocations work in steady state, while host-harness safety classifiers deny +commands carrying it — and cited the probe itself as intent (#2479). An environment +that genuinely hits an untrusted-hook prompt surfaces through the `.err` capture + +empty-output guard below as a dropped lane with diagnosable stderr, not silent +attrition. Do not reintroduce the flag (even spelled out in prose here — a +regression test bans the literal file-wide) or the probe; the #1115 "unexpected +argument" failure mode existed only because the flag was emitted, so with no flag +there is nothing to version-gate. + **Reviewer instances (#1517, optional):** when instances are configured, each selected instance invokes its base `cli` with its own `model`/`agent` (opaque argv, never shell-interpolated). Exact invocation in `gsd-core/references/reviewer-instances.md`. @@ -315,18 +317,18 @@ fi **Codex:** ```bash -# $CODEX_BYPASS_FLAG is capability-gated above (#1115). Capture stderr to a .err -# file (not /dev/null) so a non-zero exit — e.g. a flag the installed codex-cli -# does not support — is diagnosable instead of a silent empty review. +# No hook-trust bypass flag — see the #2479 note above. Capture stderr to a .err +# file (not /dev/null) so a non-zero exit — e.g. an untrusted-hook prompt on a +# first run — is diagnosable instead of a silent empty review (#1115). # Capture the review via codex's own `-o/--output-last-message ` (only the # final agent message) and discard stdout (#1698): on some platforms (Windows) # codex writes process-teardown output to stdout *after* the final message, and a # stdout redirect would append that noise to a non-empty file — slipping past the # `[ ! -s … ]` empty-output guard as a silently polluted review. if [ -n "$CODEX_MODEL" ] && [ "$CODEX_MODEL" != "null" ]; then - cat {run_dir}/gsd-review-prompt.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --model "$CODEX_MODEL" $CODEX_EFFORT_ARGS --skip-git-repo-check -o {run_dir}/gsd-review-codex.md - 2>{run_dir}/gsd-review-codex.err >/dev/null + cat {run_dir}/gsd-review-prompt.md | codex exec --ephemeral --model "$CODEX_MODEL" $CODEX_EFFORT_ARGS --skip-git-repo-check -o {run_dir}/gsd-review-codex.md - 2>{run_dir}/gsd-review-codex.err >/dev/null else - cat {run_dir}/gsd-review-prompt.md | codex exec --ephemeral $CODEX_BYPASS_FLAG $CODEX_EFFORT_ARGS --skip-git-repo-check -o {run_dir}/gsd-review-codex.md - 2>{run_dir}/gsd-review-codex.err >/dev/null + cat {run_dir}/gsd-review-prompt.md | codex exec --ephemeral $CODEX_EFFORT_ARGS --skip-git-repo-check -o {run_dir}/gsd-review-codex.md - 2>{run_dir}/gsd-review-codex.err >/dev/null fi if [ ! -s {run_dir}/gsd-review-codex.md ]; then echo "Codex review failed or returned empty output. stderr:" > {run_dir}/gsd-review-codex.md @@ -504,9 +506,9 @@ fi # #2176: grant the reviewer the repo under review. Without --add-dir, agy's # permission context never receives the cwd repo — the agent anchors on its own # ~/.gemini/antigravity-cli/scratch dir and reviews the plan text in isolation -# (the exact failure the Review Instructions forbid). Capability-probed like the -# Codex bypass flag so an older agy without --add-dir still runs; the prompt -# anchor below keeps absolute-path reads possible on that fallback. +# (the exact failure the Review Instructions forbid). Capability-probed so an +# older agy without --add-dir still runs; the prompt anchor below keeps +# absolute-path reads possible on that fallback. if agy --help 2>/dev/null | grep -q -- '--add-dir'; then set -- "$@" --add-dir "$_AGY_WS" fi diff --git a/tests/fixtures/golden-install-parity/antigravity.json b/tests/fixtures/golden-install-parity/antigravity.json index 60e63695c..7fb37cf67 100644 --- a/tests/fixtures/golden-install-parity/antigravity.json +++ b/tests/fixtures/golden-install-parity/antigravity.json @@ -301,7 +301,7 @@ "gsd-core/workflows/remove-phase.md": "23b9eb0858a2535e", "gsd-core/workflows/remove-workspace.md": "1058d1d3160eb120", "gsd-core/workflows/resume-project.md": "98e2cf8908e73a52", - "gsd-core/workflows/review.md": "73ea346aebf61b77", + "gsd-core/workflows/review.md": "b6a91a893a94b56b", "gsd-core/workflows/scan.md": "46c5a73f6f682023", "gsd-core/workflows/secure-phase.md": "9564c529052d1d36", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/augment.json b/tests/fixtures/golden-install-parity/augment.json index b68bd6c20..18e87133a 100644 --- a/tests/fixtures/golden-install-parity/augment.json +++ b/tests/fixtures/golden-install-parity/augment.json @@ -372,7 +372,7 @@ "gsd-core/workflows/remove-phase.md": "df9a45f0b1880999", "gsd-core/workflows/remove-workspace.md": "f67860c795fb4bfe", "gsd-core/workflows/resume-project.md": "f28da1200e4545f4", - "gsd-core/workflows/review.md": "ed04746925ea035f", + "gsd-core/workflows/review.md": "cc0125d717a29c25", "gsd-core/workflows/scan.md": "e1c12d542e61720d", "gsd-core/workflows/secure-phase.md": "fda2361739e511ee", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/claude-local.json b/tests/fixtures/golden-install-parity/claude-local.json index 9120e2a6e..93070f1ee 100644 --- a/tests/fixtures/golden-install-parity/claude-local.json +++ b/tests/fixtures/golden-install-parity/claude-local.json @@ -371,7 +371,7 @@ "gsd-core/workflows/remove-phase.md": "8effc8742d58a11a", "gsd-core/workflows/remove-workspace.md": "64b73daff58b9aec", "gsd-core/workflows/resume-project.md": "af9761bcec0f6fe9", - "gsd-core/workflows/review.md": "7838e12644bf808a", + "gsd-core/workflows/review.md": "145646378b6243ec", "gsd-core/workflows/scan.md": "686e787d3704db90", "gsd-core/workflows/secure-phase.md": "a7272ff8163a61ac", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/claude.json b/tests/fixtures/golden-install-parity/claude.json index 04be146f7..02be55ce7 100644 --- a/tests/fixtures/golden-install-parity/claude.json +++ b/tests/fixtures/golden-install-parity/claude.json @@ -300,7 +300,7 @@ "gsd-core/workflows/remove-phase.md": "ada8a0546c686483", "gsd-core/workflows/remove-workspace.md": "015cde237c75be39", "gsd-core/workflows/resume-project.md": "7f8dc986f0f35d96", - "gsd-core/workflows/review.md": "fa72c8f343102dba", + "gsd-core/workflows/review.md": "4d4975c16d79515d", "gsd-core/workflows/scan.md": "a71e3009998cfc57", "gsd-core/workflows/secure-phase.md": "ba807b4862d7f3c9", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/cline.json b/tests/fixtures/golden-install-parity/cline.json index 56561fb76..fa6653ff0 100644 --- a/tests/fixtures/golden-install-parity/cline.json +++ b/tests/fixtures/golden-install-parity/cline.json @@ -304,7 +304,7 @@ "gsd-core/workflows/remove-phase.md": "e336350f8113a328", "gsd-core/workflows/remove-workspace.md": "79d3669cc9eb0b10", "gsd-core/workflows/resume-project.md": "e23981178fa37b3d", - "gsd-core/workflows/review.md": "2a95ced731e6d14c", + "gsd-core/workflows/review.md": "eb0a2e4e10bf92ab", "gsd-core/workflows/scan.md": "f0bd2f64f5530598", "gsd-core/workflows/secure-phase.md": "1a2e389991fc6263", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/codebuddy.json b/tests/fixtures/golden-install-parity/codebuddy.json index 0825415c2..03813638b 100644 --- a/tests/fixtures/golden-install-parity/codebuddy.json +++ b/tests/fixtures/golden-install-parity/codebuddy.json @@ -372,7 +372,7 @@ "gsd-core/workflows/remove-phase.md": "df9a45f0b1880999", "gsd-core/workflows/remove-workspace.md": "f67860c795fb4bfe", "gsd-core/workflows/resume-project.md": "f28da1200e4545f4", - "gsd-core/workflows/review.md": "ed04746925ea035f", + "gsd-core/workflows/review.md": "cc0125d717a29c25", "gsd-core/workflows/scan.md": "e1c12d542e61720d", "gsd-core/workflows/secure-phase.md": "fda2361739e511ee", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/codex.json b/tests/fixtures/golden-install-parity/codex.json index cfdefde19..05e96afb0 100644 --- a/tests/fixtures/golden-install-parity/codex.json +++ b/tests/fixtures/golden-install-parity/codex.json @@ -407,7 +407,7 @@ "gsd-core/workflows/remove-phase.md": "9ee0fddd11a0d9d4", "gsd-core/workflows/remove-workspace.md": "d0160c5d05bcb2bb", "gsd-core/workflows/resume-project.md": "9965f87eb278f7f8", - "gsd-core/workflows/review.md": "9987e9fd8f7e5adb", + "gsd-core/workflows/review.md": "b8108a114467fafe", "gsd-core/workflows/scan.md": "dcd6aac25ef39251", "gsd-core/workflows/secure-phase.md": "3ba89719288dd3f3", "gsd-core/workflows/session-report.md": "dd8fa011c9394075", diff --git a/tests/fixtures/golden-install-parity/copilot.json b/tests/fixtures/golden-install-parity/copilot.json index f8e3d7744..991790e8e 100644 --- a/tests/fixtures/golden-install-parity/copilot.json +++ b/tests/fixtures/golden-install-parity/copilot.json @@ -302,7 +302,7 @@ "gsd-core/workflows/remove-phase.md": "e262654e319d1bc4", "gsd-core/workflows/remove-workspace.md": "e7e5b5b1e0cc9d81", "gsd-core/workflows/resume-project.md": "40db7f350f5866d8", - "gsd-core/workflows/review.md": "6aad3c5254932206", + "gsd-core/workflows/review.md": "49d74c87b31abce8", "gsd-core/workflows/scan.md": "76aad4e70281c364", "gsd-core/workflows/secure-phase.md": "d60aa4053154e52f", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/cursor.json b/tests/fixtures/golden-install-parity/cursor.json index 124808242..144836b08 100644 --- a/tests/fixtures/golden-install-parity/cursor.json +++ b/tests/fixtures/golden-install-parity/cursor.json @@ -372,7 +372,7 @@ "gsd-core/workflows/remove-phase.md": "ada8a0546c686483", "gsd-core/workflows/remove-workspace.md": "0572a83d71650937", "gsd-core/workflows/resume-project.md": "7f8dc986f0f35d96", - "gsd-core/workflows/review.md": "f5972bbe92dc5f0c", + "gsd-core/workflows/review.md": "837e0cba258335b5", "gsd-core/workflows/scan.md": "a71e3009998cfc57", "gsd-core/workflows/secure-phase.md": "b008216148d2afac", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/hermes.json b/tests/fixtures/golden-install-parity/hermes.json index c6b2446ea..d36fea163 100644 --- a/tests/fixtures/golden-install-parity/hermes.json +++ b/tests/fixtures/golden-install-parity/hermes.json @@ -301,7 +301,7 @@ "gsd-core/workflows/remove-phase.md": "fce799aae3ab2715", "gsd-core/workflows/remove-workspace.md": "42029a7559f1d8fb", "gsd-core/workflows/resume-project.md": "a0443839f1f83c2d", - "gsd-core/workflows/review.md": "b7aa706def0b93d6", + "gsd-core/workflows/review.md": "0ba5a89b6b164971", "gsd-core/workflows/scan.md": "5c2370d6a8118b6c", "gsd-core/workflows/secure-phase.md": "c087131f1dd12901", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/kilo.json b/tests/fixtures/golden-install-parity/kilo.json index eaa87efcb..64dbe7162 100644 --- a/tests/fixtures/golden-install-parity/kilo.json +++ b/tests/fixtures/golden-install-parity/kilo.json @@ -372,7 +372,7 @@ "gsd-core/workflows/remove-phase.md": "ada8a0546c686483", "gsd-core/workflows/remove-workspace.md": "f5dc82bb63e2efa4", "gsd-core/workflows/resume-project.md": "7f8dc986f0f35d96", - "gsd-core/workflows/review.md": "c5c59f2bb70396ab", + "gsd-core/workflows/review.md": "e86d4d7ac6b8a025", "gsd-core/workflows/scan.md": "c039d3e40d26b606", "gsd-core/workflows/secure-phase.md": "5a8fbf603d218100", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/kimi-code.json b/tests/fixtures/golden-install-parity/kimi-code.json index 1ea320df0..1e0d27bf5 100644 --- a/tests/fixtures/golden-install-parity/kimi-code.json +++ b/tests/fixtures/golden-install-parity/kimi-code.json @@ -329,7 +329,7 @@ "gsd-core/workflows/remove-phase.md": "df9a45f0b1880999", "gsd-core/workflows/remove-workspace.md": "f67860c795fb4bfe", "gsd-core/workflows/resume-project.md": "f28da1200e4545f4", - "gsd-core/workflows/review.md": "ed04746925ea035f", + "gsd-core/workflows/review.md": "cc0125d717a29c25", "gsd-core/workflows/scan.md": "e1c12d542e61720d", "gsd-core/workflows/secure-phase.md": "fda2361739e511ee", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/kimi.json b/tests/fixtures/golden-install-parity/kimi.json index 42a8d3e63..fff3470bb 100644 --- a/tests/fixtures/golden-install-parity/kimi.json +++ b/tests/fixtures/golden-install-parity/kimi.json @@ -365,7 +365,7 @@ "gsd-core/workflows/remove-phase.md": "df9a45f0b1880999", "gsd-core/workflows/remove-workspace.md": "f67860c795fb4bfe", "gsd-core/workflows/resume-project.md": "f28da1200e4545f4", - "gsd-core/workflows/review.md": "ed04746925ea035f", + "gsd-core/workflows/review.md": "cc0125d717a29c25", "gsd-core/workflows/scan.md": "e1c12d542e61720d", "gsd-core/workflows/secure-phase.md": "fda2361739e511ee", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/opencode.json b/tests/fixtures/golden-install-parity/opencode.json index a31661f9c..fc36c2881 100644 --- a/tests/fixtures/golden-install-parity/opencode.json +++ b/tests/fixtures/golden-install-parity/opencode.json @@ -372,7 +372,7 @@ "gsd-core/workflows/remove-phase.md": "dea4661e8f89596f", "gsd-core/workflows/remove-workspace.md": "21a8581add5f31ae", "gsd-core/workflows/resume-project.md": "ad9f06a10bab8cc0", - "gsd-core/workflows/review.md": "486bc0f9ab4c24f4", + "gsd-core/workflows/review.md": "65770618edc68d3f", "gsd-core/workflows/scan.md": "cbfb79df855e5e61", "gsd-core/workflows/secure-phase.md": "ef09f40dfd4d2424", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/pi.json b/tests/fixtures/golden-install-parity/pi.json index 9d4876fce..234596a62 100644 --- a/tests/fixtures/golden-install-parity/pi.json +++ b/tests/fixtures/golden-install-parity/pi.json @@ -268,7 +268,7 @@ "gsd-core/workflows/remove-phase.md": "df9a45f0b1880999", "gsd-core/workflows/remove-workspace.md": "f67860c795fb4bfe", "gsd-core/workflows/resume-project.md": "f28da1200e4545f4", - "gsd-core/workflows/review.md": "ed04746925ea035f", + "gsd-core/workflows/review.md": "cc0125d717a29c25", "gsd-core/workflows/scan.md": "e1c12d542e61720d", "gsd-core/workflows/secure-phase.md": "fda2361739e511ee", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/qwen.json b/tests/fixtures/golden-install-parity/qwen.json index 5aced9709..f04d01908 100644 --- a/tests/fixtures/golden-install-parity/qwen.json +++ b/tests/fixtures/golden-install-parity/qwen.json @@ -301,7 +301,7 @@ "gsd-core/workflows/remove-phase.md": "e8ae4fbbfac700f0", "gsd-core/workflows/remove-workspace.md": "ae520235f4d1f4a5", "gsd-core/workflows/resume-project.md": "7f20769f302e5427", - "gsd-core/workflows/review.md": "3db704f47d7a5bde", + "gsd-core/workflows/review.md": "0c0037cacbee532f", "gsd-core/workflows/scan.md": "b7efd0d381a3b8a5", "gsd-core/workflows/secure-phase.md": "f7bfa7175102af31", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/trae.json b/tests/fixtures/golden-install-parity/trae.json index ff5efbdad..62442596c 100644 --- a/tests/fixtures/golden-install-parity/trae.json +++ b/tests/fixtures/golden-install-parity/trae.json @@ -301,7 +301,7 @@ "gsd-core/workflows/remove-phase.md": "a46c2fe853bf4e86", "gsd-core/workflows/remove-workspace.md": "8ddc5f04f7c48d6c", "gsd-core/workflows/resume-project.md": "f242e4c8aba18ea2", - "gsd-core/workflows/review.md": "b02dae5c743b1797", + "gsd-core/workflows/review.md": "db77e672b2312bba", "gsd-core/workflows/scan.md": "3b14bcb51d3a4de8", "gsd-core/workflows/secure-phase.md": "267393d5b02b5334", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/windsurf.json b/tests/fixtures/golden-install-parity/windsurf.json index 8940b64db..615387375 100644 --- a/tests/fixtures/golden-install-parity/windsurf.json +++ b/tests/fixtures/golden-install-parity/windsurf.json @@ -301,7 +301,7 @@ "gsd-core/workflows/remove-phase.md": "e7a6af429b36e77b", "gsd-core/workflows/remove-workspace.md": "30ca05fe4a3efc25", "gsd-core/workflows/resume-project.md": "82cfe1b8cb17c085", - "gsd-core/workflows/review.md": "f3fdf577dbc08f5f", + "gsd-core/workflows/review.md": "8e345b36846e11e3", "gsd-core/workflows/scan.md": "4a910da5e34f2685", "gsd-core/workflows/secure-phase.md": "d5d811bc468ce7f2", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/fixtures/golden-install-parity/zcode.json b/tests/fixtures/golden-install-parity/zcode.json index d17febbbf..9673733e8 100644 --- a/tests/fixtures/golden-install-parity/zcode.json +++ b/tests/fixtures/golden-install-parity/zcode.json @@ -372,7 +372,7 @@ "gsd-core/workflows/remove-phase.md": "df9a45f0b1880999", "gsd-core/workflows/remove-workspace.md": "f67860c795fb4bfe", "gsd-core/workflows/resume-project.md": "f28da1200e4545f4", - "gsd-core/workflows/review.md": "ed04746925ea035f", + "gsd-core/workflows/review.md": "cc0125d717a29c25", "gsd-core/workflows/scan.md": "e1c12d542e61720d", "gsd-core/workflows/secure-phase.md": "fda2361739e511ee", "gsd-core/workflows/session-report.md": "2e5b1205324ddefa", diff --git a/tests/review-default-reviewers-workflow.test.cjs b/tests/review-default-reviewers-workflow.test.cjs index 7043d290b..cda596345 100644 --- a/tests/review-default-reviewers-workflow.test.cjs +++ b/tests/review-default-reviewers-workflow.test.cjs @@ -259,15 +259,16 @@ const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); -describe('enh-773: automated codex exec invocations include --ephemeral and --dangerously-bypass-hook-trust', () => { +describe('enh-773: automated codex exec invocations include --ephemeral (hook-trust bypass dropped by #2479)', () => { const workflow = fs.readFileSync( path.join(process.cwd(), 'gsd-core', 'workflows', 'review.md'), 'utf8' ); - // Extract codex exec INVOCATION lines from code fences. The #1115 capability - // probe (`codex exec --help | grep …`) is not an automation invocation, so it - // is excluded from the per-invocation flag assertions below. + // Extract codex exec INVOCATION lines from code fences. A `codex exec --help` + // capability probe would not be an automation invocation, so keep it excluded + // from the per-invocation flag assertions below (#2479 asserts no such probe + // exists at all). const codexExecLines = workflow .split(/\r?\n/) .filter((line) => line.includes('codex exec') && !line.includes('codex exec --help')); @@ -288,29 +289,29 @@ describe('enh-773: automated codex exec invocations include --ephemeral and --da } }); - test('#1115: the hook-trust bypass is capability-gated, not passed unconditionally', () => { - // --dangerously-bypass-hook-trust only exists on codex-cli >= 0.137.0. It must - // be probed (`codex exec --help | grep`) and applied via $CODEX_BYPASS_FLAG so - // older installs do not fail with "unexpected argument" (a silent empty review). + test('#2479: no hook-trust bypass — flag and capability probe are both absent', () => { + // The flag only bypasses *persisted* hook trust (a first-run condition) and + // flagless invocations work in steady state, while host-harness safety + // classifiers deny commands carrying it — and cited the probe itself as + // intent. Inverts the former #1115 gating contract: instead of probe + gated + // $CODEX_BYPASS_FLAG, the workflow must be free of the literal flag string + // ANYWHERE in the file — not just on invocation lines — so a line + // continuation, a renamed carrier variable, or a probe grepping for it are + // all caught by the same assertion. (The #2479 prose note deliberately + // describes the flag without spelling it out, keeping the file-wide ban + // clean.) assert.ok( - /codex exec --help[^\r\n]*grep[^\r\n]*--dangerously-bypass-hook-trust/.test(workflow), - 'review.md must capability-probe --dangerously-bypass-hook-trust via `codex exec --help | grep`' + !workflow.includes('--dangerously-bypass-hook-trust'), + 'review.md must not contain --dangerously-bypass-hook-trust anywhere (#2479 — file-wide ban covers invocations, continuations, carrier variables, and probes)' ); assert.ok( - workflow.includes('CODEX_BYPASS_FLAG="--dangerously-bypass-hook-trust"'), - 'the probe must set CODEX_BYPASS_FLAG to the flag when the CLI supports it' + !workflow.includes('CODEX_BYPASS_FLAG'), + 'review.md must not interpolate a $CODEX_BYPASS_FLAG variable (#2479)' + ); + assert.ok( + !/codex[^\r\n]*--help[^\r\n]*grep/.test(workflow), + 'review.md must not capability-probe codex flags via `codex --help | grep` (#2479 — the probe itself feeds harness safety classifiers)' ); - for (const line of codexExecLines) { - assert.ok( - line.includes('$CODEX_BYPASS_FLAG'), - `codex exec invocation must apply the capability-gated $CODEX_BYPASS_FLAG, not an unconditional flag:\n ${line.trim()}` - ); - // …and must NOT also pass the literal flag (that would reintroduce #1115). - assert.ok( - !line.includes('--dangerously-bypass-hook-trust'), - `codex exec invocation must not pass the literal --dangerously-bypass-hook-trust (use the gated $CODEX_BYPASS_FLAG):\n ${line.trim()}` - ); - } }); test('#1115: codex review failures are surfaced, not silently swallowed', () => { diff --git a/tests/workflow-size-baseline.json b/tests/workflow-size-baseline.json index 260ef4378..424971eb3 100644 --- a/tests/workflow-size-baseline.json +++ b/tests/workflow-size-baseline.json @@ -64,7 +64,7 @@ "remove-phase.md": 8513, "remove-workspace.md": 7916, "resume-project.md": 17270, - "review.md": 52646, + "review.md": 52964, "scan.md": 8314, "secure-phase.md": 14627, "session-report.md": 4044,