Skip to content

ci: harden GitHub Actions workflows against Scorecard and CodeQL alerts - #463

Merged
TheGupta2012 merged 5 commits into
mainfrom
ci/harden-workflows
Oct 26, 2026
Merged

TheGupta2012 merged 5 commits into
mainfrom
ci/harden-workflows

Conversation

@TheGupta2012

Copy link
Copy Markdown
Member

Summary of changes

Fixes 79 of the 81 open code scanning alerts on .github/workflows/*.yml. These come from OpenSSF Scorecard (Pinned-Dependencies, Token-Permissions) and CodeQL (actions/missing-workflow-permissions). The aim is to change no workflow behavior beyond the items listed under "Behavior changes".

Action pins. Every uses: now names a commit SHA, with the version in a comment. Each SHA is the commit its tag pointed to, so no workflow runs different code. Dependabot updates the SHA and the comment together.

Token permissions. The 8 workflows with no permissions block now declare one:

  • format, docs, main, pre-release, release and test-release read contents only. The publish jobs keep their own id-token block.
  • bump-version and pr-compliance get an empty top-level block. Each job asks only for what it uses.

Hash-locked installs. Jobs that hold a write token or a secret now install their Python tools with --require-hashes:

  • tox.txt is used by format and gh-pages.
  • bump-version.txt is used by bump-version.
  • lab-env-tools.txt is used by publish-lab-env.

These files live in .github/requirements/. Each .txt is compiled with uv pip compile from the .in file of the same name, and its header gives the command. A new Dependabot uv entry updates them in one grouped weekly PR. .gitattributes marks them as generated, so GitHub collapses them in diffs.

Behavior changes

  • pr-compliance.yml no longer checks out the repository. The changelog reminder only calls the GitHub API, so the checkout did nothing. Its job now has pull-requests: write only.
  • The pip install --upgrade pip lines are removed. In main.yml, pip install setuptools is removed too: Python 3.11 already ships it, and nothing imports it.
  • Fixes a shell bug in format and gh-pages. pip install tox>=4.2.0 without quotes sent pip's output to a file named =4.2.0.
  • publish-lab-env.yml reads the qbraid-cli 0.16.10 and qbraid-core 0.6.27 pins from lab-env-tools.in instead of env vars. Dependabot will now propose bumps for both. Check a qbraid-core bump with a staging run before a production publish.

Alerts left open

Both should be dismissed with these reasons:

  • bump-version.yml:20: the job needs contents: write to push its branch. Removing it needs a GitHub App token or a PAT.
  • docs.yml:24: pip install -e '.[docs]' stays unlocked. The job has a read-only token and no secrets, so a lock costs upkeep for little gain.

The shell-script alerts in bin/ and the 5 repository-level alerts are out of scope.

Validation

  • A script checked each of the 81 alert locations against this branch: 79 are fixed, and the 2 above remain.
  • Every pinned SHA was re-checked against its tag. All workflows parse, and actionlint reports nothing.
  • Each lock installs with pip --require-hashes:
    • tox.txt on Python 3.10, 3.11 and 3.14.
    • bump-version.txt on 3.11.
    • lab-env-tools.txt on 3.12 with PIP_ONLY_BINARY=:all:.
  • Each lock also resolves for x86_64-manylinux_2_28.
  • An independent review found no blockers. Its findings are fixed.

No workflow has run with these changes yet. This PR's own checks test main, format, docs and pr-compliance. The release workflows first run at the next release. A manual test-release.yml run after merge would test the publish path.

TheGupta2012 and others added 4 commits October 26, 2026 12:53
Scorecard's Pinned-Dependencies check flags each action referenced by a
tag or branch, because the owner can move the tag to new code. Each one
now names the commit its tag pointed to on 2026-10-26, with the exact
version in a comment. Dependabot updates the SHA and the comment
together. The floating tags
resolve as follows: setup-python v7 is v7.1.0, download-artifact v8 is
v8.0.2, configure-pages v6 is v6.0.0, upload-pages-artifact v5 is
v5.0.0, deploy-pages v5 is v5.0.1, and pypi-publish release/v1 is
v1.14.3. No workflow runs different code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Eight workflows had no permissions block, so their token took the
repository default. Scorecard's Token-Permissions and CodeQL's
missing-workflow-permissions flag that. Each one now sets a top-level
block that its jobs inherit, unless a job sets its own:

- format, docs, main, pre-release, release and test-release read
  contents only. The publish jobs keep their own id-token block.
- bump-version gets an empty top-level block. Its job keeps contents
  and pull-requests write, since it pushes a branch and opens a PR.
- pr-compliance gets an empty top-level block, and its job gets
  pull-requests write. The reminder action only calls the API: it
  lists the PR's files and adds or deletes its comment.

The pr-compliance job also drops its actions/checkout step. The action
reads no files, so the checkout did nothing. Under pull_request_target
a checkout with a write token is the risky pattern, so removing it
also removes the need for contents access.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Scorecard flags every pip install that does not check hashes. The
format, gh-pages and bump-version workflows now install from lock files
in .github/requirements/, with --require-hashes:

- tox.txt locks tox for format and gh-pages.
- bump-version.txt locks qbraid-core and pyyaml.

These jobs hold a write token: gh-pages has pages and id-token write,
and bump-version has contents write. docs.yml stays unlocked. It runs
with a read-only token and no secrets, so a lock there costs upkeep and
protects little.

Each .txt file is compiled from the .in file with the same name. Its
first lines give the uv pip compile command that rebuilds it. The locks
are universal, from Python 3.10 up, because gh-pages runs on the newest
Python 3. A new Dependabot uv entry updates them in one grouped weekly
PR. .gitattributes marks them as generated, so GitHub collapses them in
diffs.

The pip self-upgrades go away, since they were unpinned installs too.
In main.yml, `pip install setuptools` did nothing: Python 3.11 from
setup-python already ships setuptools, and no test or script imports
it.

This also fixes a shell bug. `pip install tox>=4.2.0` without quotes
sent pip's output to a file named `=4.2.0` and installed any tox
version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tool venv in publish-lab-env.yml now installs qbraid-cli 0.16.10 and
qbraid-core 0.6.27 from .github/requirements/lab-env-tools.txt, with
--require-hashes. The two versions moved from the QBRAID_CLI_VERSION and
QBRAID_CORE_VERSION variables into lab-env-tools.in. The other
dependencies are now locked too, and PIP_ONLY_BINARY still applies.

Dependabot now proposes new qbraid-cli and qbraid-core versions in the
grouped weekly PR. Before, they changed only by hand. qbraid-core does
the upload path rewriting, so check a bump of it with a staging run
before the next production publish.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@argus-eye

argus-eye Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Argus review

Auto-review is off for this repo. Tick the box below to run a review on this PR.

Running Argus review...

Estimated cost

  • Files changed: 19
  • Diff lines (±): 1929
  • Historical avg: ~343.4k tokens · ~$1.24 · across last 16 review(s)

Tip: you can also comment @argus-eye review at any time.

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

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@TheGupta2012
TheGupta2012 marked this pull request as ready for review October 26, 2026 07:27
@argus-eye

This comment has been minimized.

@argus-eye argus-eye Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argus · 9/10 — Wrong ecosystem for compiled requirements

Check 1 warning before you merge. Argus reviewed 19 files.

What this PR does · 16 author checks
  • Fix 79 of 81 workflow code scanning alerts from Scorecard and CodeQL without changing workflow behavior beyond the listed behavior changes.
  • Excludes: Shell-script alerts in bin/ and the 5 repository-level alerts are out of scope.
  • Excludes: Removing contents: write from bump-version.yml requires a GitHub App token or PAT and is not included.

Author's checks

  • 79 of the 81 workflow alert locations are fixed; the identified bump-version.yml and docs.yml alerts remain.
  • Every uses: reference names a commit SHA matching its original tag, with the version in a comment.
  • format, docs, main, pre-release, release and test-release declare contents: read; publish jobs retain their id-token permissions.
  • bump-version and pr-compliance declare empty top-level permissions blocks, with job-specific permissions.
  • Jobs holding a write token or secret install Python tools from the specified lock files with --require-hashes.
  • Each requirements .txt is compiled from its same-named .in file using uv pip compile, with the command in its header.
  • Dependabot has a uv entry updating the requirements in one grouped weekly PR.
  • .gitattributes marks the requirements lock files as generated.
  • pr-compliance.yml does not check out the repository, and its changelog reminder job has only pull-requests: write.
  • Remove pip install --upgrade pip lines and main.yml's pip install setuptools.
  • Fix the unquoted pip install tox>=4.2.0 shell redirection bug in format and gh-pages.
  • publish-lab-env.yml reads qbraid-cli 0.16.10 and qbraid-core 0.6.27 pins from lab-env-tools.in rather than environment variables.
  • All workflows parse and actionlint reports no findings.
  • tox.txt installs with --require-hashes on Python 3.10, 3.11 and 3.14; bump-version.txt installs on Python 3.11.
  • lab-env-tools.txt installs with --require-hashes on Python 3.12 with PIP_ONLY_BINARY=:all:.
  • Each lock resolves for x86_64-manylinux_2_28.

⚠️ This PR exceeds reviewable size — findings carry reduced confidence. Consider splitting it into smaller PRs.

usage: 233.7k tokens · 4 stages

Contract: config/full · checked: single-pass review · review took 57s

Stage Model Tokens Cost
Intent openai/gpt-6.1-sol 7.5k $0.0151
Triage openai/gpt-6.1-sol 35.7k $0.0374
Review openai/gpt-6.1-sol 188.3k $0.3900
Scoring openai/gpt-6.1-sol 2.1k $0.0032

Note

1929 lines changed, over the full-review limit of 1500 — reviewing at reduced depth


Dashboard → · React 👎 on an inline comment to dismiss it · Reply to an inline comment or use @argus-eye help

🧠 Learned: 1 PR summary · 1 finding memory · 1 file memory · 1 architecture note

Comment thread .github/dependabot.yml Resolved
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@TheGupta2012

Copy link
Copy Markdown
Member Author

Merging after argus review was passed.

@TheGupta2012
TheGupta2012 merged commit 44b0766 into main Oct 26, 2026
23 checks passed
TheGupta2012 added a commit that referenced this pull request Oct 26, 2026
#465)

* ci(lab-env): set minimum versions in lab-env-tools.in so Dependabot can update it

Dependabot's first weekly uv update after #463 failed with "No solution
found". lab-env-tools.in pinned qbraid-cli==0.16.10 and
qbraid-core==0.6.27 exactly, and Dependabot raises one package at a time:

- qbraid-cli 0.16.16 needs qbraid-core>=0.6.35, which the exact core
  pin forbids.
- Dependabot treats the qbraid-core in bump-version.in as the same
  package. Raising it to 0.6.36 collided with the ==0.6.27 pin here.

The .in file now sets minimum versions only. The exact versions stay in
lab-env-tools.txt, which the workflow installs, and rebuilding it gives
a byte-identical file. A run of the same uv pip compile -P commands
Dependabot used now resolves, to qbraid-cli 0.16.16 and qbraid-core
0.6.37.

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

* docs(changelog): note the lab-env-tools.in minimum versions

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

2 participants