Wait within decision validity bounds and preserve failed preflight evidence
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 3s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a09cbb-87c6-7900-a145-4ce53ba9f1a6
This commit is contained in:
tegwick 2026-09-14 03:46:28 +02:00
parent 1c9fd5279c
commit 5aaa49a2ec
7 changed files with 647 additions and 1 deletions

View file

@ -18,7 +18,7 @@
| workplan | SECRETS-WP-0007 | active | — | workplans/SECRETS-WP-0007-production-lifecycle-hardening.md |
| workplan | SECRETS-WP-0008 | active | — | workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md |
| workplan | SECRETS-WP-0009 | blocked | — | workplans/SECRETS-WP-0009-glas-claude-native-delivery.md |
| workplan | SECRETS-WP-0010 | blocked | — | workplans/SECRETS-WP-0010-openrouter-native-access.md |
| workplan | SECRETS-WP-0010 | active | — | workplans/SECRETS-WP-0010-openrouter-native-access.md |
| task | SECRETS-WP-ADHOC-2026-08-21-T01 | done | — | workplans/ADHOC-2026-08-21.md |
| task | SECRETS-WP-ADHOC-2026-08-23-T01 | done | — | workplans/ADHOC-2026-08-23.md |
| task | SECRETS-WP-0001-T01 | done | — | workplans/SECRETS-WP-0001-statehub-bootstrap.md |

View file

@ -199,3 +199,11 @@ 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.
A future `not_before` is now awaited for at most two seconds before full decision
validation. Larger skew refuses. Expiry and claim freshness are checked afterward;
the consumer never shifts its validation clock or treats a future decision as
already valid. Native preflight exposed workstation clock drift; the existing
NTP service was restarted. All three owner-store/native-PDP diagnostic joins
passed afterward, without consuming approvals. Full regression suite: 420 passed.

View file

@ -0,0 +1,557 @@
[
{
"action": "apply",
"scope": "read-only owner-store claim and native PDP diagnosis; not authenticated claim/consume execution",
"claim_valid_now": true,
"claim_reason": "ok",
"effect": "allow",
"reason": "catalog_lane_policy_matched",
"binding": {
"tenant": "tenant:platform",
"subject": {
"id": "secrets-engine",
"type": "service",
"tenant": "tenant:platform",
"attributes": {
"description": "secrets-engine's own service identity, the single calling identity for the twelve gated catalog-lane actions it sends to POST /v1/check. Because it is the only subject, the package has no action_not_granted branch (FLEX-WP-0021-T02); registering a second identity is the revisit trigger.",
"display_name": "secrets-engine service principal",
"groups": [
"group:secrets-engine-lane-operators"
],
"organization_relation": "ServiceProvider",
"roles": [
"Operator"
]
}
},
"action": "apply",
"resource": {
"id": "catalog:openrouter-llm-connect",
"type": "secret-catalog-lane",
"system": "secrets-engine",
"tenant": "tenant:platform",
"attributes": {
"auth_targets": [
"se-prod-openrouter-llm-connect"
],
"fields": [],
"policy_targets": [
"se-prod-openrouter-llm-connect"
],
"stage": "prod"
}
},
"context": {
"approval": {
"approval_id": "09592588-ab15-53e7-89b8-c4e9f29aaacf",
"binding": {
"action": "apply",
"actor": "secrets-engine",
"digest": "sha256:03cc5b37437f14e86b686ce4054f976556334eff3fa260b03e8014ed3d9217e5",
"human_control": true,
"pdp_digest": "sha256:933427642c58c54f65dd4781b8e4c8e2f358eb96497ae35870fff4bd593d2b84",
"pdp_path": true,
"principal": "secrets-engine",
"purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference",
"target": {
"attributes": {
"auth_targets": [
"se-prod-openrouter-llm-connect"
],
"fields": [],
"policy_targets": [
"se-prod-openrouter-llm-connect"
],
"stage": "prod"
},
"id": "catalog:openrouter-llm-connect",
"system": "secrets-engine",
"type": "secret-catalog-lane"
}
},
"consumed": false,
"freshness": {
"not_after": "2026-09-14T01:43:41+00:00",
"observed_at": "2026-09-14T01:43:11+00:00",
"ttl_seconds": 30
},
"issuer": "approval-engine",
"kind": "approval-claim",
"reason_code": "ok",
"schema_version": "0.1",
"state": "valid",
"valid_now": true,
"validity": {
"expires_at": "2026-09-15T00:33:06.559689+00:00",
"not_before": "2026-09-14T00:33:06.559689+00:00"
},
"yields_to": "net-kingdom taxonomy request-claim schema (statute \u00a717; unassigned)"
},
"catalog_target": {
"auth_capability": {},
"consumers": [
{
"auth": "kubernetes",
"claim": "serviceaccount:external-secrets/external-secrets",
"name": "llm-connect-activity-core",
"purpose": "sync llm-connect-provider-secrets for the activity-core deployment"
},
{
"auth": "approle",
"claim": "catalog:openrouter-llm-connect",
"name": "intelligence-radar-key-check",
"purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference"
}
],
"delivery_auth": {
"management": "engine",
"method": "approle",
"policy_name": "se-prod-openrouter-llm-connect",
"role_name": "se-prod-openrouter-llm-connect",
"secret_id_num_uses": 1,
"secret_id_ttl": "15m",
"token_max_ttl": "30m",
"token_num_uses": 8,
"token_ttl": "15m"
},
"delivery_config": {
"exec_owner": {
"command": [
"/usr/bin/python3.12",
"-I",
"-B",
"/home/worsch/.local/share/secrets-engine/recipients/openrouter-key-check-dc1569f63ef7/openrouter_key_check.py"
],
"cwd": "/run/user/1000/secrets-engine-openrouter-check",
"environment": {
"LANG": "C.UTF-8"
},
"files": {
"/home/worsch/.local/share/secrets-engine/recipients/openrouter-key-check-dc1569f63ef7/openrouter_key_check.py": {
"private": true,
"sha256": "dc1569f63ef74d73f0a735548c0573db2a1493f7ffc86945f52d0be9b27a3253"
},
"/usr/bin/python3.12": {
"private": false,
"sha256": "e50d468e8b0adfb05733f5b87b3cff34829c4a8c1aea50c865aa8bdfe4bb150f"
}
},
"owner": "intelligence-radar-key-check",
"status": "configured"
}
},
"delivery_modes": [
"exec-env",
"read-check"
],
"fields": [
"OPENROUTER_API_KEY"
],
"kind": "kv",
"mount": "platform",
"mount_management": "existing",
"org": "coulomb",
"path": "workloads/activity-core/llm-connect/llm-connect-provider-secrets",
"repo": "llm-connect",
"workload_delivery": [
{
"mode": "external-secrets",
"owner": "railiance-platform + llm-connect"
}
]
},
"human_control": true,
"purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference"
},
"request_digest": "sha256:1e2a0b721dca7a8e719a5837fd4e298be11be4c66535a0f40e11f2fa0639f9df",
"approval_binding_digest": "sha256:933427642c58c54f65dd4781b8e4c8e2f358eb96497ae35870fff4bd593d2b84",
"submitted_request_digest": "sha256:9241fdc373759d67b8db7c356730714e784804465f1a18d7c12a91bd200f3517"
},
"provenance": {
"evaluator": "flex-auth/local",
"mode": "standalone",
"policy_package": "secrets-engine.catalog-lane.lifecycle",
"policy_version": "v2",
"policy_package_digest": "sha256:bd11c5fe77ce6439c65fea225ad6b71d2110efc5e7b5bc9b499c59cd0a53b8b4",
"registry_snapshot_digest": "sha256:f5a309bc0b36721fd6d9ad7f53eb21222162bc2eac62a0ab0802a9a1d51340bb",
"input_claim_digests": {
"context": "sha256:eb41f86373ada6e123049610c1722116b1638d597069b460b2d0b3538b868a60"
},
"decision_time": "2026-09-14T01:43:11Z"
},
"validated": true
},
{
"action": "verify",
"scope": "read-only owner-store claim and native PDP diagnosis; not authenticated claim/consume execution",
"claim_valid_now": true,
"claim_reason": "ok",
"effect": "allow",
"reason": "catalog_lane_policy_matched",
"binding": {
"tenant": "tenant:platform",
"subject": {
"id": "secrets-engine",
"type": "service",
"tenant": "tenant:platform",
"attributes": {
"description": "secrets-engine's own service identity, the single calling identity for the twelve gated catalog-lane actions it sends to POST /v1/check. Because it is the only subject, the package has no action_not_granted branch (FLEX-WP-0021-T02); registering a second identity is the revisit trigger.",
"display_name": "secrets-engine service principal",
"groups": [
"group:secrets-engine-lane-operators"
],
"organization_relation": "ServiceProvider",
"roles": [
"Operator"
]
}
},
"action": "verify",
"resource": {
"id": "catalog:openrouter-llm-connect",
"type": "secret-catalog-lane",
"system": "secrets-engine",
"tenant": "tenant:platform",
"attributes": {
"auth_targets": [
"se-prod-openrouter-llm-connect"
],
"fields": [
"OPENROUTER_API_KEY"
],
"policy_targets": [
"se-prod-openrouter-llm-connect"
],
"stage": "prod"
}
},
"context": {
"approval": {
"approval_id": "9416fa31-fa9e-5603-8289-f35bc9625409",
"binding": {
"action": "verify",
"actor": "secrets-engine",
"digest": "sha256:72d9267d038c17107c880ffc9009793ce9c70defbddfe2219628854b811a04b2",
"human_control": true,
"pdp_digest": "sha256:9e36cdbf3890cc5a7e550fd57191f9c0f2a6b2180909aac302aa3b999e7e6b25",
"pdp_path": true,
"principal": "secrets-engine",
"purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference",
"target": {
"attributes": {
"auth_targets": [
"se-prod-openrouter-llm-connect"
],
"fields": [
"OPENROUTER_API_KEY"
],
"policy_targets": [
"se-prod-openrouter-llm-connect"
],
"stage": "prod"
},
"id": "catalog:openrouter-llm-connect",
"system": "secrets-engine",
"type": "secret-catalog-lane"
}
},
"consumed": false,
"freshness": {
"not_after": "2026-09-14T01:43:43+00:00",
"observed_at": "2026-09-14T01:43:13+00:00",
"ttl_seconds": 30
},
"issuer": "approval-engine",
"kind": "approval-claim",
"reason_code": "ok",
"schema_version": "0.1",
"state": "valid",
"valid_now": true,
"validity": {
"expires_at": "2026-09-15T00:33:06.722887+00:00",
"not_before": "2026-09-14T00:33:06.722887+00:00"
},
"yields_to": "net-kingdom taxonomy request-claim schema (statute \u00a717; unassigned)"
},
"catalog_target": {
"auth_capability": {},
"consumers": [
{
"auth": "kubernetes",
"claim": "serviceaccount:external-secrets/external-secrets",
"name": "llm-connect-activity-core",
"purpose": "sync llm-connect-provider-secrets for the activity-core deployment"
},
{
"auth": "approle",
"claim": "catalog:openrouter-llm-connect",
"name": "intelligence-radar-key-check",
"purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference"
}
],
"delivery_auth": {
"management": "engine",
"method": "approle",
"policy_name": "se-prod-openrouter-llm-connect",
"role_name": "se-prod-openrouter-llm-connect",
"secret_id_num_uses": 1,
"secret_id_ttl": "15m",
"token_max_ttl": "30m",
"token_num_uses": 8,
"token_ttl": "15m"
},
"delivery_config": {
"exec_owner": {
"command": [
"/usr/bin/python3.12",
"-I",
"-B",
"/home/worsch/.local/share/secrets-engine/recipients/openrouter-key-check-dc1569f63ef7/openrouter_key_check.py"
],
"cwd": "/run/user/1000/secrets-engine-openrouter-check",
"environment": {
"LANG": "C.UTF-8"
},
"files": {
"/home/worsch/.local/share/secrets-engine/recipients/openrouter-key-check-dc1569f63ef7/openrouter_key_check.py": {
"private": true,
"sha256": "dc1569f63ef74d73f0a735548c0573db2a1493f7ffc86945f52d0be9b27a3253"
},
"/usr/bin/python3.12": {
"private": false,
"sha256": "e50d468e8b0adfb05733f5b87b3cff34829c4a8c1aea50c865aa8bdfe4bb150f"
}
},
"owner": "intelligence-radar-key-check",
"status": "configured"
}
},
"delivery_modes": [
"exec-env",
"read-check"
],
"fields": [
"OPENROUTER_API_KEY"
],
"kind": "kv",
"mount": "platform",
"mount_management": "existing",
"org": "coulomb",
"path": "workloads/activity-core/llm-connect/llm-connect-provider-secrets",
"repo": "llm-connect",
"workload_delivery": [
{
"mode": "external-secrets",
"owner": "railiance-platform + llm-connect"
}
]
},
"human_control": true,
"purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference"
},
"request_digest": "sha256:9e9f8b506b94fb3d0351b2129f6804f09bc8f207230b636da2112ff722005ab9",
"approval_binding_digest": "sha256:9e36cdbf3890cc5a7e550fd57191f9c0f2a6b2180909aac302aa3b999e7e6b25",
"submitted_request_digest": "sha256:ae7fdd0a04e2d1f131cbe8e384357aa0f994ab325032b8ff2322aba4532111c7"
},
"provenance": {
"evaluator": "flex-auth/local",
"mode": "standalone",
"policy_package": "secrets-engine.catalog-lane.lifecycle",
"policy_version": "v2",
"policy_package_digest": "sha256:bd11c5fe77ce6439c65fea225ad6b71d2110efc5e7b5bc9b499c59cd0a53b8b4",
"registry_snapshot_digest": "sha256:f5a309bc0b36721fd6d9ad7f53eb21222162bc2eac62a0ab0802a9a1d51340bb",
"input_claim_digests": {
"context": "sha256:418548cb749db472a28010fdd9dbb2a20a1c6fdd35b3d756fac6c7a7abc306fe"
},
"decision_time": "2026-09-14T01:43:13Z"
},
"validated": true
},
{
"action": "exec",
"scope": "read-only owner-store claim and native PDP diagnosis; not authenticated claim/consume execution",
"claim_valid_now": true,
"claim_reason": "ok",
"effect": "allow",
"reason": "catalog_lane_policy_matched",
"binding": {
"tenant": "tenant:platform",
"subject": {
"id": "secrets-engine",
"type": "service",
"tenant": "tenant:platform",
"attributes": {
"description": "secrets-engine's own service identity, the single calling identity for the twelve gated catalog-lane actions it sends to POST /v1/check. Because it is the only subject, the package has no action_not_granted branch (FLEX-WP-0021-T02); registering a second identity is the revisit trigger.",
"display_name": "secrets-engine service principal",
"groups": [
"group:secrets-engine-lane-operators"
],
"organization_relation": "ServiceProvider",
"roles": [
"Operator"
]
}
},
"action": "exec",
"resource": {
"id": "catalog:openrouter-llm-connect",
"type": "secret-catalog-lane",
"system": "secrets-engine",
"tenant": "tenant:platform",
"attributes": {
"auth_targets": [
"se-prod-openrouter-llm-connect"
],
"fields": [
"OPENROUTER_API_KEY"
],
"policy_targets": [
"se-prod-openrouter-llm-connect"
],
"stage": "prod"
}
},
"context": {
"approval": {
"approval_id": "da678b61-35be-598e-8d95-a7aefa2fdc73",
"binding": {
"action": "exec",
"actor": "secrets-engine",
"digest": "sha256:f2cf0fb53b740900756ccde5587c3578fcff44beef2f1edab17b9a198a4033d8",
"human_control": true,
"pdp_digest": "sha256:9f17812750fc8962b0fc58fc09df136850c9935a864fafa998a1c030dfb75bd9",
"pdp_path": true,
"principal": "secrets-engine",
"purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference",
"target": {
"attributes": {
"auth_targets": [
"se-prod-openrouter-llm-connect"
],
"fields": [
"OPENROUTER_API_KEY"
],
"policy_targets": [
"se-prod-openrouter-llm-connect"
],
"stage": "prod"
},
"id": "catalog:openrouter-llm-connect",
"system": "secrets-engine",
"type": "secret-catalog-lane"
}
},
"consumed": false,
"freshness": {
"not_after": "2026-09-14T01:43:46+00:00",
"observed_at": "2026-09-14T01:43:16+00:00",
"ttl_seconds": 30
},
"issuer": "approval-engine",
"kind": "approval-claim",
"reason_code": "ok",
"schema_version": "0.1",
"state": "valid",
"valid_now": true,
"validity": {
"expires_at": "2026-09-15T00:33:06.955168+00:00",
"not_before": "2026-09-14T00:33:06.955168+00:00"
},
"yields_to": "net-kingdom taxonomy request-claim schema (statute \u00a717; unassigned)"
},
"catalog_target": {
"auth_capability": {},
"consumers": [
{
"auth": "kubernetes",
"claim": "serviceaccount:external-secrets/external-secrets",
"name": "llm-connect-activity-core",
"purpose": "sync llm-connect-provider-secrets for the activity-core deployment"
},
{
"auth": "approle",
"claim": "catalog:openrouter-llm-connect",
"name": "intelligence-radar-key-check",
"purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference"
}
],
"delivery_auth": {
"management": "engine",
"method": "approle",
"policy_name": "se-prod-openrouter-llm-connect",
"role_name": "se-prod-openrouter-llm-connect",
"secret_id_num_uses": 1,
"secret_id_ttl": "15m",
"token_max_ttl": "30m",
"token_num_uses": 8,
"token_ttl": "15m"
},
"delivery_config": {
"exec_owner": {
"command": [
"/usr/bin/python3.12",
"-I",
"-B",
"/home/worsch/.local/share/secrets-engine/recipients/openrouter-key-check-dc1569f63ef7/openrouter_key_check.py"
],
"cwd": "/run/user/1000/secrets-engine-openrouter-check",
"environment": {
"LANG": "C.UTF-8"
},
"files": {
"/home/worsch/.local/share/secrets-engine/recipients/openrouter-key-check-dc1569f63ef7/openrouter_key_check.py": {
"private": true,
"sha256": "dc1569f63ef74d73f0a735548c0573db2a1493f7ffc86945f52d0be9b27a3253"
},
"/usr/bin/python3.12": {
"private": false,
"sha256": "e50d468e8b0adfb05733f5b87b3cff34829c4a8c1aea50c865aa8bdfe4bb150f"
}
},
"owner": "intelligence-radar-key-check",
"status": "configured"
}
},
"delivery_modes": [
"exec-env",
"read-check"
],
"fields": [
"OPENROUTER_API_KEY"
],
"kind": "kv",
"mount": "platform",
"mount_management": "existing",
"org": "coulomb",
"path": "workloads/activity-core/llm-connect/llm-connect-provider-secrets",
"repo": "llm-connect",
"workload_delivery": [
{
"mode": "external-secrets",
"owner": "railiance-platform + llm-connect"
}
]
},
"exec_owner_sha256": "22393c7e751e458fa64bb24305ee66a26bbe3993c5aba03ae1fc1a488e777b42",
"human_control": true,
"purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference"
},
"request_digest": "sha256:0d18ec993f609e9fcaa0d0b18314d1cbfd10e5e16176748f0c21abbd3bf27c51",
"approval_binding_digest": "sha256:9f17812750fc8962b0fc58fc09df136850c9935a864fafa998a1c030dfb75bd9",
"submitted_request_digest": "sha256:1da3ba876912a80bf0df729ab58325d4ec8da2ff3b77f25bd4157a874f6faa06"
},
"provenance": {
"evaluator": "flex-auth/local",
"mode": "standalone",
"policy_package": "secrets-engine.catalog-lane.lifecycle",
"policy_version": "v2",
"policy_package_digest": "sha256:bd11c5fe77ce6439c65fea225ad6b71d2110efc5e7b5bc9b499c59cd0a53b8b4",
"registry_snapshot_digest": "sha256:f5a309bc0b36721fd6d9ad7f53eb21222162bc2eac62a0ab0802a9a1d51340bb",
"input_claim_digests": {
"context": "sha256:da1e2a9704eb5aae6a6cc2d24154246221668d2bd293c0e204f5d0c9d4fb8047"
},
"decision_time": "2026-09-14T01:43:16Z"
},
"validated": true
}
]

View file

@ -0,0 +1,24 @@
{
"status": "failed",
"phase": "preflight",
"observed_at": "2026-09-14T01:32:29.742409+00:00",
"actions": [],
"health_before": {
"deployment": [
{
"namespace": "activity-core",
"name": "llm-connect",
"ready": 1
}
],
"externalsecret": [
{
"namespace": "activity-core",
"name": "llm-connect-provider-secrets",
"ready": true
}
]
},
"failure_type": "DecisionError",
"owner_forwards_closed": true
}

View file

@ -25,6 +25,7 @@ from secrets_engine.decision_check import check_decision
from secrets_engine.authorization import (
build_action_request,
validate_decision_envelope,
wait_for_decision_start,
)
from secrets_engine.errors import DecisionError
from secrets_engine.openbao import read_strict_token_file
@ -312,6 +313,7 @@ def authorize_action(
request=expected_request,
opener=pdp_opener or urlopen,
)
wait_for_decision_start(envelope)
validated = validate_decision_envelope(
envelope,
expected_request,

View file

@ -10,6 +10,7 @@ import copy
import hashlib
import json
import re
import time
import uuid
from dataclasses import dataclass
from datetime import datetime, timezone
@ -399,3 +400,24 @@ def validate_decision_envelope(
request_digest=evaluated,
submitted_request_digest=submitted,
)
def wait_for_decision_start(envelope: object, *, clock=None, sleeper=None) -> None:
"""Wait at most two seconds for an owner's future start, never waive it.
Full decision/claim validation still runs afterward against the real clock.
Longer skew refuses rather than holding an approval claim until it is stale.
"""
current_time = clock or (lambda: datetime.now(timezone.utc))
sleep = sleeper or time.sleep
if not isinstance(envelope, dict):
return
lifetime = _required_dict(envelope, "lifetime")
if lifetime.get("not_before") is None:
return
start = _parse_time(lifetime["not_before"], "not_before")
delay = (start - current_time()).total_seconds()
if delay > 2:
raise DecisionError("flex-auth decision start exceeds bounded wait")
if delay > 0:
sleep(delay)

View file

@ -0,0 +1,33 @@
from datetime import datetime, timedelta, timezone
import pytest
from secrets_engine.authorization import wait_for_decision_start
from secrets_engine.errors import DecisionError
@pytest.mark.parametrize("offset,expected", [(-1, []), (0, []), (0.25, [0.25]), (2, [2])])
def test_waits_until_start_without_changing_the_envelope(offset, expected):
now = datetime(2026, 9, 14, tzinfo=timezone.utc)
envelope = {"lifetime": {"not_before": (now + timedelta(seconds=offset)).isoformat()}}
calls = []
wait_for_decision_start(envelope, clock=lambda: now, sleeper=calls.append)
assert calls == expected
assert envelope["lifetime"]["not_before"] == (now + timedelta(seconds=offset)).isoformat()
def test_large_skew_refuses_without_sleep():
now = datetime(2026, 9, 14, tzinfo=timezone.utc)
with pytest.raises(DecisionError, match="bounded wait"):
wait_for_decision_start({"lifetime": {"not_before": (now + timedelta(seconds=3)).isoformat()}},
clock=lambda: now, sleeper=lambda _: pytest.fail("must not sleep"))
def test_wait_does_not_waive_expiration_or_start_validation():
from secrets_engine.authorization import validate_decision_envelope
from tests.test_action_authorization import _envelope, _request
request = _request()
envelope = _envelope(request)
now = datetime(2026, 9, 14, tzinfo=timezone.utc)
envelope["lifetime"] = {"not_before": (now + timedelta(seconds=1)).isoformat(),
"expires_at": (now + timedelta(seconds=2)).isoformat()}
wait_for_decision_start(envelope, clock=lambda: now, sleeper=lambda _: None)
with pytest.raises(DecisionError, match="has not started"):
validate_decision_envelope(envelope, request, accepted_policy_packages={"secrets-engine.catalog-lane.lifecycle"}, accepted_policy_versions={"v2"}, now=now)
with pytest.raises(DecisionError, match="expired"):
validate_decision_envelope(envelope, request, accepted_policy_packages={"secrets-engine.catalog-lane.lifecycle"}, accepted_policy_versions={"v2"}, now=now + timedelta(seconds=3))