Align native CLI execution with approved T03 targets and authority
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a09cbb-87c6-7900-a145-4ce53ba9f1a6
This commit is contained in:
parent
09422db079
commit
25a7d71cf5
8 changed files with 90 additions and 8 deletions
|
|
@ -188,3 +188,14 @@ pins — and that pin has not been created, so the PDP call is not wired yet.
|
||||||
- It does not render or cache an authorization decision.
|
- It does not render or cache an authorization decision.
|
||||||
- It does not infer consumption from a decision record or from local
|
- It does not infer consumption from a decision record or from local
|
||||||
evidence.
|
evidence.
|
||||||
|
|
||||||
|
|
||||||
|
### Native CLI authority and target correction — 2026-09-14
|
||||||
|
|
||||||
|
The CLI now submits the catalog's explicit policy and AppRole targets, matching
|
||||||
|
its frozen review inputs. After a valid native claim/PDP join, it retains the
|
||||||
|
actual PDP decision id for evidence and still requires successful CAS consume.
|
||||||
|
The catalog CCR reference remains provenance; the native path does not demand a
|
||||||
|
second hub decision or local fixture with that CCR identifier. Unserved legacy
|
||||||
|
build/test paths retain their existing review gate. Claim, PDP, human-control,
|
||||||
|
stance, freshness and consume refusals still prevent backend access.
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,11 @@ class AuthorizedAction:
|
||||||
decision_id: str
|
decision_id: str
|
||||||
expires_at: str
|
expires_at: str
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self) -> str:
|
||||||
|
"""The actual PDP decision id for shared CLI evidence/plan callers."""
|
||||||
|
return self.decision_id
|
||||||
|
|
||||||
def as_evidence(self) -> dict[str, object]:
|
def as_evidence(self) -> dict[str, object]:
|
||||||
return {
|
return {
|
||||||
"authorization_decision_id": self.decision_id,
|
"authorization_decision_id": self.decision_id,
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,9 @@ def _require_lane_approval(
|
||||||
# unreachable-engine residue inapplicable. Absent configuration returns
|
# unreachable-engine residue inapplicable. Absent configuration returns
|
||||||
# None and production stays closed exactly as before.
|
# None and production stays closed exactly as before.
|
||||||
authorization = authorize_action(
|
authorization = authorize_action(
|
||||||
cfg, entry, action or "unknown", None, fields=fields
|
cfg, entry, action or "unknown", None, fields=fields,
|
||||||
|
policy_targets=(entry.policy_name,) if entry.has_delivery_auth else (),
|
||||||
|
auth_targets=(entry.role_name,) if entry.has_delivery_auth else (),
|
||||||
)
|
)
|
||||||
stance = apply_unreachable_engine_stance(
|
stance = apply_unreachable_engine_stance(
|
||||||
cfg, entry, action or "unknown", authorized=authorization is not None
|
cfg, entry, action or "unknown", authorized=authorization is not None
|
||||||
|
|
@ -135,8 +137,11 @@ def _require_lane_approval(
|
||||||
evidence.mark_stance(stance)
|
evidence.mark_stance(stance)
|
||||||
if authorization is not None:
|
if authorization is not None:
|
||||||
evidence.detail.update(authorization.as_evidence())
|
evidence.detail.update(authorization.as_evidence())
|
||||||
decision = None
|
# A served claim/PDP decision is the native authority. The CCR reference
|
||||||
if entry.approval_required():
|
# remains provenance; the hub/fixture path is only the legacy fallback.
|
||||||
|
# Neither path can discharge the required native CAS below.
|
||||||
|
decision = authorization
|
||||||
|
if authorization is None and entry.approval_required():
|
||||||
decision = resolve_decision(
|
decision = resolve_decision(
|
||||||
hub_url=cfg.hub_url,
|
hub_url=cfg.hub_url,
|
||||||
repo_root=repo_root(),
|
repo_root=repo_root(),
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ def test_cli_gate_exchanges_for_claim_and_consume(tmp_path, monkeypatch, failure
|
||||||
monkeypatch.setattr(approval_auth, "credential_urlopen", exchange)
|
monkeypatch.setattr(approval_auth, "credential_urlopen", exchange)
|
||||||
cfg.approval_url = cfg.pdp_url = stub.url
|
cfg.approval_url = cfg.pdp_url = stub.url
|
||||||
from secrets_engine.approval_consume import _expected_request
|
from secrets_engine.approval_consume import _expected_request
|
||||||
stub.bind_request(_expected_request(cfg, entry, "apply"))
|
stub.bind_request(_expected_request(cfg, entry, "apply", policy_targets=(entry.policy_name,), auth_targets=(entry.role_name,)))
|
||||||
if failure == "conflict":
|
if failure == "conflict":
|
||||||
stub.consume_status = 409
|
stub.consume_status = 409
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -359,3 +359,25 @@ def test_confirmed_consume_allows_openbao_resolve(tmp_path, monkeypatch):
|
||||||
assert records[-1]["detail"]["approval_consumed"] is True
|
assert records[-1]["detail"]["approval_consumed"] is True
|
||||||
assert records[-1]["detail"]["approval_id"] == "appr_test-1"
|
assert records[-1]["detail"]["approval_id"] == "appr_test-1"
|
||||||
assert TOKEN not in json.dumps(records)
|
assert TOKEN not in json.dumps(records)
|
||||||
|
|
||||||
|
|
||||||
|
def test_native_human_control_uses_real_join_not_a_hub_fixture(tmp_path, monkeypatch):
|
||||||
|
entry = validate_entry(dict(VALID, stage="prod", approval={"model": "ccr",
|
||||||
|
"human_control": True, "decision_ref": "CCR-native-provenance"}))
|
||||||
|
authorized = _authorized()
|
||||||
|
monkeypatch.setattr(cli, "authorize_action", lambda *_a, **_k: authorized)
|
||||||
|
monkeypatch.setattr(cli, "apply_unreachable_engine_stance", _allow_prod_stance)
|
||||||
|
monkeypatch.setattr(cli, "resolve_decision", lambda **_k: pytest.fail("native authority must not resolve a legacy fixture"))
|
||||||
|
calls = []
|
||||||
|
def consume(cfg, actual, **kwargs):
|
||||||
|
assert kwargs["binding"] is authorized.binding
|
||||||
|
calls.append("consume")
|
||||||
|
monkeypatch.setattr(cli, "require_production_consume", consume)
|
||||||
|
result = cli._require_lane_approval(_config(tmp_path), entry, "apply")
|
||||||
|
assert result is authorized and result.id == authorized.decision_id
|
||||||
|
assert calls == ["consume"]
|
||||||
|
def refused(*_a, **_k):
|
||||||
|
raise DecisionError("consume refused")
|
||||||
|
monkeypatch.setattr(cli, "require_production_consume", refused)
|
||||||
|
with pytest.raises(DecisionError, match="consume refused"):
|
||||||
|
cli._require_lane_approval(_config(tmp_path), entry, "apply")
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ def _prime(stub, cfg, entry, action="apply"):
|
||||||
"""Tell the stub which exact request the engine will propose."""
|
"""Tell the stub which exact request the engine will propose."""
|
||||||
from secrets_engine.approval_consume import _expected_request
|
from secrets_engine.approval_consume import _expected_request
|
||||||
|
|
||||||
stub.bind_request(_expected_request(cfg, entry, action))
|
stub.bind_request(_expected_request(cfg, entry, action, policy_targets=(entry.policy_name,), auth_targets=(entry.role_name,)))
|
||||||
|
|
||||||
|
|
||||||
def test_full_authorization_chain_reaches_openbao(bao_dev, stub, lane, tmp_path):
|
def test_full_authorization_chain_reaches_openbao(bao_dev, stub, lane, tmp_path):
|
||||||
|
|
@ -136,7 +136,7 @@ def test_full_authorization_chain_reaches_openbao(bao_dev, stub, lane, tmp_path)
|
||||||
cfg = _cfg(tmp_path, catalog_dir, stub, addr)
|
cfg = _cfg(tmp_path, catalog_dir, stub, addr)
|
||||||
_prime(stub, cfg, entry)
|
_prime(stub, cfg, entry)
|
||||||
|
|
||||||
authorization = authorize_action(cfg, entry, "apply", None)
|
authorization = authorize_action(cfg, entry, "apply", None, policy_targets=(entry.policy_name,), auth_targets=(entry.role_name,))
|
||||||
assert authorization is not None
|
assert authorization is not None
|
||||||
assert authorization.decision_id == "decision:stub-apply"
|
assert authorization.decision_id == "decision:stub-apply"
|
||||||
assert stub.calls == ["claim", "check"], "PIP then PDP, in that order"
|
assert stub.calls == ["claim", "check"], "PIP then PDP, in that order"
|
||||||
|
|
|
||||||
|
|
@ -59,3 +59,26 @@ def test_openrouter_plan_exposes_all_limits_and_preserves_existing_custody():
|
||||||
"token_ttl": "15m", "token_max_ttl": "30m", "token_num_uses": 8,
|
"token_ttl": "15m", "token_max_ttl": "30m", "token_num_uses": 8,
|
||||||
"secret_id_ttl": "15m", "secret_id_num_uses": 1,
|
"secret_id_ttl": "15m", "secret_id_num_uses": 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("action", ["apply", "verify", "exec"])
|
||||||
|
def test_cli_submits_the_exact_reviewed_openrouter_targets(action, tmp_path, monkeypatch):
|
||||||
|
import json
|
||||||
|
from secrets_engine import cli
|
||||||
|
from secrets_engine.authorization import digest_material
|
||||||
|
from secrets_engine.config import Config
|
||||||
|
root = Path(__file__).resolve().parents[1]
|
||||||
|
entry = load_entry(root / "docs/proposals/openrouter-key-check.yaml")
|
||||||
|
expected = json.loads((root / f"docs/evidence/2026-09-14-openrouter-final-{action}-request.json").read_text())
|
||||||
|
class Observed(Exception):
|
||||||
|
pass
|
||||||
|
def observe(cfg, actual_entry, actual_action, decision, **kwargs):
|
||||||
|
actual = build_action_request(actual_entry, actual_action,
|
||||||
|
subject_id="secrets-engine", subject_type="service",
|
||||||
|
purpose=actual_entry.approval["purpose"], **kwargs)
|
||||||
|
assert digest_material(actual) == digest_material(expected)
|
||||||
|
raise Observed
|
||||||
|
monkeypatch.setattr(cli, "authorize_action", observe)
|
||||||
|
with pytest.raises(Observed):
|
||||||
|
cli._require_lane_approval(Config.load(), entry, action,
|
||||||
|
fields=() if action == "apply" else tuple(entry.fields))
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ type: workplan
|
||||||
title: "Native OpenRouter access for intelligence-radar"
|
title: "Native OpenRouter access for intelligence-radar"
|
||||||
domain: infotech
|
domain: infotech
|
||||||
repo: secrets-engine
|
repo: secrets-engine
|
||||||
status: blocked
|
status: active
|
||||||
owner: codex
|
owner: codex
|
||||||
topic_slug: netkingdom
|
topic_slug: netkingdom
|
||||||
created: "2026-09-14"
|
created: "2026-09-14"
|
||||||
|
|
@ -52,7 +52,7 @@ and bounded plan are review artifacts, not runtime grants.
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: SECRETS-WP-0010-T03
|
id: SECRETS-WP-0010-T03
|
||||||
status: wait
|
status: progress
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "2aa6d2d3-bebc-5ae2-a04b-1bb2e9605405"
|
state_hub_task_id: "2aa6d2d3-bebc-5ae2-a04b-1bb2e9605405"
|
||||||
```
|
```
|
||||||
|
|
@ -180,3 +180,19 @@ Repeatable contained helper: key-cape/tools/register-informed-decision.py
|
||||||
(default preflight; --apply mutates only a missing exact registration).
|
(default preflight; --apply mutates only a missing exact registration).
|
||||||
Human callback/MFA/token proof and T03 approval entries remain pending. The
|
Human callback/MFA/token proof and T03 approval entries remain pending. The
|
||||||
previous ready check established service health, not browser login acceptance.
|
previous ready check established service health, not browser login acceptance.
|
||||||
|
|
||||||
|
|
||||||
|
### Human approval and execution preparation — 2026-09-14
|
||||||
|
|
||||||
|
The three native Approval Engine records are approved by the actual signed-in
|
||||||
|
human uid=platform-root,ou=people,dc=netkingdom,dc=local, with one human entry each
|
||||||
|
and no consumption at inspection. The exact action/memo IDs remain unchanged.
|
||||||
|
Execution preflight found and corrected two CLI gaps: missing explicit policy/
|
||||||
|
role targets, and an unnecessary hub/fixture lookup after an already validated
|
||||||
|
native claim/PDP join. Real claim validation and mandatory CAS remain in place;
|
||||||
|
unserved legacy review paths are unchanged. 414 regression tests passed, including
|
||||||
|
frozen approved-request comparisons and consume-refusal/backend isolation.
|
||||||
|
The attended owner procedure is in platform scripts/t03-native-execution.py and
|
||||||
|
t03-attended-delivery.py. It uses the exact scoped client reader, contained
|
||||||
|
platform administration, named/pinned native pods, private runtime storage, and
|
||||||
|
native CLI handlers. No approval has yet been consumed by this preparation.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue