Skip to content

chore: harden CI supply chain#517

Merged
andreatgretel merged 3 commits intomainfrom
andreatgretel/chore/ci-supply-chain-hardening
Apr 13, 2026
Merged

chore: harden CI supply chain#517
andreatgretel merged 3 commits intomainfrom
andreatgretel/chore/ci-supply-chain-hardening

Conversation

@andreatgretel
Copy link
Copy Markdown
Contributor

📋 Summary

Harden CI workflows against supply chain attacks by pinning all GitHub Actions to
immutable commit SHAs, removing a single-maintainer third-party action, enforcing
least-privilege workflow permissions, and enabling Dependabot. Motivated by
CVE-2025-30066
(tj-actions/changed-files tag compromise) and
Astral's open-source security writeup.

🔗 Related Issue

Closes #471

🔄 Changes

  • Pin ~30 GitHub Action references across 9 workflows to commit SHAs with # vN comments for readability
  • Replace softprops/action-gh-release with gh release upload in pack-tutorials.yml, eliminating a single-maintainer dependency with no security policy
  • Add top-level permissions: {} to 7 workflows that lacked it (build-docs, build-notebooks, check-colab-notebooks, ci, docs-preview, health-checks, pack-tutorials), enforcing least-privilege by default
  • Add .github/dependabot.yml for weekly automated updates to GitHub Actions and pip dependencies

🧪 Testing

  • make test passes - N/A, no runtime code changes
  • Unit tests added/updated - N/A, CI-only changes
  • Verify pack-tutorials workflow works on next release or via workflow_dispatch

✅ Checklist

  • Follows commit message conventions
  • Commits are signed off (DCO)
  • Architecture docs updated - N/A

Pin all GitHub Actions to commit SHAs to prevent tag-based supply chain
attacks (same class as CVE-2025-30066). Replace softprops/action-gh-release
(single-maintainer, no security policy) with gh CLI. Add top-level
permissions: {} to all workflows that lacked it, enforcing least-privilege
by default. Enable Dependabot for GitHub Actions and pip dependencies.

Closes #471
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 9, 2026

Docs preview: https://5fb796f1.dd-docs-preview.pages.dev

Notebook tutorials are placeholder-only in previews.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 9, 2026

Greptile Summary

This PR hardens CI supply chain security by pinning ~30 GitHub Action references to commit SHAs, replacing softprops/action-gh-release with the built-in gh release upload, adding top-level permissions: {} to 7 workflows, and introducing a Dependabot config (with per-package pip entries already addressed in a prior fix).

  • Adding permissions: {} at the top of build-docs.yml and pack-tutorials.yml without a corresponding permissions: block on the build-notebooks: reusable-workflow call job means the called workflow's GITHUB_TOKEN inherits {} permissions. The actions: read grant in build-notebooks.yml's build job is effectively nullified by the caller. In practice this silently disables the "Seed cache from last successful artifact" step (which needs actions: read for gh run list/gh run download), falling back gracefully but degrading CI cache hit rates.

Confidence Score: 5/5

Safe to merge — all findings are P2; no runtime code is changed, only CI workflows.

The two P2 comments identify a permission-inheritance gap for reusable workflow calls that silently degrades CI cache seeding efficiency but does not break correctness (graceful fallback is in place). All other changes are straightforward SHA pins and a clean action replacement. No P0 or P1 issues found.

.github/workflows/build-docs.yml and .github/workflows/pack-tutorials.yml — the build-notebooks: reusable-workflow job is missing a permissions: actions: read grant.

Important Files Changed

Filename Overview
.github/dependabot.yml New file: adds weekly Dependabot updates for GitHub Actions (root) and pip (three sub-package directories), correctly addressing the previous comment about per-package pip entries.
.github/workflows/pack-tutorials.yml Adds permissions: {} top-level, pins actions/download-artifact to SHA, and replaces softprops/action-gh-release with gh release upload; the build-notebooks: reusable-workflow call lacks permissions: actions: read, silently disabling cache seeding.
.github/workflows/build-docs.yml Adds permissions: {} top-level and pins all actions to SHAs; build-notebooks: reusable-workflow call lacks permissions: actions: read, silently disabling cache seeding in the called workflow.
.github/workflows/build-notebooks.yml Adds permissions: {} top-level; build job correctly grants actions: read and contents: write; all actions pinned to SHAs.
.github/workflows/ci.yml Adds permissions: {} top-level and pins all actions/checkout and astral-sh/setup-uv references to SHAs; test jobs don't need GITHUB_TOKEN so no permission issues.
.github/workflows/docs-preview.yml Adds permissions: {} top-level; build-and-deploy job correctly specifies contents: read and pull-requests: write; all four third-party actions pinned to SHAs.
.github/workflows/agentic-ci-pr-review.yml Pins actions/checkout to SHA (v4); already had explicit top-level permissions so no change needed there.
.github/workflows/semantic-pull-requests.yml Pins the external reusable workflow call to a commit SHA; already had correct permissions.

Sequence Diagram

sequenceDiagram
    participant GH as GitHub Event
    participant PT as pack-tutorials.yml
    participant BN as build-notebooks.yml
    participant Runner as Runner
    participant GHAPI as GitHub API

    GH->>PT: release:published / workflow_dispatch
    Note over PT: permissions: {} (top-level)
    PT->>BN: calls reusable workflow (no job-level permissions)
    Note over BN: GITHUB_TOKEN inherits permissions: {} from caller
    BN->>Runner: checkout + install + build notebooks
    BN-->>Runner: upload artifact (service token, unaffected)
    BN-->>PT: artifact available

    PT->>Runner: download artifact → zip tutorials
    Note over PT: zip-and-upload job: permissions: contents:write
    Runner->>GHAPI: gh release upload tag zip_file
    GHAPI-->>Runner: asset uploaded
    Runner->>Runner: rm zip (cleanup)
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: .github/workflows/build-docs.yml
Line: 16-19

Comment:
**Reusable-workflow call inherits `permissions: {}`, silently losing `actions: read`**

With top-level `permissions: {}` and no `permissions:` key on this job, the GITHUB_TOKEN passed into `build-notebooks.yml` is capped at zero permissions. The called workflow's `build` job explicitly grants `actions: read`, but that grant cannot exceed what the caller provides, so it is effectively `none`. The immediate consequence is that the "Seed cache from last successful artifact" step (`gh run list` / `gh run download`) silently fails and the cache-seeding path is skipped — falling back to a full rebuild on every run. Adding `permissions: actions: read` here preserves the intended behaviour. (The same applies to `pack-tutorials.yml` line 12.)

```suggestion
  build-notebooks:
    uses: ./.github/workflows/build-notebooks.yml
    permissions:
      actions: read
    with:
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: .github/workflows/pack-tutorials.yml
Line: 11-13

Comment:
**Reusable-workflow call inherits `permissions: {}`, silently losing `actions: read`**

Same issue as `build-docs.yml`: the `build-notebooks:` job has no `permissions:` block, so the called workflow's GITHUB_TOKEN is capped at `{}` (from the top-level `permissions: {}`). The `actions: read` declared inside `build-notebooks.yml` is nullified. The cache-seeding step (`gh run list`/`gh run download`) silently falls back to a full rebuild.

```suggestion
  build-notebooks:
    uses: ./.github/workflows/build-notebooks.yml
    permissions:
      actions: read
    secrets: inherit
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (3): Last reviewed commit: "Merge branch 'main' into andreatgretel/c..." | Re-trigger Greptile

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 9, 2026

PR #517 Review: chore: harden CI supply chain

Summary

This PR hardens the CI pipeline against supply chain attacks by:

  1. Pinning ~30 GitHub Action references across 10 workflows to immutable commit SHAs (with # vN comments for readability)
  2. Replacing the single-maintainer softprops/action-gh-release with the native gh release upload CLI command
  3. Adding top-level permissions: {} to 7 workflows that lacked explicit permission scoping
  4. Adding .github/dependabot.yml for weekly automated updates to GitHub Actions and pip dependencies

Motivated by CVE-2025-30066 (tj-actions/changed-files tag compromise) and Astral's open-source security writeup. Changes are CI-only with no runtime code impact.

Changed files (10): All under .github/ — 67 additions, 42 deletions.

Findings

SHA Pin Verification (all passed)

All SHA-to-tag mappings were verified against upstream repositories:

Action SHA (truncated) Claimed Tag Verified
actions/checkout de0fac2e... v6 Yes
actions/checkout 34e11487... v4 Yes
astral-sh/setup-uv 37802adc... v7 Yes (annotated tag)
actions/cache 66822842... v5 Yes
actions/download-artifact 37930b1c... v7 Yes
actions/upload-artifact b7c566a7... v6 Yes
cloudflare/wrangler-action da0e0dfe... v3 Yes
peter-evans/find-comment b30e6a3c... v4 Yes
peter-evans/create-or-update-comment e8674b07... v5 Yes
NVIDIA-NeMo/FW-CI-templates 21f18ae8... v0.65.12 Yes

Workflow Coverage Check

Two workflows were not modified by this PR:

  • dco-assistant.yml — Already hardened: uses SHA-pinned contributor-assistant/github-action@ca4a40a7... and has an explicit permissions: block. No changes needed.
  • agentic-ci-health-probe.yml — Already has permissions: contents: read and uses no third-party actions (only shell steps). No changes needed.

All workflows are accounted for.

Permissions Model

The permissions: {} approach is correct: it denies all permissions by default, and jobs that need elevated access (e.g., build-docs needs contents: write, docs-preview needs pull-requests: write) declare them at the job level.

Suggestion (Low Severity): Explicit contents: read for CI jobs

In ci.yml, check-colab-notebooks.yml, and health-checks.yml, jobs have permissions: {} at the workflow level but no job-level permissions. actions/checkout works on public repos without a token, so this functions correctly today. However, adding explicit permissions: { contents: read } at the job level would be more self-documenting and resilient if the repo's visibility ever changes.

Files: .github/workflows/ci.yml, .github/workflows/check-colab-notebooks.yml, .github/workflows/health-checks.yml

Note (Informational): Checkout version inconsistency

agentic-ci-pr-review.yml pins actions/checkout to v4 (34e11487...) while all other workflows use v6 (de0fac2e...). This appears intentional (the agentic CI workflow was recently added), but it's worth being aware of for future maintenance. The Dependabot configuration will flag this for upgrade automatically.

softprops/action-gh-release Replacement

The replacement of softprops/action-gh-release@v2 with gh release upload in pack-tutorials.yml is clean and correct:

  • GH_TOKEN is properly set via ${{ github.token }}
  • The contents: write permission is declared at the job level
  • The command correctly uses the tag output from the previous step
  • This eliminates a third-party dependency from a single maintainer with no security policy

Dependabot Configuration

Well structured:

  • github-actions ecosystem with ci commit prefix — aligns with conventional commits
  • pip ecosystem with chore commit prefix
  • Weekly schedule for both is reasonable

Verdict

Approve. This is a well-executed supply chain hardening PR. All SHA pins are verified against upstream tags, the permissions model is correctly implemented with least-privilege defaults, and the removal of softprops/action-gh-release is a sensible de-risking. The one suggestion (explicit contents: read on CI jobs) is low-severity and non-blocking.

nabinchha
nabinchha previously approved these changes Apr 9, 2026
The root directory has no pyproject.toml; the actual packages live under
packages/data-designer-config, packages/data-designer-engine, and
packages/data-designer.
@andreatgretel andreatgretel merged commit 54d51bd into main Apr 13, 2026
48 checks passed
andreatgretel added a commit that referenced this pull request Apr 13, 2026
The Dependabot config added in #517 included weekly version-bump PRs for
all three pip packages. This would generate noisy PRs for routine dep
updates we don't need. Set open-pull-requests-limit: 0 on the pip
ecosystems so only CVE-triggered security updates open PRs.

GitHub Actions weekly bumps are kept as-is to keep SHA pins current.
andreatgretel added a commit that referenced this pull request Apr 13, 2026
The Dependabot config added in #517 included weekly version-bump PRs for
all three pip packages. This would generate noisy PRs for routine dep
updates we don't need. Set open-pull-requests-limit: 0 on the pip
ecosystems so only CVE-triggered security updates open PRs.

GitHub Actions weekly bumps are kept as-is to keep SHA pins current.
andreatgretel added a commit that referenced this pull request Apr 13, 2026
Address Greptile review findings:
- Pin checkout, setup-uv, and download-artifact to commit SHAs
  matching the pattern from #517
- Add top-level permissions: {} to restrict default token scope
andreatgretel added a commit that referenced this pull request Apr 13, 2026
- Add a Dependabot group to bundle all GitHub Actions updates into a
  single weekly PR instead of one per action
- Fix DCO allowlist: dependabot -> dependabot[bot] to match the actual
  GitHub username (the old value never matched, but there were no
  Dependabot PRs before #517 to expose the bug)
andreatgretel added a commit that referenced this pull request Apr 13, 2026
* fix: restrict Dependabot pip updates to security-only

The Dependabot config added in #517 included weekly version-bump PRs for
all three pip packages. This would generate noisy PRs for routine dep
updates we don't need. Set open-pull-requests-limit: 0 on the pip
ecosystems so only CVE-triggered security updates open PRs.

GitHub Actions weekly bumps are kept as-is to keep SHA pins current.

* fix: group Dependabot Actions PRs and fix DCO allowlist

- Add a Dependabot group to bundle all GitHub Actions updates into a
  single weekly PR instead of one per action
- Fix DCO allowlist: dependabot -> dependabot[bot] to match the actual
  GitHub username (the old value never matched, but there were no
  Dependabot PRs before #517 to expose the bug)

* fix: align DCO assistant if-condition with custom sign-off text

The step's if-condition checked for the default sign-off text but
custom-pr-sign-comment uses different wording. This meant the
issue_comment trigger was always skipped - sign-offs only worked
by accident when a subsequent push re-triggered the action via
pull_request_target.
andreatgretel added a commit that referenced this pull request Apr 13, 2026
* ci: add workflow to publish devnotes independently of releases

Adds a GitHub Actions workflow that rebuilds the `latest` docs alias
when devnotes change on main, so blog posts go live without cutting
a package release.

* ci: pin actions to commit SHAs and restrict default permissions

Address Greptile review findings:
- Pin checkout, setup-uv, and download-artifact to commit SHAs
  matching the pattern from #517
- Add top-level permissions: {} to restrict default token scope

* ci: build devnotes from last deployed state, not main

Instead of building the full site from main (which could include
unreleased docs), checkout the commit that latest was last built
from (tracked in gh-pages commit messages) and overlay only
docs/devnotes/ from main. Download notebooks from the last
successful build-docs run instead of rebuilding them.

* ci: add actions:read permission for notebook download

The gh run list/download calls need actions:read on GITHUB_TOKEN,
which is denied by the top-level permissions: {} block.
@andreatgretel andreatgretel deleted the andreatgretel/chore/ci-supply-chain-hardening branch April 14, 2026 11:55
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.

chore: replace softprops/action-gh-release with gh CLI in pack-tutorials workflow

2 participants