feat: fresh-authorize and audit Human Gate decisions
This commit is contained in:
1 parent
4319c161cb
commit
1c66905b4a
2 files changed
+183
No files matched your search
+32
@@ -561,6 +561,7 @@ class QuietHoursPayload(BaseModel):
|
||||
|
||||
|
||||
StepUpAction = Literal[
|
||||
"decide_human_gate",
|
||||
"merge_pull",
|
||||
"delete_source_branch",
|
||||
"prepare_release_rollback",
|
||||
@@ -1884,11 +1885,35 @@ async def decide_human_gate(
|
||||
payload: HumanGateDecision,
|
||||
request: Request,
|
||||
idempotency_key: str = Header(alias="Idempotency-Key", min_length=1, max_length=128),
|
||||
step_up_grant: str | None = Header(
|
||||
default=None, alias="X-Step-Up-Grant", max_length=128
|
||||
),
|
||||
):
|
||||
await _require_step_up(
|
||||
request,
|
||||
step_up_grant,
|
||||
action="decide_human_gate",
|
||||
target=gate_id,
|
||||
)
|
||||
login = await _human_gate_login(request)
|
||||
journal = _security_event_store()
|
||||
operation_id = None
|
||||
try:
|
||||
store = _human_gate_store()
|
||||
existed = await asyncio.to_thread(store.has_receipt_key, login, idempotency_key)
|
||||
if not existed:
|
||||
try:
|
||||
operation_id = await asyncio.to_thread(
|
||||
journal.reserve,
|
||||
"human_gate_decision",
|
||||
method=payload.decision,
|
||||
target=gate_id,
|
||||
)
|
||||
except SecurityEventStoreError as error:
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail="Security activity is temporarily unavailable",
|
||||
) from error
|
||||
receipt = await asyncio.to_thread(
|
||||
store.decide,
|
||||
login,
|
||||
@@ -1901,7 +1926,14 @@ async def decide_human_gate(
|
||||
idempotency_key=idempotency_key,
|
||||
)
|
||||
except (GateValidationError, GateConflict, GateNotFound, sqlite3.Error) as error:
|
||||
if operation_id is not None:
|
||||
try:
|
||||
await asyncio.to_thread(journal.discard, operation_id)
|
||||
except SecurityEventStoreError:
|
||||
pass
|
||||
raise _gate_error(error) from error
|
||||
if operation_id is not None:
|
||||
await asyncio.to_thread(journal.finalize, operation_id)
|
||||
return JSONResponse(
|
||||
receipt, status_code=200 if existed else 201, headers={"Cache-Control": "no-store"}
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user