diff --git a/build/opt.go b/build/opt.go index 4b5246c75181..8764087db82e 100644 --- a/build/opt.go +++ b/build/opt.go @@ -850,7 +850,7 @@ func loadInputs(ctx context.Context, d *driver.DriverHandle, inp *Inputs, pw pro if p, err := filepath.Abs(sharedKey); err == nil { sharedKey = filepath.Base(p) } - target.SharedKey = sharedKey + target.SharedKey = sanitizeSharedKey(sharedKey) switch inp.DockerfilePath { case "-": dockerfileReader = inp.InStream.NewReadCloser() @@ -1032,7 +1032,7 @@ func loadInputs(ctx context.Context, d *driver.DriverHandle, inp *Inputs, pw pro } else { sharedKey = filepath.Base(sharedKey) } - target.FrontendAttrs["sharedkey:localdir:"+k] = sharedKey + target.FrontendAttrs["sharedkey:localdir:"+k] = sanitizeSharedKey(sharedKey) } release := func() { @@ -1542,6 +1542,16 @@ func isActive(ce *client.CacheOptionsEntry) bool { return ce.Attrs["token"] != "" && (ce.Attrs["url"] != "" || ce.Attrs["url_v2"] != "") } +// sanitizeSharedKey hashes non-ASCII keys for gRPC metadata +func sanitizeSharedKey(key string) string { + for i := 0; i < len(key); i++ { + if key[i] < 0x20 || key[i] > 0x7E { + return digest.FromString(key).Encoded() + } + } + return key +} + func defaultPlatform(bopts gateway.BuildOpts) *ocispecs.Platform { pl := bopts.Workers[0].Platforms if len(pl) == 0 { diff --git a/build/opt_test.go b/build/opt_test.go index 9327d211d37c..89cca9015143 100644 --- a/build/opt_test.go +++ b/build/opt_test.go @@ -167,6 +167,31 @@ func TestProxyArgKeyExists(t *testing.T) { } } +func TestSanitizeSharedKey(t *testing.T) { + tests := []struct { + name string + key string + want string + }{ + { + name: "ascii", + key: "a", + want: "a", + }, + { + name: "non-ascii", + key: "早", + want: "e7c7fb50f3db8408eacd8f1702021a00a7b8cfb549f422fcf4d977f725df4b36", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, sanitizeSharedKey(tt.key)) + }) + } +} + func TestApplyPolicyCapsEnablesProxyNetwork(t *testing.T) { p := policyWithDecision(` package docker