From f10ccf7e99fd4fafcc2f98145d6e3e4d253667c8 Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Mon, 5 Feb 2024 17:38:29 -0500 Subject: [PATCH] Document unprivileged user in GitHub workflows At some point GitHub changed things so that the entrypoint script does not run, so the `AS_USER` variable does nothing. Which is just as well, becaues that user would have no permissions, so even a checkout will fail. So remove the GitHib-specific stuff from `entrypoint.sh` and document how to use `gosu` directly in a GitHub workflow to execute commands as an unprivileged user. Thanks to @pgguru for figuring out the technique. --- .github/workflows/cicd.yml | 2 ++ Dockerfile | 3 +-- README.md | 53 ++++++++++++++++++++++++-------------- bin/entrypoint.sh | 10 +------ 4 files changed, 38 insertions(+), 30 deletions(-) diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index a52eec8..bd8839d 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -18,6 +18,8 @@ jobs: # Test with Git repo - name: Test Git as root run: "docker run -w /repo --rm --volume \"$(pwd):/repo\" pgxn-tools-test ./test/runtest.sh ${{ matrix.pg }} git" + - name: Test Git as postgres + run: "docker run -w /repo --rm --volume \"$(pwd):/repo\" -u postgres pgxn-tools-test ./test/runtest.sh ${{ matrix.pg }} git" - name: Test Git as non-root run: "docker run -w /repo --rm --volume \"$(pwd):/repo\" -e AS_USER=worker pgxn-tools-test ./test/runtest.sh ${{ matrix.pg }} git" - name: Test Git with extra file diff --git a/Dockerfile b/Dockerfile index 3f49fcc..2ced8fb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,8 +15,7 @@ RUN chmod +x /usr/local/bin/apt.postgresql.org.sh \ && ./cpanm --notest PGXN::Meta::Validator \ && rm -r cpanm ~/.cpanm \ && echo Defaults lecture = never >> /etc/sudoers \ - && perl -i -pe 's/\bALL$/NOPASSWD:ALL/g' /etc/sudoers \ - && echo 'postgres ALL=(ALL:ALL) NOPASSWD:ALL' >> /etc/sudoers \ + && usermod -a -G sudo postgres \ # Ensure Git can do stuff in the working directory (issue #5). && git config --system --add safe.directory '*' \ # Install git-archive-all diff --git a/README.md b/README.md index 1e1c900..20b427a 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,11 @@ The image is based on the Debian Bookworm Slim image, and uses the Unprivileged User ----------------- -By default the container runs as `root`. To run as an unprivileged user, pass -the `AS_USER` environment variable, and a user with that name will be created -with `sudo` privileges (already used by `pg-start` and `pg-build-test`): +By default the container runs as `root`. To run as an unprivileged user (unless +the runtime environment requires the the user to be root, in which case [see +below](#unprivileged-user-workflow)), pass the `AS_USER` environment variable +and a user with that name will be created with `sudo` privileges (already used +by `pg-start` and `pg-build-test`): ``` sh docker run -it --rm -w /repo -e AS_USER=worker \ @@ -46,11 +48,6 @@ docker run -it --rm -w /repo -e AS_USER=worker -e LOCAL_UID=$(id -u) \ sh -c 'sudo pg-start 14 && pg-build-test' ``` -If no `LOCAL_UID` is set but `GITHUB_EVENT_PATH` is set (as it is in GitHub -workflows), the UID will be set to the same value as the owner of the -`GITHUB_EVENT_PATH` file. This allows the user to have full access to the -GitHub project volume. - ### Postgres User The `postgres` user, created by `pg-start`, also has full permission to use @@ -77,20 +74,11 @@ jobs: - name: Start PostgreSQL ${{ matrix.pg }} run: pg-start ${{ matrix.pg }} - name: Check out the repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Test on PostgreSQL ${{ matrix.pg }} run: pg-build-test ``` -If you need to run the tests as an unprivileged user, pass the `AS_USER` -variable as a container option: - -``` yaml - container: - image: pgxn/pgxn-tools - options: -e AS_USER=randy -``` - This example demonstrates automatic publishing of a release whenever a tag is pushed matching `v*`. It publishes both to GitHub (using the [create-release] and [upload-release-asset] actions) and to PGXN: @@ -111,7 +99,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Check out the repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Bundle the Release id: bundle run: pgxn-bundle @@ -141,6 +129,31 @@ jobs: asset_content_type: application/zip ``` +### Unprivileged User Workflow + +If you need to run take action as an unprivileged user, the `AS_USER` variable +[documented above](#unprivileged-user) will not work, both because GitHub +actions [require the root user] to work with the workspace and because GitHub +does not execute `entrypoint` script. + +Instead, set things up as the root user, then use [gosu] to execute a command as +the `postgres` (can still run `sudo`) or `nobody` (no privileges at all) user. +For example: + +``` yaml + container: pgxn/pgxn-tools + steps: + - uses: actions/checkout@v4 + - run: pg-start ${{ matrix.pg }} + - run: chown -R postgres:postgres . + - run: gosu postgres pg-build-test +``` + +The checkout action, `pg-start`, and `chown` commands run as `root`. Then, with +the current directory's files all owned the `postgres` user, the last `run` +commands executes `pg-build-test` as `postgres`, with the necessary permissions +to write files to the workspace directory. + Tools ----- @@ -388,7 +401,9 @@ Copyright (c) 2020-2024 The PGXN Maintainers. Distributed under the [`pgxn-release`]: bin/pgxn-release [PostgreSQL Apt]: https://wiki.postgresql.org/wiki/Apt [back to 8.2]: http://apt.postgresql.org/pub/repos/apt/dists/bookworm-pgdg/ + [require the root user]: https://docs.github.com/en/actions/creating-actions/dockerfile-support-for-github-actions#user [GithHub Workflow]: https://help.github.com/en/actions/configuring-and-managing-workflows + [gosu]: https://github.com/tianon/gosu [create-release]: https://github.com/actions/create-release [upload-release-asset]: https://github.com/actions/upload-release-asset [git-archive-all]: https://github.com/Kentzo/git-archive-all diff --git a/bin/entrypoint.sh b/bin/entrypoint.sh index 005cd31..da81a6d 100755 --- a/bin/entrypoint.sh +++ b/bin/entrypoint.sh @@ -5,17 +5,9 @@ set -e # Just continue if unprivileged user not requested. [ -z "$AS_USER" ] && exec "$@" -USER_ID=${LOCAL_UID:-0} +USER_ID=${LOCAL_UID:-1001} USERNAME=worker -if [ $USER_ID == 0 ]; then - if [ -n "${GITHUB_EVENT_PATH}" ]; then - USER_ID=$(stat -f %u "${GITHUB_EVENT_PATH}") - else - USER_ID=1001 - fi -fi - echo "Starting with UID $USER_ID" useradd --system --create-home --shell /bin/bash -g root -G sudo -u $USER_ID "$AS_USER" export HOME="/home/$AS_USER"