niko_trust/internal/protocol/helpers_test.go
Niko Marmeladkov 9d66003689
Initial commit: signed-object trust relay, verifier, and docs
- server: relay storing signed objects (PUT/GET), per-IP rate limiting,
  per-subject quota (1000), one-response-per-request, pagination,
  /v1/healthz /v1/readyz /v1/metrics
- verify: signature-verifying trust evaluator; every object is checked via
  env.Verify(), approvals via VerifyApprovalResponse, revocations via
  VerifyRevocationOf; k-of-n approval quorum
- docs: TRUST-MODEL.md and API.md describing issuer-anchored signatures and
  the endpoint/status-code contract
- tests: server, verify, and ratelimit packages
2026-08-12 22:36:49 +03:00

118 lines
2.8 KiB
Go

package protocol_test
import (
"encoding/hex"
"encoding/json"
"os"
"testing"
"git.n1ko.dev/Niko/niko_trust/internal/identity/signer"
)
const vectorsPath = "../../testdata/vectors/tce_vectors.json"
// vectorFile mirrors the frozen reference file. Only the fields the protocol
// tests need are declared.
type vectorFile struct {
Parties map[string]struct {
SeedHex string `json:"seed_hex"`
PubkeyHex string `json:"pubkey_hex"`
Address string `json:"address"`
} `json:"parties"`
Vectors []vectorEntry `json:"vectors"`
Rejects []rejectEntry `json:"rejects"`
}
type vectorEntry struct {
Name string `json:"name"`
Description string `json:"description"`
TCEHex string `json:"tce_hex"`
TCELen int `json:"tce_len"`
ObjectIDHex string `json:"object_id_hex"`
SignerPubkey string `json:"signer_pubkey_hex"`
SignerAddress string `json:"signer_address"`
SignatureHex string `json:"signature_hex"`
RequestIDHex string `json:"request_id_hex"`
JSON json.RawMessage `json:"json"`
}
type rejectEntry struct {
Name string `json:"name"`
TCEHex *string `json:"tce_hex"`
}
func loadVectors(t *testing.T) *vectorFile {
t.Helper()
b, err := os.ReadFile(vectorsPath)
if err != nil {
t.Fatalf("read vectors: %v", err)
}
var vf vectorFile
if err := json.Unmarshal(b, &vf); err != nil {
t.Fatalf("parse vectors: %v", err)
}
return &vf
}
func mustHex(t *testing.T, s string) []byte {
t.Helper()
b, err := hex.DecodeString(s)
if err != nil {
t.Fatalf("bad hex %q: %v", s, err)
}
return b
}
func mustSigner(t *testing.T) *signer.Signer {
t.Helper()
s, err := signer.Generate()
if err != nil {
t.Fatal(err)
}
return s
}
// seedSigner builds a signer from a 32-byte seed.
func seedSigner(t *testing.T, seed []byte) *signer.Signer {
t.Helper()
s, err := signer.FromSeed(seed)
if err != nil {
t.Fatalf("FromSeed: %v", err)
}
return s
}
// nonce returns a 16-byte nonce filled with a repeating byte.
func nonce(b byte) []byte {
out := make([]byte, 16)
for i := range out {
out[i] = b
}
return out
}
// signerFixtures holds two independent signers for building and signing test
// objects. Signing lives in signer, which the package under test never
// imports; tests may.
type signerFixtures struct {
alice *signer.Signer
bob *signer.Signer
}
func newSignerFixtures(t *testing.T) *signerFixtures {
t.Helper()
return &signerFixtures{alice: mustSigner(t), bob: mustSigner(t)}
}
// byName returns the vector entry with the given name, failing the test if it
// is absent.
func byName(t *testing.T, vf *vectorFile, name string) *vectorEntry {
t.Helper()
for i := range vf.Vectors {
if vf.Vectors[i].Name == name {
return &vf.Vectors[i]
}
}
t.Fatalf("vector %q not found", name)
return nil
}