Menu

#384 test(parity): prove gitignored-delete gate on mcp-proxy

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

Originally created by: blackcoderx

Pull Request

Slice

  • Repo: doberman-core
  • Feature / Slice: parity — gitignored-delete gate on mcp-proxy (closes [#330])

What this PR does

Adds the MCP-proxy sibling of tests/unit/test_rule_commands.py::test_unrecoverable_gitignored_data_delete_requires_auth,
proving the AN-1 guarantee ("deleting unrecoverable gitignored data is gated")
holds through the proxy's wiring, not just at the engine-rule level. No
production code changes — DestructiveCommandRule already enforces this; the
gap was test coverage on this host only.

docs/PARITY.md is regenerated (python -m tools.parity.generate_parity) so
the Mcp Proxy cell for that guarantee moves from to , linking to the
new test. No other cell changes.

Tests added (run in CI)

  • tests/integration/test_engine_blocks_reach_no_tool.py::test_unrecoverable_gitignored_delete_requires_auth
    — marked @pytest.mark.guarantee("gitignored-delete-gate", host="mcp-proxy").
    Sends rm data/app.db as a shell_exec call through the real proxied
    session (DEFAULT_OBJECTIVE left un-stubbed, only run_auth_challenge is
    monkeypatched to a deterministic denial), and asserts the result is an
    AUTH-required error and that the fake downstream recorded nothing.

Mutation-checked: temporarily commented out the unrecoverable-data branch
in _segment_verdict (src/doberman/engine/rules/commands.py) and confirmed
this new test goes red (assert result.isError fails: the call passes
through unmediated instead); 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 2841 passed / 6 skipped / 1 failed at 91.92% coverage; the one
    failure (test_real_plugin_install_discovery.py::test_installed_plugin_is_discovered_and_fires_despite_pip_target)
    is a pre-existing, environment-specific failure reproduced identically on
    a clean, unmodified main in this sandbox (an isolated venv it pip-installs
    into can't import doberman afterward) — unrelated to this change and not
    introduced by it.

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

Related

Tickets: #330
Tickets: #389
Tickets: #390
Tickets: #391

Discussion

  • Anonymous

    Anonymous - 2026-08-16

    Originally posted by: fu351

    Merged. Two decisions here were exactly right: you left DEFAULT_OBJECTIVE real so the actual DestructiveCommandRule makes the call (a stubbed rule would only prove the mock), and you closed the loop with fake.calls == [], which is the assertion that matters: gated means the downstream server never saw the call. Regenerating PARITY.md with the tool instead of hand-editing the cell kept the matrix honest too. Great first contribution.

    Nothing was changed on your branch.

    If you want another cell, [#331] (approvals are single-use and action-bound on Codex, level-3) is a natural next: the same prove-a-guarantee shape, but on the auth path you just mocked. Comment there and it's yours.

    We're on Discord if you want faster feedback or to argue threat models: https://discord.gg/Sfy5XGNqty

     

    Related

    Tickets: #331

  • Anonymous

    Anonymous - 2026-08-16

    Ticket changed by: fu351

    • status: open --> closed
     

Log in to post a comment.