Harden dependency supply chain security#463
Harden dependency supply chain security#463Ed Fricker (beastawakens) wants to merge 3 commits intomainfrom
Conversation
- Add bundler-audit for Ruby dependency scanning - Add security audit workflow (daily + PR) - Verify Package.resolved is committed (already was) - Add BUNDLE_FROZEN=true in CI (setup action + build-app) - Update Dependabot with open-pull-requests-limit - SHA-pin all GitHub Actions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
| - name: Create issue on failure | ||
| if: failure() && github.event_name != 'pull_request' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| EXISTING=$(gh issue list --label "security-audit" --state open --json number --jq 'length') | ||
| if [ "$EXISTING" -gt 0 ]; then exit 0; fi | ||
| TITLE_DATE=$(date +%Y-%m-%d) | ||
| gh issue create \ | ||
| --title "Security: Ruby dependency vulnerabilities detected (${TITLE_DATE})" \ | ||
| --label "security-audit,priority:high" \ | ||
| --body "The daily security audit has detected vulnerabilities. See [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details." |
There was a problem hiding this comment.
Suggestion: The label priority:high may not exist in the repository, causing gh issue create to fail silently or with an error. More importantly, the --label flag expects labels that already exist. Consider creating labels beforehand or using only the security-audit label. Also, the step lacks permissions: issues: write at the job level — though it's present, the GITHUB_TOKEN in PRs from forks won't have write access, so this is acceptable given the github.event_name != 'pull_request' guard. [general, importance: 6]
| - name: Create issue on failure | |
| if: failure() && github.event_name != 'pull_request' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| EXISTING=$(gh issue list --label "security-audit" --state open --json number --jq 'length') | |
| if [ "$EXISTING" -gt 0 ]; then exit 0; fi | |
| TITLE_DATE=$(date +%Y-%m-%d) | |
| gh issue create \ | |
| --title "Security: Ruby dependency vulnerabilities detected (${TITLE_DATE})" \ | |
| --label "security-audit,priority:high" \ | |
| --body "The daily security audit has detected vulnerabilities. See [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details." | |
| - name: Create issue on failure | |
| if: failure() && github.event_name != 'pull_request' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| EXISTING=$(gh issue list --label "security-audit" --state open --json number --jq 'length') | |
| if [ "$EXISTING" -gt 0 ]; then exit 0; fi | |
| TITLE_DATE=$(date +%Y-%m-%d) | |
| gh label create "security-audit" --description "Automated security audit findings" --color "D93F0B" 2>/dev/null || true | |
| gh label create "priority:high" --description "High priority" --color "B60205" 2>/dev/null || true | |
| gh issue create \ | |
| --title "Security: Ruby dependency vulnerabilities detected (${TITLE_DATE})" \ | |
| --label "security-audit,priority:high" \ | |
| --body "The daily security audit has detected vulnerabilities. See [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details." |
| contents: read | ||
| issues: write | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 |
There was a problem hiding this comment.
Suggestion: The pinned SHA de0fac2e4500dabe0009e67214ff5f5447ce83dd for actions/checkout does not correspond to any known v6 release (v6 doesn't exist yet as of the known releases; the latest stable is v4). Verify this SHA is correct and points to a legitimate commit in the actions/checkout repository to avoid a supply chain attack vector or workflow failure. [security, importance: 7]
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 |
.github/dependabot.yml
Outdated
| - '*' | ||
| - package-ecosystem: "swift" | ||
| directory: "/" | ||
| open-pull-requests-limit: 0 |
There was a problem hiding this comment.
Suggestion: Setting open-pull-requests-limit: 0 for both Swift and Bundler ecosystems completely disables Dependabot PRs for these ecosystems. This means security vulnerability patches for Swift packages and Ruby gems will never be automatically proposed. Consider using open-pull-requests-limit: 0 only if you have another mechanism (like the audit workflow) to track and apply updates, but note that the audit workflow only covers Ruby, not Swift dependencies. [security, importance: 6]
| open-pull-requests-limit: 0 | |
| open-pull-requests-limit: 5 |
| ls -1 /Applications | grep Xcode || true | ||
| - name: Cache SwiftPM | ||
| uses: actions/cache@v5 | ||
| uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 |
There was a problem hiding this comment.
Suggestion: The SHA 668228422ae6a00e4ad889ee87cd7109ec5666a7 is pinned as actions/cache v5, but in .github/actions/setup/action.yml the same action is pinned to a different SHA (0057852bfaa89a56745cba8c7296529d2fc39830) labeled as v4. Using different versions of the same action across the repository is inconsistent and could lead to subtle caching behavior differences. Align all actions/cache references to the same version and SHA. [general, importance: 5]
| uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5 |
There was a problem hiding this comment.
Pull request overview
This PR strengthens dependency supply chain security for the repo’s Ruby (Bundler) and Swift (SPM) toolchains, and hardens GitHub Actions usage by pinning action references and adding automated security scanning.
Changes:
- Added
bundler-auditto the Ruby toolchain and introduced a scheduled/PR-triggered “Security Audit” workflow to scan dependencies and open an issue on scheduled failures. - Enforced Bundler lockfile consistency in CI via
BUNDLE_FROZEN(composite setup action + build workflow). - Updated Dependabot configuration to be alert-only for Swift/Bundler (limit 0), while maintaining GitHub Actions updates (limit 5), and SHA-pinned various GitHub Actions
uses:references.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| Gemfile | Adds bundler-audit dependency. |
| Gemfile.lock | Locks bundler-audit (and transitive deps) into the Ruby toolchain. |
| .github/workflows/audit.yml | New scheduled + PR-triggered dependency security audit workflow (Ruby). |
| .github/workflows/build-app.yml | Pins action SHAs and enforces BUNDLE_FROZEN during bundle install. |
| .github/actions/setup/action.yml | Pins cache action SHA and enforces BUNDLE_FROZEN during gem install. |
| .github/dependabot.yml | Adjusts PR limits per ecosystem (alert-only for swift/bundler). |
| .github/workflows/sdk-primary.yml | Pins action SHAs (checkout/cache) used in primary CI. |
| .github/workflows/stale.yml | Pins actions/stale to a commit SHA. |
| .github/workflows/post_release.yml | Pins checkout + create-pull-request actions to commit SHAs. |
| .github/workflows/auto-author-assign.yml | Pins auto-author-assign action to a commit SHA. |
Comments suppressed due to low confidence (1)
.github/workflows/sdk-primary.yml:21
- The lint job pulls
ghcr.io/nicklockwood/swiftformat:latest, which is a mutable tag and weakens the supply-chain hardening goal (the image contents can change without a PR). Pin this Docker action to an immutable reference (e.g., a versioned tag and ideally an image digest), and consider doing the same for the Danger image tag as well.
uses: docker://ghcr.io/nicklockwood/swiftformat:latest
with:
args: --lint .
- name: Danger
uses: docker://ghcr.io/danger/danger-swift-with-swiftlint:3.15.0
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| permissions: | ||
| contents: read | ||
| issues: write | ||
| steps: |
There was a problem hiding this comment.
This job grants issues: write even when running on pull_request events. Since pull_request workflows execute code from the PR branch, it’s safer to keep PR permissions read-only and only grant issues: write for the scheduled/dispatch run that may create issues (e.g., split into two jobs with different permissions + if: conditions).
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| - uses: ruby/setup-ruby@3ff19f5e2baf30647122352b96108b1fbe250c64 # v1 | ||
| with: | ||
| bundler-cache: true | ||
| - name: Update advisory database | ||
| run: bundle exec bundler-audit update | ||
| - name: Run bundler-audit | ||
| run: bundle exec bundler-audit check |
There was a problem hiding this comment.
CI hardening enforces BUNDLE_FROZEN in other workflows/composite actions, but this audit workflow doesn’t set it. Without frozen, Bundler may rewrite Gemfile.lock (e.g., platform sections) during bundler-cache installs, which can hide drift. Consider setting BUNDLE_FROZEN: "true" at the job level (or configuring Bundler frozen mode) before running bundle exec bundler-audit.
.github/workflows/audit.yml
Outdated
| jobs: | ||
| ruby-audit: | ||
| name: Ruby Security Audit | ||
| runs-on: macos-latest |
There was a problem hiding this comment.
bundler-audit doesn’t require macOS, and the lockfile includes a Linux platform entry, so running this job on ubuntu-latest should work and will reduce runner cost/queue time versus macos-latest for a daily scheduled workflow.
| runs-on: macos-latest | |
| runs-on: ubuntu-latest |
- Fix CI: add ruby-version to setup-ruby (no .ruby-version file exists) - Use ubuntu-latest instead of macos-latest (bundler-audit doesn't need macOS) - Add BUNDLE_FROZEN=true to audit job for lockfile consistency - Create labels before gh issue create to prevent failures - Remove Swift paths from audit triggers (only Ruby is audited) - Keep Dependabot PRs enabled for Swift (no audit covers it) - Align actions/cache to v5 across all workflows Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Pushed fixes addressing review feedback (44ae1f4): CI fix:
Review feedback addressed:
Not changed (intentional):
|
🔍 Semgrep Security Scan Results✅ No security findings detected by |
|
Ed Fricker (@beastawakens), this one is failing too |
User description
Summary
Applies dependency supply chain security hardening consistent with smileidentity/lambda#4304, adapted for Swift/SPM + Ruby.
Changes
cron 0 9 * * *) + runs on PRs touching dependency files, auto-creates issue on failure.gitignore(already was ✅)open-pull-requests-limit: 0for swift/bundler (alert-only), kept5for github-actionsuses:directives pinned to commit SHAs with version commentsPR Type
Enhancement
Description
SHA-pin all GitHub Actions for supply chain security
Add security audit workflow for Ruby dependencies
Enforce
BUNDLE_FROZEN=truein CI environmentsConfigure Dependabot alert-only mode for swift/bundler
Diagram Walkthrough
File Walkthrough
7 files
SHA-pin cache action and enforce BUNDLE_FROZENAdd daily Ruby security audit workflowSHA-pin auto-author-assign actionSHA-pin actions and enforce BUNDLE_FROZENSHA-pin checkout and create-pull-request actionsSHA-pin checkout and cache actionsSHA-pin stale action1 files
Set open-pull-requests-limit per ecosystem1 files
Add bundler-audit gem dependency