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

Add PYTEST_TMPDIR_FILE_MASK environment variable #10786

Closed

Conversation

BeyondEvil
Copy link

Fixes: #10738

Copy link
Member

@nicoddemus nicoddemus left a comment

Choose a reason for hiding this comment

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

Thanks @BeyondEvil!

Other than my comments, why did you decide on using an environment variable rather than a configuration option? I suspect because one would use this only when running external code in containers, so it makes sense for it to be configured in the environment, just wanted to make sure.

changelog/10738.trivial.rst Outdated Show resolved Hide resolved
doc/en/how-to/tmp_path.rst Outdated Show resolved Hide resolved
@nicoddemus nicoddemus closed this Mar 3, 2023
@nicoddemus nicoddemus reopened this Mar 3, 2023
@BeyondEvil
Copy link
Author

Thanks @BeyondEvil!

Other than my comments, why did you decide on using an environment variable rather than a configuration option? I suspect because one would use this only when running external code in containers, so it makes sense for it to be configured in the environment, just wanted to make sure.

The original fix of setting mode to 700 wasn't necessarily the longterm fix that we wanted/needed, so after discussion with @RonnyPfannschmidt it was decided this was the path of least resistance. And yes, having it as an environment variable simplifies usage in containerized situations.

@BeyondEvil
Copy link
Author

I think I've adressed all your comments @nicoddemus, thanks for reviewing! 🙇

Github Actions were having issues yesterday, so I expect tests to pass today.

Copy link
Member

@nicoddemus nicoddemus left a comment

Choose a reason for hiding this comment

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

Thanks @BeyondEvil!

@nicoddemus
Copy link
Member

The test failure will be fixed by #10788.

@nicoddemus
Copy link
Member

Took the liberty of rebasing on main.

@BeyondEvil
Copy link
Author

BeyondEvil commented Mar 3, 2023

Took the liberty of rebasing on main.

Thanks, appreciate it! 🙏

Anything else needed from me at this time?

@nicoddemus
Copy link
Member

Anything else needed from at this time?

Not from my POV, let's see if other maintainers want to chime in before getting this in.

Copy link
Member

@bluetech bluetech left a comment

Choose a reason for hiding this comment

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

No comment on whether this is a good idea or not (unfortunately don't have time to think it through ATM), but a couple of smaller comments.

@@ -51,6 +51,8 @@
1921, # ERROR_CANT_RESOLVE_FILENAME - fix for broken symlink pointing to itself
)

TMPDIR_FILE_MODE = int(os.getenv("PYTEST_TMPDIR_FILE_MODE", "0o700"), 8)
Copy link
Member

Choose a reason for hiding this comment

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

If you specify base 8, then you can drop the 0o prefix.

Copy link
Author

Choose a reason for hiding this comment

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

I can, but should I?

I felt it was clearer this way. But happy to remove it if you think it's better.

Copy link
Member

Choose a reason for hiding this comment

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

To me the 0o means that the field doesn't specify a base, i.e. 123 is decimal, 0x123 would work, etc. I think the base 8 is good, but then we should drop the 0o

@@ -51,6 +51,8 @@
1921, # ERROR_CANT_RESOLVE_FILENAME - fix for broken symlink pointing to itself
)

TMPDIR_FILE_MODE = int(os.getenv("PYTEST_TMPDIR_FILE_MODE", "0o700"), 8)
Copy link
Member

Choose a reason for hiding this comment

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

You've chosen to grab the envvar once during import. Other alternatives are to grab it during initialization, and to grab it each time. Any particular reason you chose this way?

Copy link
Author

Choose a reason for hiding this comment

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

No particular reason. Preferably I would want to grab it in one place and then share it.

But I'm not versed enough in core to know where and how to do that.

Happy to take some guidance! 🙏

Copy link
Member

Choose a reason for hiding this comment

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

IMO (although again, I didn't think it through)

each-time > init > import

init > import because import is not great for this getenv, since then the user doesn't really get a chance to setenv from within python (when using pytest.main etc).

each-time > init is more debatable, but each-time allows a user to setenv whenever and it would take effect -- is there any reason to disallow that?

Copy link
Author

Choose a reason for hiding this comment

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

each-time > init is more debatable, but each-time allows a user to setenv whenever and it would take effect -- is there any reason to disallow that?

Not really, I think maximum flexibility is allowed here. I don't think it's our business to protect users from themselves. Especially since the default is more or less the most restrictive.

So would you recommend a small static method somewhere to get the user defined file mode? If so, where should I put such (static) method?

Something like:

def file_mode() -> int:
    return int(os.getenv("PYTEST_TMPDIR_FILE_MODE", "700"), 8)

Copy link
Member

Choose a reason for hiding this comment

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

Just a note that if we change the default (and remove the 0o), we should update the docs too. 👍

Copy link
Member

Choose a reason for hiding this comment

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

So would you recommend a small static method somewhere to get the user defined file mode

Yes. Though I'd call it tmpdir_file_mode.

If so, where should I put such (static) method?

I'd say best place for it is src/_pytest/pathlib.py.

Copy link
Author

Choose a reason for hiding this comment

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

Updated accordingly @bluetech 🙇

@nicoddemus
Copy link
Member

@bluetech would you like to take a final review?

udhaykiran2

This comment was marked as spam.

@Zac-HD
Copy link
Member

Zac-HD commented Mar 11, 2023

I'm sorry to raise this so late in the process, but I'm quite strongly against this change.

File permissions for the temporary directories were restricted for security reasons, and allowing that to be adjusted by an environment variable weakens those defenses considerably. Instead, I'd want to use an approach which is clearly visible in the source code, such as by adding a config option, or an explicit fixture for world_accessible_tmpdir (which might take the tmpdir fixture and chown() the result).

@nicoddemus
Copy link
Member

@BeyondEvil would you like to argue in favor of this change with @Zac-HD?

@BeyondEvil
Copy link
Author

BeyondEvil commented Mar 27, 2023

@BeyondEvil would you like to argue in favor of this change with @Zac-HD?

No, lol.
Jokes aside, sorry, I misinterpreted my role here. I made the assumption this was a discussion for core devs. Apologies for that.

I'm fine with changing the implementation, but I think it's sort of semantics or security by obscurity.

If I have access to modifying the environment variables, it's likely that I can change the test code as well. Meaning I can work around the "restriction" anyway:

        # Begin workaround
        # See: https://github.com/pytest-dev/pytest/issues/10738
        path.chmod(0o755)
        for parent in path.parents:
            try:
                os.chmod(parent, 0o755)
            except PermissionError:
                continue
        # End workaround

That said, I have a limited understanding of all the use cases of pytest and in what environments it's running. Hence, I'm happy to implement a fixture instead.

In my particular use case tho, I don't think a "chown" will work (as evident by the mask above I have to use to make it work).

So I would suggest a file mode fixture, one that potentially could warn on too loose permissions.

@nicoddemus
Copy link
Member

Let's close this then. Thanks a lot @BeyondEvil for the PR, sorry it did not ended up being included! 👍

@nicoddemus nicoddemus closed this Apr 4, 2023
@BeyondEvil
Copy link
Author

Sorry, I don't follow the logic of closing this. 🤔

@nicoddemus
Copy link
Member

From:

That said, I have a limited understanding of all the use cases of pytest and in what environments it's running. Hence, I'm happy to implement a fixture instead.

I understand the environment variable implementation will be dropped, and potentially a new PR will be opened?

@BeyondEvil
Copy link
Author

From:

That said, I have a limited understanding of all the use cases of pytest and in what environments it's running. Hence, I'm happy to implement a fixture instead.

I understand the environment variable implementation will be dropped, and potentially a new PR will be opened?

Ah, I get it.

sorry it did not ended up being included

That confused me a little. But yes, I'll open a new PR with a fixture-based solution instead.

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.

tempdir hardening prevents intentionaly world owned tmpdirs for container sharing
5 participants