Skip to content

feat(sandbox-kit): version and publish the Docker Sandboxes kit (PFM-7373) - #3455

Merged
migmartri merged 8 commits into
chainloop-dev:mainfrom
migmartri:publish-sandbox-kit
Sep 21, 2026
Merged

migmartri merged 8 commits into
chainloop-dev:mainfrom
migmartri:publish-sandbox-kit

Conversation

@migmartri

@migmartri migmartri commented Sep 18, 2026 •

Copy link
Copy Markdown
Member

Gives the chainloop-trace-claude Docker Sandboxes kit a release lifecycle, and narrows it to a single supported mode.

Publishing

The kit declares a version: in its spec that tracks the Chainloop release whose CLI it ships. bump-chart-and-dagger-version.sh rewrites it on release alongside the chart's appVersion, and merging the resulting bump PR triggers a new Package Sandbox Kit workflow that publishes to docker.io/chainloop/sbx-kit-claude under both the version tag and latest, with a signature and SLSA provenance attached — mirroring how package_chart.yaml reacts to changes under deployment/chainloop/.

Docker Hub rather than ghcr: sbx's default kit.allowedSources is already ["docker.io/"], so consumers pull the kit without changing their host settings. Authentication is via a Docker Hub OIDC connection, so no long-lived registry credential is stored in the repository; access is governed by a ruleset matching the subject claim repo:chainloop-dev/chainloop:ref:refs/heads/main.

v1.109.0 and latest have been published manually to bootstrap the repository.

Persistent tracing only

The kit now requires a repository already initialized with chainloop trace init and refuses to start otherwise, pointing the user at that command. Identity always comes from the committed .chainloop.yml, so the traceMode, chainloopOrg, chainloopProject and chainloopWorkflow arguments are gone.

chainloop trace run is dropped deliberately: it ignores .chainloop.yml by design, and its teardown wipes .git/chainloop-trace/ and strips the committed hooks — destructive on exactly the repositories this kit accepts. The trade-off is that a session whose work is never pushed attests nothing.

Layout and docs

The spec moves to devel/sandbox-kit/claude/ to make room for further kits. A discover job derives the publish matrix from the directories holding a spec.yaml and the bump script globs the same tree, so a new kit is published with no workflow edit. The trigger is scoped to devel/sandbox-kit/*/spec.yaml so a README edit cannot republish a released tag, and a version already present in the registry is skipped rather than overwritten. sbxenv.yaml keeps pointing at the in-repo copy so the local environment runs the kit as it exists on the current branch.

The spec gains a usage header pointing at the guide, and sheds its long-form rationale in favour of short notes referring to devel/sandbox-kit/README.md, which already carries the same material. The README's sbx run invocations are corrected: the kit is kind: sandbox, so it is the agent and belongs in the positional slot rather than behind --kit, which accepts mixins only.

AI assistance: this change was produced with Claude Code.

Give the chainloop-trace-claude kit the same release lifecycle the Helm
chart already has: it declares a `version:` that tracks the Chainloop
release whose CLI it ships, the release bump script rewrites it alongside
the chart's appVersion, and merging that bump PR publishes the kit to
docker.io/chainloop/sbx-kit-claude:<version> with a signature and SLSA
provenance attached.

Docker Hub rather than ghcr because sbx's default kit.allowedSources is
already ["docker.io/"], so consumers need no host settings change to pull
the kit.

The spec moves under devel/sandbox-kit/claude/ to make room for further
kits; the packaging workflow and the bump script both glob the directory,
so additional kits are picked up without further edits. sbxenv.yaml keeps
pointing at the in-repo copy so the local environment always runs the kit
as it exists on the current branch.

Also corrects the README's sbx run invocations: the kit is `kind: sandbox`,
so it is the agent and belongs in the positional slot, not behind --kit,
which takes mixins only.

Assisted-by: Claude Code
Signed-off-by: Miguel Martinez <miguel@chainloop.dev>

Chainloop-Trace-Sessions: 7da50f6b-428c-4749-82b5-562ae1ba890e
@chainloop-platform

chainloop-platform Bot commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

AI Session Checks — 🟡 75% · ⚠️ 2 failing

Avg score Sessions Failing policies Attribution Files Lines Total Duration
🟡 75% 1 ⚠️ 2 100% AI / 0% Human 6 +857 / -842 50h56m22s

🟡 75% — 100% AI — ⚠️ 2 policies failing

Sep 18, 2026 14:08 UTC · 50h56m22s · $67.52 · 1.0k in / 346.2k out · claude-code 2.1.276 (claude-opus-5)

View session details ↗

Change Summary

  • Moves the sandbox kit spec under devel/sandbox-kit/claude/ and trims kit comments/docs.
  • Adds kit version: handling and updates the release bump script to rewrite sandbox kit specs.
  • Adds and then hardens package_sandbox_kit.yaml for discovery, validation, publishing, attestation, and latest tagging.
  • Updates sbxenv.yaml and the kit wrapper for persistent-only tracing and stricter repo detection.

AI Session Overall Score

🟡 75% — Useful session, but claim drift and unexercised workflow changes leave reviewer work.

AI Session Analysis Breakdown

🟢 92% · user-trust-signal

🟢 The user kept moving to the next task without sharp corrections. · High Impact

🟢 90% · scope-discipline

🟢 Code changes stayed inside the sandbox-kit area the user kept steering. · High Impact

🟢 84% · solution-quality

🟢 Replaced the coarse skip guard with version-change discovery. · High Impact

🟡 72% · alignment

🟠 The AI twice described shipped behavior more strongly than the branch supported at the time. · Medium Severity

💡 Verify capability claims against the current branch before stating them in summaries or PR text.

🟡 71% · context-and-planning

🟠 A broad workflow, script, spec, and config change ran mostly without a visible plan. · Medium Severity

💡 For multi-file release changes, write a short visible plan before editing so later fixes stay anchored.

🟡 58% · verification

🔴 Workflow edits were never rerun end-to-end after the final changes. · High Severity

💡 For CI or workflow changes, rerun the workflow or an equivalent end-to-end publish path before calling it done.


File Attribution

████████████████████ 100% AI / 0% Human

Status Attribution File Lines
modified ai devel/sandbox-kit/claude/spec.yaml +554 / -353
deleted ai devel/sandbox-kit/spec.yaml +0 / -396
modified ai .github/workflows/package_sandbox_kit.yaml +243 / -59
modified ai devel/sandbox-kit/README.md +25 / -11
modified ai sbxenv.yaml +16 / -16
modified ai .github/workflows/utils/bump-chart-and-dagger-version.sh +19 / -7

Policies (4, 2 failing)

Status Policy Material Messages
✅ Passed ai-config-ai-agents-allowed ai-coding-session-7da50f -
⚠️ Failed ai-config-no-dangerous-commands ai-coding-session-7da50f
  • Forbidden bash pattern /curl[^|\n]|\s(?:bash|sh)\b/ matched command: cat > .github/workflows/package_sandbox_kit.yaml <<'YAML' name: Package Sandbox Kit on: # Only push the kit if the kit sources have changed. The release bump...
  • Forbidden bash pattern /curl[^|\n]|\s(?:bash|sh)\b/ matched command: git add .github/workflows/package_sandbox_kit.yaml && git commit -S -s -F - <<'MSG' && git push 2>&1 | tail -2 fix(sandbox-kit): harden the packaging workflow (...
  • Forbidden bash pattern /curl[^|\n]|\s(?:bash|sh)\b/ matched command: python3 - <<'PY' import sys, pathlib p = pathlib.Path(".github/workflows/package_sandbox_kit.yaml") s = p.read_text() old = """ - name: Install Chainloop ...
⚠️ Failed ai-config-no-secrets ai-coding-session-7da50f
  • Secret (generic-[REDACTED:generic-password) detected in session content [turn=831, source=tool_result, line=62]: | ⚠️ Failed | ai-config-no-secrets | [ai-coding-session-7da50f](https://app.chainloop.dev/u/chainloop/projects/chainloop/versi...
  • Secret (generic-credential-uri) detected in session content [turn=886, source=assistant-text, line=27]: test-token https://gitlab-ci-token:[REDACTED:generic-credential-uri]@github.com/chainloop-dev/chainloop.git
  • Secret (generic-password) detected in session content [turn=15, source=tool_result, line=33]: [REDACTED:generic-password]: ${{ secrets.GITHUB_TOKEN }}
  • Secret (generic-password) detected in session content [turn=29, source=tool_result, line=33]: 33 [REDACTED:generic-password]: ${{ secrets.GITHUB_TOKEN }}
  • Secret (generic-password) detected in session content [turn=34, source=tool_result, line=93]: 93 [REDACTED:generic-password]: ${{ secrets.GITHUB_TOKEN }}
  • Secret (generic-password) detected in session content [turn=35, source=tool_result, line=115]: 115 [REDACTED:generic-password]: ${{ secrets.GITHUB_TOKEN }}
  • Secret (generic-password) detected in session content [turn=493, source=tool_result, line=33]: 33 [REDACTED:generic-password]: ${{ secrets.GITHUB_TOKEN }}
  • Secret (generic-password) detected in session content [turn=563, source=assistant-tool_use:Bash, line=46]: [REDACTED:generic-password]: ${{ secrets.DOCKERHUB_TOKEN }}
  • Secret (generic-password) detected in session content [turn=624, source=assistant-text, line=12]: | DOCKERHUB_TOKEN | Docker Hub access token (Account Settings → Personal access tokens), scoped Read & Write, not your [REDACTED:generic-password] |
  • Secret (generic-password) detected in session content [turn=632, source=assistant-tool_use:Bash, line=1]: grep -rn "login-action" -A 6 .github/workflows/.yaml .github/workflows/.yml 2>/dev/null | grep -iE "registry:|username:|[REDACTED:generic-password]:|login-action" | head -20
  • Secret (generic-password) detected in session content [turn=633, source=tool_result, line=11]: .github/workflows/package_chart.yaml-33- [REDACTED:generic-password]: ${{ secrets.GITHUB_TOKEN }}
  • Secret (generic-password) detected in session content [turn=633, source=tool_result, line=15]: .github/workflows/release.yaml-93- [REDACTED:generic-password]: ${{ secrets.GITHUB_TOKEN }}
  • Secret (generic-password) detected in session content [turn=633, source=tool_result, line=4]: .github/workflows/build_external_container_images.yaml-115- [REDACTED:generic-password]: ${{ secrets.GITHUB_TOKEN }}
  • Secret (generic-password) detected in session content [turn=633, source=tool_result, line=7]: .github/workflows/package_sandbox_kit.yaml-45- [REDACTED:generic-password]: ${{ secrets.DOCKERHUB_TOKEN }}
  • Secret (generic-password) detected in session content [turn=650, source=tool_result, line=17]: The workflow must grant the id-token: write permission, pass the Docker Hub organization name as username, omit [REDACTED:generic-password], and set the OIDC connection ID in DOCKERHUB_OIDC_CONNECTION...
  • Secret (generic-password) detected in session content [turn=650, source=tool_result, line=1]: Web search results for query: "Docker Hub OIDC GitHub Actions push without [REDACTED:generic-password] trusted publishing"
  • Secret (generic-password) detected in session content [turn=655, source=tool_result, line=32]: - username: Docker Hub organization name (no [REDACTED:generic-password] field)
  • Secret (generic-password) detected in session content [turn=658, source=assistant-text, line=7]: The change to my workflow is small — drop the [REDACTED:generic-password], and the two remaining values are variables, not secrets:
  • Secret (generic-password) detected in session content [turn=703, source=assistant-tool_use:Bash, line=16]: [REDACTED:generic-password]: ${{ secrets.DOCKERHUB_TOKEN }}"""
  • Secret (generic-password) detected in session content [turn=831, source=tool_result, line=62]: | ⚠️ Failed | ai-config-no-secrets | [ai-coding-session-7da50f](https://app.chainloop.dev/u/chainloop/projects/chainloop/versi...
  • … and 6 more — view all ↗
✅ Passed ai-config-mcp-servers-allowed ai-coding-session-7da50f -

Security Checks — ✅ 10 passing

✅ secret-scan

Status Policy Messages
✅ Passed secrets-detection -

✅ github-actions-scan

Status Policy Messages
✅ Passed ci-pipeline-security -

✅ sast-scan

Status Policy Messages
✅ Passed owasp-top10-2025 -
✅ Passed sast -
✅ Passed cwe-top25 -
✅ Passed cwe-top26-40-cusp -

✅ iac-scan

Status Policy Messages
✅ Passed iac-misconfiguration -

PR info

Status Policy Messages
✅ Passed pr-min-approvals -
✅ Passed pr-description-required -
✅ Passed pr-user-story-linked -

⏭️ 1 scan not applied

Scan Reason
vulnerability-scan no manifest/lockfile changed

View attestation ↗
View attestation ↗


Powered by Chainloop and Chainloop Trace

Replace the DOCKERHUB_USERNAME/DOCKERHUB_TOKEN secrets with an OIDC
connection, so publishing needs no long-lived Docker Hub credential in the
repository. GitHub mints a short-lived identity token per run and Docker
exchanges it for a registry token that expires with the job; access is
governed by the connection's ruleset on the subject claim.

Assisted-by: Claude Code
Signed-off-by: Miguel Martinez <miguel@chainloop.dev>

Chainloop-Trace-Sessions: 7da50f6b-428c-4749-82b5-562ae1ba890e
@kusari-inspector

kusari-inspector Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Kusari Inspector

Kusari Analysis Results:

Proceed with these changes

✅ No Flagged Issues Detected
All values appear to be within acceptable risk parameters.

Dependency analysis found no pinned version dependency changes and raised no concerns. Code analysis flagged a Docker Hub secret detection at line 63, but determined it is a DOCKERHUB_OIDC_CONNECTIONID identifier, not an actual credential - the workflow uses OIDC federation with short-lived tokens rather than storing long-lived secrets, which is a security best practice. No codeIssues or workflow_issues were reported. Both analyses independently recommend proceeding, and the combined findings do not change the overall risk profile. No action items required before merging.

Note

View full detailed analysis result for more information on the output and the checks that were run.


@kusari-inspector rerun - Trigger a re-analysis of this PR
@kusari-inspector feedback [your message] - Send feedback to our AI and team
See Kusari's documentation for setup and configuration.
Commit: 7c9bee1, performed at: 2026-09-18T17:10:50Z

Found this helpful? Give it a 👍 or 👎 reaction!

Comment thread .github/workflows/package_sandbox_kit.yaml

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed

Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.

Re-trigger cubic

Comment thread .github/workflows/package_sandbox_kit.yaml Outdated
Each release moves docker.io/chainloop/sbx-kit-claude:latest to the version
just published, so consumers can track the current kit without pinning. The
attestation keeps naming the immutable tag.

Assisted-by: Claude Code
Signed-off-by: Miguel Martinez <miguel@chainloop.dev>

Chainloop-Trace-Sessions: 7da50f6b-428c-4749-82b5-562ae1ba890e
@kusari-inspector

Copy link
Copy Markdown

Kusari PR Analysis rerun based on - 7ffa222 performed at: 2026-09-18T17:05:50Z - link to updated analysis

@migmartri
migmartri requested a review from a team September 18, 2026 17:06

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed against the latest diff

Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.

Re-trigger cubic

Comment thread .github/workflows/package_sandbox_kit.yaml Outdated
Comment thread devel/sandbox-kit/claude/spec.yaml
Comment thread .github/workflows/package_sandbox_kit.yaml Outdated
Comment thread .github/workflows/utils/bump-chart-and-dagger-version.sh Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 1 file (changes from recent commits).

Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.

Re-trigger cubic

Comment thread .github/workflows/package_sandbox_kit.yaml
Address the SAST and Kusari findings on the new workflow:

- Replace the `curl | bash` installer with a fetch, sha256 digest check and
  then execute. The job holds an OIDC token that mints Docker Hub
  credentials and signs artifacts, so an unverified install script is a
  privilege escalation path.
- Pass the kit version into the publish step through env rather than
  interpolating the step output into the shell source, removing the
  template injection surface.

Assisted-by: Claude Code
Signed-off-by: Miguel Martinez <miguel@chainloop.dev>

Chainloop-Trace-Sessions: 7da50f6b-428c-4749-82b5-562ae1ba890e
@migmartri migmartri changed the title feat(sandbox-kit): version and publish the Docker Sandboxes kit feat(sandbox-kit): version and publish the Docker Sandboxes kit (PFM-7373) Sep 18, 2026
@kusari-inspector

Copy link
Copy Markdown

Kusari PR Analysis rerun based on - 7c9bee1 performed at: 2026-09-18T17:11:02Z - link to updated analysis

The kit now requires a repository that has already been initialized with
`chainloop trace init` and refuses to start otherwise, telling the user to
run it in the repository first. Identity always comes from the committed
.chainloop.yml, so the traceMode, chainloopOrg, chainloopProject and
chainloopWorkflow arguments are gone.

`chainloop trace run` is dropped deliberately: it ignores .chainloop.yml by
design, and its teardown wipes .git/chainloop-trace/ and strips the
committed hooks, which is destructive on exactly the repositories this kit
accepts. The trade-off is that a session whose work is never pushed attests
nothing.

Also adds a usage header pointing at the guide, drops the edition wording
from the CLI install and egress comments, and condenses the commentary.

Assisted-by: Claude Code
Signed-off-by: Miguel Martinez <miguel@chainloop.dev>

Chainloop-Trace-Sessions: 7da50f6b-428c-4749-82b5-562ae1ba890e

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 3 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread devel/sandbox-kit/claude/spec.yaml Outdated
Move the long-form rationale out of spec.yaml and leave short notes with
pointers to the README, which already carries the same material under "Why
nightly" and "Why the token is passed in". Removes the build-requirement
banner, the gRPC/ALPN analysis, the commented-out proxy-managed credential
block, the v1-to-v2 migration asides and the per-host debugging notes.

No functional change: the egress allowlist, environment variables and
wrapper behaviour are unchanged.

Assisted-by: Claude Code
Signed-off-by: Miguel Martinez <miguel@chainloop.dev>

Chainloop-Trace-Sessions: 7da50f6b-428c-4749-82b5-562ae1ba890e

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 1 file (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread devel/sandbox-kit/claude/spec.yaml Outdated
…(PFM-7373)

Review follow-ups.

Publish every kit under devel/sandbox-kit rather than the hardcoded claude
one: a discover job derives the matrix from the directories that hold a
spec.yaml, so a new kit needs no workflow edit.

Narrow the trigger to devel/sandbox-kit/*/spec.yaml. The previous
devel/sandbox-kit/** also matched the README, so a docs edit republished the
released tag with fresh content under the same immutable version. Guard the
same hazard from the other side by skipping a version already present in the
registry, since the trigger still fires on spec edits that leave the version
alone.

Make a zero-match glob fatal in the bump script. It previously ran from the
invocation directory and swallowed a miss, so a release run from the wrong
place would leave every spec at the old version and publish nothing, with no
error.

Move checkout and the version read ahead of the tooling installs so a missing
version fails in seconds rather than after a 95MB download. Drop the wrapper's
run_plain indirection and the detected flag left over from two-mode dispatch,
along with the last stale references to the removed trace mode.

Assisted-by: Claude Code
Signed-off-by: Miguel Martinez <miguel@chainloop.dev>

Chainloop-Trace-Sessions: 7da50f6b-428c-4749-82b5-562ae1ba890e

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files (changes from recent commits).

Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.
Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread .github/workflows/package_sandbox_kit.yaml Outdated
Comment thread devel/sandbox-kit/claude/spec.yaml Outdated
…-7373)

Review follow-ups on PR 3455.

Select kits in the discover job by diffing each spec's `version:` across the
pushed range, and drop the registry-existence guard that replaced. The guard
skipped the whole publish block, so a run whose version push succeeded but
whose `latest` push or attestation failed could never be reconciled by a
re-run; selecting on the version change instead leaves a re-run of that same
push selecting the kit and completing the work, while a comment-only spec
edit selects nothing.

Spell out the two config filenames the wrapper accepts. The .chainloop.y*ml
glob also matched files Chainloop never reads, such as .chainloop.yolo.ml,
which would let the sandbox start without the tracing it promises.

Restore the proxy re-test probe next to the credentials note, which pointed at
a README section carrying the reasoning but not the procedure.

Assisted-by: Claude Code
Signed-off-by: Miguel Martinez <miguel@chainloop.dev>

Chainloop-Trace-Sessions: 7da50f6b-428c-4749-82b5-562ae1ba890e

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread .github/workflows/package_sandbox_kit.yaml
@migmartri
migmartri requested review from a team and matiasinsaurralde September 20, 2026 21:44
Comment thread devel/sandbox-kit/claude/spec.yaml
@migmartri
migmartri merged commit 1c95de9 into chainloop-dev:main Sep 21, 2026
16 of 17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants