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