diff --git a/frontend/dockerfile/dockerfile_buildinfo_test.go b/frontend/dockerfile/dockerfile_buildinfo_test.go index d2e33a0c3e91..ea3705920972 100644 --- a/frontend/dockerfile/dockerfile_buildinfo_test.go +++ b/frontend/dockerfile/dockerfile_buildinfo_test.go @@ -52,7 +52,7 @@ func testBuildInfoSources(t *testing.T, sb integration.Sandbox) { dockerfile := ` FROM alpine:latest@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 AS alpine FROM busybox:latest -ADD https://raw.githubusercontent.com/moby/moby/v20.10.21/README.md / +ADD https://user2:pw2@raw.githubusercontent.com/moby/moby/v20.10.21/README.md / COPY --from=alpine /bin/busybox /alpine-busybox ` @@ -93,10 +93,15 @@ COPY --from=alpine /bin/busybox /alpine-busybox }} } + expectedURL := strings.Replace(server.URL, "http://", "http://xxxxx:xxxxx@", 1) + require.NotEqual(t, expectedURL, server.URL) + server.URL = strings.Replace(server.URL, "http://", "http://user:pass@", 1) + res, err := f.Solve(sb.Context(), c, client.SolveOpt{ Exports: exports, FrontendAttrs: map[string]string{ - builder.DefaultLocalNameContext: server.URL + "/.git#buildinfo", + builder.DefaultLocalNameContext: server.URL + "/.git#buildinfo", + builder.DefaultLocalNameContext + ":foo": "https://foo:bar@example.invalid/foo.html", }, }, nil) require.NoError(t, err) @@ -110,7 +115,9 @@ COPY --from=alpine /bin/busybox /alpine-busybox require.NoError(t, err) require.Contains(t, bi.Attrs, "context") - require.Equal(t, server.URL+"/.git#buildinfo", *bi.Attrs["context"]) + require.Equal(t, expectedURL+"/.git#buildinfo", *bi.Attrs["context"]) + + require.Equal(t, "https://xxxxx:xxxxx@example.invalid/foo.html", *bi.Attrs["context:foo"]) _, isGateway := f.(*gatewayFrontend) @@ -131,11 +138,11 @@ COPY --from=alpine /bin/busybox /alpine-busybox assert.NotEmpty(t, sources[1].Pin) assert.Equal(t, binfotypes.SourceTypeGit, sources[2].Type) - assert.Equal(t, server.URL+"/.git#buildinfo", sources[2].Ref) + assert.Equal(t, expectedURL+"/.git#buildinfo", sources[2].Ref) assert.NotEmpty(t, sources[2].Pin) assert.Equal(t, binfotypes.SourceTypeHTTP, sources[3].Type) - assert.Equal(t, "https://raw.githubusercontent.com/moby/moby/v20.10.21/README.md", sources[3].Ref) + assert.Equal(t, "https://xxxxx:xxxxx@raw.githubusercontent.com/moby/moby/v20.10.21/README.md", sources[3].Ref) assert.Equal(t, "sha256:419455202b0ef97e480d7f8199b26a721a417818bc0e2d106975f74323f25e6c", sources[3].Pin) } diff --git a/frontend/dockerfile/dockerfile_provenance_test.go b/frontend/dockerfile/dockerfile_provenance_test.go index 94f1374db0b1..835f72a52b86 100644 --- a/frontend/dockerfile/dockerfile_provenance_test.go +++ b/frontend/dockerfile/dockerfile_provenance_test.go @@ -74,12 +74,13 @@ RUN echo "ok" > /foo builder.DefaultLocalNameContext: dir, }, FrontendAttrs: map[string]string{ - "attest:provenance": provReq, - "build-arg:FOO": "bar", - "label:lbl": "abc", - "vcs:source": "https://example.invalid/repo.git", - "vcs:revision": "123456", - "filename": "Dockerfile", + "attest:provenance": provReq, + "build-arg:FOO": "bar", + "label:lbl": "abc", + "vcs:source": "https://user:pass@example.invalid/repo.git", + "vcs:revision": "123456", + "filename": "Dockerfile", + builder.DefaultLocalNameContext + ":foo": "https://foo:bar@example.invalid/foo.html", }, Exports: []client.ExportEntry{ { @@ -137,7 +138,7 @@ RUN echo "ok" > /foo require.Equal(t, "gateway.v0", pred.Invocation.Parameters.Frontend) if mode == "max" || mode == "" { - require.Equal(t, 3, len(args), "%v", args) + require.Equal(t, 4, len(args), "%v", args) require.True(t, pred.Metadata.Completeness.Parameters) require.Equal(t, "bar", args["build-arg:FOO"]) @@ -145,22 +146,24 @@ RUN echo "ok" > /foo require.Contains(t, args["source"], "buildkit_test/") } else { require.False(t, pred.Metadata.Completeness.Parameters) - require.Equal(t, 1, len(args), "%v", args) + require.Equal(t, 2, len(args), "%v", args) require.Contains(t, args["source"], "buildkit_test/") } + require.Equal(t, "https://xxxxx:xxxxx@example.invalid/foo.html", args["context:foo"]) } else { require.Equal(t, "dockerfile.v0", pred.Invocation.Parameters.Frontend) if mode == "max" || mode == "" { - require.Equal(t, 2, len(args)) + require.Equal(t, 3, len(args)) require.True(t, pred.Metadata.Completeness.Parameters) require.Equal(t, "bar", args["build-arg:FOO"]) require.Equal(t, "abc", args["label:lbl"]) } else { require.False(t, pred.Metadata.Completeness.Parameters) - require.Equal(t, 0, len(args), "%v", args) + require.Equal(t, 1, len(args), "%v", args) } + require.Equal(t, "https://xxxxx:xxxxx@example.invalid/foo.html", args["context:foo"]) } expectedBase := "pkg:docker/busybox@latest?platform=" + url.PathEscape(platforms.Format(platforms.Normalize(platforms.DefaultSpec()))) @@ -177,7 +180,7 @@ RUN echo "ok" > /foo if !isClient { require.Equal(t, "Dockerfile", pred.Invocation.ConfigSource.EntryPoint) - require.Equal(t, "https://example.invalid/repo.git", pred.Metadata.BuildKitMetadata.VCS["source"]) + require.Equal(t, "https://xxxxx:xxxxx@example.invalid/repo.git", pred.Metadata.BuildKitMetadata.VCS["source"]) require.Equal(t, "123456", pred.Metadata.BuildKitMetadata.VCS["revision"]) } @@ -265,6 +268,11 @@ COPY myapp.Dockerfile / target := registry + "/buildkit/testwithprovenance:git" + // inject dummy credentials to test that they are masked + expectedURL := strings.Replace(server.URL, "http://", "http://xxxxx:xxxxx@", 1) + require.NotEqual(t, expectedURL, server.URL) + server.URL = strings.Replace(server.URL, "http://", "http://user:pass@", 1) + _, err = f.Solve(sb.Context(), c, client.SolveOpt{ FrontendAttrs: map[string]string{ "context": server.URL + "/.git#v1", @@ -318,7 +326,7 @@ COPY myapp.Dockerfile / require.Equal(t, "", pred.Invocation.ConfigSource.EntryPoint) } else { require.NotEmpty(t, pred.Invocation.Parameters.Frontend) - require.Equal(t, server.URL+"/.git#v1", pred.Invocation.ConfigSource.URI) + require.Equal(t, expectedURL+"/.git#v1", pred.Invocation.ConfigSource.URI) require.Equal(t, "myapp.Dockerfile", pred.Invocation.ConfigSource.EntryPoint) } @@ -332,7 +340,7 @@ COPY myapp.Dockerfile / require.Equal(t, expBase, pred.Materials[1].URI) require.NotEmpty(t, pred.Materials[1].Digest["sha256"]) - require.Equal(t, server.URL+"/.git#v1", pred.Materials[2].URI) + require.Equal(t, expectedURL+"/.git#v1", pred.Materials[2].URI) require.Equal(t, strings.TrimSpace(string(expectedGitSHA)), pred.Materials[2].Digest["sha1"]) } else { require.Equal(t, 2, len(pred.Materials), "%+v", pred.Materials) @@ -340,7 +348,7 @@ COPY myapp.Dockerfile / require.Equal(t, expBase, pred.Materials[0].URI) require.NotEmpty(t, pred.Materials[0].Digest["sha256"]) - require.Equal(t, server.URL+"/.git#v1", pred.Materials[1].URI) + require.Equal(t, expectedURL+"/.git#v1", pred.Materials[1].URI) require.Equal(t, strings.TrimSpace(string(expectedGitSHA)), pred.Materials[1].Digest["sha1"]) } diff --git a/solver/llbsolver/provenance/capture.go b/solver/llbsolver/provenance/capture.go index a176e9875faa..6252ebc3cf34 100644 --- a/solver/llbsolver/provenance/capture.go +++ b/solver/llbsolver/provenance/capture.go @@ -5,6 +5,7 @@ import ( distreference "github.com/docker/distribution/reference" "github.com/moby/buildkit/solver/result" + "github.com/moby/buildkit/util/urlutil" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -190,6 +191,7 @@ func (c *Capture) AddLocal(l LocalSource) { } func (c *Capture) AddGit(g GitSource) { + g.URL = urlutil.RedactCredentials(g.URL) for _, v := range c.Sources.Git { if v.URL == g.URL { return @@ -199,6 +201,7 @@ func (c *Capture) AddGit(g GitSource) { } func (c *Capture) AddHTTP(h HTTPSource) { + h.URL = urlutil.RedactCredentials(h.URL) for _, v := range c.Sources.HTTP { if v.URL == h.URL { return diff --git a/solver/llbsolver/provenance/predicate.go b/solver/llbsolver/provenance/predicate.go index 7608f5cfae9c..a7b5a78cca51 100644 --- a/solver/llbsolver/provenance/predicate.go +++ b/solver/llbsolver/provenance/predicate.go @@ -7,6 +7,7 @@ import ( slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" slsa02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" "github.com/moby/buildkit/util/purl" + "github.com/moby/buildkit/util/urlutil" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/package-url/packageurl-go" ) @@ -151,6 +152,7 @@ func NewPredicate(c *Capture) (*ProvenancePredicate, error) { } else { inv.ConfigSource.URI = v } + inv.ConfigSource.URI = urlutil.RedactCredentials(inv.ConfigSource.URI) delete(c.Args, contextKey) } @@ -162,6 +164,9 @@ func NewPredicate(c *Capture) (*ProvenancePredicate, error) { vcs := make(map[string]string) for k, v := range c.Args { if strings.HasPrefix(k, "vcs:") { + if k == "vcs:source" { + v = urlutil.RedactCredentials(v) + } delete(c.Args, k) if v != "" { vcs[strings.TrimPrefix(k, "vcs:")] = v @@ -231,6 +236,11 @@ func FilterArgs(m map[string]string) map[string]string { "platform": {}, "cache-imports": {}, } + const defaultContextKey = "context" + contextKey := defaultContextKey + if v, ok := m["contextkey"]; ok && v != "" { + contextKey = v + } out := make(map[string]string) for k, v := range m { if _, ok := hostSpecificArgs[k]; ok { @@ -239,6 +249,9 @@ func FilterArgs(m map[string]string) map[string]string { if strings.HasPrefix(k, "attest:") { continue } + if k == contextKey || strings.HasPrefix(k, defaultContextKey+":") { + v = urlutil.RedactCredentials(v) + } out[k] = v } return out