feat: Linux/cloud platform stack (TLS, registry, static/cross, selfhost PM)
ci / build (ubuntu) (push) Has been cancelled
ci / macos smoke (push) Has been cancelled
ci / windows smoke (push) Has been cancelled
selfhost-loop / bootstrap determinism (push) Has been cancelled
ci / unit + fmt (push) Has been cancelled
ci / examples (push) Has been cancelled
ci / goldens + tools (push) Has been cancelled
ci / apps (push) Has been cancelled
ci / selfhost smoke (push) Has been cancelled
ci / CI gate (push) Has been cancelled
ci / build (ubuntu) (push) Has been cancelled
ci / macos smoke (push) Has been cancelled
ci / windows smoke (push) Has been cancelled
selfhost-loop / bootstrap determinism (push) Has been cancelled
ci / unit + fmt (push) Has been cancelled
ci / examples (push) Has been cancelled
ci / goldens + tools (push) Has been cancelled
ci / apps (push) Has been cancelled
ci / selfhost smoke (push) Has been cancelled
ci / CI gate (push) Has been cancelled
Ship the QUALITY_PLAN platform focus: thin/minimal runtime, --static/--target, Nexus HTTPS/mTLS with graceful stop, lock checksums + install --locked, selfhost registry (search/add/HTTP), containers, and CI smokes for cloud path.
This commit is contained in:
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build examples/http_health.bux → build/http_health for container packaging.
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
export BUX_STDLIB="${BUX_STDLIB:-$ROOT/lib}"
|
||||
OUT_DIR="${1:-$ROOT/build}"
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
if [[ ! -x "$ROOT/buxc" ]]; then
|
||||
(cd "$ROOT" && make build)
|
||||
fi
|
||||
|
||||
PKG=$(mktemp -d)
|
||||
trap 'rm -rf "$PKG"' EXIT
|
||||
mkdir -p "$PKG/src"
|
||||
cp -a "$ROOT/rt" "$PKG/"
|
||||
cat > "$PKG/bux.toml" <<'EOF'
|
||||
[Package]
|
||||
Name = "http_health"
|
||||
Version = "0.1.0"
|
||||
Type = "bin"
|
||||
|
||||
[Build]
|
||||
Output = "Bin"
|
||||
EOF
|
||||
cp "$ROOT/examples/http_health.bux" "$PKG/src/Main.bux"
|
||||
|
||||
"$ROOT/buxc" --quiet --release build "$PKG"
|
||||
cp "$PKG/build/http_health" "$OUT_DIR/http_health"
|
||||
file "$OUT_DIR/http_health"
|
||||
echo "wrote $OUT_DIR/http_health"
|
||||
echo "docker: docker build -f examples/docker/Dockerfile.health -t bux-health $ROOT"
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build a fully-static hello binary for container / distroless demos (session 75).
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
export BUX_STDLIB="${BUX_STDLIB:-$ROOT/lib}"
|
||||
OUT_DIR="${1:-$ROOT/build}"
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
if [[ ! -x "$ROOT/buxc" ]]; then
|
||||
(cd "$ROOT" && make build)
|
||||
fi
|
||||
|
||||
PKG=$(mktemp -d)
|
||||
trap 'rm -rf "$PKG"' EXIT
|
||||
mkdir -p "$PKG/src"
|
||||
cp -a "$ROOT/rt" "$PKG/"
|
||||
cat > "$PKG/bux.toml" <<'EOF'
|
||||
[Package]
|
||||
Name = "hello_static"
|
||||
Version = "0.1.0"
|
||||
Type = "bin"
|
||||
|
||||
[Build]
|
||||
Output = "Bin"
|
||||
EOF
|
||||
cp "$ROOT/examples/hello.bux" "$PKG/src/Main.bux"
|
||||
|
||||
"$ROOT/buxc" --quiet --static --release build "$PKG"
|
||||
cp "$PKG/build/hello_static" "$OUT_DIR/hello_static"
|
||||
file "$OUT_DIR/hello_static"
|
||||
echo "wrote $OUT_DIR/hello_static"
|
||||
echo "docker: docker build -f examples/docker/Dockerfile.static --build-arg BIN=$OUT_DIR/hello_static -t bux-hello-static $ROOT"
|
||||
@@ -150,6 +150,36 @@ if ! sed -n '/^Array_int TakeViaPtr/,/^}/p' "$TMP/mptr/build/main.c" | grep -q '
|
||||
fi
|
||||
echo " move_field_ptr: PASS (run + no Bag_Drop + Tracked_Drop remaining)"
|
||||
|
||||
# --- cross-function pointer ownership TakeItems(&bag) ---
|
||||
echo "=== smoke: move_cross_fn ==="
|
||||
mkdir -p "$TMP/mcf/src"
|
||||
cp -a "$ROOT/rt" "$TMP/mcf/"
|
||||
cat > "$TMP/mcf/bux.toml" <<'EOF'
|
||||
[Package]
|
||||
Name = "move_cross_fn"
|
||||
Version = "0.1.0"
|
||||
Type = "bin"
|
||||
|
||||
[Build]
|
||||
Output = "Bin"
|
||||
EOF
|
||||
cp "$ROOT/examples/move_cross_fn.bux" "$TMP/mcf/src/Main.bux"
|
||||
out=$(cd "$TMP/mcf" && "$BUXC" run .)
|
||||
echo "$out" | grep -q 'cross_fn_drops=2'
|
||||
echo "$out" | grep -q 'PASS'
|
||||
# CallTakeItems must Tracked_Drop remaining tag, not Bag_Drop (would free moved items)
|
||||
if sed -n '/^int CallTakeItems/,/^}/p' "$TMP/mcf/build/main.c" | grep -q 'Bag_Drop'; then
|
||||
echo "error: CallTakeItems still Bag_Drops after TakeItems(&bag)" >&2
|
||||
sed -n '/^int CallTakeItems/,/^}/p' "$TMP/mcf/build/main.c"
|
||||
exit 1
|
||||
fi
|
||||
if ! sed -n '/^int CallTakeItems/,/^}/p' "$TMP/mcf/build/main.c" | grep -q 'Tracked_Drop'; then
|
||||
echo "error: CallTakeItems missing Tracked_Drop for remaining tag" >&2
|
||||
sed -n '/^int CallTakeItems/,/^}/p' "$TMP/mcf/build/main.c"
|
||||
exit 1
|
||||
fi
|
||||
echo " move_cross_fn: PASS (run + no Bag_Drop + Tracked_Drop remaining)"
|
||||
|
||||
# --- early return Drop counts ---
|
||||
echo "=== smoke: drop_early_return ==="
|
||||
mkdir -p "$TMP/de/src"
|
||||
@@ -168,4 +198,4 @@ out=$(cd "$TMP/de" && "$BUXC" run .)
|
||||
echo "$out" | grep -q 'PASS'
|
||||
echo " drop_early_return: PASS"
|
||||
|
||||
echo "PASS: smoke_drop_move (field-move + partial + remaining + nested + ptr + early-return)"
|
||||
echo "PASS: smoke_drop_move (field-move + partial + remaining + nested + ptr + cross-fn + early-return)"
|
||||
|
||||
Executable
+117
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env bash
|
||||
# Session 75 — Linux / cloud / embedded smoke:
|
||||
# 1) BUX_RUNTIME=minimal (thin runtime, run hello)
|
||||
# 2) --static --release (fully-static binary, file(1) check)
|
||||
# 3) --target aarch64-linux-gnu (cross build if toolchain present)
|
||||
# 4) CTFE CRC example under minimal runtime
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
export BUX_STDLIB="${BUX_STDLIB:-$ROOT/lib}"
|
||||
unset BUX_DEBUG_FILE || true
|
||||
unset BUX_RUNTIME || true
|
||||
unset BUX_STATIC || true
|
||||
unset BUX_CC || true
|
||||
|
||||
if [[ -x "$ROOT/buxc" ]]; then
|
||||
BUXC="$ROOT/buxc"
|
||||
else
|
||||
(cd "$ROOT" && make build)
|
||||
BUXC="$ROOT/buxc"
|
||||
fi
|
||||
|
||||
mkpkg() {
|
||||
local name="$1" src="$2"
|
||||
local d
|
||||
d=$(mktemp -d)
|
||||
mkdir -p "$d/src"
|
||||
cp -a "$ROOT/rt" "$d/"
|
||||
cat > "$d/bux.toml" <<EOF
|
||||
[Package]
|
||||
Name = "$name"
|
||||
Version = "0.1.0"
|
||||
Type = "bin"
|
||||
|
||||
[Build]
|
||||
Output = "Bin"
|
||||
EOF
|
||||
cp "$src" "$d/src/Main.bux"
|
||||
echo "$d"
|
||||
}
|
||||
|
||||
pass=0
|
||||
fail=0
|
||||
note() { echo "=== $* ==="; }
|
||||
|
||||
# ── 1) minimal runtime ──────────────────────────────────────────────────
|
||||
note "minimal runtime (BUX_RUNTIME=minimal)"
|
||||
PKG=$(mkpkg hello_min "$ROOT/examples/hello.bux")
|
||||
trap 'rm -rf "$PKG" "${PKG2:-}" "${PKG3:-}" "${PKG4:-}"' EXIT
|
||||
export BUX_RUNTIME=minimal
|
||||
out=$("$BUXC" --quiet run "$PKG" 2>&1) || { echo "$out" >&2; exit 1; }
|
||||
echo "$out" | grep -q 'Hello, Bux!'
|
||||
grep -q 'minimal / embedded / static' "$PKG/build/runtime.c"
|
||||
# must not pull full POSIX
|
||||
if grep -q 'openssl/evp\|pthread.h' "$PKG/build/runtime.c"; then
|
||||
echo "error: minimal runtime still has pthread/openssl includes" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "PASS: minimal runtime"
|
||||
pass=$((pass+1))
|
||||
unset BUX_RUNTIME
|
||||
|
||||
# ── 2) fully-static (thin runtime implied) ──────────────────────────────
|
||||
note "static link (--static --release)"
|
||||
PKG2=$(mkpkg hello_static "$ROOT/examples/hello.bux")
|
||||
out=$("$BUXC" --quiet --static --release build "$PKG2" 2>&1) || { echo "$out" >&2; exit 1; }
|
||||
BIN="$PKG2/build/hello_static"
|
||||
[[ -x "$BIN" ]] || BIN="$PKG2/build/hello_static.exe"
|
||||
file_out=$(file "$BIN")
|
||||
echo "$file_out"
|
||||
echo "$file_out" | grep -qi 'statically linked\|static-pie\|static '
|
||||
# run only if host arch matches
|
||||
if echo "$file_out" | grep -qi 'x86-64\|x86_64\|Intel 80386'; then
|
||||
run_out=$("$BIN" 2>&1) || { echo "$run_out" >&2; exit 1; }
|
||||
echo "$run_out" | grep -q 'Hello, Bux!'
|
||||
fi
|
||||
grep -q 'minimal / embedded / static' "$PKG2/build/runtime.c"
|
||||
echo "PASS: static link"
|
||||
pass=$((pass+1))
|
||||
|
||||
# ── 3) cross aarch64 (optional toolchain) ───────────────────────────────
|
||||
note "cross aarch64-linux-gnu"
|
||||
PKG3=$(mkpkg hello_arm "$ROOT/examples/hello.bux")
|
||||
if command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then
|
||||
out=$("$BUXC" --quiet --static --release --target aarch64-linux-gnu build "$PKG3" 2>&1) || {
|
||||
echo "$out" >&2
|
||||
exit 1
|
||||
}
|
||||
BIN3="$PKG3/build/hello_arm"
|
||||
[[ -x "$BIN3" ]] || BIN3="$PKG3/build/hello_arm.exe"
|
||||
file_out=$(file "$BIN3")
|
||||
echo "$file_out"
|
||||
echo "$file_out" | grep -qi 'ARM aarch64\|aarch64'
|
||||
echo "$file_out" | grep -qi 'statically linked\|static-pie\|static '
|
||||
echo "PASS: cross aarch64"
|
||||
pass=$((pass+1))
|
||||
else
|
||||
echo "SKIP: aarch64-linux-gnu-gcc not on PATH"
|
||||
fi
|
||||
|
||||
# ── 4) CTFE CRC under minimal runtime ───────────────────────────────────
|
||||
note "ctfe_crc (minimal)"
|
||||
if [[ -f "$ROOT/examples/ctfe_crc.bux" ]]; then
|
||||
PKG4=$(mkpkg ctfe_crc "$ROOT/examples/ctfe_crc.bux")
|
||||
export BUX_RUNTIME=minimal
|
||||
out=$("$BUXC" --quiet run "$PKG4" 2>&1) || { echo "$out" >&2; exit 1; }
|
||||
echo "$out"
|
||||
echo "$out" | grep -q 'PASS ctfe_crc'
|
||||
echo "PASS: ctfe_crc"
|
||||
pass=$((pass+1))
|
||||
unset BUX_RUNTIME
|
||||
else
|
||||
echo "SKIP: examples/ctfe_crc.bux missing"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "smoke_linux_targets: $pass checks passed"
|
||||
echo "PASS: smoke_linux_targets"
|
||||
Executable
+86
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env bash
|
||||
# Session 79 — musl fully-static path (skips if no musl-gcc / zig musl target).
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
export BUX_STDLIB="${BUX_STDLIB:-$ROOT/lib}"
|
||||
|
||||
if [[ ! -x "$ROOT/buxc" ]]; then
|
||||
(cd "$ROOT" && make build)
|
||||
fi
|
||||
|
||||
pick_cc() {
|
||||
if command -v musl-gcc >/dev/null 2>&1; then
|
||||
echo "musl-gcc"
|
||||
return
|
||||
fi
|
||||
if command -v x86_64-linux-musl-gcc >/dev/null 2>&1; then
|
||||
echo "x86_64-linux-musl-gcc"
|
||||
return
|
||||
fi
|
||||
if command -v zig >/dev/null 2>&1; then
|
||||
# zig cc -target x86_64-linux-musl acts as a C compiler when BUX_CC is a wrapper
|
||||
echo "zig-musl"
|
||||
return
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
CC_KIND=$(pick_cc)
|
||||
if [[ -z "$CC_KIND" ]]; then
|
||||
echo "SKIP: no musl-gcc / zig on PATH (install musl-tools or zig for Alpine static)"
|
||||
echo "PASS: smoke_musl_static (skipped)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
mkdir -p "$TMP/src"
|
||||
cp -a "$ROOT/rt" "$TMP/"
|
||||
cp "$ROOT/examples/hello.bux" "$TMP/src/Main.bux"
|
||||
cat > "$TMP/bux.toml" <<'EOF'
|
||||
[Package]
|
||||
Name = "hello_musl"
|
||||
Version = "0.1.0"
|
||||
Type = "bin"
|
||||
|
||||
[Build]
|
||||
Output = "Bin"
|
||||
EOF
|
||||
|
||||
export BUX_RUNTIME=minimal
|
||||
if [[ "$CC_KIND" == "zig-musl" ]]; then
|
||||
# Wrapper so buxc invokes zig as cc
|
||||
cat > "$TMP/zigcc" <<'EOF'
|
||||
#!/bin/sh
|
||||
exec zig cc -target x86_64-linux-musl "$@"
|
||||
EOF
|
||||
chmod +x "$TMP/zigcc"
|
||||
export BUX_CC="$TMP/zigcc"
|
||||
else
|
||||
export BUX_CC="$CC_KIND"
|
||||
fi
|
||||
|
||||
echo "=== musl static hello (BUX_CC=$BUX_CC) ==="
|
||||
"$ROOT/buxc" --quiet --static --release build "$TMP"
|
||||
BIN="$TMP/build/hello_musl"
|
||||
file "$BIN"
|
||||
# musl static often reports "statically linked"
|
||||
if file "$BIN" | grep -qi 'statically linked\|static-pie\|static '; then
|
||||
echo "static: ok"
|
||||
else
|
||||
# some musl toolchains still produce dynamic musl — accept if ldd mentions musl
|
||||
if command -v ldd >/dev/null 2>&1 && ldd "$BIN" 2>&1 | grep -qi musl; then
|
||||
echo "dynamic musl: ok"
|
||||
else
|
||||
echo "WARN: could not confirm musl/static; file output above"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Run only if host can execute
|
||||
if "$BIN" 2>/dev/null | grep -q 'Hello, Bux!'; then
|
||||
echo "run: ok"
|
||||
else
|
||||
echo "run: skipped or failed (cross?)"
|
||||
fi
|
||||
|
||||
echo "PASS: smoke_musl_static"
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
# Session 80 — Nexus mTLS: reject no-client-cert; accept with client cert.
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
export BUX_STDLIB="${BUX_STDLIB:-$ROOT/lib}"
|
||||
PORT="${NEXUS_PORT:-18444}"
|
||||
BIND="${NEXUS_BIND:-127.0.0.1}"
|
||||
|
||||
if [[ ! -x "$ROOT/apps/nexus/build/nexus" ]]; then
|
||||
(cd "$ROOT/apps/nexus" && "$ROOT/buxc" --release build)
|
||||
fi
|
||||
NEXUS="$ROOT/apps/nexus/build/nexus"
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP"; kill $NPID 2>/dev/null || true' EXIT
|
||||
|
||||
# CA + server + client certs
|
||||
openssl req -x509 -newkey rsa:2048 -nodes -keyout "$TMP/ca.key" -out "$TMP/ca.pem" \
|
||||
-days 1 -subj "/CN=TestCA" 2>/dev/null
|
||||
openssl req -newkey rsa:2048 -nodes -keyout "$TMP/server.key" -out "$TMP/server.csr" \
|
||||
-subj "/CN=localhost" 2>/dev/null
|
||||
openssl x509 -req -in "$TMP/server.csr" -CA "$TMP/ca.pem" -CAkey "$TMP/ca.key" \
|
||||
-CAcreateserial -out "$TMP/server.pem" -days 1 2>/dev/null
|
||||
openssl req -newkey rsa:2048 -nodes -keyout "$TMP/client.key" -out "$TMP/client.csr" \
|
||||
-subj "/CN=client" 2>/dev/null
|
||||
openssl x509 -req -in "$TMP/client.csr" -CA "$TMP/ca.pem" -CAkey "$TMP/ca.key" \
|
||||
-CAcreateserial -out "$TMP/client.pem" -days 1 2>/dev/null
|
||||
|
||||
NEXUS_PORT="$PORT" NEXUS_BIND="$BIND" NEXUS_WORKERS=2 NEXUS_ACCESS_LOG=0 \
|
||||
NEXUS_TLS=1 NEXUS_TLS_CERT="$TMP/server.pem" NEXUS_TLS_KEY="$TMP/server.key" \
|
||||
NEXUS_TLS_CLIENT_CA="$TMP/ca.pem" \
|
||||
"$NEXUS" >"$TMP/nexus.log" 2>&1 &
|
||||
NPID=$!
|
||||
sleep 0.7
|
||||
|
||||
if ! kill -0 "$NPID" 2>/dev/null; then
|
||||
echo "error: nexus failed" >&2
|
||||
cat "$TMP/nexus.log" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Without client cert → fail
|
||||
if curl -sk --max-time 3 "https://${BIND}:${PORT}/api/health" -o /dev/null 2>/dev/null; then
|
||||
# some curl versions might still get empty; check exit code
|
||||
:
|
||||
fi
|
||||
set +e
|
||||
curl -sk --max-time 3 "https://${BIND}:${PORT}/api/health" >/dev/null 2>&1
|
||||
noclient=$?
|
||||
set -e
|
||||
if [[ $noclient -eq 0 ]]; then
|
||||
# Try again more strictly — handshake should fail
|
||||
if curl -sk --max-time 3 "https://${BIND}:${PORT}/api/health" 2>&1 | grep -q status; then
|
||||
echo "error: mTLS allowed request without client cert" >&2
|
||||
cat "$TMP/nexus.log" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo "no-client: rejected (curl exit $noclient)"
|
||||
|
||||
# With client cert → ok
|
||||
body=$(curl -sk --max-time 5 \
|
||||
--cert "$TMP/client.pem" --key "$TMP/client.key" \
|
||||
--cacert "$TMP/ca.pem" \
|
||||
"https://${BIND}:${PORT}/api/health")
|
||||
echo "$body"
|
||||
echo "$body" | grep -q '"status":"ok"'
|
||||
echo "$body" | grep -q '0.6.0'
|
||||
|
||||
kill -TERM "$NPID" 2>/dev/null || true
|
||||
sleep 0.6
|
||||
kill -0 "$NPID" 2>/dev/null && kill -9 "$NPID" 2>/dev/null || true
|
||||
|
||||
grep -q 'mTLS' "$TMP/nexus.log" || grep -q 'client certificates' "$TMP/nexus.log"
|
||||
|
||||
echo "PASS: smoke_nexus_mtls"
|
||||
Executable
+58
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
# Session 78 — Nexus HTTPS smoke (self-signed cert + curl -k).
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
export BUX_STDLIB="${BUX_STDLIB:-$ROOT/lib}"
|
||||
PORT="${NEXUS_PORT:-18443}"
|
||||
BIND="${NEXUS_BIND:-127.0.0.1}"
|
||||
|
||||
if [[ ! -x "$ROOT/apps/nexus/build/nexus" ]]; then
|
||||
(cd "$ROOT/apps/nexus" && "$ROOT/buxc" --release build)
|
||||
fi
|
||||
NEXUS="$ROOT/apps/nexus/build/nexus"
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP"; kill $NPID 2>/dev/null || true' EXIT
|
||||
|
||||
# Self-signed cert (10y, CN=localhost)
|
||||
openssl req -x509 -newkey rsa:2048 -nodes \
|
||||
-keyout "$TMP/key.pem" -out "$TMP/cert.pem" \
|
||||
-days 3650 -subj "/CN=localhost" 2>/dev/null
|
||||
|
||||
NEXUS_PORT="$PORT" NEXUS_BIND="$BIND" NEXUS_WORKERS=2 NEXUS_ACCESS_LOG=1 \
|
||||
NEXUS_TLS=1 NEXUS_TLS_CERT="$TMP/cert.pem" NEXUS_TLS_KEY="$TMP/key.pem" \
|
||||
"$NEXUS" >"$TMP/nexus.log" 2>&1 &
|
||||
NPID=$!
|
||||
sleep 0.6
|
||||
|
||||
if ! kill -0 "$NPID" 2>/dev/null; then
|
||||
echo "error: nexus failed to start" >&2
|
||||
cat "$TMP/nexus.log" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
body=$(curl -sk --max-time 5 "https://${BIND}:${PORT}/api/health")
|
||||
echo "$body"
|
||||
echo "$body" | grep -q '"status":"ok"'
|
||||
echo "$body" | grep -q '0.6.0'
|
||||
|
||||
info=$(curl -sk --max-time 5 "https://${BIND}:${PORT}/api/info")
|
||||
echo "$info" | grep -q 'TLS'
|
||||
|
||||
kill -TERM "$NPID" 2>/dev/null || true
|
||||
sleep 0.8
|
||||
if kill -0 "$NPID" 2>/dev/null; then
|
||||
kill -9 "$NPID" 2>/dev/null || true
|
||||
echo "WARN: forced kill after SIGTERM"
|
||||
else
|
||||
echo "PASS: SIGTERM exit"
|
||||
fi
|
||||
|
||||
grep -q 'Listening on https://' "$TMP/nexus.log" || {
|
||||
echo "error: expected https banner" >&2
|
||||
cat "$TMP/nexus.log" >&2
|
||||
exit 1
|
||||
}
|
||||
grep -q 'GET /api/health' "$TMP/nexus.log" || true
|
||||
|
||||
echo "PASS: smoke_nexus_tls"
|
||||
+93
-10
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# Smoke: registry search + add + install + build with greet package (E.1)
|
||||
# Also verifies HTTP-fetchable registry index (E.1b).
|
||||
# Smoke: registry search + add + install + lock reproducibility + HTTPS (E.1 / session 79)
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
BUXC="$ROOT/buxc"
|
||||
@@ -12,11 +11,16 @@ fi
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
HTTP_PID=""
|
||||
HTTPS_PID=""
|
||||
cleanup() {
|
||||
if [[ -n "$HTTP_PID" ]]; then
|
||||
kill "$HTTP_PID" 2>/dev/null || true
|
||||
wait "$HTTP_PID" 2>/dev/null || true
|
||||
fi
|
||||
if [[ -n "$HTTPS_PID" ]]; then
|
||||
kill "$HTTPS_PID" 2>/dev/null || true
|
||||
wait "$HTTPS_PID" 2>/dev/null || true
|
||||
fi
|
||||
rm -rf "$TMP"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
@@ -60,20 +64,67 @@ echo "=== bux add greet ==="
|
||||
grep -q greet bux.toml
|
||||
cat bux.toml
|
||||
|
||||
echo "=== bux install ==="
|
||||
echo "=== bux install (with checksum) ==="
|
||||
"$BUXC" install
|
||||
test -f bux.lock
|
||||
grep -q greet bux.lock
|
||||
grep -q Checksum bux.lock
|
||||
cat bux.lock
|
||||
cp bux.lock "$TMP/lock1"
|
||||
|
||||
echo "=== lock reproducibility (second install) ==="
|
||||
"$BUXC" install
|
||||
# Source path + version + checksum must match
|
||||
diff -u "$TMP/lock1" bux.lock
|
||||
|
||||
echo "=== bux install --locked ==="
|
||||
"$BUXC" install --locked
|
||||
|
||||
echo "=== install --locked fails without lock ==="
|
||||
rm -f bux.lock
|
||||
if "$BUXC" install --locked 2>"$TMP/locked_err"; then
|
||||
echo "error: expected --locked to fail without lock" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -qi 'missing\|locked' "$TMP/locked_err"
|
||||
"$BUXC" install
|
||||
test -f bux.lock
|
||||
|
||||
echo "=== checksum mismatch detected ==="
|
||||
# Corrupt checksum
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
p = Path("bux.lock")
|
||||
t = p.read_text()
|
||||
# flip last hex nibble of Checksum line if present
|
||||
lines = []
|
||||
for line in t.splitlines():
|
||||
if line.startswith("Checksum"):
|
||||
# Checksum = "abcdef..."
|
||||
import re
|
||||
m = re.search(r'"([0-9a-fA-F]+)"', line)
|
||||
if m:
|
||||
h = m.group(1)
|
||||
h2 = h[:-1] + ("0" if h[-1] != "0" else "1")
|
||||
line = f'Checksum = "{h2}"'
|
||||
lines.append(line)
|
||||
p.write_text("\n".join(lines) + "\n")
|
||||
PY
|
||||
if "$BUXC" install --locked 2>"$TMP/csum_err"; then
|
||||
echo "error: expected checksum mismatch failure" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -qi 'checksum' "$TMP/csum_err"
|
||||
# restore good lock
|
||||
"$BUXC" install >/dev/null
|
||||
|
||||
echo "=== bux run ==="
|
||||
"$BUXC" run . | tee "$TMP/run.out"
|
||||
grep -q "Hello, Bux!" "$TMP/run.out"
|
||||
|
||||
# --- HTTP registry index ---
|
||||
echo "=== HTTP registry index (E.1b) ==="
|
||||
echo "=== HTTP registry index ==="
|
||||
mkdir -p "$TMP/http"
|
||||
# Absolute file: path so resolution works after download to ~/.bux/cache
|
||||
cat > "$TMP/http/registry.toml" <<EOF
|
||||
[[package]]
|
||||
name = "greet"
|
||||
@@ -82,14 +133,12 @@ source = "file:$ROOT/registry/packages/greet"
|
||||
description = "HTTP-served greet package"
|
||||
EOF
|
||||
|
||||
# Free port via python
|
||||
PORT=$(python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1",0)); print(s.getsockname()[1]); s.close()')
|
||||
(
|
||||
cd "$TMP/http"
|
||||
python3 -m http.server "$PORT" --bind 127.0.0.1 >/dev/null 2>&1
|
||||
) &
|
||||
HTTP_PID=$!
|
||||
# Wait until server responds
|
||||
for _ in 1 2 3 4 5 6 7 8 9 10; do
|
||||
if curl -fsS "http://127.0.0.1:${PORT}/registry.toml" >/dev/null 2>&1; then
|
||||
break
|
||||
@@ -101,9 +150,43 @@ export BUX_REGISTRY="http://127.0.0.1:${PORT}/registry.toml"
|
||||
export BUX_REGISTRY_REFRESH=1
|
||||
"$BUXC" search greet | tee "$TMP/http_search.out"
|
||||
grep -q greet "$TMP/http_search.out"
|
||||
grep -q "http://127.0.0.1" "$TMP/http_search.out" || grep -q "cached" "$TMP/http_search.out"
|
||||
unset BUX_REGISTRY_REFRESH
|
||||
# Second search should hit cache without refresh
|
||||
"$BUXC" search greet | grep -q greet
|
||||
|
||||
echo "PASS: registry smoke (local + HTTP search + add + install + build)"
|
||||
# --- HTTPS registry (self-signed) ---
|
||||
echo "=== HTTPS registry index (self-signed + BUX_REGISTRY_INSECURE) ==="
|
||||
mkdir -p "$TMP/https"
|
||||
cp "$TMP/http/registry.toml" "$TMP/https/registry.toml"
|
||||
openssl req -x509 -newkey rsa:2048 -nodes \
|
||||
-keyout "$TMP/https/key.pem" -out "$TMP/https/cert.pem" \
|
||||
-days 1 -subj "/CN=localhost" 2>/dev/null
|
||||
|
||||
SPORT=$(python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1",0)); print(s.getsockname()[1]); s.close()')
|
||||
python3 - <<PY &
|
||||
import http.server, ssl, os
|
||||
os.chdir("$TMP/https")
|
||||
httpd = http.server.HTTPServer(("127.0.0.1", $SPORT), http.server.SimpleHTTPRequestHandler)
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
ctx.load_cert_chain("$TMP/https/cert.pem", "$TMP/https/key.pem")
|
||||
httpd.socket = ctx.wrap_socket(httpd.socket, server_side=True)
|
||||
httpd.serve_forever()
|
||||
PY
|
||||
HTTPS_PID=$!
|
||||
for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
|
||||
if curl -kfsS "https://127.0.0.1:${SPORT}/registry.toml" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 0.15
|
||||
done
|
||||
|
||||
export BUX_REGISTRY="https://127.0.0.1:${SPORT}/registry.toml"
|
||||
export BUX_REGISTRY_REFRESH=1
|
||||
export BUX_REGISTRY_INSECURE=1
|
||||
"$BUXC" search greet | tee "$TMP/https_search.out"
|
||||
grep -q greet "$TMP/https_search.out"
|
||||
grep -q "https://" "$TMP/https_search.out" || grep -q "cached" "$TMP/https_search.out"
|
||||
unset BUX_REGISTRY_INSECURE
|
||||
unset BUX_REGISTRY_REFRESH
|
||||
unset BUX_REGISTRY
|
||||
|
||||
echo "PASS: registry smoke (local + lock/checksum + locked + HTTP + HTTPS)"
|
||||
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
# Session 80 — selfhost buxc2 install + --locked checksum parity
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
export BUX_STDLIB="${BUX_STDLIB:-$ROOT/lib}"
|
||||
|
||||
if [[ ! -x "$ROOT/build/selfhost/build/buxc2" ]]; then
|
||||
(cd "$ROOT" && make selfhost)
|
||||
fi
|
||||
BUXC2="$ROOT/build/selfhost/build/buxc2"
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
mkdir -p "$TMP/app/src" "$TMP/libpkg/src"
|
||||
# mini lib package
|
||||
cat > "$TMP/libpkg/bux.toml" <<'EOF'
|
||||
[Package]
|
||||
Name = "mini"
|
||||
Version = "1.2.3"
|
||||
Type = "lib"
|
||||
EOF
|
||||
cat > "$TMP/libpkg/src/Lib.bux" <<'EOF'
|
||||
func Mini_Version() -> String { return "1.2.3"; }
|
||||
EOF
|
||||
|
||||
cat > "$TMP/app/bux.toml" <<EOF
|
||||
[Package]
|
||||
Name = "app"
|
||||
Version = "0.1.0"
|
||||
Type = "bin"
|
||||
|
||||
[Build]
|
||||
Output = "Bin"
|
||||
|
||||
[Dependencies]
|
||||
mini = { Path = "$TMP/libpkg" }
|
||||
EOF
|
||||
cat > "$TMP/app/src/Main.bux" <<'EOF'
|
||||
func Main() -> int { return 0; }
|
||||
EOF
|
||||
|
||||
cd "$TMP/app"
|
||||
echo "=== buxc2 install ==="
|
||||
"$BUXC2" install .
|
||||
test -f bux.lock
|
||||
grep -q mini bux.lock
|
||||
grep -q Checksum bux.lock
|
||||
cat bux.lock
|
||||
cp bux.lock "$TMP/lock1"
|
||||
|
||||
echo "=== install reproducible ==="
|
||||
"$BUXC2" install .
|
||||
diff -u "$TMP/lock1" bux.lock
|
||||
|
||||
echo "=== install --locked ==="
|
||||
"$BUXC2" install --locked .
|
||||
|
||||
echo "=== --locked fails without lock ==="
|
||||
rm bux.lock
|
||||
if "$BUXC2" install --locked . >"$TMP/err" 2>&1; then
|
||||
echo "error: expected failure" >&2
|
||||
cat "$TMP/err" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -qi 'missing\|locked' "$TMP/err"
|
||||
"$BUXC2" install . >/dev/null
|
||||
|
||||
echo "=== checksum mismatch ==="
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import re
|
||||
p = Path("bux.lock")
|
||||
t = p.read_text()
|
||||
lines = []
|
||||
for line in t.splitlines():
|
||||
if line.startswith("Checksum"):
|
||||
m = re.search(r'"([0-9a-fA-F]+)"', line)
|
||||
if m:
|
||||
h = m.group(1)
|
||||
h2 = h[:-1] + ("0" if h[-1] != "0" else "1")
|
||||
line = f'Checksum = "{h2}"'
|
||||
lines.append(line)
|
||||
p.write_text("\n".join(lines) + "\n")
|
||||
PY
|
||||
if "$BUXC2" install --locked . >"$TMP/err2" 2>&1; then
|
||||
echo "error: expected checksum fail" >&2
|
||||
cat "$TMP/err2" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -qi checksum "$TMP/err2"
|
||||
|
||||
echo "PASS: smoke_selfhost_install"
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env bash
|
||||
# Session 81 — selfhost registry: search / add by name / install / HTTP index
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
export BUX_STDLIB="${BUX_STDLIB:-$ROOT/lib}"
|
||||
export BUX_REGISTRY="$ROOT/config/registry.toml"
|
||||
|
||||
if [[ ! -x "$ROOT/build/selfhost/build/buxc2" ]]; then
|
||||
(cd "$ROOT" && make selfhost)
|
||||
fi
|
||||
BUXC2="$ROOT/build/selfhost/build/buxc2"
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
HTTP_PID=""
|
||||
cleanup() {
|
||||
[[ -n "$HTTP_PID" ]] && kill "$HTTP_PID" 2>/dev/null || true
|
||||
rm -rf "$TMP"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "=== buxc2 search greet (local) ==="
|
||||
"$BUXC2" search greet | tee "$TMP/s.out"
|
||||
grep -q greet "$TMP/s.out"
|
||||
|
||||
echo "=== consumer + add greet (registry) ==="
|
||||
mkdir -p "$TMP/app/src"
|
||||
cat > "$TMP/app/bux.toml" <<'EOF'
|
||||
[Package]
|
||||
Name = "reg_consumer"
|
||||
Version = "0.1.0"
|
||||
Type = "bin"
|
||||
|
||||
[Build]
|
||||
Output = "Bin"
|
||||
EOF
|
||||
cat > "$TMP/app/src/Main.bux" <<'EOF'
|
||||
import Std::Io::{PrintLine};
|
||||
import Std::String::{String_Eq};
|
||||
import Std::Test::{Test_AssertTrue, Test_Pass};
|
||||
|
||||
func Main() -> int {
|
||||
let msg: String = Greet_Hello("Bux");
|
||||
Test_AssertTrue(String_Eq(msg, "Hello, Bux!"));
|
||||
PrintLine(msg);
|
||||
Test_Pass("reg_consumer");
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
cd "$TMP/app"
|
||||
"$BUXC2" add greet | tee "$TMP/add.out"
|
||||
grep -q greet bux.toml
|
||||
"$BUXC2" install .
|
||||
test -f bux.lock
|
||||
grep -q Checksum bux.lock
|
||||
"$BUXC2" install --locked .
|
||||
|
||||
echo "=== buxc2 run with registry dep ==="
|
||||
"$BUXC2" run . | tee "$TMP/run.out"
|
||||
grep -q "Hello, Bux!" "$TMP/run.out"
|
||||
|
||||
echo "=== HTTP registry search ==="
|
||||
mkdir -p "$TMP/http"
|
||||
cat > "$TMP/http/registry.toml" <<EOF
|
||||
[[package]]
|
||||
name = "greet"
|
||||
version = "0.1.1"
|
||||
source = "file:$ROOT/registry/packages/greet"
|
||||
description = "HTTP-served greet (selfhost)"
|
||||
EOF
|
||||
PORT=$(python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1",0)); print(s.getsockname()[1]); s.close()')
|
||||
python3 -m http.server "$PORT" --bind 127.0.0.1 -d "$TMP/http" >/dev/null 2>&1 &
|
||||
HTTP_PID=$!
|
||||
for _ in 1 2 3 4 5 6 7 8 9 10; do
|
||||
curl -fsS "http://127.0.0.1:${PORT}/registry.toml" >/dev/null 2>&1 && break
|
||||
sleep 0.1
|
||||
done
|
||||
export BUX_REGISTRY="http://127.0.0.1:${PORT}/registry.toml"
|
||||
export BUX_REGISTRY_REFRESH=1
|
||||
"$BUXC2" search greet | tee "$TMP/http.out"
|
||||
grep -q greet "$TMP/http.out"
|
||||
grep -q "http://" "$TMP/http.out" || grep -q cached "$TMP/http.out"
|
||||
|
||||
echo "PASS: smoke_selfhost_registry"
|
||||
Reference in New Issue
Block a user