From 05f93d0330d3e56bb208a4c6ce9be80c329c7481 Mon Sep 17 00:00:00 2001 From: ilia Date: Wed, 15 Jul 2026 09:39:45 -0400 Subject: [PATCH] docs: OPS checklist for npm token + Outline scopes Record outstanding one-time UI steps after v0.4.0, add publish-gitea-npm.sh, and align outline-sync body with the live Playkit page format. --- README.md | 2 +- ROADMAP.md | 3 +- docs/NPM_REGISTRY.md | 22 ++++++------ docs/OPS.md | 61 +++++++++++++++++++++++++++++++++ docs/OUTLINE.md | 32 +++++++---------- scripts/outline-sync-playkit.py | 22 +++++++----- scripts/publish-gitea-npm.sh | 26 ++++++++++++++ 7 files changed, 127 insertions(+), 41 deletions(-) create mode 100644 docs/OPS.md create mode 100755 scripts/publish-gitea-npm.sh diff --git a/README.md b/README.md index 396d006..6da530b 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ test('sign-out stays on public host', async ({ page, playkitConfig, timings }) = | `interceptNetworkCall` | Spy or mock the next matching page network call | | `playkit` CLI | `init` scaffold + `smoke` post-deploy gate | -See also `docs/NETWORK.md`, `docs/SELFTEST.md`, `docs/NPM_REGISTRY.md`, `docs/IDEAS.md`, `docs/OUTLINE.md`. +See also `docs/NETWORK.md`, `docs/SELFTEST.md`, `docs/NPM_REGISTRY.md`, `docs/OPS.md`, `docs/IDEAS.md`, `docs/OUTLINE.md`. ## Network (page traffic) diff --git a/ROADMAP.md b/ROADMAP.md index 4806b0d..470bba9 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -14,7 +14,8 @@ Living plan for making `@levkin/playkit` more useful across Levkin repos. - [ ] End adoption pause — migrate first extra consumer (`screening` candidate) - [ ] Evaluate `playwright-exporter` for scheduled synthetics (may supersede bespoke cron wrappers around `playkit smoke`) -- [ ] **Wire `NPM_PUBLISH_TOKEN` / `write:package`** — `v0.4.0` git release OK; first npm publish hit E401 (token scope). Soft-fail in CI until fixed. +- [ ] **Wire `NPM_PUBLISH_TOKEN` / `write:package`** — `v0.4.0` git release OK; first npm publish hit E401. Soft-fail in CI until fixed. Checklist: `docs/OPS.md` +- [ ] **Outline API key scopes** — vault key needs `documents.update` (+ delete/archive). Living page synced to v0.4.0 via UI; script thereafter. Checklist: `docs/OPS.md` ## Adoption pause diff --git a/docs/NPM_REGISTRY.md b/docs/NPM_REGISTRY.md index 065a59e..2aed268 100644 --- a/docs/NPM_REGISTRY.md +++ b/docs/NPM_REGISTRY.md @@ -27,13 +27,16 @@ npm i git+https://git.levkin.ca/ilia/playkit.git#v0.4.0 On `vX.Y.Z` tag, `.gitea/workflows/ci.yml` `release` job: -1. Creates the Gitea Release + attaches `npm pack` tarball (existing) +1. Creates the Gitea Release + attaches `npm pack` tarball 2. Runs `npm publish` to `https://git.levkin.ca/api/packages/ilia/npm/` - using `RELEASE_TOKEN` (needs **`write:package`** in addition to release scopes) + using `NPM_PUBLISH_TOKEN` if set, else `RELEASE_TOKEN` + (needs **`write:package`**) -One-time: edit the `RELEASE_TOKEN` personal access token / app token on Gitea -to include package write, or add a dedicated `NPM_PUBLISH_TOKEN` secret and -wire it in CI (preferred if you want least privilege). +Manual one-shot: + +```bash +NPM_PUBLISH_TOKEN=… ./scripts/publish-gitea-npm.sh +``` ## Verify @@ -41,10 +44,7 @@ wire it in CI (preferred if you want least privilege). npm view @levkin/playkit versions --registry https://git.levkin.ca/api/packages/ilia/npm/ ``` -## Outstanding ops +## Token setup -First `v0.4.0` Gitea Release succeeded; `npm publish` returned **E401** because `RELEASE_TOKEN` lacks `write:package`. Create/refresh a token with package write (or add `NPM_PUBLISH_TOKEN`) and either re-run the release job or publish once by hand: - -```bash -npm publish --registry https://git.levkin.ca/api/packages/ilia/npm/ -``` +See **`docs/OPS.md`** (Outstanding → Gitea npm publish token). First `v0.4.0` +publish hit E401 until a package-scoped token is stored as `NPM_PUBLISH_TOKEN`. diff --git a/docs/OPS.md b/docs/OPS.md new file mode 100644 index 0000000..fc07507 --- /dev/null +++ b/docs/OPS.md @@ -0,0 +1,61 @@ +# Ops checklist (playkit) + +Living ops/status after releases. Update when an item closes. + +## Done + +| Item | Status | +|------|--------| +| Pushgateway + `live-playkit` Grafana board | Applied (`10.0.10.24:9091`) | +| Tag release workflow + `RELEASE_TOKEN` | Working (`v0.3.1`, `v0.4.0` Gitea releases) | +| Selftest CI | Green (Playwright image pinned to package version) | +| Outline **QA & Dev → Playkit** content @ v0.4.0 | Updated 2026-07-15 (browser sync); keep in sync via script once API scopes fixed | +| v0.4 CLI / retry presets / registry wiring | Shipped on `main` | + +## Outstanding (needs human UI once) + +### 1. Gitea npm publish token (`write:package`) + +`v0.4.0` **Gitea Release** succeeded; `npm publish` failed with **E401** because +Actions `RELEASE_TOKEN` lacks package scopes. + +1. Gitea → **Settings → Applications → Generate New Token** +2. Scopes: **`write:package`** (implies read) + keep `write:repository` if this token also cuts releases +3. Prefer a dedicated token named `playkit-npm-publish` +4. Store as repo Action secret **`NPM_PUBLISH_TOKEN`** on `ilia/playkit` + (optional: also `vault_playkit_npm_token` in ansible vault — see ansible `docs/hardening/SECRETS.md`) +5. Publish once: + +```bash +cd /path/to/playkit # on main @ v0.4.0 +npm ci && npm run build +npm publish --registry https://git.levkin.ca/api/packages/ilia/npm/ +# or: ./scripts/publish-gitea-npm.sh +``` + +6. Verify: `npm view @levkin/playkit version --registry https://git.levkin.ca/api/packages/ilia/npm/` + +Until then consumers use the git pin: `#v0.4.0`. + +### 2. Outline API key scopes + +Vault `vault_outline_api_key` can **list/create/info/export** but **not** +`documents.update` / `delete` / `archive` (HTTP 403). + +1. Outline → **Settings → API** (API & Access) +2. Edit/recreate key with scopes at least: + +``` +collections.list documents.list documents.info documents.create documents.update documents.delete documents.archive documents.search +``` + +(Full recommended list: ansible `docs/guides/authentik-apps.md` → Outline API key) + +3. Update vault + `make vault-export-env` +4. `python3 scripts/outline-sync-playkit.py` +5. Delete leftover **QA & Dev → Playkit sync probe** if still present + +### 3. Adoption soak + +Keep **no new consumer repos** until punimtag e2e + kit CI + metrics stay green +for a few days. Then prefer `screening` as the next adopter. diff --git a/docs/OUTLINE.md b/docs/OUTLINE.md index 2fa858f..46386d4 100644 --- a/docs/OUTLINE.md +++ b/docs/OUTLINE.md @@ -2,14 +2,17 @@ Canonical prose stays in git (`README.md`, `docs/*`, `ROADMAP.md`). Browsable front door: **Outline** → collection **QA & Dev** → doc **Playkit** -(`https://notes.levkin.ca`). +(`https://notes.levkin.ca/doc/playkit-3ekU0eghbV`). + +Ops status for this page (scopes, last sync): **`docs/OPS.md`**. ## Sync script (preferred) From this repo, with Outline credentials loaded: ```bash -# from ansible: make vault-export-env && set -a && source .env && set +a +# from ansible: make vault-export-env +# then export OUTLINE_URL / OUTLINE_API_KEY (safe parse — .env may contain shell-special chars) python3 scripts/outline-sync-playkit.py python3 scripts/outline-sync-playkit.py --dry-run ``` @@ -19,8 +22,13 @@ version, install pin, what’s-in-the-box digest, and links to repo docs. **Required API scopes** (Outline → Settings → API & Access): at least `collections.list`, `documents.list`, `documents.info`, `documents.create`, -`documents.update`. Without `documents.update` the script can create a first -doc but cannot refresh an existing Playkit page (HTTP 403). +`documents.update`, and preferably `documents.delete` / `documents.archive`. +Without `documents.update` the script can create a first doc but cannot refresh +an existing Playkit page (HTTP 403). + +As of 2026-07-15 the living page was synced to **v0.4.0** via signed-in UI +because the vault API key still lacked `documents.update`. Fix the key scopes, +then prefer this script for every future release. ## When to update Outline @@ -33,19 +41,3 @@ changes consumer behavior: 3. Spot-check in Outline (search “Playkit” under QA & Dev) 4. Optional: `make outline-setup` from ansible only if collections are missing — prefer the sync script for the living Playkit page - -Paste template (if editing by hand — adjust version): - -```markdown -# @levkin/playkit - -Shared Playwright + API e2e kit. **Source of truth is the git repo.** - -- Repo: https://git.levkin.ca/ilia/playkit -- Current: vX.Y.Z -- Consumers: punimtag (e2e/) — *pause further adoption until soak completes* - -## Quick links -- README · CONSUMER.md · NETWORK.md · IDEAS.md · SELFTEST.md · ROADMAP · CHANGELOG -- Metrics: dash.levkin.ca → Live — Playkit e2e -``` diff --git a/scripts/outline-sync-playkit.py b/scripts/outline-sync-playkit.py index 8ede84a..fc1a42d 100755 --- a/scripts/outline-sync-playkit.py +++ b/scripts/outline-sync-playkit.py @@ -32,14 +32,15 @@ def load_package_version() -> str: def playkit_markdown(version: str) -> str: - return f"""# @levkin/playkit - -Shared Playwright + API e2e kit for Levkin repos. **Source of truth is the git repo** — this page is the browsable front door. + # Do not start with a second H1 — Outline already uses document title "Playkit". + return f"""Shared Playwright + API e2e kit for Levkin repos. **Source of truth is the git repo** — this page is the browsable front door. - **Repo:** https://git.levkin.ca/ilia/playkit - **Current:** v{version} - **Consumers:** punimtag (`e2e/`) — *pause further adoption until soak completes* -- **Install (git pin):** `npm i git+https://git.levkin.ca/ilia/playkit.git#v{version}` +- **Install (npm):** `npm i @levkin/playkit@{version}` — see docs/NPM_REGISTRY.md +- **Fallback (git pin):** `npm i git+https://git.levkin.ca/ilia/playkit.git#v{version}` +- **CLI:** `npx @levkin/playkit init` · `playkit smoke` ## What's in the box @@ -49,6 +50,8 @@ Shared Playwright + API e2e kit for Levkin repos. **Source of truth is the git r - Mail: `createMailInbox()` (Mailpit default, Mailtrap optional) - Auth helpers: `saveStorageState` / `storageStateUse`, `playkitFailureArtifacts()` - Metrics: `TimingCollector` → Prometheus Pushgateway → Grafana **Live — Playkit e2e** +- Retry presets: `PLAYKIT_RETRY_PRESET=strictCi|flakyNetwork|default` +- Kit selftest CI against a fake site — docs/SELFTEST.md ## Quick links (in-repo) @@ -57,10 +60,12 @@ Shared Playwright + API e2e kit for Levkin repos. **Source of truth is the git r | `README.md` | Install, env vars, release steps | | `docs/CONSUMER.md` | How to wire a consumer `e2e/` | | `docs/NETWORK.md` | Page traffic spy / error monitor | +| `docs/NPM_REGISTRY.md` | Gitea npm install / publish | +| `docs/OPS.md` | Ops soak + outstanding UI one-timers | | `docs/IDEAS.md` | OSS-borrowed backlog | | `docs/OUTLINE.md` | When / how to re-sync this page | | `docs/SELFTEST.md` | Kit CI fake-site self-test | -| `ROADMAP.md` | v0.4+ plan | +| `ROADMAP.md` | Living plan | | `CHANGELOG.md` | Per-version notes | ## Metrics @@ -71,9 +76,10 @@ Shared Playwright + API e2e kit for Levkin repos. **Source of truth is the git r ## Release checklist (operators) -1. Tag `vX.Y.Z` (must match `package.json` + CHANGELOG section) → Gitea `release` job uses `RELEASE_TOKEN` -2. Re-run this script: `python3 scripts/outline-sync-playkit.py` -3. Confirm Grafana board + Pushgateway scrape after `make deploy-observability` (ansible) +1. Tag `vX.Y.Z` (must match `package.json` + CHANGELOG section) → Gitea `release` job +2. Ensure `NPM_PUBLISH_TOKEN` has `write:package` (docs/OPS.md) so registry publish succeeds +3. Re-run this script: `python3 scripts/outline-sync-playkit.py` +4. Confirm Grafana board + Pushgateway scrape (`make deploy-observability` in ansible) _Last synced by `scripts/outline-sync-playkit.py` for v{version}._ """ diff --git a/scripts/publish-gitea-npm.sh b/scripts/publish-gitea-npm.sh new file mode 100755 index 0000000..f7c4c9e --- /dev/null +++ b/scripts/publish-gitea-npm.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Publish @levkin/playkit to the Gitea npm registry. +# Usage: +# NPM_PUBLISH_TOKEN=… ./scripts/publish-gitea-npm.sh +# # or export from vault: vault_playkit_npm_token / RELEASE_TOKEN with write:package +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +TOKEN="${NPM_PUBLISH_TOKEN:-${PLAYKIT_NPM_TOKEN:-${RELEASE_TOKEN:-}}}" +if [[ -z "${TOKEN}" ]]; then + echo "Set NPM_PUBLISH_TOKEN (Gitea token with write:package). See docs/OPS.md" >&2 + exit 1 +fi + +REG="https://git.levkin.ca/api/packages/ilia/npm/" +npm run build +TMP="$(mktemp)" +cat >"$TMP" <