Files
stack/packages/mosaic/framework/tools/git/test-issue-create-body-safety.sh
T
fargo d789a43cae
ci/woodpecker/pr/ci Pipeline was canceled
test(git): hermetic fixtures for issue-create harnesses (#1282-#1287)
test-issue-create-body-safety.sh and test-issue-create-interactive-auth.sh
inherited the seat's real HOME and global git config. With the #1280 fix
activating identity mode BEFORE the tea path, a workstation-global
mosaic.gitIdentity resolved inside the fixture repo, and the wrapper's
API fallback posted to the LIVE forge with a real per-slot token — six
real issues (#1282-#1287, authored mos-dt-0, closed with provenance by
fred within the hour).

Neutralize the source the resolver actually reads, and prove it by making
the resolution fail. A control that does not make the thing fail has not
been shown to control it. The earlier attempted neutralization pinned
MOSAIC_CREDENTIALS_FILE to a fake — a real guard aimed at an adjacent
input: the identity arm reads the per-slot token file directly and never
consults credentials.json. Hence env -i with a fake HOME and
GIT_CONFIG_GLOBAL=/dev/null (severing the global identity) rather than
one more targeted variable, plus a curl tripwire stub in the body-safety
harness so ANY provider request is a loud test failure instead of a live
write.
2026-08-17 15:19:04 -05:00

126 lines
4.3 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Regression harness for issue-create.sh Markdown-body safety (#559).
#
# Guards against reintroduction of eval-based command construction. The wrapper
# builds its tea/gh invocation as an argv array, so a body containing command
# substitution ($(...)), backticks, quotes, and dollar signs MUST reach tea
# verbatim and MUST NOT be shell-evaluated. This test asserts both:
# 1. No command-substitution side effect (an injected `touch SENTINEL` never runs).
# 2. The --description value tea receives is byte-for-byte the original body.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WORK_DIR="${MOSAIC_TEST_WORK_DIR:-$PWD/.mosaic-test-work/issue-create-body-safety}"
REPO_DIR="$WORK_DIR/repo"
BIN_DIR="$WORK_DIR/bin"
SENTINEL="$WORK_DIR/INJECTION_SENTINEL"
BODY_FILE="$WORK_DIR/body.txt"
RECEIVED_FILE="$WORK_DIR/received-description.txt"
rm -rf "$WORK_DIR"
mkdir -p "$REPO_DIR" "$BIN_DIR"
git -C "$REPO_DIR" init -q
git -C "$REPO_DIR" remote add origin https://git.mosaicstack.dev/mosaicstack/stack.git
# Hostile Markdown body. The unquoted heredoc expands $SENTINEL (a real path we
# want embedded) but every shell metacharacter we care about is backslash-escaped
# so the TEST shell writes them literally into the file — the bytes the wrapper
# must then preserve.
cat > "$BODY_FILE" <<EOF
# Release notes
Inline code: \`rm -rf /\` must stay literal.
Command sub attempt: \$(touch $SENTINEL)
Backtick cmd attempt: \`touch $SENTINEL\`
Dollars: \$HOME \${PATH} \$5.00 and 100% done
Quotes: "double" and 'single' and \`mixed\`
Trailing pipe-ish: foo | bar && baz ; qux
EOF
BODY="$(cat "$BODY_FILE")"
# Mock tea: resolve a mosaicstack login, then capture the --description verbatim.
cat > "$BIN_DIR/tea" <<'SH'
#!/usr/bin/env bash
set -euo pipefail
if [[ "$*" == "login list --output json" ]]; then
cat <<'JSON'
[
{"name":"mosaicstack","url":"https://git.mosaicstack.dev","user":"ci-bot"}
]
JSON
exit 0
fi
if [[ "${1:-}" == "api" ]]; then
printf '%s\n' '{"login":"ci-bot"}'
exit 0
fi
if [[ "${1:-}" == "issue" && "${2:-}" == "create" ]]; then
desc=""
while [[ $# -gt 0 ]]; do
case "$1" in
--description) desc="$2"; shift 2 ;;
*) shift ;;
esac
done
printf '%s' "$desc" > "$MOSAIC_TEST_RECEIVED"
echo "#1 created"
exit 0
fi
exit 0
SH
chmod +x "$BIN_DIR/tea"
# TRIPWIRE provider stub: this harness tests argv construction, so ANY curl
# call is a failure of that contract (and, before this stub existed, a LIVE
# write — the #1282#1287 incident: the seat's real HOME leaked a global
# mosaic.gitIdentity, flipping the wrapper into identity mode whose real
# per-slot token created real issues on the forge). Fail loudly instead.
cat > "$BIN_DIR/curl" <<'SH'
#!/usr/bin/env bash
echo "FAIL: body-safety harness reached a provider request — this test must never curl" >&2
exit 99
SH
chmod +x "$BIN_DIR/curl"
# Hermetic invocation: fake HOME (no credentials, no tea config, no token
# slots) and GIT_CONFIG_GLOBAL severed — `git config --get mosaic.gitIdentity`
# otherwise resolves the WORKSTATION's global identity (mos-dt-0 on the seat
# that wrote this) and reroutes the wrapper into identity mode (#1280 family).
(
cd "$REPO_DIR"
env -i HOME="$WORK_DIR/home" PATH="$BIN_DIR:$PATH" \
GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null \
MOSAIC_TEST_RECEIVED="$RECEIVED_FILE" \
"$SCRIPT_DIR/issue-create.sh" -t "Body safety test" -b "$BODY"
) >/dev/null
mkdir -p "$WORK_DIR/home"
# 1. No command substitution executed anywhere in the pipeline.
if [[ -e "$SENTINEL" ]]; then
echo "FAIL: injected command substitution executed (sentinel file created): $SENTINEL" >&2
exit 1
fi
# 2. tea actually received the body (issue create path taken, not silently dropped).
if [[ ! -f "$RECEIVED_FILE" ]]; then
echo "FAIL: tea issue create was never invoked with a --description" >&2
exit 1
fi
# 3. The description tea received is byte-for-byte the original body.
if [[ "$(cat "$RECEIVED_FILE")" != "$BODY" ]]; then
echo "FAIL: body was not preserved verbatim through issue-create.sh" >&2
echo "--- expected ---" >&2; printf '%s\n' "$BODY" >&2
echo "--- received ---" >&2; cat "$RECEIVED_FILE" >&2
exit 1
fi
echo "issue-create.sh Markdown body-safety regression harness passed"