From 705d0f0d95b22fa01322eb083c06cecbed2c9364 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Mon, 13 Apr 2026 15:32:09 -0700 Subject: [PATCH 1/8] Update GitHub Actions to latest major versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - actions/checkout v4 → v6 - slackapi/slack-github-action v1 → v3 (migrate to new input API) - actions/stale v9 → v10 --- .github/workflows/cd.yml | 13 +++++-------- .github/workflows/ci.yml | 17 +++++++---------- .github/workflows/stale.yml | 2 +- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 72c2bd0..b131bf9 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Tag and Push Gem id: tag-and-push-gem uses: discourse/publish-rubygems-action@v3 @@ -25,13 +25,10 @@ jobs: runs-on: ubuntu-latest needs: [deploy] if: ${{ failure() && github.ref == 'refs/heads/main' }} - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK steps: - - uses: slackapi/slack-github-action@v1.25.0 + - uses: slackapi/slack-github-action@v3 with: + webhook: ${{ secrets.SLACK_WEBHOOK_URL }} + webhook-type: incoming-webhook payload: | - { - "text": "${{ github.repository }}/${{ github.ref }}: FAILED\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - } + text: "${{ github.repository }}/${{ github.ref }}: FAILED\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ee8a6c..96f2613 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: BUNDLE_GEMFILE: Gemfile name: "Run tests: Ruby ${{ matrix.ruby }}" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install ripgrep run: sudo apt-get install -y ripgrep - name: Set up Ruby ${{ matrix.ruby }} @@ -41,7 +41,7 @@ jobs: name: "Type Check" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -53,7 +53,7 @@ jobs: runs-on: ubuntu-latest name: "Linter" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -65,13 +65,10 @@ jobs: runs-on: ubuntu-latest needs: [run_tests, static_type_check, run_linter] if: ${{ failure() && github.ref == 'refs/heads/main' }} - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK steps: - - uses: slackapi/slack-github-action@v1.25.0 + - uses: slackapi/slack-github-action@v3 with: + webhook: ${{ secrets.SLACK_WEBHOOK_URL }} + webhook-type: incoming-webhook payload: | - { - "text": "${{ github.repository }}/${{ github.ref }}: FAILED\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - } + text: "${{ github.repository }}/${{ github.ref }}: FAILED\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index daabc95..9029291 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -6,7 +6,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v9 + - uses: actions/stale@v10 with: stale-issue-message: 'This issue has been marked stale because it has been open for six months with no activity. To prevent this issue from automatically being closed in one week, update it or remove the stale label.' stale-pr-message: 'This PR has been marked stale because it has been open for six months with no activity. To prevent this PR from automatically being closed in one week, update it or remove the stale label.' From 226f27962368ce5f652219400e62b192fc5843e3 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Mon, 13 Apr 2026 15:35:07 -0700 Subject: [PATCH 2/8] Add zizmor GitHub Actions security linter - Add zizmor workflow as a PR check - Add persist-credentials: false to all checkout steps - Add .zizmor.yml config to disable unpinned-uses and secrets-outside-env (intentional for reusable workflows) - Add inline ignores for template-injection on trusted workflow_call inputs and step outputs --- .github/workflows/cd.yml | 3 +++ .github/workflows/ci.yml | 8 ++++++++ .github/workflows/zizmor.yml | 25 +++++++++++++++++++++++++ .zizmor.yml | 5 +++++ 4 files changed, 41 insertions(+) create mode 100644 .github/workflows/zizmor.yml create mode 100644 .zizmor.yml diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index b131bf9..2c1bc96 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -8,6 +8,8 @@ jobs: if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Tag and Push Gem id: tag-and-push-gem uses: discourse/publish-rubygems-action@v3 @@ -17,6 +19,7 @@ jobs: GIT_NAME: ${{secrets.GUSTO_GIT_NAME}} RUBYGEMS_API_KEY: ${{secrets.RUBYGEMS_API_KEY}} - name: Create GitHub Release + # zizmor: ignore[template-injection] gem_version comes from a trusted prior step run: gh release create v${{steps.tag-and-push-gem.outputs.gem_version}} --generate-notes if: ${{ steps.tag-and-push-gem.outputs.new_version == 'true' }} env: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 96f2613..5b74a33 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,8 @@ jobs: name: "Run tests: Ruby ${{ matrix.ruby }}" steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Install ripgrep run: sudo apt-get install -y ripgrep - name: Set up Ruby ${{ matrix.ruby }} @@ -36,12 +38,15 @@ jobs: bundler-cache: true ruby-version: ${{ matrix.ruby }} - name: Run tests + # zizmor: ignore[template-injection] workflow_call inputs are controlled by the caller run: ${{ inputs.test-command }} static_type_check: name: "Type Check" runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -54,12 +59,15 @@ jobs: name: "Linter" steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Set up Ruby uses: ruby/setup-ruby@v1 with: bundler-cache: true ruby-version: 3.4 - name: Run linter + # zizmor: ignore[template-injection] workflow_call inputs are controlled by the caller run: ${{ inputs.linter-command }} notify_on_failure: runs-on: ubuntu-latest diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 0000000..77ced13 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,25 @@ +name: GitHub Actions Security Analysis + +on: + push: + branches: [main] + pull_request: + branches: ["**"] + +permissions: {} + +jobs: + zizmor: + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + actions: read + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Run zizmor + uses: zizmorcore/zizmor-action@v0 diff --git a/.zizmor.yml b/.zizmor.yml new file mode 100644 index 0000000..e1a7a0a --- /dev/null +++ b/.zizmor.yml @@ -0,0 +1,5 @@ +rules: + unpinned-uses: + disable: true + secrets-outside-env: + disable: true From 40c9e88f1a72d85350dcf569f3f1b47919ec723d Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Mon, 13 Apr 2026 19:33:30 -0700 Subject: [PATCH 3/8] Fix zizmor-action version to v0.5.3 No v0 major version tag exists; pin to latest point release. --- .github/workflows/zizmor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 77ced13..70fe47e 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -22,4 +22,4 @@ jobs: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@v0 + uses: zizmorcore/zizmor-action@v0.5.3 From 589378abe37922d3b0fddb7097fc7bcabbe3818c Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Mon, 13 Apr 2026 19:34:21 -0700 Subject: [PATCH 4/8] Add Dependabot config for GitHub Actions updates --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..3a626c3 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly From 87746e213ab80a1679202fd6f3b158f8694601b0 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Mon, 13 Apr 2026 19:36:37 -0700 Subject: [PATCH 5/8] Pass .zizmor.yml config to zizmor-action Without this, the action runs with default settings and reports unpinned-uses findings that we've intentionally disabled. --- .github/dependabot.yml | 2 ++ .github/workflows/zizmor.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3a626c3..cd83dc8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,5 @@ updates: directory: / schedule: interval: monthly + cooldown: + default-days: 7 diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 70fe47e..0a5c267 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -23,3 +23,5 @@ jobs: - name: Run zizmor uses: zizmorcore/zizmor-action@v0.5.3 + with: + config: .zizmor.yml From 7207b68f49b4343e82c9a0988f70c5480d274841 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Mon, 13 Apr 2026 19:43:20 -0700 Subject: [PATCH 6/8] Pin all actions to SHA hashes and remove blanket zizmor disables Replace tag references with SHA-pinned references for all actions. Replace blanket unpinned-uses and secrets-outside-env disables with targeted inline ignores where appropriate. Remove .zizmor.yml since no global rule overrides are needed. --- .github/workflows/cd.yml | 10 +++++----- .github/workflows/ci.yml | 16 ++++++++-------- .github/workflows/stale.yml | 2 +- .github/workflows/zizmor.yml | 6 ++---- .zizmor.yml | 5 ----- 5 files changed, 16 insertions(+), 23 deletions(-) delete mode 100644 .zizmor.yml diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 2c1bc96..b49a165 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -3,16 +3,16 @@ name: CD on: workflow_call: jobs: - deploy: + deploy: # zizmor: ignore[secrets-outside-env] reusable workflow; environments are managed by callers runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - name: Tag and Push Gem id: tag-and-push-gem - uses: discourse/publish-rubygems-action@v3 + uses: discourse/publish-rubygems-action@4bd305c65315cb691bad1e8de97a87aaf29a0a85 # v3 env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} GIT_EMAIL: ${{secrets.GUSTO_GIT_EMAIL}} @@ -24,12 +24,12 @@ jobs: if: ${{ steps.tag-and-push-gem.outputs.new_version == 'true' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - notify_on_failure: + notify_on_failure: # zizmor: ignore[secrets-outside-env] reusable workflow; environments are managed by callers runs-on: ubuntu-latest needs: [deploy] if: ${{ failure() && github.ref == 'refs/heads/main' }} steps: - - uses: slackapi/slack-github-action@v3 + - uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3 with: webhook: ${{ secrets.SLACK_WEBHOOK_URL }} webhook-type: incoming-webhook diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b74a33..dd05d91 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,13 +27,13 @@ jobs: BUNDLE_GEMFILE: Gemfile name: "Run tests: Ruby ${{ matrix.ruby }}" steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - name: Install ripgrep run: sudo apt-get install -y ripgrep - name: Set up Ruby ${{ matrix.ruby }} - uses: ruby/setup-ruby@v1 + uses: ruby/setup-ruby@4c56a21280b36d862b5fc31348f463d60bdc55d5 # v1 with: bundler-cache: true ruby-version: ${{ matrix.ruby }} @@ -44,11 +44,11 @@ jobs: name: "Type Check" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - name: Set up Ruby - uses: ruby/setup-ruby@v1 + uses: ruby/setup-ruby@4c56a21280b36d862b5fc31348f463d60bdc55d5 # v1 with: bundler-cache: true ruby-version: 3.4 @@ -58,23 +58,23 @@ jobs: runs-on: ubuntu-latest name: "Linter" steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - name: Set up Ruby - uses: ruby/setup-ruby@v1 + uses: ruby/setup-ruby@4c56a21280b36d862b5fc31348f463d60bdc55d5 # v1 with: bundler-cache: true ruby-version: 3.4 - name: Run linter # zizmor: ignore[template-injection] workflow_call inputs are controlled by the caller run: ${{ inputs.linter-command }} - notify_on_failure: + notify_on_failure: # zizmor: ignore[secrets-outside-env] reusable workflow; environments are managed by callers runs-on: ubuntu-latest needs: [run_tests, static_type_check, run_linter] if: ${{ failure() && github.ref == 'refs/heads/main' }} steps: - - uses: slackapi/slack-github-action@v3 + - uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3 with: webhook: ${{ secrets.SLACK_WEBHOOK_URL }} webhook-type: incoming-webhook diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 9029291..f643305 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -6,7 +6,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v10 + - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10 with: stale-issue-message: 'This issue has been marked stale because it has been open for six months with no activity. To prevent this issue from automatically being closed in one week, update it or remove the stale label.' stale-pr-message: 'This PR has been marked stale because it has been open for six months with no activity. To prevent this PR from automatically being closed in one week, update it or remove the stale label.' diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 0a5c267..1daa847 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -17,11 +17,9 @@ jobs: actions: read steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@v0.5.3 - with: - config: .zizmor.yml + uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 diff --git a/.zizmor.yml b/.zizmor.yml deleted file mode 100644 index e1a7a0a..0000000 --- a/.zizmor.yml +++ /dev/null @@ -1,5 +0,0 @@ -rules: - unpinned-uses: - disable: true - secrets-outside-env: - disable: true From ee1f5d86b92e35868e5cf85b734d6a10ac1c4594 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Mon, 13 Apr 2026 19:47:29 -0700 Subject: [PATCH 7/8] Clean up zizmor workflow style to match other workflows --- .github/workflows/zizmor.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 1daa847..cebce9f 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -16,10 +16,8 @@ jobs: contents: read actions: read steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - - name: Run zizmor uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 From a937aaa053fb587ff6b50c06288c5a87a28372e2 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Tue, 14 Apr 2026 11:01:45 -0700 Subject: [PATCH 8/8] Expand README with workflow documentation and usage examples --- README.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8df7404..d3cf40a 100644 --- a/README.md +++ b/README.md @@ -1 +1,61 @@ -# shared-config \ No newline at end of file +# shared-config + +Shared reusable GitHub Actions workflows for [rubyatscale](https://github.com/rubyatscale) gems. + +## Workflows + +### Reusable workflows (`workflow_call`) + +These workflows are called from individual gem repos via `uses: rubyatscale/shared-config/.github/workflows/.yml@main`. + +| Workflow | Description | +|----------|-------------| +| **CI** (`ci.yml`) | Runs tests across Ruby 3.2–4.0, Sorbet type checking, and linting (RuboCop). Test and linter commands are configurable via inputs. | +| **CD** (`cd.yml`) | Publishes the gem to RubyGems and creates a GitHub Release on successful main builds. | +| **Stale** (`stale.yml`) | Marks issues and PRs as stale after 180 days of inactivity, then closes them after 7 more days. | +| **Triage** (`triage.yml`) | Labels new issues with `triage`. | + +### Repository workflows + +| Workflow | Description | +|----------|-------------| +| **zizmor** (`zizmor.yml`) | Runs the [zizmor](https://github.com/zizmorcore/zizmor) security linter against all workflow files on every push and PR. | + +## Usage + +In a gem repo, create a workflow that calls the shared workflow: + +```yaml +# .github/workflows/ci.yml +name: CI + +on: + push: + branches: [main] + pull_request: + +jobs: + ci: + uses: rubyatscale/shared-config/.github/workflows/ci.yml@main +``` + +### CI inputs + +| Input | Default | Description | +|-------|---------|-------------| +| `test-command` | `bundle exec rspec` | Command to run tests | +| `linter-command` | `bundle exec rubocop` | Command to run the linter | + +### Required secrets + +The **CD** workflow requires the following secrets in the calling repo: + +- `GUSTO_GIT_EMAIL` / `GUSTO_GIT_NAME` — Git identity for tagging +- `RUBYGEMS_API_KEY` — API key for publishing to RubyGems +- `SLACK_WEBHOOK_URL` — Incoming webhook URL for failure notifications (used by both CI and CD) + +## Security + +- All action references are pinned to SHA hashes +- [zizmor](https://github.com/zizmorcore/zizmor) runs on every PR to lint workflows for security issues +- [Dependabot](https://docs.github.com/en/code-security/dependabot) is configured for monthly GitHub Actions updates \ No newline at end of file