// Package httpapi exposes the signing-service's HTTP contract as a public // package so sibling modules (admin-api interop tests, future verifier // services) can build a real, in-process signing-service against which to // run end-to-end checks without duplicating ADR-0005 wire assembly. // // Production builds reach the handler through cmd/signing-service/main.go, // which wires the same internal/httpapi.Server with Pocket-ID JWKS, OPA, and // OpenBao backends. The signing-service module itself does not expose those // prod backends through this package; this is the test/interop surface only. package httpapi import ( "crypto/ed25519" "net/http" "time" internalhttpapi "basicstack.de/proofedmesh/services/signing-service/internal/httpapi" "basicstack.de/proofedmesh/services/signing-service/internal/policy" "basicstack.de/proofedmesh/services/signing-service/internal/signer" "basicstack.de/proofedmesh/services/signing-service/internal/token" ) // TestServerConfig configures the in-memory signing-service for interop tests. // All fields are required; the factory panics on empty maps so a silent typo // in a sibling module's test does not look like a successful setup. type TestServerConfig struct { // Keys maps key_ref → Ed25519 private key. The matching public key must // be held by the test so it can independently verify the returned // envelope signatures. Keys map[string]ed25519.PrivateKey // Tokens maps bearer token → subject (the Pocket-ID "sub" claim). The // handler returns 401 for any token not in this map. Tokens map[string]string // Now is injected so SignedAt is deterministic in tests. Optional. Now func() time.Time } // NewTestHandler constructs the full signing-service HTTP handler with the // in-memory signer, AllowAll policy, and static token validator. The handler // implements the ADR-0005 POST /api/v1/sign/dsse contract and exposes // GET /healthz. It is safe to wrap in an httptest.Server. func NewTestHandler(cfg TestServerConfig) http.Handler { if len(cfg.Keys) == 0 { panic("signing-service/pkg/httpapi: TestServerConfig.Keys must not be empty") } if len(cfg.Tokens) == 0 { panic("signing-service/pkg/httpapi: TestServerConfig.Tokens must not be empty") } s := signer.NewInMemory() for ref, priv := range cfg.Keys { s.AddKey(ref, priv) } srv := internalhttpapi.Server{ Signer: s, Policy: policy.AllowAll{}, Validator: token.Static(cfg.Tokens), Now: cfg.Now, } mux := http.NewServeMux() srv.Mount(mux) return mux }