sec(auth): a mission's door token is revoked when the mission ends
The skills-door token was minted with a 24 h TTL and nothing revoked it sooner, so a mission that finished in twenty minutes left a live credential in its container for the rest of the day. auth_sessions gains mission_id (ON DELETE CASCADE, so a purge revokes too); mint_scoped_for_mission records it; revoke_mission_sessions deletes it. Revocation runs on both terminal paths — the runner's close (RETURNING the closed ids) and the operator's stop — and says how many it cleared. Granularity is the mission, not the phase: the container and its door are installed once per mission and serve every phase. Lingering Authority (arXiv 2606.22504) is the reference. Tests: a minted token authenticates for its scope and not as a full session, is dead after revoke, and another mission's token is untouched; the harness gatepolicy scenario now runs on the index arm and asserts the server revoked ≥1, no row carries the mission, and the door answers 401 to the token. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WZb5A2kfVfjpdwSochkuHz
This commit is contained in:
co-authored by
Claude Opus 5
parent
3909fa14ca
commit
2069bdf322
@@ -1494,6 +1494,11 @@ pub async fn set_status(
|
||||
|
||||
cm_db::repo::missions::set_status(&state.pool, id, user.workspace_id.as_uuid(), &body.status)
|
||||
.await?;
|
||||
// An operator's stop is a terminal transition too, and the runner's
|
||||
// close never sees it: revoke here as well.
|
||||
if matches!(body.status.as_str(), "completed" | "failed" | "cancelled") {
|
||||
crate::mission_orchestrator::revoke_mission_credentials(&state.pool, id).await;
|
||||
}
|
||||
|
||||
let mission = cm_db::repo::missions::get(&state.pool, id, user.workspace_id.as_uuid())
|
||||
.await?
|
||||
|
||||
Reference in New Issue
Block a user