|
| 1 | +#!/usr/bin/env bash |
| 2 | +# A supervised worker that produces a valid MCP error response is healthy. |
| 3 | +# The CLI may exit nonzero when presenting that error to a human, but the worker |
| 4 | +# transport must exit zero so its parent reads the response instead of inventing |
| 5 | +# an exit_nonzero "crashed on a file" diagnosis. |
| 6 | +set -euo pipefail |
| 7 | + |
| 8 | +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" |
| 9 | +BINARY="${ROOT}/build/c/codebase-memory-mcp" |
| 10 | +if [[ ! -x "${BINARY}" && -x "${BINARY}.exe" ]]; then |
| 11 | + BINARY="${BINARY}.exe" |
| 12 | +fi |
| 13 | + |
| 14 | +if [[ ! -x "${BINARY}" ]]; then |
| 15 | + echo "missing binary: ${BINARY}" >&2 |
| 16 | + exit 2 |
| 17 | +fi |
| 18 | + |
| 19 | +if command -v shasum >/dev/null 2>&1; then |
| 20 | + BUILD_FINGERPRINT="$(shasum -a 256 "${BINARY}" | awk '{print $1}')" |
| 21 | +elif command -v sha256sum >/dev/null 2>&1; then |
| 22 | + BUILD_FINGERPRINT="$(sha256sum "${BINARY}" | awk '{print $1}')" |
| 23 | +elif command -v openssl >/dev/null 2>&1; then |
| 24 | + BUILD_FINGERPRINT="$(openssl dgst -sha256 "${BINARY}" | awk '{print $NF}')" |
| 25 | +else |
| 26 | + echo "no SHA-256 command available for worker build binding" >&2 |
| 27 | + exit 2 |
| 28 | +fi |
| 29 | +if [[ ! "${BUILD_FINGERPRINT}" =~ ^[0-9a-f]{64}$ ]]; then |
| 30 | + echo "invalid worker build fingerprint: ${BUILD_FINGERPRINT}" >&2 |
| 31 | + exit 2 |
| 32 | +fi |
| 33 | + |
| 34 | +tmpdir="$(mktemp -d)" |
| 35 | +cleanup() { |
| 36 | + CBM_CACHE_DIR="${tmpdir}/cache-supervisor" \ |
| 37 | + "${BINARY}" daemon stop >/dev/null 2>&1 || true |
| 38 | + rm -rf "${tmpdir}" |
| 39 | +} |
| 40 | +trap cleanup EXIT |
| 41 | + |
| 42 | +missing="${tmpdir}/repository-does-not-exist" |
| 43 | +response="${tmpdir}/worker.response" |
| 44 | +args="{\"repo_path\":\"${missing}\",\"mode\":\"fast\"}" |
| 45 | + |
| 46 | +if ! CBM_CACHE_DIR="${tmpdir}/cache-worker" \ |
| 47 | + "${BINARY}" cli --index-worker \ |
| 48 | + --index-worker-build "${BUILD_FINGERPRINT}" \ |
| 49 | + index_repository "${args}" \ |
| 50 | + --response-out "${response}" >"${tmpdir}/worker.out" 2>"${tmpdir}/worker.err"; then |
| 51 | + echo "worker treated a delivered MCP error as a process failure" >&2 |
| 52 | + cat "${tmpdir}/worker.err" >&2 |
| 53 | + exit 1 |
| 54 | +fi |
| 55 | + |
| 56 | +if [[ ! -s "${response}" ]] || ! grep -q 'Pipeline failed' "${response}"; then |
| 57 | + echo "worker did not deliver the underlying pipeline error" >&2 |
| 58 | + cat "${response}" 2>/dev/null >&2 || true |
| 59 | + exit 1 |
| 60 | +fi |
| 61 | + |
| 62 | +set +e |
| 63 | +CBM_CACHE_DIR="${tmpdir}/cache-supervisor" \ |
| 64 | + "${BINARY}" cli index_repository --repo-path "${missing}" --mode fast \ |
| 65 | + >"${tmpdir}/supervisor.out" 2>"${tmpdir}/supervisor.err" |
| 66 | +cli_rc=$? |
| 67 | +set -e |
| 68 | + |
| 69 | +if [[ ${cli_rc} -eq 0 ]]; then |
| 70 | + echo "human-facing CLI unexpectedly accepted an indexing error" >&2 |
| 71 | + exit 1 |
| 72 | +fi |
| 73 | +if grep -q 'crashed on a file' "${tmpdir}/supervisor.out" "${tmpdir}/supervisor.err"; then |
| 74 | + echo "supervisor replaced a valid tool error with a false crash diagnosis" >&2 |
| 75 | + exit 1 |
| 76 | +fi |
| 77 | +if ! grep -q 'Pipeline failed' "${tmpdir}/supervisor.out" "${tmpdir}/supervisor.err"; then |
| 78 | + echo "supervisor did not preserve the worker's pipeline error" >&2 |
| 79 | + cat "${tmpdir}/supervisor.out" >&2 |
| 80 | + cat "${tmpdir}/supervisor.err" >&2 |
| 81 | + exit 1 |
| 82 | +fi |
| 83 | + |
| 84 | +echo "ok: worker MCP errors remain tool errors, not process crashes" |
0 commit comments