Files
mpc/pkg/scheduler/orchestrator_integration_test.go
zeekay 9c6ee31cd4 v0.61+v0.62: scheduler trust gate + NVIDIA attestation primitives
v0.61 — wire the scheduler workload-policy gate into the MPC SignGate.
SignGate gains optional Scheduler + Worker fields; AuthorizeSign now
runs scheduler.Eligible(worker, ci.PolicyID) BEFORE the policy
verifier and short-circuits on insufficient trust posture. Existing
callers that pass nil Scheduler are unaffected.

  pkg/scheduler/policy_gate.go     — TrustMode/IOLevel enums,
                                     WorkloadPolicy.Eligible(Worker)
  pkg/scheduler/service_drain.go   — AuthorizeDrain + AuthorizeSession
  pkg/mpc/sign_orchestrator.go     — Scheduler/Worker fields,
                                     WithScheduler(...), two-stage gate

v0.62 — NVIDIA Confidential-Compute attestation primitives. Clean-room
parsers + verifiers against the publicly documented nvTrust schema
(Apache-2 derived); no NVIDIA proprietary code vendored.

  pkg/attestation/nvidia/gpu_report.go   — GPU evidence-report parser
  pkg/attestation/nvidia/nras_client.go  — NRAS HTTP client + JWS verify
  pkg/attestation/nvidia/rim.go          — RIM signature + value match
  pkg/attestation/nvidia/composite.go    — VerifiedBundle (CPU+GPU bind)

Tests (57 passing, -race clean):
  pkg/scheduler                        — 11 (truth-table, drain,
                                          session, orchestrator
                                          integration)
  pkg/attestation/nvidia               — 46 (parser, RIM Ed25519/ECDSA/
                                          RSA-PSS, NRAS happy/error/
                                          signature paths, ECDSA JOSE)
  pkg/attestation/nvidia (hwattest)    — 3, env-skipped without real GPU

Sibling v0.60 reconciliation: pkg/registry + pkg/attestation already
land WorkerCapability + CompositeAttestation envelope using lattice
trust types. nvidia.VerifiedBundle is renamed (was Composite-) to
avoid collision with pkg/attestation.CompositeAttestation; the
canonical envelope wraps the verified blobs this package emits.

Residual: lattice/v7/types is not yet published, so pkg/registry +
pkg/attestation cannot compile against luxfi/[email protected]; the
sibling v0.60 work tracks that. pkg/policy still has a pre-existing
unresolved import of luxfi/fhe/threshold (should be /pkg/threshold);
sign_orchestrator_scheduler_test.go is ready to run as soon as that
upstream issue is fixed by its owner.
2025-12-28 16:53:46 -08:00

100 lines
3.5 KiB
Go

package scheduler
import (
"errors"
"testing"
)
// TestOrchestratorIntegration_TrustGateRunsBeforePolicy proves the
// integration contract that pkg/mpc.SignGate now relies on:
//
// - The scheduler is consulted with (Worker, ci.PolicyID) BEFORE
// any policy-bundle verification work.
// - A worker below MinTrust short-circuits with ErrInsufficientTrust
// wrapped from Eligible.
// - A worker at or above MinTrust returns nil, allowing the caller
// (the policy verifier) to proceed.
//
// This is the behavioral contract the orchestrator file imports the
// scheduler for; testing it here keeps the proof close to the scheduler
// logic and avoids the upstream pkg/policy build dependency that is
// pre-existing breakage in this branch.
func TestOrchestratorIntegration_TrustGateRunsBeforePolicy(t *testing.T) {
// Workload requires GPU + private lane + attested CPU+GPU.
policy := &WorkloadPolicy{
WorkloadID: "p-prod",
MinTrust: TrustGPU,
MinIO: IOPrivateLane,
RequireGPUAttested: true,
RequireCPUAttested: true,
RequireModelConfidentiality: false, // simplify
}
src := NewStaticPolicySource(map[string]*WorkloadPolicy{"p-prod": policy})
s := New(src)
// Eligible worker matches the policy floors.
good := Worker{
ID: "node-good", TrustMode: TrustGPU, IOLevel: IOPrivateLane,
GPUAttested: true, CPUAttested: true, Online: true,
}
if err := s.Eligible(good, "p-prod"); err != nil {
t.Fatalf("expected eligible, got %v", err)
}
// Worker below GPU trust → reject. Wraps ErrInsufficientTrust via
// AuthorizeSession; via Eligible, returns descriptive error.
bad := good
bad.TrustMode = TrustCVM
if err := s.Eligible(bad, "p-prod"); err == nil {
t.Fatal("expected ineligible")
}
// Worker offline — second-level guard.
off := good
off.Online = false
if err := s.Eligible(off, "p-prod"); err == nil {
t.Fatal("expected offline rejection")
}
// Workload not found in the policy source — distinct error.
if err := s.Eligible(good, "ghost-policy"); err == nil {
t.Fatal("expected lookup error")
}
}
// TestOrchestratorIntegration_AuthorizeSession_FiltersWorkers proves the
// scheduler's AuthorizeSession (used by the sign coordinator to pick
// the t+1 nodes that may participate) excludes any worker that fails
// any gate, in stable order. This is the multi-node analogue of the
// per-call gate inside SignGate.AuthorizeSign.
func TestOrchestratorIntegration_AuthorizeSession_FiltersWorkers(t *testing.T) {
policy := &WorkloadPolicy{
WorkloadID: "p-prod",
MinTrust: TrustGPU,
MinIO: IOPrivateLane,
RequireGPUAttested: true,
RequireCPUAttested: true,
}
src := NewStaticPolicySource(map[string]*WorkloadPolicy{"p-prod": policy})
s := New(src)
good1 := Worker{ID: "n1", TrustMode: TrustGPU, IOLevel: IOPrivateLane, GPUAttested: true, CPUAttested: true, Online: true}
good2 := Worker{ID: "n2", TrustMode: TrustGPU, IOLevel: IOPrivateLane, GPUAttested: true, CPUAttested: true, Online: true}
bad := good1
bad.ID = "n3"
bad.GPUAttested = false // missing GPU attestation
out, err := s.AuthorizeSession("p-prod", []Worker{good1, bad, good2}, 2)
if err != nil {
t.Fatalf("authorize: %v", err)
}
if len(out) != 2 || out[0].ID != "n1" || out[1].ID != "n2" {
t.Fatalf("ordering or filter wrong: %+v", out)
}
// Below threshold → ErrInsufficientTrust.
if _, err := s.AuthorizeSession("p-prod", []Worker{bad}, 1); !errors.Is(err, ErrInsufficientTrust) {
t.Fatalf("got %v", err)
}
}