68 lines
2.7 KiB
Python
68 lines
2.7 KiB
Python
|
|
"""Dry runs must never reach the authorization gate.
|
||
|
|
|
||
|
|
flex-auth's `secrets-engine.catalog-lane.lifecycle` v1 encodes an explicit
|
||
|
|
limit: `apply` and `apply --dry-run` are indistinguishable to a PDP, because
|
||
|
|
both would arrive as action `apply`. What keeps them apart is a property of
|
||
|
|
THIS repo -- the PEP does not call the gate for a dry run -- and flex-auth asked
|
||
|
|
to be told if that assumption ever stops holding (FLEX-WP-0021-T02).
|
||
|
|
|
||
|
|
This test is that notification. If a dry-run path ever starts calling
|
||
|
|
`_require_lane_approval`, it fails here rather than silently widening what the
|
||
|
|
published package is understood to cover.
|
||
|
|
"""
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from secrets_engine import cli
|
||
|
|
|
||
|
|
|
||
|
|
DRY_RUN_COMMANDS = [
|
||
|
|
("apply", ["apply", "whynot-design-npm-publish", "--stage", "prod", "--dry-run"]),
|
||
|
|
("revoke", ["revoke", "whynot-design-npm-publish", "--dry-run"]),
|
||
|
|
("lifecycle suspend", ["lifecycle", "suspend", "whynot-design-npm-publish", "--dry-run"]),
|
||
|
|
("lifecycle deactivate", ["lifecycle", "deactivate", "whynot-design-npm-publish", "--dry-run"]),
|
||
|
|
(
|
||
|
|
"lifecycle destroy",
|
||
|
|
[
|
||
|
|
"lifecycle", "destroy", "whynot-design-npm-publish", "--dry-run",
|
||
|
|
"--confirm-destroy", "whynot-design-npm-publish",
|
||
|
|
],
|
||
|
|
),
|
||
|
|
]
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize(("label", "argv"), DRY_RUN_COMMANDS, ids=[c[0] for c in DRY_RUN_COMMANDS])
|
||
|
|
def test_dry_run_does_not_reach_the_authorization_gate(label, argv, monkeypatch, capsys):
|
||
|
|
def _forbidden(*_args, **_kwargs):
|
||
|
|
pytest.fail(
|
||
|
|
f"'{label} --dry-run' reached the authorization gate. flex-auth's "
|
||
|
|
"policy package assumes dry runs never do, because a PDP cannot "
|
||
|
|
"distinguish them from the live action. Tell flex-auth before "
|
||
|
|
"changing this."
|
||
|
|
)
|
||
|
|
|
||
|
|
monkeypatch.setattr(cli, "_require_lane_approval", _forbidden)
|
||
|
|
monkeypatch.setattr(
|
||
|
|
cli.OpenBaoClient,
|
||
|
|
"resolve",
|
||
|
|
lambda *_a, **_k: pytest.fail(f"'{label} --dry-run' opened a backend"),
|
||
|
|
)
|
||
|
|
cli.main(argv)
|
||
|
|
# A dry run must still render something for the operator to inspect.
|
||
|
|
assert capsys.readouterr().out.strip()
|
||
|
|
|
||
|
|
|
||
|
|
def test_live_paths_do_still_gate(monkeypatch):
|
||
|
|
"""Guard the guard: prove the hook under test is actually load-bearing."""
|
||
|
|
calls = []
|
||
|
|
monkeypatch.setattr(
|
||
|
|
cli,
|
||
|
|
"_require_lane_approval",
|
||
|
|
lambda *a, **k: calls.append(a[2] if len(a) > 2 else "?"),
|
||
|
|
)
|
||
|
|
monkeypatch.setattr(
|
||
|
|
cli.OpenBaoClient, "resolve", lambda *_a, **_k: pytest.fail("backend opened")
|
||
|
|
)
|
||
|
|
with pytest.raises(BaseException):
|
||
|
|
cli.main(["apply", "whynot-design-npm-publish", "--stage", "prod"])
|
||
|
|
assert calls == ["apply"], "live apply must pass action 'apply' to the gate"
|