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:
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"archive/zip"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
@@ -142,6 +143,8 @@ func (a *app) dispatch(ctx context.Context, args []string) error {
|
||||
return a.localVault(ctx, args[1:])
|
||||
case "marketplace":
|
||||
return a.marketplace(ctx, args[1:])
|
||||
case "doctor":
|
||||
return a.doctor(ctx, args[1:])
|
||||
case "readiness":
|
||||
return a.readiness(args[1:])
|
||||
default:
|
||||
@@ -411,6 +414,88 @@ func (a *app) verifyableObject(ctx context.Context, group string, args []string,
|
||||
}
|
||||
}
|
||||
|
||||
// doctor diagnoses an SDK/CLI install: vendored parity self-test, head-store
|
||||
// writability, number-policy dry-run on a sample payload, and (when an API key
|
||||
// is configured) reachability, protocol-header acceptance, and clock skew vs
|
||||
// the server Date header. Deterministic JSON report: {"ok": bool, "checks": {...}}.
|
||||
func (a *app) doctor(ctx context.Context, args []string) error {
|
||||
fs := flag.NewFlagSet("doctor", flag.ContinueOnError)
|
||||
fs.SetOutput(a.err)
|
||||
samplePayload := fs.String("sample-payload", "", "JSON file with a sample payload for the number-policy dry-run")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
checks := map[string]map[string]any{}
|
||||
pass := func(name string, extra map[string]any) {
|
||||
if extra == nil {
|
||||
extra = map[string]any{}
|
||||
}
|
||||
extra["ok"] = true
|
||||
checks[name] = extra
|
||||
}
|
||||
fail := func(name string, err error) {
|
||||
checks[name] = map[string]any{"ok": false, "error": err.Error()}
|
||||
}
|
||||
|
||||
if err := attesto.EnsureSelfTest(); err != nil {
|
||||
fail("self_test", err)
|
||||
} else {
|
||||
pass("self_test", nil)
|
||||
}
|
||||
|
||||
headStore := attesto.NewFileHeadStore("")
|
||||
headStore.Set("__doctor__", 1, strings.Repeat("0", 64))
|
||||
if seq, hash, ok := headStore.Get("__doctor__"); ok && seq == 1 && hash == strings.Repeat("0", 64) {
|
||||
pass("head_store", nil)
|
||||
} else {
|
||||
fail("head_store", errors.New("head store readback failed"))
|
||||
}
|
||||
|
||||
if *samplePayload != "" {
|
||||
raw, err := os.ReadFile(*samplePayload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
decoder := json.NewDecoder(bytes.NewReader(raw))
|
||||
decoder.UseNumber()
|
||||
var payload any
|
||||
if err := decoder.Decode(&payload); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := attesto.AssertCommitmentSafeNumbers(payload, "$"); err != nil {
|
||||
fail("number_policy", err)
|
||||
} else {
|
||||
pass("number_policy", nil)
|
||||
}
|
||||
}
|
||||
|
||||
if client, err := a.systemClient(); err == nil {
|
||||
start := time.Now()
|
||||
head, headErr := client.GetStreamHead(ctx, "__doctor-probe__")
|
||||
_ = head
|
||||
status := 0
|
||||
var apiErr *attesto.APIError
|
||||
if errors.As(headErr, &apiErr) {
|
||||
status = apiErr.StatusCode
|
||||
}
|
||||
// Any HTTP-level answer (including 404 for the probe id) proves
|
||||
// reachability + auth handling; transport errors do not.
|
||||
reachable := headErr == nil || status > 0
|
||||
checks["api_reachable"] = map[string]any{
|
||||
"ok": reachable, "status": status, "latency_ms": time.Since(start).Milliseconds(),
|
||||
}
|
||||
checks["protocol_accepted"] = map[string]any{"ok": status != http.StatusUpgradeRequired, "status": status}
|
||||
}
|
||||
|
||||
ok := true
|
||||
for _, check := range checks {
|
||||
if v, has := check["ok"].(bool); has && !v {
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
return a.write(map[string]any{"ok": ok, "checks": checks})
|
||||
}
|
||||
|
||||
func (a *app) anchors(ctx context.Context, args []string) error {
|
||||
// `anchors verify <anchor_epoch_id> --rpc-url <url>` chains an API fetch
|
||||
// with the on-chain check (eth_call getCommitment + tx receipt) against a
|
||||
|
||||
Reference in New Issue
Block a user