diff --git a/README.md b/README.md index 629cde0..a8cbd92 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,17 @@ The registry's deploys are not gated on the scan result. Stable URLs, no auth required: -+ Public site: `https://coder.github.io/coder-skill-scanner/` -+ Per-skill detail: `https://coder.github.io/coder-skill-scanner/skills//` -+ Run history: `https://coder.github.io/coder-skill-scanner/history` -+ CDN-cached JSON: `https://coder.github.io/coder-skill-scanner/latest.json` ++ Public site: `https://scanner.registry.coder.com/` ++ Per-skill detail: `https://scanner.registry.coder.com/skills//` ++ Run history: `https://scanner.registry.coder.com/history` ++ CDN-cached JSON: `https://scanner.registry.coder.com/latest.json` + Tagged release: `https://github.com/coder/coder-skill-scanner/releases/latest/download/latest.json` -+ Schema: `https://coder.github.io/coder-skill-scanner/schema.json` (v1) -+ Per-scan history (JSON): `https://coder.github.io/coder-skill-scanner/history/index.json` ++ Schema: `https://scanner.registry.coder.com/schema.json` (v1) ++ Per-scan history (JSON): `https://scanner.registry.coder.com/history/index.json` + +The custom domain is configured via `site/public/CNAME`; the legacy +project-page URL (`https://coder.github.io/coder-skill-scanner/`) is +still redirected by GitHub Pages but should not be used in new code. ## Public API (v1) @@ -68,19 +72,23 @@ Two badges per skill: Embed a status badge in a README: ```markdown -![skill scan](https://coder.github.io/coder-skill-scanner/api/v1/skills/coder/setup/badge/status.svg) +![skill scan](https://scanner.registry.coder.com/api/v1/skills/coder/setup/badge/status.svg) ``` Or via shields.io if you want their renderer: ```markdown -![skill scan](https://img.shields.io/endpoint?url=https://coder.github.io/coder-skill-scanner/api/v1/skills/coder/setup/badge/status.json) +![skill scan](https://img.shields.io/endpoint?url=https://scanner.registry.coder.com/api/v1/skills/coder/setup/badge/status.json) ``` -For a fork, swap the host: `https://.github.io//api/v1/...`. -The scanner derives the public base URL from `$GITHUB_REPOSITORY` at -publish time, so the same URL pattern is correct for any fork without -config changes. +For a fork, swap the host: `https:///api/v1/...`. The scanner +picks the public base URL at publish time in this order: + +1. `site/public/CNAME` (the custom Pages domain, if set), +2. otherwise `$GITHUB_REPOSITORY` -> `https://.github.io/`. + +So a fork that just sets a CNAME gets the right URLs everywhere without +touching workflow code. ## Running locally @@ -114,6 +122,7 @@ as `/skills/coder/setup` stay client-side. |-- scanner/ # Python module (CLI + enumerate + combine + aggregate + history) |-- tests/ # pytest, no on-disk fixtures |-- site/ # React SPA (Vite + Tailwind + Radix + react-router-dom) +| `-- public/CNAME # custom Pages domain (drop or change for a fork) |-- pyproject.toml |-- Makefile |-- mise.toml # pinned Python + Node versions @@ -140,15 +149,19 @@ This scanner is data-driven. To run it against a different registry: 2. Edit `config.yaml`'s `catalogue.registry_repo` block. 3. Configure GitHub Pages on your fork (Settings, Pages, source: "GitHub Actions"). -4. Set Actions workflow permissions to "Read and write" so the +4. Optional: set a custom domain by editing `site/public/CNAME` (one + line, the bare host). Delete the file to publish at the github.io + project-page URL instead. Whichever you choose, DNS for the host + needs to point at `.github.io` separately. +5. Set Actions workflow permissions to "Read and write" so the publish-release job can create releases. -5. To enable the LLM semantic pass, set the credential secret matching +6. To enable the LLM semantic pass, set the credential secret matching `config.yaml`'s `scanners.skillspector.llm.provider` on your fork (for the default `anthropic` provider, `ANTHROPIC_API_KEY`), AND confirm `.github/workflows/scan.yaml` exports that secret into the SkillSpector step. Static-only mode (without the secret) is the default and works out of the box. -6. Enable Actions. +7. Enable Actions. No source changes required for catalogue changes. diff --git a/scanner/_carry_history.py b/scanner/_carry_history.py index f152338..41f92fb 100644 --- a/scanner/_carry_history.py +++ b/scanner/_carry_history.py @@ -18,17 +18,33 @@ import urllib.request from pathlib import Path -DEFAULT_BASE = "https://coder.github.io/coder-skill-scanner" +DEFAULT_BASE_FALLBACK = "https://coder.github.io/coder-skill-scanner" MAX_SNAPSHOTS = 120 # roughly 30 days at a 6h cadence. +def _default_base() -> str: + """Return the canonical Pages URL for this repo. + + Prefer ``site/public/CNAME`` when present so a custom-domain deploy + fetches prior history from the same origin it will publish to. Fall + back to the github.io project-page URL otherwise. + """ + cname = Path("site/public/CNAME") + if cname.is_file(): + for line in cname.read_text(encoding="utf-8").splitlines(): + host = line.strip() + if host: + return f"https://{host}" + return DEFAULT_BASE_FALLBACK + + def _fetch(url: str, dest: Path) -> None: dest.parent.mkdir(parents=True, exist_ok=True) urllib.request.urlretrieve(url, dest) def main(out_dir: str = "prior-history") -> int: - base = os.environ.get("PAGES_URL") or DEFAULT_BASE + base = os.environ.get("PAGES_URL") or _default_base() base = base.rstrip("/") out = Path(out_dir) out.mkdir(parents=True, exist_ok=True) diff --git a/site/public/CNAME b/site/public/CNAME new file mode 100644 index 0000000..2af9d2e --- /dev/null +++ b/site/public/CNAME @@ -0,0 +1 @@ +scanner.registry.coder.com diff --git a/site/vite.config.ts b/site/vite.config.ts index 6b39ff2..1e29f4a 100644 --- a/site/vite.config.ts +++ b/site/vite.config.ts @@ -20,10 +20,13 @@ const REPORT_REGEX = /^\/(latest\.json|schema\.json|history\/.+\.json)$/; * Resolve the production `base` path. Lookup priority: * 1. `VITE_BASE_PATH` env (explicit override; useful for local prod * builds when you want to mimic a specific Pages deployment). - * 2. The repo name parsed from `GITHUB_REPOSITORY` (CI default; a fork - * named `/` gets `//` automatically with zero - * config). - * 3. `/` (apex / local-build fallback). + * 2. A `public/CNAME` file. When the site is published to a custom + * Pages domain, GitHub serves it at the apex of that domain so + * assets must resolve at `/`, not under `//`. + * 3. The repo name parsed from `GITHUB_REPOSITORY` (CI default; a fork + * named `/` without a custom domain gets `//` + * automatically with zero config). + * 4. `/` (apex / local-build fallback). * * Always returns a value with leading and trailing slashes so Vite's * own asset URL logic does not have to special-case the input. @@ -34,6 +37,9 @@ function resolveProductionBase(): string { const prefixed = explicit.startsWith("/") ? explicit : `/${explicit}`; return prefixed.endsWith("/") ? prefixed : `${prefixed}/`; } + if (fs.existsSync(path.resolve("public", "CNAME"))) { + return "/"; + } const repo = process.env.GITHUB_REPOSITORY?.split("/")[1]?.trim(); if (repo) return `/${repo}/`; return "/";