Files
attesto-go/export_parity_test.go
Codex 6858bbcdd8 feat(P3.4): portable receipts, attestedFetch, edge-runtime lane, receipt PDF
Portable receipt export (*.attesto.json): export_receipt_file /
verify_receipt_file in Python, exportReceiptFile / verifyReceiptFile in
TypeScript, ExportReceiptFile / VerifyReceiptExport in Go, plus
`attesto verify file` in the CLI. New normative corpus
golden-vectors/sdk-parity/receipt-export.json (valid, tampered-inner,
linkage-mismatch, wrong-format, embedded-hint-only) passes identically in
all three SDKs; a Python-made export verifies through the Go CLI
end-to-end. Embedded witness keys are explicit second-class hints
(kind=receipt-export-selfcontained).

attestedFetch (TS) attests AI calls at the transport exactly like the
gateway: OpenAI-compatible paths -> attesto.model_decision with
commitments only (SSE reassembled after byte-for-byte pass-through),
anything else -> http_call; fail-open by default with onError, strict
rejects; attest() wraps any function with a commitment event +
lastReceipt. 5 emulator tests prove raw prompt/completion text never
appears in any stored object.

Edge runtimes: new guard test fails the build if any node: builtin enters
the dist/index.js module graph (FileHeadStore stays out by design), and
the receipt+export corpora now run on Bun in CI (10 cases green locally).

render_receipt_pdf ships behind the attesto[receipt-pdf] extra (fpdf2 +
qrcode, pure Python; core stays light) — one-page rendering with a QR of
{receipt_hash, event_hash} and a disclaimer that the JSON, not the PDF,
is the evidence; clean ImportError naming the extra when absent.

Also fixed a stale CI assertion: the npm package-install smoke pinned
SDK_VERSION 0.1.1; it now reads the version from package.json.

Suites: Python 106 passed, TypeScript 67+5 passed, Go green, package
policy contract green. Connectorkit already exists in all three languages
(no port needed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 09:57:34 +02:00

78 lines
2.2 KiB
Go

package attesto
// [P3.4] Receipt-export parity corpus — Go verifier.
import (
"encoding/json"
"os"
"path/filepath"
"testing"
)
func TestReceiptExportParity(t *testing.T) {
raw, err := os.ReadFile(filepath.Join("..", "..", "golden-vectors", "sdk-parity", "receipt-export.json"))
if err != nil {
t.Fatalf("read corpus: %v", err)
}
var corpus struct {
Cases []struct {
ID string `json:"id"`
ExpectOK bool `json:"expect_ok"`
PublicKeyHex *string `json:"public_key_hex"`
Export json.RawMessage `json:"export"`
} `json:"cases"`
}
if err := json.Unmarshal(raw, &corpus); err != nil {
t.Fatalf("parse corpus: %v", err)
}
if len(corpus.Cases) < 5 {
t.Fatalf("expected >=5 cases, got %d", len(corpus.Cases))
}
for _, testCase := range corpus.Cases {
t.Run(testCase.ID, func(t *testing.T) {
key := ""
if testCase.PublicKeyHex != nil {
key = *testCase.PublicKeyHex
}
report := VerifyReceiptExport(testCase.Export, key)
if report.OK != testCase.ExpectOK {
t.Fatalf("ok=%v want %v (problems: %v)", report.OK, testCase.ExpectOK, report.Problems)
}
if testCase.PublicKeyHex == nil && testCase.ExpectOK && report.Kind != "receipt-export-selfcontained" {
t.Fatalf("kind=%q, want receipt-export-selfcontained", report.Kind)
}
})
}
}
func TestExportReceiptFileRoundTrip(t *testing.T) {
raw, err := os.ReadFile(filepath.Join("..", "..", "golden-vectors", "sdk-parity", "receipt-export.json"))
if err != nil {
t.Fatalf("read corpus: %v", err)
}
var corpus struct {
Cases []struct {
PublicKeyHex *string `json:"public_key_hex"`
Export struct {
Receipt json.RawMessage `json:"receipt"`
} `json:"export"`
} `json:"cases"`
}
if err := json.Unmarshal(raw, &corpus); err != nil {
t.Fatalf("parse corpus: %v", err)
}
valid := corpus.Cases[0]
path := filepath.Join(t.TempDir(), "receipt.attesto.json")
if _, err := ExportReceiptFile(valid.Export.Receipt, path, *valid.PublicKeyHex); err != nil {
t.Fatalf("export: %v", err)
}
exported, err := os.ReadFile(path)
if err != nil {
t.Fatalf("read export: %v", err)
}
report := VerifyReceiptExport(exported, *valid.PublicKeyHex)
if !report.OK {
t.Fatalf("round-trip verify failed: %v", report.Problems)
}
}