5.3 KiB
5.3 KiB
Dual-Control Signing Ceremonies (M-of-N Threshold)
Module
Signer
Status
VERIFIED
Description
Orchestrator for M-of-N threshold signing ceremonies requiring multiple authorized participants to approve key operations, with API endpoints for ceremony initiation, participant enrollment, share submission, and ceremony completion.
Implementation Details
- CeremonyOrchestrator:
src/Signer/StellaOps.Signer/StellaOps.Signer.Core/Ceremonies/CeremonyOrchestrator.cs-- full M-of-N orchestration: CreateCeremonyAsync (configurable threshold/expiration per operation type), ApproveCeremonyAsync (duplicate detection, approver validation via ICeremonyApproverValidator, signature verification), ExecuteCeremonyAsync (only from Approved state), CancelCeremonyAsync, ProcessExpiredCeremoniesAsync (batch expiry); ICeremonyAuditSink for all lifecycle events - CeremonyStateMachine:
src/Signer/StellaOps.Signer/StellaOps.Signer.Core/Ceremonies/CeremonyStateMachine.cs-- enforces valid state transitions: Pending -> PartiallyApproved -> Approved -> Executed; terminal states (Executed/Expired/Cancelled); CanAcceptApproval, CanExecute, CanCancel guards; ComputeStateAfterApproval for threshold-based transitions - CeremonyModels:
src/Signer/StellaOps.Signer/StellaOps.Signer.Core/Ceremonies/CeremonyModels.cs-- Ceremony, CeremonyApproval, CeremonyResult, CeremonyFilter, CeremonyState enum (Pending/PartiallyApproved/Approved/Executed/Expired/Cancelled), CeremonyOperationType enum (KeyGeneration/KeyRotation/KeyRevocation/KeyExport/KeyImport/KeyRecovery), CeremonyErrorCode enum - CeremonyOptions:
src/Signer/StellaOps.Signer/StellaOps.Signer.Core/Ceremonies/CeremonyOptions.cs-- configurable thresholds and expiration per operation type - CeremonyAuditEvents:
src/Signer/StellaOps.Signer/StellaOps.Signer.Core/Ceremonies/CeremonyAuditEvents.cs-- Initiated, Approved, ApprovalRejected, ThresholdReached, Executed, Cancelled, Expired audit event types - ICeremonyOrchestrator:
src/Signer/StellaOps.Signer/StellaOps.Signer.Core/Ceremonies/ICeremonyOrchestrator.cs-- interface contract - ICeremonyRepository:
src/Signer/StellaOps.Signer/StellaOps.Signer.Core/Ceremonies/ICeremonyRepository.cs-- persistence interface: CreateAsync, GetByIdAsync, HasApprovedAsync, AddApprovalAsync, UpdateStateAsync, ListAsync, GetExpiredCeremoniesAsync, MarkExpiredAsync - CeremonyEndpoints:
src/Signer/StellaOps.Signer/StellaOps.Signer.WebService/Endpoints/CeremonyEndpoints.cs-- REST API at/api/v1/ceremonies: POST / (create, ceremony:create), GET / (list with state/operationType/initiatedBy/tenantId/limit/offset filters), GET /{ceremonyId} (get by ID), POST /{ceremonyId}/approve (ceremony:approve, base64 signature required), POST /{ceremonyId}/execute (ceremony:execute), DELETE /{ceremonyId} (ceremony:cancel); all require ceremony:read authorization - Tests:
src/Signer/StellaOps.Signer/StellaOps.Signer.Tests/Ceremonies/CeremonyOrchestratorIntegrationTests.cs,CeremonyStateMachineTests.cs - Source: SPRINT_20260112_018_SIGNER_dual_control_ceremonies.md
E2E Test Plan
- POST /api/v1/ceremonies creates a new ceremony with threshold, expiration, and operation type; verify 201 response with ceremonyId
- POST /{ceremonyId}/approve accepts approval with base64 signature; verify duplicate approval returns 409, unauthorized approver returns 403
- Verify state transitions: Pending -> PartiallyApproved (after first approval) -> Approved (when threshold reached) -> Executed (after execution)
- POST /{ceremonyId}/execute succeeds only when state is Approved; verify 409 for non-approved states
- DELETE /{ceremonyId} cancels ceremony; verify only non-terminal ceremonies can be cancelled
- Verify expired ceremonies cannot accept approvals or be executed (409)
- GET / returns filtered list with pagination (limit/offset) and state/operationType filters
- Verify audit events are recorded for all lifecycle transitions (Initiated, Approved, Executed, Cancelled, Expired)
Verification
- Run ID: run-001
- Date: 2026-02-10
- Method: Tier 1 code review + Tier 2d existing test verification
- Build: PASS (0 errors, 0 warnings)
- Tests: PASS (491/491 signer tests pass)
- Code Review:
- CeremonyOrchestrator: Complete M-of-N orchestration verified. CreateCeremonyAsync generates UUID ceremony ID, sets Pending state with configurable threshold. ApproveCeremonyAsync checks for duplicate approvals, validates approver via ICeremonyApproverValidator, verifies signature, calls ComputeStateAfterApproval. ExecuteCeremonyAsync gate-checks Approved state. CancelCeremonyAsync rejects terminal states. ProcessExpiredCeremoniesAsync batch-processes expired ceremonies.
- CeremonyStateMachine: Deterministic state transitions verified. Pending -> PartiallyApproved (first approval), PartiallyApproved -> Approved (threshold met). Terminal states (Executed/Expired/Cancelled) reject all transitions.
- CeremonyEndpoints: Full REST API at /api/v1/ceremonies. All endpoints require ceremony:read authorization. CRUD + approve + execute + cancel operations verified with correct HTTP status codes.
- Tests: CeremonyOrchestratorIntegrationTests (end-to-end flow with in-memory repository), CeremonyStateMachineTests (all state transitions, guards, edge cases).
- Verdict: PASS