Menu

#390 test(parity): prove auth-action-bound gate on codex

closed
nobody
None
2026-08-27
2026-08-16
Anonymous
No

Originally created by: blackcoderx

Pull Request

Slice

  • Repo: doberman-core
  • Feature / Slice: parity — auth-action-bound gate on codex (closes [#331])

What this PR does

Adds the Codex sibling of tests/unit/test_hosthook_auth_challenge.py::test_approval_is_bound_to_the_action_id,
proving that an approved auth result is only honored when it's bound to the
same action id — through the Codex host-hook adapter, not just Claude Code.
No production code changes — hookio.resolve_auth's binding check
(result.approved and result.action_id == action.id) is shared by both
adapters already; the gap was test coverage on the Codex host only.

docs/PARITY.md is regenerated (python -m tools.parity.generate_parity) so
the Codex cell for "Approvals are single-use and bound to one action id"
moves from to , linking to the new test. No other cell changes.

Tests added (run in CI)

  • tests/unit/test_hosthook_codex.py::test_approval_is_bound_to_the_action_id
    — marked @pytest.mark.guarantee("auth-action-bound", host="codex").
    Monkeypatches doberman.auth.challenge.run_auth_challenge to return an
    AuthResult(approved=True, action_id="some-other-action") — approved, but
    for the wrong action — against an AUTH-tier Write to
    .github/workflows/ci.yml, and asserts codex.evaluate_pre(...) still
    denies.

Mutation-checked: temporarily dropped the result.action_id == action.id
comparison in hookio.resolve_auth and confirmed this new test goes red
(the mismatched-action approval wrongly resolves to allow); reverted before
committing.

Public-release safety (doberman-core only)

  • [x] Contains nothing from the "not allowed" list: no enterprise/hosted code, no proprietary detection, no customer data, no secrets, no commercial-license code
  • [x] Core still builds/tests/runs with NO enterprise package installed

Security checklist

  • [x] Fails closed on error / uncertainty (unchanged; this PR is test-only)
  • [x] No secret, full file, or unredacted prompt logged or committed
  • [x] Any guardrail/learning change is raise-only (no silent loosening) — N/A, no guardrail logic changed
  • [x] Every BLOCK/AUTH carries reason codes + a human explanation — unchanged, verified by the new test
  • [x] doberman-core does not import doberman_enterprise

Edge cases covered / Deviations from plan / Risks introduced

  • None beyond the issue's scope. Locally, pytest -n auto --cov=doberman --cov-fail-under=80
    reports 2842 passed / 6 skipped / 1 failed at 91.78% coverage; the one
    failure (test_real_plugin_install_discovery.py::test_installed_plugin_is_discovered_and_fires_despite_pip_target)
    is the same pre-existing, environment-specific failure noted in [#384]
    reproduced identically on a clean main in this sandbox, unrelated to this
    change.

Written with AI assistance (Claude Code) as a guided contribution walkthrough;
all commands were run and verified locally before pushing.

Related

Tickets: #331
Tickets: #384
Tickets: #391

Discussion

  • Anonymous

    Anonymous - 2026-08-16

    Originally posted by: fu351

    Merged — and this one nearly reviewed itself. You ran the mutation check before I could ask for it: dropped the action_id comparison, watched the test go red, put it back. I re-ran that exact check locally on your branch and it held — only the new test failed, with allow where deny belongs. That is precisely what a parity cell is for. Reusing the CI-config Write from the neighboring test instead of inventing a new fixture kept the diff honest, too.

    Nothing changed on your branch — merged as you wrote it.

    If you want the next one: [#334] (level-4) — the AUTH-deadline auto-deny and timeout-vs-refusal cells on Codex. Same lattice you've been building, one level up: you've already handled AuthResult, and the new wrinkle is proving the wall-clock deadline denies on its own and that a timeout is logged distinctly from a human refusal. It's yours if you say the word.

     

    Related

    Tickets: #334

  • Anonymous

    Anonymous - 2026-08-16

    Ticket changed by: fu351

    • status: open --> closed
     

Log in to post a comment.