FIX 11 — reject cross-language-divergent numbers in committed payloads. append_stream_event now rejects non-integer numbers and integers beyond ±(2^53−1) in payload/metadata at ingestion (HTTP 422), so a customer recomputing a commitment in a Go/TS verifier can never read it as tampering. Documented in the protocol spec + all three SDK READMEs; 9 tests. FIX 12 — Nova IVC chain-continuity invariant. record_ivc_epoch now takes a per-stream transaction-scoped advisory lock and fails closed (409) if an epoch does not extend the latest verified epoch's next_state_root or would skip an unproven checkpoint — so two concurrent provers cannot fork Attesto's own lane and a failed proof cannot be chained over. The worker stops the pass on a failed proof (break, not continue) and always backfills the oldest unproven checkpoint first so holes heal. Tests cover both 409 paths plus in-order record + replay. FIX 13 — pin the e2e v1 checkpoint shape. Config now requires PROOFSTREAM_WINDOW_MAX_EVENTS=1 (alongside CHECKPOINT_MAX_WINDOWS=4) when Nova is enabled, and the worker refuses to close an aged checkpoint below the 4-window shape (which would be unprovable). Documented as the deliberate fail-closed v1 behavior; config + worker tests. VERIFY-1 — investigation: the standard production ingestion path (SDK → append_stream_event → persist_stream_event_receipt) does NOT write the nova_e2e boundary metadata the prover requires; no writer exists in backend/app, and _e2e_vector_for_checkpoint requires (not derives) it. So Nova proofs currently cover golden-vector/harness inputs, not live customer receipts — the open Route A/B item. Recorded in CRYPTO_REVIEW_CHECKLIST as a coverage-scope note; no Route A/B implementation in this release. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Attesto Go SDK
Official Go SDK for Attesto 2.0 Proofstream. The default API base URL is
https://verify.attesto.eu. Use it from server-side, infrastructure, security
tooling, CI, evidence exporters, and operator automation. Do not embed Attesto API keys in browser bundles, mobile apps, or public artifacts.
Install
go get git.rotz.ai/rotzmediagroup/attesto-v1/sdk/go
The first release is VCS-resolved from the Attesto repository. It intentionally uses only the Go standard library.
Quickstart
package main
import (
"context"
"fmt"
"log"
"os"
"time"
attesto "git.rotz.ai/rotzmediagroup/attesto-v1/sdk/go"
)
func main() {
ctx := context.Background()
client, err := attesto.NewClient(os.Getenv("ATTESTO_API_KEY"))
if err != nil {
log.Fatal(err)
}
stream, err := client.CreateStream(ctx, attesto.StreamCreateInput{
UseCase: "ai-governance",
PolicyID: "policy-main",
})
if err != nil {
log.Fatal(err)
}
receipt, err := client.LogEvent(ctx, stream.StreamID, attesto.EventInput{
SourceRef: "decision-42",
OccurredAt: time.Now().UTC().Format(time.RFC3339Nano),
Payload: attesto.M{
"model": "risk-classifier",
"score": 0.92,
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(receipt.StreamEventID, receipt.EventHash)
}
Attesto stores source-system time separately from backend ingest time.
OccurredAt must be RFC3339 with a timezone offset. The Go SDK fills it with
time.Now().UTC() when omitted, but production integrations should pass the
real upstream event timestamp whenever the source system provides one.
Committed payload number rule
When events are committed to a Proofstream, payload and metadata numbers must
serialize identically across Python, Go, and JavaScript. Non-integer numbers
and integers beyond ±(2^53−1) are rejected at ingestion (HTTP 422); encode
decimals and large integers as strings (e.g. {"score": "0.87"}). This keeps
cross-language commitment recomputation byte-exact (CanonicalJSON).
Verification
Remote verification uses Attesto's public /v2/verify API. Offline receipt
verification uses ATTESTO-PROOFSTREAM-001 canonical JSON, domain-separated
hashes, and Ed25519 signature verification locally.
report := attesto.VerifyReceiptOffline(receipt.Receipt, publicKeyHex)
if !report.OK {
log.Fatalf("receipt failed verification: %v", report.Problems)
}
Operator and Admin Endpoints
System-key clients are created with attesto.NewClient. Tenant/operator
endpoints, including connector installation and Local Vault installation
management, use attesto.NewBearerClient with a tenant bearer token obtained
from the dashboard session flow.
Secrets returned once by connector creation are present only in the returned struct and are never logged by the SDK.