Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2fe5f05
fix(audit): eliminate 20 silent failure patterns across 8 files
hunnibear Feb 20, 2026
8565058
fix(runtime): unblock nats-init bootstrap and gpu profile bring-up
hunnibear Feb 20, 2026
b84fb29
fix(prod): default archon stack to production agent settings
hunnibear Feb 20, 2026
5883bb8
fix(compose): keep nats-init available for default config validation
hunnibear Feb 20, 2026
d987dd5
fix(ci): skip free-disk-space action on self-hosted test runners
hunnibear Feb 20, 2026
2b1db52
fix(ci): isolate pytest service runs to avoid conftest collisions
hunnibear Feb 20, 2026
69deeb8
fix(ci): skip missing service test directories in python lane
hunnibear Feb 20, 2026
94f500d
fix(ci): keep python-tests lane service-only
hunnibear Feb 20, 2026
e4b30f2
fix(common): import timezone for UTC envelope timestamps
hunnibear Feb 20, 2026
5425ecf
fix(tests): make pmoves-yt imports path-safe in CI
hunnibear Feb 20, 2026
87bb1ec
fix(tests): provide load_service_module fixture for agent-zero suite
hunnibear Feb 21, 2026
7fb38d1
fix(agent-zero): stabilize test imports and nats startup hooks
hunnibear Feb 21, 2026
b3cbad2
fix(ci): keep disk cleanup non-blocking on self-hosted tests
hunnibear Feb 21, 2026
b29bf41
fix(tests): stabilize agent-zero suite for isolated CI runs
hunnibear Feb 21, 2026
acbd14c
fix(ci): include repo root in pythonpath for service tests
hunnibear Feb 21, 2026
e2e9cf2
fix(ci): include gateway package path in pytest pythonpath
hunnibear Feb 21, 2026
40e7a1d
fix(tests): isolate gateway chit stubs and align assertions
hunnibear Feb 21, 2026
df9c973
fix(tests): gate live flute audio checks and align provider expectations
hunnibear Feb 21, 2026
d45c6e9
fix(tests): decouple trusted proxy checks from torch/testclient coupling
hunnibear Feb 21, 2026
a290abd
fix(tests): harden hi-rag-v2 stubs for torchless CI
hunnibear Feb 21, 2026
67bec9d
fix(security): catch SSE stream exceptions to prevent stack trace exp…
hunnibear Feb 21, 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
45 changes: 28 additions & 17 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
matrix:
python-version: ['3.11']
env:
PYTHONPATH: pmoves
PYTHONPATH: .:pmoves:pmoves/services/gateway
steps:
- name: Harden Runner
uses: step-security/harden-runner@v2
Expand All @@ -54,6 +54,8 @@ jobs:

- uses: actions/checkout@v4
- name: Free Disk Space (Ubuntu)
if: ${{ runner.environment == 'github-hosted' }}
continue-on-error: true
uses: jlumbroso/free-disk-space@main
with:
tool-cache: false
Expand Down Expand Up @@ -127,19 +129,28 @@ jobs:
PY
- name: Run all service tests
run: |
pytest -q --tb=short --import-mode=importlib --rootdir=. \
pmoves/tests/ \
pmoves/services/publisher/tests \
pmoves/services/pmoves-yt/tests \
pmoves/services/publisher-discord/tests \
pmoves/services/agent-zero/tests \
pmoves/services/channel-monitor/tests \
pmoves/services/chat-relay/tests \
pmoves/services/common/tests \
pmoves/services/gateway/tests \
pmoves/services/flute-gateway/tests \
pmoves/services/hi-rag-gateway/tests \
pmoves/services/hi-rag-gateway-v2/tests \
pmoves/services/jellyfin-bridge/tests \
--ignore=pmoves/services/media-audio/tests \
--ignore=pmoves/services/media-video/tests
test_targets=(
"pmoves/services/publisher/tests"
"pmoves/services/pmoves-yt/tests"
"pmoves/services/publisher-discord/tests"
"pmoves/services/agent-zero/tests"
"pmoves/services/channel-monitor/tests"
"pmoves/services/chat-relay/tests"
"pmoves/services/common/tests"
"pmoves/services/gateway/tests"
"pmoves/services/flute-gateway/tests"
"pmoves/services/hi-rag-gateway/tests"
"pmoves/services/hi-rag-gateway-v2/tests"
"pmoves/services/jellyfin-bridge/tests"
)

for target in "${test_targets[@]}"; do
if [ ! -d "$target" ]; then
echo "Skipping missing test dir: $target"
continue
fi

echo "::group::pytest ${target}"
pytest -q --tb=short --import-mode=importlib --rootdir=. "${target}"
echo "::endgroup::"
done
129 changes: 119 additions & 10 deletions deploy/scripts/deploy-compose.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
#
# deploy-compose.sh
#
# Simple Docker Compose launcher for PMOVES local dev / PBnJ.
# Docker Compose launcher for PMOVES local dev / PBnJ.
# Includes secrets-funnel pre-flight and post-deploy health checks.
#

set -euo pipefail
Expand All @@ -16,21 +17,39 @@ PMOVES_DIR="${MONO_ROOT}/pmoves"
COMPOSE_FILE="${PMOVES_COMPOSE_FILE:-${PMOVES_DIR}/docker-compose.yml}"
PROJECT_NAME="${PMOVES_COMPOSE_PROJECT:-pmoves_local}"

# Health-check endpoints (service:port/path)
HEALTH_ENDPOINTS=(
"agent-zero:8080/healthz"
"archon:8091/healthz"
"jellyfin-bridge:8093/healthz"
"flute-gateway:8055/healthz"
"media-video:8079/healthz"
"extract-worker:8083/healthz"
)
HEALTH_TIMEOUT="${HEALTH_TIMEOUT:-5}"
STRICT="${STRICT:-false}"

usage() {
cat <<EOF
PMOVES Docker Compose deploy script

Usage:
$(basename "$0") {up|down|logs}
$(basename "$0") {up|down|logs|health} [--strict]

Commands:
up Start local stack (detached)
up Start local stack (detached) with pre-flight checks
down Stop stack and remove containers
logs Tail logs for all services
health Check health of running services

Options:
--strict Fail hard if secrets-funnel fails (default: warn and continue)

Env overrides:
PMOVES_COMPOSE_FILE Path to docker-compose file (default: ${COMPOSE_FILE})
PMOVES_COMPOSE_PROJECT Docker Compose project name (default: ${PROJECT_NAME})
HEALTH_TIMEOUT Health check timeout in seconds (default: 5)
SKIP_SECRETS_FUNNEL Set to 1 to skip secrets-funnel pre-flight
EOF
}

Expand All @@ -40,40 +59,119 @@ ensure_compose() {
elif command -v docker-compose >/dev/null 2>&1; then
DOCKER_COMPOSE_BIN=("docker-compose")
else
echo " docker compose or docker-compose is required but not found in PATH" >&2
echo "ERROR: docker compose or docker-compose is required but not found in PATH" >&2
exit 1
fi
}

ensure_files() {
if [ ! -d "${PMOVES_DIR}" ]; then
echo " pmoves/ directory not found at ${PMOVES_DIR}" >&2
echo "ERROR: pmoves/ directory not found at ${PMOVES_DIR}" >&2
exit 1
fi

if [ ! -f "${COMPOSE_FILE}" ]; then
echo "✖ docker-compose file not found: ${COMPOSE_FILE}" >&2
echo "ERROR: docker-compose file not found: ${COMPOSE_FILE}" >&2
exit 1
fi
}

preflight_env() {
# Verify env.shared exists
if [ ! -f "${PMOVES_DIR}/env.shared" ]; then
echo "ERROR: pmoves/env.shared not found." >&2
echo " Run: make -C pmoves secrets-funnel" >&2
exit 1
fi
}

SECRETS_FUNNEL_OK=true

run_secrets_funnel() {
if [ "${SKIP_SECRETS_FUNNEL:-0}" = "1" ]; then
echo " Skipping secrets-funnel (SKIP_SECRETS_FUNNEL=1)"
return 0
fi

if [ -f "${PMOVES_DIR}/Makefile" ] && command -v make >/dev/null 2>&1; then
if make -C "${PMOVES_DIR}" -n secrets-funnel >/dev/null 2>&1; then
echo " Running secrets-funnel..."
if ! make -C "${PMOVES_DIR}" secrets-funnel; then
SECRETS_FUNNEL_OK=false
if [ "${STRICT}" = "true" ]; then
echo "ERROR: secrets-funnel failed (--strict mode)" >&2
exit 1
fi
echo "WARNING: secrets-funnel failed, continuing with existing env files" >&2
fi
fi
fi
}

cmd_health() {
echo " Checking service health..."
local pass=0 fail=0 skip=0
for entry in "${HEALTH_ENDPOINTS[@]}"; do
local svc="${entry%%:*}"
local port_path="${entry#*:}"
local port="${port_path%%/*}"
local path="/${port_path#*/}"

local url="http://127.0.0.1:${port}${path}"
if curl -sf --max-time "${HEALTH_TIMEOUT}" "${url}" >/dev/null 2>&1; then
echo " [PASS] ${svc} (${url})"
((pass++)) || true
else
# Check if container is even running
if "${DOCKER_COMPOSE_BIN[@]}" -f "${COMPOSE_FILE}" -p "${PROJECT_NAME}" ps --format json 2>/dev/null | grep -q "\"${svc}\""; then
echo " [FAIL] ${svc} (${url})"
((fail++)) || true
else
echo " [SKIP] ${svc} (not running)"
((skip++)) || true
fi
fi
done
echo ""
echo " Health: ${pass} pass, ${fail} fail, ${skip} skip"
return "${fail}"
}

cmd_up() {
echo " Starting PMOVES local stack"
echo "=> Starting PMOVES local stack"
echo " Compose file: ${COMPOSE_FILE}"
echo " Project: ${PROJECT_NAME}"

# Pre-flight checks
preflight_env
run_secrets_funnel

echo " Launching containers..."
"${DOCKER_COMPOSE_BIN[@]}" -f "${COMPOSE_FILE}" -p "${PROJECT_NAME}" up -d

echo ""
echo " Waiting 10s for services to initialize..."
sleep 10

# Post-deploy health check (non-fatal)
cmd_health || echo " Some services unhealthy — check logs with: $(basename "$0") logs"

echo ""
if [ "${SECRETS_FUNNEL_OK}" = "false" ]; then
echo " WARNING: secrets-funnel failed during pre-flight"
fi
echo "=> Stack started. Project: ${PROJECT_NAME}"
}

cmd_down() {
echo " Stopping PMOVES local stack"
echo "=> Stopping PMOVES local stack"
echo " Project: ${PROJECT_NAME}"

"${DOCKER_COMPOSE_BIN[@]}" -f "${COMPOSE_FILE}" -p "${PROJECT_NAME}" down
}

cmd_logs() {
echo " Tailing logs for PMOVES local stack"
echo "=> Tailing logs for PMOVES local stack"
echo " Project: ${PROJECT_NAME}"

"${DOCKER_COMPOSE_BIN[@]}" -f "${COMPOSE_FILE}" -p "${PROJECT_NAME}" logs -f
Expand All @@ -87,6 +185,14 @@ main() {

local cmd="$1"; shift || true

# Parse remaining flags
while [ $# -gt 0 ]; do
case "$1" in
--strict) STRICT=true; shift;;
*) echo "Unknown flag: $1" >&2; usage; exit 2;;
esac
done

ensure_compose
ensure_files

Expand All @@ -100,8 +206,11 @@ main() {
logs)
cmd_logs
;;
health)
cmd_health
;;
*)
echo " Unknown command: ${cmd}" >&2
echo "ERROR: Unknown command: ${cmd}" >&2
usage
exit 2
;;
Expand Down
Loading