diff --git a/server/util/redact/redact.go b/server/util/redact/redact.go index 6672b6e6dd9..a6d015f3dd6 100644 --- a/server/util/redact/redact.go +++ b/server/util/redact/redact.go @@ -2,6 +2,7 @@ package redact import ( "context" + "encoding/json" "reflect" "regexp" "strings" @@ -38,6 +39,7 @@ const ( buildMetadataOptionPrefix = "--build_metadata=" allowEnvPrefix = "ALLOW_ENV=" allowEnvListSeparator = "," + explicitCommandLineName = "EXPLICIT_COMMAND_LINE" ) var ( @@ -187,9 +189,18 @@ func stripRemoteHeadersFromCmdLine(tokens []string) { } } +func stripExplicitCommandLineFromCmdLine(tokens []string) { + for i, token := range tokens { + if strings.HasPrefix(token, buildMetadataOptionPrefix+explicitCommandLineName+"=") { + tokens[i] = "" + } + } +} + func redactCmdLine(tokens []string) { stripURLSecretsFromCmdLine(tokens) stripRemoteHeadersFromCmdLine(tokens) + stripExplicitCommandLineFromCmdLine(tokens) } func stripURLSecretsFromFile(file *bespb.File) *bespb.File { @@ -213,6 +224,13 @@ func stripRepoURLCredentialsFromBuildMetadata(metadata *bespb.BuildMetadata) { metadata.Metadata[repoURLKey] = gitutil.StripRepoURLCredentials(val) } } + if m, ok := metadata.Metadata[explicitCommandLineName]; ok { + var commandLine []string + _ = json.Unmarshal([]byte(m), &commandLine) + redactCmdLine(commandLine) + commandLineJSON, _ := json.Marshal(commandLine) + metadata.Metadata[explicitCommandLineName] = string(commandLineJSON) + } } func stripRepoURLCredentialsFromWorkspaceStatus(status *bespb.WorkspaceStatus) { @@ -256,6 +274,9 @@ func filterCommandLineOptions(options []*clpb.Option) []*clpb.Option { if option.OptionName == "default_override" { continue } + if option.OptionName == "build_metadata" && strings.HasPrefix(option.OptionValue, explicitCommandLineName) { + continue + } filtered = append(filtered, option) } return filtered diff --git a/server/util/redact/redact_test.go b/server/util/redact/redact_test.go index c6c1199c80c..ed921d340d4 100644 --- a/server/util/redact/redact_test.go +++ b/server/util/redact/redact_test.go @@ -141,6 +141,20 @@ func TestRedactMetadata_StructuredCommandLine(t *testing.T) { redactor.RedactMetadata(event) assert.Empty(t, getCommandLineOptions(event), "--default_override options should be removed") + + // EXPLICIT_COMMAND_LINE flags should be dropped altogether. + + option = &clpb.Option{ + OptionName: "build_metadata", + OptionValue: `EXPLICIT_COMMAND_LINE=["secrets"]`, + CombinedForm: `--build_metadata=EXPLICIT_COMMAND_LINE=["secrets"]`, + } + event = structuredCommandLineEvent(option) + assert.NotEmpty(t, getCommandLineOptions(event), "sanity check: EXPLICIT_COMMAND_LINE should be an option before redacting") + + redactor.RedactMetadata(event) + + assert.Empty(t, getCommandLineOptions(event), "EXPLICIT_COMMAND_LINE should be removed") } func TestRedactMetadata_OptionsParsed_StripsURLSecretsAndRemoteHeaders(t *testing.T) { @@ -153,6 +167,7 @@ func TestRedactMetadata_OptionsParsed_StripsURLSecretsAndRemoteHeaders(t *testin "--bes_header=foo=TOPSECRET", "--build_metadata=PATTERN=@//foo,NAME=@bar,SECRET=TOPSECRET@", "--some_other_flag=SUBFLAG=@//foo", + "--build_metadata=EXPLICIT_COMMAND_LINE=[\"SECRET\"]", }, ExplicitCmdLine: []string{ "213wZJyTUyhXkj381312@explicit", @@ -161,6 +176,7 @@ func TestRedactMetadata_OptionsParsed_StripsURLSecretsAndRemoteHeaders(t *testin "--bes_header=foo=TOPSECRET", "--build_metadata=PATTERN=@//foo,NAME=@bar,SECRET=TOPSECRET_EXPLICIT@", "--some_other_flag=SUBFLAG=@//foo", + "--build_metadata=EXPLICIT_COMMAND_LINE=[\"SECRET\"]", }, } @@ -177,6 +193,7 @@ func TestRedactMetadata_OptionsParsed_StripsURLSecretsAndRemoteHeaders(t *testin "--bes_header=", "--build_metadata=PATTERN=@//foo,NAME=@bar,SECRET=", "--some_other_flag=//foo", + "", }, optionsParsed.CmdLine) assert.Equal( @@ -188,6 +205,7 @@ func TestRedactMetadata_OptionsParsed_StripsURLSecretsAndRemoteHeaders(t *testin "--bes_header=", "--build_metadata=PATTERN=@//foo,NAME=@bar,SECRET=", "--some_other_flag=//foo", + "", }, optionsParsed.ExplicitCmdLine) } @@ -271,9 +289,10 @@ func TestRedactMetadata_BuildMetadata_StripsURLSecrets(t *testing.T) { redactor := redact.NewStreamingRedactor(testenv.GetTestEnv(t)) buildMetadata := &bespb.BuildMetadata{ Metadata: map[string]string{ - "ALLOW_ENV": "SHELL", - "ROLE": "METADATA_CI", - "REPO_URL": "https://USERNAME:PASSWORD@github.com/buildbuddy-io/metadata_repo_url", + "ALLOW_ENV": "SHELL", + "ROLE": "METADATA_CI", + "REPO_URL": "https://USERNAME:PASSWORD@github.com/buildbuddy-io/metadata_repo_url", + "EXPLICIT_COMMAND_LINE": `["--remote_header=x-buildbuddy-platform.container-registry-password=SECRET", "--foo=SAFE"]`, }, } @@ -282,6 +301,7 @@ func TestRedactMetadata_BuildMetadata_StripsURLSecrets(t *testing.T) { }) assert.Equal(t, "https://github.com/buildbuddy-io/metadata_repo_url", buildMetadata.Metadata["REPO_URL"]) + assert.Equal(t, `["--remote_header=\u003cREDACTED\u003e","--foo=SAFE"]`, buildMetadata.Metadata["EXPLICIT_COMMAND_LINE"]) } func TestRedactMetadata_WorkspaceStatus_StripsRepoURLCredentials(t *testing.T) {