Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
0fc9b15
ci: onboard Blacksmith Testbox
lawrencecchen Aug 13, 2026
e407046
ci: provision cmux-tui Rust Testbox lane
lawrencecchen Aug 13, 2026
67f398f
ci: serialize Testbox benchmark stages
lawrencecchen Aug 13, 2026
5e31e66
ci: harden trusted Blacksmith Testbox lane
lawrencecchen Aug 13, 2026
33b0dfe
docs: tighten Testbox source preflight
lawrencecchen Aug 13, 2026
22800c1
ci: serialize and recover trusted Testbox runs
lawrencecchen Aug 13, 2026
42ab3da
ci: bind Testbox cleanup to setup receipts
lawrencecchen Aug 13, 2026
5735ee5
ci: pin Testbox hydration failure reporting
lawrencecchen Aug 13, 2026
bc7ff77
ci: bound and verify remote Testbox builds
lawrencecchen Aug 13, 2026
5cdb5fc
ci: verify Testbox ready phone-home
lawrencecchen Aug 13, 2026
94c6187
ci: fence setup markers and preserve evidence
lawrencecchen Aug 13, 2026
5da1401
docs: state Testbox trust configuration limits
lawrencecchen Aug 13, 2026
bd89ec7
ci: preview owned Testbox cleanup
lawrencecchen Aug 13, 2026
c1999b8
ci: assert trusted runner identity
lawrencecchen Aug 13, 2026
ba2fd40
ci: finalize Testbox readiness and cleanup states
lawrencecchen Aug 13, 2026
dd3765c
ci: make Testbox readiness and cleanup explicit
lawrencecchen Aug 13, 2026
b0c5b80
ci: gate Testbox readiness and destructive cleanup
lawrencecchen Aug 13, 2026
4a05ae6
ci: verify Testbox ownership before cleanup
lawrencecchen Aug 13, 2026
1c95667
ci: restrict Testbox token setup to main
lawrencecchen Aug 13, 2026
1dd0e2a
ci: validate Testbox inputs before cleanup
lawrencecchen Aug 13, 2026
7e1e7cc
ci: align Testbox cleanup with CLI inventory
lawrencecchen Aug 13, 2026
3c283ab
ci: make Testbox cleanup status-specific
lawrencecchen Aug 13, 2026
4465525
ci: parse Testbox status formats safely
lawrencecchen Aug 13, 2026
9fc1b55
ci: require a current Testbox cleanup preview
lawrencecchen Aug 13, 2026
63d74f3
ci: close final Testbox trust gaps
lawrencecchen Aug 13, 2026
d0e7108
ci: bound Testbox control-plane operations
lawrencecchen Aug 13, 2026
905939f
ci: use portable bounded Testbox commands
lawrencecchen Aug 13, 2026
ad1206b
ci: require preview-bound Testbox cleanup
lawrencecchen Aug 13, 2026
53fbe79
docs: bound Testbox downloads and cleanup hashing
lawrencecchen Aug 13, 2026
d210746
ci: handle Testbox metadata and CLI schema drift
lawrencecchen Aug 13, 2026
229119d
ci: tighten Testbox ownership parsing
lawrencecchen Aug 13, 2026
07c1856
ci: enforce hydrated toolchain identity
lawrencecchen Aug 13, 2026
2af052b
ci: bound warmup and preserve interrupted stages
lawrencecchen Aug 13, 2026
89bd10d
ci: compare toolchain identity in cmux-tui
lawrencecchen Aug 13, 2026
5c529ba
ci: own bounded Testbox keepalive
lawrencecchen Aug 13, 2026
6042481
ci: fix keepalive SSH activity detection
lawrencecchen Aug 13, 2026
00634a2
docs: require independently reviewed cleanup preview
lawrencecchen Aug 13, 2026
1f21d21
ci: pin reviewed Testbox branch and SHA
lawrencecchen Aug 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ self-hosted-runner:
# Linux: Blacksmith primary (LINUX_RUNNER), WarpBuild overflow fallback.
- blacksmith-4vcpu-ubuntu-2404
- blacksmith-8vcpu-ubuntu-2404
- blacksmith-32vcpu-ubuntu-2404
- warp-ubuntu-latest-x64-4x
114 changes: 114 additions & 0 deletions .github/workflows/ci-workflow-guard-tests-testbox.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: cmux-tui Rust Testbox setup

on:
workflow_dispatch:
inputs:
testbox_id:
description: "Testbox session ID supplied by blacksmith testbox warmup"
required: true
type: string

permissions:
contents: read

jobs:
cmux-tui-rust:
name: cmux-tui Rust setup
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 45
steps:
# begin-testbox must be the first step. It attaches the VM requested by
# `blacksmith testbox warmup` and leaves it alive after this setup job.
- name: Begin Testbox
uses: useblacksmith/begin-testbox@233448af4bfdc6fca509a7f0974411ac6d8a8043 # v2
Comment on lines +110 to +111

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate the repository before beginning the Testbox

When this workflow is dispatched from another repository on its main branch, the ref guard passes and Begin Testbox runs before REPOSITORY is checked at lines 69–72. Because the begin action installs the Testbox authentication token, the declared manaflow-ai/cmux restriction is enforced too late for the token-bearing step; include the repository predicate in the pre-begin guard.

Useful? React with 👍 / 👎.

with:
testbox_id: ${{ inputs.testbox_id }}

- name: Checkout exact dispatch commit
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
ref: ${{ github.sha }}

- name: Require exact checkout
env:
EXPECTED_SHA: ${{ github.sha }}
shell: bash
run: |
actual_sha="$(git rev-parse HEAD)"
if [[ "$actual_sha" != "$EXPECTED_SHA" ]]; then
echo "::error::checked out $actual_sha, expected dispatch SHA $EXPECTED_SHA" >&2
exit 1
fi
printf 'testbox setup commit: %s\n' "$actual_sha"

- name: Initialize Ghostty source submodule
shell: bash
run: |
git submodule update --init --depth 1 ghostty
test -f ghostty/build.zig.zon

- name: Install Linux build dependencies
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y clang libclang-dev pkg-config

- name: Cache Zig package downloads
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/zig
key: cmux-tui-zig-${{ hashFiles('ghostty/build.zig.zon', 'ghostty/build.zig.zon.json') }}
restore-keys: |
cmux-tui-zig-

- name: Install repository-pinned Zig
shell: bash
run: ./scripts/install-zig-ci.sh

- name: Fetch Ghostty Zig dependencies without compiling
working-directory: ghostty
shell: bash
run: |
# `--fetch` hydrates the package cache and exits before a build.
"$CMUX_ZIG" build --fetch

- name: Cache Cargo registry and git dependencies
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
~/.cargo/registry
~/.cargo/git
key: cmux-tui-cargo-${{ runner.os }}-${{ hashFiles('cmux-tui/Cargo.lock', 'cmux-tui/rust-toolchain.toml') }}
restore-keys: |
cmux-tui-cargo-${{ runner.os }}-

- name: Set up repository-pinned cmux-tui Rust
uses: ./.github/actions/setup-cmux-tui-rust

- name: Fetch Cargo dependencies without compiling
working-directory: cmux-tui
shell: bash
run: cargo fetch --locked

- name: Record hydrated toolchain and workspace metadata
working-directory: cmux-tui
shell: bash
run: |
printf 'rust-toolchain: '
rustup show active-toolchain
printf 'cargo: '
cargo --version
printf 'rustc: '
rustc --version
printf 'zig: '
"$CMUX_ZIG" version
cargo metadata --locked --no-deps --format-version 1 > "$RUNNER_TEMP/cmux-tui-cargo-metadata.json"
test -s "$RUNNER_TEMP/cmux-tui-cargo-metadata.json"

# Always hand control back to Testbox. Warmup is setup-only: all actual
# Rust builds are issued later with `blacksmith testbox run`.
- name: Run Testbox
uses: useblacksmith/run-testbox@5ca05834db1d3813554d1dd109e5f2087a8d7cbc # v2
if: always()
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,7 @@ artifacts/

# tmux verbose debug logs (tmux -v) that land in the cwd
tmux-*.log

# Remote-only Blacksmith cmux-tui benchmark output
testbox-benchmark/
.cmux-scratch/
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
129 changes: 129 additions & 0 deletions scripts/blacksmith-cmux-tui-testbox-stage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#!/usr/bin/env bash
set -euo pipefail

# This helper is intentionally remote-only. The local benchmark plan invokes it
# through `blacksmith testbox run`; the guard makes an accidental local launch a
# no-op instead of running a Rust build on the developer's Mac.
if [[ "${CMUX_TESTBOX_REMOTE:-}" != "1" ]]; then
echo "refusing to run outside a Blacksmith Testbox (set CMUX_TESTBOX_REMOTE=1 only in the remote command)" >&2
exit 64
fi
Comment thread
coderabbitai[bot] marked this conversation as resolved.

if [[ $# -ne 1 ]]; then
echo "usage: CMUX_TESTBOX_REMOTE=1 $0 {first-clean|incremental-noop|changed-file}" >&2
exit 64
fi

stage="$1"
case "$stage" in
first-clean|incremental-noop|changed-file) ;;
*)
echo "unsupported benchmark stage: $stage" >&2
exit 64
;;
esac

repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"
if [[ ! -f cmux-tui/Cargo.toml || ! -f ghostty/.git || ! -f ghostty/build.zig.zon ]]; then
echo "cmux-tui and its Ghostty source submodule must be initialized" >&2
exit 65
fi

benchmark_dir="$repo_root/testbox-benchmark"
mkdir -p "$benchmark_dir"
# Testbox can acknowledge a run while its remote shell is still flushing
# output. Serialize stages and hold the lock through artifact writes so a
# subsequent run cannot overwrite a prior stage's timing file.
exec 9>"$benchmark_dir/.stage.lock"
flock -x 9
Comment thread
coderabbitai[bot] marked this conversation as resolved.
log_path="$benchmark_dir/$stage.log"
time_path="$benchmark_dir/$stage.time"
json_path="$benchmark_dir/$stage.json"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
changed_file="cmux-tui/crates/cmux-tui/src/main.rs"
changed_backup=""

# shellcheck disable=SC2329 # invoked indirectly by the EXIT trap
restore_changed_file() {
if [[ -n "$changed_backup" && -f "$changed_backup" ]]; then
cp "$changed_backup" "$repo_root/$changed_file"
rm -f "$changed_backup"
fi
}
trap restore_changed_file EXIT

case "$stage" in
first-clean)
rm -rf "$repo_root/cmux-tui/target"
;;
changed-file)
changed_backup="$(mktemp "${TMPDIR:-/tmp}/cmux-tui-testbox-source.XXXXXX")"
cp "$repo_root/$changed_file" "$changed_backup"
printf '\n// Blacksmith Testbox changed-file timing marker.\n' >> "$repo_root/$changed_file"
;;
esac

start_epoch="$(python3 -c 'import time; print(time.time())')"
set +e
(
cd "$repo_root/cmux-tui"
/usr/bin/time -p -o "$time_path" cargo build -p cmux-tui --locked
) >"$log_path" 2>&1
status=$?
set -e
end_epoch="$(python3 -c 'import time; print(time.time())')"

python3 - "$stage" "$start_epoch" "$end_epoch" "$status" "$time_path" "$changed_file" >"$json_path" <<'PY'
import datetime as dt
import json
import os
import platform
import subprocess
import sys

stage, start, end, status, time_path, changed_file = sys.argv[1:]
start = float(start)
end = float(end)
status = int(status)
remote_time = {}
with open(time_path, encoding="utf-8") as handle:
for line in handle:
key, _, value = line.strip().partition(" ")
if key in {"real", "user", "sys"}:
remote_time[f"time_{key}_seconds"] = float(value)

try:
git_sha = subprocess.check_output(
["git", "rev-parse", "HEAD"], text=True, stderr=subprocess.DEVNULL
).strip()
except subprocess.CalledProcessError:
git_sha = "unknown"

record = {
"schema": 1,
"stage": stage,
"command": "cargo build -p cmux-tui --locked",
"exit_code": status,
"ok": status == 0,
"started_at": dt.datetime.fromtimestamp(start, dt.timezone.utc).isoformat(),
"finished_at": dt.datetime.fromtimestamp(end, dt.timezone.utc).isoformat(),
"wall_seconds": round(end - start, 3),
"git_sha": git_sha,
"runner": {
"hostname": platform.node(),
"arch": platform.machine(),
"cpu_count": os.cpu_count(),
"uname": " ".join(platform.uname()),
},
"changed_file": changed_file if stage == "changed-file" else None,
**remote_time,
}
print(json.dumps(record, sort_keys=True))
PY

cat "$log_path"
printf '\n--- /usr/bin/time -p (%s) ---\n' "$stage"
cat "$time_path"
printf '\n--- structured timing (%s) ---\n' "$stage"
cat "$json_path"
exit "$status"
Loading