Skip to content

ci: validate plugins.json against schema + sort/dedup gate (P-CI1)#2

Merged
detain merged 1 commit into
masterfrom
fix/plugins-ci1-validate
Jun 28, 2026
Merged

ci: validate plugins.json against schema + sort/dedup gate (P-CI1)#2
detain merged 1 commit into
masterfrom
fix/plugins-ci1-validate

Conversation

@detain

@detain detain commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Step P-CI1 — Add JSON-Schema validation CI workflow

Adds .github/workflows/validate-catalog.yml (triggered on push + pull_request) that gates every change to the catalog trust root.

Jobs / steps

  1. Schema (schema job) — validates plugins.json against the already-merged plugins.schema.json with a pinned validator:
    npx --yes --package ajv-cli@5 --package ajv-formats@2 -- ajv validate --spec=draft2020 -s plugins.schema.json -d plugins.json -c ajv-formats
    • ajv-formats@2 is co-installed and passed via -c ajv-formats because the schema uses format: uri (plain ajv errors on the uri keyword — known catalog-PR landmine).
    • --spec=draft2020 because the schema is Draft 2020-12 (ajv-cli@5 / ajv v8 does not enable it by default).
    • No setup-node cache: npm — there is no lockfile in this repo (known landmine).
  2. Sort/dedup (same job) — a single jq -e filter asserts plugins.json is valid JSON (jq exits 5 on parse error) AND entries are sorted by name with no duplicate name. Addresses the "entries unsorted/undeduped" code-quality gap.
  3. Pin-drift (pin-drift job, continue-on-error: true) — for each entry, downloads https://github.com/<owner>/<repo>/archive/<ref>.tar.gz and asserts sha256sum == artifactSha256, surfacing pin drift without flaking PRs.

Data reorder (required)

The 4 entries on master were not sorted by name (anidb, myanimelist, trakt, lastfm), so the new sort-check would have failed CI. This PR sorts the plugins array by name (anidb, lastfm, myanimelist, trakt) via jq '.plugins |= sort_by(.name)'. Proven data-only: sorting the original HEAD file and the new file and diffing is IDENTICAL — only element order changed, no field values touched.

Local proof — GOOD data

$ ajv validate --spec=draft2020 -s plugins.schema.json -d plugins.json -c ajv-formats
plugins.json valid              # EXIT=0

$ jq -e -r '<sort/dedup filter>' plugins.json
OK: 4 entries sorted & unique   # EXIT=0

Local proof — BAD data (each exits non-zero; fixtures never committed)

bad name (evil-plugin)   -> must match pattern "^phlix-plugin-..."      EXIT=1
missing ref              -> must have required property 'ref'           EXIT=1
39-hex ref               -> must match pattern "^[0-9a-f]{40}$"         EXIT=1
unsorted (master order)  -> ERROR: plugins are not sorted by name       EXIT=1
duplicate name           -> ERROR: duplicate plugin name(s): [...]      EXIT=1
truncated JSON           -> jq -e                                       EXIT=5

YAML validated with python3 yaml.safe_load → OK.

Do not merge — Phase Coordinator owns the git cycle.

🤖 Generated with Claude Code

Add .github/workflows/validate-catalog.yml (push + pull_request):
- schema job: ajv-cli@5 + ajv-formats@2 (--spec=draft2020, -c ajv-formats)
  validates plugins.json against plugins.schema.json. ajv-formats is required
  because the schema uses `format: uri`; no setup-node `cache: npm` (no lockfile).
- jq step: asserts valid JSON + entries sorted by `name` + no duplicate `name`.
- pin-drift job (continue-on-error): downloads each pinned tarball and compares
  sha256sum to artifactSha256, surfacing drift without flaking PRs.

Also reorder the `plugins` array by `name` (data-only; lastfm now precedes
myanimelist/trakt) so the new sort-check passes. No field values changed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@detain detain merged commit 6a2868f into master Jun 28, 2026
4 checks passed
@detain detain deleted the fix/plugins-ci1-validate branch June 28, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant