SIGN IN SIGN UP

CI hardening (#4546)

* ci: set least-privilege permissions on workflows

Add an explicit top-level permissions: block to every workflow that was
relying on the default GITHUB_TOKEN scope, granting only what each one
needs (contents: read by default; packages: write for the ghcr.io pushes;
actions: write for the cache cleanup).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ci: disable credential persistence on checkout

Set persist-credentials: false on every actions/checkout step so the
GITHUB_TOKEN is not written to .git/config for the job's lifetime. None
of these jobs push via git, so nothing relied on the persisted token.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ci: pass untrusted values via env instead of inline interpolation

In version.yml and cache-cleanup.yaml, move workflow-dispatch- and
pull_request-derived values out of the inline run: script and into env:
variables, removing the shell-injection surface.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ci: verify protoc and javy download checksums

The go generate check downloaded protoc and javy release binaries over
curl with no integrity check. Pin the sha256 of each asset and verify it
before use (job aborts on mismatch via set -e), and harden the curl
invocation (--fail, --proto '=https', --tlsv1.2).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ci: use native gh cache instead of third-party extension

Cache cleanup installed the actions/gh-actions-cache extension at runtime
(an unpinned, unverified download). gh now manages Actions caches
natively, so replace the extension + delete loop with a single
'gh cache delete --all --ref ...'. This also drops the now-unnecessary
repo checkout (gh reads the repo from GH_REPO) and narrows permissions to
just actions: write.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ci: inline coverage badge update instead of third-party action

Replace schneegans/dynamic-badges-action with an inline gh api PATCH to
the badge gist. The action was just wrapping a GitHub Gist update with
shields.io endpoint JSON, so this removes a single-maintainer dependency
in favor of the GitHub API we already trust, and updates both badge
files in one call.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(bats): fetch hub index from a git clone to dodge CDN rate limiting

The bats fixture builds fetch the hub index from cdn-hub.crowdsec.net,
which rate-limits shared CI runner IPs and intermittently 403s, failing
'cscli hub update'. The committed .index.json on each hub branch already
embeds every item's content, so 'collections install' needs no further
downloads once the index is present.

Add a TEST_HUB_CLONE switch to config-local: when set, fetch the index
from a shallow git clone of the hub at the pinned branch instead of the
CDN (default behavior is unchanged, so local dev still uses the CDN). All
four bats CI jobs set it. On a failed index fetch (CDN or clone) log the
runner's public IP to help diagnose future rate limiting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ci(docker): use a GitHub environment for docker publish secrets

Set the reusable publish-docker workflow's push job to a configurable
environment (default: docker) so DockerHub credentials are sourced from
environment secrets. Drop the now-redundant secrets forwarding from the
master and release callers.

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

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
B
blotus committed
7364ef838e345c5b093f96ac789a008e5e97ae08
Parent: 112cc23
Committed by GitHub <noreply@github.com> on 7/8/2026, 8:03:30 AM