Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ require (
github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.1
github.com/Microsoft/go-winio v0.6.2
github.com/a2aproject/a2a-go v0.3.15
github.com/alecthomas/chroma/v2 v2.24.1
github.com/alecthomas/chroma/v2 v2.25.0
github.com/alpkeskin/gotoon v0.1.1
github.com/anthropics/anthropic-sdk-go v1.45.0
github.com/atotto/clipboard v0.1.4
github.com/aws/aws-sdk-go-v2 v1.41.7
github.com/aws/aws-sdk-go-v2/config v1.32.17
github.com/aws/aws-sdk-go-v2/credentials v1.19.16
github.com/aws/aws-sdk-go-v2/config v1.32.18
github.com/aws/aws-sdk-go-v2/credentials v1.19.17
github.com/aws/aws-sdk-go-v2/service/bedrockruntime v1.52.0
github.com/aws/aws-sdk-go-v2/service/sts v1.42.1
github.com/aws/smithy-go v1.25.1
Expand All @@ -30,7 +30,7 @@ require (
github.com/coder/acp-go-sdk v0.13.0
github.com/docker/cli v29.5.2+incompatible
github.com/docker/go-units v0.5.0
github.com/docker/portcullis v0.0.0-20260522094836-b66c4ab750fd
github.com/docker/portcullis v0.0.0-20260526131538-fc97bf12bbdb
github.com/dop251/goja v0.0.0-20260311135729-065cd970411c
github.com/fatih/color v1.19.0
github.com/fsnotify/fsnotify v1.10.1
Expand All @@ -42,7 +42,7 @@ require (
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.3
github.com/hashicorp/hcl/v2 v2.24.0
github.com/junegunn/fzf v0.72.0
github.com/junegunn/fzf v0.73.1
github.com/k3a/html2text v1.4.0
github.com/kofalt/go-memoize v0.0.0-20240506050413-9e5eb99a0f2a
github.com/labstack/echo/v4 v4.15.2
Expand Down Expand Up @@ -86,6 +86,7 @@ require (
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 // indirect
github.com/blevesearch/zapx/v17 v17.1.2 // indirect
github.com/danieljoos/wincred v1.2.2 // indirect
github.com/dlclark/regexp2/v2 v2.1.0 // indirect
github.com/dvsekhvalnov/jose2go v1.7.0 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
Expand Down Expand Up @@ -120,7 +121,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/bits-and-blooms/bitset v1.24.4 // indirect
Expand Down
26 changes: 14 additions & 12 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tj
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma/v2 v2.24.1 h1:m5ffpfZbIb++k8AqFEKy9uVgY12xIQtBsQlc6DfZJQM=
github.com/alecthomas/chroma/v2 v2.24.1/go.mod h1:l+ohZ9xRXIbGe7cIW+YZgOGbvuVLjMps/FYN/CwuabI=
github.com/alecthomas/chroma/v2 v2.25.0 h1:DWkVlxrNpxPf+Qcfe04LBqUArxUiybK8ZQ9T7OFu68E=
github.com/alecthomas/chroma/v2 v2.25.0/go.mod h1:+95AZrRWlpW9g6qXD7S7UdHviopsGP/kCIrtJcU3QoQ=
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
Expand All @@ -65,10 +65,10 @@ github.com/aws/aws-sdk-go-v2 v1.41.7 h1:DWpAJt66FmnnaRIOT/8ASTucrvuDPZASqhhLey6t
github.com/aws/aws-sdk-go-v2 v1.41.7/go.mod h1:4LAfZOPHNVNQEckOACQx60Y8pSRjIkNZQz1w92xpMJc=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.10 h1:gx1AwW1Iyk9Z9dD9F4akX5gnN3QZwUB20GGKH/I+Rho=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.10/go.mod h1:qqY157uZoqm5OXq/amuaBJyC9hgBCBQnsaWnPe905GY=
github.com/aws/aws-sdk-go-v2/config v1.32.17 h1:FpL4/758/diKwqbytU0prpuiu60fgXKUWCpDJtApclU=
github.com/aws/aws-sdk-go-v2/config v1.32.17/go.mod h1:OXqUMzgXytfoF9JaKkhrOYsyh72t9G+MJH8mMRaexOE=
github.com/aws/aws-sdk-go-v2/credentials v1.19.16 h1:r3RJBuU7X9ibt8RHbMjWE6y60QbKBiII6wSrXnapxSU=
github.com/aws/aws-sdk-go-v2/credentials v1.19.16/go.mod h1:6cx7zqDENJDbBIIWX6P8s0h6hqHC8Avbjh9Dseo27ug=
github.com/aws/aws-sdk-go-v2/config v1.32.18 h1:Hcia46bxhGgF3BaSnG8nSNCWmqTK6bj9xN9/FJ3WK6Q=
github.com/aws/aws-sdk-go-v2/config v1.32.18/go.mod h1:zEjCAYmxqDadH1WX8CdBvmLKhUEUVFgKRQG38zjDmrY=
github.com/aws/aws-sdk-go-v2/credentials v1.19.17 h1:gP2nkGsS+KMvF/jfFz2Vv2qiiOqWKyPACSzPsqHgoW8=
github.com/aws/aws-sdk-go-v2/credentials v1.19.17/go.mod h1:Bsew3S/moG5iT77giPj1q8wb/s0RE5/QfH+ASjYtuQc=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 h1:UuSfcORqNSz/ey3VPRS8TcVH2Ikf0/sC+Hdj400QI6U=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23/go.mod h1:+G/OSGiOFnSOkYloKj/9M35s74LgVAdJBSD5lsFfqKg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 h1:GpT/TrnBYuE5gan2cZbTtvP+JlHsutdmlV2YfEyNde0=
Expand All @@ -87,8 +87,8 @@ github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 h1:TdJ+HdzOBhU8+iVAOGUTU63VX
github.com/aws/aws-sdk-go-v2/service/signin v1.0.11/go.mod h1:R82ZRExE/nheo0N+T8zHPcLRTcH8MGsnR3BiVGX0TwI=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 h1:7byT8HUWrgoRp6sXjxtZwgOKfhss5fW6SkLBtqzgRoE=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.17/go.mod h1:xNWknVi4Ezm1vg1QsB/5EWpAJURq22uqd38U8qKvOJc=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 h1:+1Kl1zx6bWi4X7cKi3VYh29h8BvsCoHQEQ6ST9X8w7w=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21/go.mod h1:4vIRDq+CJB2xFAXZ+YgGUTiEft7oAQlhIs71xcSeuVg=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0 h1:nDARhv/oF55bcxF7rCI/4PDxOKnVXVWwDuDwCs2I2SQ=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0/go.mod h1:4vIRDq+CJB2xFAXZ+YgGUTiEft7oAQlhIs71xcSeuVg=
github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 h1:F/M5Y9I3nwr2IEpshZgh1GeHpOItExNM9L1euNuh/fk=
github.com/aws/aws-sdk-go-v2/service/sts v1.42.1/go.mod h1:mTNxImtovCOEEuD65mKW7DCsL+2gjEH+RPEAexAzAio=
github.com/aws/smithy-go v1.25.1 h1:J8ERsGSU7d+aCmdQur5Txg6bVoYelvQJgtZehD12GkI=
Expand Down Expand Up @@ -199,6 +199,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8=
github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2/v2 v2.1.0 h1:jHXRmHRZGbuQzDZjMlCAXOvQb75iv3HyLDzXGj5H1AY=
github.com/dlclark/regexp2/v2 v2.1.0/go.mod h1:Bz5TMy5d8fPK0ximH0Yi9KvsRHNnvXqUx9XG6a4wB+I=
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/cli v29.5.2+incompatible h1:ubykJ1Y8LmNRGJ2BuMQ0kHOt/RO1YzGNswqWMJgivuQ=
Expand All @@ -213,8 +215,8 @@ github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQ
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/portcullis v0.0.0-20260522094836-b66c4ab750fd h1:IGSoI9F8+p5ukGASbGrKpa0Mxm9CIGL6f/QzCgRzOhg=
github.com/docker/portcullis v0.0.0-20260522094836-b66c4ab750fd/go.mod h1:3Hov4sJxb5afp5R4NE9wSz/c8xlCTU9Kn1sUgF6O6U4=
github.com/docker/portcullis v0.0.0-20260526131538-fc97bf12bbdb h1:0Juktp2Xn6Nxs0fqaCeuTSM01i6Pe1+7aKLsBhMfp2I=
github.com/docker/portcullis v0.0.0-20260526131538-fc97bf12bbdb/go.mod h1:FBCDtWLlYquonR/uesgN9HhLvbaDIX3PEC6lgHCnL24=
github.com/dop251/goja v0.0.0-20260311135729-065cd970411c h1:OcLmPfx1T1RmZVHHFwWMPaZDdRf0DBMZOFMVWJa7Pdk=
github.com/dop251/goja v0.0.0-20260311135729-065cd970411c/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
Expand Down Expand Up @@ -328,8 +330,8 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/junegunn/fzf v0.72.0 h1:GnXEfKYp3s/HljrIcDgkOrWWxHWfhkLyRBIiC/enaVY=
github.com/junegunn/fzf v0.72.0/go.mod h1:xlXX2/rmsccKQUnr9QOXPDi5DyV9cM0UjKy/huScBeE=
github.com/junegunn/fzf v0.73.1 h1:Ni9jaVMxsehcx9IwJ4ZAL/sr2c4dOEg1DHIAwPUVlyo=
github.com/junegunn/fzf v0.73.1/go.mod h1:hKDkO8orBWT5VLIZOL8oyhxn7mRLXdGyu+gz1Ss58pU=
github.com/junegunn/go-shellwords v0.0.0-20250127100254-2aa3b3277741 h1:7dYDtfMDfKzjT+DVfIS4iqknSEKtZpEcXtu6vuaasHs=
github.com/junegunn/go-shellwords v0.0.0-20250127100254-2aa3b3277741/go.mod h1:6EILKtGpo5t+KLb85LNZLAF6P9LKp78hJI80PXMcn3c=
github.com/k3a/html2text v1.4.0 h1:e4xarrVgZST+h+5C/fbA6AI49VFDSlEWMmIcDWcxsd0=
Expand Down
15 changes: 10 additions & 5 deletions pkg/hooks/builtins/redact_secrets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@ import (

"github.com/docker/docker-agent/pkg/chat"
"github.com/docker/docker-agent/pkg/hooks"
"github.com/docker/docker-agent/pkg/internal/portcullistest"
"github.com/docker/docker-agent/pkg/tools"
)

func fakeGitHubPAT() string {
return portcullistest.FakeGitHubPAT("cxLeRrvbJfmYdUtr70xnNE3Q7Gvli4")
}

// TestRedactSecretsScrubsTopLevelStringValue: a recognised secret in
// a top-level string argument is replaced and ONLY the rewritten key
// is emitted in UpdatedInput. The latter is critical because
Expand All @@ -21,7 +26,7 @@ import (
func TestRedactSecretsScrubsTopLevelStringValue(t *testing.T) {
t.Parallel()

const secret = "ghp_cxLeRrvbJfmYdUtr70xnNE3Q7Gvli43s19PD"
secret := fakeGitHubPAT()

in := &hooks.Input{
HookEventName: hooks.EventPreToolUse,
Expand Down Expand Up @@ -133,7 +138,7 @@ func TestRedactSecretsIsRegistered(t *testing.T) {
handler, ok := reg.LookupBuiltin(RedactSecrets)
require.Truef(t, ok, "builtin %q must be registered", RedactSecrets)

const secret = "ghp_cxLeRrvbJfmYdUtr70xnNE3Q7Gvli43s19PD"
secret := fakeGitHubPAT()
out, err := handler(t.Context(), &hooks.Input{
HookEventName: hooks.EventPreToolUse,
ToolName: "shell",
Expand Down Expand Up @@ -187,7 +192,7 @@ func TestApplyAgentDefaultsInjectsRedactSecrets(t *testing.T) {
func TestRedactSecretsScrubsOutgoingMessages(t *testing.T) {
t.Parallel()

const secret = "ghp_cxLeRrvbJfmYdUtr70xnNE3Q7Gvli43s19PD"
secret := fakeGitHubPAT()
in := &hooks.Input{
HookEventName: hooks.EventBeforeLLMCall,
Messages: []chat.Message{
Expand Down Expand Up @@ -236,7 +241,7 @@ func TestRedactSecretsBeforeLLMCallNoOpOnCleanMessages(t *testing.T) {
func TestRedactSecretsBeforeLLMCallScrubsToolCallArguments(t *testing.T) {
t.Parallel()

const secret = "ghp_cxLeRrvbJfmYdUtr70xnNE3Q7Gvli43s19PD"
secret := fakeGitHubPAT()
in := &hooks.Input{
HookEventName: hooks.EventBeforeLLMCall,
Messages: []chat.Message{
Expand Down Expand Up @@ -275,7 +280,7 @@ func TestRedactSecretsBeforeLLMCallScrubsToolCallArguments(t *testing.T) {
func TestRedactSecretsScrubsToolOutput(t *testing.T) {
t.Parallel()

const secret = "ghp_cxLeRrvbJfmYdUtr70xnNE3Q7Gvli43s19PD"
secret := fakeGitHubPAT()
in := &hooks.Input{
HookEventName: hooks.EventToolResponseTransform,
ToolName: "shell",
Expand Down
33 changes: 33 additions & 0 deletions pkg/internal/portcullistest/fakegithubpat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Package portcullistest provides test helpers for code that
// exercises portcullis' GitHub-token detection rules.
package portcullistest

import "hash/crc32"

// FakeGitHubPAT returns a synthetic GitHub PAT whose trailing 6-char
// base62 CRC32 suffix passes portcullis' validGitHubChecksum, so the
// returned token is detected (and redacted) by the secret scanner.
//
// The token is assembled at runtime: the full 40-char `ghp_…` string
// never appears as a source literal, so GitHub's secret-scanning
// push protection won't flag files that call this helper.
//
// body must be exactly 30 base62 characters; callers vary it to get
// distinct fake tokens. The result has the GitHub-PAT shape
// `ghp_` + 36 base62 chars and is never a real credential.
func FakeGitHubPAT(body string) string {
const (
alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
suffixLen = 6
)
if len(body) != 30 {
panic("portcullistest: body must be 30 chars")
}
var suffix [suffixLen]byte
checksum := uint64(crc32.ChecksumIEEE([]byte(body)))
for i := suffixLen - 1; i >= 0; i-- {
suffix[i] = alphabet[checksum%62]
checksum /= 62
}
return "ghp_" + body + string(suffix[:])
}
28 changes: 28 additions & 0 deletions pkg/internal/portcullistest/fakegithubpat_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package portcullistest_test

import (
"strings"
"testing"

"github.com/docker/portcullis"
"github.com/stretchr/testify/assert"

"github.com/docker/docker-agent/pkg/internal/portcullistest"
)

func TestFakeGitHubPAT_DetectedByPortcullis(t *testing.T) {
t.Parallel()

tok := portcullistest.FakeGitHubPAT("cxLeRrvbJfmYdUtr70xnNE3Q7Gvli4")

assert.True(t, strings.HasPrefix(tok, "ghp_"))
assert.Len(t, tok, 40)
assert.True(t, portcullis.Contains(tok), "synthetic PAT must trigger portcullis detection")
assert.Equal(t, portcullis.Marker, portcullis.Redact(tok))
}

func TestFakeGitHubPAT_RejectsWrongLength(t *testing.T) {
t.Parallel()

assert.Panics(t, func() { portcullistest.FakeGitHubPAT("too-short") })
}
20 changes: 12 additions & 8 deletions pkg/sandbox/kit/kit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ import (
"github.com/stretchr/testify/require"

latestcfg "github.com/docker/docker-agent/pkg/config/latest"
"github.com/docker/docker-agent/pkg/internal/portcullistest"
"github.com/docker/docker-agent/pkg/promptfiles"
"github.com/docker/docker-agent/pkg/skills"
)

// fakeGitHubToken is a syntactically valid GitHub PAT that triggers
// portcullis. It is only used as input to the redactor, never as an
// fakeGitHubToken is used only as input to the redactor, never as an
// actual credential.
const fakeGitHubToken = "ghp_" + "1234567890abcdefghijklmnopqrstuvwxyz"
func fakeGitHubToken() string {
return portcullistest.FakeGitHubPAT("1234567890abcdefghijklmnopqrst")
}

// isolateEnv prevents a developer-exported DOCKER_AGENT_KIT_DIR from
// flipping the in-process resolvers (notably skills.Load) into
Expand All @@ -39,7 +41,8 @@ func TestBuild_StagesSkillsAndRedacts(t *testing.T) {
// Stage one local skill on the host with a secret embedded.
skillDir := filepath.Join(hostHome, ".agents", "skills", "secret-keeper")
require.NoError(t, os.MkdirAll(skillDir, 0o755))
skillBody := "---\nname: secret-keeper\ndescription: ships with a secret\n---\n\ntoken=" + fakeGitHubToken + "\n"
token := fakeGitHubToken()
skillBody := "---\nname: secret-keeper\ndescription: ships with a secret\n---\n\ntoken=" + token + "\n"
require.NoError(t, os.WriteFile(filepath.Join(skillDir, "SKILL.md"), []byte(skillBody), 0o644))

t.Setenv("HOME", hostHome)
Expand All @@ -66,7 +69,7 @@ func TestBuild_StagesSkillsAndRedacts(t *testing.T) {
staged := filepath.Join(res.HostDir, skills.KitSkillsSubdir, "secret-keeper", "SKILL.md")
data, err := os.ReadFile(staged)
require.NoError(t, err)
assert.NotContains(t, string(data), fakeGitHubToken, "host secret must not survive in kit")
assert.NotContains(t, string(data), token, "host secret must not survive in kit")
assert.Contains(t, string(data), portcullis.Marker, "redaction marker must be present")

// The manifest records the skill and the redaction.
Expand Down Expand Up @@ -555,8 +558,9 @@ func TestPrintSummary(t *testing.T) {
// with secret count, and ~ collapsing of host paths.
withSecret := filepath.Join(hostHome, ".agents", "skills", "with-secret")
require.NoError(t, os.MkdirAll(withSecret, 0o755))
token := fakeGitHubToken()
require.NoError(t, os.WriteFile(filepath.Join(withSecret, "SKILL.md"),
[]byte("---\nname: with-secret\ndescription: leaks\n---\n\ntoken="+fakeGitHubToken+"\n"), 0o644))
[]byte("---\nname: with-secret\ndescription: leaks\n---\n\ntoken="+token+"\n"), 0o644))
require.NoError(t, os.WriteFile(filepath.Join(withSecret, "helper.sh"),
[]byte("#!/bin/sh\necho hi\n"), 0o755))

Expand All @@ -566,7 +570,7 @@ func TestPrintSummary(t *testing.T) {
[]byte("---\nname: plain\ndescription: plain\n---\n"), 0o644))

agentsMD := filepath.Join(hostHome, "AGENTS.md")
require.NoError(t, os.WriteFile(agentsMD, []byte("token="+fakeGitHubToken+"\n"), 0o600))
require.NoError(t, os.WriteFile(agentsMD, []byte("token="+token+"\n"), 0o600))

workspace := t.TempDir()
agentYAML := []byte(`#!/usr/bin/env docker-agent
Expand Down Expand Up @@ -622,7 +626,7 @@ models:
assert.Contains(t, out, "summary: 2 skills, 1 prompt file, 2 secrets redacted")

// And no host secret leaks into the printed output.
assert.NotContains(t, out, fakeGitHubToken)
assert.NotContains(t, out, token)
}

func TestPrintSummary_WorkspacePromptFile(t *testing.T) {
Expand Down
Loading