Skip to content

fix(release): the workflow has been invalid since #512 — secrets is not allowed in an if: - #558

Merged
eaitbrahim merged 1 commit into
mainfrom
fix-release-workflow
Aug 26, 2026
Merged

fix(release): the workflow has been invalid since #512 — secrets is not allowed in an if:#558
eaitbrahim merged 1 commit into
mainfrom
fix-release-workflow

Conversation

@eaitbrahim

Copy link
Copy Markdown
Contributor

Release has not been dispatchable since 2026-08-23, when #512 landed. Every push since has
recorded a failed run; the last twenty are all the same failure.

What was wrong

The four signing steps #512 added were gated on the secrets context in a step-level if::

if: runner.os == 'macOS' && secrets.MACOS_CERT_P12_BASE64 != '' && ...

secrets is not a context GitHub allows in if:. It rejects the file at parse time —
Unrecognized named-value: 'secrets' at lines 500, 598, 608 and 644 — so the entire workflow was
invalid, not just those steps.

Why it went unnoticed for three days

An unparseable workflow can't report its own name. GitHub recorded each failure under the file
path
(.github/workflows/release.yml) rather than name: Release, with zero jobs, on a
push event — for a workflow that is workflow_dispatch-only and should never run on push at
all. Three signals that each individually look like noise: a run nobody triggered, for a workflow
nobody recognises, failing before it did anything.

Then it was masked completely. An unrelated org billing lock began failing every workflow on
2026-08-26 with a three-second "account is locked" error, and this became one red X among many.

The fix, and the one it deliberately isn't

The usual remedy is a job-level env: block, since env is allowed in if:. Rejected here:
that would put every signing certificate and notarisation key into the environment of every step
in the job — uv sync, the PyInstaller build, all of it — which is precisely the exposure #512's own
"protected signing environment" exists to prevent.

So the secrets stay scoped to the single step that reads them, and what leaves that step is a
boolean. steps.signing.outputs.{macos,windows} is yes/no; nothing derived from a certificate
reaches an output (outputs are visible in the run's API payload); the four conditions read the
boolean. shell: bash on that step because it runs on both macOS and Windows runners and the
Windows default is pwsh.

Verification

GitHub's parser is the only authority here, so I let it judge:

  • Pushing this branch at 17:30:51Z produced no release.yml run at all.
  • Every failure on record predates it (17:19, 17:25, 17:28, 17:29 on main).
  • The comparison that makes this meaningful: the earlier push to chore-pwa-arch did produce
    one (09:22), so a feature-branch push does generate the synthetic failure while the file is
    invalid. It no longer does.

Locally: parses as YAML, no duplicate keys, desktop job structurally intact with the new
signing step id and all four conditions rewritten.

What this means for D5

The signing and notarisation work in #512 has never executed. The workflow could not be
dispatched, so no release has been cut through it since it landed. This restores the ability to
dispatch it; whether signing then works is unverified and needs a real run with the secrets
present on the signing environment.

🤖 Generated with Claude Code

https://claude.ai/code/session_01T6yA5khYnJ2qzheArRToQ2

…s not allowed in an `if:`

`Release` has not been dispatchable since 2026-08-23. Every push since has recorded a
failed run, and the last twenty are all the same failure.

── WHAT WAS WRONG ─────────────────────────────────────────────────────────────

The four signing steps #512 added were gated as:

    if: runner.os == 'macOS' && secrets.MACOS_CERT_P12_BASE64 != '' && ...

`secrets` is not a context GitHub allows in a step-level `if:`. It rejects the
file at PARSE time -- "Unrecognized named-value: 'secrets'", lines 500, 598, 608
and 644 -- so the whole workflow was invalid, not just those steps.

── WHY NOBODY NOTICED FOR THREE DAYS ──────────────────────────────────────────

An unparseable workflow cannot report its own name. GitHub recorded each failure
under the FILE PATH (`.github/workflows/release.yml`) rather than under
`name: Release`, with zero jobs, on a `push` event -- for a workflow that is
`workflow_dispatch`-only and should never run on push at all. Three signals that
each look like noise: a run nobody triggered, for a workflow nobody recognises,
that failed before doing anything.

It was then masked entirely: an unrelated org billing lock started failing every
workflow on 2026-08-26 with a three-second "account is locked" error, and this
became one red X among many.

── THE FIX, AND THE ONE IT IS NOT ─────────────────────────────────────────────

The usual remedy is a job-level `env:` block, because `env` IS allowed in `if:`.
Rejected here: it would put every signing certificate and notarisation key into
the environment of EVERY step in the job -- `uv sync`, the PyInstaller build, the
lot -- which is the exposure #512's own "protected signing environment" exists to
prevent.

So the secrets stay scoped to the single step that reads them, and what leaves
that step is a boolean. `steps.signing.outputs.{macos,windows}` is `yes`/`no`,
nothing derived from a certificate reaches an output, and the four conditions
read the boolean instead.

`shell: bash` on that step because it runs on both macOS and Windows runners and
the Windows default is pwsh.

── WHAT THIS MEANS FOR D5 ─────────────────────────────────────────────────────

The signing and notarisation work in #512 has never executed. The workflow could
not be dispatched, so no release has been cut through it since it landed. This
restores the ability to dispatch; whether signing then WORKS is unverified and
needs a real run with the secrets present.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T6yA5khYnJ2qzheArRToQ2
@eaitbrahim
eaitbrahim merged commit 1312df5 into main Aug 26, 2026
3 of 4 checks passed
@eaitbrahim
eaitbrahim deleted the fix-release-workflow branch August 26, 2026 18:06
eaitbrahim added a commit that referenced this pull request Aug 26, 2026
…, and one they missed (#559)

`main` is red because I merged #558 without running the suite. Three tests in
`test_desktop_packaging.py` assert the signing gates by looking for
`secrets.X != ''` inside each step's `if:` -- the exact expression #558 had to
remove, because GitHub rejects `secrets` in an `if:` at parse time.

The GUARANTEE is unchanged and is still pinned: all five Apple credentials or
none, both Windows credentials or none, and each skip notice firing on the exact
complement of its sign step. What moved is where that is decided -- from four
`if:` conditions into one `signing` step whose outputs the conditions read -- so
the assertions move with it.

── AND A PIN FOR THE FAILURE THESE TESTS COULD NOT SEE ────────────────────────

The old tests asserted that a string appeared in a condition. That says nothing
about whether GitHub can PARSE the file, which is why they were green for the
three days the workflow was undispatchable. Two new pins close that:

  * no `secrets` in any `if:`, in any job or step -- the thing that made the
    whole workflow invalid;
  * no signing credential in a job-level `env:` -- the obvious fix for the first
    one, and the wrong one, because it exposes every certificate to `uv sync`,
    the PyInstaller build and every other step in the job.

All three are mutation-checked: restoring a secret to an `if:` fails two tests,
dropping one credential from the gate fails a third, and hoisting a secret to
job-level env fails the fourth.

── THE PROCESS FAILURE, RECORDED ──────────────────────────────────────────────

I validated #558's YAML, checked its structure, and let GitHub's own parser
confirm the fix -- and did not run `pytest`, because it was "only a workflow
file". This repository pins its workflows WITH tests; that is the whole reason
those three existed. The suite is not optional on a workflow change here.


Claude-Session: https://claude.ai/code/session_01T6yA5khYnJ2qzheArRToQ2

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant