Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 0 additions & 1 deletion .claude/worktrees/gov-red
Submodule gov-red deleted from 7add7b
1 change: 0 additions & 1 deletion .claude/worktrees/zig-mutex
Submodule zig-mutex deleted from a1517a
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,8 @@ generated/abi/
# Superpowers docs and artefacts (local only)
docs/superpowers/
.superpowers/

# Claude Code scratch worktrees — per-developer checkouts, never shared.
# Two of these were once committed as gitlinks (mode 160000) with no
# .gitmodules, so a fresh clone got two permanently-"modified" empty dirs.
.claude/worktrees/
77 changes: 60 additions & 17 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -261,20 +261,35 @@ init:
# BUILD & COMPILE
# ═══════════════════════════════════════════════════════════════════════════════

# Build all Zig FFI layers (catalogue + all cartridges)
# Build all Zig FFI layers (catalogue + every cartridge in the catalog root)
#
# The bundled cartridges/ tree was retired (canonical source:
# hyperpolymath/boj-server-cartridges). The catalog root defaults to the
# tracked fixture catalogue, as in tests/e2e_full.sh; point
# BOJ_CARTRIDGES_PATH at a fetched cache (scripts/fetch-cartridges.sh) to
# build the full registry.
build *args:
#!/usr/bin/env bash
set -euo pipefail
CARTS="${BOJ_CARTRIDGES_PATH:-tests/fixtures/cartridges}"
echo "Building BoJ catalogue FFI..."
(cd ffi/zig && zig build {{args}})
echo "Building cartridge FFIs..."
echo "Building cartridge FFIs from $CARTS ..."
FAILED=()
for d in cartridges/*/ffi; do
BUILT=0
for d in "$CARTS"/*/ffi; do
[ -f "$d/build.zig" ] || continue
BUILT=$((BUILT + 1))
if ! (cd "$d" && zig build {{args}} 2>&1); then
FAILED+=("$d")
fi
done
if [ "$BUILT" -eq 0 ]; then
echo "WARNING: no cartridge FFI (no */ffi/build.zig) under $CARTS — built the catalogue only."
echo " Populate a cache with scripts/fetch-cartridges.sh and set BOJ_CARTRIDGES_PATH."
else
echo "Attempted $BUILT cartridge FFI build(s)."
fi
if [ ${#FAILED[@]} -gt 0 ]; then
echo "WARNING: ${#FAILED[@]} cartridge FFI(s) failed to build:"
for f in "${FAILED[@]}"; do echo " $f"; done
Expand All @@ -293,8 +308,8 @@ build-watch:
clean:
@echo "Cleaning..."
rm -rf ffi/zig/.zig-cache ffi/zig/zig-out
rm -rf cartridges/*/ffi/.zig-cache cartridges/*/ffi/zig-out
rm -rf src/abi/build cartridges/*/abi/build
rm -rf tests/fixtures/cartridges/*/ffi/.zig-cache tests/fixtures/cartridges/*/ffi/zig-out
rm -rf src/abi/build
rm -rf target/ _build/ build/ dist/ out/

# Deep clean including caches [reversible: rebuild]
Expand All @@ -305,36 +320,51 @@ clean-all: clean
# TEST & QUALITY
# ═══════════════════════════════════════════════════════════════════════════════

# Run all Zig FFI tests (catalogue + all 111 cartridges with build.zig)
# Run all Zig FFI tests (catalogue + every cartridge FFI in the catalog root)
test *args:
#!/usr/bin/env bash
set -euo pipefail
CARTS="${BOJ_CARTRIDGES_PATH:-tests/fixtures/cartridges}"
echo "Running catalogue FFI tests..."
(cd ffi/zig && zig build test)
echo "Running cartridge FFI tests..."
echo "Running cartridge FFI tests from $CARTS ..."
FAILED=()
for d in cartridges/*/ffi; do
RAN=0
for d in "$CARTS"/*/ffi; do
[ -f "$d/build.zig" ] || continue
RAN=$((RAN + 1))
if ! (cd "$d" && zig build test 2>&1); then
FAILED+=("$d")
fi
done
if [ "$RAN" -eq 0 ]; then
echo "FAILED: no cartridge FFI (no */ffi/build.zig) under $CARTS — nothing was tested." >&2
echo " Populate a cache with scripts/fetch-cartridges.sh and set BOJ_CARTRIDGES_PATH." >&2
exit 1
fi
if [ ${#FAILED[@]} -gt 0 ]; then
echo "FAILED: ${#FAILED[@]} cartridge FFI test(s):"
echo "FAILED: ${#FAILED[@]} of $RAN cartridge FFI test(s):"
for f in "${FAILED[@]}"; do echo " $f"; done
exit 1
fi
echo "All FFI tests passed!"
echo "All FFI tests passed ($RAN cartridge FFI(s))!"

# Run tests with verbose output
test-verbose *args:
#!/usr/bin/env bash
set -euo pipefail
CARTS="${BOJ_CARTRIDGES_PATH:-tests/fixtures/cartridges}"
(cd ffi/zig && zig build test -- --verbose)
for d in cartridges/*/ffi; do
RAN=0
for d in "$CARTS"/*/ffi; do
[ -f "$d/build.zig" ] || continue
RAN=$((RAN + 1))
(cd "$d" && zig build test -- --verbose)
done
if [ "$RAN" -eq 0 ]; then
echo "FAILED: no cartridge FFI (no */ffi/build.zig) under $CARTS — nothing was tested." >&2
exit 1
fi

# Smoke test — type-check core ABI + run one FFI test
test-smoke:
Expand Down Expand Up @@ -1313,18 +1343,25 @@ heal:
fi
# --- Clear stale Zig caches ---
echo "Clearing stale Zig caches..."
rm -rf ffi/zig/.zig-cache cartridges/*/ffi/.zig-cache 2>/dev/null || true
rm -rf ffi/zig/.zig-cache tests/fixtures/cartridges/*/ffi/.zig-cache 2>/dev/null || true
HEALED=$((HEALED + 1))
echo " Cleared."
echo ""
# --- Rebuild all FFI layers ---
if command -v zig >/dev/null 2>&1; then
echo "Rebuilding all FFI layers..."
CARTS="${BOJ_CARTRIDGES_PATH:-tests/fixtures/cartridges}"
echo "Rebuilding all FFI layers (cartridge catalog root: $CARTS)..."
(cd ffi/zig && zig build) && echo " Catalogue FFI: OK" || echo " Catalogue FFI: FAILED"
for d in cartridges/*/ffi; do
REBUILT=0
for d in "$CARTS"/*/ffi; do
[ -f "$d/build.zig" ] || continue
REBUILT=$((REBUILT + 1))
(cd "$d" && zig build 2>/dev/null) && echo " $d: OK" || echo " $d: FAILED"
done
if [ "$REBUILT" -eq 0 ]; then
echo " No cartridge FFI under $CARTS — catalogue only."
echo " Populate a cache with scripts/fetch-cartridges.sh and set BOJ_CARTRIDGES_PATH."
fi
HEALED=$((HEALED + 1))
fi
echo ""
Expand Down Expand Up @@ -1361,8 +1398,14 @@ tour:
echo " elixir/ REST server (Plug/Cowboy)"
echo " container/ Stapeln container ecosystem"
echo ""
CART_COUNT=$(ls -d cartridges/*-mcp 2>/dev/null | wc -l)
echo "Current cartridge count: $CART_COUNT"
CARTS="${BOJ_CARTRIDGES_PATH:-tests/fixtures/cartridges}"
CART_COUNT=$(ls -d "$CARTS"/*-mcp 2>/dev/null | wc -l)
if [ "$CART_COUNT" -eq 0 ]; then
echo "Cartridge catalog root $CARTS is empty or absent."
echo " Populate one: scripts/fetch-cartridges.sh; then export BOJ_CARTRIDGES_PATH."
else
echo "Cartridges visible in $CARTS: $CART_COUNT"
fi
echo ""
echo "Quick commands:"
echo " just run Start server (REST 7700, gRPC 7701, GraphQL 7702)"
Expand Down Expand Up @@ -1400,7 +1443,7 @@ help-me:
echo " just tunnel Cloudflare quick tunnel only"
echo ""
echo "TEST & VERIFY:"
echo " just test Run all FFI tests (catalogue + 17 cartridges)"
echo " just test Run all FFI tests (catalogue + cartridge catalog root)"
echo " just test-verbose Run tests with verbose output"
echo " just test-smoke Quick smoke test (ABI check + catalogue test)"
echo " just readiness Component Readiness Grade tests"
Expand Down
3 changes: 2 additions & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ A good vulnerability report helps us understand and reproduce the issue quickly.
[e.g., Command Injection, SSRF, Path Traversal, Privilege Escalation, etc.]

## Affected Component
[e.g., cartridges/browser-mcp/, cartridges/cloudflare/, ffi/zig/src/, mcp-bridge/]
[e.g., ffi/zig/src/, elixir/lib/boj_rest/, mcp-bridge/, or a cartridge in
hyperpolymath/boj-server-cartridges — cartridges are no longer bundled here]

## Affected Versions
[Version range or specific commits]
Expand Down
34 changes: 27 additions & 7 deletions mcp-bridge/lib/generate-offline-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,48 @@
// scripts/fetch-cartridges.sh) for subdirectories matching the *-mcp
// pattern and produces a static OFFLINE_MENU object. This prevents the
// hardcoded menu from going stale as cartridges are added or removed.
// The bundled ../../cartridges tree this used to scan was retired.
//
// The bundled ../../cartridges tree this used to scan was retired, so the
// fallback is the tracked fixture catalogue (as in tests/e2e_full.sh) —
// never a path that cannot exist. Scanning an empty or absent root is a
// hard error: regenerating the menu from nothing would silently blank it.

import { readdirSync, statSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = dirname(fileURLToPath(import.meta.url));
const cartridgesDir =
Deno.env.get("BOJ_CARTRIDGES_PATH") ?? join(__dirname, "../../cartridges");
Deno.env.get("BOJ_CARTRIDGES_PATH") ??
join(__dirname, "../../tests/fixtures/cartridges");

let entries;
try {
const entries = readdirSync(cartridgesDir)
entries = readdirSync(cartridgesDir)
.filter(name => {
const full = join(cartridgesDir, name);
return statSync(full).isDirectory() && name.endsWith("-mcp");
})
.sort();

console.log(`Found ${entries.length} cartridges in ${cartridgesDir}`);
console.log("Cartridges:", entries.join(", "));
console.log("\nUpdate mcp-bridge/lib/offline-menu.js with any new cartridges.");
} catch (err) {
console.error(`Error scanning cartridges directory: ${err.message}`);
console.error(
"Set BOJ_CARTRIDGES_PATH to a catalog root populated by " +
"scripts/fetch-cartridges.sh.",
);
Deno.exit(1);
}

if (entries.length === 0) {
console.error(`No *-mcp cartridges found in ${cartridgesDir}.`);
console.error(
"Refusing to regenerate the offline menu from an empty catalog — " +
"set BOJ_CARTRIDGES_PATH to a populated catalog root " +
"(scripts/fetch-cartridges.sh).",
);
Deno.exit(1);
}

console.log(`Found ${entries.length} cartridges in ${cartridgesDir}`);
console.log("Cartridges:", entries.join(", "));
console.log("\nUpdate mcp-bridge/lib/offline-menu.js with any new cartridges.");
17 changes: 11 additions & 6 deletions mcp-bridge/lib/offline-menu.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 31 additions & 7 deletions scripts/boj-selinux-contexts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,45 @@
# Must be run with sudo. Persists across restorecon / relabels.
#
# Usage: sudo ./scripts/boj-selinux-contexts.sh
#
# The bundled cartridges/ tree was retired (canonical source:
# hyperpolymath/boj-server-cartridges). Cartridge .so files now live under a
# host-local cache populated by scripts/fetch-cartridges.sh, so the cartridge
# rule is written against that cache root rather than against the repo.
#
# Environment:
# BOJ_CARTRIDGES_PATH cartridge cache root (default: $HOME/.boj/cartridges).
# Under sudo, $HOME is root's — pass this explicitly
# (sudo BOJ_CARTRIDGES_PATH=... ./scripts/...) to label
# a cache that belongs to the invoking user.

set -euo pipefail

# Derive repo root from script location
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly BOJ_ROOT="$(dirname "$SCRIPT_DIR")"
readonly CARTRIDGES_ROOT="${BOJ_CARTRIDGES_PATH:-$HOME/.boj/cartridges}"

# SELinux has an equivalency rule: /var/mnt -> /mnt
# semanage fcontext requires the /mnt/... form for rule paths.
# Strip /var prefix if present (semanage needs canonical /mnt paths).
readonly BOJ_ROOT_SEMANAGE="${BOJ_ROOT#/var}"
readonly CARTRIDGES_ROOT_SEMANAGE="${CARTRIDGES_ROOT#/var}"

echo "=== BoJ Server SELinux Context Setup ==="

# 1. Cartridge shared libraries: lib_t
echo "[1/2] Setting fcontext rule: cartridge .so files -> lib_t"
semanage fcontext -a -t lib_t \
"${BOJ_ROOT_SEMANAGE}/cartridges/.*/ffi/zig-out/lib/.*\\.so" 2>/dev/null \
|| semanage fcontext -m -t lib_t \
"${BOJ_ROOT_SEMANAGE}/cartridges/.*/ffi/zig-out/lib/.*\\.so"
if [ -d "$CARTRIDGES_ROOT" ]; then
echo "[1/2] Setting fcontext rule: cartridge .so files -> lib_t ($CARTRIDGES_ROOT)"
semanage fcontext -a -t lib_t \
"${CARTRIDGES_ROOT_SEMANAGE}/.*/ffi/zig-out/lib/.*\\.so" 2>/dev/null \
|| semanage fcontext -m -t lib_t \
"${CARTRIDGES_ROOT_SEMANAGE}/.*/ffi/zig-out/lib/.*\\.so"
else
echo "[1/2] SKIP: no cartridge cache at $CARTRIDGES_ROOT."
echo " Populate one with scripts/fetch-cartridges.sh, or set"
echo " BOJ_CARTRIDGES_PATH, then re-run to label cartridge .so files."
fi

# 2. Core FFI shared libraries: lib_t
echo "[2/2] Setting fcontext rule: core FFI .so files -> lib_t"
Expand All @@ -34,7 +53,12 @@ semanage fcontext -a -t lib_t \

# Apply the contexts
echo "Applying contexts with restorecon..."
restorecon -Rv "${BOJ_ROOT}/cartridges/" 2>&1 || true
if [ -d "$CARTRIDGES_ROOT" ]; then
restorecon -Rv "${CARTRIDGES_ROOT}/" 2>&1 || true
fi
restorecon -Rv "${BOJ_ROOT}/ffi/" 2>&1 || true

echo "=== Done. Verify with: ls -Z ${BOJ_ROOT}/cartridges/database-mcp/ffi/zig-out/lib/ ==="
echo "=== Done. Verify with: ls -Z ${BOJ_ROOT}/ffi/zig/zig-out/lib/ ==="
if [ -d "$CARTRIDGES_ROOT" ]; then
echo "=== and: ls -Z ${CARTRIDGES_ROOT}/*/ffi/zig-out/lib/ ==="
fi
Loading