{"repo": "byteyellow/agentprovenance", "files": {"scripts/demo_k8s_substrate.sh": {"3b1cb9ffc50985d4e02ddf04a8ac10c093a7a95e": {"t": 1786068351.6786134, "n": 9680, "h": "184a7f4f5d308f85", "c": "#!/usr/bin/env bash\n# Demo: the k8s-daemonset Producer Profile, end to end, over a real LLM workload.\n#\n# Deploys a Python agent Pod that makes real DeepSeek/Anthropic API calls in a\n# loop, captures its kernel telemetry AND its model-intent (TLS request/response\n# bodies) from the NODE side without touching the image, attributes it to a run\n# via the pod cgroup + pod metadata, and serves it on the substrate lens.\n#\n# This is the k8s counterpart of the local-record demo: same evidence, an\n# externally-scheduled pod that was never wrapped by `record`. The model-intent\n# capture points the libssl uprobe at the pod's own libssl through /proc//\n# root, satisfying the roadmap's \"TLS symbols resolvable from the node/rootfs\".\n#\n# Run on the node. Requires single-node k3s/k8s + Docker, run as root (the\n# sensor needs privileged BPF and the k3s kubeconfig is root-only).\n#\n# Env:\n# AGENTPROV path to the linux agentprov binary (required)\n# SENSOR path to the linux agentprov-sensor binary (required)\n# KUBECTL kubectl command (default \"k3s kubectl\")\n# IMAGE python image present in the cluster containerd\n# (default docker.io/library/python:3-slim)\n# DEEPSEEK_API_KEY real key -> real completions; unset/placeholder -> 401s\n# ANTHROPIC_API_KEY real key -> real completions; unset/placeholder -> 401s\n# DNS_SERVER pod upstream DNS, bypassing broken in-cluster CoreDNS\n# (default 10.211.55.1; set to your node's resolver)\n# DATA agentprov data dir (default /home/agentprov/agentprov-demo)\n# CAPTURE_SECONDS sensor capture window (default 50)\n# SERVE 1 = leave the dashboard running at the end (default 1)\n# ADDR dashboard listen address (default 127.0.0.1:7396)\nset -uo pipefail\n\nAGENTPROV=\"${AGENTPROV:?set AGENTPROV to the agentprov binary}\"\nSENSOR=\"${SENSOR:?set SENSOR to the agentprov-sensor binary}\"\nKUBECTL=\"${KUBECTL:-k3s kubectl}\"\nIMAGE=\"${IMAGE:-docker.io/library/python:3-slim}\"\nDNS_SERVER=\"${DNS_SERVER:-10.211.55.1}\"\nDATA=\"${DATA:-/home/agentprov/agentprov-demo}\"\nCAPTURE_SECONDS=\"${CAPTURE_SECONDS:-50}\"\nSERVE=\"${SERVE:-1}\"\nADDR=\"${ADDR:-127.0.0.1:7396}\"\nRUN=\"claude-demo\"\nPOD=\"claude-agent\"\nNS=\"default\"\nWORK=\"$(mktemp -d)\"\ncleanup() { rm -rf \"$WORK\"; }\ntrap cleanup EXIT\n\necho \"== render the agent workload + pod manifest\"\ncat > \"$WORK/agent_demo.py\" <<'PY'\nimport json\nimport os\nimport time\nimport urllib.request\n\n\ndef call(name, url, headers, body):\n req = urllib.request.Request(\n url,\n data=json.dumps(body).encode(),\n headers={\"Content-Type\": \"application/json\", **headers},\n method=\"POST\",\n )\n try:\n with urllib.request.urlopen(req, timeout=20) as r:\n print(name, r.status, r.read()[:160], flush=True)\n except Exception as e: # noqa: BLE001 - demo loop must survive 401/network errors\n print(name, \"ERR\", getattr(e, \"code\", e), flush=True)\n\n\nak = os.environ.get(\"ANTHROPIC_API_KEY\", \"\")\ndk = os.environ.get(\"DEEPSEEK_API_KEY\", \"\")\ni = 0\nwhile True:\n i += 1\n call(\n \"anthropic\",\n \"https://api.anthropic.com/v1/messages\",\n {\"x-api-key\": ak, \"anthropic-version\": \"2023-06-01\"},\n {\n \"model\": \"claude-sonnet-5\",\n \"max_tokens\": 48,\n \"messages\": [\n {\"role\": \"user\", \"content\": f\"k8s substrate demo ping {i}: reply with one short sentence\"}\n ],\n },\n )\n call(\n \"deepseek\",\n \"https://api.deepseek.com/chat/completions\",\n {\"Authorization\": \"Bearer \" + dk},\n {\n \"model\": \"deepseek-chat\",\n \"max_tokens\": 48,\n \"messages\": [{\"role\": \"user\", \"content\": f\"k8s substrate demo ping {i}\"}],\n },\n )\n time.sleep(5)\nPY\n\ncat > \"$WORK/pod.yaml\" </dev/null 2>&1\n $KUBECTL create secret generic agent-keys -n \"$NS\" \\\n --from-literal=DEEPSEEK_API_KEY=\"${DEEPSEEK_API_KEY:-placeholder}\" \\\n --from-literal=ANTHROPIC_API_KEY=\"${ANTHROPIC_API_KEY:-placeholder}\" >/dev/null\n dsstate=$([ -n \"${DEEPSEEK_API_KEY:-}\" ] && echo \"real key\" || echo placeholder)\n anstate=$([ -n \"${ANTHROPIC_API_KEY:-}\" ] && echo \"real key\" || echo placeholder)\n echo \" secret agent-keys set (deepseek=$dsstate, anthropic=$anstate)\"\nelse\n echo \" no keys in env; reusing existing agent-keys secret if present (calls 401 otherwise)\"\nfi\n\necho \"== deploy the agent pod\"\n$KUBECTL delete pod \"$POD\" -n \"$NS\" --force --grace-period=0 >/dev/null 2>&1\n$KUBECTL create configmap \"${POD}-script\" -n \"$NS\" --from-file=\"$WORK/agent_demo.py\" \\\n --dry-run=client -o yaml | $KUBECTL apply -f - >/dev/null\n$KUBECTL apply -f \"$WORK/pod.yaml\" >/dev/null\nfor _ in $(seq 1 40); do\n [ \"$($KUBECTL get pod \"$POD\" -n \"$NS\" -o jsonpath='{.status.phase}' 2>/dev/null)\" = \"Running\" ] && break\n sleep 2\ndone\n[ \"$($KUBECTL get pod \"$POD\" -n \"$NS\" -o jsonpath='{.status.phase}' 2>/dev/null)\" = \"Running\" ] || {\n echo \"FAIL: pod did not reach Running (image '$IMAGE' present in cluster containerd?)\"\n echo \" hint: docker pull '$IMAGE' && docker save '$IMAGE' | k3s ctr images import -\"\n exit 1; }\necho \" pod Running; giving it a few call cycles\"\nsleep 12\n$KUBECTL logs \"$POD\" -n \"$NS\" --tail=4 | sed 's/^/ log: /'\n\necho \"== resolve the pod's pid / cgroup / libssl, capture ${CAPTURE_SECONDS}s from the node\"\nPID=\"$(pgrep -f agent_demo.py | head -1)\"\n[ -n \"$PID\" ] || { echo \"FAIL: agent process not found on the node\"; exit 1; }\nLIBSSL=\"/proc/$PID/root/usr/lib/aarch64-linux-gnu/libssl.so.3\"\n[ -e \"$LIBSSL\" ] || LIBSSL=\"/proc/$PID/root/usr/lib/x86_64-linux-gnu/libssl.so.3\"\nCGREL=\"$(awk -F:: '{print $2}' \"/proc/$PID/cgroup\")\"\nCGID=\"$(stat -c %i \"/sys/fs/cgroup$CGREL\")\"\nPODUID=\"$($KUBECTL get pod \"$POD\" -n \"$NS\" -o jsonpath='{.metadata.uid}')\"\nSTART=\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"\necho \" pid=$PID cgroup=$CGID pod_uid=$PODUID libssl=$LIBSSL\"\n\ndocker run --rm --privileged --pid=host \\\n -v /sys/kernel/btf:/sys/kernel/btf:ro -v /sys/kernel/tracing:/sys/kernel/tracing \\\n -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/cgroup:/sys/fs/cgroup:ro \\\n -v \"$SENSOR\":/agentprov-sensor:ro -v \"$WORK\":/out \\\n -e AGENTPROV_SSL_LIB=\"$LIBSSL\" \\\n ubuntu:24.04 bash -c \\\n \"/agentprov-sensor >/out/sensor.jsonl 2>/out/sensor.err & SP=\\$!; sleep $CAPTURE_SECONDS; kill \\$SP 2>/dev/null\" \\\n >/dev/null 2>&1\n\nJ=\"$WORK/sensor.jsonl\"\nexecveN=$(grep -c execve \"$J\")\ntlsN=$(grep -cE '\"event_type\":\"tls_' \"$J\")\ncgN=$(grep -cF \"\\\"cgroup_id\\\":\\\"$CGID\\\"\" \"$J\")\necho \" captured: execve=$execveN tls=$tlsN pod-cgroup-events=$cgN\"\n[ \"$cgN\" -ge 1 ] || { echo \"FAIL: no telemetry attributed to the pod cgroup\"; exit 1; }\n\necho \"== bind pod cgroup + metadata -> run, ingest, export, verify\"\nrm -rf \"$DATA\" && \"$AGENTPROV\" --data-dir \"$DATA\" init >/dev/null\n\"$AGENTPROV\" --data-dir \"$DATA\" sandbox bind-cgroup --run \"$RUN\" \\\n --cgroup-id \"$CGID\" --session \"$PODUID\" --started-at \"$START\" \\\n --pod-name \"$POD\" --namespace \"$NS\" --labels app=\"$POD\",demo=substrate | sed 's/^/ /'\ngrep -F \"\\\"cgroup_id\\\":\\\"$CGID\\\"\" \"$J\" > \"$WORK/pod.jsonl\"\n# AGENTPROV_TLS_CAPTURE_BODY=1 keeps the full request/response bodies (the actual\n# prompt + completion) so the dashboard can show them, matching what the `launch`\n# integrated path does. Without it only a sha256 + 80-char preview is stored.\nAGENTPROV_TLS_CAPTURE_BODY=1 \"$AGENTPROV\" --data-dir \"$DATA\" telemetry ingest-jsonl --run \"$RUN\" \\\n --file \"$WORK/pod.jsonl\" --format native 2>&1 | grep -o 'read=[0-9]* ingested=[0-9]* skipped=[0-9]* failed=[0-9]*' | sed 's/^/ /'\n# Objectify the captured LLM traffic into verifiable llm_message objects + llm_call\n# nodes (agent-intent lens). NOTE: request<->response pairing currently keys on the\n# logical process_id, which passive node-side capture does not populate, so this\n# reports 0 calls until that pairing falls back to pid/cgroup scope.\nllmN=\"$(\"$AGENTPROV\" --data-dir \"$DATA\" graph materialize-llm --run \"$RUN\" 2>/dev/null | grep -o '\"llm_calls\":[0-9]*' | grep -o '[0-9]*')\"\necho \" materialized llm_calls=${llmN:-0}\"\n\"$AGENTPROV\" --data-dir \"$DATA\" forensics export \"$RUN\" >/dev/null 2>&1\nverify=\"$(\"$AGENTPROV\" --data-dir \"$DATA\" graph verify --run \"$RUN\" 2>&1 | head -1)\"\necho \" $verify\"\necho \"$verify\" | grep -q \"errors=0\" || { echo \"FAIL: demo run did not verify clean\"; exit 1; }\n\ntlsRead=$(grep -c '\"event_type\":\"tls_read\"' \"$WORK/pod.jsonl\")\necho \"PASS: k8s pod observed from the node -> run '$RUN' (verify errors=0; tls_read bodies=$tlsRead)\"\n\nif [ \"$SERVE\" = \"1\" ]; then\n pkill -f \"dashboard serve\" 2>/dev/null\n setsid nohup \"$AGENTPROV\" --data-dir \"$DATA\" dashboard serve --addr \"$ADDR\" \\\n >/tmp/agentprov-demo-dashboard.log 2>&1 < /dev/null &\n sleep 2\n echo \"== dashboard: http://$ADDR/ (run '$RUN', substrate lens)\"\n echo \" from a workstation: ssh -f -N -L ${ADDR##*:}:$ADDR then open http://localhost:${ADDR##*:}/\"\nfi\n"}}}}