Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redact EXPLICIT_COMMAND_LINE #4525

Merged
merged 2 commits into from
Aug 11, 2023
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
21 changes: 21 additions & 0 deletions server/util/redact/redact.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package redact

import (
"context"
"encoding/json"
"reflect"
"regexp"
"strings"
Expand Down Expand Up @@ -38,6 +39,7 @@ const (
buildMetadataOptionPrefix = "--build_metadata="
allowEnvPrefix = "ALLOW_ENV="
allowEnvListSeparator = ","
explicitCommandLineName = "EXPLICIT_COMMAND_LINE"
)

var (
Expand Down Expand Up @@ -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] = ""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clearing out the arg (instead of dropping) might cause issues later, since a literal "" argument is treated by bazel as an error, but seems fine for now since we won't actually render the "" in the UI. just something to be aware of in case we see errors in the future

ERROR: Skipping '': invalid target name '': empty target name

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack, this should just be for UI rendering - we can switch to filtering if it causes issues.

}
}
}

func redactCmdLine(tokens []string) {
stripURLSecretsFromCmdLine(tokens)
stripRemoteHeadersFromCmdLine(tokens)
stripExplicitCommandLineFromCmdLine(tokens)
}

func stripURLSecretsFromFile(file *bespb.File) *bespb.File {
Expand All @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
26 changes: 23 additions & 3 deletions server/util/redact/redact_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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",
Expand All @@ -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\"]",
},
}

Expand All @@ -177,6 +193,7 @@ func TestRedactMetadata_OptionsParsed_StripsURLSecretsAndRemoteHeaders(t *testin
"--bes_header=<REDACTED>",
"--build_metadata=PATTERN=@//foo,NAME=@bar,SECRET=",
"--some_other_flag=//foo",
"",
},
optionsParsed.CmdLine)
assert.Equal(
Expand All @@ -188,6 +205,7 @@ func TestRedactMetadata_OptionsParsed_StripsURLSecretsAndRemoteHeaders(t *testin
"--bes_header=<REDACTED>",
"--build_metadata=PATTERN=@//foo,NAME=@bar,SECRET=",
"--some_other_flag=//foo",
"",
},
optionsParsed.ExplicitCmdLine)
}
Expand Down Expand Up @@ -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"]`,
},
}

Expand All @@ -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"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use < and > since they are plain ascii chars?

Suggested change
assert.Equal(t, `["--remote_header=\u003cREDACTED\u003e","--foo=SAFE"]`, buildMetadata.Metadata["EXPLICIT_COMMAND_LINE"])
assert.Equal(t, `["--remote_header=<REDACTED>","--foo=SAFE"]`, buildMetadata.Metadata["EXPLICIT_COMMAND_LINE"])

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had this initially, but it seems the JSON marshalling / unmarshalling code converts these into \u003c and \u003e. They're rendered correctly in the UI so it doesn't seem like a huge deal (there's a way to enable this escaping, but I'd kinda rather leave it enabled because I'm sure there's some reason for it).

What I was really looking for was an assert.Equal that behaves more like strings.EqualFold() but couldn't find anything.

Copy link
Member

@bduffany bduffany Aug 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd kinda rather leave it enabled because I'm sure there's some reason for it

ah I bet it's to support dumping these into HTML templates without the < being treated as a tag or something like that.

Copy link
Member

@bduffany bduffany Aug 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

huh, TIL: https://codepen.io/bduffs/pen/LYXoKoP

I guess the HTML parser isn't aware of what's going on inside the <script> and is just blindly looking for the closing </script>.

}

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