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

Match Container's User and Group to Host #49962

Merged
merged 20 commits into from
Apr 28, 2023
Merged

Match Container's User and Group to Host #49962

merged 20 commits into from
Apr 28, 2023

Conversation

ObliviousHarmony
Copy link
Contributor

@ObliviousHarmony ObliviousHarmony commented Apr 20, 2023

What?

This pull request changes some of the permissions for wp-env containers in order to ensure parity with the host operating system.

Why?

By using the host's user and group we are able to make sure the host and containers are all acting as the same owner for files and folders. This ensures files created by any of them are readable and writeable by the rest. For instance, wp rewrite structure '/%postname%/' --hard in the cli container will create a .htaccess file that the wordpress container is able to read.

Closes #22515, #45592, #49373, and #28201

How?

We add the current host user to the wordpress and tests-wordpress containers using the same uid and gid from the host. We also use the APACHE_RUN_USER and APACHE_RUN_GROUP environment variables so that the web server will run as the host user too. Lastly, when using wp-env run we use the host user that we created on the container.

Thanks to #42826 we can be sure that the entire contents of our WordPress installation is mounted. This is good because it means we don't have to change the permissions of any files or folders to get this to work. The end result is that on operating systems where the distinction matters, the owner of these files is the same everywhere.

Testing Instructions

  1. Since CI is using Linux, successfully passing the tests that use wp-env is a good indicator that nothing has broken.
  2. Run npm run env start locally and confirm that it builds the container. If you already have one, make sure to use npm run env start --update so that the new Dockerfile is used.
  3. Run npm run env run wordpress ls -la and confirm that the files are owned by your current user. On macOS the ownership seemed oddly flaky at times, but, it doesn't matter because of the way the mounting works. I'm not sure if it does this on Linux, but, someone can test 😄
  4. Run npm run env run cli ls -la and confirm that the files are still owned by your current user. The name will be missing, but, the raw uid is a good indicator of the difference made here.
  5. Run npm run env run wordpress ls -la wp-content/plugins/gutenberg and note that your current user owns all of the files and folders here.
  6. Log into wp-admin in the container and install a plugin via the UI. It should work.
  7. Create a wp-cli.yml file in /var/www/html with the content:
apache_modules:
  - mod_rewrite
  1. Run npm run env run cli wp rewrite structure '/%postname%/' --hard. Use npm run env run cli ls -la to confirm that a .htaccess file was created as expected.
  2. Visit a page in the container and verify that pretty permalink are enabled and working.
  3. Upload some media and verify that it works as expected.

Given the opportunity for this PR to go wrong, I would suggest trying anything else that you can think of!

Instead of running the web service as `root` and the CLI service
as `33:33`, we should be running them as the host user. By
doing this we ensure ownership parity in mounted folders
on platforms where having different owners would result
in permission issues.
@ObliviousHarmony ObliviousHarmony marked this pull request as ready for review April 20, 2023 18:22
@ObliviousHarmony
Copy link
Contributor Author

Hey @defunctl, @Luc45, and @eliot-akira! Given the wide reach of this pull request, I was wondering if you folks might take a look at this and try it out locally? I think this will solve all of our existing permission problems in a minimally invasive way.

Comment on lines 80 to 82
const hostUser = os.userInfo();
const uid = ( hostUser.uid === -1 ? 0 : hostUser.uid ).toString();
const gid = ( hostUser.gid === -1 ? 0 : hostUser.gid ).toString();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As per Node's documentation, on Windows the uid and gid is -1. I think this only happens with a process.platform of win32. If you're using WSL you will realistically be running commands inside the container, so, this is more of an edge-case where they have Node installed on Windows.

The question I have is whether or not this breaks anything. I'm curious about what kind of permission magic takes place when going mounting from Windows -> Docker instead of WSL -> Docker. If it works anything like macOS, I would wager that having everything owned by root doesn't matter.

@noahtallen noahtallen added [Package] Env /packages/env [Type] Bug An existing feature does not function as intended labels Apr 20, 2023
@noahtallen
Copy link
Member

I noticed this wp-content and wp-config.php are under different users and groups. Not sure if that's a problem!

-rw-r--r--   1 www-data  www-data  5868 Apr 20 22:52 wp-config.php
drwxr-xr-x   6 root      root       192 Feb 17 20:22 wp-content

Also, curious if this code is necessary any more:

async function createUploadsDir( corePath ) {
// Ensure the tests uploads folder is writeable for travis,
// creating the folder if necessary.
const uploadPath = path.join( corePath, 'wp-content/uploads' );
await fs.mkdir( uploadPath, { recursive: true } );
await fs.chmod( uploadPath, 0o0767 );
}

So far this is working fine on macOS, but that's expected 😅

I'll try to test on Windows as well.

@ObliviousHarmony
Copy link
Contributor Author

I noticed this wp-content and wp-config.php are under different users and groups. Not sure if that's a problem!

This is probably because the "wordpress" image sets the permissions on that file to www-data. I might suggest trying npm run env destroy and then npm run env start if you haven't before this PR. It's worth noting though that the permissions on macOS are a bit strange. I saw it jump from root to my user for, as far as I can tell, absolutely no reason. I think it may have happened after a subsequent wp-env start because it did a git pull and maybe changed the permissions? I have absolutely no idea, but, because of the way the permissions work in macOS, it doesn't really matter.

These problems shouldn't happen on Linux because it uses bind to mount the volume and has unified ownership and permissions across the containers from the host.

Also, curious if this code is necessary any more

It probably isn't, actually. Let's wait for some further verification on whether or not this pull request works, and if it does, we can take a look at other things like this that may not be necessary anymore.

@noahtallen
Copy link
Member

I might suggest trying npm run env destroy and then npm run env start if you haven't before this PR

I hadn't done that. Potentially worth mentioning in the changelog if it's necessary

@Luc45
Copy link

Luc45 commented Apr 21, 2023

I haven't tested this yet, but the logic seems sound. This is similar to what fixuid does. One thing that it does and I'm not seeing here is something like sudo chown -R $MAPPED_USER /var/www

@ObliviousHarmony
Copy link
Contributor Author

Thanks @Luc45, fixuid works by changing the ownership of all files owned by a given user to another user. In our case, /var/www/html is a mapped directory from the host. These files are created by wp-env and are already owned by the host user. Thanks to that, we don't need to change the ownership, just the user's container.

@ObliviousHarmony
Copy link
Contributor Author

I hadn't done that. Potentially worth mentioning in the changelog if it's necessary

I think it might be necessary on macOS @noahtallen, but, I'm not sure if it is elsewhere. On macOS the permissions in the containers are unique to them, so, they'll retain whatever permissions they had prior. With Linux, since the permissions are unified, they probably won't need to make any changes.

Assuming that it works in Linux as-is without regenerating the environment, I don't think folks need to do anything. If regenerating works, we should test a pre-PR start re-ran with start here and see if that breaks anything. As long as everything works before and after I don't think it matters what it looks like on macOS.

@Luc45
Copy link

Luc45 commented Apr 21, 2023

Sounds good, I'll take it for a spin (tentatively tomorrow) and report back

@ObliviousHarmony
Copy link
Contributor Author

I used npm pack to try this fix out in our GitHub workflows. This workflow run is for a PR that has this fix. Under the Load docker images and start containers with COT enabled. header is some log output that I added:

Web Permissions 

ℹ Starting 'ls -la' on the tests-wordpress container. 

Creating 36f129a9d109274d16f01b89c88bf54c_tests-wordpress_run ... 
Creating 36f129a9d109274d16f01b89c88bf54c_tests-wordpress_run ... done
total 252
drwxr-xr-x  5 runner runner  4096 Apr 21 19:11 .
drwxr-xr-x  1 root   root    4096 Nov 15 04:13 ..
-rw-r--r--  1 runner runner   405 Apr 21 19:11 index.php
-rw-r--r--  1 runner runner 19915 Apr 21 19:11 license.txt
-rw-r--r--  1 runner runner  7402 Apr 21 19:11 readme.html
-rw-r--r--  1 runner runner  7205 Apr 21 19:11 wp-activate.php
drwxr-xr-x  9 runner runner  4096 Apr 21 19:11 wp-admin
-rw-r--r--  1 runner runner   351 Apr 21 19:11 wp-blog-header.php
-rw-r--r--  1 runner runner    32 Apr 21 19:03 wp-cli.yml
-rw-r--r--  1 runner runner  2338 Apr 21 19:11 wp-comments-post.php
-rw-r--r--  1 runner runner  3013 Apr 21 19:11 wp-config-sample.php
-rw-r--r--  1 runner runner  6019 Apr 21 19:11 wp-config.php
drwxr-xr-x  5 runner runner  4096 Apr 21 19:11 wp-content
-rw-r--r--  1 runner runner  5536 Apr 21 19:11 wp-cron.php
drwxr-xr-x 28 runner runner 12288 Apr 21 19:11 wp-includes
-rw-r--r--  1 runner runner  2502 Apr 21 19:11 wp-links-opml.php
-rw-r--r--  1 runner runner  3792 Apr 21 19:11 wp-load.php
-rw-r--r--  1 runner runner 49330 Apr 21 19:11 wp-login.php
-rw-r--r--  1 runner runner  8541 Apr 21 19:11 wp-mail.php
-rw-r--r--  1 runner runner 24993 Apr 21 19:11 wp-settings.php
-rw-r--r--  1 runner runner 34350 Apr 21 19:11 wp-signup.php
-rw-r--r--  1 runner runner  4889 Apr 21 19:11 wp-trackback.php
-rw-r--r--  1 runner runner  3238 Apr 21 19:11 xmlrpc.php
✔ Ran `ls -la` in 'tests-wordpress'. (in 1s 495ms)
CLI Permissions 

ℹ Starting 'ls -la' on the tests-cli container. 

Creating 36f129a9d109274d16f01b89c88bf54c_tests-cli_run ... 
Creating 36f129a9d109274d16f01b89c88bf54c_tests-cli_run ... done
total 252
drwxr-xr-x    5 1001     122           4096 Apr 21 19:11 .
drwxr-xr-x    1 root     root          4096 Nov 12 08:36 ..
-rw-r--r--    1 1001     122            405 Apr 21 19:11 index.php
-rw-r--r--    1 1001     122          19915 Apr 21 19:11 license.txt
-rw-r--r--    1 1001     122           7402 Apr 21 19:11 readme.html
-rw-r--r--    1 1001     122           7205 Apr 21 19:11 wp-activate.php
drwxr-xr-x    9 1001     122           4096 Apr 21 19:11 wp-admin
-rw-r--r--    1 1001     122            351 Apr 21 19:11 wp-blog-header.php
-rw-r--r--    1 1001     122             32 Apr 21 19:03 wp-cli.yml
-rw-r--r--    1 1001     122           2338 Apr 21 19:11 wp-comments-post.php
-rw-r--r--    1 1001     122           3013 Apr 21 19:11 wp-config-sample.php
-rw-r--r--    1 1001     122           6019 Apr 21 19:11 wp-config.php
drwxr-xr-x    5 1001     122           4096 Apr 21 19:11 wp-content
-rw-r--r--    1 1001     122           5536 Apr 21 19:11 wp-cron.php
drwxr-xr-x   28 1001     122          12288 Apr 21 19:11 wp-includes
-rw-r--r--    1 1001     122           2502 Apr 21 19:11 wp-links-opml.php
-rw-r--r--    1 1001     122           3792 Apr 21 19:11 wp-load.php
-rw-r--r--    1 1001     122          49330 Apr 21 19:11 wp-login.php
-rw-r--r--    1 1001     122           8541 Apr 21 19:11 wp-mail.php
-rw-r--r--    1 1001     122          24993 Apr 21 19:11 wp-settings.php
-rw-r--r--    1 1001     122          34350 Apr 21 19:11 wp-signup.php
-rw-r--r--    1 1001     122           4889 Apr 21 19:11 wp-trackback.php
-rw-r--r--    1 1001     122           3238 Apr 21 19:11 xmlrpc.php
✔ Ran `ls -la` in 'tests-cli'. (in 2s 299ms)

It looks like the changes in this PR had the desired effect. There was no longer a need to change any permissions and everything worked exactly as expected. None of the permission oddities we see on macOS are present and everything has exactly what we expected it to.

@ObliviousHarmony
Copy link
Contributor Author

I set up WSL2 on my Windows machine and tested this out there. I confirmed that on trunk I receive permission issues when running wp plugin install woocommerce. After checking out this pull request I am able to run the same command and it installs WooCommerce without issue.

I've also confirmed that uploads operate the same way. Now that I've got this environment set up, I'll come back and try out removing the permission change for uploads. This might be it!

With the changes in this pull request we
no longer need to do this.
@noahtallen
Copy link
Member

I think it might be necessary on macOS @noahtallen, but, I'm not sure if it is elsewhere. On macOS the permissions in the containers are unique to them, so, they'll retain whatever permissions they had prior. With Linux, since the permissions are unified, they probably won't need to make any changes.

I mean, wp-env still seemed to work ok without destroying it, but maybe I should stress test it more :P

This will ensure things like `wp plugin install` have a directory to
use as a cache. Anything else can now refer to the home directory
for the same purpose.
Some of our `docker-compose run` actions weren't removing the
container after being executed. This was breaking `wp-env destroy`
becuase of the volumes that were in-use.
@ObliviousHarmony
Copy link
Contributor Author

Thank you again for such comprehensive feedback @eliot-akira. This has given me a great deal of confidence that we can release this change without destroying everyone's environment. It looks like we will just need folks to destroy their current environment. Once they've done that, it will work as-expected.

Copy link
Member

@noahtallen noahtallen left a comment

Choose a reason for hiding this comment

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

I think the phpunit test failures could potentially be related: https://github.com/WordPress/gutenberg/actions/runs/4802349358/jobs/8545703892?pr=49962#step:11:183

Or at the very least, the changes in the PR might be uncovering an issue. I feel like these were also flaky in the PR last week, and the phpunit ones normally shouldn't be that flaky 🤔

packages/env/CHANGELOG.md Outdated Show resolved Hide resolved

```sh
wp-env start --debug
```

`wp-env` will output its config which includes `dockerComposeConfigPath`.
`wp-env` will output its config which includes `dockerComposeConfigPath`:
Copy link
Member

Choose a reason for hiding this comment

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

This doc section is actually out of date now that we have npx install-path! We could probably change the entire thing to say that you can just cd $(npx wp-env install-path) and then see all the generated config files

Co-authored-by: Noah Allen <noahtallen@gmail.com>
@ObliviousHarmony
Copy link
Contributor Author

Some documentation thoughts @noahtallen:

  • Remove the permission error information since this PR solves the problem.
  • Expand on the install-path documentation to clarify that it is also the location for the Docker files.
  • Remove the section made unnecessary by the install-path command since it is already documented as such.
Debian stretch was just removed from deb.debian.org and moved
to the archive repository. This commit changes the sources
so that, on stretch, the apt-get update won't break.
@@ -203,6 +203,14 @@ function wordpressDockerFileContents( image, config ) {

return `FROM ${ image }

# Update apt sources for archived versions of Debian.
Copy link
Member

Choose a reason for hiding this comment

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

I might also add a comment linking to that stack overflow thread for a bit of extra context

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This isn't a bad idea. Given that it's a better source of truth, I've instead linked to the Debian mailing list record of the change.

@noahtallen noahtallen enabled auto-merge (squash) April 28, 2023 01:38
Copy link
Member

@noahtallen noahtallen left a comment

Choose a reason for hiding this comment

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

Alright, let's give this a shot!

@noahtallen noahtallen merged commit 602ba69 into WordPress:trunk Apr 28, 2023
@github-actions github-actions bot added this to the Gutenberg 15.8 milestone Apr 28, 2023
@westonruter
Copy link
Member

Closes #22515, #45592, #49373, and #28201

Only the the first issue got closed when this PR was merged.

@eliot-akira
Copy link

eliot-akira commented Apr 29, 2023

Amazing work - thank you @ObliviousHarmony, from all of us who will benefit from this improvement.

@mrfoxtalbot
Copy link

@ObliviousHarmony, could you confirm if this PR should have fixed what @shashwatahalder01 has reported in #50538 ? Thank you!

@ObliviousHarmony
Copy link
Contributor Author

Hi @mrfoxtalbot,

No, this behavior is expected without appropriate configuration. As per the documentation, they will need to add a wp-cli.yml configuration file to an appropriate directory. This is one way of doing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Env /packages/env [Type] Bug An existing feature does not function as intended
6 participants