sdk(P1.10): embedded parity self-test + attesto doctor
A trimmed (~1.7 KB) copy of the cross-language parity vectors now ships inside
each package (Python package-data JSON, Go go:embed, TS generated module). On
the first hashing operation per process each SDK recomputes the commitment
hash, the receipt domain-hash, and an inclusion fold against the vendored
vectors and fails closed (AttestoSelfTestError / ErrSelfTest) on any mismatch
— a corrupted install or diverging runtime can never silently produce wrong
evidence. Result is cached (including failure); cost <5 ms once. Corrupting a
vendored vector is test-asserted to fail closed in all three languages. The
frozen canonical primitives are untouched; the gate lives in the commitment/
verify entry points built on top of them.
attesto doctor: Go CLI subcommand and Python attesto.doctor(), producing a
deterministic {"ok", "checks"} report — vendored self-test, head-store
writability, number-policy dry-run on a sample payload, Ed25519 availability
(Python), and with credentials: reachability, protocol-header acceptance, and
clock skew vs the server Date header (warn >30 s; webhooks break at 300 s).
package_artifact_policy allows exactly attesto/_selftest_vectors.json in the
wheel (verified: built wheel contains it, policy green). READMEs updated.
This completes the last Phase-1 build item.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
72
selftest.go
Normal file
72
selftest.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package attesto
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// [P1.10] Trimmed parity vectors vendored into the package; regenerated from
|
||||
// golden-vectors/sdk-parity (do not hand-edit).
|
||||
//
|
||||
//go:embed selftest_vectors.json
|
||||
var selftestVectors []byte
|
||||
|
||||
// ErrSelfTest wraps a failed vendored parity self-test: this install's hashing
|
||||
// diverges from the pinned cross-language vectors (corrupted package or broken
|
||||
// runtime). The SDK fails closed rather than produce wrong evidence.
|
||||
var ErrSelfTest = errors.New("attesto self-test failed")
|
||||
|
||||
var (
|
||||
selftestOnce sync.Once
|
||||
selftestErr error
|
||||
)
|
||||
|
||||
func runSelfTest(raw []byte) error {
|
||||
var vectors struct {
|
||||
Commitment struct {
|
||||
Payload map[string]any `json:"payload"`
|
||||
CanonicalPayloadHash string `json:"canonical_payload_hash"`
|
||||
} `json:"commitment"`
|
||||
Receipt struct {
|
||||
Payload map[string]any `json:"payload"`
|
||||
ReceiptHash string `json:"receipt_hash"`
|
||||
} `json:"receipt"`
|
||||
Inclusion struct {
|
||||
LeafHash string `json:"leaf_hash"`
|
||||
Proof []InclusionStep `json:"proof"`
|
||||
RootHash string `json:"root_hash"`
|
||||
} `json:"inclusion"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &vectors); err != nil {
|
||||
return fmt.Errorf("%w: vendored vectors unreadable: %v", ErrSelfTest, err)
|
||||
}
|
||||
canonical, err := CanonicalJSON(vectors.Commitment.Payload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %v", ErrSelfTest, err)
|
||||
}
|
||||
if SHA256Hex(canonical) != vectors.Commitment.CanonicalPayloadHash {
|
||||
return fmt.Errorf("%w: commitment hash diverged from vendored vector", ErrSelfTest)
|
||||
}
|
||||
receiptHash, err := DomainHashHex(ProofstreamDomains["receipt"], vectors.Receipt.Payload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %v", ErrSelfTest, err)
|
||||
}
|
||||
if receiptHash != vectors.Receipt.ReceiptHash {
|
||||
return fmt.Errorf("%w: receipt domain-hash diverged from vendored vector", ErrSelfTest)
|
||||
}
|
||||
ok, err := VerifyInclusionProof(
|
||||
vectors.Inclusion.LeafHash, vectors.Inclusion.Proof, vectors.Inclusion.RootHash)
|
||||
if err != nil || !ok {
|
||||
return fmt.Errorf("%w: inclusion fold diverged from vendored vector", ErrSelfTest)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureSelfTest runs the vendored parity self-test once per process (cached).
|
||||
func EnsureSelfTest() error {
|
||||
selftestOnce.Do(func() { selftestErr = runSelfTest(selftestVectors) })
|
||||
return selftestErr
|
||||
}
|
||||
Reference in New Issue
Block a user