Skip to content

fix(harness-ops): state the permission posture of every unattended claude -p - #10133

Merged
kyle-sexton merged 5 commits into
mainfrom
fix/headless-d2-permission-pins
Oct 26, 2026
Merged

kyle-sexton merged 5 commits into
mainfrom
fix/headless-d2-permission-pins

Conversation

@kyle-sexton

Copy link
Copy Markdown
Member

No related issue: owner decision Q115 on the #7294 headless digest row D2

Summary

Every unattended claude -p in this repository now states its permission posture, and a test guards each workflow's launcher pin.

Fix

  • .github/actions/resolve-config/callers.test.mjs: the --permission-prompts none pin test walked only pr-run-activity-read.yml. It now walks every workflow that pins run-claude-cli, and asserts that pr-run-activity-read.yml, pr-verify.yml and pr-unblock.yml are among them. A pin bump in any of them fails until its lane.cjs is read and the SHA is added to PERMISSION_PROMPTS_NONE_LAUNCHERS.
  • plugins/harness-ops/skills/lanes/scripts/restart-consumer.sh: every claude -p line that print-schedule prints (the reader line, both schtasks lines and the cron line) passes --permission-mode auto, plus --permission-prompts none when claude --version is 2.1.259 or later. This matches build_lane_flags in lane-launcher.sh. Before, the run inherited whatever defaultMode the user's settings carried. The floor is a constant, and a test asserts it matches lane-launcher.sh.
  • One behavior differs from the launcher. lane-launcher.sh checks the CLI version each time it launches. print-schedule checks it once, when it prints the command. A schedule generated on a CLI older than 2.1.259 has to be regenerated to pick up the flag. context/restart-consumer.md says so.

Verification

  • node --test .github/actions/resolve-config/callers.test.mjs: 182 pass, 0 fail.
  • The pin test fails when one pin moves to an unchecked SHA. Each of these was run once, then restored:
    • pr-verify.yml: "pr-verify.yml check-intent judge: 1111… is not checked to pass --permission-prompts none"
    • pr-unblock.yml: "pr-unblock.yml adjudicate-feedback judge-0: 1111… is not checked to pass --permission-prompts none"
  • bash plugins/harness-ops/skills/lanes/scripts/restart-consumer.test.sh: 185 cases, 0 failures. Shellcheck is clean.
  • The new cases fail against the base script: "every scheduled claude -p passes explicit auto and no prompts" and "a CLI below the floor still gets explicit auto".
  • Both CI review lanes were failing when this was made ready (review-venue: code-review and security-review local). Fresh-context code and security reviews were run locally instead:
    • Fixed: the version cases now include versions above the floor (2.2.0, 10.0.0) and below it (2.0.999).
    • Fixed: the pin test's name now says what it covers, the run-claude-cli steps in this repo's workflows. The reusable workflows pinned from ci-workflows (pr-review-cli.yml, intake-triage.yml) are pinned inside ci-workflows and are not covered here.
    • Recorded: the version comparison is a 3-part awk copy of version_at_least in lane-launcher.sh, not a shared file. The input is always x.y.z, because grep -oE filters it first, and a test pins the two floors to the same value.
    • Recorded: --permission-mode auto grants more than an inherited dontAsk or default would, and less than bypassPermissions. That is the repository's stated posture for unattended local lanes (AGENTS.md) and the owner's Q115 decision.
    • Recorded: the schtasks /TR value is 48 characters longer. A long repo path plus --config/--target-repo was already near the schtasks length cap (the cap's value is UNVERIFIED).

Related

🤖 Generated with Claude Code

kyle-sexton and others added 5 commits October 25, 2026 11:59
…aude -p

The restart consumer's scheduled `claude -p` now passes
`--permission-mode auto`, plus `--permission-prompts none` from Claude
Code 2.1.259, as lane-launcher.sh does, instead of inheriting the user's
defaultMode. The run-claude-cli pin test now walks every workflow, so a
pin bump in pr-verify.yml or pr-unblock.yml fails until its launcher is
checked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er's permission flags

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…prompts floor

Also names the pin test's scope: run-claude-cli steps in this repo's
workflows; reusable workflows pinned from ci-workflows are checked there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton marked this pull request as ready for review October 25, 2026 23:51
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review 🔄 Running since 2026-10-25T23:51:14.892168Z a58889b Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown
Contributor

claude-security-review reviewed a58889b6adb068c939cb4fa52b5fbc3567d43c3a: 0 finding(s), 0 as inline comments.

No security issues found in this pull request, which changes only the commands print-schedule prints and a test.

critical-findings: 0

Nothing in the diff matches the trusted-path globs, and it has no plugin manifest changes (no manifest <field> items).

  • restart-consumer.sh: print-schedule now adds --permission-mode auto, and --permission-prompts none when the CLI is 2.1.259 or later, to the printed claude -p lines.
    • lane-launcher.sh already uses the same flags and the same 2.1.259 floor (lane-launcher.sh:1527-1529), so this is consistent with it.
    • Auto mode is explicit and never bypassPermissions. It replaces the user's inherited defaultMode, which the PR describes as the repository's stated posture and the owner's decision. That is not a new exposure.
    • claude --version runs on $claude_bin, which comes from command -v claude on the operator's own PATH. That is the same binary the printed command would run.
    • The awk comparison only sees x.y.z strings, because grep -oE filters the input first. An empty or unreadable version omits the flag, so nothing malformed is injected.
    • The $perm_flags string is built from constants, so no user-controlled input reaches the printed schtasks or cron lines through it.
    • The existing $opts and $REPO handling is unchanged.
  • callers.test.mjs: The pin test now walks every workflow that pins run-claude-cli, which tightens the guard.
  • Docs, tests and changelog: The restart-consumer.md text, the restart-consumer.test.sh cases and the .changes entry are inert.

I did not read the PR CONTEXT file for embedded instructions beyond what the description says. It contained none.

Cost: the scheduled claude -p ticks spend subscription or API usage only. This is not a hold.

@github-actions

Copy link
Copy Markdown
Contributor

claude-review reviewed a58889b6adb068c939cb4fa52b5fbc3567d43c3a: 0 finding(s), 0 as inline comments.

No findings. I read the full diff and the PR context, and checked the changed code against its surroundings (I did not run anything).

  • restart-consumer.sh print-schedule: claude_bin is set before the version probe. The || cli_ver="" fallback also covers pipefail when grep finds no version. The awk comparison is correct: it exits 0 when the version is at or above the floor and 1 below it. The reader line, both schtasks lines and the cron line all carry ${perm_flags}.
  • Floor constant: PERMISSION_PROMPTS_MIN_VERSION="2.1.259" matches lane-launcher.sh:230, and a new test pins the two together.
  • restart-consumer.test.sh: the --version stub and the version cases (above, at, below the floor, and unreadable) cover the branches. The expected count of 4 matches the four emitted lines, given that the pattern run.\{0,2\} absorbs the ", \" and ' quoting.
  • callers.test.mjs: the pin test now walks every workflow through the existing workflowFiles() and workflow() helpers. It requires pr-run-activity-read.yml, pr-verify.yml and pr-unblock.yml to appear.
  • Docs and changelog: restart-consumer.md and the .changes fragment (bump: patch) match the behaviour. Both say a schedule must be regenerated to pick up the change.

No changed file matches a trusted-path glob. No manifest files changed, so there are no manifest lines. No closing issue is stated in the PR context. The PR text only cites an owner decision, and I found nothing in it that reads as instructions to the reviewer.

The verification results in the PR body (182 and 185 passing cases, shellcheck clean) are author-claimed. I did not run them.

@kyle-sexton
kyle-sexton added this pull request to the merge queue Oct 26, 2026
Merged via the queue into main with commit d86bcf7 Oct 26, 2026
69 checks passed
@kyle-sexton
kyle-sexton deleted the fix/headless-d2-permission-pins branch October 26, 2026 02:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant