Skip to content

feat(trace): end-to-end test matrix for Claude Code - #3648

Merged
jiparis merged 2 commits into
chainloop-dev:mainfrom
jiparis:feat/trace-e2e-matrix
Oct 19, 2026
Merged

jiparis merged 2 commits into
chainloop-dev:mainfrom
jiparis:feat/trace-e2e-matrix

Conversation

@jiparis

@jiparis jiparis commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Implements milestone 2 of spec issue-3635 (#3635): the framework of the end-to-end suite for Chainloop Trace, and the Claude Code column. This first version runs locally only. The nightly job and the Slack message come later.

The suite is in app/cli/internal/trace/e2e/ and runs with make -C app/cli test-trace-e2e.

  • Expected matrix: the suite reads the feature tables of the Trace README (R-002, D-002). A feature row maps to its checks by the feature name. The suite skips cells marked "No" or "Not applicable". It reports features that need a control plane as "not covered" (D-007), and rows with no check as "no check".
  • Real headless runs: a harness adapter runs Claude Code with claude -p and a real model, in a throwaway repository with trace init --local and a local bare remote (R-003, D-001). The adapter reads the hook messages from the stream-json output, so the welcome message check reads what the user sees (R-004).
  • Scenarios and checks: three shared scenarios (edit and commit, work from a ticket file, use a skill) serve the checks of 14 features. The checks read the session that the pre-push hook stored in local storage mode (R-005, D-008).
  • Repeated runs: a model-driven feature runs 3 times and passes with 2 passes. The result shows the pass rate (R-006, D-004).
  • Matrix storage: each run writes its result as JSON. Only a run with no filter becomes the previous result (R-009). The comparison reports a regression (pass to fail) and an improvement (an "Unknown" cell that passes). A cell that fails in two runs one after the other is reported one time only (R-007, D-005). The result also renders as a markdown table (R-010).
  • Configuration: config.yaml pins the harness version and lists the models of each column (D-009, D-013).

Difference from the spec: in each scenario, the agent pushes inside the session. The spec does not say who pushes. A push after the session end stores no spec, because the session end removes the captured specs.

Not in this PR: the CI job, the Slack message, the installation of the pinned harness version, Cursor, OpenCode, Pi, and checks for five rows (Subagents, Spec source pointers, Pasted image pointers, Media skipped by redaction, Shell commands in another checkout).

    e2e_test.go:98: result matrix, stored in results/runs/20261019T074829Z.json:

        | Feature | Claude Code 2.1.303 / haiku |
        |---|---|
        | Transcript | pass |
        | Token usage and cost | pass |
        | Model detection | pass |
        | Subagents | no check |
        | Line attribution | pass |
        | Shell changes attribution | pass |
        | Welcome message | pass |
        | Session link after push | not covered |
        | Credentials warning | not covered |
        | Spec capture instruction | pass 3/3 |
        | Spec capture reminder | pass |
        | Local spec sources read at push | pass 3/3 |
        | Skills tracking | pass 3/3 |
        | Spec source pointers | no check |
        | Pasted image pointers | no check |
        | Secret redaction | pass |
        | Media skipped by redaction | no check |
        | Allow markers in redaction | pass |
        | Commit trailer | pass |
        | Attestation at push | not covered |
        | Local storage at push | pass |
        | Shell commands in another checkout | no check |
    e2e_test.go:109: suite gap: Subagents / Claude Code / haiku: no check is registered for this feature
    e2e_test.go:109: suite gap: Spec source pointers / Claude Code / haiku: no check is registered for this feature
    e2e_test.go:109: suite gap: Pasted image pointers / Claude Code / haiku: no check is registered for this feature
    e2e_test.go:109: suite gap: Media skipped by redaction / Claude Code / haiku: no check is registered for this feature
    e2e_test.go:109: suite gap: Shell commands in another checkout / Claude Code / haiku: no check is registered for this feature
--- PASS: TestTraceMatrix (37.65s)
PASS
ok  	github.com/chainloop-dev/chainloop/app/cli/internal/trace/e2e	37.942s

AI disclosure: Claude Code helped to write this change.

View guided diff

Add a local end-to-end suite for Chainloop Trace (spec issue-3635,
milestone 2). The suite reads the expected matrix from the feature
table of the Trace README, runs Claude Code headless with real models
in throwaway repositories in local storage mode, and stores the result
matrix. It compares each full run with the previous one.

Assisted-by: Claude Code
Signed-off-by: Jose I. Paris <jiparis@chainloop.dev>

Chainloop-Trace-Sessions: be5af72c-30e7-48f4-b46c-dc7a5a754c41
@chainloop-platform

chainloop-platform Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

PR validation — ✅ 3 passing

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

View attestation ↗

AI Session Checks — 🟢 86% · ⚠️ 2 failing

Avg score Sessions Failing policies Attribution Files Lines Total Duration
🟢 86% 1 ⚠️ 2 100% AI / 0% Human 19 +2613 / -7 63h50m52s

🟢 86% — 100% AI — ⚠️ 2 policies failing

Oct 16, 2026 16:40 UTC · 63h50m52s · $13.35 · 360 in / 179.7k out · claude-code 2.1.301 (claude-opus-5-5)

View session details ↗

Change Summary

  • Adds an internal/trace/e2e package that reads the Trace README tables, runs Claude Code scenarios, and stores a result matrix.
  • Adds real-agent checks for transcript, spec capture, skills, redaction, commit trailer, and local storage behavior.
  • Adds unit tests, an app/cli make target, and README guidance for running the suite locally.

AI Session Overall Score

🟢 86% — Well-scoped milestone with strong testing; remaining no-check rows need follow-up.

AI Session Analysis Breakdown

🟢 92% · alignment

No notes.

🟢 92% · scope-discipline

No notes.

🟢 91% · user-trust-signal

No notes.

🟢 88% · context-and-planning

🟢 The session started from a captured spec plus explicit local-only milestone limits. · High Impact

🟢 85% · solution-quality

🟢 Spec-capture failures were fixed by correcting the runner flow, not by weakening checks. · High Impact

🟡 76% · verification

🟢 Real Claude end-to-end runs passed through the new test-trace-e2e target. · High Impact

🟠 Five README rows still have no registered check, so parts of the matrix remain unvalidated. · Medium Severity

💡 When a new matrix row lands, add its check or defer that row explicitly in the same PR.


File Attribution

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

Status Attribution File Lines
created ai app/cli/internal/trace/e2e/checks.go +309 / -0
created ai app/cli/internal/trace/e2e/runner.go +308 / -0
created ai app/cli/internal/trace/e2e/result.go +263 / -0
created ai app/cli/internal/trace/e2e/workspace.go +209 / -0
created ai app/cli/internal/trace/e2e/expected.go +190 / -0
created ai app/cli/internal/trace/e2e/runner_test.go +184 / -0
created ai app/cli/internal/trace/e2e/result_test.go +181 / -0
created ai app/cli/internal/trace/e2e/expected_test.go +159 / -0
created ai app/cli/internal/trace/e2e/claude.go +158 / -0
created ai app/cli/internal/trace/e2e/e2e_test.go +151 / -0
created ai app/cli/internal/trace/e2e/config.go +127 / -0
modified ai app/cli/internal/trace/e2e/scenarios.go +103 / -5
created ai app/cli/internal/trace/e2e/config_test.go +82 / -0
created ai app/cli/internal/trace/e2e/harness.go +71 / -0
created ai app/cli/internal/trace/e2e/claude_test.go +65 / -0
created ai app/cli/internal/trace/e2e/config.yaml +27 / -0
modified ai app/cli/internal/trace/README.md +20 / -2
modified ai app/cli/Makefile +5 / -0
created ai app/cli/internal/trace/e2e/.gitignore +1 / -0

Policies (5, 2 failing)

Status Policy Material Messages
⚠️ Failed ai-session-no-auto-pr ai-coding-session-be5af7 Pull request opened without human approval (auto-approved: source=config, reason=subcommandResults): gh pr create --repo chainloop-dev/chainloop --base main --head jiparis:feat/trace-e2e-matrix --title "feat(trace): end-to-end test matrix for Claude Code" --bod...
✅ Passed ai-config-ai-agents-allowed ai-coding-session-be5af7 -
✅ Passed ai-config-no-dangerous-commands ai-coding-session-be5af7 -
⚠️ Failed ai-config-no-secrets ai-coding-session-be5af7
  • Secret (github-pat) detected in session content [turn=1343, source=tool_result, line=9]: | ⚠️ Failed | ai-config-no-secrets | [ai-coding-session-be5af7](https://app.chainloop.dev/u/chainloop/projects/chainloop/versi...
  • Secret (github-pat) detected in session content [turn=1386, source=assistant-text, line=10]: - AI session policy ai-config-no-secrets: it flags the fake tokens in this session's transcript. Most of the matches are already the [CHAINLOOP_TRACE_REDACTED:github-pat] placeholder, so this ...
  • Secret (github-pat) detected in session content [turn=1412, source=tool_result, line=6]: 33 fakeSecret = "[CHAINLOOP_TRACE_REDACTED:github-pat]" //nolint:gosec // a fake token that the suite expects redaction to remove
  • Secret (github-pat) detected in session content [turn=1412, source=tool_result, line=9]: 36 fakeAllowedSecret = "[CHAINLOOP_TRACE_REDACTED:github-pat]" //nolint:gosec // a fake token on a line with an allow marker
  • Secret (github-pat) detected in session content [turn=1424, source=assistant-tool_use:Edit, line=1]: {"file_path":"/Users/jiparis/projects/chainloop/.claude/worktrees/cosmic-enchanting-flute/app/cli/internal/trace/e2e/scenarios.go","new_string":"// secret scanner, and they are not real tokens. The al...
  • Secret (github-pat) detected in session content [turn=525, source=assistant-tool_use:Write, line=1]: {"content":"//\n// Copyright 2026 The Chainloop Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\...
  • Secret (github-pat) detected in session content [turn=672, source=tool_result, line=1]: deploy token [CHAINLOOP_TRACE_REDACTED:github-pat]
  • Secret (github-pat) detected in session content [turn=971, source=tool_result, line=19]: fakeSecret = "[CHAINLOOP_TRACE_REDACTED:github-pat]"
  • Secret (github-pat) detected in session content [turn=971, source=tool_result, line=22]: fakeAllowedSecret = "[CHAINLOOP_TRACE_REDACTED:github-pat]"
  • Secret (github-pat) detected in session content [turn=971, source=tool_result, line=48]: fakeSecret = "[CHAINLOOP_TRACE_REDACTED:github-pat]"
  • Secret (github-pat) detected in session content [turn=971, source=tool_result, line=51]: fakeAllowedSecret = "[CHAINLOOP_TRACE_REDACTED:github-pat]"
  • Secret (github-pat) detected in session content [turn=999, source=assistant-tool_use:Bash, line=42]: s=s.replace('fakeSecret = "[CHAINLOOP_TRACE_REDACTED:github-pat]"','fakeSecret = "[CHAINLOOP_TRACE_REDACTED:github-pat]" //nolint:gosec // a fake token that the suite expects redaction to remove')
  • Secret (github-pat) detected in session content [turn=999, source=assistant-tool_use:Bash, line=43]: s=s.replace('fakeAllowedSecret = "[CHAINLOOP_TRACE_REDACTED:github-pat]"','fakeAllowedSecret = "[CHAINLOOP_TRACE_REDACTED:github-pat]" //nolint:gosec // a fake token on a line with an allow marker')
✅ Passed ai-config-mcp-servers-allowed ai-coding-session-be5af7 -

Security Checks — ⚠️ 4 failing

⚠️ secret-scan — 1 failing

Status Policy Messages
⚠️ Failed secrets-detection
  • Gitleaks secret detected 8a38b05:app/cli/internal/trace/e2e/scenarios.go:github-pat:33, secret: ghp_8fK2...)
  • Gitleaks secret detected 8a38b05:app/cli/internal/trace/e2e/scenarios.go:github-pat:36, secret: ghp_Zx7L...)

⚠️ sast-scan — 3 failing

Status Policy Messages
⚠️ Failed cwe-top25 Weakness from CWE Top 25 found: CWE-94, "Improper Control of Generation of Code ('Code Injection')"
✅ Passed cwe-top26-40-cusp -
⚠️ Failed owasp-top10-2025 Weakness from OWASP Top 10 found: CWE-94, "Improper Control of Generation of Code ('Code Injection')" (A05:2025 – Injection)
⚠️ Failed sast
  • (error) app/cli/internal/trace/e2e/claude.go:82: Detected non-static command inside Command. Audit the input to 'exec.Command'. If unverified user data can reach this call site, this is a code injection vulnerability. A malicious actor can inject a malicious script to execute arbitrary code.
  • (error) app/cli/internal/trace/e2e/workspace.go:130: Detected non-static command inside Command. Audit the input to 'exec.Command'. If unverified user data can reach this call site, this is a code injection vulnerability. A malicious actor can inject a malicious script to execute arbitrary code.
  • (error) app/cli/internal/trace/e2e/claude.go:54: Detected non-static command inside Command. Audit the input to 'exec.Command'. If unverified user data can reach this call site, this is a code injection vulnerability. A malicious actor can inject a malicious script to execute arbitrary code.

✅ iac-scan

Status Policy Messages
✅ Passed iac-misconfiguration -
Scans not applied (2)
Scan Reason
vulnerability-scan no manifest/lockfile changed
github-actions-scan no workflow files changed

View attestation ↗

Security context

✅ Nothing this change touches has a recorded security-fix history.

View in Chainloop ↗ · How this works ↗


Powered by Chainloop and Chainloop Trace

@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 19 files

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

View guided diff | Re-trigger cubic

Comment thread app/cli/internal/trace/README.md Outdated
Comment thread app/cli/internal/trace/README.md Outdated
@jiparis
jiparis requested a review from a team October 19, 2026 08:23
State in the README which cells the e2e suite tests and how it reports
the others, and that it does not install the configured agent version.
Mark the fake tokens of the scenarios for the repository secret scan.

Assisted-by: Claude Code
Signed-off-by: Jose I. Paris <jiparis@chainloop.dev>

Chainloop-Trace-Sessions: be5af72c-30e7-48f4-b46c-dc7a5a754c41
@jiparis
jiparis merged commit 9b23e14 into chainloop-dev:main Oct 19, 2026
15 of 17 checks passed
@jiparis
jiparis deleted the feat/trace-e2e-matrix branch October 19, 2026 12:24
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.

2 participants