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
5 changes: 5 additions & 0 deletions .flow/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"memory": {
"enabled": false
}
}
13 changes: 13 additions & 0 deletions .flow/epics/fn-1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"branch_name": "fn-152-c1",
"created_at": "2026-06-08T22:04:26.033805Z",
"depends_on_epics": [],
"id": "fn-1",
"next_task": 1,
"plan_review_status": "unknown",
"plan_reviewed_at": null,
"spec_path": ".flow/specs/fn-1.md",
"status": "open",
"title": "Stream C \u2014 auths-verify-widget GTM: resolver-doc truth + embed/SRI/playground",
"updated_at": "2026-06-08T22:36:13.268099Z"
}
4 changes: 4 additions & 0 deletions .flow/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"next_epic": 1,
"schema_version": 2
}
95 changes: 95 additions & 0 deletions .flow/specs/fn-1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Stream C — `auths-verify-widget` GTM

> Source: `roadmap/go_to_market/go_to_market.md` → "Stream C — `auths-verify-widget` (the most launch-ready artifact)".
> Roadmap task IDs preserved for traceability: **G0.5 / G4.1 (D-5)**, **G4.4**, **G4.5**.

## Overview

`@auths-dev/verify@0.3.0` is the most launch-ready artifact in the GTM plan: live on unpkg *and* jsDelivr, WASM base64-inlined into a single file so the one-line `<script>` embed works today, 7 a11y states (`src/styles.ts`). It is held back by **one credibility blocker**: the docs describe a resolver the code stopped using two migrations ago. This epic makes the surface tell the truth about the substance, standardizes the embed form, and adds the SRI/version-pinning + interactive-playground polish that turns a curious visitor into a copy-paste.

**Scope discipline (from the roadmap):** zero new product features. Everything here is drift-elimination, packaging, and UX polish on primitives that already pass tests. **One repo per session** — this epic touches ONLY `auths-verify-widget`. The roadmap text mentions `example-verify-badge/README.md:21`; that is **Stream D, out of scope here**.

## The core drift (D-5)

The GitHub resolver **actually** fetches `*.auths.json` from GitHub **Releases** (`src/resolvers/github.ts`: `GET /repos/{owner}/{repo}/releases/latest` → find asset ending `.auths.json` → download via Contents API with a Releases-asset-API fallback → use `attestation.device_public_key` as the verification key). `listAuthsRefs` is a `return []` stub for the GitHub adapter (kept only for `ForgeAdapter` interface compat).

But the docs **claim** it reads git refs:
- `README.md:34-40` ("Quick Start" step 1) and `README.md:159-169` ("How It Works") describe `refs/auths/identity` + `refs/auths/devices/nodes/` — false for GitHub.
- `README.md:166` says "Ed25519 public key"; `did-utils.ts` now also extracts **P-256**.
- `CHANGELOG.md:17` documents the obsolete refs-based GitHub adapter; `[Unreleased]` is empty; the CHANGELOG's latest entry is `[0.1.1]` while `package.json` is `0.3.0`.
- `examples/auto-resolve.html:23` repeats "from the forge's Git refs."
- `src/resolvers/adapter.ts:3` interface comment still says "via Git refs."
- `tests/e2e/live-resolve.test.ts:50-58,74` is **executable** drift — it calls `githubAdapter.listAuthsRefs()` and asserts `refs/auths/registry` exists and a `did:keri:` issuer. It cannot pass and is silently CI-excluded (`vitest.config.ts:8`).

**Critical nuance — do NOT over-correct:** Gitea (`src/resolvers/gitea.ts`) *legitimately* uses git refs (`refs/auths/registry`) and implements `listAuthsRefs` for real. GitLab is intentionally unsupported (returns a descriptive error). So the fix is **GitHub-specific**, not a blanket removal of all "refs" language. Leave Gitea/GitLab refs wording (`README.md:44`, `CHANGELOG.md:18-19`, `gitea.ts`, `gitlab.ts`) intact.

## Decisions (locked at planning)

1. **Task 1 reach:** reconcile **docs + the e2e test + the `adapter.ts` comment** (the drift lives in code/tests too, not just prose).
2. **Canonical `repo=` form:** standardize every documented/generated snippet on the **full URL** form (`https://github.com/org/repo`). Works for all forges, unambiguous, matches the existing README. Short-form `org/repo` stays *supported* in `detect.ts` but is no longer the documented/emitted form.
3. **Interactive artifacts home:** one **combined embed-builder + live-playground page deployed to GitHub Pages** — public, linkable from the README, a real GTM asset. Generator and playground share one accessible copy-button component.
4. **Granularity:** fine-grained — five tasks, each sized for one `/flow-next:work` iteration.

## Scope / tasks

| Task | Pri | Roadmap | Summary |
|------|-----|---------|---------|
| fn-1.1 | P0 | G0.5 / G4.1 (D-5) | Reconcile GitHub resolver **docs + e2e test + adapter comment** to the Releases-asset reality |
| fn-1.2 | P1 | G4.4 (code) | Harden `detect.ts` URL normalization, standardize on full-URL form, add tests, align all snippets |
| fn-1.3 | P2 | G4.5 (SRI) | SRI + pinned-version + `crossorigin` CDN guidance; build-time sha384 tooling; resolve slim-build WASM truth |
| fn-1.4 | P1 | G4.4 (UI) | Embed-snippet generator page: paste repo URL → canonical pinned+SRI snippet with accessible copy button |
| fn-1.5 | P2 | G4.5 (playground) | Live badge preview (sandboxed iframe) + GitHub Pages deploy for the builder/playground |

**Dependency DAG:** `1.2 → 1.1`; `1.3 → 1.1`; `1.4 → {1.2, 1.3}`; `1.5 → 1.4`.

## Approach

- **fn-1.1 first** — until the docs/test tell the truth, the generator (1.4) and playground (1.5) would re-encode the wrong mental model. 1.2 and 1.3 also touch the README, so they depend on 1.1 to avoid re-introducing drift and to minimize merge churn.
- Reuse the correct **JSDoc in `src/resolvers/github.ts:1-12,28-32`** as the source of truth when rewriting "How It Works."
- The full build base64-inlines WASM into the single `dist/auths-verify.mjs` (671 KB) — **one sha384 covers everything**, the SRI-friendly path. The **slim** build (`dist/slim/`) is ambiguous (no separate `.wasm` emitted, same size as full); fn-1.3 must establish ground truth before writing any slim SRI guidance and should steer SRI users to the full bundle.
- SRI is incompatible with a moving `@latest` CDN URL (hash changes every release) → pinning an exact version (`@0.3.0`) is **mandatory** with SRI, and the snippet needs `crossorigin="anonymous"`.
- Playground respects GitHub's **60 req/hr/IP** unauthenticated limit: debounce, lean on the existing 5-min resolver cache (`resolver.ts:44-45`), and render the live preview in a sandboxed `iframe srcdoc`.

## Risks / dependencies

- **Precondition — clean tree.** This branch (`fn-152-c1`) carries in-flight uncommitted P-256 work in `src/resolvers/did-utils.ts` + its test. Commit/stash it and branch fresh from `main` before starting, or the GTM diff entangles with the P-256 change. (The README P-256 wording fix in fn-1.1 assumes that P-256 work lands.)
- **GitHub Pages enablement is a one-time repo setting** (OPS-ish). fn-1.5 commits the deploy workflow + page; turning Pages on in repo settings is a manual step flagged in that task.
- **Examples are not published** (`package.json:18-20` `files: ["dist"]`) — the builder/playground reaches users via GitHub Pages, not npm/CDN. Don't assume `unpkg` serves it.
- **Published-bytes hash drift:** the sha384 in docs must be computed from the *published* `0.3.0` bytes, not a stale local `dist/`. fn-1.3 wires hash generation into the release flow to prevent drift.

## Quick commands (smoke tests)

```bash
# from the repo root: /Users/bordumb/workspace/repositories/auths-base/auths-verify-widget
npm run typecheck # tsc --noEmit
npm test # vitest run (unit; e2e is excluded by config)
npm run build # build:full (inline WASM) + build:slim; CI verifies dist/auths-verify.mjs exists

# Drift guard (fn-1.1): these GitHub-specific refs strings must be GONE from user-facing docs
! grep -RInE 'refs/auths/identity|refs/auths/devices/nodes' README.md CHANGELOG.md examples/ \
|| echo "FAIL: stale GitHub git-refs language still present"

# Canonical form guard (fn-1.2): documented snippets use full URLs
grep -RIn 'auths-verify repo=' README.md examples/
```

## Acceptance (epic-level)

- [ ] No user-facing doc/test/comment describes the **GitHub** resolver as reading git refs; the Releases-asset flow is described accurately (incl. Ed25519 **and** P-256). Gitea/GitLab refs language is preserved.
- [ ] `tests/e2e/live-resolve.test.ts` asserts the real Releases-asset behavior for GitHub (or is restructured) — no assertion that can never pass.
- [ ] All documented and generated embed snippets use the canonical **full-URL** `repo=` form; `detect.ts` normalizes pasted URLs (`/tree/*`, `.git`, query/hash) with tests.
- [ ] README CDN snippet is **pinned** (`@0.3.0`) with a correct `integrity="sha384-…"` + `crossorigin="anonymous"`; hash generation is wired to the release flow; slim-vs-full SRI behavior is documented truthfully.
- [ ] A combined embed-builder + live-playground page is deployed to GitHub Pages, linked from the README, with an accessible (aria-live, keyboard, secure-context fallback) copy button.
- [ ] `npm run typecheck && npm test && npm run build` all pass.

## References

- `src/resolvers/github.ts:1-12,28-35,42-108` — Releases-asset resolver + stubs (source of truth)
- `src/resolvers/gitea.ts`, `src/resolvers/gitlab.ts` — legitimately refs-based / unsupported (do not touch wording)
- `src/resolvers/detect.ts:11-76` — `detectForge`, short-form vs full-URL handling
- `src/resolvers/did-utils.ts` — Ed25519 + P-256 key extraction (in-flight on this branch)
- `src/verifier-bridge.ts:11,22-44`, `vite.config.ts:7-32,44-51` — inline-vs-slim WASM build
- `package.json:3,18-20,23-31,45` — version, `files`, build scripts, keywords
- `README.md:12-14,34-44,75-77,143-169,226`, `CHANGELOG.md:8,10,17`, `examples/auto-resolve.html:21-24,67`
- `tests/e2e/live-resolve.test.ts:50-58,74`, `vitest.config.ts:8`, `tests/resolvers/detect.test.ts`
- External: [MDN SRI](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity), [jsDelivr SRI](https://www.jsdelivr.com/using-sri-with-dynamic-files), [GitHub REST — Releases](https://docs.github.com/en/rest/releases/releases), [GitHub rate limits](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api), [MDN Clipboard.writeText](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText)
26 changes: 26 additions & 0 deletions .flow/tasks/fn-1.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"assignee": "bordumbb@gmail.com",
"claim_note": "",
"claimed_at": "2026-06-08T22:38:46.846335Z",
"created_at": "2026-06-08T22:06:20.287294Z",
"depends_on": [
"fn-1.6"
],
"epic": "fn-1",
"evidence": {
"commits": [
"6ce96797123da2cad76ca5b1cb3f1f951552b865"
],
"prs": [],
"tests": [
"npm run typecheck",
"npx vitest run"
]
},
"id": "fn-1.1",
"priority": null,
"spec_path": ".flow/tasks/fn-1.1.md",
"status": "done",
"title": "Reconcile GitHub resolver docs + e2e test + adapter comment to Releases-asset reality",
"updated_at": "2026-06-08T22:44:10.719442Z"
}
63 changes: 63 additions & 0 deletions .flow/tasks/fn-1.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# fn-1.1 Reconcile GitHub resolver docs + e2e test + adapter comment to Releases-asset reality

## Description
## Goal

Make every **GitHub** resolver surface tell the truth: the widget resolves attestations from GitHub **Releases** (`*.auths.json` assets), not from git refs. Fix the docs, the lying e2e test, and the stale interface comment. **Roadmap:** G0.5 / G4.1 (D-5) — `[P0·EDIT]`, the #1 credibility blocker.

## Source of truth

`src/resolvers/github.ts:1-12,28-35,42-108` already documents the real flow in JSDoc — reuse its wording:
1. `GET {baseUrl}/repos/{owner}/{repo}/releases/latest` (`baseUrl` = `https://api.github.com`).
2. Find the release asset whose name ends in `.auths.json` (`github.ts:55`).
3. Download it via the Contents API (`.../contents/{name}`, base64-decoded — `github.ts:69-72`), falling back to the Releases-asset API (`.../releases/assets/{id}` with `Accept: application/octet-stream` — `github.ts:75-77`).
4. Use `attestation.device_public_key` as the verification key and `attestation.issuer` as `identity_did` (`github.ts:95-101`).
5. Hand the bundle to the WASM verifier.

## Edits (GitHub-specific only)

1. **`README.md:34-40`** — "Quick Start" step 1: replace "read the repository's `refs/auths/` identity data" with the Releases-asset flow.
2. **`README.md:159-169`** — "How It Works": rewrite steps 2/3/5 (`refs/auths/identity`, `identity.json`, `refs/auths/devices/nodes/`) to the 5-step Releases flow above. If the section is single-forge, either make it GitHub-specific with a short "Gitea differs (git refs)" note, or split per-forge — keep it accurate for both.
3. **`README.md:166`** — "Ed25519 public key" → "Ed25519 **or** P-256 public key" (`did-utils.ts` now extracts both).
4. **`CHANGELOG.md`** — add an entry documenting the GitHub adapter pivot (refs → Releases assets) and P-256 support. **Chosen approach:** convert the empty `[Unreleased]` (`CHANGELOG.md:8`) into / add a `[0.3.0]` entry capturing the pivot; do NOT attempt a full 0.2.x reconstruction — add a one-line note that 0.2.x history is summarized. The obsolete line `CHANGELOG.md:17` ("resolves `refs/auths/identity` …") should be corrected or annotated as superseded, **without** touching the accurate Gitea/GitLab lines (`:18-19`).
5. **`examples/auto-resolve.html:21-24`** — "from the forge's **Git refs**" → forge-accurate wording (GitHub = Releases assets; Gitea = git refs).
6. **`src/resolvers/adapter.ts:3`** — interface comment "via Git refs" → forge-neutral (e.g. "resolves identity + attestations from a forge — git refs for Gitea, Release assets for GitHub").
7. **`tests/e2e/live-resolve.test.ts:50-58,74`** — the GitHub portion asserts `listAuthsRefs()` returns `refs/auths/registry` and a `did:keri:` issuer; neither holds for the Releases adapter (`listAuthsRefs` is a `return []` stub). Rewrite the GitHub case to assert the Releases-asset path (or restructure the test so it no longer makes an assertion that can never pass). **Keep the Gitea refs assertions** — they are legitimate.

## Do NOT touch (legitimately refs-based)

- `src/resolvers/gitea.ts` (real `refs/auths/registry` implementation), `src/resolvers/gitlab.ts` (intentional error).
- `README.md:44` ("GitLab … does not expose custom Git refs") and `CHANGELOG.md:18-19` — accurate.

## Notes

- Assumes the in-flight P-256 work in `did-utils.ts` lands (it's uncommitted on this branch). If it is reverted, drop the P-256 wording in edit #3.
- This is docs + a focused test/comment fix — no resolver logic changes.

## Out of scope

- `example-verify-badge/README.md:21` (Stream D, different repo).
- Publishing a real `*.auths.json` demo asset (Stream D, OPS, D-6/G4.2).
## Acceptance

- [ ] `grep -RInE 'refs/auths/identity|refs/auths/devices/nodes' README.md CHANGELOG.md examples/` returns **nothing** (GitHub git-refs language gone from user-facing docs).
- [ ] `README.md` "How It Works" + "Quick Start" describe the GitHub Releases-asset flow accurately (latest release → `*.auths.json` asset → Contents/asset API → `device_public_key`), and mention **Ed25519 or P-256**.
- [ ] Gitea/GitLab refs wording is **preserved** — `grep -n 'refs/auths/registry' src/resolvers/gitea.ts` still present; `README.md:44` GitLab note unchanged.
- [ ] `CHANGELOG.md` has an entry documenting the refs→Releases pivot + P-256; the obsolete refs description is corrected/superseded.
- [ ] `examples/auto-resolve.html` no longer claims GitHub resolves "from Git refs."
- [ ] `src/resolvers/adapter.ts` interface comment is forge-neutral (no implication that all forges use git refs).
- [ ] `tests/e2e/live-resolve.test.ts` no longer asserts `githubAdapter.listAuthsRefs()` returns refs; the GitHub case reflects Releases-asset reality (Gitea case still asserts refs). The test file is internally consistent (would pass if run against a live/mocked Releases asset).
- [ ] `npm run typecheck` and `npm test` pass.
## Done summary
- Corrected every GitHub-resolver surface to the Releases-asset reality: README Quick Start + "How It Works" (forge-split: GitHub = `*.auths.json` Release asset, Gitea = `refs/auths/`, GitLab = unsupported), prerequisite, supported-forges line, and the manual-mode public-key row (Ed25519 or P-256).
- CHANGELOG: added `[0.3.0]` documenting the refs→Releases pivot + P-256; annotated the obsolete 0.1.1 GitHub-adapter line as superseded (removed the `refs/auths/identity` / `refs/auths/devices/nodes` strings).
- `examples/auto-resolve.html` intro reworded; `adapter.ts` interface doc made forge-neutral.
- Rewrote the CI-excluded `tests/e2e/live-resolve.test.ts`: GitHub `listAuthsRefs` now asserted as the `[]` stub; resolve steps accept a well-formed bundle OR a well-formed "no asset" error (the example asset is pending Stream D / D-6).
- Why: D-5, the #1 credibility blocker — docs claimed git-refs resolution the GitHub adapter abandoned two migrations ago.
- Left Gitea/GitLab refs wording intact (legitimately refs-based).
- Verification: drift grep clean on README/CHANGELOG/examples; `grep refs/auths/registry src/resolvers/gitea.ts` still present; `npm run typecheck` clean; `npx vitest run` 72/72; standalone `tsc` on the rewritten e2e file compiles.
- Follow-up: live e2e green path requires D-6 (publish a real `*.auths.json` asset on example-verify-badge — Stream D, out of this repo).
## Evidence
- Commits: 6ce96797123da2cad76ca5b1cb3f1f951552b865
- Tests: npm run typecheck, npx vitest run
- PRs:
26 changes: 26 additions & 0 deletions .flow/tasks/fn-1.2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"assignee": "bordumbb@gmail.com",
"claim_note": "",
"claimed_at": "2026-06-08T22:44:23.851677Z",
"created_at": "2026-06-08T22:06:20.465209Z",
"depends_on": [
"fn-1.1"
],
"epic": "fn-1",
"evidence": {
"commits": [
"8ff53e3a49572455fe5861986ce438d7932399a5"
],
"prs": [],
"tests": [
"npm run typecheck",
"npx vitest run"
]
},
"id": "fn-1.2",
"priority": null,
"spec_path": ".flow/tasks/fn-1.2.md",
"status": "done",
"title": "Harden detect.ts URL normalization; standardize on full-URL repo= form; add tests; align snippets",
"updated_at": "2026-06-08T22:47:03.651268Z"
}
Loading
Loading