Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions examples/okf-bundle/add-to-cart-event.md
Original file line number Diff line number Diff line change
@@ -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] |
14 changes: 14 additions & 0 deletions examples/okf-bundle/consent-mode.md
Original file line number Diff line number Diff line change
@@ -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
16 changes: 16 additions & 0 deletions examples/okf-bundle/purchase-event.md
Original file line number Diff line number Diff line change
@@ -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[] |
24 changes: 24 additions & 0 deletions examples/sign-and-verify.sh
Original file line number Diff line number Diff line change
@@ -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"
34 changes: 34 additions & 0 deletions packages/visualizer/test/example.test.ts
Original file line number Diff line number Diff line change
@@ -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</g) ?? []).length).toBe(files.length);
expect(html).not.toMatch(/(?:src|href)\s*=\s*["']https?:\/\//i);
});
});
Loading