mirror of
https://github.com/luxfi/mpc.git
synced 2026-09-24 00:26:24 +00:00
fix(cc/attest): TDX/NRAS stubs error-return instead of panic
TDX.Verify and NRAS.Verify panicked when reached during stage 1 of issue #222, taking the whole MPC process down whenever Dispatch was called from a request-handling goroutine. The fail-loud guarantee is preserved by returning ErrNotImplemented (a hard refusal — callers must not paper over it) so the release gate still refuses, but the process survives. Updates verifier_test.go's stub coverage from TestStubsPanic to TestStubsReturnNotImplemented and adds Dispatch-path coverage for the same behaviour.
This commit is contained in:
+4
-4
@@ -34,15 +34,15 @@ import (
|
||||
// evidence, opts...) entry point with an internal JWKS cache and the
|
||||
// canonical VerifiedReport output shape.
|
||||
//
|
||||
// Verify panics so any caller routing NRAS evidence to it during stage 1
|
||||
// fails LOUD. See TDX.Verify for the rationale.
|
||||
// Verify returns ErrNotImplemented so the call site refuses the release
|
||||
// without crashing the process. See TDX.Verify for the rationale.
|
||||
type NRAS struct{}
|
||||
|
||||
// Verify implements Verifier. NOT YET IMPLEMENTED — do not enable NRAS
|
||||
// dispatch in production until #222 stage 3 lands.
|
||||
func (NRAS) Verify(ctx context.Context, evidence []byte, opts ...Option) (*VerifiedReport, error) {
|
||||
panic(fmt.Sprintf("%v: NRAS verifier; tracked at #222 stage 3 (use NRAS JWT + JWKS cache)",
|
||||
ErrNotImplemented))
|
||||
return nil, fmt.Errorf("%w: NRAS attestation envelope verification not configured for this build (tracked at #222 stage 3: NRAS JWT + JWKS cache)",
|
||||
ErrNotImplemented)
|
||||
}
|
||||
|
||||
var _ Verifier = NRAS{}
|
||||
|
||||
+10
-8
@@ -26,19 +26,21 @@ import (
|
||||
// - Compose CompositeHash via the same domain-separated SHA-256 as
|
||||
// the SEV path (see verifier.go::computeCompositeHash).
|
||||
//
|
||||
// Verify panics so any caller routing TDX evidence to it during stage 1
|
||||
// fails LOUD. A silent no-op or error-return would let the release gate
|
||||
// accidentally accept evidence the verifier has not actually checked;
|
||||
// panic + recover at the Dispatch site is cheaper to diagnose and
|
||||
// impossible to ignore in CI. Callers that want to soft-skip TDX should
|
||||
// gate on a feature flag at their layer rather than here.
|
||||
// Verify returns ErrNotImplemented so the call site refuses the release
|
||||
// without crashing the process. Callers MUST treat this exactly like
|
||||
// any other refusal: do not release, do not fall back. A silent no-op
|
||||
// or success would let the release gate accidentally accept evidence
|
||||
// the verifier has not actually checked; the explicit error-return path
|
||||
// preserves the same hard-refusal guarantee while letting Dispatch be
|
||||
// invoked from request-handling goroutines without taking the whole
|
||||
// process down.
|
||||
type TDX struct{}
|
||||
|
||||
// Verify implements Verifier. NOT YET IMPLEMENTED — do not enable TDX
|
||||
// dispatch in production until #222 stage 2 lands.
|
||||
func (TDX) Verify(ctx context.Context, evidence []byte, opts ...Option) (*VerifiedReport, error) {
|
||||
panic(fmt.Sprintf("%v: TDX verifier; tracked at #222 stage 2 (use go-tdx-guest + Intel PCS)",
|
||||
ErrNotImplemented))
|
||||
return nil, fmt.Errorf("%w: TDX attestation envelope verification not configured for this build (tracked at #222 stage 2: go-tdx-guest + Intel PCS)",
|
||||
ErrNotImplemented)
|
||||
}
|
||||
|
||||
var _ Verifier = TDX{}
|
||||
|
||||
@@ -233,12 +233,15 @@ func TestDispatch_RejectsUnknownKind(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestStubsPanic confirms the TDX/NRAS stubs FAIL LOUD rather than silently
|
||||
// returning nil. This is the only test the stubs need: it guards against an
|
||||
// accidental future change that silently accepts evidence the verifier
|
||||
// hasn't actually checked. When stages 2 + 3 of #222 land, replace this
|
||||
// test with real verify cases.
|
||||
func TestStubsPanic(t *testing.T) {
|
||||
// TestStubsReturnNotImplemented confirms the TDX/NRAS stubs FAIL LOUD —
|
||||
// returning ErrNotImplemented (a hard refusal callers must not paper
|
||||
// over) rather than silently returning a nil error. This guards against
|
||||
// an accidental future change that silently accepts evidence the
|
||||
// verifier hasn't actually checked, while keeping the failure
|
||||
// recoverable so request-handling goroutines do not crash the whole
|
||||
// process. When stages 2 + 3 of #222 land, replace this test with real
|
||||
// verify cases.
|
||||
func TestStubsReturnNotImplemented(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
v Verifier
|
||||
@@ -249,11 +252,39 @@ func TestStubsPanic(t *testing.T) {
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Fatalf("%s.Verify did not panic; stubs MUST fail loud", c.name)
|
||||
if r := recover(); r != nil {
|
||||
t.Fatalf("%s.Verify panicked (must error-return instead): %v", c.name, r)
|
||||
}
|
||||
}()
|
||||
_, _ = c.v.Verify(context.Background(), []byte{0x00})
|
||||
rep, err := c.v.Verify(context.Background(), []byte{0x00})
|
||||
if rep != nil {
|
||||
t.Fatalf("%s.Verify returned non-nil report: %+v", c.name, rep)
|
||||
}
|
||||
if !errors.Is(err, ErrNotImplemented) {
|
||||
t.Fatalf("%s.Verify returned %v, want ErrNotImplemented", c.name, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestDispatch_StubKindsReturnNotImplemented covers the Dispatch path
|
||||
// for the stub kinds: the entry point must surface ErrNotImplemented
|
||||
// instead of crashing.
|
||||
func TestDispatch_StubKindsReturnNotImplemented(t *testing.T) {
|
||||
for _, kind := range []Kind{KindTDX, KindNRAS} {
|
||||
t.Run(string(kind), func(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Fatalf("Dispatch(%s) panicked: %v", kind, r)
|
||||
}
|
||||
}()
|
||||
rep, err := Dispatch(context.Background(), kind, []byte{0x00})
|
||||
if rep != nil {
|
||||
t.Fatalf("Dispatch(%s) returned non-nil report: %+v", kind, rep)
|
||||
}
|
||||
if !errors.Is(err, ErrNotImplemented) {
|
||||
t.Fatalf("Dispatch(%s) returned %v, want ErrNotImplemented", kind, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user