From 6f3609728670785a1cbe1dadbb38beca4297658a Mon Sep 17 00:00:00 2001 From: Elmehdi Aitbrahim Date: Sat, 15 Aug 2026 16:15:33 -0400 Subject: [PATCH] ci: run every workflow on merge to main, except the release The repository became PUBLIC on 2026-08-15. GitHub bills no Actions minutes for standard runners on public repositories, so the cost argument that kept `code-quality` and `migrate` off `push` no longer applies. Both now also run on merge to `main`; `ci` already did. `release.yml` stays `workflow_dispatch` only, deliberately and by the operator's explicit instruction. Its own header states the rule -- "Nothing about a money-moving tool should ship on a merge" -- and it could not run on `push` anyway: its `version` input is required and a push event supplies no inputs, so the job would fail at its first validation step. `migrate.yml` gains a safety property worth naming, because it is a property of the EVENT rather than of anyone's care: `db_path` is a `workflow_dispatch` input, and a push carries no inputs, so on a merge `inputs.db_path` renders empty and the job always takes its `migration_smoke.py` branch. No merge can supply a value that makes it write to a real database. The comment says so, and says not to add a default target or read one from a repo variable, since either would remove the property. `code-quality.yml` keeps its weekly schedule rather than replacing it: a CVE published against an unchanged pin is invisible to a per-merge trigger and obvious to a scheduled one. It still does NOT run on `pull_request`, and on a public repo that is now a security choice rather than a cost one -- fork PRs receive no repository secrets, so every one would fail at the preflight for a reason the contributor could not fix. KNOWN CONSEQUENCE: SONAR_TOKEN and SNYK_TOKEN do not exist at repo or org level, so `code-quality` will fail its preflight on every merge until they are added. That job exists to say why in one line rather than let the scanners fail obscurely, but it will now say it on a schedule of every merge. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/code-quality.yml | 26 ++++++++++++++++---------- .github/workflows/migrate.yml | 17 +++++++++++++---- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 3ba5b4d2..e610df66 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -16,18 +16,24 @@ name: Code Quality # │ SonarQube Cloud requires -- read that file before the first run. # └─────────────────────────────────────────────────────────────────────────────────────────────── # -# TRIGGERS: a DELIBERATE divergence from the reference workflow this is modelled on -# (TempTrak-Ingestion-Service's `code-quality.yml`), which runs on `push`, `pull_request` and -# `workflow_dispatch`. Running per-push here would reintroduce exactly the automatic Actions spend -# that `ci.yml` was just changed to remove -- the two changes would cancel out. The scheduled run -# is kept because dependency scanning is the one kind of check that finds something new without -# the code changing: a CVE published against a version of `cryptography` that keel has been -# pinning, unmodified, for months is invisible to a per-push trigger and obvious to a weekly one. -# Static analysis has no such property, but it is cheap to fold into the same weekly pass. -# Adding `push:` / `pull_request:` below is a one-line change if parity with the other repo is -# wanted later. +# TRIGGERS. This was `workflow_dispatch` + `schedule` only, to avoid the automatic Actions spend a +# per-merge trigger implies. **That constraint is gone: the repository became PUBLIC on 2026-08-15, +# and GitHub bills no Actions minutes for standard runners on public repositories.** The cost +# argument that kept this off `push` no longer holds, so it now also runs on every merge to `main`. +# +# The scheduled run is KEPT rather than replaced, deliberately: dependency scanning is the one kind +# of check that finds something new WITHOUT the code changing. A CVE published against a version of +# `cryptography` that keel has been pinning, unmodified, for months is invisible to a per-merge +# trigger and obvious to a weekly one. Static analysis has no such property, but it is cheap to +# fold into the same pass. +# +# `pull_request` is still deliberately absent, and on a public repo that is now a SECURITY choice +# rather than a cost one: `pull_request` fires for forks, fork runs receive no repository secrets, +# so every fork PR would fail at the preflight below for a reason the contributor cannot fix. on: workflow_dispatch: + push: + branches: [main] schedule: # 06:00 UTC every Monday. A fixed weekday makes a newly-appeared finding easy to date, and # off-the-hour minutes avoid the top-of-hour scheduling queue on GitHub's shared runners. diff --git a/.github/workflows/migrate.yml b/.github/workflows/migrate.yml index d0e447a0..7a9e7063 100644 --- a/.github/workflows/migrate.yml +++ b/.github/workflows/migrate.yml @@ -1,16 +1,23 @@ name: Migrate database -# MANUAL ONLY. Schema migration for an EXISTING database -- never runs on push or merge. +# Migrating a REAL database is manual only. Merging to `main` runs the migration-chain SMOKE TEST, +# and structurally cannot do more than that -- see the safety property below. # # Migration is deliberately separate from seeding: `keel init` seeds the strategy (rules) library # on a FRESH deployment, while `keel migrate` only evolves an existing database's schema. Seeding # on migrate would resurrect rules that were deliberately deleted or refuted. # +# ⚠️ THE SAFETY PROPERTY THAT MAKES THE `push` TRIGGER SOUND, and it is a property of the event, not +# of anyone's discipline: `db_path` is a `workflow_dispatch` INPUT. A `push` event carries no +# inputs, so on a merge `${{ inputs.db_path }}` renders EMPTY and the job below takes its +# `migration_smoke.py` branch -- always. There is no value a merge can supply that would make it +# migrate a real database. Only a human dispatching it by hand can pass a `db_path`. +# Do not "helpfully" add a default target or read a path from a repo variable: either would remove +# this property and let a merge write to a live database. +# # DEFERRED SEAM: today `keel.db` is local, git-ignored and single-user, so CI has no database to # reach. Once the app is server-hosted, that deployment's database becomes the `db_path` target -# (via a self-hosted runner or a mounted volume) and the release workflow can call this job. Until -# then, dispatching this with no target runs a migration-integrity check instead of pretending to -# migrate something that is not there. +# (via a self-hosted runner or a mounted volume) and the release workflow can call this job. on: workflow_dispatch: inputs: @@ -19,6 +26,8 @@ on: required: false type: string default: "" + push: + branches: [main] permissions: contents: read