132 lines
10 KiB
Markdown
132 lines
10 KiB
Markdown
# 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
|
|
- [x] POST /api/v1/ceremonies creates a new ceremony with threshold, expiration, and operation type; verify 201 response with ceremonyId
|
|
- [x] POST /{ceremonyId}/approve accepts approval with base64 signature; verify duplicate approval returns 409, unauthorized approver returns 403
|
|
- [x] Verify state transitions: Pending -> PartiallyApproved (after first approval) -> Approved (when threshold reached) -> Executed (after execution)
|
|
- [x] POST /{ceremonyId}/execute succeeds only when state is Approved; verify 409 for non-approved states
|
|
- [x] DELETE /{ceremonyId} cancels ceremony; verify only non-terminal ceremonies can be cancelled
|
|
- [x] Verify expired ceremonies cannot accept approvals or be executed (409)
|
|
- [x] GET / returns filtered list with pagination (limit/offset) and state/operationType filters
|
|
- [x] 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
|
|
|
|
## Recheck (Run-002)
|
|
- **Verified**: 2026-02-10
|
|
- **Method**: Tier 2a live API replay + Tier 1 regression suite replay.
|
|
- **Tests**: PASS (496/496 signer tests pass).
|
|
- **Tier 2 Evidence**: `docs/qa/feature-checks/runs/signer/dual-control-signing-ceremonies/run-002/tier2-api-check.json`
|
|
- **Regression Coverage Added**: `Ceremonies_CreateAndGet_WorksForAuthenticatedCaller`.
|
|
- **Outcome**: Ceremony endpoints are now fully wired at runtime (create/get verified via public API).
|
|
|
|
## Recheck (Run-003)
|
|
- **Verified**: 2026-02-10
|
|
- **Method**: Tier 2 follow-up deterministic replay.
|
|
- **Tests**: PASS (`src/Signer/StellaOps.Signer/StellaOps.Signer.Tests`: 496/496).
|
|
- **Tier 2 Evidence**: `docs/qa/feature-checks/runs/signer/dual-control-signing-ceremonies/run-003/tier2-api-check.json`
|
|
- **Outcome**: Ceremony API lifecycle behavior remains stable with registered orchestrator services.
|
|
|
|
|
|
## Recheck (Run-004)
|
|
- **Verified**: 2026-02-10
|
|
- **Method**: Tier 2 replay + full Signer suite replay.
|
|
- **Tests**: PASS (`src/Signer/StellaOps.Signer/StellaOps.Signer.Tests`: 496/496).
|
|
- **Tier 2 Evidence**: `docs/qa/feature-checks/runs/signer/dual-control-signing-ceremonies/run-004/tier2-api-check.json`
|
|
- **Outcome**: Ceremony create/get API behavior remains stable.
|
|
|
|
## Recheck (Run-005)
|
|
- **Verified**: 2026-02-10
|
|
- **Method**: Tier 2 replay validated via Signer suite and endpoint coverage.
|
|
- **Tests**: PASS (src/Signer/StellaOps.Signer/StellaOps.Signer.Tests: 496/496).
|
|
- **Tier 2 Evidence**: docs/qa/feature-checks/runs/signer/dual-control-signing-ceremonies/run-005/tier2-api-check.json
|
|
- **Outcome**: Checked signer behavior remains healthy in follow-up replay.
|
|
|
|
## Recheck (Run-006)
|
|
- **Verified**: 2026-02-10
|
|
- **Method**: Tier 2 replay (API + integration) with deterministic signer suite verification.
|
|
- **Tests**: PASS (src/Signer/StellaOps.Signer/StellaOps.Signer.Tests: 496/496).
|
|
- **Tier 2 Evidence**: docs/qa/feature-checks/runs/signer/dual-control-signing-ceremonies/run-006/tier2-api-check.json
|
|
- **Outcome**: Checked signer behavior remains healthy in continued replay.
|
|
|
|
## Recheck (Run-007)
|
|
- **Verified**: 2026-02-10
|
|
- **Method**: Tier 2 replay (API + integration) with deterministic signer suite verification.
|
|
- **Tests**: PASS (src/Signer/StellaOps.Signer/StellaOps.Signer.Tests: 496/496).
|
|
- **Tier 2 Evidence**: docs/qa/feature-checks/runs/signer/dual-control-signing-ceremonies/run-007/tier2-api-check.json
|
|
- **Outcome**: Checked signer behavior remains healthy in continued replay.
|
|
|
|
## Recheck (Run-008)
|
|
- **Verified**: 2026-02-10
|
|
- **Method**: Tier 2a API replay + deterministic integration suite replay.
|
|
- **Tests**: PASS (src/Signer/StellaOps.Signer/StellaOps.Signer.Tests: 496/496).
|
|
- **Tier 2 Evidence**: docs/qa/feature-checks/runs/signer/dual-control-signing-ceremonies/run-008/tier2-api-check.json
|
|
- **Outcome**: Checked Signer behavior remains healthy in continued replay.
|
|
|
|
|
|
## Recheck (Run-009)
|
|
- **Verified**: 2026-02-10
|
|
- **Method**: Tier 2a API replay + deterministic integration suite replay.
|
|
- **Tests**: PASS (src/Signer/StellaOps.Signer/StellaOps.Signer.Tests: 496/496).
|
|
- **Tier 2 Evidence**: docs/qa/feature-checks/runs/signer/dual-control-signing-ceremonies/run-009/tier2-api-check.json
|
|
- **Outcome**: Checked Signer behavior remains healthy in continued replay.
|
|
|
|
|
|
## Recheck (Run-010)
|
|
- **Verified**: 2026-02-10
|
|
- **Method**: Tier 2d deterministic integration replay.
|
|
- **Tests**: PASS (src/Signer/StellaOps.Signer/StellaOps.Signer.Tests: 496/496).
|
|
- **Tier 2 Evidence**: docs/qa/feature-checks/runs/signer/dual-control-signing-ceremonies/run-010/tier2-integration-check.json
|
|
- **Outcome**: Checked signer behavior remains healthy in continued replay.
|
|
## Recheck (Run-011)
|
|
- **Verified**: 2026-02-10
|
|
- **Method**: Tier 2d deterministic integration replay.
|
|
- **Tests**: PASS (src/Signer/StellaOps.Signer/StellaOps.Signer.Tests: 496/496).
|
|
- **Tier 2 Evidence**: docs/qa/feature-checks/runs/signer/dual-control-signing-ceremonies/run-011/tier2-integration-check.json
|
|
- **Outcome**: Checked signer behavior remains healthy in continued replay.
|
|
## Recheck (Run-012)
|
|
- **Verified**: 2026-02-10
|
|
- **Method**: Tier 2 replay + deterministic integration suite replay.
|
|
- **Tests**: PASS (src/Signer/StellaOps.Signer/StellaOps.Signer.Tests: 496/496).
|
|
- **Tier 2 Evidence**: docs/qa/feature-checks/runs/signer/dual-control-signing-ceremonies/run-012/tier2-api-check.json
|
|
- **Outcome**: Checked signer behavior remains healthy in continued replay.
|
|
|
|
## Recheck (Run-013)
|
|
- **Verified**: 2026-02-10
|
|
- **Method**: Tier 2a live API replay on running Signer service (`http://127.0.0.1:10051`) + deterministic suite replay.
|
|
- **Tests**: PASS (src/Signer/StellaOps.Signer/StellaOps.Signer.Tests: 497/497).
|
|
- **Tier 2 Evidence**: docs/qa/feature-checks/runs/signer/dual-control-signing-ceremonies/run-013/tier2-api-check.json
|
|
- **Outcome**: Invalid `operationType` now returns `400 Bad Request` (client validation) instead of `500 Internal Server Error`; live create/get/approve/execute and negative-path semantics are stable.
|