From 08a820adcf94dce01bbce82e5b076c7e9481ada9 Mon Sep 17 00:00:00 2001 From: Jaap-Jan de Wit | DodoTech Date: Sat, 1 Aug 2026 17:01:06 +0200 Subject: [PATCH] Stop the login step interpolating a comment I wrote in it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The secrets were never the problem. The log shows both arriving masked, which is what a runner does with a value it holds — so the repository secrets were configured correctly the whole time, and the guidance about Actions Variables was wrong. What broke was the guard added to diagnose them. Its comment contained an expression delimiter written out literally to explain what an unset secret renders as, and a shell comment is not a comment yet at that point: the runner substitutes the whole script before any shell sees it, so it tried to evaluate an empty expression and failed the step with a parse error carrying no line number. The step never ran, and push then reached the registry with nothing to authenticate as — "no basic auth credentials", which looks precisely like the missing-secret problem the guard was added to rule out. The comment now describes the delimiter instead of containing one, and warns the next person, since the failure is invisible to review and to every local check: the file is valid YAML and the script is valid shell. Verified with a scan for empty expressions across every run block in the file — one before, none after — and by running the step's script with credentials set, which passes the guard and gets a 401 from the real registry. That is the right answer for an invented password, and it means the endpoint is reachable and the path through this step is sound. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a39c4c2..c9596ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -488,9 +488,16 @@ jobs: set -eu # Checked before use, because an unset secret is not an error anywhere upstream of - # here: ${{ }} renders a missing value as the empty string, so docker is handed - # --username "" and answers with something about credentials, which sends people - # to the registry to debug a value that never left the settings page. + # here: an expression that resolves to nothing renders as the empty string, so + # docker is handed --username "" and answers with something about credentials, + # which sends people to the registry to debug a value that never left the + # settings page. + # + # Note for anyone editing this comment: an expression delimiter written literally + # here is interpolated even though this is a shell comment. The runner substitutes + # the whole script before any shell sees it, so an empty one fails the step with a + # parse error and no line number — which is how this very block broke the release + # it was added to protect. # # Reported by length, and never by value. Gitea masks known secret values in logs, # but a mask is only as good as the runner's bookkeeping and a length answers the