Merge test/v0.21-battle-docker — Docker install.sh battle-test (CHANGELOG conflict resolved)
This commit is contained in:
commit
82689d108b
5 changed files with 175 additions and 0 deletions
|
|
@ -33,6 +33,7 @@ _primitives/_rust/target/release/kei-changelog \
|
|||
- "Branch" semantics: S3 has no native branching, so a branch is modelled as a key prefix (`<branch>/<path>`). `branch()` sets the active prefix in-memory; default `main`.
|
||||
- Factory auto-routes: `backend = "s3"` + feature `s3` + `s3.bucket` set → real cloud; otherwise falls back to the v0.14 local-manifest stub (still behind `KEI_STORE_ALLOW_S3_STUB=1`).
|
||||
- Path-traversal guard parity with `FilesystemStore`: absolute and `..`-component paths rejected before keys are spliced.
|
||||
- **tests/battle:** Docker-based clean-Ubuntu install test — `tests/battle/Dockerfile.install-test` + `verify.sh` + `battle-entry.sh` + README. Builds a fresh `ubuntu:24.04` image, runs `install.sh --profile=<minimal|core|dev|full>` under `--yes`, then asserts post-install counts (blocks ≥ 79, skills ≥ 39, top hooks ≥ 10, `_lib` hooks ≥ 2), runs `hooks/_lib/test-gate.sh`, and validates `settings.json`. First real-world "does it work on a fresh machine?" signal — CI previously only ran `--no-execute` dry-runs. v0.21 ship-blocker for any profile that regresses.
|
||||
- **primitives (v0.20 — brain schema v2 + per-client hint):**
|
||||
- Brain schema v2 with per-platform `mcp_server` dispatch — a single brain directory can now host binaries for darwin-arm64/darwin-x64/linux-x64/linux-arm64/windows-x64 and `keisei attach` picks the right one automatically. Schema v1 (single string) still accepted for backward-compat.
|
||||
- `ClientAdapter::post_attach_hint()` — per-client reload instruction, no more hardcoded Claude-Code string in the orchestrator.
|
||||
|
|
|
|||
57
tests/battle/Dockerfile.install-test
Normal file
57
tests/battle/Dockerfile.install-test
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# tests/battle/Dockerfile.install-test
|
||||
# Battle-test: run KeiSeiKit install.sh on a clean Ubuntu 24.04 container.
|
||||
# Validates: install succeeds, block/skill/hook counts match README, hook
|
||||
# test-gate passes, settings.json (if any) is valid JSON.
|
||||
#
|
||||
# Build from repo root:
|
||||
# docker build -t keisei-battle:latest -f tests/battle/Dockerfile.install-test .
|
||||
#
|
||||
# Run (default: minimal profile):
|
||||
# docker run --rm keisei-battle:latest
|
||||
#
|
||||
# Override profile:
|
||||
# docker run --rm -e PROFILE=dev keisei-battle:latest
|
||||
# docker run --rm -e PROFILE=full keisei-battle:latest
|
||||
#
|
||||
# Env:
|
||||
# PROFILE one of minimal|core|dev|full (default: minimal)
|
||||
# KEI_SKIP_RUST_BUILD 1 = skip cargo build for primitives (assembler
|
||||
# still builds; install.sh always builds it)
|
||||
|
||||
FROM ubuntu:24.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
LANG=C.UTF-8 \
|
||||
LC_ALL=C.UTF-8 \
|
||||
CARGO_HOME=/root/.cargo \
|
||||
RUSTUP_HOME=/root/.rustup \
|
||||
PATH=/root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
|
||||
# Baseline deps that a "fresh" user machine would have after apt install.
|
||||
# build-essential: cc/ld for cargo. jq: install.sh HARD prereq. pandoc:
|
||||
# soft prereq for tomd. git, curl, ca-certificates: kit + rustup download.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
git curl ca-certificates build-essential jq pandoc \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Rust toolchain — Ubuntu 24.04 ships rustc 1.75; _assembler/Cargo.toml uses
|
||||
# edition = "2024" which needs >= 1.85. Use rustup to get stable.
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
|
||||
| sh -s -- -y --default-toolchain stable --profile minimal --no-modify-path \
|
||||
&& rustc --version && cargo --version
|
||||
|
||||
# Copy the kit. .dockerignore excludes target/ so the image stays slim.
|
||||
WORKDIR /opt/keiseikit
|
||||
COPY . /opt/keiseikit/
|
||||
|
||||
# Install verify + entry scripts (path is hardcoded so they remain runnable
|
||||
# whatever CWD the user sets via -w).
|
||||
COPY tests/battle/verify.sh /usr/local/bin/verify.sh
|
||||
COPY tests/battle/battle-entry.sh /usr/local/bin/battle-entry.sh
|
||||
RUN chmod +x /usr/local/bin/verify.sh \
|
||||
/usr/local/bin/battle-entry.sh \
|
||||
/opt/keiseikit/install.sh
|
||||
|
||||
ENV PROFILE=minimal
|
||||
ENTRYPOINT ["/usr/local/bin/battle-entry.sh"]
|
||||
39
tests/battle/README.md
Normal file
39
tests/battle/README.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# tests/battle — Clean-Ubuntu Install Test
|
||||
|
||||
Validates `install.sh` on a fresh `ubuntu:24.04` container. CI only runs
|
||||
`--no-execute` dry-runs; this battle-test actually executes the installer.
|
||||
|
||||
## Run
|
||||
|
||||
From repo root:
|
||||
|
||||
```bash
|
||||
docker build -t keisei-battle:latest -f tests/battle/Dockerfile.install-test .
|
||||
docker run --rm keisei-battle:latest # minimal
|
||||
docker run --rm -e PROFILE=core keisei-battle:latest
|
||||
docker run --rm -e PROFILE=dev keisei-battle:latest
|
||||
docker run --rm -e PROFILE=full keisei-battle:latest
|
||||
```
|
||||
|
||||
Container exits 0 = green. Any other code = investigate stdout.
|
||||
|
||||
## What it asserts (verify.sh)
|
||||
|
||||
- `~/.claude/agents/_blocks` ≥ 79
|
||||
- `~/.claude/skills` ≥ 39
|
||||
- `~/.claude/hooks/*.sh` ≥ 10 top-level
|
||||
- `~/.claude/hooks/_lib/*.sh` ≥ 2 (gate.sh + test-gate.sh, v0.17)
|
||||
- `hooks/_lib/test-gate.sh` self-test passes (11/11)
|
||||
- `settings.json` (if created) parses as valid JSON
|
||||
|
||||
## Known quirks (2026-04-22)
|
||||
|
||||
- **`kei-artifact` crate fails** on `dev`/`full`: `copy_rust_primitive`
|
||||
(install/lib-primitives.sh) copies `src/` + `tests/` only — misses
|
||||
sibling `schemas/`, so `include_str!("../schemas/*.json")` breaks.
|
||||
Install still exits 0 (build is soft-fail); primitive binary count
|
||||
drops (`6/25` on full). Fix: copy every sibling dir the crate ships.
|
||||
- **Ubuntu 24.04 rustc is 1.75** — too old for `edition = "2024"`.
|
||||
Dockerfile installs rustup stable; `apt install rustc` is NOT enough.
|
||||
- **Apple Silicon hosts**: image builds linux/arm64 natively; binaries
|
||||
produced inside won't run on x86_64 hosts.
|
||||
28
tests/battle/battle-entry.sh
Executable file
28
tests/battle/battle-entry.sh
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
# tests/battle/battle-entry.sh — container ENTRYPOINT.
|
||||
# Picks profile from $PROFILE env (default: minimal), runs installer, then
|
||||
# verify.sh. Kept as a dedicated file (instead of a Dockerfile heredoc) so
|
||||
# BuildKit isn't required and the script is editable post-image-build.
|
||||
set -u
|
||||
|
||||
PROFILE="${PROFILE:-minimal}"
|
||||
echo "=== battle-test: profile=$PROFILE ==="
|
||||
echo "=== host: $(uname -a) ==="
|
||||
echo "=== cargo: $(cargo --version) ==="
|
||||
echo "=== jq: $(jq --version) ==="
|
||||
echo
|
||||
|
||||
cd /opt/keiseikit || { echo "kit missing at /opt/keiseikit"; exit 2; }
|
||||
./install.sh --profile="$PROFILE" --yes 2>&1
|
||||
INSTALL_EXIT=$?
|
||||
echo
|
||||
echo "=== install exit code: $INSTALL_EXIT ==="
|
||||
|
||||
if [ "$INSTALL_EXIT" -ne 0 ]; then
|
||||
echo "=== install failed; skipping verify ==="
|
||||
exit "$INSTALL_EXIT"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "=== running verify.sh ==="
|
||||
/usr/local/bin/verify.sh
|
||||
50
tests/battle/verify.sh
Executable file
50
tests/battle/verify.sh
Executable file
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env sh
|
||||
# tests/battle/verify.sh — post-install assertions for the battle test.
|
||||
# POSIX sh; runs inside ubuntu:24.04 container as root ($HOME=/root).
|
||||
# Thresholds match v0.21 kit snapshot (2026-04-22):
|
||||
# _blocks >= 79, skills >= 39, top hooks >= 10, _lib hooks >= 2.
|
||||
set -u
|
||||
|
||||
fail() { printf 'FAIL: %s\n' "$1" >&2; exit 1; }
|
||||
pass() { printf 'PASS: %s\n' "$1"; }
|
||||
|
||||
AG="$HOME/.claude/agents"
|
||||
HK="$HOME/.claude/hooks"
|
||||
SK="$HOME/.claude/skills"
|
||||
|
||||
n_blocks=$(ls -1 "$AG/_blocks" 2>/dev/null | wc -l | tr -d ' ')
|
||||
[ "$n_blocks" -ge 79 ] || fail "_blocks count $n_blocks < 79"
|
||||
pass "_blocks count = $n_blocks (>= 79)"
|
||||
|
||||
n_skills=$(ls -1 "$SK" 2>/dev/null | wc -l | tr -d ' ')
|
||||
[ "$n_skills" -ge 39 ] || fail "skills count $n_skills < 39"
|
||||
pass "skills count = $n_skills (>= 39)"
|
||||
|
||||
n_hooks=$(find "$HK" -maxdepth 1 -type f -name '*.sh' 2>/dev/null | wc -l | tr -d ' ')
|
||||
[ "$n_hooks" -ge 10 ] || fail "top hooks count $n_hooks < 10"
|
||||
pass "top hooks count = $n_hooks (>= 10)"
|
||||
|
||||
n_lib=$(find "$HK/_lib" -maxdepth 1 -type f -name '*.sh' 2>/dev/null | wc -l | tr -d ' ')
|
||||
[ "$n_lib" -ge 2 ] || fail "_lib hooks count $n_lib < 2"
|
||||
pass "_lib hooks count = $n_lib (>= 2)"
|
||||
|
||||
if [ -x "$HK/_lib/test-gate.sh" ]; then
|
||||
if bash "$HK/_lib/test-gate.sh" >/tmp/test-gate.out 2>&1; then
|
||||
pass "test-gate.sh exits 0"
|
||||
else
|
||||
cat /tmp/test-gate.out >&2
|
||||
fail "test-gate.sh exited non-zero"
|
||||
fi
|
||||
else
|
||||
fail "test-gate.sh missing at $HK/_lib/test-gate.sh"
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.claude/settings.json" ]; then
|
||||
jq . "$HOME/.claude/settings.json" >/dev/null 2>&1 \
|
||||
&& pass "settings.json parses as valid JSON" \
|
||||
|| fail "settings.json is not valid JSON"
|
||||
else
|
||||
pass "settings.json absent (not activated — OK)"
|
||||
fi
|
||||
|
||||
echo "=== verify.sh: all checks passed ==="
|
||||
Loading…
Reference in a new issue