framework tools/git: issue-comment R1/R4 usage-error contract (sync from brain) #1462
@@ -1,6 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# issue-comment.sh - Add a comment to an issue on GitHub or Gitea
|
# issue-comment.sh - Add a comment to an issue on GitHub or Gitea
|
||||||
# Usage: issue-comment.sh -i <issue_number> -c <comment> [--login <name>]
|
# Usage: issue-comment.sh -i <issue_number> -b <comment> [--login <name>]
|
||||||
|
# (-c/--comment is a backward-compatible alias for -b/--body; R1, 2026-08-28)
|
||||||
#
|
#
|
||||||
# tea v0.11.1 defines no `comment` subcommand under `tea issue` (or `tea pr`);
|
# tea v0.11.1 defines no `comment` subcommand under `tea issue` (or `tea pr`);
|
||||||
# the non-existent `tea issue comment ...` form does not error — tea silently
|
# the non-existent `tea issue comment ...` form does not error — tea silently
|
||||||
@@ -32,45 +33,61 @@ ISSUE_NUMBER=""
|
|||||||
COMMENT=""
|
COMMENT=""
|
||||||
LOGIN_OVERRIDE=""
|
LOGIN_OVERRIDE=""
|
||||||
|
|
||||||
|
# Usage-error contract (R4, 2026-08-28): usage errors print to STDERR and exit 2,
|
||||||
|
# distinct from provider, credential, and verification failures (exit 1), so a
|
||||||
|
# caller or stop gate can tell an invocation defect from a delivery blocker
|
||||||
|
# (CONSTITUTION gate 8 as amended; E2E-DELIVERY).
|
||||||
|
usage_error() {
|
||||||
|
echo "Error: $*" >&2
|
||||||
|
echo "Usage: issue-comment.sh -i <issue_number> -b <comment> [--login <name>] (see --help)" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case $1 in
|
case $1 in
|
||||||
-i|--issue)
|
-i|--issue)
|
||||||
|
[[ $# -ge 2 ]] || usage_error "option $1 requires a value"
|
||||||
ISSUE_NUMBER="$2"
|
ISSUE_NUMBER="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
-c|--comment)
|
-b|--body|-c|--comment)
|
||||||
|
# R1 (2026-08-28): --body is the canonical flag, matching
|
||||||
|
# issue-create/issue-edit/pr-create/pr-edit; -c/--comment stays a
|
||||||
|
# backward-compatible alias.
|
||||||
|
[[ $# -ge 2 ]] || usage_error "option $1 requires a value"
|
||||||
COMMENT="$2"
|
COMMENT="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
-l|--login)
|
-l|--login)
|
||||||
|
[[ $# -ge 2 ]] || usage_error "option $1 requires a value"
|
||||||
LOGIN_OVERRIDE="$2"
|
LOGIN_OVERRIDE="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
echo "Usage: issue-comment.sh -i <issue_number> -c <comment> [--login <name>]"
|
echo "Usage: issue-comment.sh -i <issue_number> -b <comment> [--login <name>]"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Options:"
|
echo "Options:"
|
||||||
echo " -i, --issue Issue number (required)"
|
echo " -i, --issue Issue number (required)"
|
||||||
echo " -c, --comment Comment text (required)"
|
echo " -b, --body Comment text (required; canonical)"
|
||||||
|
echo " -c, --comment Alias for --body"
|
||||||
echo " -l, --login Override the detected Gitea tea login for this call"
|
echo " -l, --login Override the detected Gitea tea login for this call"
|
||||||
echo " -h, --help Show this help"
|
echo " -h, --help Show this help"
|
||||||
|
echo ""
|
||||||
|
echo "Exit codes: 0 success; 2 usage error (stderr); 1 provider/credential/verification failure."
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown option: $1"
|
usage_error "unknown option: $1"
|
||||||
exit 1
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ -z "$ISSUE_NUMBER" ]]; then
|
if [[ -z "$ISSUE_NUMBER" ]]; then
|
||||||
echo "Error: Issue number is required (-i)"
|
usage_error "issue number is required (-i/--issue)"
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "$COMMENT" ]]; then
|
if [[ -z "$COMMENT" ]]; then
|
||||||
echo "Error: Comment is required (-c)"
|
usage_error "comment is required (-b/--body, or the -c/--comment alias)"
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
detect_platform >/dev/null
|
detect_platform >/dev/null
|
||||||
@@ -340,7 +357,15 @@ PY
|
|||||||
}
|
}
|
||||||
|
|
||||||
if [[ "$PLATFORM" == "github" ]]; then
|
if [[ "$PLATFORM" == "github" ]]; then
|
||||||
gh issue comment "$ISSUE_NUMBER" --body "$COMMENT"
|
# R4 exit-code contract: normalize provider failures to exit 1. gh's own
|
||||||
|
# usage errors exit 2, which would collide with this wrapper's reserved
|
||||||
|
# usage-error status if propagated raw (codex review of 08a00149).
|
||||||
|
gh_rc=0
|
||||||
|
gh issue comment "$ISSUE_NUMBER" --body "$COMMENT" || gh_rc=$?
|
||||||
|
if [[ "$gh_rc" -ne 0 ]]; then
|
||||||
|
echo "Error: GitHub comment write failed (gh exit $gh_rc; provider/credential failure — usage errors are exit 2)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
echo "Added comment to GitHub issue #$ISSUE_NUMBER"
|
echo "Added comment to GitHub issue #$ISSUE_NUMBER"
|
||||||
elif [[ "$PLATFORM" == "gitea" ]]; then
|
elif [[ "$PLATFORM" == "gitea" ]]; then
|
||||||
# A --login override selects a NAMED tea credential and is the only way to
|
# A --login override selects a NAMED tea credential and is the only way to
|
||||||
|
|||||||
@@ -42,6 +42,8 @@
|
|||||||
# 10. leaves NO temp files behind (POST/GET bodies + metadata) on either the
|
# 10. leaves NO temp files behind (POST/GET bodies + metadata) on either the
|
||||||
# success or the failure path — nested function-scoped RETURN traps do not
|
# success or the failure path — nested function-scoped RETURN traps do not
|
||||||
# clobber each other and every scratch file is removed on all exit paths.
|
# clobber each other and every scratch file is removed on all exit paths.
|
||||||
|
# 11. accepts the canonical -b/--body flag exactly like the -c/--comment alias
|
||||||
|
# (R1, 2026-08-28): a full verified write via -b alone.
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -409,11 +411,28 @@ run_comment() {
|
|||||||
seed_state "$mode"
|
seed_state "$mode"
|
||||||
(
|
(
|
||||||
cd "$REPO_DIR"
|
cd "$REPO_DIR"
|
||||||
|
# Provisioned seats export MOSAIC_GIT_IDENTITY and MOSAIC_BRAIN_HOME
|
||||||
|
# seat-wide (launcher), and both escape this harness's sandboxed HOME:
|
||||||
|
# detect-platform.sh consults MOSAIC_GIT_IDENTITY BEFORE the repo-local
|
||||||
|
# mosaic.gitIdentity pin, and resolves the brain home (whose
|
||||||
|
# fleet/agents presence arms the no-identity fail-loud branch) from
|
||||||
|
# MOSAIC_BRAIN_HOME before $HOME. Without these explicit empties the
|
||||||
|
# wrapper either resolves the REAL seat-slot token (stub curl rejects
|
||||||
|
# it: the documented HTTP 401) or fails loud before any request.
|
||||||
|
# Set-but-empty reads as unset to detect-platform's "${VAR:-}" forms.
|
||||||
|
# NOTE: keep this comment block ABOVE the assignment chain — a comment
|
||||||
|
# inside a backslash-continued prefix chain terminates the command and
|
||||||
|
# silently demotes every earlier assignment to an unexported subshell
|
||||||
|
# assignment (measured 2026-08-28: the wrapper then ran without
|
||||||
|
# MOSAIC_CREDENTIALS_FILE and the suite died at credential resolution
|
||||||
|
# with zero diagnostic output).
|
||||||
PATH="$BIN_DIR:$PATH" \
|
PATH="$BIN_DIR:$PATH" \
|
||||||
TMPDIR="$TMP_SCRATCH" \
|
TMPDIR="$TMP_SCRATCH" \
|
||||||
HOME="$HOME_DIR" \
|
HOME="$HOME_DIR" \
|
||||||
XDG_CONFIG_HOME="$XDG_DIR" \
|
XDG_CONFIG_HOME="$XDG_DIR" \
|
||||||
MOSAIC_CREDENTIALS_FILE="$CREDENTIALS_FILE" \
|
MOSAIC_CREDENTIALS_FILE="$CREDENTIALS_FILE" \
|
||||||
|
MOSAIC_GIT_IDENTITY="" \
|
||||||
|
MOSAIC_BRAIN_HOME="" \
|
||||||
ISSUE_COMMENT_TEA_LOG="$TEA_LOG" \
|
ISSUE_COMMENT_TEA_LOG="$TEA_LOG" \
|
||||||
ISSUE_COMMENT_CURL_LOG="$CURL_LOG" \
|
ISSUE_COMMENT_CURL_LOG="$CURL_LOG" \
|
||||||
ISSUE_COMMENT_CURL_ARGV_LOG="$CURL_ARGV_LOG" \
|
ISSUE_COMMENT_CURL_ARGV_LOG="$CURL_ARGV_LOG" \
|
||||||
@@ -430,7 +449,7 @@ run_comment() {
|
|||||||
ISSUE_COMMENT_REPO_SLUG="$REPO_SLUG" \
|
ISSUE_COMMENT_REPO_SLUG="$REPO_SLUG" \
|
||||||
ISSUE_COMMENT_API_BASE="$API_BASE" \
|
ISSUE_COMMENT_API_BASE="$API_BASE" \
|
||||||
ISSUE_COMMENT_API_ROOT="$API_ROOT" \
|
ISSUE_COMMENT_API_ROOT="$API_ROOT" \
|
||||||
"$SCRIPT_DIR/issue-comment.sh" -i "$ISSUE_NUMBER" -c "$BODY" "$@"
|
"$SCRIPT_DIR/issue-comment.sh" -i "$ISSUE_NUMBER" "${BODY_FLAG:--c}" "$BODY" "$@"
|
||||||
) > "$OUTPUT_FILE" 2>&1
|
) > "$OUTPUT_FILE" 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,4 +633,21 @@ done
|
|||||||
# issue_url (already exercised by Case 1's fresh-success), so the tightened check
|
# issue_url (already exercised by Case 1's fresh-success), so the tightened check
|
||||||
# is not rejecting genuine writes.
|
# is not rejecting genuine writes.
|
||||||
|
|
||||||
|
# Case 11 (R1, 2026-08-28): -b/--body is the canonical comment flag and must
|
||||||
|
# drive a full verified write exactly like the -c/--comment alias. BODY_FLAG
|
||||||
|
# swaps only the flag spelling; every assertion below is case 1's contract.
|
||||||
|
BODY_FLAG="-b"
|
||||||
|
run_comment fresh-success
|
||||||
|
grep -q 'Added and verified comment on Gitea issue #7 (comment ID 51)' "$OUTPUT_FILE"
|
||||||
|
grep -q "^POST $API_BASE/issues/7/comments$" "$CURL_LOG"
|
||||||
|
if grep -Eq '^comment |^issue comment ' "$TEA_LOG"; then
|
||||||
|
echo "FAIL: --body write went through tea instead of REST" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
grep -q "^GET $API_BASE/issues/comments/51$" "$CURL_LOG"
|
||||||
|
grep -q "^POST $API_BASE/issues/7/comments $ACTING_LOGIN$" "$AUTH_LOG"
|
||||||
|
assert_no_temp_leak "fresh-success-body-flag"
|
||||||
|
assert_token_not_in_argv "fresh-success-body-flag"
|
||||||
|
unset BODY_FLAG
|
||||||
|
|
||||||
echo "issue-comment.sh REST create + exact-id read-back regression passed"
|
echo "issue-comment.sh REST create + exact-id read-back regression passed"
|
||||||
|
|||||||
@@ -0,0 +1,165 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Usage-error contract for issue-comment.sh (R1/R4 remediation, 2026-08-28).
|
||||||
|
#
|
||||||
|
# R4: usage errors print to STDERR and exit 2, distinct from provider,
|
||||||
|
# credential, and verification failures (exit 1), so a caller (or a stop gate)
|
||||||
|
# can tell an invocation defect from a delivery blocker. Before this contract
|
||||||
|
# the wrapper exited 1 for usage errors with messages on STDOUT, and a
|
||||||
|
# value-less flag (-c with no value) died SILENTLY at rc=1 because set -e
|
||||||
|
# killed the failed `shift 2`. That silent shape is what full-stopped a fleet
|
||||||
|
# seat: a caller could not distinguish "I invoked it wrong" from "delivery is
|
||||||
|
# blocked".
|
||||||
|
#
|
||||||
|
# R1: -b/--body is the canonical comment flag (matching issue-create,
|
||||||
|
# issue-edit, pr-create, pr-edit); -c/--comment remains a backward-compatible
|
||||||
|
# alias.
|
||||||
|
#
|
||||||
|
# Arms:
|
||||||
|
# 1. --help and -h exit 0 and print usage.
|
||||||
|
# 2. Unknown option exits 2 with the message on stderr.
|
||||||
|
# 3. Missing required -i exits 2 (stderr).
|
||||||
|
# 4. Missing required comment exits 2 (stderr).
|
||||||
|
# 5. A value-less flag (-i -b -c -l and long forms) exits 2 with a
|
||||||
|
# "requires a value" message on stderr (the former silent-death class).
|
||||||
|
# 6. -b and -c both pass parsing (the run then fails at platform detection
|
||||||
|
# in this non-repo fixture, nonzero and NOT 2), proving alias acceptance
|
||||||
|
# without any provider fixture.
|
||||||
|
# 7. No arm performs any provider request: PATH shims for gh/tea/curl
|
||||||
|
# record every invocation and the probe log must stay empty.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
WORK_DIR="${MOSAIC_TEST_WORK_DIR:-$PWD/.mosaic-test-work/issue-comment-usage}"
|
||||||
|
BIN_DIR="$WORK_DIR/bin"
|
||||||
|
PROBE_LOG="$WORK_DIR/provider-probes.log"
|
||||||
|
OUT_FILE="$WORK_DIR/out.log"
|
||||||
|
ERR_FILE="$WORK_DIR/err.log"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -rf "$WORK_DIR"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
mkdir -p "$BIN_DIR"
|
||||||
|
: > "$PROBE_LOG"
|
||||||
|
|
||||||
|
# Provider shims: any invocation is recorded and fails the run at the end.
|
||||||
|
# Usage-error arms must exit during argument parsing, before detect_platform,
|
||||||
|
# so these prove "no provider request on parser failure".
|
||||||
|
for tool in gh tea curl; do
|
||||||
|
cat > "$BIN_DIR/$tool" <<STUB
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
echo "$tool \$*" >> "$PROBE_LOG"
|
||||||
|
# gh doubles as platform probe AND write path in arm 6b: probes exit 0; the
|
||||||
|
# comment write exits 2 (gh's own usage-error status) to prove the wrapper
|
||||||
|
# normalizes provider failures to exit 1 instead of propagating 2.
|
||||||
|
if [[ "\$1 \$2" == "issue comment" ]]; then exit 2; fi
|
||||||
|
exit 0
|
||||||
|
STUB
|
||||||
|
chmod +x "$BIN_DIR/$tool"
|
||||||
|
done
|
||||||
|
|
||||||
|
run_wrapper() {
|
||||||
|
( cd "$WORK_DIR" && PATH="$BIN_DIR:$PATH" "$SCRIPT_DIR/issue-comment.sh" "$@" )
|
||||||
|
}
|
||||||
|
|
||||||
|
# Hermetic variant for parse-acceptance arms: neutralizes every identity/
|
||||||
|
# credential source the wrapper consults (seat env vars, HOME, XDG tea config)
|
||||||
|
# so the arm fails at credential resolution in ANY cwd repo, never reading a
|
||||||
|
# real token or contacting a provider. Measured 2026-08-28: without this, the
|
||||||
|
# arm's outcome depended on incidental URL-resolution state (brain cwd died at
|
||||||
|
# URL-not-found; a stack worktree cwd resolved a configured URL, read the real
|
||||||
|
# seat token, and invoked the curl stub — the suite then failed its own
|
||||||
|
# no-provider-contact check, correctly).
|
||||||
|
run_wrapper_sandboxed() {
|
||||||
|
mkdir -p "$WORK_DIR/home" "$WORK_DIR/xdg"
|
||||||
|
(
|
||||||
|
cd "$WORK_DIR"
|
||||||
|
PATH="$BIN_DIR:$PATH" HOME="$WORK_DIR/home" XDG_CONFIG_HOME="$WORK_DIR/xdg" \
|
||||||
|
MOSAIC_GIT_IDENTITY="" MOSAIC_BRAIN_HOME="" \
|
||||||
|
"$SCRIPT_DIR/issue-comment.sh" "$@"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "FAIL: $*" >&2
|
||||||
|
echo "--- stderr ---" >&2
|
||||||
|
cat "$ERR_FILE" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_rc() { # expect_rc <want> <desc> <args...>
|
||||||
|
local want="$1" desc="$2" rc=0
|
||||||
|
shift 2
|
||||||
|
run_wrapper "$@" >"$OUT_FILE" 2>"$ERR_FILE" || rc=$?
|
||||||
|
[[ "$rc" -eq "$want" ]] || fail "$desc: rc=$rc, want $want"
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_stderr() { # expect_stderr <pattern> <desc>
|
||||||
|
grep -q "$1" "$ERR_FILE" || fail "$desc: stderr missing '$1'"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 1. Help exits 0 and prints usage on stdout.
|
||||||
|
expect_rc 0 "--help exits 0" --help
|
||||||
|
grep -q "Usage: issue-comment.sh" "$OUT_FILE" || fail "--help did not print usage"
|
||||||
|
expect_rc 0 "-h exits 0" -h
|
||||||
|
|
||||||
|
# 2. Unknown option: rc 2, message on stderr.
|
||||||
|
expect_rc 2 "unknown option exits 2" --bogus
|
||||||
|
expect_stderr "unknown option" "unknown option names itself on stderr"
|
||||||
|
|
||||||
|
# 3. Missing required issue number: rc 2, stderr.
|
||||||
|
expect_rc 2 "missing -i exits 2"
|
||||||
|
expect_stderr "issue number is required" "missing -i message on stderr"
|
||||||
|
|
||||||
|
# 4. Missing required comment: rc 2, stderr.
|
||||||
|
expect_rc 2 "missing comment exits 2" -i 5
|
||||||
|
expect_stderr "comment is required" "missing comment message on stderr"
|
||||||
|
|
||||||
|
# 5. Value-less flags: rc 2 with "requires a value" on stderr. The old parser
|
||||||
|
# died here silently (set -e on the failed shift 2).
|
||||||
|
for flag in -i -b -c -l --issue --body --comment --login; do
|
||||||
|
expect_rc 2 "value-less $flag exits 2" "$flag"
|
||||||
|
expect_stderr "requires a value" "value-less $flag message on stderr"
|
||||||
|
done
|
||||||
|
|
||||||
|
# 6. Alias acceptance at parse level: both -b and -c carry a value past
|
||||||
|
# parsing; the wrapper then fails at platform detection (not a git repo)
|
||||||
|
# nonzero but NOT as a usage error (rc must not be 2).
|
||||||
|
for flag in -b -c; do
|
||||||
|
rc=0
|
||||||
|
run_wrapper_sandboxed -i 5 "$flag" "some text" >"$OUT_FILE" 2>"$ERR_FILE" || rc=$?
|
||||||
|
[[ "$rc" -ne 0 ]] || fail "$flag arm unexpectedly succeeded in the sandbox"
|
||||||
|
[[ "$rc" -ne 2 ]] || fail "$flag arm misclassified credential failure as a usage error"
|
||||||
|
done
|
||||||
|
|
||||||
|
# 6b. GitHub-path exit normalization (codex blocker on 08a00149): gh's own
|
||||||
|
# usage errors exit 2; the wrapper must NOT propagate that status (reserved
|
||||||
|
# for the wrapper's usage-error contract). With a github remote and a gh stub
|
||||||
|
# whose comment write exits 2, the wrapper must exit 1 with the normalized
|
||||||
|
# error on stderr.
|
||||||
|
GH_REPO="$WORK_DIR/repo-gh"
|
||||||
|
mkdir -p "$GH_REPO"
|
||||||
|
git -C "$GH_REPO" init -q
|
||||||
|
git -C "$GH_REPO" remote add origin https://github.com/acme/widgets.git
|
||||||
|
git -C "$GH_REPO" config mosaic.gitIdentity ""
|
||||||
|
rc=0
|
||||||
|
(
|
||||||
|
cd "$GH_REPO"
|
||||||
|
PATH="$BIN_DIR:$PATH" MOSAIC_GIT_IDENTITY="" MOSAIC_BRAIN_HOME="" \
|
||||||
|
"$SCRIPT_DIR/issue-comment.sh" -i 5 -b "text" >"$OUT_FILE" 2>"$ERR_FILE"
|
||||||
|
) || rc=$?
|
||||||
|
[[ "$rc" -eq 1 ]] || fail "GitHub path: gh exit 2 must normalize to wrapper exit 1 (got $rc)"
|
||||||
|
grep -q "GitHub comment write failed" "$ERR_FILE" || fail "GitHub path: normalized error missing from stderr"
|
||||||
|
grep -q "^gh issue comment" "$PROBE_LOG" || fail "GitHub path: gh write was not invoked"
|
||||||
|
|
||||||
|
# 7. No provider contact from any usage-error arm (arm 6b's deliberate gh
|
||||||
|
# invocation is the only permitted entry in the probe log).
|
||||||
|
if grep -v '^gh issue comment' "$PROBE_LOG" | grep -q .; then
|
||||||
|
echo "FAIL: a parser-failure arm contacted a provider:" >&2
|
||||||
|
grep -v '^gh issue comment' "$PROBE_LOG" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "issue-comment.sh usage-contract regression passed (R1/R4)"
|
||||||
@@ -14,7 +14,6 @@
|
|||||||
packages/mosaic/framework/tools/git/test-pr-merge-gitea-empty-uid.sh | resolves real credentials (#1007 census); joins CI after the wrapper-half hermeticity fix (git -C scoping)
|
packages/mosaic/framework/tools/git/test-pr-merge-gitea-empty-uid.sh | resolves real credentials (#1007 census); joins CI after the wrapper-half hermeticity fix (git -C scoping)
|
||||||
packages/mosaic/framework/tools/git/test-issue-create-interactive-auth.sh | resolves real credentials (#1007 census); joins CI after the wrapper-half hermeticity fix
|
packages/mosaic/framework/tools/git/test-issue-create-interactive-auth.sh | resolves real credentials (#1007 census); joins CI after the wrapper-half hermeticity fix
|
||||||
packages/mosaic/framework/tools/git/test-pr-metadata-gitea.sh | resolves real credentials (#1007 census, fourth entry via family-grep); joins CI after the wrapper-half hermeticity fix
|
packages/mosaic/framework/tools/git/test-pr-metadata-gitea.sh | resolves real credentials (#1007 census, fourth entry via family-grep); joins CI after the wrapper-half hermeticity fix
|
||||||
packages/mosaic/framework/tools/git/test-issue-comment-readback.sh | resolves real credentials (#1007 census, fifth entry); joins CI after the wrapper-half hermeticity fix
|
|
||||||
|
|
||||||
# --- tools/git: push guards — measured green locally, CI-image fitness unverified ---
|
# --- tools/git: push guards — measured green locally, CI-image fitness unverified ---
|
||||||
packages/mosaic/framework/tools/git/test-push-guard.sh | measured green at 826a8b3b (46 passed / 0 failed, one run, 2026-07-31); CI-image fitness unverified; #1017 burndown
|
packages/mosaic/framework/tools/git/test-push-guard.sh | measured green at 826a8b3b (46 passed / 0 failed, one run, 2026-07-31); CI-image fitness unverified; #1017 burndown
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"lint": "eslint src",
|
"lint": "eslint src",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"test": "vitest run --passWithNoTests && pnpm run test:framework-shell",
|
"test": "vitest run --passWithNoTests && pnpm run test:framework-shell",
|
||||||
"test:framework-shell": "bash framework/tools/quality/scripts/check-test-enumeration.sh && bash framework/tools/quality/scripts/test-check-test-enumeration.sh && python3 framework/tools/quality/scripts/test-framework-drift-check.py && bash framework/tools/quality/scripts/test-framework-drift-doctor.sh && bash framework/systemd/user/test-fleet-units.sh && python3 src/lease-broker/daemon_deadline_unittest.py && python3 src/lease-broker/normative_fragments_unittest.py && python3 src/lease-broker/promotion_binding_unittest.py && python3 src/lease-broker/promotion_trigger_unittest.py && python3 src/lease-broker/receipt_challenge_unittest.py && python3 src/lease-broker/context_recovery_unittest.py && python3 src/lease-broker/recovery_runtime_unittest.py && python3 src/lease-broker/recovery_b1_adversarial_unittest.py && python3 src/lease-broker/receipt_observer_client_unittest.py && python3 src/lease-broker/invariant_r_unittest.py && python3 src/lease-broker/framework_skill_portability_unittest.py && python3 src/lease-broker/revoke_noop_unittest.py && python3 src/mutator-gate/runtime_tools_unittest.py && python3 src/mutator-gate/runtime_launch_guard_unittest.py && python3 src/mutator-gate/version_coupling_unittest.py && python3 framework/tools/lease-broker/check-runtime-launches.py --root ../.. && bash framework/tools/codex/test-pr-diff-context.sh && bash framework/tools/qa/test-deps-preflight.sh && bash framework/tools/git/test-pr-edit.sh && bash framework/tools/git/test-pr-create-fallback-default-base.sh && bash framework/tools/git/test-repo-decl-consumption.sh && bash framework/tools/git/test-pr-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.sh && bash framework/tools/git/test-ci-queue-wait-no-status.sh && bash framework/tools/git/test-ci-queue-wait-branch-absent.sh && bash framework/tools/git/test-ci-queue-wait-tristate.sh && bash framework/tools/git/test-ci-queue-wait-github-checks.sh && bash framework/tools/git/test-ci-queue-wait-no-ci-expected.sh && bash framework/tools/git/test-pr-merge-queue-branch.sh && bash framework/tools/git/test-pr-merge-no-ci-expected.sh && bash framework/tools/git/test-pr-merge-fork-ci-status.sh && bash framework/tools/git/test-pr-merge-head-pin.sh && bash framework/tools/git/test-pr-merge-message-field.sh && bash framework/tools/git/test-git-credential-mosaic.sh && bash framework/tools/git/test-gitea-token-identity.sh && bash framework/tools/git/test-explain-diagnostic-status-neutral.sh && bash framework/tools/git/test-detect-platform-outside-repo.sh && bash framework/tools/woodpecker/test-terminal-green-contract.sh && bash framework/tools/_scripts/test-install-ordering-guard.sh && bash framework/tools/_scripts/test-mosaic-init-rce.sh && bash framework/tools/tmux/agent-send.test.sh && bash framework/tools/wake/test-wake-store-ack.sh && bash framework/tools/wake/test-wake-store-enqueue-race.sh && bash framework/tools/wake/test-wake-digest-hmac.sh && bash framework/tools/wake/test-wake-digest-quarantine.sh && bash framework/tools/wake/test-wake-detector.sh && bash framework/tools/wake/test-wake-fn-oracle.sh && bash framework/tools/wake/test-wake-reconcile.sh && bash framework/tools/wake/test-wake-beacon.sh && bash framework/tools/wake/test-wake-preimage.sh && bash framework/tools/wake/test-wake-install.sh && bash framework/tools/glpi/test-list-http-status.sh && bash framework/tools/orchestrator/test-board-roll.sh && bash framework/tools/woodpecker/test-ci-wait-exit-matrix.sh && bash framework/tools/_scripts/test-fleet-transport-check.sh && bash framework/tools/_scripts/test-brain-home-check.sh && bash framework/tools/_scripts/test-structure-anchor-check.sh && bash framework/tools/fleet/test-agent-session-broker-preflight.sh && bash framework/tools/fleet/test-agent-session-legacy-socket-guard.sh && bash framework/tools/git/test-grant-reviewer.sh"
|
"test:framework-shell": "bash framework/tools/quality/scripts/check-test-enumeration.sh && bash framework/tools/quality/scripts/test-check-test-enumeration.sh && python3 framework/tools/quality/scripts/test-framework-drift-check.py && bash framework/tools/quality/scripts/test-framework-drift-doctor.sh && bash framework/systemd/user/test-fleet-units.sh && python3 src/lease-broker/daemon_deadline_unittest.py && python3 src/lease-broker/normative_fragments_unittest.py && python3 src/lease-broker/promotion_binding_unittest.py && python3 src/lease-broker/promotion_trigger_unittest.py && python3 src/lease-broker/receipt_challenge_unittest.py && python3 src/lease-broker/context_recovery_unittest.py && python3 src/lease-broker/recovery_runtime_unittest.py && python3 src/lease-broker/recovery_b1_adversarial_unittest.py && python3 src/lease-broker/receipt_observer_client_unittest.py && python3 src/lease-broker/invariant_r_unittest.py && python3 src/lease-broker/framework_skill_portability_unittest.py && python3 src/lease-broker/revoke_noop_unittest.py && python3 src/mutator-gate/runtime_tools_unittest.py && python3 src/mutator-gate/runtime_launch_guard_unittest.py && python3 src/mutator-gate/version_coupling_unittest.py && python3 framework/tools/lease-broker/check-runtime-launches.py --root ../.. && bash framework/tools/codex/test-pr-diff-context.sh && bash framework/tools/qa/test-deps-preflight.sh && bash framework/tools/git/test-pr-edit.sh && bash framework/tools/git/test-pr-create-fallback-default-base.sh && bash framework/tools/git/test-repo-decl-consumption.sh && bash framework/tools/git/test-pr-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.sh && bash framework/tools/git/test-ci-queue-wait-no-status.sh && bash framework/tools/git/test-ci-queue-wait-branch-absent.sh && bash framework/tools/git/test-ci-queue-wait-tristate.sh && bash framework/tools/git/test-ci-queue-wait-github-checks.sh && bash framework/tools/git/test-ci-queue-wait-no-ci-expected.sh && bash framework/tools/git/test-pr-merge-queue-branch.sh && bash framework/tools/git/test-pr-merge-no-ci-expected.sh && bash framework/tools/git/test-pr-merge-fork-ci-status.sh && bash framework/tools/git/test-pr-merge-head-pin.sh && bash framework/tools/git/test-pr-merge-message-field.sh && bash framework/tools/git/test-git-credential-mosaic.sh && bash framework/tools/git/test-gitea-token-identity.sh && bash framework/tools/git/test-issue-comment-usage-contract.sh && bash framework/tools/git/test-issue-comment-readback.sh && bash framework/tools/git/test-explain-diagnostic-status-neutral.sh && bash framework/tools/git/test-detect-platform-outside-repo.sh && bash framework/tools/woodpecker/test-terminal-green-contract.sh && bash framework/tools/_scripts/test-install-ordering-guard.sh && bash framework/tools/_scripts/test-mosaic-init-rce.sh && bash framework/tools/tmux/agent-send.test.sh && bash framework/tools/wake/test-wake-store-ack.sh && bash framework/tools/wake/test-wake-store-enqueue-race.sh && bash framework/tools/wake/test-wake-digest-hmac.sh && bash framework/tools/wake/test-wake-digest-quarantine.sh && bash framework/tools/wake/test-wake-detector.sh && bash framework/tools/wake/test-wake-fn-oracle.sh && bash framework/tools/wake/test-wake-reconcile.sh && bash framework/tools/wake/test-wake-beacon.sh && bash framework/tools/wake/test-wake-preimage.sh && bash framework/tools/wake/test-wake-install.sh && bash framework/tools/glpi/test-list-http-status.sh && bash framework/tools/orchestrator/test-board-roll.sh && bash framework/tools/woodpecker/test-ci-wait-exit-matrix.sh && bash framework/tools/_scripts/test-fleet-transport-check.sh && bash framework/tools/_scripts/test-brain-home-check.sh && bash framework/tools/_scripts/test-structure-anchor-check.sh && bash framework/tools/fleet/test-agent-session-broker-preflight.sh && bash framework/tools/fleet/test-agent-session-legacy-socket-guard.sh && bash framework/tools/git/test-grant-reviewer.sh"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mosaicstack/brain": "workspace:*",
|
"@mosaicstack/brain": "workspace:*",
|
||||||
|
|||||||
Reference in New Issue
Block a user