Initial Go SDK for Keysat licensing service

Pure-Go, stdlib-only implementation of the LIC1 wire format:
- ParseKey + Verify + ParseAndVerify for offline verification
- HashFingerprint helper (SHA-256, matching the daemon's contract)
- LoadPublicKeyPEM for the standard PKIX-encoded Ed25519 public keys
  the daemon emits
- Client.Validate / Client.PublicKey for online checks against a
  running Keysat daemon
- LicensePayload struct with idiomatic Go getters (IsTrial,
  IsFingerprintBound, IsExpiredAt, HasEntitlement)

Wire-format crosscheck against the shared tests/crosscheck/vector.json
(the same file the Rust, TypeScript, Python SDKs and the daemon itself
test against). All four fixtures pass — v1 legacy fingerprint-bound,
v2 trial with entitlements, v2 perpetual unbound, plus end-to-end
PEM-load → ParseAndVerify signature roundtrip. Confirms byte-for-byte
agreement across five independent implementations.

No third-party dependencies. Module path:
github.com/keysat-xyz/keysat-client-go
go 1.21
This commit is contained in:
Grant
2026-05-08 11:17:46 -05:00
commit 81a621423a
8 changed files with 765 additions and 0 deletions
+180
View File
@@ -0,0 +1,180 @@
// 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)
}
}