一键导入
sandbox
Self-census: identity, capabilities, network position, privilege/restrictions, Slack readiness, posture summary
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Self-census: identity, capabilities, network position, privilege/restrictions, Slack readiness, posture summary
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Post messages from inside a sandbox to its per-sandbox Slack channel using km-slack — for end-of-task status, progress notes, operator pings, threaded transcript replies, and Block-Kit-rendered output
Operator CLI guide for the km command — creating sandboxes, running agents, learning traffic, managing lifecycle
Connect local desktop VS Code to a sandbox via SSM port-forward + per-sandbox ed25519 keypair; rotate keys without destroying the sandbox
One-time platform setup for an operator workstation — km configure, km init, multi-instance resource_prefix isolation, Slack/Lambda bootstrap, and rollout sequences after sidecar/Lambda changes
Launch a KasmVNC graphical browser session (kiosk or full XFCE) inside a sandbox EC2 and tunnel it to the operator's local browser over SSM port-forward
Provision cross-account IAM roles in the klanker AWS account that trust k8s clusters in other AWS accounts via IRSA (projected ServiceAccount tokens, auto-rotating 3600s sessions)
| name | sandbox |
| description | Self-census: identity, capabilities, network position, privilege/restrictions, Slack readiness, posture summary |
Run this skill first whenever you need to understand who you are, what you can do, where you sit on the network, and what restrictions are in place — and why. A single invocation gives you full self-knowledge grounded in both the declarative profile on disk and live runtime probes.
Invoke this skill first before using klanker:email, klanker:operator, or klanker:slack.
klanker:email — send/receive email between sandboxes and to the operatorklanker:slack — post from inside a sandbox to its per-sandbox Slack channel (see Section E for readiness check)klanker:operator — natural-language requests to the operator inboxklanker:init — operator-side companion (one-time platform setup that provisions the env this skill detects)KM_PROFILE=$(cat /opt/km/.km-profile.yaml 2>/dev/null)
if [ -z "$KM_PROFILE" ]; then
echo "[INFO] /opt/km/.km-profile.yaml absent — pre-Phase-113 sandbox"
echo "[INFO] Falling back to env-var census + live probes only"
PROFILE_AVAILABLE=0
else
PROFILE_AVAILABLE=1
echo "[INFO] Profile loaded from /opt/km/.km-profile.yaml"
fi
Every profile-derived check below is guarded on PROFILE_AVAILABLE. When PROFILE_AVAILABLE=0
the skill continues via env vars and live probes — it never errors on the missing file.
Determine who you are. If KM_SANDBOX_ID is empty you are not in a KM sandbox — stop and
inform the user. All other klanker skills require a sandbox environment.
echo "=== A: Identity ==="
echo "KM_SANDBOX_ID=$KM_SANDBOX_ID"
echo "KM_SANDBOX_ALIAS=$KM_SANDBOX_ALIAS"
echo "KM_SANDBOX_EMAIL=$KM_SANDBOX_EMAIL"
echo "KM_EMAIL_ADDRESS=$KM_EMAIL_ADDRESS"
echo "KM_OPERATOR_EMAIL=$KM_OPERATOR_EMAIL"
echo "KM_SANDBOX_DOMAIN=$KM_SANDBOX_DOMAIN"
echo "KM_ARTIFACTS_BUCKET=$KM_ARTIFACTS_BUCKET"
echo "KM_AGENT=$KM_AGENT" # claude | codex — default agent for this box
if [ -z "$KM_SANDBOX_ID" ]; then
echo "[STOP] Not in a KM sandbox. klanker skills are unavailable."
exit 0
fi
# Agent default from profile (cross-check KM_AGENT)
if [ "$PROFILE_AVAILABLE" = "1" ]; then
PROFILE_AGENT=$(echo "$KM_PROFILE" | grep -A2 '^ agent:' | grep 'default:' | awk '{print $2}')
echo "Profile agent.default: ${PROFILE_AGENT:-claude (implicit)}"
fi
Enumerate what this box can do — which bridges it serves, which channels are wired, and which runtime features are available. All bash; no new binary.
echo "=== B: Capability Census ==="
# B1. Sidecar helper binaries
# km-github present → this box serves the GitHub inbound bridge
# km-h1 present → this box serves the HackerOne inbound bridge
for bin in km-send km-recv km-slack km-presence km-github km-h1; do
if test -x /opt/km/bin/$bin; then
echo "$bin: present"
else
echo "$bin: absent"
fi
done
# B2. Channels wired
echo "--- Channels ---"
# Email
echo "KM_SANDBOX_EMAIL=$KM_SANDBOX_EMAIL"
if [ "$PROFILE_AVAILABLE" = "1" ]; then
echo "Email signing policy: $(echo "$KM_PROFILE" | grep -A10 '^ email:' | grep 'signing:' | awk '{print $2}' | head -1)"
echo "Email verifyInbound: $(echo "$KM_PROFILE" | grep -A10 '^ email:' | grep 'verifyInbound:' | awk '{print $2}' | head -1)"
echo "Email encryption policy: $(echo "$KM_PROFILE" | grep -A10 '^ email:' | grep 'encryption:' | awk '{print $2}' | head -1)"
fi
# Slack post-back
echo "KM_NOTIFY_SLACK_ENABLED=$KM_NOTIFY_SLACK_ENABLED"
echo "KM_SLACK_CHANNEL_ID=$KM_SLACK_CHANNEL_ID"
echo "KM_SLACK_BRIDGE_URL=$KM_SLACK_BRIDGE_URL"
echo "KM_SLACK_THREAD_TS=$KM_SLACK_THREAD_TS"
# Inbound pollers (live probe via systemctl)
for svc in km-slack-inbound-poller km-github-inbound-poller km-h1-inbound-poller; do
STATUS=$(systemctl is-active ${svc}.service 2>/dev/null || echo "not-found")
echo "${svc}: $STATUS"
done
# Inbound queue URLs (populated when inbound is enabled)
echo "KM_GITHUB_INBOUND_QUEUE_URL=$KM_GITHUB_INBOUND_QUEUE_URL"
echo "KM_H1_INBOUND_QUEUE_URL=$KM_H1_INBOUND_QUEUE_URL"
# B3. Runtime features (profile-guarded)
echo "--- Runtime features ---"
if [ "$PROFILE_AVAILABLE" = "1" ]; then
VS_CODE=$(echo "$KM_PROFILE" | grep -A3 'vscode:' | grep 'enabled:' | awk '{print $2}' | head -1)
DESKTOP=$(echo "$KM_PROFILE" | grep -A3 'desktop:' | grep 'enabled:' | awk '{print $2}' | head -1)
echo "VS Code Remote-SSH: ${VS_CODE:-false}"
echo "Desktop (KasmVNC): ${DESKTOP:-false}"
# Budget / lifecycle
echo "Budget/TTL from profile:"
echo "$KM_PROFILE" | grep -E '(ttl|idle|maxSpendUSD|computeBudget):' | head -6 | sed 's/^/ /'
# Additional storage
ADD_VOL=$(echo "$KM_PROFILE" | grep 'additionalVolume:' | head -1)
ADD_SNAP=$(echo "$KM_PROFILE" | grep 'additionalSnapshots:' | head -1)
[ -n "$ADD_VOL" ] && echo "additionalVolume: $ADD_VOL"
[ -n "$ADD_SNAP" ] && echo "additionalSnapshots: $ADD_SNAP"
else
echo "(profile absent — VS Code, desktop, budget, storage: check profile when available)"
fi
# B4. Always-present systemd sidecars
echo "--- Core sidecars ---"
for svc in km-http-proxy km-dns-proxy km-audit-log km-tracing km-presence km-mail-poller; do
STATUS=$(systemctl is-active ${svc}.service 2>/dev/null || echo "not-found")
echo "${svc}: $STATUS"
done
# Signing key access (needed by km-send and km-slack)
aws ssm get-parameter --name "/sandbox/$KM_SANDBOX_ID/signing-key" \
--with-decryption --query 'Parameter.Value' --output text > /dev/null 2>&1 \
&& echo "signing-key: OK" || echo "signing-key: MISSING (km-send --no-sign required for external recipients)"
Key interpretation:
km-github present → this box dispatches GitHub PR comment turns; the GitHub inbound poller
should be active.km-h1 present → this box dispatches HackerOne report comment turns.km-send/km-recv always present on Phase-63+ sandboxes.km-slack (Slack envelope signing) and km-send (sandbox-to-sandbox
email). If missing and signing: required, both will fail. External email: use km-send --no-sign.External email exception: For non-sandbox recipients (Gmail, corporate email), always pass
--no-sign — it skips the signing key fetch entirely. Inbound replies from non-sandbox senders
must include KM-AUTH: <safe-phrase> in the body; otherwise km-mail-poller drops them silently
to /var/mail/km/skipped/.
Understand what egress is permitted and how it is enforced. Network section is passive plus
exactly two safe-active curls — the only traffic-generating step (expect these in km otel).
echo "=== C: Network Position ==="
# C1. Infer enforcement mode — there is NO KM_ENFORCEMENT env var on-box; infer from runtime
# signals. Proxy is detected from HTTPS_PROXY / the injected CA (no root needed); the iptables
# DNAT count is a best-effort EXTRA signal (needs iptables read perms — 0 on non-privileged boxes,
# which is why it is not the sole proxy signal).
EBPF_ACTIVE=$(systemctl is-active km-ebpf-enforcer.service 2>/dev/null || echo inactive)
DNAT_OUT=$(iptables -t nat -L OUTPUT -n 2>/dev/null | grep -c DNAT) # grep -c always prints one integer
IPTABLES_DNAT=${DNAT_OUT:-0}
PROXY_ACTIVE=no
if [ -n "$HTTPS_PROXY" ] || [ -f /usr/local/share/ca-certificates/km-proxy-ca.crt ] || [ "$IPTABLES_DNAT" -gt 0 ] 2>/dev/null; then
PROXY_ACTIVE=yes
fi
if [ "$EBPF_ACTIVE" = "active" ] && [ "$PROXY_ACTIVE" = "yes" ]; then
INFERRED_MODE="both"
elif [ "$EBPF_ACTIVE" = "active" ]; then
INFERRED_MODE="ebpf"
elif [ "$PROXY_ACTIVE" = "yes" ]; then
INFERRED_MODE="proxy"
else
INFERRED_MODE="unknown"
fi
echo "Inferred enforcement mode: $INFERRED_MODE (ebpf-enforcer=$EBPF_ACTIVE, proxy=$PROXY_ACTIVE, DNAT rules=$IPTABLES_DNAT)"
if [ "$PROFILE_AVAILABLE" = "1" ]; then
# `enforcement:` is unique to spec.network — match it directly (a shallow -A context window
# misses it because it sits below the egress: sub-block).
PROFILE_MODE=$(echo "$KM_PROFILE" | grep -E '^[[:space:]]+enforcement:' | awk '{print $2}' | head -1)
echo "Profile spec.network.enforcement: ${PROFILE_MODE:-(not set, default=proxy)}"
if [ -n "$PROFILE_MODE" ] && [ "$PROFILE_MODE" != "$INFERRED_MODE" ]; then
echo "[WARN] enforcement mode mismatch: profile=$PROFILE_MODE inferred=$INFERRED_MODE"
fi
fi
# C2. Proxy / CA / eBPF signals
echo "HTTP_PROXY=$HTTP_PROXY"
echo "HTTPS_PROXY=$HTTPS_PROXY"
[ -f /usr/local/share/ca-certificates/km-proxy-ca.crt ] \
&& echo "km-proxy CA: present (proxy/both mode)" \
|| echo "km-proxy CA: absent"
KM_EBPF_CGROUP="/sys/fs/cgroup/km.slice/km-${KM_SANDBOX_ID}.scope"
[ -d "$KM_EBPF_CGROUP" ] \
&& echo "eBPF cgroup: present ($KM_EBPF_CGROUP)" \
|| echo "eBPF cgroup: absent"
echo "DNS resolver: $(grep ^nameserver /etc/resolv.conf | head -2 | tr '\n' ' ')"
# C3. Egress allowlist from profile — block-scoped to the allowedHosts / allowedDNSSuffixes lists
# only (a flat `grep '- '` over the whole network: block scoops unrelated list items like
# allowedRegions, initCommands, and trustedDirectories).
if [ "$PROFILE_AVAILABLE" = "1" ]; then
echo "--- Egress allowlist (from profile) ---"
echo "$KM_PROFILE" | awk '
/^[[:space:]]*(allowedHosts|allowedDNSSuffixes):/ { inlist=1; print " " $0; next }
inlist && /^[[:space:]]*-[[:space:]]/ { print " " $0; next }
inlist && /^[[:space:]]*[A-Za-z]/ { inlist=0 }
' | head -20
fi
# C4. Safe-active confirmation: ONE allowed + ONE known-blocked host.
# NOTE: These are the ONLY two outbound requests this section makes.
# They will appear in `km otel` output — this is expected operator behavior.
echo "--- Active egress probe (2 requests only) ---"
# Pick a CONCRETE allowed host from allowedHosts (skip wildcards / glob patterns); fall back to a
# commonly-permitted domain when the allowlist is wildcard-only.
if [ "$PROFILE_AVAILABLE" = "1" ]; then
ALLOWED_HOST=$(echo "$KM_PROFILE" | awk '
/^[[:space:]]*allowedHosts:/ { inlist=1; next }
inlist && /^[[:space:]]*-[[:space:]]/ {
h=$2; gsub(/"/,"",h);
if (h != "*" && h !~ /\*/) { print h; exit }
next
}
inlist && /^[[:space:]]*[A-Za-z]/ { inlist=0 }
')
fi
ALLOWED_HOST=${ALLOWED_HOST:-api.anthropic.com} # always permitted on Claude sandboxes
echo "Testing ALLOWED host: $ALLOWED_HOST"
# `-w '%{http_code}'` already prints 000 on connection failure/timeout — do NOT add `|| echo 000`
# (that double-emits, e.g. "000000"); default an empty value instead.
ALLOWED_CODE=$(curl --max-time 5 -sS -o /dev/null -w '%{http_code}' "https://$ALLOWED_HOST/" 2>/dev/null); ALLOWED_CODE=${ALLOWED_CODE:-000}
echo " Result: $ALLOWED_CODE (2xx/3xx/4xx = reachable; 000/timeout = blocked)"
# Known-blocked host. NOTE: on a WILDCARD allowlist (allowedHosts: ["*"], e.g. learn profiles)
# nothing is blocked, so this probe also succeeds — that is correct, not a failure.
BLOCKED_HOST="evil.example.com" # not in a normal allowlist
echo "Testing BLOCKED host: $BLOCKED_HOST"
BLOCKED_CODE=$(curl --max-time 5 -sS -o /dev/null -w '%{http_code}' "https://$BLOCKED_HOST/" 2>/dev/null); BLOCKED_CODE=${BLOCKED_CODE:-000}
echo " Result: $BLOCKED_CODE (000/timeout = correctly blocked; 2xx/3xx = allowlist is wildcard)"
Each restriction is explained so you stop fighting locked-down behavior.
echo "=== D: Privilege & Restrictions ==="
# D1. Passwordless sudo probe
if sudo -n true 2>/dev/null; then
SUDO_STATUS="yes — passwordless sudo available"
else
SUDO_STATUS="no — sudo requires a password or is disabled"
fi
echo "Passwordless sudo: $SUDO_STATUS"
# Cross-check against profile
if [ "$PROFILE_AVAILABLE" = "1" ]; then
PROFILE_PRIV=$(echo "$KM_PROFILE" | grep 'privileged:' | awk '{print $2}' | head -1)
echo "Profile spec.execution.privileged: ${PROFILE_PRIV:-(not set, default=false)}"
if [ "$PROFILE_PRIV" = "true" ] && ! sudo -n true 2>/dev/null; then
echo "[WARN] Profile says privileged=true but sudo probe failed — box may need recreate"
fi
if [ "${PROFILE_PRIV:-false}" = "false" ] && sudo -n true 2>/dev/null; then
echo "[WARN] Unexpected sudo access — profile says privileged=false"
fi
fi
# Why: spec.execution.privileged: false (the default) means no wheel/sudo access.
# This is intentional — do NOT attempt to escalate privileges.
# Privileged sandboxes are opt-in and must be declared in the profile.
echo ""
echo "Why each restriction exists:"
echo " - No sudo: spec.execution.privileged: false (default). Intentional sandbox isolation."
echo " Do not attempt privilege escalation — it will fail and log to the audit stream."
# D2. Git-ref enforcement
echo " - Git refs: KM_ALLOWED_REFS=$KM_ALLOWED_REFS"
if [ "$PROFILE_AVAILABLE" = "1" ]; then
ALLOWED_REFS=$(echo "$KM_PROFILE" | grep -A5 'sourceAccess:' | grep 'allowedRefs:' | head -1)
echo " Profile: $ALLOWED_REFS"
fi
echo " The poller enforces this list — pushes to non-allowed refs are rejected."
# D3. Secret paths
if [ "$PROFILE_AVAILABLE" = "1" ]; then
SECRET_PATHS=$(echo "$KM_PROFILE" | grep -A10 'allowedSecretPaths:' | grep -E '^\s+-' | head -5 | sed 's/^/ /')
if [ -n "$SECRET_PATHS" ]; then
echo " - Secret paths: only these SSM paths are IAM-accessible from this role:"
echo "$SECRET_PATHS"
else
echo " - Secret paths: spec.iam.allowedSecretPaths: (none declared — SSM access limited to sandbox key)"
fi
fi
# D4. Network egress (summarize; details in Section C)
echo " - Network egress: enforcement=$INFERRED_MODE — outbound connections outside the allowlist"
echo " are blocked at the kernel/proxy layer. This is not a transient error;"
echo " it is intentional policy. Check Section C allowlist for permitted hosts."
Confirm the Slack post-back environment is wired before using klanker:slack.
echo "=== E: Slack Publish-Back Readiness ==="
ALL_SLACK_OK=1
for var in KM_NOTIFY_SLACK_ENABLED KM_SLACK_CHANNEL_ID KM_SLACK_BRIDGE_URL; do
VAL=$(eval echo "\$$var")
if [ -z "$VAL" ] || [ "$VAL" = "0" ]; then
echo "$var: NOT SET — Slack posting unavailable"
ALL_SLACK_OK=0
else
echo "$var: OK ($VAL)"
fi
done
# KM_SLACK_THREAD_TS is populated only when the agent is inside a Slack-initiated thread
echo "KM_SLACK_THREAD_TS=${KM_SLACK_THREAD_TS:-(not set; replies will create a new thread)}"
# km-slack binary check
test -x /opt/km/bin/km-slack \
&& echo "km-slack binary: present" \
|| echo "km-slack binary: MISSING — recreate sandbox after km init --sidecars"
if [ "$ALL_SLACK_OK" = "1" ]; then
echo "[OK] Slack post-back is ready. See klanker:slack for usage."
else
echo "[WARN] Slack is not fully provisioned. Check notification.slack.enabled in the profile"
echo " and verify km init --dry-run=false has been run with the Slack bridge deployed."
fi
For the full Slack posting API (streaming transcripts, attachments, thread management), see
klanker:slack. Do NOT duplicate that skill's content here.
After running sections A–E, write a one-paragraph posture statement:
Who I am: Sandbox $KM_SANDBOX_ID (alias $KM_SANDBOX_ALIAS), agent $KM_AGENT.
What I can do: [list of present km-* helpers and active pollers]
Network: Enforcement mode $INFERRED_MODE. Egress allowed to [list]. BLOCKED: everything else.
Restrictions: [sudo yes/no; privileged reason; allowedRefs; secret paths]
Slack: [ready / not provisioned]
Example posture statement (fill in your actual values):
I am sandbox
sb-abc123(aliasreview-bot), running as theclaudeagent. I havekm-send,km-recv,km-slack, andkm-githubpresent, so I serve the GitHub inbound bridge. Email is signed (signing: required). Network enforcement isboth(eBPF + proxy); egress is limited toapi.anthropic.com,github.com, andapi.github.com— all other outbound connections are blocked by policy, not by transient error. I have no sudo access (privileged: false) — this is intentional, so I will not attempt privilege escalation. Slack post-back is ready on channelC0ABC123.
Use this context when invoking klanker:email, klanker:operator, or klanker:slack.