package tlog // Interop test: the real admin-api HTTPSubmitter talks to the real // transparency-log HTTP handler + in-memory backend from the sibling // services/transparency-log module. This proves end-to-end that the // ADR-0005 wire shape agreed on both sides (field names, status codes, // idempotency semantics, content_hash algorithm) is actually compatible. // // The transparency-log module is pulled in via a replace directive in the // top-level go.mod. import ( "context" "net/http/httptest" "testing" "basicstack.de/proofedmesh/services/admin-api/internal/attest" tlbackend "basicstack.de/proofedmesh/services/transparency-log/pkg/backend" tlhttp "basicstack.de/proofedmesh/services/transparency-log/pkg/httpapi" ) func TestInterop_HTTPSubmitter_HappyPathAndIdempotency(t *testing.T) { backendMem := tlbackend.NewMemory() server := httptest.NewServer((&tlhttp.Server{Backend: backendMem}).Handler()) defer server.Close() sub := HTTPSubmitter{BaseURL: server.URL, TokenSource: attest.StaticToken("dev")} env := attest.Envelope{ PayloadType: "application/vnd.in-toto+json", Payload: "aGVsbG8", Signatures: []attest.EnvelopeSignature{{KeyID: "k", Sig: "c2ln"}}, } ch, err := attest.EnvelopeContentHash(env) if err != nil { t.Fatalf("hash: %v", err) } r1, err := sub.Submit(context.Background(), env, ch) if err != nil { t.Fatalf("first submit: %v", err) } if r1.LogIndex != 0 { t.Errorf("first log_index: want 0, got %d", r1.LogIndex) } if r1.ContentHash != ch { t.Errorf("content_hash echoed wrong: %q vs %q", r1.ContentHash, ch) } if r1.InclusionProof.TreeSize != 1 { t.Errorf("tree_size: %d", r1.InclusionProof.TreeSize) } // Idempotent repeat. r2, err := sub.Submit(context.Background(), env, ch) if err != nil { t.Fatalf("second submit: %v", err) } if r2.LogIndex != r1.LogIndex { t.Errorf("idempotent log_index drifted: %d -> %d", r1.LogIndex, r2.LogIndex) } if r2.InclusionProof.TreeRootHash != r1.InclusionProof.TreeRootHash { t.Errorf("tree_root drifted without new entries") } // Second distinct envelope — tree grows. envB := env envB.Payload = "d29ybGQ" chB, _ := attest.EnvelopeContentHash(envB) rB, err := sub.Submit(context.Background(), envB, chB) if err != nil { t.Fatalf("submit B: %v", err) } if rB.LogIndex != 1 { t.Errorf("second entry log_index: want 1, got %d", rB.LogIndex) } if rB.InclusionProof.TreeSize != 2 { t.Errorf("tree_size after B: %d", rB.InclusionProof.TreeSize) } } func TestInterop_HTTPSubmitter_ContentHashMismatchFails(t *testing.T) { server := httptest.NewServer((&tlhttp.Server{Backend: tlbackend.NewMemory()}).Handler()) defer server.Close() sub := HTTPSubmitter{BaseURL: server.URL, TokenSource: attest.StaticToken("dev")} env := attest.Envelope{ PayloadType: "application/vnd.in-toto+json", Payload: "aGVsbG8", Signatures: []attest.EnvelopeSignature{{KeyID: "k", Sig: "c2ln"}}, } // Wrong hash on purpose. Server must respond 409; the client surfaces // that as an error. _, err := sub.Submit(context.Background(), env, "sha256:00000000000000000000000000000000000000000000000000000000deadbeef") if err == nil { t.Fatalf("expected error on content_hash mismatch, got nil") } }