#559 — Markdown body safety / eval removal:
- Add test-issue-create-body-safety.sh: feeds a hostile Markdown body
($(...), backticks, quotes, $vars, pipes) through issue-create.sh and
asserts no command substitution runs and the body reaches tea verbatim.
- Convert issue-comment.sh from unquoted $(get_gitea_repo_args) word-splitting
to an argv array with an explicit loud login-resolution error.
- Confirmed: zero eval usages remain across tools/git/*.sh; the other
body-carrying wrappers (issue-create, pr-create, issue-edit, issue-assign)
already use argv arrays.
#560 — host-derived Gitea login + loud failure:
- detect-platform.sh: add print_gitea_login_diagnostic and emit it on the
get_gitea_login_for_host failure path (stderr only) — names the unresolved
host, lists available tea logins, and gives the GITEA_LOGIN override +
tea-login-add fix. Replaces the previous silent failure.
- Extend test-gitea-login-resolution.sh: assert the diagnostic fires and lists
logins, login is derived from origin host for both mosaicstack and usc (scoped
second tea mock), and a valid GITEA_LOGIN override is honored.
Also gitignore the .mosaic-test-work/ shell-harness scratch dir.
Scope: wrapper surface only. All wrapper test harnesses pass locally.
F-06 follow-up per Mos ruling. The no-CI fast-exit was a pure empty-poll streak
(NO_CI_MAX×interval ≈ 45s), so a slow-to-register pipeline (webhook/queue lag)
looked like 'no CI' and could false-green a merge gate before the pipeline existed.
Two-tier no-CI determination:
- PRIMARY: probe the repo's DEFAULT BRANCH commit status once at startup. If it
has CI history, the repo runs CI → an empty status on the PR head means the
pipeline has not REGISTERED yet → never fast-green; poll until it registers or
timeout (both safe). Closes the webhook-lag false-green.
- SECONDARY: the empty-poll streak fast-exit now applies ONLY to genuinely CI-less
repos (default branch also has no CI history). Preserves the original no-CI win.
- Probe failure → conservative REPO_HAS_CI=1 (assume CI; wait-then-timeout beats
false-green). All early returns are explicit 'return 0' + guarded call so the
probe can never abort under set -e.
Verified: bash -n + shellcheck clean; behavioral harness covers established-repo
(stays 1), CI-less (→0), empty-branch/probe-fail (conservative 1), and the
no-status gate (has-CI never fast-greens, CI-less fast-exits).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kt2D8TsnDwhtzEAPijsNmR
F-03: validate TLS by default. New _mosaic_tls_opt helper in _lib/credentials.sh
returns -k only for private-network IP literals (trusted LAN) or an explicit
MOSAIC_INSECURE_TLS opt-in; generic mosaic_http/_post/_patch helpers now use
`curl -sS $_tls` instead of `curl -sk`. Woodpecker scripts (_lib.sh,
pipeline-status/list/trigger.sh) talk only to the two public/valid CI hosts, so
`-sk` is changed to `-sS` (straight -k removal, no helper).
F-02: credentials.sh resolves MOSAIC_CREDENTIALS_FILE via a fallback chain —
env first, then ~/.config/mosaic/credentials.json, then the legacy
~/src/jarvis-brain/credentials.json retained as final fallback so the running
fleet keeps working.
F-06: pr-ci-wait.sh distinguishes a genuine no-CI condition (empty state AND no
statuses) as a new `no-status` state and fast-exits 0 after 3 consecutive empty
polls with a clear "no CI configured" message. Repos that DO have pipelines are
unaffected — any pipeline signal resets the streak and pending still waits.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kt2D8TsnDwhtzEAPijsNmR