sha256:cf28adb66a532822633866a278893afc317a82f9948bed7aef6876099f984647
Last pushed
3 days by migmartri
Type
Sandbox Kit
Manifest digest
sha256:cf28adb66a532822633866a278893afc317a82f9948bed7aef6876099f984647
schemaVersion: "2"
kind: sandbox
name: chainloop-trace-claude
version: v1.110.0
displayName: Claude Code (Chainloop-traced)
description: 'Claude Code traced with Chainloop. Requires a repository already initialized for `chainloop trace`: identity comes from its committed .chainloop.yml and the attestation is pushed on `git push`. Fork of the built-in `claude` agent.'
extends: claude
args:
chainloopConfig:
default: ""
description: 'Absolute path INSIDE the sandbox to a chainloop config.toml to adopt - i.e. where you mounted the host''s, which sbx mounts at the SAME absolute path it has on the host. The wrapper copies it to ~/.config/chainloop/config.toml so every later `chainloop` invocation finds it, including the managed git hooks, which run as their own processes (a --config flag would not reach those). Brings the org and the control-plane/CAS/platform endpoints with it, which is what makes this worthwhile for self-hosted. NOTE its [auth] token is your personal login session: short-lived (~days) and your full identity. Prefer chainloopToken for anything unattended.'
chainloopToken:
default: ""
description: 'Chainloop org-scoped API token (chainloop organization api-token create). Authenticates the attestation push, so it must have access to the org pinned in the repo''s .chainloop.yml. OPTIONAL only because chainloopConfig is the other way to authenticate - supply one or the other, or the wrapper refuses to start. When both are present this one WINS: the CLI prefers an exported CHAINLOOP_TOKEN over a config-file login session and logs "Both user credentials and $CHAINLOOP_TOKEN set. Ignoring user credentials." (app/cli/cmd/root.go).'
sandbox:
entrypoint:
- /home/agent/.local/bin/cl-trace-wrap.sh
agentInstructions:
content: |
## Chainloop tracing
This session is recorded by Chainloop trace. Tool/MCP usage and coding
activity are attested and sent to Chainloop (as a CHAINLOOP_AI_CODING_SESSION
attestation) when you `git push` from this sandbox. No push, no record -
so push before the sandbox is reclaimed.
permissions:
network:
allow:
- api.cp.chainloop.dev:443
- api.cas.chainloop.dev:443
- api.app.chainloop.dev:443
- t.chainloop.dev:443
- crb.chainloop.dev:443
- timestamp.digicert.com:80
- buf.build:443
- dl.chainloop.dev:443
- chainloop-baafegchfnekdcde.z02.azurefd.net:443
- github.com:443
environment:
variables:
CHAINLOOP_TOKEN: ${{ kit.args.chainloopToken }}
CL_TRACE_CONFIG_SOURCE: ${{ kit.args.chainloopConfig }}
NO_PROXY: localhost,127.0.0.1,::1,gateway.docker.internal,api.cp.chainloop.dev,api.cas.chainloop.dev,api.app.chainloop.dev
no_proxy: localhost,127.0.0.1,::1,gateway.docker.internal,api.cp.chainloop.dev,api.cas.chainloop.dev,api.app.chainloop.dev
setup:
install:
- command: mkdir -p /usr/local/bin && curl -sfL https://dl.chainloop.dev/cli/install.sh | bash -s -- --path /usr/local/bin && chainloop version
user: "0"
description: Install the chainloop CLI on PATH
files:
- path: /home/agent/.local/bin/cl-trace-wrap.sh
content: |
#!/usr/bin/env bash
set -euo pipefail
# Anything that would hand back an untraced agent is fatal: a sandbox
# that quietly records nothing is worse than one that refuses to start.
die() {
echo "[chainloop-trace] ERROR: $1" >&2
exit 1
}
if ! command -v chainloop >/dev/null 2>&1; then
die "chainloop CLI not on PATH - the kit's install step did not complete
(check egress to dl.chainloop.dev). Refusing to start an untraced agent."
fi
# Adopt a mounted host config.toml. Copied into place rather than passed
# with --config, so the git hooks find it in their own processes too.
if [ -n "$CL_TRACE_CONFIG_SOURCE" ]; then
if [ ! -r "$CL_TRACE_CONFIG_SOURCE" ]; then
die "chainloopConfig points at '$CL_TRACE_CONFIG_SOURCE', which is not
readable in the sandbox. Mount it read-only and give the path it has ON
THE HOST - that is where sbx mounts it inside too, e.g.
sbx run ... \"\$HOME/Library/Application Support/chainloop:ro\""
fi
mkdir -p "$HOME/.config/chainloop"
install -m 600 "$CL_TRACE_CONFIG_SOURCE" "$HOME/.config/chainloop/config.toml"
echo "[chainloop-trace] Adopted chainloop config from $CL_TRACE_CONFIG_SOURCE" >&2
fi
# Without credentials nothing can be pushed, so refuse rather than
# record nothing. A token wins over a config-file login session.
if [ -z "$CHAINLOOP_TOKEN" ] && [ ! -r "$HOME/.config/chainloop/config.toml" ]; then
die "no Chainloop credentials. Pass an org-scoped API token with
--kit-arg chainloopToken=<token>
or mount your host config and point at it with
--kit-arg chainloopConfig=<path-inside-sandbox>"
fi
# Persistent tracing only: the repo must already be initialized, and the
# identity comes from its committed .chainloop.yml.
repo_root=$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")
# The two filenames the CLI reads, spelled out: a glob here would also
# accept files Chainloop never looks at, letting the sandbox start untraced.
if ! { grep -qsE '^[[:space:]]*projectName:[[:space:]]*["'"'"']?[A-Za-z0-9]' "$repo_root/.chainloop.yml" \
|| grep -qsE '^[[:space:]]*projectName:[[:space:]]*["'"'"']?[A-Za-z0-9]' "$repo_root/.chainloop.yaml"; } \
|| ! grep -qs "chainloop trace hook" "$repo_root/.claude/settings.json"; then
die "this repository is not initialized for chainloop trace.
Run this in the repository first, then start the sandbox again:
chainloop trace init
It writes .chainloop.yml (organization + projectName) and the
'chainloop trace hook' entries in .claude/settings.json, which this kit
reads to know what to attest and when. Both must be committed - the
sandbox works on a clone, so uncommitted config does not reach it.
Refusing to start rather than run a session that records nothing."
fi
echo "[chainloop-trace] Repo initialized for chainloop trace - persistent mode" >&2
echo "[chainloop-trace] identity from .chainloop.yml; attestation is pushed on 'git push'" >&2
exec claude --dangerously-skip-permissions "$@"
mode: "0755"