hub: F-14 part 2 — gated auto-Reissue on the PBS-DR enable dead-end
pbsdrProvisionAtom, on tenantsync token_exists: consult the customer's MOST RECENT host-deletion record. escrow_acked=true -> invoke the EXISTING tenantsync Reissue op, store the audit event (pbsdr_auto_reissue, hub-source, "Previous key destroyed (acknowledged deletion) - credentials re-issued automatically."), proceed to secret+descriptor as a normal provision. No record / un-acked -> the pre-existing refusal, byte-unchanged (never-silently-re-key law; operator ruling 2026-07-13). Scenario A test drives the REAL handler path over a REAL escrow-ack delete; scenario B pins the exact non-effect (zero Reissue calls, no state). Red-proof: bypassing the gate flips both B subtests to 303 (silent re-key).
This commit is contained in:
@@ -205,11 +205,38 @@ func (s *Server) pbsdrProvisionAtom(ctx context.Context, customerID string, host
|
||||
defer cancel()
|
||||
res, err := s.tenantsync.Provision(ctx, customerID)
|
||||
if errors.Is(err, tenantsync.ErrTokenExists) {
|
||||
// ep0 has a token but the hub has no descriptor — state mismatch (lost hub state or a
|
||||
// half-torn earlier attempt). Never silently re-key: the operator decides via Re-issue.
|
||||
return "", fmt.Errorf("the endpoint already holds a PBS token for %s but the hub has no descriptor — use the explicit \"Re-issue PBS credentials\" action", customerID)
|
||||
}
|
||||
if err != nil {
|
||||
// ep0 has a token but the hub has no descriptor — state mismatch (lost hub state, a
|
||||
// half-torn earlier attempt, or the F-14 shape: host deleted, tenancy survived).
|
||||
//
|
||||
// F-14 gate (operator ruling 2026-07-13): auto-re-issue is permitted ONLY when the
|
||||
// hub's own deletion record shows the tenancy's owning host — the customer's most
|
||||
// recent host deletion — was removed through the escrow-ack flow. Acknowledged
|
||||
// destruction is not silent re-keying; the old secret went down with the acked host.
|
||||
// No record / un-acked record → the refusal below, byte-unchanged (manual path).
|
||||
rec, derr := s.store.LatestHostDeletion(customerID)
|
||||
if derr != nil {
|
||||
return "", fmt.Errorf("pbsdr: deletion-provenance lookup for %s: %w", customerID, derr)
|
||||
}
|
||||
if rec == nil || !rec.EscrowAcked {
|
||||
return "", fmt.Errorf("the endpoint already holds a PBS token for %s but the hub has no descriptor — use the explicit \"Re-issue PBS credentials\" action", customerID)
|
||||
}
|
||||
res, err = s.tenantsync.Reissue(ctx, customerID) // the EXISTING re-issue op — no new endpoint interaction
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("pbsdr: F-14 auto re-issue for %s: %w", customerID, err)
|
||||
}
|
||||
note := "Previous key destroyed (acknowledged deletion) — credentials re-issued automatically."
|
||||
details, _ := json.Marshal(map[string]string{
|
||||
"deleted_host": rec.HostID,
|
||||
"deleted_at": rec.DeletedAt.UTC().Format(time.RFC3339),
|
||||
"new_host": host.HostID,
|
||||
"token_id": res.TokenID,
|
||||
})
|
||||
if _, eerr := s.store.SaveEvent(customerID, "pbsdr_auto_reissue", "info", note, string(details), "hub"); eerr != nil {
|
||||
s.logger.Printf("[WARN] pbsdr: F-14 audit event for %s not stored: %v", customerID, eerr)
|
||||
}
|
||||
s.logger.Printf("[INFO] pbsdr F-14 auto re-issue for %s: owning host %s removed via escrow-ack flow (%s) — %s",
|
||||
customerID, rec.HostID, rec.DeletedAt.UTC().Format(time.RFC3339), note)
|
||||
} else if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user