Skip to content

feat: allow masking output on comments #4331

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

GMartinez-Sisti
Copy link
Member

@GMartinez-Sisti GMartinez-Sisti commented Mar 10, 2024

what

Part of #163 (comment).

why

I have the requirements to mask some values that are passed to the comments posted by Atlantis, building up on strip_refreshing I added two new output configurations that will allow this via a regex configured on the step. There is an assumption that users that shouldn't see secrets/sensitive values won't have access to the URL jobs, where the plan outputs are shown untouched.

The output key can now contain a string, []stringor[]any`, this was we ensure compatibility while adding new possibilities to it.

Example (added to the docs):

workflows:
  terragrunt:
    plan:
      steps:
      - run:
          command: terragrunt plan -input=false -out=$PLANFILE
          output:
            - strip_refreshing
            # Filters text matching 'mySecret: "aaa"' -> 'mySecret: "<redacted>"'
            - filter_regex: "((?i)secret:\\s\")[^\"]*"

Note that the changes related to mocks were made manually since make go-generate is currently broken (#4664).

tests

  • Running all the tests locally and adding coverage for the new feature
  • Build and deployed this version with the new config from feature and tested that atlantis plan provides the desired masked output on GitHub 😄

references

Possibly solves #163.

@GMartinez-Sisti GMartinez-Sisti requested review from a team as code owners March 10, 2024 18:41
@GMartinez-Sisti GMartinez-Sisti requested review from jamengual, lukemassa and X-Guardian and removed request for a team March 10, 2024 18:41
@github-actions github-actions bot added docs Documentation go Pull requests that update Go code provider/github labels Mar 10, 2024
@jamengual
Copy link
Contributor

did you test tfmask? or any other tool?

@GMartinez-Sisti
Copy link
Member Author

GMartinez-Sisti commented Mar 10, 2024

did you test tfmask? or any other tool?

I did, also terrahelp and even plain sed. The problem is that we are sending the output straight to the $planfile, so we can’t act on it. I even tried to change the $showfile, and while that works, Atlantis doesn’t use it for the comment.

@jamengual
Copy link
Contributor

I see ok, it make sense on doing the pre-processing

@jamengual jamengual added feature New functionality/enhancement waiting-on-review Waiting for a review from a maintainer labels Mar 10, 2024
@jamengual jamengual added this to the v0.28.0 milestone Apr 2, 2024
@chenrui333 chenrui333 modified the milestones: v0.28.0, v0.29.0 May 22, 2024
@anryko
Copy link
Contributor

anryko commented May 28, 2024

I like the feature and find it very useful. However, IMHO, the API could be better.
To maintain backward compatibility and allow for extending this API I would suggest the following implementation:

workflows:
  terragrunt:
    plan:
      steps:
      - run:
          command: terragrunt plan -input=false -out=$PLANFILE
          output: strip_refreshing|show|hide
      - run:
          command: terragrunt plan -input=false -out=$PLANFILE
          output:
            - show
            - strip_refreshing
            - filter_regex: "((?i)secret:\\s\")[^\"]*"

This would allow us to support previous string values and in case of the list[string], apply multiple filters sequentially, as well as add more filters in the future without breaking the API.
The filter_regex is a better name because it matches <action> | <action>_<topic> naming pattern of already supported strip_refreshing|show|hide output actions.

@GMartinez-Sisti
Copy link
Member Author

GMartinez-Sisti commented May 28, 2024

I like the feature and find it very useful. However, IMHO, the API could be better. To maintain backward compatibility and allow for extending this API I would suggest the following implementation:

workflows:
  terragrunt:
    plan:
      steps:
      - run:
          command: terragrunt plan -input=false -out=$PLANFILE
          output: strip_refreshing|show|hide
      - run:
          command: terragrunt plan -input=false -out=$PLANFILE
          output:
            - show
            - strip_refreshing
            - filter_regex: "((?i)secret:\\s\")[^\"]*"

This would allow us to support previous string values and in case of the list[string], apply multiple filters sequentially, as well as add more filters in the future without breaking the API. The filter_regex is a better name because it matches <action> | <action>_<topic> naming pattern of already supported strip_refreshing|show|hide output actions.

Hi, thanks for the feedback 😃

I've been using this to support terraform for 100+ environments on the three major clouds with zero issues so far. I adjusted the regex to "((?i)secret.*:\\s\")[^\"]*" so it includes pretty much all fields with secret on the name.

I have to rebase this soon, I'll take a stab at making it work the way you suggested and see how it behaves.

@X-Guardian
Copy link
Contributor

Hi @GMartinez-Sisti, are you able to look at the suggestions from @anryko. It would be great to get this merged.

@X-Guardian X-Guardian added waiting-on-response Waiting for a response from the user and removed waiting-on-review Waiting for a review from a maintainer labels Nov 2, 2024
@GMartinez-Sisti
Copy link
Member Author

GMartinez-Sisti commented Nov 3, 2024

I've been thinking about the suggested API, the suggested output accepts either:

  • a string
  • a list of strings and a list of maps

I think this is not ideal and might create some confusion, we can support multiple types but only one at a time and act accordingly. This is my suggestion:

workflows:
  terragrunt:
    plan:
      steps:
      - run:
          command: terragrunt plan -input=false -out=$PLANFILE
          output: strip_refreshing|show|hide
      - run:
          command: terragrunt plan -input=false -out=$PLANFILE
          output:
            - show
            - strip_refreshing
            - filter_regex
          regex_expression: "((?i)secret:\\s\")[^\"]*"
  • output accepts either string or map[string]string
  • regex_expression has a default value and we can optionally define it to set a different value

WDYT @anryko and @X-Guardian ?

@anryko
Copy link
Contributor

anryko commented Nov 3, 2024

The api I suggested would provide an option to apply a sequence of simple regexps one after another. It would make your feature more powerful. I understand the added implementation complexity you are referring to and believe that this would be a bit easier to implement on top of the changes done for this feature, which "loosens" the config unmarshaling.

@GMartinez-Sisti
Copy link
Member Author

The api I suggested would provide an option to apply a sequence of simple regexps one after another. It would make your feature more powerful. I understand the added implementation complexity you are referring to and believe that this would be a bit easier to implement on top of the changes done for this feature, which "loosens" the config unmarshaling.

I see it, while being more verbose it will be more flexible indeed. I'll wait for #5024 to be merged then so I can leverage the new map[string]map[string]interface{}.

@X-Guardian
Copy link
Contributor

Hi @GMartinez-Sisti, #5024 is now merged. Can you resolve the conflicts on this?

@GMartinez-Sisti GMartinez-Sisti force-pushed the add-regex-filter branch 2 times, most recently from fd73789 to dd862aa Compare November 10, 2024 17:17
@GMartinez-Sisti
Copy link
Member Author

Hi @GMartinez-Sisti, #5024 is now merged. Can you resolve the conflicts on this?

I've fixed the conflicts, but haven't updated the logic to match the suggestions.

Copy link

This issue is stale because it has been open for 1 month with no activity. Remove stale label or comment or this will be closed in 1 month.

@github-actions github-actions bot added the Stale label Dec 12, 2024
@GMartinez-Sisti
Copy link
Member Author

Will still work on this! ☺️

@X-Guardian X-Guardian removed this from the v0.29.0 milestone Dec 17, 2024
@jamengual
Copy link
Contributor

@GMartinez-Sisti still working on this? Thanks.

@GMartinez-Sisti
Copy link
Member Author

@GMartinez-Sisti still working on this? Thanks.

Yes! Just haven't add the time to focus and update it. But not forgotten.

Copy link

github-actions bot commented Feb 3, 2025

This issue is stale because it has been open for 1 month with no activity. Remove stale label or comment or this will be closed in 1 month.

@GMartinez-Sisti
Copy link
Member Author

I'll pick this up this weekend. Sorry for the delay.

@GMartinez-Sisti GMartinez-Sisti force-pushed the add-regex-filter branch 5 times, most recently from 34e6093 to 0a039ba Compare March 9, 2025 21:56
@GMartinez-Sisti
Copy link
Member Author

@X-Guardian @jamengual @anryko I finally got some time to work on this! Please take a look when possible :) 🙏

)

// ParseRegex validates and returns a [Regexp] object
func ParseRegex(pattern string) (*regexp.Regexp, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this warrants a "utility" function. Its purpose seems to be just to change the zero object from the empty string regex to a nil. I'd prefer this happens at the call site, since it's not a "general" behavior we have. Additionally this would allow

testRegexDotStar, _ := utils.ParseRegex(".*")

to be written in the simpler and more idiomatic

testRegexDotStar := regexp.MustCompile(".*")

If we have to have this utility function, I'd prefer its name be changed to reflect the way its semantics differ from that of the standard library regexp.Compile, or at the very least its godoc comment updated to explain the difference.

Copy link
Member Author

Choose a reason for hiding this comment

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

Moving it closer to the call site makes sense. When I started this I thought it would have to be reused across multiple packages, but in the end it didn't so I can move it.

Regarding MustCompile, this will panic if it fails to parse, it's true that we already validated it when we parsed the configs so we can change it, was just trying to play it safe 😅 .

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh yeah sorry to be clear, I'm only recommending MustCompile() in cases where you pass a literal string to it, like in tests.

Copy link
Member Author

Choose a reason for hiding this comment

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

This func is used in multiple in the raw package:

→ ag ParseRegex
server/core/config/raw/step.go
311:                                                    _, err := utils.ParseRegex(v)
450:                                                                    r, _ := utils.ParseRegex(t)
454:                                                                            r, _ := utils.ParseRegex(e)

server/core/config/raw/step_test.go
508:    testRegexDotStar, _ := utils.ParseRegex(".*")
509:    testRegexSecret, _ := utils.ParseRegex("((?i)secret:\\s\")[^\"]*")

server/core/runtime/run_step_runner_test.go
26:     testRegexSecret, _ := utils.ParseRegex(`((?i)Secret:\s")[^"]*`)

server/core/runtime/plan_step_runner_test.go
654:            r, err := utils.ParseRegex(c.regex)

server/utils/regex.go
7:// ParseRegex validates and returns a [Regexp] object
8:func ParseRegex(pattern string) (*regexp.Regexp, error) {

What is your suggestion here? Just move the regex.go file to the raw package? Or add the func to a random file from that package?

return output
}

return filterRegex.ReplaceAllString(output, "${1}<redacted>$2")
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like the logic here is that we keep the first and second capture group, if they exist, and put them before and after <redacted>. I don't see this in the documentation, can this be added?

What happens if there are zero, one, or more than two capture groups? We should have test cases in TestCustomRegexFromPlanOutputFromPlanOutput to show the expectations here.

Copy link
Member Author

Choose a reason for hiding this comment

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

It will just match everything and return it without any change.

Also if it helps I have been running this in production since I made the PR :) And also already deployed this latest version and it's working fine.

Copy link

This issue is stale because it has been open for 1 month with no activity. Remove stale label or comment or this will be closed in 1 month.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Documentation feature New functionality/enhancement go Pull requests that update Go code provider/github waiting-on-response Waiting for a response from the user work-in-progress
Projects
Status: In Development
Development

Successfully merging this pull request may close these issues.

6 participants