From 1713eafa6689bdb668d2c3b1c60b826c77bd6865 Mon Sep 17 00:00:00 2001 From: Mayumi Hara Date: Tue, 16 Jun 2026 08:26:30 +0900 Subject: [PATCH] =?UTF-8?q?docs(examples):=20worked=20example=20=E2=80=94?= =?UTF-8?q?=20sign=20&=20verify=20an=20OKF=20bundle=20(VOKF-9=20/=20M1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completes M1. examples/okf-bundle/ is a small multi-concept OKF bundle (a GA4 analytics mapping: purchase / add_to_cart / consent-mode). - examples/sign-and-verify.sh: signs every concept, verifies each, and renders an offline HTML report via the built CLIs (< 5 min, copy-paste). - README: a "Worked example" section. - A visualizer test guards it in CI: every concept signs → verifies as `verified`, and the rendered report is offline (no external refs). Full suite green (canon 28 + signer 7 + verifier 22 + visualizer 7 + attest 5 = 69). Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 14 ++++++++++ examples/okf-bundle/add-to-cart-event.md | 15 +++++++++++ examples/okf-bundle/consent-mode.md | 14 ++++++++++ examples/okf-bundle/purchase-event.md | 16 +++++++++++ examples/sign-and-verify.sh | 24 +++++++++++++++++ packages/visualizer/test/example.test.ts | 34 ++++++++++++++++++++++++ 6 files changed, 117 insertions(+) create mode 100644 examples/okf-bundle/add-to-cart-event.md create mode 100644 examples/okf-bundle/consent-mode.md create mode 100644 examples/okf-bundle/purchase-event.md create mode 100755 examples/sign-and-verify.sh create mode 100644 packages/visualizer/test/example.test.ts diff --git a/README.md b/README.md index 08a7c42..317efe4 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,20 @@ The signed output is byte-identical to `fixtures/signed/ga4-event.md`, and tampe signature, schema, or issuer yields the corresponding `failed` reason code (see `fixtures/tampered/`). Verification is fully offline for `did:key`; `did:web` resolves the issuer over HTTPS. +## Worked example (a real OKF bundle) + +`examples/okf-bundle/` is a small multi-concept OKF bundle (a GA4 analytics mapping). Sign every +concept, verify each, and render an offline report: + +```bash +pnpm install && pnpm build +examples/sign-and-verify.sh +# add-to-cart-event.md {"status":"verified", ...} +# consent-mode.md {"status":"verified", ...} +# purchase-event.md {"status":"verified", ...} +# report → /tmp/.../report.html (3 concepts, 0 failed) +``` + ## Development ```bash pnpm install diff --git a/examples/okf-bundle/add-to-cart-event.md b/examples/okf-bundle/add-to-cart-event.md new file mode 100644 index 0000000..78f249f --- /dev/null +++ b/examples/okf-bundle/add-to-cart-event.md @@ -0,0 +1,15 @@ +--- +title: GA4 — add_to_cart event +resource: https://example.com/okf/ga4/add-to-cart +type: event +tags: [analytics, ga4, ecommerce] +--- +# add_to_cart + +Emit `add_to_cart` when an item is added to the cart. + +| parameter | source | +|---|---| +| value | item.price * item.qty | +| currency | catalog.currency | +| items | [item] | diff --git a/examples/okf-bundle/consent-mode.md b/examples/okf-bundle/consent-mode.md new file mode 100644 index 0000000..33de6b3 --- /dev/null +++ b/examples/okf-bundle/consent-mode.md @@ -0,0 +1,14 @@ +--- +title: GA4 — consent mode defaults +resource: https://example.com/okf/ga4/consent +type: config +tags: [analytics, ga4, consent] +--- +# consent mode + +Default consent state before the user interacts with the banner. + +- `ad_storage`: denied +- `analytics_storage`: denied +- `ad_user_data`: denied +- `ad_personalization`: denied diff --git a/examples/okf-bundle/purchase-event.md b/examples/okf-bundle/purchase-event.md new file mode 100644 index 0000000..0b76b4d --- /dev/null +++ b/examples/okf-bundle/purchase-event.md @@ -0,0 +1,16 @@ +--- +title: GA4 — purchase event +resource: https://example.com/okf/ga4/purchase +type: event +tags: [analytics, ga4, ecommerce] +--- +# purchase + +Emit a GA4 `purchase` event when an order is confirmed server-side. + +| parameter | source | +|---|---| +| transaction_id | order.id | +| value | order.total | +| currency | order.currency | +| items | order.line_items[] | diff --git a/examples/sign-and-verify.sh b/examples/sign-and-verify.sh new file mode 100755 index 0000000..c80fdd1 --- /dev/null +++ b/examples/sign-and-verify.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# Worked example: sign every concept in examples/okf-bundle/, verify each, and +# render an offline HTML report. Run `pnpm install && pnpm build` first. +set -e +cd "$(dirname "$0")/.." # repo root + +# Test-only Ed25519 seed (32 bytes hex). NEVER use a real key on the CLI. +SEED=0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20 +OUT="$(mktemp -d)" + +echo "→ signing examples/okf-bundle/ → $OUT" +for f in examples/okf-bundle/*.md; do + node packages/signer/dist/cli.js "$f" --key "$SEED" \ + --valid-from 2026-01-01T00:00:00Z --valid-until 2027-01-01T00:00:00Z \ + -o "$OUT/$(basename "$f")" +done + +echo "→ verifying" +for f in "$OUT"/*.md; do + printf ' %-22s %s\n' "$(basename "$f")" "$(node packages/verifier/dist/cli.js "$f")" +done + +node packages/visualizer/dist/cli.js "$OUT" -o "$OUT/report.html" +echo "→ report: $OUT/report.html" diff --git a/packages/visualizer/test/example.test.ts b/packages/visualizer/test/example.test.ts new file mode 100644 index 0000000..9fdf2ca --- /dev/null +++ b/packages/visualizer/test/example.test.ts @@ -0,0 +1,34 @@ +import { describe, it, expect } from "vitest"; +import { readFileSync, readdirSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import { signConcept } from "@verifiable-okf/signer"; +import { verifyConcept } from "@verifiable-okf/verifier"; +import { renderReport, type ReportItem } from "../src/index.js"; + +// VOKF-9 worked example: the OKF bundle under examples/ must sign → verify cleanly. +const bundleDir = fileURLToPath(new URL("../../../examples/okf-bundle", import.meta.url)); +const SEED = Uint8Array.from(Array.from({ length: 32 }, (_, i) => i + 1)); +const SIGN = { privateKey: SEED, validFrom: "2026-01-01T00:00:00Z", validUntil: "2027-01-01T00:00:00Z" }; +const NOW = new Date("2026-06-15T00:00:00Z"); + +describe("worked example (examples/okf-bundle)", () => { + const files = readdirSync(bundleDir).filter((f) => f.endsWith(".md")).sort(); + + it("contains a multi-concept bundle", () => { + expect(files.length).toBeGreaterThanOrEqual(3); + }); + + it("every concept signs then verifies as `verified`", async () => { + const items: ReportItem[] = []; + for (const f of files) { + const signed = signConcept(readFileSync(`${bundleDir}/${f}`), SIGN); + const result = await verifyConcept(signed, { now: NOW }); + expect(result.status, f).toBe("verified"); + items.push({ id: f, result }); + } + // and the report renders all of them as verified, offline + const html = renderReport(items); + expect((html.match(/>verified