Compare commits

..
Author SHA1 Message Date
be-coder-08 2c4748bd71 fix(fleet): make shell assertions SIGPIPE-safe
ci/woodpecker/pr/ci Pipeline was successful
2026-08-07 03:03:59 -05:00
be-coder-06andMos 4fa2768962 fix(fleet): propagate roster git identity (#1073)
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
Co-authored-by: be-coder-06 <[email protected]>
2026-08-07 07:07:45 +00:00
Mos aa0a7b5fa2 fix(tools/git): issue-close.sh silently dropped the closing comment (#1085)
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
2026-08-07 05:59:12 +00:00
Mos 42ac19af48 test(gateway): size the enrollment clamp tolerance to CI jitter, not to a fast machine (closes #1090) (#1094)
ci/woodpecker/push/publish Pipeline failed
ci/woodpecker/push/ci Pipeline was successful
2026-08-07 05:33:38 +00:00
Mos f744f32214 feat(tools/git): explain tea's misleading user does not exist error (stale token, not a missing account) (#1086)
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
2026-08-07 05:07:40 +00:00
Mos 8ff7aac0ca fix(tools/git): detect-platform died silently outside a repo, taking every wrapper with it (#1089)
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
2026-08-07 04:26:36 +00:00
14 changed files with 578 additions and 44 deletions
+4
View File
@@ -46,6 +46,10 @@ steps:
# [0] of the pnpm chain, so severing that chain would silence it together
# with everything it guards; this direct line keeps one instrument running.
- bash packages/mosaic/framework/tools/quality/scripts/check-test-enumeration.sh
# Hermetic regression for issue-close.sh (#1081): mocks tea/curl onto PATH
# and sandboxes a throwaway git repo, so it resolves no real credentials and
# joins CI directly rather than the exclusions file.
- bash packages/mosaic/framework/tools/git/test-issue-close-fail-closed.sh
# Blocking gate (#791): a framework upgrade must never write or delete an
# operator-owned path. The HARD GATE proves an unanticipated operator sentinel
@@ -245,9 +245,21 @@ describe('EnrollmentService.createToken', () => {
const after = Date.now();
const expiresMs = new Date(result.expiresAt).getTime();
// Should be at most 900s from now
expect(expiresMs - before).toBeLessThanOrEqual(900_000 + 100);
// The property under test is CLAMPING: a 9999s request must come back as 900s.
// The gap between clamped and unclamped is 9_099_000 ms, so the tolerance below
// only has to exceed CI scheduling jitter — it does not need to be tight to keep
// the assertion discriminating. A 5s allowance consumes 0.05% of that margin and
// an unclamped result still misses by three orders of magnitude.
//
// It was 100ms and failed on a loaded agent at 900_106 — 6ms over (#1090). A
// wall-clock budget sized to a fast machine is a flake, not a tighter test.
const CI_JITTER_MS = 5_000;
expect(expiresMs - before).toBeLessThanOrEqual(900_000 + CI_JITTER_MS);
expect(expiresMs - after).toBeGreaterThanOrEqual(0);
// Explicitly pin the clamp itself, independent of any timing allowance:
// unclamped (9999s) would exceed this by ~9_099_000 ms.
expect(expiresMs - before).toBeLessThan(1_000_000);
});
});
+32
View File
@@ -176,6 +176,38 @@ roster-derived part of the generated launch projection and prove it reaches the
3. `AC-FGI-03`: Focused launcher and generated-environment tests, repository quality gates,
independent review, and the required RED/green/R7 evidence are recorded before push.
### Framework shell assertion portability (#1098)
#### Problem and objective
The blocking framework-shell chain can report that a pane command omitted `/usr/bin/env -i` even when
`-i` matched successfully. A short-circuiting `grep -q` under `set -o pipefail` may close its pipe after
the match and cause an upstream producer to exit with SIGPIPE, turning a valid semantic result into a
nonzero aggregate pipeline. The objective is to inspect the captured NUL-delimited argv directly and
make failures carry the observed records needed for diagnosis.
#### Normative requirements
1. `FSP-REQ-01`: The pane-boundary test SHALL validate an adjacent `/usr/bin/env`, `-i` argv pair from
the authoritative NUL-delimited tmux capture without a short-circuit pipeline whose upstream status
can override a successful match.
2. `FSP-REQ-02`: Missing, reversed, or non-adjacent boundary tokens SHALL fail, while valid boundaries
SHALL remain valid regardless of trailing argv size, pipe capacity, process scheduling, or host/CI
utility implementation.
3. `FSP-REQ-03`: A failed boundary check SHALL print stable indexed, shell-escaped observed argv records
before exiting nonzero; the fixture SHALL continue to contain generated non-secret launch data only.
4. `FSP-REQ-04`: Verification SHALL include RED-first large-payload evidence, negative token-order
controls, the complete focused launcher suite, canonical Woodpecker CI, and independent review.
#### Acceptance criteria
1. `AC-FSP-01`: A large captured argv with adjacent `/usr/bin/env`, `-i` passes even when the former
`grep -q` pipeline returns nonzero from an upstream SIGPIPE.
2. `AC-FSP-02`: Missing executable, missing flag, and detached/reversed flag fixtures return nonzero and
emit the indexed observed argv.
3. `AC-FSP-03`: The focused suite passes on the development host and CI image, and the merged-main
Woodpecker pipeline is terminal green before #1098 closes.
---
## Exact Cross-Harness Fleet Communications Contract (#766)
@@ -0,0 +1,97 @@
# #1098 — Framework shell portability / red main
## Objective
Restore terminal-green `main` by making the `test-start-agent-session.sh` clean-environment assertion semantic and portable without removing either newly enumerated framework-shell suite.
## Scope
- Tracking issue: `mosaicstack/stack#1098`
- Branch: `fix/framework-shell-portability`
- Base: `origin/main` at `4fa2768962702d53e16e8b67ee6ad52ebcb0910e`
- Primary file: `packages/mosaic/framework/tools/fleet/test-start-agent-session.sh`
- Requirements source: `docs/PRD.md` § Framework shell assertion portability (#1098)
- Out of scope: deployed files under `~/.config/mosaic`, pnpm-store cleanup, checkout deletion, and changes to the launchers `/usr/bin/env -i` behavior.
## Acceptance criteria
1. The test inspects the captured NUL-delimited tmux argv semantically and accepts an adjacent `/usr/bin/env`, `-i` pair regardless of trailing payload size or pipe scheduling.
2. Missing `/usr/bin/env`, missing `-i`, and non-adjacent `-i` remain failures.
3. Failure output includes the observed argv records with stable indexes and shell escaping; it exposes no credentials because this fixture supplies only generated non-secret launch data.
4. The focused suite passes on the dev host and in the repository CI image; the blocking PR/main pipeline returns terminal green.
5. Independent review passes; PR is squash-merged and #1098 is closed only after merged-main CI is terminal green.
## Budget
- ASSUMPTION: 30K-token working budget; rationale: one shell-test defect plus full PR/CI lifecycle.
- Auto-reduction: focused shell and package gates first; rely on canonical Woodpecker for the full monorepo suite rather than duplicating a dependency install under constrained `/home`.
- Disk baseline before clone/build: `/home` 7.1G free (99% used), `/tmp` 2.4G free (92% used).
## Investigation
### First-hand CI evidence
- Public log: `GET https://ci.mosaicstack.dev/api/repos/47/logs/2269/53041`
- Decoded 1,436 entries (11 null `data` entries treated as empty log rows), 190,756 bytes.
- Failure: `FAIL: pane command did not clear its environment` immediately after the expected pane-PID warning.
- BusyBox primitives, complete assertion pipeline, real CI image, stale/current image digests, Turbo cache masking, gateway failure, and heartbeat-sidecar concurrent writing were independently excluded.
### Root cause
The assertion ends in:
```bash
printf '%s\n' "$pane_args" | tail -n +"$after_pane_env" | grep -qxF -- '-i'
```
The script has `set -o pipefail`. `grep -q` exits as soon as it finds the valid `-i` record. Upstream `tail`/`printf` can then receive SIGPIPE, making the aggregate pipeline nonzero even though grep returned 0 and the semantic property is true. This depends on payload size, pipe capacity, and scheduling, explaining a local/image pass with a CI failure.
Discriminating stress control with `/usr/bin/env` followed immediately by `-i`:
- 8,192-byte trailing payload: `printf=0 tail=0 grep=0`, aggregate 0.
- 16,384-byte trailing payload: `printf=0 tail=141 grep=0`, aggregate 141.
- 32,768+ bytes: `printf=141 tail=141 grep=0`, aggregate 141.
- A full-reading `grep -xF` control remained 0 for every payload.
This is a third branch omitted by the earlier present-vs-corrupted split: the pair can be present and intact while `pipefail` reports an upstream SIGPIPE.
## TDD plan
1. RED: preserve the one-off stress reproducer above and add an automated large-argv semantic regression that fails under the current pipeline implementation.
2. GREEN: parse the authoritative NUL-delimited capture into a Bash array and search for an adjacent `/usr/bin/env`, `-i` pair without a short-circuit pipeline.
3. Add negative controls for missing, detached, and reversed tokens.
4. On failure, print indexed `%q` argv records before returning nonzero.
5. Run focused suite, mutation controls, shell syntax/format checks, then repository baseline gates feasible without dependency installation.
6. Independent review, queue guard, push, PR, CI, coordinator merge authorization, squash merge, merged-main CI, issue close.
## Progress
- [x] Checkout created and based on `origin/main` `4fa27689`.
- [x] CI log decoded directly.
- [x] Root-cause stress control reproduced semantic match + aggregate pipeline failure.
- [x] RED evidence: intact `/usr/bin/env`, `-i` fixture produced component statuses `0/141/0` and aggregate 141 under the former `grep -q` pipeline; full-reading semantic control stayed 0.
- [x] GREEN implementation: direct NUL-argv adjacency parser, indexed diagnostics, and full-reading scalar predicates replace all load-bearing early-exit pipelines in this test.
- [x] Baseline/situational tests:
- focused launcher suite: PASS on GNU host and cached Alpine CI image;
- paired `test-fleet-units.sh`: PASS;
- enumeration guard: PASS (`population=53`, `enumerated=36`, `excluded=18`), 14/14 mutation needles;
- `bash -n`, ShellCheck, `git diff --check`: PASS;
- static denominator after change: zero load-bearing `grep -q`/`head`/`-m1` pipeline candidates in `test-start-agent-session.sh`;
- delete-the-subject mutation removing production `-i`: RED with 78 indexed argv records, byte count, and explicit boundary failure.
- [x] Independent review:
- first Codex review: request changes — negative fixtures did not each assert diagnostics;
- remediation: centralized predicate + diagnostic wrapper and exercised all four negative fixtures;
- second Codex review: APPROVE, 0 blockers/should-fix/suggestions;
- Codex security review: risk none, 0 findings.
- [ ] PR CI, formal fleet review, merge, merged-main CI, issue closure.
## Documentation disposition
- Updated canonical `docs/PRD.md` with FSP requirements and acceptance criteria.
- This is an internal test/reliability change with no API, user workflow, deployment, navigation, or publishing-surface change; no user/admin/API/sitemap update is required.
- `docs/TASKS.md` remains unchanged because the project contract makes it orchestrator-only.
## Risks
- The CI failure did not print its captured argv, so the exact CI payload is unavailable. The stress control proves the assertion is non-portable and can emit the exact false verdict; branch CI is the canonical confirmation that replacing it resolves pipeline 2269s failure class.
- Printing fixture argv is safe only while this tests projection remains non-secret. The diagnostic must stay scoped to the test capture and shell-escaped.
@@ -14,6 +14,82 @@ fail() {
exit 1
}
pane_command_clears_environment() {
local calls_file="$1"
local -a argv=()
local index
mapfile -d '' -t argv < "$calls_file"
for ((index = 0; index + 1 < ${#argv[@]}; index++)); do
if [ "${argv[$index]}" = /usr/bin/env ] && [ "${argv[$((index + 1))]}" = -i ]; then
return 0
fi
done
return 1
}
print_pane_argv() {
local calls_file="$1"
local -a argv=()
local bytes index
mapfile -d '' -t argv < "$calls_file"
bytes=$(wc -c < "$calls_file")
printf 'observed pane argv: records=%s bytes=%s\n' "${#argv[@]}" "$bytes" >&2
for ((index = 0; index < ${#argv[@]}; index++)); do
printf ' [%03d] %q\n' "$index" "${argv[$index]}" >&2
done
}
check_pane_environment_boundary() {
local calls_file="$1"
if pane_command_clears_environment "$calls_file"; then
return 0
fi
print_pane_argv "$calls_file"
return 1
}
contains_literal() {
grep -F -- "$2" <<< "$1" >/dev/null
}
contains_line() {
grep -xF -- "$2" <<< "$1" >/dev/null
}
# Portability regression: inspect the authoritative NUL-delimited argv instead
# of piping a newline reconstruction through `grep -q` under pipefail. The old
# pipeline could report failure after a successful match when an upstream
# producer received SIGPIPE. A large trailing argument keeps that failure class
# covered without making stream size part of the semantic contract.
PORTABILITY_CALLS="$ROOT/portability-calls"
printf -v PORTABILITY_PADDING '%*s' 32768 ''
PORTABILITY_PADDING=${PORTABILITY_PADDING// /x}
printf '%s\0' /usr/bin/env -i "$PORTABILITY_PADDING" > "$PORTABILITY_CALLS"
pane_command_clears_environment "$PORTABILITY_CALLS" || \
fail "valid large pane argv was rejected by the environment-boundary assertion"
assert_pane_boundary_rejected() {
local case_name="$1"
local expected_records="$2"
local diagnostic
if diagnostic=$(check_pane_environment_boundary "$PORTABILITY_CALLS" 2>&1); then
fail "pane boundary accepted invalid $case_name fixture"
fi
contains_literal "$diagnostic" "records=$expected_records bytes=" || \
fail "pane argv diagnostic omitted counts for $case_name fixture"
contains_literal "$diagnostic" '[000]' || \
fail "pane argv diagnostic omitted indexed arguments for $case_name fixture"
}
printf '%s\0' tmux -i > "$PORTABILITY_CALLS"
assert_pane_boundary_rejected missing-env 2
printf '%s\0' /usr/bin/env HOME=/untrusted > "$PORTABILITY_CALLS"
assert_pane_boundary_rejected missing-i 2
printf '%s\0' /usr/bin/env HOME=/untrusted -i > "$PORTABILITY_CALLS"
assert_pane_boundary_rejected non-adjacent-i 3
printf '%s\0' -i /usr/bin/env > "$PORTABILITY_CALLS"
assert_pane_boundary_rejected reversed-boundary 2
cat > "$FAKE_BIN/tmux" <<'SHIM'
#!/usr/bin/env bash
set -euo pipefail
@@ -115,19 +191,19 @@ AGENT_VALID="coder0"
write_generated "$HOME_VALID" "$AGENT_VALID"
run_start "$HOME_VALID" "$AGENT_VALID"
valid_args=$(tr '\0' '\n' < "$TMUX_CALLS")
echo "$valid_args" | grep -qF new-session || fail "valid generated projection did not reach tmux"
echo "$valid_args" | grep -qF 'mosaic' || fail "fixed mosaic launcher command missing"
echo "$valid_args" | grep -qF 'yolo' || fail "fixed yolo launcher command missing"
echo "$valid_args" | grep -qF 'pi' || fail "roster runtime missing"
if echo "$valid_args" | grep -qF 'bash -c'; then
contains_literal "$valid_args" new-session || fail "valid generated projection did not reach tmux"
contains_literal "$valid_args" mosaic || fail "fixed mosaic launcher command missing"
contains_literal "$valid_args" yolo || fail "fixed yolo launcher command missing"
contains_literal "$valid_args" pi || fail "roster runtime missing"
if contains_literal "$valid_args" 'bash -c'; then
fail "launcher constructed a shell command payload"
fi
# The pane must start through an absolute clean-environment boundary. Its
# runtime command remains an argv vector, but no holder/session environment
# control variable can pass through the pane command.
echo "$valid_args" | grep -qxF '/usr/bin/env' || fail "pane does not use absolute env"
echo "$valid_args" | grep -qxF -- '-i' || fail "pane environment is not cleared"
check_pane_environment_boundary "$TMUX_CALLS" || \
fail "pane command did not use an adjacent /usr/bin/env -i boundary"
# Git identity is generated authority, not an optional or independently mutable
# local value. Each invalid form must fail before fake tmux receives a call.
@@ -156,7 +232,7 @@ assert_git_identity_rejected() {
fail "Git identity case $case_name was accepted"
fi
[ ! -s "$TMUX_CALLS" ] || fail "tmux ran before Git identity $case_name rejection"
echo "$output" | grep -qF "code=$expected_code" || \
contains_literal "$output" "code=$expected_code" || \
fail "Git identity $case_name diagnostic omitted code $expected_code"
}
@@ -176,7 +252,7 @@ if output=$(run_start "$HOME_UNSAFE_PARENT" coder-parent 2>&1); then
fail "generated file under a world-writable parent was accepted"
fi
[ ! -s "$TMUX_CALLS" ] || fail "tmux ran before unsafe parent rejection"
echo "$output" | grep -qF 'code=unsafe-permissions' || fail "unsafe parent diagnostic missing"
contains_literal "$output" 'code=unsafe-permissions' || fail "unsafe parent diagnostic missing"
: > "$TMUX_CALLS"
HOME_SYMLINK_PARENT="$ROOT/symlink-parent"
@@ -187,7 +263,7 @@ if output=$(run_start "$HOME_SYMLINK_PARENT" coder-symlink-parent 2>&1); then
fail "generated file under a symlinked parent was accepted"
fi
[ ! -s "$TMUX_CALLS" ] || fail "tmux ran before symlinked parent rejection"
echo "$output" | grep -qF 'code=unsafe-directory' || fail "symlinked parent diagnostic missing"
contains_literal "$output" 'code=unsafe-directory' || fail "symlinked parent diagnostic missing"
# Every managed ancestor is a boundary: MOSAIC_HOME, fleet, and agents. A
# symlink or group/world-writable ancestor must fail before environment parsing,
@@ -225,8 +301,8 @@ assert_managed_ancestor_rejected() {
fi
[ ! -s "$TMUX_CALLS" ] || fail "tmux ran before $hazard $ancestor rejection"
[ ! -e "$home/work" ] || fail "workdir was created before $hazard $ancestor rejection"
echo "$output" | grep -qF "code=unsafe-" || fail "managed ancestor diagnostic missing"
if echo "$output" | grep -qF 'key=MOSAIC_AGENT_COMMAND'; then
contains_literal "$output" 'code=unsafe-' || fail "managed ancestor diagnostic missing"
if contains_literal "$output" 'key=MOSAIC_AGENT_COMMAND'; then
fail "environment parsing ran before $hazard $ancestor rejection"
fi
}
@@ -247,9 +323,9 @@ if output=$(run_start "$HOME_SHADOW" coder1 2>&1); then
fail "generated-key shadow was accepted"
fi
[ ! -s "$TMUX_CALLS" ] || fail "tmux ran before generated-key shadow rejection"
echo "$output" | grep -qF 'key=MOSAIC_AGENT_RUNTIME' || fail "shadow diagnostic omitted key"
echo "$output" | grep -qF 'sha256=' || fail "shadow diagnostic omitted hash"
if echo "$output" | grep -qF 'codex'; then
contains_literal "$output" 'key=MOSAIC_AGENT_RUNTIME' || fail "shadow diagnostic omitted key"
contains_literal "$output" 'sha256=' || fail "shadow diagnostic omitted hash"
if contains_literal "$output" codex; then
fail "shadow diagnostic leaked value"
fi
@@ -265,9 +341,9 @@ if output=$(run_start "$HOME_COMMAND" coder2 2>&1); then
fail "arbitrary command override was accepted"
fi
[ ! -s "$TMUX_CALLS" ] || fail "tmux ran before command rejection"
echo "$output" | grep -qF 'key=MOSAIC_AGENT_COMMAND' || fail "command diagnostic omitted key"
echo "$output" | grep -qF 'sha256=' || fail "command diagnostic omitted hash"
if echo "$output" | grep -qF "$COMMAND_VALUE"; then
contains_literal "$output" 'key=MOSAIC_AGENT_COMMAND' || fail "command diagnostic omitted key"
contains_literal "$output" 'sha256=' || fail "command diagnostic omitted hash"
if contains_literal "$output" "$COMMAND_VALUE"; then
fail "command diagnostic leaked command value"
fi
@@ -281,7 +357,7 @@ if output=$(run_start "$HOME_PERMS" coder3 2>&1); then
fail "world-readable local input was accepted"
fi
[ ! -s "$TMUX_CALLS" ] || fail "tmux ran before permissions rejection"
echo "$output" | grep -qF 'code=unsafe-permissions' || fail "permission diagnostic missing"
contains_literal "$output" 'code=unsafe-permissions' || fail "permission diagnostic missing"
# A unit/holder-like clean bootstrap must yield a pane with trusted HOME and
# computed PATH only. The pane command itself must not carry loader, shell
@@ -311,19 +387,17 @@ PATH="$PANE_STALE_PATH" \
MOSAIC_TEST_EXECUTE_PANE=1 \
"$START" coder-pane-boundary
pane_args=$(tr '\0' '\n' < "$TMUX_CALLS")
echo "$pane_args" | grep -qxF "HOME=$PANE_TRUSTED_HOME" || \
contains_line "$pane_args" "HOME=$PANE_TRUSTED_HOME" || \
fail "pane did not restore trusted HOME"
echo "$pane_args" | grep -qF "HOME=$PANE_STALE_HOME" && \
contains_literal "$pane_args" "HOME=$PANE_STALE_HOME" && \
fail "pane inherited stale HOME"
echo "$pane_args" | grep -qF "$PANE_STALE_PATH" && fail "pane inherited stale PATH"
contains_literal "$pane_args" "$PANE_STALE_PATH" && fail "pane inherited stale PATH"
for blocked in LD_PRELOAD= BASH_ENV= MOSAIC_UNTRUSTED_SENTINEL=; do
echo "$pane_args" | grep -qF "$blocked" && fail "pane inherited $blocked"
contains_literal "$pane_args" "$blocked" && fail "pane inherited $blocked"
done
after_pane_env=$(printf '%s\n' "$pane_args" | grep -n -m1 -F '/usr/bin/env' | cut -d: -f1)
[ -n "$after_pane_env" ] || fail "pane command did not use absolute env"
printf '%s\n' "$pane_args" | tail -n +"$after_pane_env" | grep -qxF -- '-i' || \
fail "pane command did not clear its environment"
check_pane_environment_boundary "$TMUX_CALLS" || \
fail "pane command did not use an adjacent /usr/bin/env -i boundary"
pane_environment=$(tr '\0' '\n' < "$HOME_PANE_BOUNDARY/fleet/pane-environment")
# Exercise the repository launcher at $START, not the independently installed
# host copy. Set-compare every declared generated projection entry with the
@@ -337,11 +411,11 @@ if [ -n "$missing_or_changed_generated_environment" ]; then
missing_or_changed_keys=$(printf '%s\n' "$missing_or_changed_generated_environment" | cut -d= -f1 | paste -sd, -)
fail "runtime pane omitted or changed generated environment keys: $missing_or_changed_keys"
fi
echo "$pane_environment" | grep -qxF "HOME=$PANE_TRUSTED_HOME" || \
contains_line "$pane_environment" "HOME=$PANE_TRUSTED_HOME" || \
fail "runtime pane did not receive trusted HOME"
echo "$pane_environment" | grep -qF "$PANE_STALE_PATH" && fail "runtime pane received stale PATH"
contains_literal "$pane_environment" "$PANE_STALE_PATH" && fail "runtime pane received stale PATH"
for blocked in LD_PRELOAD= BASH_ENV= MOSAIC_UNTRUSTED_SENTINEL=; do
echo "$pane_environment" | grep -qF "$blocked" && fail "runtime pane received $blocked"
contains_literal "$pane_environment" "$blocked" && fail "runtime pane received $blocked"
done
write_interaction_generated() {
@@ -442,7 +516,7 @@ if output=$(run_interaction "$HOME_INTERACTION_MALFORMED" interaction-malformed
fail "interaction wrapper accepted malformed generated data"
fi
[ ! -s "$TMUX_CALLS" ] || fail "tmux ran before interaction strict-parser rejection"
echo "$output" | grep -qF 'code=unknown-key' || fail "interaction did not use shared strict parser first"
contains_literal "$output" 'code=unknown-key' || fail "interaction did not use shared strict parser first"
# A syntactically valid but policy-incompatible projection reaches the pinned
# interaction policy check only after strict parsing and never starts tmux.
@@ -455,9 +529,9 @@ if output=$(run_interaction "$HOME_INTERACTION_POLICY" interaction-policy 2>&1);
fail "interaction wrapper accepted a policy-incompatible projection"
fi
interaction_policy_args=$(tr '\0' '\n' < "$TMUX_CALLS")
echo "$interaction_policy_args" | grep -qF 'new-session' && \
contains_literal "$interaction_policy_args" new-session && \
fail "interaction pinned-policy rejection created a tmux session"
echo "$output" | grep -qF 'operator interaction service requires runtime pi' || \
contains_literal "$output" 'operator interaction service requires runtime pi' || \
fail "interaction pinned-policy check did not follow strict parsing"
# Exact stop derives the socket exclusively from the validated generated
@@ -470,10 +544,10 @@ HOME="$HOME_STOP" PATH="$FAKE_BIN:$PATH" MOSAIC_TEST_TMUX_CALLS="$TMUX_CALLS" \
MOSAIC_TEST_FLEET_OWNER=123e4567-e89b-12d3-a456-426614174000 \
MOSAIC_HOME="$HOME_STOP" MOSAIC_TMUX_SOCKET=ambient-socket "$START" --stop coder-stop
stop_args=$(tr '\0' '\n' < "$TMUX_CALLS")
echo "$stop_args" | grep -qxF 'mosaic-test' || fail "exact stop did not use the validated generated socket"
echo "$stop_args" | grep -qxF 'kill-session' || fail "exact stop did not request session termination"
echo "$stop_args" | grep -qxF '=coder-stop' || fail "exact stop did not exact-match the generated agent name"
if echo "$stop_args" | grep -qF 'ambient-socket'; then
contains_line "$stop_args" mosaic-test || fail "exact stop did not use the validated generated socket"
contains_line "$stop_args" kill-session || fail "exact stop did not request session termination"
contains_line "$stop_args" '=coder-stop' || fail "exact stop did not exact-match the generated agent name"
if contains_literal "$stop_args" ambient-socket; then
fail "exact stop trusted an ambient socket"
fi
@@ -5,7 +5,10 @@
detect_platform() {
local remote_url
remote_url=$(git remote get-url origin 2>/dev/null)
# `|| true` is load-bearing under `set -e`: outside a git repo this returns 128 and
# kills the CALLER before the -z check below can run, so the error message that is
# already written here was unreachable. Same idiom as get_gitea_repo_args() below.
remote_url=$(git remote get-url origin 2>/dev/null) || true
if [[ -z "$remote_url" ]]; then
echo "error: not a git repository or no origin remote" >&2
@@ -39,7 +42,10 @@ detect_platform() {
get_repo_info() {
local remote_url
remote_url=$(git remote get-url origin 2>/dev/null)
# `|| true` is load-bearing under `set -e`: outside a git repo this returns 128 and
# kills the CALLER before the -z check below can run, so the error message that is
# already written here was unreachable. Same idiom as get_gitea_repo_args() below.
remote_url=$(git remote get-url origin 2>/dev/null) || true
if [[ -z "$remote_url" ]]; then
echo "error: not a git repository or no origin remote" >&2
@@ -240,6 +246,21 @@ PY
} >&2
}
# Explain tea's most misleading failure. `user does not exist [uid: 0, name: ]` reads
# as a missing account; it almost always means a REVOKED OR STALE TOKEN. `tea login`
# keeps its OWN COPY of the token, so rotating the credential store does not update it.
# Diagnostic only -- stderr, no control flow, no exit.
explain_tea_user_does_not_exist() {
cat >&2 <<'MSG'
NOTE: `user does not exist [uid: 0, name: ]` from tea usually means a REVOKED OR STALE TOKEN,
not a missing account. A `tea login` stores its OWN COPY of the token; rotating the
credential store does NOT update it.
CHECK: the login's cached copy (`tea login list` -- read the FULL table, never `| head`),
then re-register that login against the current token.
DO NOT probe capability with a mutating request; a POST is the action, not a check.
MSG
}
get_gitea_login_for_host() {
local host="${1:-}"
local login
@@ -91,13 +91,32 @@ elif [[ "$PLATFORM" == "gitea" ]]; then
GITEA_LOGIN_NAME=$(get_gitea_login || true)
if [[ -n "$GITEA_LOGIN_NAME" ]]; then
if [[ -n "$COMMENT" ]]; then
tea issue comment "$ISSUE_NUMBER" "$COMMENT" --repo "$OWNER/$REPO" --login "$GITEA_LOGIN_NAME"
# `tea issue comment` is NOT a subcommand -- tea 0.11.x lists only
# list/create/edit/reopen/close under `tea issue`. Comments are the
# TOP-LEVEL `tea comment`, which takes the same --repo/--login flags.
# The old call therefore always failed, was unchecked, and the script
# closed the issue anyway, losing the record of WHY.
#
# Use `tea comment` rather than the API helper so the comment and the
# close are made by the SAME principal ($GITEA_LOGIN_NAME). Routing the
# comment through the token-authenticated helper here would attribute the
# comment to the token holder and the close to the tea login -- two
# principals for one operation.
tea comment "$ISSUE_NUMBER" "$COMMENT" --repo "$OWNER/$REPO" --login "$GITEA_LOGIN_NAME" || {
echo "Error: failed to post comment on #$ISSUE_NUMBER -- NOT closing (fail closed)." >&2
exit 1
}
fi
tea issue close "$ISSUE_NUMBER" --repo "$OWNER/$REPO" --login "$GITEA_LOGIN_NAME"
else
echo "No tea login configured for $(get_remote_host); using authenticated Gitea API fallback." >&2
if [[ -n "$COMMENT" ]]; then
gitea_issue_comment_api
# Fail closed here too: an unchecked comment lets the issue close without its
# audit trail, which is the same defect as the tea path above.
gitea_issue_comment_api || {
echo "Error: failed to post comment on #$ISSUE_NUMBER -- NOT closing (fail closed)." >&2
exit 1
}
fi
gitea_issue_close_api
fi
@@ -156,6 +156,7 @@ case "$PLATFORM" in
exit 0
fi
echo "Warning: tea issue create failed, trying Gitea API fallback..." >&2
{ declare -F explain_tea_user_does_not_exist >/dev/null && explain_tea_user_does_not_exist; } || true
fi
gitea_issue_create_api
;;
@@ -71,6 +71,7 @@ elif [[ "$PLATFORM" == "gitea" ]]; then
exit 0
fi
echo "Warning: tea issue view failed, trying Gitea API fallback..." >&2
{ declare -F explain_tea_user_does_not_exist >/dev/null && explain_tea_user_does_not_exist; } || true
fi
gitea_issue_view_api
else
@@ -219,6 +219,7 @@ case "$PLATFORM" in
exit 0
fi
echo "Warning: tea pr create failed, trying Gitea API fallback..." >&2
{ declare -F explain_tea_user_does_not_exist >/dev/null && explain_tea_user_does_not_exist; } || true
gitea_pr_create_api
;;
*)
@@ -0,0 +1,58 @@
#!/bin/bash
# Regression: detect_platform / get_repo_info must FAIL LOUDLY outside a git repo,
# not kill the caller silently.
#
# Both functions already contained the right error path:
# if [[ -z "$remote_url" ]]; then echo "error: not a git repository..." >&2; return 1; fi
# but under `set -e` -- which every wrapper in this directory uses -- the preceding
# assignment `remote_url=$(git remote get-url origin 2>/dev/null)` returns git's 128
# outside a repo and terminates the CALLER first. The message was unreachable.
#
# Observed cost: pr-review.sh invoked from a non-repo cwd exits 128 with NO stdout and
# NO stderr, even when -r/--repo and -H/--host are supplied -- the flags documented as
# "skips git-remote inference". Two reviewer seats hit this and correctly reported
# `blocked` with no diagnostic to report.
#
# The control that matters is the LOUD one: asserting "rc != 0" passes on the broken
# build too, because 128 is also non-zero. The test must assert the MESSAGE.
set -uo pipefail
fail=0
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
run_outside() { # $1=function name -> "rc:sawmessage"
local fn="$1" out rc
out=$( cd "$TMP" && bash -c "set -e; source '$HERE/detect-platform.sh'; $fn" 2>&1 ); rc=$?
printf '%s:%s' "$rc" "$(grep -qi 'not a git repository' <<<"$out" && echo yes || echo no)"
}
check() { if [ "$2" = "$3" ]; then echo " PASS $1 ($2)"; else echo " FAIL $1: got $2, want $3"; fail=1; fi; }
# $TMP must not be inside a git repo. Do not SKIP on failure: be-coder-07 showed the
# original SKIP exited 0, so pointing TMPDIR beneath a git worktree made this test PASS
# against unchanged main. A skip that exits 0 is indistinguishable from a pass.
# GIT_CEILING_DIRECTORIES stops git walking above $TMP, making the condition hold
# regardless of where TMPDIR lives, rather than merely detecting when it does not.
# GIT_CEILING_DIRECTORIES is matched against the PHYSICAL path -- a symlinked TMPDIR
# (/tmp is commonly one) makes the logical path never match, and the ceiling silently
# does nothing. Resolve it before exporting.
TMP="$(cd "$TMP" && pwd -P)"
export GIT_CEILING_DIRECTORIES="$TMP"
if ( cd "$TMP" && git rev-parse --git-dir >/dev/null 2>&1 ); then
echo " FAIL scratch dir is inside a git repo even with GIT_CEILING_DIRECTORIES set;"
echo " the outside-a-repo precondition cannot be established -- refusing to report a result"
exit 1
fi
echo "== outside a git repo: rc=1 AND the diagnostic is emitted =="
check "detect_platform" "$(run_outside detect_platform)" "1:yes"
check "get_repo_info" "$(run_outside get_repo_info)" "1:yes"
echo "== inside a git repo the functions still work =="
git init -q "$TMP/repo" 2>/dev/null
git -C "$TMP/repo" remote add origin https://git.mosaicstack.dev/mosaicstack/stack.git 2>/dev/null
out=$( cd "$TMP/repo" && bash -c "set -e; source '$HERE/detect-platform.sh'; detect_platform" 2>&1 ); rc=$?
if [ "$rc" -eq 0 ] && grep -qi 'gitea' <<<"$out"; then echo " PASS detect_platform in-repo (rc=0, $out)"
else echo " FAIL detect_platform in-repo: rc=$rc out=$out"; fail=1; fi
[ "$fail" -eq 0 ] && echo "OK detect-platform fails loudly outside a repo" || echo "FAILED"
exit "$fail"
@@ -0,0 +1,64 @@
#!/bin/bash
# Regression: the tea-failure diagnostic must be STATUS-NEUTRAL.
#
# Found by be-coder-08 reviewing PR #1086. At all three call sites the diagnostic is emitted
# immediately BEFORE the Gitea API fallback. Written as the last command of an && list:
# declare -F explain_... >/dev/null && explain_...
# under `set -e` a FAILING diagnostic exits and the fallback never runs -- a diagnostic that
# suppresses the recovery path it exists to explain. It misbehaves ONLY when the helper is
# PRESENT, so the helper-absent path (pre-#1086 behaviour) keeps working and reads as a
# passing control.
#
# TWO DEFECTS IN THE FIRST VERSION OF THIS TEST, both found by be-coder-08:
# 1. `out=$( ... ) 2>"$errto"` applies the redirection to the ASSIGNMENT, not to the
# command substitution, so the probe's stderr was never actually pointed at /dev/full
# and the /dev/full rows proved nothing. Verified: `out=$(echo x >&2) 2>/dev/full`
# leaks to the terminal and returns 0; the redirect must be INSIDE the substitution.
# 2. `eval "$CONSTRUCT"` changes `set -e` semantics for a bare && list, so the probe did
# not exercise the construct as the shipped file executes it. It now writes the line
# into a real script and runs it -- same parse, same set -e rules, no eval.
# The construct is still LIFTED FROM THE SHIPPED FILE: retyping the fixed form makes the
# probe pass on a build whose real call sites still carry the bare && form.
set -uo pipefail
fail=0
GIT_DIR_UNDER_TEST="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
probe() { # $1=present|absent $2=stderr target $3=source file -> "rc:fallback"
local helper="$1" errto="$2" src="$3" construct script out rc
construct=$(grep -m1 'explain_tea_user_does_not_exist' "$GIT_DIR_UNDER_TEST/$src" | sed 's/^[[:space:]]*//')
[ -n "$construct" ] || { printf 'no-construct:no'; return; }
script="$TMP/probe.sh"
{
echo '#!/bin/bash'
echo 'set -e'
echo 'explain_tea_user_does_not_exist() { echo "diagnostic" >&2; }'
[ "$helper" = absent ] && echo 'unset -f explain_tea_user_does_not_exist'
echo "$construct" # the shipped line, parsed by a real shell
echo 'echo FALLBACK_REACHED'
} > "$script"
# redirect INSIDE the substitution so the subshell's stderr really is $errto
out=$( bash "$script" 2>"$errto" ); rc=$?
printf '%s:%s' "$rc" "$(grep -q FALLBACK_REACHED <<<"$out" && echo yes || echo no)"
}
check() { if [ "$2" = "$3" ]; then echo " PASS $1 ($2)"; else echo " FAIL $1: got $2, want $3"; fail=1; fi; }
echo "== diagnostic must not alter exit status or skip the fallback =="
# /dev/full makes every stderr write fail -- the real-world shape is a closed or full fd.
for src in pr-create.sh issue-view.sh issue-create.sh; do
check "$src stderr OK / helper present" "$(probe present /dev/null "$src")" "0:yes"
check "$src stderr OK / helper absent " "$(probe absent /dev/null "$src")" "0:yes"
check "$src stderr FAILING / helper present" "$(probe present /dev/full "$src")" "0:yes"
check "$src stderr FAILING / helper absent " "$(probe absent /dev/full "$src")" "0:yes"
done
echo "== all three call sites use the status-neutral form =="
for f in pr-create.sh issue-view.sh issue-create.sh; do
p="$GIT_DIR_UNDER_TEST/$f"
grep -q '{ declare -F explain_tea_user_does_not_exist >/dev/null && explain_tea_user_does_not_exist; } || true' "$p" \
&& echo " PASS $f guarded" || { echo " FAIL $f: diagnostic is not status-neutral"; fail=1; }
done
[ "$fail" -eq 0 ] && echo "OK diagnostic is status-neutral" || echo "FAILED"
exit "$fail"
@@ -0,0 +1,150 @@
#!/usr/bin/env bash
# Regression: issue-close.sh must NOT close an issue when the closing comment could not
# be posted, and comment+close must be made by ONE principal.
#
# Guards two defects fixed together (see #1081):
# 1. `tea issue comment` is not a subcommand -- tea exposes comments as the TOP-LEVEL
# `tea comment`. The old call always failed, was unchecked, and the issue closed
# anyway, losing the record of WHY it was closed.
# 2. Routing the comment through the token-authenticated API helper while the close
# used --login would attribute one operation to two principals.
#
# SAFETY (rev-974, #1085 review 130): this test previously ran under `set -uo pipefail`
# with unchecked mkdir/redirect/cd, then prepended a possibly-nonexistent $MOCK_BIN to
# PATH -- while `git remote add origin` names the REAL repository. Forcing setup failure
# with an unwritable AGENT_WORK_ROOT made it `git init` in its CALLER's directory and
# invoke the real, provider-mutating issue-close.sh. Setup now fails closed, and both
# `tea` and `curl` are asserted to resolve INSIDE $MOCK_BIN before any target run.
set -euo pipefail
# NOTE: with `set -e`, `grep -q X && fail "..."` is a trap -- the ABSENT case (grep rc=1,
# which is the PASSING case for a must-not-appear assertion) is the last command of an &&
# list and silently terminates the script with no message. Every must-not-appear check
# below is therefore an if-block. This is the same set -e + &&-list defect be-coder-08
# found in #1086, reintroduced here by adding `set -e` for the sandbox-safety fix.
WORK_ROOT="${AGENT_WORK_ROOT:-${TMPDIR:-/tmp}}"
SANDBOX="$WORK_ROOT/issue-close-fail-closed-test-$$"
MOCK_BIN="$SANDBOX/bin"; REPO_DIR="$SANDBOX/repo"; CALLS="$SANDBOX/calls.log"
cleanup() { rm -rf "$SANDBOX"; }
trap cleanup EXIT
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TARGET="$SCRIPT_DIR/issue-close.sh"
[ -f "$TARGET" ] || { echo "FAIL: issue-close.sh not found beside this test"; exit 1; }
fail() { echo "FAIL: $*"; exit 1; }
# Every setup step is checked. Under `set -e` these abort; the explicit || fail keeps the
# reason legible instead of a bare non-zero exit.
mkdir -p "$MOCK_BIN" "$REPO_DIR" || fail "setup: cannot create sandbox under $WORK_ROOT"
: > "$CALLS" || fail "setup: cannot write calls log at $CALLS"
cd "$REPO_DIR" || fail "setup: cannot cd into $REPO_DIR"
git init -q || fail "setup: git init failed"
git remote add origin https://git.mosaicstack.dev/mosaicstack/stack.git || fail "setup: git remote add failed"
export PATH="$MOCK_BIN:$PATH" CALLS
export GITEA_URL="https://git.mosaicstack.dev"
export GITEA_TOKEN="redacted-test-token"
cat > "$MOCK_BIN/curl" <<'EOF'
#!/bin/bash
method=GET; url=""
while [ $# -gt 0 ]; do
case "$1" in
-X) method="$2"; shift 2 ;;
http*|https*) url="$1"; shift ;;
*) shift ;;
esac
done
printf 'curl %s %s\n' "$method" "$url" >> "$CALLS"
[ "${MOCK_CURL_FAIL:-}" = "1" ] && [ "$method" = "POST" ] && exit 22
exit 0
EOF
chmod +x "$MOCK_BIN/curl"
mk_tea() { # $1 = exit code for a comment attempt; $2 = login list (empty => no login)
local rc="$1" login="${2-}"
cat > "$MOCK_BIN/tea" <<EOF
#!/bin/bash
printf 'tea %s\n' "\$*" >> "$CALLS"
if [[ "\$*" == *"login list"* ]]; then
printf '%s\n' '${login}'; exit 0
fi
# Fail ANY comment attempt -- both the correct top-level \`tea comment\` and the broken
# \`tea issue comment\` -- so an unfixed script exercises the DEFECT rather than tripping
# a setup assertion.
if [[ "\$1" == "comment" || ( "\$1" == "issue" && "\$2" == "comment" ) ]]; then exit $rc; fi
exit 0
EOF
chmod +x "$MOCK_BIN/tea"
}
LOGIN_JSON='[{"name":"git.mosaicstack.dev","url":"https://git.mosaicstack.dev"}]'
# The mocks must be the ones that run. Without this, a failed setup silently falls through
# to the real tea/curl and the "test" mutates the real provider.
assert_mocked() {
local w
for w in tea curl; do
p=$(command -v "$w" || true)
[ -n "$p" ] || fail "SAFETY: $w does not resolve at all"
case "$p" in
"$MOCK_BIN"/*) : ;;
*) fail "SAFETY: $w resolves to $p, OUTSIDE the sandbox -- refusing to invoke the target" ;;
esac
done
}
run_target() { # never let a target failure abort the test; we assert on rc
# Call sites MUST use `rc=0; run_target ... || rc=$?` -- a bare `run_target ...; rc=$?`
# lets the non-zero RETURN trip set -e in the CALLER before rc is ever read.
set +e; bash "$TARGET" "$@" >/dev/null 2>&1; local rc=$?; set -e; return $rc
}
# ── tea path ────────────────────────────────────────────────────────────────────────
# 1. NEGATIVE (the regression): comment fails => must NOT close, must exit non-zero
mk_tea 1 "$LOGIN_JSON"; : > "$CALLS"; assert_mocked
rc=0; run_target -i 42 -c "closing note" || rc=$?
grep -qE 'tea (issue )?comment' "$CALLS" || fail "no comment attempt -- setup did not reach the tea branch"
if grep -q 'tea issue close' "$CALLS"; then fail "ISSUE CLOSED AFTER THE COMMENT FAILED -- the regression"; fi
[ "$rc" -ne 0 ] || fail "comment failed but issue-close exited 0 -- FAIL-OPEN"
# 2. POSITIVE: comment succeeds => close proceeds, exit 0
mk_tea 0 "$LOGIN_JSON"; : > "$CALLS"; assert_mocked
rc=0; run_target -i 42 -c "closing note" || rc=$?
[ "$rc" -eq 0 ] || fail "comment succeeded but issue-close exited $rc"
grep -q 'tea issue close' "$CALLS" || fail "issue not closed even though the comment succeeded"
# 3. must use top-level `tea comment`, never `tea issue comment`
if grep -q 'tea issue comment' "$CALLS"; then fail "used 'tea issue comment' -- not a valid subcommand"; fi
# 4. ONE PRINCIPAL: comment and close must carry the SAME --login
c=$(grep -m1 '^tea comment' "$CALLS" | grep -o -- '--login [^ ]*' | awk '{print $2}')
k=$(grep -m1 '^tea issue close' "$CALLS" | grep -o -- '--login [^ ]*' | awk '{print $2}')
[ -n "$c" ] || fail "comment carried no --login"
[ "$c" = "$k" ] || fail "MIXED PRINCIPALS: comment=$c close=$k"
# ── no-login / API fallback path ────────────────────────────────────────────────────
# rev-974: the delta also adds fail-closed behaviour to this branch, and the suite never
# reached it -- replacing the whole fallback contract with an unconditional close still
# passed. These assert the POSTCONDITION (which HTTP calls happened, in what order),
# not merely that a command ran.
# 5. no login + comment FAILS => POST attempted, NO PATCH, non-zero
mk_tea 0 ""; : > "$CALLS"; assert_mocked
rc=0; MOCK_CURL_FAIL=1 run_target -i 42 -c "closing note" || rc=$?
grep -q 'curl POST' "$CALLS" || fail "API path: no comment POST attempted"
if grep -q 'curl PATCH' "$CALLS"; then fail "API path: ISSUE CLOSED (PATCH) AFTER THE COMMENT POST FAILED"; fi
[ "$rc" -ne 0 ] || fail "API path: comment failed but exited 0 -- FAIL-OPEN"
# 6. no login + comment SUCCEEDS => POST strictly BEFORE PATCH, exit 0
mk_tea 0 ""; : > "$CALLS"; assert_mocked
rc=0; run_target -i 42 -c "closing note" || rc=$?
[ "$rc" -eq 0 ] || fail "API path: comment succeeded but exited $rc"
order=$(grep -oE 'curl (POST|PATCH)' "$CALLS" | awk '{print $2}' | paste -sd, -)
[ "$order" = "POST,PATCH" ] || fail "API path: expected POST,PATCH -- got '${order:-<none>}'"
# 7. no login + NO comment => PATCH only, never a POST
mk_tea 0 ""; : > "$CALLS"; assert_mocked
rc=0; run_target -i 42 || rc=$?
[ "$rc" -eq 0 ] || fail "API path: no-comment close exited $rc"
if grep -q 'curl POST' "$CALLS"; then fail "API path: posted a comment when none was requested"; fi
grep -q 'curl PATCH' "$CALLS" || fail "API path: issue not closed when no comment was requested"
echo "issue-close.sh fail-closed + single-principal regression passed"
+1 -1
View File
@@ -25,7 +25,7 @@
"lint": "eslint src",
"typecheck": "tsc --noEmit",
"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 && bash framework/tools/fleet/test-start-agent-session.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/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/framework_skill_portability_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-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.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-pr-merge-queue-branch.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/woodpecker/test-terminal-green-contract.sh && bash framework/tools/_scripts/test-install-ordering-guard.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"
"test:framework-shell": "bash framework/tools/quality/scripts/check-test-enumeration.sh && bash framework/tools/quality/scripts/test-check-test-enumeration.sh && bash framework/tools/fleet/test-start-agent-session.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/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/framework_skill_portability_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-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.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-pr-merge-queue-branch.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/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"
},
"dependencies": {
"@mosaicstack/brain": "workspace:*",