* ci(security): add scoped GITHUB_TOKEN permissions to all workflows
Every workflow now declares its token permissions explicitly instead of
inheriting the repository default, which satisfies OpenSSF Scorecard's
token-permissions check.
Multi-job and write-scoped workflows use `permissions: {}` as a
deny-by-default floor at the top level, with the actual grants declared
per job. Consolidating those grants at the workflow level would leak
scopes into jobs that don't need them — a `permissions` block replaces
rather than merges, so the empty top-level block also makes a forgotten
job block fail closed rather than inherit the default.
Single-job read-only package workflows keep a plain top-level
`contents: read`; there is no write scope to leak, so a second block per
file would only add noise.
Scopes were matched to what each job's steps actually do:
- linting-icons: `contents: read` per job. No `pull-requests: read` —
tj-actions/changed-files only needs that with `use_rest_api: true`,
and here it reads the local .git.
- lint-pr-title: `pull-requests: read`, which
action-semantic-pull-request needs to read the PR title.
- close-stale-prs: `pull-requests: write` only; the job never checks out.
- comment-icon-preview: `actions: read` for the cross-run artifact
download, plus `pull-requests: write` to post the comment.
- release: `contents: read` for the checkouts, `id-token: write` only on
the publishing jobs that use npm provenance, and `contents: write` only
on post-release, which uploads the release assets. The prepare job
neither checks out nor calls the API, so its empty scope is explicit.
- ci: `contents: write` only on create-release; the reusable-workflow
calls pass `id-token: write` and `contents: write` down to release.yml,
since a called workflow can only reduce what the caller grants.
Verified with actionlint (no new findings) and zizmor (no
excessive-permissions findings).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(ci): correct pull_request path filter in the lucide-vue workflow
The Vue package lives in packages/vue, not packages/lucide-vue, so the
filter never matched and the workflow did not run for changes to the
package itself.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Remove empty scope in prepare
* Patch WeaknessCWE-506
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The create-release job restored the shared pnpm store through
setup-node before computing and tagging the new version. Actions
caches can be written by other workflow runs, so the job that cuts
releases should install from the registry instead; the frozen
lockfile still pins and verifies every dependency, and this job runs
only a few times a day at most.
Jobs without a permissions block inherit the repository default token
scope. Scopes are derived from what each workflow actually does with
the token:
- the fourteen package build and test workflows plus the code linter
never write through the token, they drop to contents: read.
- lint-pr-title.yml gets pull-requests: read, which is what the
semantic PR title action documents needing.
- comment-icon-preview.yml runs on workflow_run, a privileged trigger
processing artifacts produced by fork PRs, so an exact scope matters
most there: actions: read to download the artifact, issues: write
plus pull-requests: write to post the preview comment, contents:
read for the rest.
The workflows that already declared scoped permissions (labeler,
stale, linting-icons, release and friends) are untouched.
Both reusable calls to release.yml used 'secrets: inherit', which
forwards the caller's entire secret set. The only secret release.yml
reads is BLOB_READ_WRITE_TOKEN, used by the build-font job to upload
the code points blob; npm publishing is OIDC trusted publishing and
needs no token secret at all. Declare that one secret on the reusable
workflow and pass it explicitly, so the workflow files show exactly
which secret flows into the release path and nothing else does. It is
declared optional, so tag-push runs (which read it from the repo
secrets directly) and forks without the secret behave as before.
Version tags are movable pointers: whoever controls an action's repo
can re-point them, and the previous commit's CVE is the proof it
happens in practice, to this very repository's dependency set. These
workflows hold real credentials: release.yml publishes the whole
lucide npm family with OIDC trusted publishing, ci.yml creates the
GitHub releases, and the comment and review workflows carry
pull-request write tokens.
Pinning by full commit SHA makes the reviewed code the code that runs.
Every pin keeps a version comment, resolved from the upstream repo and
cross-checked against its release tag (softprops v1 has no patch tag,
the comment names the floating tag it replaced). Dependabot understands
SHA pins and keeps bumping them with the comment in sync; the repo has
no dependabot.yml yet, adding one with the github-actions ecosystem is
a one-block follow-up.
request-review.yml still referenced tj-actions/changed-files@v41, the
action and version range hit by the March 2025 supply chain compromise
(GHSA-mrrh-fwg8-r2c3): the attacker re-pointed existing version tags at
code that dumped the runner's memory, including the job's GITHUB_TOKEN,
into the public build logs.
Bump to v46.0.5, pinned by commit SHA so the ref cannot be re-pointed
again; the two other call sites already on v46 get the same pin in the
next commit. The action's file-matching API is unchanged between v41
and v46 for the patterns used here.
2026-08-05 11:04:21 +02:00
Eric FennisandCopilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* feat(ci): added custom prettier plugin for icon SVG files
* feat(ci): added custom prettier plugin for icon SVG files
* feat(ci): replace prettier plugin implementation with one based on svgo
* fix(ci): fix linting issues in prettier plugin
* Allow fill in path to fix podcast icon
* Format code
---------
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
* fix(ci): add check to skip release if latest tag was created today
* Apply dispatch gate to the ci workflow
* Fix ci
* Revert svg changes
* Revert svg
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Format ci file
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>