pr-metadata.sh: anonymous fallback lacks the ^2 check, so a successful 200 is reported as 'unknown API error' at rc=1 #1015
Open
opened 2026-07-31 12:34:45 +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#1015
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
pr-metadata.sh's Gitea path has three request arms: token, basic-auth, and an anonymous fallback. The first two check[[ "$raw_code" =~ ^2 ]]and return the body on success. The third does not. It issues the request, assignshttp_code, and falls straight through to the error reporter andreturn 1.The result: when no credential is available, a successful anonymous read of a public repo is reported as a failure, with a self-contradictory message.
Exit status 1, zero bytes on stdout. The metadata was fetched and is then discarded.
unknown API erroris not a message the server sent — it is manufactured by the reporter at:101, which looks formessageorerrorkeys. A successful pull-request payload has neither, so the success case is guaranteed to produce the most uninformative text the reporter can emit. The better the response, the worse the diagnostic.Mechanism
pr-metadata.sh:69-92:The omission is mechanically visible as a count imbalance, which makes it greppable across the family:
raw_code=$(curl=~ ^2guardspr-merge.shpr-metadata.shpr-merge.shis not affected: it has only the token and basic-auth arms, both guarded, and no anonymous arm at all — which is right for a write operation.pr-metadata.shis the only site.Measured — controlled pair, identical response, opposite verdicts
Hermetic harness: fresh repo with
origin = https://git.mosaicstack.dev/mosaicstack/stack.git, sandboxedHOME, repo-localmosaic.gitIdentitypinned empty (per #1007), and a stubcurlonPATHthat writes a valid pull-request JSON body and prints200. The only difference between the two arms is whether a credential is resolvable.A — no credential (anonymous arm):
B — credential present (token arm), same stub, byte-identical 200 response:
Same HTTP status, same bytes, same endpoint. The verdict is decided entirely by which branch handled the response — i.e. by the presence of the
^2check, not by anything about the request or the reply.Why the existing suite cannot catch it
test-pr-metadata-gitea.shhas two live-curl cases,run_curl_success_case(:182) andrun_curl_early_exit_cleanup_case(:223). Both setGITEA_TOKEN/GITEA_URL(and, after the #1007 fix,MOSAIC_CREDENTIALS_FILE), so both take the token arm. No case runs with no credential at all.The one arm with no guard is the one arm with no test. The suite would stay green through this defect indefinitely — and per #1007 it is not run by CI in the first place (
test:framework-shellenumerates a list that excludes it).Impact
Anonymous read of a public Gitea repo can never succeed through this wrapper. The blast radius is bounded today only because every seat that runs it happens to have a credential — the failure is invisible exactly until someone runs it without one, which is the case a fallback exists to serve. A fallback arm that cannot succeed is not a fallback; it is a slower path to the same error.
Note also the pairing with #1007: on a seat where the identity pin leaks and
get_gitea_tokenreturns nothing usable, control reaches these lower arms more often than the author expected. Two independently tolerable defects composing again.Suggested fix (not implemented — filing only)
if [[ "$raw_code" =~ ^2 ]]; then cat "$body_file"; return 0; fi. One line, symmetric with:72and:82.^2test out of the three arms into one place after the request loop, so a future fourth arm cannot repeat this. An invariant enforced once cannot be forgotten once.:94-105should not be reachable with a 2xx code. If it ever is, it should say so plainly rather than inventingunknown API error— a diagnostic that reports a success as an unknown error trains readers to distrust the diagnostic instead of the code.Independent confirmation — by a different actor and a different method
Confirmed at
main(826a8b3b) from a second seat (pepper, sb-it-1-dt) by static read, independently of and concurrently with the dynamic harness above: the:89-92arm setshttp_codeand falls into the error renderer with no^2check and nocat "$body_file", while both authenticated arms directly above it have both. Two different methods — one reading the code, one exercising it — reached the same conclusion without sharing intermediate results, and the static read named the asymmetry as the fix shape before seeing the measurement.Stated precisely, because the distinction matters and this repo's tooling cannot record it:
pepperandmos-dtare different actors but share a Gitea login, so the corroboration is real and is not recordable as distinct-login independence. Read this as two instruments agreeing, not as a review.Provenance
Found while verifying #1007 (the credential-leak hermeticity work) in
pr-metadata.sh's test suite; that suite's own inertGITEA_TOKEN/GITEA_URLfixture is what drew attention to how the arms are selected. Filed separately from #1007 because it is an independent defect in the wrapper, not in the suites — carried forward as a promised filing rather than folded into the hermeticity branch, which changes no wrapper.Related: #1007 (suite hermeticity + the wrapper half), #1014 (the other fail-closed-after-the-fact reporting defect in this family).
— mos-dt