Files
deepseek-harness/.gitea/workflows/inspect-deployment.yml
T
Ward dfaa1a82fc Inspect deployment: show recent logs and how the state-volume profile is composed
Read-only probe for boot failures: collapsed log tail, the profile package.json and patch layers (key-like values redacted, credentials never read), profile-local bundle packages and the rows they insert. Tooling probe falls back to the image when the container is not running.
2026-09-11 13:42:26 -04:00

103 lines
5.9 KiB
YAML

name: Inspect deployment
# Manual-only: report what the DeepSeek Harness container on the runner host
# (the Unraid box) is actually running — image reference and digest, whether
# that digest is one this repo published, recent logs, how the dsh profile in
# the state volume is composed (bundle layers, user patch layers, profile-local
# plugins), and whether dsh/pnpm are on PATH inside it. Read-only: nothing is
# changed, the state volume is mounted read-only, credential files are never
# read, and any key/token/secret-looking value in a patch file is redacted.
on:
workflow_dispatch:
inputs:
container:
description: Container name to inspect
default: Deepseek
jobs:
inspect:
runs-on: ubuntu-latest
steps:
- name: Locate container
run: |
set -eu
C="${{ inputs.container || 'Deepseek' }}"
if ! docker inspect "$C" > /dev/null 2>&1; then
echo "::error::no container named $C on this host"
echo "== containers on this host whose image mentions deepseek =="
docker ps -a --format '{{.Names}} {{.Image}} {{.Status}}' | grep -i deepseek || echo "(none)"
exit 1
fi
echo "== $C =="
docker inspect --format 'image ref: {{.Config.Image}}' "$C"
docker inspect --format 'image id: {{.Image}}' "$C"
docker inspect --format 'state: {{.State.Status}} (started {{.State.StartedAt}}, restarts {{.RestartCount}}, exit {{.State.ExitCode}})' "$C"
docker inspect --format 'entrypoint: {{json .Config.Entrypoint}}' "$C"
docker inspect --format 'cmd: {{json .Config.Cmd}}' "$C"
docker inspect --format 'user: {{json .Config.User}}' "$C"
docker inspect --format 'mounts: {{range .Mounts}}{{.Source}} -> {{.Destination}}; {{end}}' "$C"
docker inspect --format 'env: {{range .Config.Env}}{{.}} {{end}}' "$C" | sed -E 's/(KEY|TOKEN|SECRET|PASSWORD)=[^ ]*/\1=<redacted>/g'
IMG=$(docker inspect --format '{{.Image}}' "$C")
echo "image digests: $(docker image inspect --format '{{json .RepoDigests}}' "$IMG")"
echo "image labels: $(docker image inspect --format '{{json .Config.Labels}}' "$IMG" | grep -o '"dev.milesward[^,}]*' | tr '\n' ' ' || true)"
echo "image created: $(docker image inspect --format '{{.Created}}' "$IMG")"
- name: Recent container logs
run: |
set -eu
C="${{ inputs.container || 'Deepseek' }}"
echo "== last 120 log lines of $C (stack frames collapsed) =="
docker logs --tail 120 "$C" 2>&1 | grep -v -E '^[[:space:]]+at ' || true
- name: Profile composition in the state volume
run: |
set -eu
C="${{ inputs.container || 'Deepseek' }}"
IMG=$(docker inspect --format '{{.Image}}' "$C")
STATE=$(docker inspect --format '{{range .Mounts}}{{if eq .Destination "/home/node/.dsh"}}{{.Source}}{{end}}{{end}}' "$C")
if [ -z "$STATE" ]; then
echo "nothing mounted at /home/node/.dsh — state lives inside the container"
exit 0
fi
echo "state volume: $STATE (mounted read-only below)"
docker run --rm --entrypoint sh -v "$STATE:/state:ro" "$IMG" -c '
cd /state || exit 1
echo "== layout (depth 3; sessions, caches, stores, node_modules elided) =="
find . -maxdepth 3 -not -path "*/node_modules*" -not -path "./sessions*" -not -path "./.pnpm*" -not -path "./.cache*" -not -path "./.state*" -not -path "./.config*" -not -path "./attachments*" -not -path "./storages/*" | sort
for f in profiles/web/package.json profiles/web/cordis.patch.yml cordis.patch.yml profiles/web/cordis.yml profiles/web/pnpm-workspace.yaml; do
if [ ! -f "$f" ]; then echo "== $f: absent =="; continue; fi
echo "== $f ($(wc -c < "$f") bytes) =="
sed -E "s/^([[:space:]]*[^:#]*(key|token|secret|password|authorization)[^:]*:).*/\1 <redacted>/I" "$f"
echo
done
echo "== profiles/web/node_modules =="
if [ -d profiles/web/node_modules ]; then
ls -la profiles/web/node_modules
ls -d profiles/web/node_modules/@*/* 2>/dev/null || true
else
echo "(none)"
fi
echo "== profile-local packages declaring a dsh bundle layer, and the rows their patch inserts =="
for p in profiles/web/node_modules/*/package.json profiles/web/node_modules/@*/*/package.json; do
[ -f "$p" ] || continue
grep -q "\"bundle\"" "$p" || continue
echo "-- $p: $(grep -o "\"version\": *\"[^\"]*\"" "$p" | head -1)"
grep -n -E "^[[:space:]]*-[[:space:]]*(id|insert):" "$(dirname "$p")"/*.yml 2>/dev/null | head -30 || true
done
echo "== end =="
'
- name: Probe tooling inside the running container
run: |
set -eu
C="${{ inputs.container || 'Deepseek' }}"
if [ "$(docker inspect --format '{{.State.Status}}' "$C")" != running ]; then
echo "$C is not running ($(docker inspect --format '{{.State.Status}}' "$C")) — probing the image instead of the container"
IMG=$(docker inspect --format '{{.Image}}' "$C")
docker run --rm --entrypoint sh "$IMG" -c 'echo "dsh: $(command -v dsh || echo MISSING) $(dsh --version 2>/dev/null)"; echo "pnpm: $(command -v pnpm || echo MISSING) $(pnpm --version 2>/dev/null)"; echo "node: $(node --version)"'
exit 0
fi
echo "== inside $C =="
docker exec "$C" sh -c 'echo "uid=$(id -u) HOME=$HOME PATH=$PATH"; echo "dsh: $(command -v dsh || echo MISSING) $(dsh --version 2>/dev/null)"; echo "pnpm: $(command -v pnpm || echo MISSING) $(pnpm --version 2>/dev/null)"; echo "node: $(node --version)"; ls -la /usr/local/bin | grep -E "dsh|pnpm" || true'