// Wire-format crosscheck. Each fixture in the shared // tests/crosscheck/vector.json was generated by Python's // reference_signer.py (independent crypto), then is consumed by // every Keysat SDK + the daemon. If this test fails, this Go SDK // has drifted from the wire format the rest of the ecosystem // agrees on. // // The path to vector.json assumes this package is checked out // under the parent licensing/ workspace (next to // licensing-client-rust, etc.). Skip the test gracefully if the // vector isn't reachable — when this SDK is fetched standalone // via `go get`, there's nothing to cross-check against. package keysat_test import ( "encoding/hex" "encoding/json" "errors" "os" "path/filepath" "testing" "github.com/keysat-xyz/keysat-client-go" ) type fixture struct { LicenseKey string `json:"licenseKey"` Expected struct { Version int `json:"version"` ProductUUID string `json:"productUuid"` LicenseUUID string `json:"licenseUuid"` IssuedAt int64 `json:"issuedAt"` ExpiresAt int64 `json:"expiresAt"` Flags int `json:"flags"` IsFingerprintBound bool `json:"isFingerprintBound"` IsTrial bool `json:"isTrial"` Entitlements []string `json:"entitlements"` FingerprintRaw *string `json:"fingerprintRaw"` FingerprintHashHex string `json:"fingerprintHashHex"` } `json:"expected"` } type vectorFile struct { PublicKeyPEM string `json:"publicKeyPem"` V1 fixture `json:"v1"` V2 fixture `json:"v2"` V2PerpetualUnbound fixture `json:"v2_perpetual_unbound"` } func loadVector(t *testing.T) vectorFile { t.Helper() candidates := []string{ "../tests/crosscheck/vector.json", // when this is a sibling of /tests "../../tests/crosscheck/vector.json", // when nested one deeper } for _, c := range candidates { abs, err := filepath.Abs(c) if err != nil { continue } raw, err := os.ReadFile(abs) if errors.Is(err, os.ErrNotExist) { continue } if err != nil { t.Fatalf("reading %s: %v", abs, err) } var v vectorFile if err := json.Unmarshal(raw, &v); err != nil { t.Fatalf("parsing %s: %v", abs, err) } return v } t.Skipf("crosscheck vector.json not found alongside this package " + "(expected at ../tests/crosscheck/vector.json); skipping. " + "This is normal when fetched standalone via `go get` — the " + "crosscheck only runs from the parent licensing/ workspace.") return vectorFile{} } func uuidString(b [16]byte) string { // Render as canonical 8-4-4-4-12 lowercase hex. hexStr := hex.EncodeToString(b[:]) return hexStr[0:8] + "-" + hexStr[8:12] + "-" + hexStr[12:16] + "-" + hexStr[16:20] + "-" + hexStr[20:32] } func checkFixture(t *testing.T, name string, fx fixture) { t.Helper() payload, _, _, err := keysat.ParseKey(fx.LicenseKey) if err != nil { t.Fatalf("%s: ParseKey failed: %v", name, err) } if int(payload.Version) != fx.Expected.Version { t.Errorf("%s: version = %d, want %d", name, payload.Version, fx.Expected.Version) } if uuidString(payload.ProductID) != fx.Expected.ProductUUID { t.Errorf("%s: productID = %s, want %s", name, uuidString(payload.ProductID), fx.Expected.ProductUUID) } if uuidString(payload.LicenseID) != fx.Expected.LicenseUUID { t.Errorf("%s: licenseID = %s, want %s", name, uuidString(payload.LicenseID), fx.Expected.LicenseUUID) } if payload.IssuedAt != fx.Expected.IssuedAt { t.Errorf("%s: issuedAt = %d, want %d", name, payload.IssuedAt, fx.Expected.IssuedAt) } if payload.ExpiresAt != fx.Expected.ExpiresAt { t.Errorf("%s: expiresAt = %d, want %d", name, payload.ExpiresAt, fx.Expected.ExpiresAt) } if int(payload.Flags) != fx.Expected.Flags { t.Errorf("%s: flags = %d, want %d", name, payload.Flags, fx.Expected.Flags) } if payload.IsFingerprintBound() != fx.Expected.IsFingerprintBound { t.Errorf("%s: IsFingerprintBound = %v, want %v", name, payload.IsFingerprintBound(), fx.Expected.IsFingerprintBound) } if payload.IsTrial() != fx.Expected.IsTrial { t.Errorf("%s: IsTrial = %v, want %v", name, payload.IsTrial(), fx.Expected.IsTrial) } got := payload.Entitlements if got == nil { got = []string{} } want := fx.Expected.Entitlements if want == nil { want = []string{} } if len(got) != len(want) { t.Errorf("%s: entitlements len = %d, want %d", name, len(got), len(want)) } else { for i := range got { if got[i] != want[i] { t.Errorf("%s: entitlements[%d] = %q, want %q", name, i, got[i], want[i]) } } } gotFP := hex.EncodeToString(payload.FingerprintHash[:]) if gotFP != fx.Expected.FingerprintHashHex { t.Errorf("%s: fingerprintHash = %s, want %s", name, gotFP, fx.Expected.FingerprintHashHex) } // If a raw fingerprint is supplied, verify HashFingerprint reproduces the wire bytes. if fx.Expected.FingerprintRaw != nil && fx.Expected.IsFingerprintBound { h := keysat.HashFingerprint(*fx.Expected.FingerprintRaw) if hex.EncodeToString(h[:]) != fx.Expected.FingerprintHashHex { t.Errorf("%s: HashFingerprint(raw) does not match wire hash", name) } } } func TestCrosscheck_V1(t *testing.T) { v := loadVector(t) checkFixture(t, "v1", v.V1) } func TestCrosscheck_V2_TrialWithEntitlements(t *testing.T) { v := loadVector(t) checkFixture(t, "v2", v.V2) } func TestCrosscheck_V2_PerpetualUnbound(t *testing.T) { v := loadVector(t) checkFixture(t, "v2_perpetual_unbound", v.V2PerpetualUnbound) } // Exercise signature verification end-to-end: load the vector's // public key, parse the v2 fixture, verify. Locks in the // PEM → ed25519.PublicKey path on top of the parser. func TestCrosscheck_V2_SignatureVerifies(t *testing.T) { v := loadVector(t) pub, err := keysat.LoadPublicKeyPEM(v.PublicKeyPEM) if err != nil { t.Fatalf("LoadPublicKeyPEM: %v", err) } payload, err := keysat.ParseAndVerify(v.V2.LicenseKey, pub) if err != nil { t.Fatalf("ParseAndVerify: %v", err) } if payload.Version != keysat.KeyVersionV2 { t.Errorf("unexpected version: %d", payload.Version) } }