Skip to content

Harden dependency supply chain security#463

Open
Ed Fricker (beastawakens) wants to merge 3 commits intomainfrom
dependency-hardening
Open

Harden dependency supply chain security#463
Ed Fricker (beastawakens) wants to merge 3 commits intomainfrom
dependency-hardening

Conversation

@beastawakens
Copy link
Copy Markdown
Member

@beastawakens Ed Fricker (beastawakens) commented Apr 3, 2026

User description

Summary

Applies dependency supply chain security hardening consistent with smileidentity/lambda#4304, adapted for Swift/SPM + Ruby.

Changes

  • bundler-audit: Added vulnerability scanning for Ruby deps (Gemfile + lockfile updated)
  • Security audit workflow: Daily scan (cron 0 9 * * *) + runs on PRs touching dependency files, auto-creates issue on failure
  • Package.resolved: Verified committed and not in .gitignore (already was ✅)
  • BUNDLE_FROZEN: Enforced in CI via setup composite action and build-app workflow
  • Dependabot: Added open-pull-requests-limit: 0 for swift/bundler (alert-only), kept 5 for github-actions
  • SHA-pinned GitHub Actions: All uses: directives pinned to commit SHAs with version comments

PR Type

Enhancement


Description

  • SHA-pin all GitHub Actions for supply chain security

  • Add security audit workflow for Ruby dependencies

  • Enforce BUNDLE_FROZEN=true in CI environments

  • Configure Dependabot alert-only mode for swift/bundler


Diagram Walkthrough

flowchart LR
  A["Dependabot config"] -- "alert-only limits" --> B["Dependency alerts"]
  C["audit.yml workflow"] -- "daily + PR trigger" --> D["bundler-audit scan"]
  D -- "on failure" --> E["Auto-create GitHub issue"]
  F["SHA-pinned actions"] -- "immutable refs" --> G["Tamper-proof CI"]
  H["BUNDLE_FROZEN=true"] -- "enforced in CI" --> I["Lockfile integrity"]
Loading

File Walkthrough

Relevant files
Enhancement
7 files
action.yml
SHA-pin cache action and enforce BUNDLE_FROZEN                     
+3/-1     
audit.yml
Add daily Ruby security audit workflow                                     
+41/-0   
auto-author-assign.yml
SHA-pin auto-author-assign action                                               
+1/-1     
build-app.yml
SHA-pin actions and enforce BUNDLE_FROZEN                               
+5/-3     
post_release.yml
SHA-pin checkout and create-pull-request actions                 
+3/-3     
sdk-primary.yml
SHA-pin checkout and cache actions                                             
+4/-4     
stale.yml
SHA-pin stale action                                                                         
+1/-1     
Configuration changes
1 files
dependabot.yml
Set open-pull-requests-limit per ecosystem                             
+3/-2     
Dependencies
1 files
Gemfile
Add bundler-audit gem dependency                                                 
+1/-0     


Need help?
  • Type /help how to ... in the comments thread for any questions about PR-Agent usage.
  • Check out the documentation for more information.
  • - 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>
    @beastawakens Ed Fricker (beastawakens) requested a review from a team as a code owner April 3, 2026 18:54
    Copilot AI review requested due to automatic review settings April 3, 2026 18:54
    @prfectionist
    Copy link
    Copy Markdown
    Contributor

    prfectionist bot commented Apr 3, 2026

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
    🏅 Score: 85
    🧪 No relevant tests
    🔒 No security concerns identified
    🔀 No multiple PR themes
    ⚡ Recommended focus areas for review

    Inconsistent SHA pins

    The actions/checkout SHA de0fac2e4500dabe0009e67214ff5f5447ce83dd is commented as v6 throughout the PR, but in audit.yml the actions/cache used in setup/action.yml is pinned to 0057852bfaa89a56745cba8c7296529d2fc39830 (commented v4), while in sdk-primary.yml it's pinned to 668228422ae6a00e4ad889ee87cd7109ec5666a7 (commented v5). The setup/action.yml cache pin appears to be an older version (v4) than what's used elsewhere (v5). This inconsistency should be verified — using an older cache action version in one place may be intentional but looks like an oversight.

    Missing Swift audit

    The workflow triggers on changes to Package.swift and Package.resolved but only runs a Ruby audit job (ruby-audit). There is no corresponding Swift dependency audit step, so changes to Swift dependency files will trigger the workflow but not actually scan Swift dependencies for vulnerabilities.

    paths:
      - 'Package.swift'
      - 'Package.resolved'
      - 'Gemfile'
      - 'Gemfile.lock'
    Label creation assumption

    The gh issue create command uses --label "security-audit,priority:high" and gh issue list --label "security-audit". If these labels don't already exist in the repository, the gh issue create command will fail. Consider adding a step to ensure the labels exist or handling the error case.

    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."
    Missing bundle config

    In build-app.yml, bundle install is run with BUNDLE_FROZEN: "true" but without first running bundle config set path vendor/bundle (unlike in the setup/action.yml). This means gems install to the default location rather than vendor/bundle, which may cause inconsistencies with caching or other steps that expect gems in vendor/bundle.

    run: bundle install
    env:
      BUNDLE_FROZEN: "true"

    Comment on lines +30 to +41
    - 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."
    Copy link
    Copy Markdown
    Contributor

    Choose a reason for hiding this comment

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

    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]

    Suggested change
    - 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
    Copy link
    Copy Markdown
    Contributor

    Choose a reason for hiding this comment

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

    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]

    Suggested change
    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

    - '*'
    - package-ecosystem: "swift"
    directory: "/"
    open-pull-requests-limit: 0
    Copy link
    Copy Markdown
    Contributor

    Choose a reason for hiding this comment

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

    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]

    Suggested change
    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
    Copy link
    Copy Markdown
    Contributor

    Choose a reason for hiding this comment

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

    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]

    Suggested change
    uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5

    Copy link
    Copy Markdown

    Copilot AI left a comment

    Choose a reason for hiding this comment

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

    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-audit to 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.

    Comment on lines +18 to +21
    permissions:
    contents: read
    issues: write
    steps:
    Copy link

    Copilot AI Apr 3, 2026

    Choose a reason for hiding this comment

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

    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).

    Copilot uses AI. Check for mistakes.
    Comment on lines +22 to +29
    - 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
    Copy link

    Copilot AI Apr 3, 2026

    Choose a reason for hiding this comment

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

    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.

    Copilot uses AI. Check for mistakes.
    jobs:
    ruby-audit:
    name: Ruby Security Audit
    runs-on: macos-latest
    Copy link

    Copilot AI Apr 3, 2026

    Choose a reason for hiding this comment

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

    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.

    Suggested change
    runs-on: macos-latest
    runs-on: ubuntu-latest

    Copilot uses AI. Check for mistakes.
    - 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>
    @beastawakens
    Copy link
    Copy Markdown
    Member Author

    Pushed fixes addressing review feedback (44ae1f4):

    CI fix:

    • Added ruby-version: ruby to setup-ruby — the repo has no .ruby-version file, so default fails

    Review feedback addressed:

    • ubuntu-latest: Switched audit job from macos-latest (saves cost/queue time, bundler-audit doesn't need macOS)
    • BUNDLE_FROZEN: Added to audit job env for lockfile consistency
    • Label creation: Added gh label create with 2>/dev/null || true before gh issue create to handle missing labels
    • Swift paths removed: Audit triggers no longer fire on Package.swift/Package.resolved changes (only Ruby is audited)
    • Dependabot Swift limit: Changed from 05 since no audit mechanism covers Swift deps
    • actions/cache aligned: Updated setup/action.yml from v4 → v5 SHA to match sdk-primary.yml

    Not changed (intentional):

    • actions/checkout@v6 SHA is correct — verified via gh api repos/actions/checkout/git/ref/tags/v6 returns de0fac2e...
    • Permissions: issues: write is guarded by github.event_name != 'pull_request' condition on the issue-creation step

    @github-actions
    Copy link
    Copy Markdown

    github-actions bot commented Apr 9, 2026

    🔍 Semgrep Security Scan Results

    ✅ No security findings detected by p/security-audit ruleset.

    @wangerekaharun
    Copy link
    Copy Markdown
    Member

    Ed Fricker (@beastawakens), this one is failing too

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Projects

    None yet

    Development

    Successfully merging this pull request may close these issues.

    3 participants