The first iteration moved signing from the Cloudflare worker into this repo's CI to fix the worker-as-sign-oracle defect. The re-review pointed out that this just relocated the trust problem: anyone who lands a commit on main gets the resulting bytes signed automatically. Mitigations: * CODEOWNERS — sign-script, build scripts, the workflow itself, and the auto-generated index/sig files are owned by the registry owner. Combined with branch protection requiring CODEOWNERS review, a PR touching the signing infrastructure or the artefacts it produces cannot land without explicit owner sign-off. Plugin contributions under plugins/<name>/ are covered by the standard PR-review rules but don't trip CODEOWNERS unless they touch the signing path. * SHA-pinned actions — actions/checkout@v4 and actions/setup-node@v4 replaced with full-SHA refs (v4.2.2 / v4.1.0). Blocks action-supply-chain swaps (a malicious mutable tag move on a popular action would otherwise execute in the same job that has REGISTRY_PRIVATE_KEY in scope). * Post-sign self-verify — a new step verifies plugins-index.json.sig against the committed pubkey (not a secret) BEFORE the .sig hits main. Catches a buggy sign-script run, an env-leak that produces zero-bytes output, or a half-applied edit. * REGISTRY_PRIVATE_KEY env scope — explicitly noted in workflow comment that the secret is on the sign step ONLY (where it was already), not the job. Prevents future contributors lifting it to job-level out of convenience. * In-workflow security model docstring — enumerates the residual threat model (compromised maintainer, malicious PR, sign-step bug, leaked refresh token) and what each defense addresses. Trust root is now: GitHub branch protection on main + CODEOWNERS on sign infrastructure + SHA-pinned actions + post-sign verification. A maintainer with push rights can still ship malicious bytes through a code-review bypass — that residual is the same as for any signed package registry and falls outside what CI alone can mitigate. Branch protection on `main` MUST be configured by an org admin to match the assumptions in CODEOWNERS: - require pull request reviews (at least 1) - require review from CODEOWNERS - dismiss stale approvals on new commits - restrict who can push directly to main (org admins only)
32 lines
1.4 KiB
Plaintext
32 lines
1.4 KiB
Plaintext
# CODEOWNERS for librefang-registry
|
|
#
|
|
# A push to main can trigger the registry-worker forced-refresh and have
|
|
# whatever's in plugins-index.json signed by the registry's Ed25519 key
|
|
# (REGISTRY_PRIVATE_KEY in this repo's GitHub Actions store). Branch
|
|
# protection alone doesn't constrain WHICH files a maintainer can land —
|
|
# CODEOWNERS does.
|
|
#
|
|
# Files listed here REQUIRE explicit approval from the listed owners
|
|
# before a PR can land. The signing infrastructure (workflow + script)
|
|
# and the artefacts it produces (committed indexes + signature) carry
|
|
# the highest sensitivity. Plugin contributions under plugins/<name>/
|
|
# are owned by the plugin author but still go through PR review.
|
|
#
|
|
# Branch protection on `main` MUST be configured to:
|
|
# - require pull request reviews (at least 1)
|
|
# - require review from CODEOWNERS
|
|
# - dismiss stale approvals on new commits
|
|
# - restrict who can push directly to main (org admins only)
|
|
|
|
# ---- Signing infrastructure (highest sensitivity) ----
|
|
/scripts/sign-plugins-index.mjs @suzukaze-haduki
|
|
/scripts/build-plugins-index.mjs @suzukaze-haduki
|
|
/scripts/build-registry-index.mjs @suzukaze-haduki
|
|
/.github/workflows/ @suzukaze-haduki
|
|
/.github/CODEOWNERS @suzukaze-haduki
|
|
|
|
# ---- Auto-generated artefacts (must not be hand-edited) ----
|
|
/plugins-index.json @suzukaze-haduki
|
|
/plugins-index.json.sig @suzukaze-haduki
|
|
/registry-index.json @suzukaze-haduki
|