Summary
.github/workflows/propagate-hooks.yml cannot propagate anything. Its
repository-discovery step calls gh api with no token in scope, so every
call fails, every repo is classified as having no .githooks, and the job then
crashes on the empty result. The hook-propagation path across the estate is
therefore dormant — and it fails in a way that looks like "nothing to do"
rather than like a break.
Exposed by the merge of #804, which is the first commit in a long time to touch
.githooks/** and so the first to trigger this workflow's path filter. The
defect is not caused by #804.
Evidence
Run 34952192815,
job Identify Repositories to Update, on 4c9225a1:
🔍 Filtering repos with .githooks directory...
✗ hyperpolymath/standards skipped (no .githooks)
##[error]Unable to process file command 'output' successfully.
##[error]Invalid format ' ""'
hyperpolymath/standards is the repo that owns .githooks/ — it has 14 of
them. A classifier that answers "no" for the canonical repo is answering a
different question than it appears to.
Root cause — two defects, one visible
-
No credential. The step runs
gh api /repos/$ORG/$REPO_NAME/contents/.githooks | jq -e '. | type == "array"'
with no env: GH_TOKEN and no env: GITHUB_TOKEN. The only token in the
file is on line 155, an input to a different step. Tokenless gh api
fails; 2>/dev/null hides the error; jq -e on the error object returns
false; the repo is silently classified as hookless. Every repo takes
this branch, so REPOS_WITH_HOOKS is always empty.
-
Empty bash array through printf. Line 106:
REPOS_JSON=$(printf '%s\n' "${REPOS_WITH_HOOKS[@]}" | jq -R . | jq -s .)
With an empty array this still prints one empty line, so REPOS_JSON
becomes [""], not []. Writing that multi-line value to $GITHUB_OUTPUT
without a heredoc delimiter produces Invalid format ' ""'.
Defect 2 is the only reason this was ever visible. Had the array been handled
correctly, the job would have gone green while propagating to zero repos —
a fake green, and this would still be undiagnosed.
Why it matters now
#804 added .githooks/validate-actions-lock.sh, the SHA-exact
uses ⊆ actions.lock validator. Estate repos will not receive it until this
workflow works. More generally: no .githooks change has propagated for as
long as this has been broken, so estate hook state has been drifting silently.
Acceptance criteria
Related
The same shape as the recurring "a guard asks a different question than its
consumer" trap: here the guard asks "did an unauthenticated API call return a
JSON array?" while the consumer needs "does this repo have .githooks?".
Summary
.github/workflows/propagate-hooks.ymlcannot propagate anything. Itsrepository-discovery step calls
gh apiwith no token in scope, so everycall fails, every repo is classified as having no
.githooks, and the job thencrashes on the empty result. The hook-propagation path across the estate is
therefore dormant — and it fails in a way that looks like "nothing to do"
rather than like a break.
Exposed by the merge of #804, which is the first commit in a long time to touch
.githooks/**and so the first to trigger this workflow's path filter. Thedefect is not caused by #804.
Evidence
Run 34952192815,
job Identify Repositories to Update, on
4c9225a1:hyperpolymath/standardsis the repo that owns.githooks/— it has 14 ofthem. A classifier that answers "no" for the canonical repo is answering a
different question than it appears to.
Root cause — two defects, one visible
No credential. The step runs
gh api /repos/$ORG/$REPO_NAME/contents/.githooks | jq -e '. | type == "array"'with no
env: GH_TOKENand noenv: GITHUB_TOKEN. The only token in thefile is on line 155, an input to a different step. Tokenless
gh apifails;
2>/dev/nullhides the error;jq -eon the error object returnsfalse; the repo is silently classified as hookless. Every repo takes
this branch, so
REPOS_WITH_HOOKSis always empty.Empty bash array through
printf. Line 106:REPOS_JSON=$(printf '%s\n' "${REPOS_WITH_HOOKS[@]}" | jq -R . | jq -s .)With an empty array this still prints one empty line, so
REPOS_JSONbecomes
[""], not[]. Writing that multi-line value to$GITHUB_OUTPUTwithout a heredoc delimiter produces
Invalid format ' ""'.Defect 2 is the only reason this was ever visible. Had the array been handled
correctly, the job would have gone green while propagating to zero repos —
a fake green, and this would still be undiagnosed.
Why it matters now
#804 added
.githooks/validate-actions-lock.sh, the SHA-exactuses ⊆ actions.lockvalidator. Estate repos will not receive it until thisworkflow works. More generally: no
.githookschange has propagated for aslong as this has been broken, so estate hook state has been drifting silently.
Acceptance criteria
env: GH_TOKEN: ${{ secrets.… }}witha credential that can read
contentson target repos, and the token'sscope is stated in a comment.
gh apicall causes the step to fail, notto classify the repo as hookless. Distinguish "API said no" from "API did
not answer" — drop the blanket
2>/dev/nulland check the exit status.hyperpolymath/standardsitself is classified as having.githooks.Use it as a permanent positive control in the job: if the canonical repo
is not in the list, abort.
[]and the job reports "0 repos" explicitlyrather than crashing or silently succeeding. Guard with
${arr[@]+"${arr[@]}"}or build the JSON withjq -n.$GITHUB_OUTPUTwrites use the heredoc delimiter form..githookschange propagatesvalidate-actions-lock.sh, and the summary names a non-zero repo count.Related
The same shape as the recurring "a guard asks a different question than its
consumer" trap: here the guard asks "did an unauthenticated API call return a
JSON array?" while the consumer needs "does this repo have
.githooks?".