Workers are currently hitting: Remote repository required: Specify ID via --repo or execute from a local git repo.
This rollup is intended to restore reliable wrapper behavior so BMA orchestration can resume without local-only patch drift.
## Summary
Rolls up the pending Mosaic wrapper fixes that are currently split across open PRs #513, #518, #521, #522, and #523.
Includes:
- pr-ci-wait stdin-collision fix.
- Gitea PR metadata and merge preflight hardening.
- Gitea pr-merge empty-UID fallback and unsafe PR-number rejection.
- Woodpecker legacy mosaic credentials and pagination fixes.
- Explicit Gitea --repo/--login args for tea commands.
- pr-create/issue-create eval removal for markdown/body safety.
- CI Postgres service collision fix from the Woodpecker wrapper branch.
## Verification
- mosaic update checked first: @mosaicstack/mosaic remains 0.0.30/current, so source-side PR is required.
- bash -n on changed shell wrappers.
- test-pr-metadata-gitea.sh: pass.
- test-pr-merge-gitea-empty-uid.sh: pass.
- pr-list.sh --repo mosaicstack/stack smoke: pass.
- issue-list.sh --repo mosaicstack/stack smoke: pass.
- Independent shell-safety review found one blocker: malformed Gitea merge API JSON payload. Fixed and regression test now validates POST body.
- Pre-push hook passed: typecheck, lint, format:check.
## Operational Context
Workers are currently hitting: Remote repository required: Specify ID via --repo or execute from a local git repo.
This rollup is intended to restore reliable wrapper behavior so BMA orchestration can resume without local-only patch drift.
When the wrapper invoked `python3 - <<'PY' ... PY` inside a function that
was being fed JSON via a pipe (`printf '%s' "$STATUS_JSON" |
extract_state_from_status_json`), the heredoc bound stdin to the Python
program text. The `-` argument tells Python to read its program from
stdin, so the program consumed stdin before json.load(sys.stdin) ran —
which then saw EOF and bailed to the "unknown" branch every time.
Result: pr-ci-wait.sh hung the full timeout (default 30 min) even when
the upstream Gitea status was already 'success', because every poll
returned 'unknown' and the loop kept retrying.
Fix: capture the piped JSON into a local variable with `payload=$(cat)`
BEFORE invoking python, then pass it via env (PR_CI_STATUS_JSON). The
heredoc still drives the Python program, but the payload is now read
from the environment instead of a stdin that's already been consumed.
Same fix applied to print_status_summary() which has the identical
pattern.
Verified locally:
$ echo '{"state":"success"}' | extract_state_from_status_json → success
$ echo '' | extract_state_from_status_json → unknown
$ echo '{"state":null,"statuses":[{"state":"success"}]}' | … → success
$ echo '{"state":"pending"}' | extract_state_from_status_json → pending
$ echo '{"state":"failure"}' | extract_state_from_status_json → failure
Reported in screenshot from operator session 2026-05-13 — wrapper was
stuck waiting on a PR whose underlying Gitea status was already
success. Operator workaround was to bypass the wrapper and use the raw
Gitea API.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
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
Rolls up the pending Mosaic wrapper fixes that are currently split across open PRs #513, #518, #521, #522, and #523.
Includes:
Verification
Operational Context
Workers are currently hitting: Remote repository required: Specify ID via --repo or execute from a local git repo.
This rollup is intended to restore reliable wrapper behavior so BMA orchestration can resume without local-only patch drift.
When the wrapper invoked `python3 - <<'PY' ... PY` inside a function that was being fed JSON via a pipe (`printf '%s' "$STATUS_JSON" | extract_state_from_status_json`), the heredoc bound stdin to the Python program text. The `-` argument tells Python to read its program from stdin, so the program consumed stdin before json.load(sys.stdin) ran — which then saw EOF and bailed to the "unknown" branch every time. Result: pr-ci-wait.sh hung the full timeout (default 30 min) even when the upstream Gitea status was already 'success', because every poll returned 'unknown' and the loop kept retrying. Fix: capture the piped JSON into a local variable with `payload=$(cat)` BEFORE invoking python, then pass it via env (PR_CI_STATUS_JSON). The heredoc still drives the Python program, but the payload is now read from the environment instead of a stdin that's already been consumed. Same fix applied to print_status_summary() which has the identical pattern. Verified locally: $ echo '{"state":"success"}' | extract_state_from_status_json → success $ echo '' | extract_state_from_status_json → unknown $ echo '{"state":null,"statuses":[{"state":"success"}]}' | … → success $ echo '{"state":"pending"}' | extract_state_from_status_json → pending $ echo '{"state":"failure"}' | extract_state_from_status_json → failure Reported in screenshot from operator session 2026-05-13 — wrapper was stuck waiting on a PR whose underlying Gitea status was already success. Operator workaround was to bypass the wrapper and use the raw Gitea API. Co-Authored-By: Claude Opus 4.7 <[email protected]>