Sign inSign up

chainloop/sbx-kit-claude:v1.110.0

Manifest digest

sha256:cf28adb66a532822633866a278893afc317a82f9948bed7aef6876099f984647

Last pushed

3 days by migmartri

Type

Sandbox Kit

Manifest digest

sha256:cf28adb66a532822633866a278893afc317a82f9948bed7aef6876099f984647

yaml
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"