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

fix(docker): safer argument parsing for GitHub Actions #788

Merged
merged 39 commits into from
Apr 5, 2023

Conversation

kanadgupta
Copy link
Member

@kanadgupta kanadgupta commented Mar 31, 2023

🚥 Fixes #787

🧰 Changes

The Problem 😵‍💫

Someone wrote in in #787 about an issue where their workflows started breaking due to them wrapping their file names in quotation marks. Normally our args parser (command-line-args) would handle quotation marks just fine, but because of our new Docker setup and how we have the user pass in all their rdme arguments into a single GitHub Actions input, quotation marks are escaped by the time rdme receives it 😬

To put it a different way, this was the equivalent of running something like this:

CleanShot 2023-04-04 at 17 34 02@2x

The Solution 💭

This was a pain to debug and fix (thanks @RyanGWU82 and @domharrington for pairing on this 😮‍💨), but I got something going that I'm happy with! Now, when we invoke the rdme Docker image via the GitHub Action runner, it's basically running this:

rdme docker-gha "openapi:validate \"https://github.com/readmeio/oas-examples/blob/main/3.0/json/petstore-simple.json\""

The docker-gha argument isn't documented nor exposed to users, but is basically an internal escape hatch so we can properly consume rdme arguments that are sent to us via a single string.

As part of this, I did the following:

  • Refactors our Dockerfile and our action.yml files so we're now using rdme as the executable and passing in the rdme command via good ol' fashioned docker run arguments.

To put this a different way, here's the before and after if we were to build the rdme Docker image locally and pass arguments into it:

Before (using the INPUT_RDME environmental variable):

docker run -i -t --env INPUT_RDME='openapi:validate https://github.com/readmeio/oas-examples/blob/main/3.0/json/petstore-simple.json' ghcr.io/readmeio/rdme:dev

After (using standard docker run arguments):

docker run -i -t --env DEBUG='rdme*' ghcr.io/readmeio/rdme:dev openapi:validate https://github.com/readmeio/oas-examples/blob/main/3.0/json/petstore-simple.json
  • Added logic our main rdme index.ts file to check for this new docker-gha command and if it exists, parse out the arguments using string-argv.
  • Added corresponding test coverage, both in Jest and in our GitHub Actions dry runs.

🧬 QA & Testing

If tests pass we should be good to go! If you can think of any edge cases with quotation marks and string serialization I might be missing, please let me know 🥺

To get a sense of what is going on here, feel free to run this locally:

# Build + install deps
npm ci && npm run build

# simulate the command that is being invoked by the GitHub Actions runner
bin/rdme docker-gha "openapi:validate \"https://github.com/readmeio/oas-examples/blob/main/3.0/json/petstore-simple.json\""

src/index.ts Fixed Show fixed Hide fixed
@kanadgupta kanadgupta changed the title chore: try tweaking dockerfile fix(docker): safer argument parsing for GitHub Actions Apr 4, 2023
@@ -14,3 +14,6 @@ outputs:
runs:
using: docker
image: docker://ghcr.io/readmeio/rdme:8.6.0
args:
- docker-gha
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 is a new internal argument we send to indicate to the rdme Docker image that the command is going to be a single string as opposed to an array of strings.

Copy link
Member

Choose a reason for hiding this comment

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

This is a pretty neat/sufficient solution. Annoying that it's necessary, but it's not too bad.

* This logic checks for that `docker-gha` argument and parses the second string
* into the arguments array that `command-line-args` is expecting.
*/
if (rawProcessArgv.length === 2 && rawProcessArgv[0] === 'docker-gha') {
Copy link
Member Author

Choose a reason for hiding this comment

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

We now check for that docker-gha argument before parsing out the second string and converting it to something that command-line-args can process.

Copy link
Member

Choose a reason for hiding this comment

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

Hopefully this is something we can remove down the line! But nice fix for now.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah sadly I think this will be here to stay so long as we aim to maintain Actions/CLI feature parity and stick with this Docker approach to Actions 🫠

But who knows, maybe GitHub will ship changes on this front that will allow us to simplify this 🤞🏽

@@ -8,4 +8,4 @@ FROM alpine:3.14

COPY --from=builder /rdme/exe /exe

ENTRYPOINT ["sh", "-c", "/exe/rdme $INPUT_RDME"]
ENTRYPOINT ["/exe/rdme"]
Copy link
Member Author

@kanadgupta kanadgupta Apr 4, 2023

Choose a reason for hiding this comment

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

Not only this this a lot cleaner, but we can now use good ol' docker run arguments AND GitHub recommends1 accessing inputs via arguments and not environmental variables in their own docs:

CleanShot 2023-04-04 at 18 07 29@2x

Footnotes

  1. They technically imply that it's impossible to access the INPUT_ environmental variables from the Docker container action, but that's definitely wrong — [email protected] wouldn't be working at all in that case lol. The takeaway here is that we should be passing inputs via arguments and not environmental variables.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah this is better.

@kanadgupta kanadgupta added bug Something isn't working refactor Issues about tackling technical debt GHA / CI Issues specific to GitHub Actions or other CI environments labels Apr 4, 2023
@kanadgupta kanadgupta marked this pull request as ready for review April 4, 2023 23:13
src/index.ts Outdated Show resolved Hide resolved
@kanadgupta kanadgupta requested a review from erunion April 5, 2023 04:06
Copy link
Member

@erunion erunion left a comment

Choose a reason for hiding this comment

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

hell of a bug + fix

Copy link
Member

@domharrington domharrington left a comment

Choose a reason for hiding this comment

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

Good job!

- name: Run `openapi:validate` with filename in quotes
uses: ./rdme-repo/
with:
rdme: openapi:validate "oas-examples-repo/3.1/json/petstore.json"
Copy link
Member

Choose a reason for hiding this comment

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

Is this the previously broken case? Do you have a test for that?

Copy link
Member Author

Choose a reason for hiding this comment

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

Correct, both tests added to this file check for the breakage in the most recent release!

@@ -8,4 +8,4 @@ FROM alpine:3.14

COPY --from=builder /rdme/exe /exe

ENTRYPOINT ["sh", "-c", "/exe/rdme $INPUT_RDME"]
ENTRYPOINT ["/exe/rdme"]
Copy link
Member

Choose a reason for hiding this comment

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

Yeah this is better.

@@ -14,3 +14,6 @@ outputs:
runs:
using: docker
image: docker://ghcr.io/readmeio/rdme:8.6.0
args:
- docker-gha
Copy link
Member

Choose a reason for hiding this comment

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

This is a pretty neat/sufficient solution. Annoying that it's necessary, but it's not too bad.

* This logic checks for that `docker-gha` argument and parses the second string
* into the arguments array that `command-line-args` is expecting.
*/
if (rawProcessArgv.length === 2 && rawProcessArgv[0] === 'docker-gha') {
Copy link
Member

Choose a reason for hiding this comment

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

Hopefully this is something we can remove down the line! But nice fix for now.

Copy link

@rafegoldberg rafegoldberg left a comment

Choose a reason for hiding this comment

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

Frustrating bug; interesting fix. Changes look good to me.

Copy link
Contributor

@RyanGWU82 RyanGWU82 left a comment

Choose a reason for hiding this comment

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

Thanks Kanad!

@kanadgupta kanadgupta merged commit 8328388 into next Apr 5, 2023
@kanadgupta kanadgupta deleted the dockerfile-double-quotes branch April 5, 2023 16:43
kanadgupta pushed a commit that referenced this pull request Apr 5, 2023
## [8.6.1-next.1](v8.6.0...v8.6.1-next.1) (2023-04-05)

### Bug Fixes

* **docker:** safer argument parsing for GitHub Actions ([#788](#788)) ([8328388](8328388))

[skip ci]
kanadgupta pushed a commit that referenced this pull request Apr 5, 2023
## [8.6.1](v8.6.0...v8.6.1) (2023-04-05)

### Bug Fixes

* **docker:** safer argument parsing for GitHub Actions ([#788](#788)) ([8328388](8328388))

[skip ci]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working GHA / CI Issues specific to GitHub Actions or other CI environments refactor Issues about tackling technical debt
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Filename in quotes no longer working
5 participants