package sign_test import ( "crypto/ed25519" "encoding/json" "os" "path/filepath" "testing" "github.com/netkingdom/flex-auth/internal/sign" "github.com/netkingdom/flex-auth/pkg/api" ) // testdataSeed is a well-known non-production key. It exists so fixtures can // prove verification without an OpenBao lane (FLEX-WP-0024-T02). var testdataSeed = bytes32(0x42) func bytes32(b byte) []byte { out := make([]byte, ed25519.SeedSize) for i := range out { out[i] = b } return out } func fixtureKey() (ed25519.PublicKey, ed25519.PrivateKey) { priv := ed25519.NewKeyFromSeed(testdataSeed) return priv.Public().(ed25519.PublicKey), priv } func TestSignAndVerifyRoundTrip(t *testing.T) { pub, priv := fixtureKey() envelope := sampleEnvelope("allow") digest := envelope.Binding.RequestDigest if err := sign.Sign(&envelope, priv, "testdata-ed25519"); err != nil { t.Fatal(err) } if envelope.Binding.RequestDigest != digest { t.Fatalf("request_digest moved from %s to %s", digest, envelope.Binding.RequestDigest) } if envelope.Signature == nil || envelope.Signature.Mode != api.EnvelopeSignatureSigned { t.Fatalf("signature = %+v", envelope.Signature) } if err := sign.Verify(envelope, map[string]ed25519.PublicKey{"testdata-ed25519": pub}); err != nil { t.Fatalf("Verify: %v", err) } } func TestAlteredEnvelopeFailsVerification(t *testing.T) { pub, priv := fixtureKey() envelope := sampleEnvelope("allow") if err := sign.Sign(&envelope, priv, "testdata-ed25519"); err != nil { t.Fatal(err) } envelope.Effect = api.DecisionEffectDeny if err := sign.Verify(envelope, map[string]ed25519.PublicKey{"testdata-ed25519": pub}); err == nil { t.Fatal("tampered envelope verified") } } func TestUnsignedEnvelopeDoesNotVerify(t *testing.T) { pub, _ := fixtureKey() envelope := sampleEnvelope("allow") envelope.Signature = api.UnsignedEnvelopeSignature() if err := sign.Verify(envelope, map[string]ed25519.PublicKey{"testdata-ed25519": pub}); err == nil { t.Fatal("unsigned envelope verified") } } func TestReplayFixturesProveSuccessAndFailure(t *testing.T) { pub, _ := fixtureKey() keys := map[string]ed25519.PublicKey{"testdata-ed25519": pub} signed := loadEnvelope(t, filepath.Join("..", "..", "examples", "secrets-engine", "replay", "decision_rotate_signed.json")) if err := sign.Verify(signed, keys); err != nil { t.Fatalf("genuine fixture: %v", err) } tampered := loadEnvelope(t, filepath.Join("..", "..", "examples", "secrets-engine", "replay", "decision_rotate_signed_tampered.json")) if err := sign.Verify(tampered, keys); err == nil { t.Fatal("tampered fixture verified") } } func sampleEnvelope(effect string) api.DecisionEnvelope { return api.DecisionEnvelope{ ID: "decision:test", ContractVersion: api.DecisionRecordContractV1, Effect: api.DecisionEffect(effect), Resource: api.ResourceRef{ID: "lane:test", System: "secrets-engine"}, Subject: api.SubjectRef{ID: "secrets-engine", Type: "service"}, Binding: &api.DecisionBinding{RequestDigest: "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Action: "rotate"}, Provenance: api.DecisionProvenance{Evaluator: "flex-auth/local", Mode: "standalone"}, Signature: api.UnsignedEnvelopeSignature(), } } func loadEnvelope(t *testing.T, path string) api.DecisionEnvelope { t.Helper() data, err := os.ReadFile(path) if err != nil { t.Fatal(err) } var envelope api.DecisionEnvelope if err := json.Unmarshal(data, &envelope); err != nil { t.Fatal(err) } return envelope }