Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 0 additions & 183 deletions .circleci/config.yml

This file was deleted.

File renamed without changes.
149 changes: 149 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
name: Main
on:
push:
branches:
- main

permissions:
contents: read

# Every run publishes to RubyGems; serialise so close-together merges cannot
# race on version numbers. queue: max keeps every queued run (the default
# keeps only the newest pending), so a slow release approval delays later
# prereleases instead of cancelling them.
concurrency:
group: main
cancel-in-progress: false
queue: max

jobs:

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔵 Correctness (plan concern — the loop-guard is documented belt-and-braces, D4)

GitHub natively skips push-triggered workflows for [skip ci]/[ci skip]/[no ci], and GITHUB_TOKEN pushes never trigger workflows — so this job never observes the strings it checks. If kept as belt-and-braces, note it omits the native [skip actions]/[actions skip] markers; adding them would match native semantics exactly.

skip-ci-check:
runs-on: ubuntu-latest
outputs:
should_skip_ci: ${{ steps.skip_ci_check.outputs.should_skip_ci }}
steps:
- id: skip_ci_check
env:
HEAD_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
run: |
if [[ "$HEAD_COMMIT_MESSAGE" == *"[no ci]"* ]] \
|| [[ "$HEAD_COMMIT_MESSAGE" == *"[skip ci]"* ]] \
|| [[ "$HEAD_COMMIT_MESSAGE" == *"[ci skip]"* ]]; then
echo "should_skip_ci=true" >> "$GITHUB_OUTPUT"
else
echo "should_skip_ci=false" >> "$GITHUB_OUTPUT"
fi

check:
needs: [skip-ci-check]
if: needs.skip-ci-check.outputs.should_skip_ci != 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install tools

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔵 Security (plan concern — tracking asdf_install@v1 is documented as deliberate, D6)

Actions are referenced by mutable tags (actions/checkout@v4, infrablocks/github-actions/asdf_install@v1). Tags are repointable: compromise of either repo lets an attacker run code in jobs holding unlocked RubyGems credentials and contents: write — a supply-chain path to publishing a malicious ruby_terraform.

Suggestion: post-migration hardening — pin to full commit SHAs with a tag comment and let dependabot manage bumps.

uses: infrablocks/github-actions/asdf_install@v1
- name: Check
run: ./go library:check
- name: Notify Slack
if: always()
continue-on-error: true
run: ./go "slack:notify[${{ job.status }}]"
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

test:
needs: [skip-ci-check]
if: needs.skip-ci-check.outputs.should_skip_ci != 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install tools
uses: infrablocks/github-actions/asdf_install@v1
- name: Test
run: ./go test:unit
- name: Notify Slack
if: always()
continue-on-error: true
run: ./go "slack:notify[${{ job.status }}]"
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

prerelease:
needs: [check, test]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Install tools
uses: infrablocks/github-actions/asdf_install@v1
- name: Install secrets tools
run: sudo apt-get update && sudo apt-get install -y git-crypt gnupg
- name: Unlock git-crypt
run: ./go git_crypt:unlock_with_encrypted_gpg_key
env:
ENCRYPTION_PASSPHRASE: ${{ secrets.ENCRYPTION_PASSPHRASE }}
- name: Configure RubyGems credentials

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔵 Code Quality (plan concern — this inline block is the plan's exact YAML)

The 'Configure RubyGems credentials' shell block is duplicated verbatim in the prerelease and release jobs, while sibling setup logic moved into the build system (repository:set_ci_author). A change to credentials handling must be edited in two YAML places and can't be exercised via ./go.

Suggestion: fleet-wide, consider a rake task (e.g. rubygems:configure_credentials) or a composite action in infrablocks/github-actions encapsulating the secrets bootstrap.

run: |
mkdir -p ~/.gem
cp config/secrets/rubygems/credentials ~/.gem/credentials
chmod 0600 ~/.gem/credentials
- name: Set CI git author
run: ./go repository:set_ci_author
- name: Prerelease
run: ./go "version:bump[pre]" && ./go release
- name: Push release commit
run: git push && git push --tags

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔵 Safety (plan concern — the plan's exact YAML sets no timeouts)

No job in main.yaml sets timeout-minutes, so a hung step runs for GitHub's 360-minute default. All main runs share the serialised main concurrency group, so one hung prerelease/release job stalls every queued run behind it for up to 6 hours.

Suggestion: consider a modest timeout-minutes (e.g. 20–30) per job — possibly as a plan-level amendment so the fleet stays consistent.

- name: Notify Slack of release hold
continue-on-error: true
run: ./go "slack:notify[success,on_hold]"
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
- name: Notify Slack
if: always()
continue-on-error: true
run: ./go "slack:notify[${{ job.status }}]"
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

release:
needs: [prerelease]
runs-on: ubuntu-latest
environment: release
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
ref: main
- name: Pull latest main
# Approval can land long after the run starts; release publishes main
# as of approval time, not the tested SHA — parity with the old
# release.sh, which also pulled. prerelease.sh never pulled, so the
# prerelease job deliberately has no pull.
run: git pull
- name: Install tools
uses: infrablocks/github-actions/asdf_install@v1
- name: Install secrets tools
run: sudo apt-get update && sudo apt-get install -y git-crypt gnupg

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🔵 Safety (plan concern — pull-at-approval-time is documented parity with the old release.sh)

Second-order effect worth recording: the git pull runs before git_crypt:unlock_with_encrypted_gpg_key and the credential copy, so commits landing between the tested SHA and approval can alter the release tooling (go, Rakefile) that then executes with unlocked secrets and publishes — and the approval window here can be much longer than a CircleCI hold.

Suggestion: post-migration — release the tested SHA (drop the pull) or fail the release if HEAD has advanced more than N commits/days past it.

- name: Unlock git-crypt
run: ./go git_crypt:unlock_with_encrypted_gpg_key
env:
ENCRYPTION_PASSPHRASE: ${{ secrets.ENCRYPTION_PASSPHRASE }}
- name: Configure RubyGems credentials
run: |
mkdir -p ~/.gem
cp config/secrets/rubygems/credentials ~/.gem/credentials
chmod 0600 ~/.gem/credentials
- name: Set CI git author
run: ./go repository:set_ci_author
- name: Release
run: ./go "version:bump[patch]" && ./go documentation:update && ./go release
- name: Push release commit
run: git push && git push --tags
- name: Notify Slack
if: always()
continue-on-error: true
run: ./go "slack:notify[${{ job.status }}]"
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
Loading
Loading