Skip to content

Build: pass PATH environment variable to Docker container #10133

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

Merged
merged 5 commits into from
Mar 16, 2023

Conversation

humitos
Copy link
Member

@humitos humitos commented Mar 9, 2023

Instead of prepending all the commands with the PATH= variable, we pass the environment variable directly to the Docker container.

This allow us to run multi-line shell script without failing with weird syntax errors. Besides, the implementation is cleaner since all the environment variables are passed to the commands in the same way.

I added some default paths that I found by checking the local Docker container. I'm also passing the users' path, depending if we are working locally as root or in production.

This is not 100% complete and there may be some other issues that I'm not seeing yet, but I think it's a first step to behave in a way our users are expecting.

Screenshot_2023-03-09_12-01-03

Closes #10103

Instead of prepending all the commands with the `PATH=` variable, we pass the
environment variable directly to the Docker container.

This allow us to run multi-line shell script without failing with weird syntax
errors. Besides, the implementation is cleaner since all the environment
variables are passed to the commands in the same way.

I added some _default paths_ that I found by checking the local Docker
container. I'm also passing the users' path, depending if we are working locally
as root or in production.

This is not 100% complete and there may be some other issues that I'm not seeing
yet, but I think it's a first step to behave in a way our users are expecting.

Closes #10103
Locally it tries to reverted back 🤷
@humitos humitos requested review from stsewd and ericholscher March 14, 2023 09:15
@humitos
Copy link
Member Author

humitos commented Mar 14, 2023

We told some people we were deploying this today, but it didn't got reviewed/accepted on time. Please, if you have some time today, review it and let me know if it makes sense to deploy a hotfix.

Copy link
Member

@ericholscher ericholscher left a comment

Choose a reason for hiding this comment

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

This definitely looks less hacky, so I'm 👍 on the direction. It seems like we're making a lot more assumptions about what PATH defaults should be, and we should be using some reference or standard for what those are, and documenting where we got them.

@@ -73,7 +73,7 @@ def __init__(
bin_path=None,
record_as_success=False,
demux=False,
**kwargs,
**kwargs, # pylint: disable=unused-argument
Copy link
Member

Choose a reason for hiding this comment

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

This seems like we have linting configured too strongly, if so much of this PR is linting hints... Maybe that's making the code better, but I'm not convinced this check is useful?

# Prepend the BIN_PATH if it's defined
if self.bin_path:
path = environment.get("PATH")
bin_path = self._escape_command(self.bin_path)
Copy link
Member

Choose a reason for hiding this comment

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

Why are we only escaping this here? If this is user input and security critical, it should be very explicitly mentioned.

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'm not sure why that _escape_command is there. I copied from our previous code,

if self.bin_path:
bin_path = self._escape_command(self.bin_path)
prefix += f'PATH={bin_path}:$PATH '

In theory, it's not input from the user. This should be the venv path, if I understand correctly this code.

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 may be not required, I think 🤷🏼

After a quick grep, it's always self.python_env.venv_bin() or self.venv_bin(). So, we could probably remove it if we want, but I'm not sure.

Comment on lines 321 to 327
if self.bin_path:
path = environment.get("PATH")
bin_path = self._escape_command(self.bin_path)
environment["PATH"] = bin_path
if path:
environment["PATH"] += f":{path}"

Copy link
Member

Choose a reason for hiding this comment

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

This logic feels really weird to me. We're overwriting then appending the original path if it exists, but the variable names don't make that clear. I think we want something closer to:

Suggested change
if self.bin_path:
path = environment.get("PATH")
bin_path = self._escape_command(self.bin_path)
environment["PATH"] = bin_path
if path:
environment["PATH"] += f":{path}"
if self.bin_path:
original_path = environment.get("PATH")
# SECURITY CRITICAL: Escape user input
escaped_bin_path = self._escape_command(self.bin_path)
environment["PATH"] = f"{escaped_bin_path}:{original_path}"

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 need the if because original_path could be None.

I'm taking the suggestion of the variable names, tho.

@humitos humitos requested a review from ericholscher March 15, 2023 10:59
@humitos
Copy link
Member Author

humitos commented Mar 15, 2023

I updated the PR with the suggestions provided. Let me know what you think.

Note
I have no lint issues after pulling latest changes from common/

Copy link
Member

@ericholscher ericholscher left a comment

Choose a reason for hiding this comment

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

This seems good to me to simplify this logic. I'm a little worried it might break other things randomly, but I think it's a better approach 👍

@humitos
Copy link
Member Author

humitos commented Mar 16, 2023

I'm a little worried it might break other things randomly

I hope it doesn't 🙏🏼 (thinking in positive) 😝

@humitos humitos enabled auto-merge (squash) March 16, 2023 11:30
@humitos humitos merged commit bc4bced into main Mar 16, 2023
@humitos humitos deleted the humitos/build-cmd-environment branch March 16, 2023 11:44
@ericholscher
Copy link
Member

@humitos Users can't say we didn't warn them. This is exactly why it's still in beta :)

ericholscher added a commit that referenced this pull request Mar 28, 2023
Quick revert of #10133 until we can think more about it.
ericholscher added a commit that referenced this pull request Mar 28, 2023
Quick revert of #10133 until we can think more about it.
ericholscher added a commit that referenced this pull request Mar 28, 2023
ericholscher added a commit that referenced this pull request Mar 28, 2023
ericholscher added a commit that referenced this pull request Mar 30, 2023
humitos added a commit that referenced this pull request May 22, 2023
This is another attempt to fix this issue. It follows the suggestion posted by
@bensze01 in #10103. It
looks simple and I think it makes sense to give it a try since it doesn't seem
to be harmful.

I tested it locally with the branch
https://github.com/readthedocs/test-builds/tree/build-commands-multiline and it
worked fine. Note that without this PR the branch linked fails.

Related #10133
Related #10119
Related #10206

External PRs that should be solved by this one:
* pypi/warehouse#12953
* pypi/warehouse#12953

Closes #10103
Closes #10208
humitos added a commit that referenced this pull request May 23, 2023
* Build: allow multi-line commands on `build.commands`

This is another attempt to fix this issue. It follows the suggestion posted by
@bensze01 in #10103. It
looks simple and I think it makes sense to give it a try since it doesn't seem
to be harmful.

I tested it locally with the branch
https://github.com/readthedocs/test-builds/tree/build-commands-multiline and it
worked fine. Note that without this PR the branch linked fails.

Related #10133
Related #10119
Related #10206

External PRs that should be solved by this one:
* pypi/warehouse#12953
* pypi/warehouse#12953

Closes #10103
Closes #10208

* Build: use `;` to separate PREFIX from COMMAND
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Build: build.jobs.post_build produces mysterious shell syntax errors
3 participants