ci-queue-wait.sh exits 0 when it could not measure CI state — the mandatory gate fails open #995
Open
opened 2026-07-31 09:20:12 +00:00 by mos-dt-0
·
0 comments
No Branch/Tag Specified
main
remediation/state
feat/rm-02-gate-registry
fix/rm-01-reproducible-checkout
remediation/mission-setup
fix/hygiene-inert-format-gate
fix/1019-queue-guard-stdin
feat/mos-ste-writing-standard
fix/1007-suite-hermeticity
fix/991-comment-url-scheme-normalise
feat/push-guard-null-case-verification
mos-comms-live
docs/heartbeat-framework-layering-ms-lead
feat/869-c4-version-coupling
feat/869-c2-install-ordering-guard
feat/869-c5-doctor-activation-check
feat/per-agent-gitea-identity
fix/875-belongs-case-insensitive-slug
fix/ci-queue-wait-404-branch-absent
feat/869-c1-activation-probe
feat/869-c3-broker-supervisor
fix/865-tea-cli-comment-invocation
feat/glpi-skills
fix/860-deflake-mutator-lease-gate
fix/850-detect-platform-port-normalization
fix/856-worktree-deps-preflight
fix/835-pr-review-approve-reject-comment-flag
fix/848-truthful-evidence
fix/812-pr-review-comment
fix/849-recovery-runtime-fixture-race
docs/758-ledger-m5-001-sync
feat/834-tc-server-side-doc
feat/833-constrained-recovery-command
feat/827-gate0-probe
governance/gate0-probe3-amendment
fix/795-codex-pr-diff
fix/795-ci-base-jq
fix/795-ci-base-git
feat/791-pr3-fleet-regen
feat/791-pr2-snapshot-restore
fix/807-glpi-206
fix/808-agent-send-false-sender
feat/791-upgrade-config-protection
feat/790-mosaic-yolo-claudex-pr2
feat/790-mosaic-yolo-claudex
feat/758-v1-v2-migrator
fix/766-exact-fleet-comms
test/758-reconciler-lifecycle-gates
docs/771-kbn101-db-role-split
test/758-example-profile-dispositions
feat/758-shared-role-resolution
feat/mos-logical-identity-fencing
feat/769-kbn100-unified-schema
docs/753-kbn010-threat-gate
feat/758-roster-v2-compiler
feat/756-official-discord-plugin
docs/758-fleet-config-management
fix/mos-option2-qualification-format
docs/issue-758-m0
docs/mos-option2-qualification
mos-comms
feat/tess-interaction-agent
fix/tess-docs-format
next
draft/mosaic-platform-prd
fix/installer-provider-gate-and-local-gateway-redis
release/mosaic-cli-0.0.37
feat/framework-constitution-alpha
fix/git-wrapper-repo-detection
fix/woodpecker-wrapper-legacy-mosaic
fix/t-a292e96f-gitea-pr-metadata
fix/gitea-pr-metadata-login-t-a292e96f
fix/t_a292e96f-pr-metadata-gitea
fix/t_3a368a52-gitea-usc-login
fix/bootstrap-hotfix
fix/populate-known-packages-list
fix/idempotent-init
v0.0.39-alpha
mosaic-v0.0.31
fed-v0.2.0-m2
fed-v0.1.0-m1
mosaic-v0.0.29
mosaic-v0.0.28
mosaic-v0.0.27
mosaic-v0.0.26
mosaic-v0.0.25
mosaic-v0.0.24
v0.2.0
v0.1.0
v0.0.8
v0.0.7
v0.0.6
v0.0.5
v0.0.4
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: mosaicstack/stack#995
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
ci-queue-wait.shis a mandatory pre-push/pre-merge gate. On every path where it cannot determine the CI state — including the path where the measurement did not happen at all — it exits 0 and the caller proceeds. The failure mode and the safe state produce the same output, so a guard that measured nothing is indistinguishable from a guard that measured "clear."Code-evident, independent of any particular run
get_state_from_status_jsonemitsunknownfrom two unrelated causes:Both land in the same dispatch arm:
Three problems, in increasing order of how much they matter:
unknownis not a state, it is two states. "The API call failed" and "CI reported something I don't recognise" are collapsed into one token, so neither the caller nor the log can tell which happened.gitea_get_commit_status_jsonusescurl -fsSL, which exits non-zero and emits nothing on any HTTP error. An expired token, a 403 from an identity without access, a DNS failure, or a proxy error therefore all produce empty stdin → parse failure →unknown→ exit 0. The guard is at its most permissive exactly when credentials or connectivity are broken.What I observed, and what I could not establish
Running
--purpose pushagainstmainat4fb44f6345aff14a718ae7b8cc322088af3bf900, immediately before a push:Exit 0, and the push proceeded. The commit's actual state at that sha is
successwith 2 contexts — I verified afterwards through three separate credentials (including the guard's own resolved token: HTTP 200,curlexit 0, 4775 bytes, classifier →success).I could not reproduce the
unknownand I am not going to guess at its cause. It did not recur, and the log line preserves nothing that would let anyone reconstruct it — which is itself part of the report: the guard discards the evidence that would explain its own indeterminate verdict. I checked and discarded one hypothesis (a same-name/different-parameter-order collision between this file'sgitea_get_commit_status_jsonand the one inpr-ci-wait.sh) — the two files never load each other, so it is not reachable, and I mention it only so nobody re-derives it as the answer.The defect stands without the reproduction. Whatever produced
unknownthat once, the code's response to it was to proceed, and that is visible in the source.Suggested fix
fetch-failedandindeterminateare different states and deserve different names.fetch-failed. A guard that cannot read CI state has not cleared anything. Non-zero, with the HTTP status and the endpoint in the message.unknown → exit 0for the genuinely-indeterminate case too, or at minimum require an explicit--allow-indeterminateso proceeding is a caller's decision rather than a default.*)comment: it currently describes behaviour the code does not have.Acceptance
Force each cause separately — a broken token, an unreachable host, and a genuinely unrecognised status value — and confirm from the caller's side that the fetch failures are distinguishable from a clear queue by exit code and message alone. Today all three are
exit 0withstate=unknown.Related, separable — token in
argvBoth status helpers pass the credential as a command-line argument:
Anything that can read
/procon the host — any process under the same uid, and on this host several agents share one — can recover the token frompsfor the lifetime of the call.curl -K <file>with a mode-600 config keeps it out ofargventirely. Filed here because it is the same two functions; happy to split it into its own issue if that is preferred, since it is a distinct defect with a distinct fix.