feat: add /deploy-plugins webhook route + deploy-plugins script
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled

This commit is contained in:
2026-08-17 00:05:55 +02:00
parent eca81ae9af
commit 22fe1526ca
42 changed files with 342 additions and 8156 deletions

57
scripts/deploy-plugins.sh Normal file
View File

@@ -0,0 +1,57 @@
#!/bin/sh
# Oikos-plugins deploy script — triggered by Gitea webhook on push to dtoro/oikos-plugins.
# Runs on mac-mini via launchd unit running cmd/webhook (route: /deploy-plugins).
set -e
REPO_DIR="${REPO_DIR:-$HOME/Projects/oikos}"
PLUGIN_DIR="${PLUGIN_DIR:-$HOME/oikos-plugins}"
DSH_DIR="${DSH_DIR:-$HOME/Projects/deepseek-harness}"
PROFILE_DIR="${PROFILE_DIR:-$HOME/.dsh/profiles/web}"
PORT="${PORT:-3080}"
LOCKDIR="${LOCKDIR:-/tmp/oikos-plugins-deploy.lock}"
acquire_lock() {
if mkdir "$LOCKDIR" 2>/dev/null; then
trap 'rm -rf "$LOCKDIR"' EXIT
return 0
fi
echo "deploy already running, skipping"
exit 0
}
acquire_lock
echo "=== oikos-plugins deploy started ==="
# 1. Pull latest
if [ ! -d "$PLUGIN_DIR" ]; then
git clone gitea@git-ssh.hubris.network:dtoro/oikos-plugins.git "$PLUGIN_DIR"
fi
cd "$PLUGIN_DIR"
git fetch origin master
git reset --hard origin/master
# 2. Symlink packages into dsh profile
for pkg in ui mcp-scope session-summary bundle evals; do
name=$(node -e "console.log(JSON.parse(require('fs').readFileSync('$pkg/package.json')).name)")
ln -sf "$PLUGIN_DIR/$pkg" "$PROFILE_DIR/node_modules/$name"
echo "linked $name"
done
# 3. Build UI client bundle (needs dsh workspace for tsdown)
cd "$DSH_DIR"
pnpm install --filter @deepseek-ai/dsh-oikos-ui --frozen-lockfile 2>&1
cd "$PLUGIN_DIR/ui"
DSH_BUILD_FACE=client npx tsdown --config tsdown.config.ts 2>&1
echo "UI bundle built"
# 4. Restart dsh
DASHBOARD_PID=$(pgrep -f 'dsh.*--port.*3080' 2>/dev/null || true)
if [ -n "$DASHBOARD_PID" ]; then
kill "$DASHBOARD_PID" 2>/dev/null || true
sleep 2
fi
cd "$DSH_DIR"
nohup pnpm dsh --profile web --patch /tmp/oikos-mcp-patch.yml --port "$PORT" > /tmp/dsh-web.log 2>&1 &
echo "dsh restarted (pid $!)"
echo "=== oikos-plugins deploy complete ==="

View File

@@ -238,7 +238,7 @@ echo "[6/8] prune old image tags (keep 3)"
if [ -n "$OIKOS_VERSION" ]; then
images=$(docker compose --profile "$PROFILE" config --images 2>/dev/null || true)
if [ -z "$images" ]; then
images="oikos-api oikos-scheduler oikos-migrate oikos-seed oikos-nomos"
images="oikos-api oikos-scheduler oikos-migrate oikos-seed"
fi
printf '%s\n' $images | sed 's/:.*//' | grep '^oikos-' | sort -u | while read -r repo; do
docker image ls "$repo" --format '{{.Tag}}' 2>/dev/null | grep '^v' | sort -rV | tail -n +4 | while read -r tag; do

View File

@@ -50,7 +50,10 @@ seed_key() {
}
mcp_token="$(get_container_env api OIKOS_MCP_BEARER_TOKEN)"
openrouter_key="$(get_container_env nomos OPENROUTER_API_KEY)"
# OPENROUTER_API_KEY used to come from the nomos container's env; nomos is
# decommissioned (dsh is the agent runtime now) and reads the key straight
# from Infisical, so seed from the deploying host's environment.
openrouter_key="${OPENROUTER_API_KEY:-}"
webhook_hmac="$(get_container_env api WEBHOOK_HMAC_SECRET 2>/dev/null)"
api_token="$mcp_token"

View File

@@ -1,6 +1,9 @@
#!/bin/sh
# End-to-end verification — Phase 6 acceptance criteria (14 checks).
# End-to-end verification — Phase 6 acceptance criteria (13 checks).
# Run after deploy or cutover. Exit 0 if all pass, 1 on first failure.
# The nomos gateway checks were removed with the nomos decommission
# (plans/2026-08-16-dsh-as-agent-replace-nomos.md section 5); the agent
# runtime is now dsh, which runs outside this compose stack.
set -e
@@ -27,25 +30,16 @@ check "4. Scheduler: check pass" "http://localhost:8090/api/v1/check
check "5. Actuator: executions endpoint" "http://localhost:8090/api/v1/executions" 200
check "6. Learning: patterns endpoint" "http://localhost:8090/api/v1/patterns" 200
check "7. Classifier: risk classes" "http://localhost:8090/api/v1/policy/risk-classes" 200
check "8. Nomos: gateway health" "http://localhost:8092/healthz" 200
check "9. Secrets: backend available" "http://localhost:8090/api/v1/export" 200
check "10. Deploy: events endpoint" "http://localhost:8090/api/v1/events" 200
check "11. Knowledge: content search" "http://localhost:8090/healthz" 200
check "12. Observability: graph endpoint" "http://localhost:8090/api/v1/graph" 200
check "13. Correlation: agent activity" "http://localhost:8090/api/v1/agent-activity" 200
check "14. Cutover: blast radius (authentik)" "http://localhost:8090/healthz" 200
# Additional: blast radius with actual data
echo ""
echo "--- blast radius (authentik) ---"
curl -s "http://localhost:8092/query" \
-H "Content-Type: application/json" \
-d '{"query":"what depends on authentik?"}' \
| jq -r '" entities affected: \(.result | length)"' 2>/dev/null || echo " (skipped)"
check "8. Secrets: backend available" "http://localhost:8090/api/v1/export" 200
check "9. Deploy: events endpoint" "http://localhost:8090/api/v1/events" 200
check "10. Knowledge: content search" "http://localhost:8090/healthz" 200
check "11. Observability: graph endpoint" "http://localhost:8090/api/v1/graph" 200
check "12. Correlation: agent activity" "http://localhost:8090/api/v1/agent-activity" 200
check "13. Cutover: blast radius (authentik)" "http://localhost:8090/healthz" 200
echo ""
if [ "$FAIL" -eq 0 ]; then
echo "=== ALL 14 CHECKS PASSED ==="
echo "=== ALL 13 CHECKS PASSED ==="
exit 0
else
echo "=== SOME CHECKS FAILED ==="