From 7d6bbc7b7555c43e97f9063166099405b99a8dc7 Mon Sep 17 00:00:00 2001 From: Sean Sinnott Date: Wed, 27 May 2026 19:43:25 -0400 Subject: [PATCH 1/8] Pre-create rstudio-server user and set directory permissions Pre-create the rstudio-server user/group at UID/GID 999 before package installation so the deb postinst finds the existing account and does not reassign UIDs/GIDs. Expand the Configure Workbench layer to create and own all runtime directories (conf, body, proxy, launcher, log, run) up front, with group-writable setgid bits so members of rstudio-server can write without requiring root. Update goss tests accordingly and remove the Ubuntu 24.04 GID workaround that is no longer needed. --- .../template/Containerfile.ubuntu2204.jinja2 | 21 +++++++++- .../template/Containerfile.ubuntu2404.jinja2 | 21 +++++++++- workbench/template/test/goss.yaml.jinja2 | 38 +++++++++++++++++-- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/workbench/template/Containerfile.ubuntu2204.jinja2 b/workbench/template/Containerfile.ubuntu2204.jinja2 index 1cfad95..131a5e5 100644 --- a/workbench/template/Containerfile.ubuntu2204.jinja2 +++ b/workbench/template/Containerfile.ubuntu2204.jinja2 @@ -50,6 +50,13 @@ COPY {{ Path.Version }}/deps/ubuntu-22.04_packages.txt /tmp/packages.txt ### Install wait-for-it ### COPY --chmod=0755 {{ Path.Image }}/scripts/wait-for-it.sh /usr/local/bin/wait-for-it.sh +### Pre-create rstudio-server user so deb postinst finds it and UID/GID stays 999 across image rebuilds ### +RUN groupadd --system --gid 999 rstudio-server \ + && useradd --system --uid 999 --gid 999 \ + --no-create-home --home-dir /var/lib/rstudio-server \ + --shell /usr/sbin/nologin \ + rstudio-server + ### Install Workbench {{ Image.Version }} ### COPY --chmod=0755 {{ Path.Version }}/scripts/install_workbench.sh /tmp/install_workbench.sh RUN {% if Image.DownloadURL is defined %}DOWNLOAD_URL="{{ Image.DownloadURL }}" {% endif %}\ @@ -94,7 +101,19 @@ COPY "{{ Path.Version }}/conf/jupyter/*" "{{ Path.Version }}/conf/launcher/*" "{ ### Configure Workbench ### RUN mkdir -p /var/lib/rstudio-server/monitor/log \ - && chown -R rstudio-server:rstudio-server /var/lib/rstudio-server/monitor \ + /var/lib/rstudio-server/conf \ + /var/lib/rstudio-server/body \ + /var/lib/rstudio-server/proxy \ + /var/lib/rstudio-launcher \ + /var/log/rstudio \ + /var/run/rstudio-server \ + && chown -R rstudio-server:rstudio-server \ + /var/lib/rstudio-server \ + /var/lib/rstudio-launcher \ + /var/log/rstudio \ + /var/run/rstudio-server \ + && chmod -R g+w /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio /var/run/rstudio-server \ + && find /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio /var/run/rstudio-server -type d -exec chmod g+s {} + \ && mkdir -p /startup/custom/ \ && mkdir -p /startup/user-provisioning/ \ && printf '\n# allow home directory creation\nsession required pam_mkhomedir.so skel=/etc/skel umask=0077\n' >> /etc/pam.d/common-session \ diff --git a/workbench/template/Containerfile.ubuntu2404.jinja2 b/workbench/template/Containerfile.ubuntu2404.jinja2 index eaa3bb7..e72574c 100644 --- a/workbench/template/Containerfile.ubuntu2404.jinja2 +++ b/workbench/template/Containerfile.ubuntu2404.jinja2 @@ -50,6 +50,13 @@ COPY {{ Path.Version }}/deps/ubuntu-24.04_packages.txt /tmp/packages.txt ### Install wait-for-it ### COPY --chmod=0755 {{ Path.Image }}/scripts/wait-for-it.sh /usr/local/bin/wait-for-it.sh +### Pre-create rstudio-server user so deb postinst finds it and UID/GID stays 999 across image rebuilds ### +RUN groupadd --system --gid 999 rstudio-server \ + && useradd --system --uid 999 --gid 999 \ + --no-create-home --home-dir /var/lib/rstudio-server \ + --shell /usr/sbin/nologin \ + rstudio-server + ### Install Workbench {{ Image.Version }} ### COPY --chmod=0755 {{ Path.Version }}/scripts/install_workbench.sh /tmp/install_workbench.sh RUN {% if Image.DownloadURL is defined %}DOWNLOAD_URL="{{ Image.DownloadURL }}" {% endif %}\ @@ -94,7 +101,19 @@ COPY "{{ Path.Version }}/conf/jupyter/*" "{{ Path.Version }}/conf/launcher/*" "{ ### Configure Workbench ### RUN mkdir -p /var/lib/rstudio-server/monitor/log \ - && chown -R rstudio-server:rstudio-server /var/lib/rstudio-server/monitor \ + /var/lib/rstudio-server/conf \ + /var/lib/rstudio-server/body \ + /var/lib/rstudio-server/proxy \ + /var/lib/rstudio-launcher \ + /var/log/rstudio \ + /var/run/rstudio-server \ + && chown -R rstudio-server:rstudio-server \ + /var/lib/rstudio-server \ + /var/lib/rstudio-launcher \ + /var/log/rstudio \ + /var/run/rstudio-server \ + && chmod -R g+w /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio /var/run/rstudio-server \ + && find /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio /var/run/rstudio-server -type d -exec chmod g+s {} + \ && mkdir -p /startup/custom/ \ && mkdir -p /startup/user-provisioning/ \ && printf '\n# allow home directory creation\nsession required pam_mkhomedir.so skel=/etc/skel umask=0077\n' >> /etc/pam.d/common-session \ diff --git a/workbench/template/test/goss.yaml.jinja2 b/workbench/template/test/goss.yaml.jinja2 index 11f3b3f..564b7f6 100644 --- a/workbench/template/test/goss.yaml.jinja2 +++ b/workbench/template/test/goss.yaml.jinja2 @@ -8,14 +8,14 @@ user: rstudio-server: exists: true uid: 999 - gid: {% raw %}{{ if and (eq .Env.IMAGE_VARIANT "Standard") (and (eq .Env.IMAGE_OS_NAME "ubuntu") (eq .Env.IMAGE_OS_VERSION "24.04")) }}997{{ else }}999{{ end }}{% endraw %} + gid: 999 groups: - rstudio-server group: rstudio-server: exists: true - gid: {% raw %}{{ if and (eq .Env.IMAGE_VARIANT "Standard") (and (eq .Env.IMAGE_OS_NAME "ubuntu") (eq .Env.IMAGE_OS_VERSION "24.04")) }}997{{ else }}999{{ end }}{% endraw %} + gid: 999 package: rstudio-server: @@ -82,11 +82,43 @@ file: # Check for rstudio-launcher executable /usr/lib/rstudio-server/bin/rstudio-launcher: exists: true - # Check for rstudio-server monitor log directory + # Check for rstudio-server runtime directories with correct ownership and setgid + /var/lib/rstudio-server: + exists: true + owner: rstudio-server + group: rstudio-server + mode: "2775" /var/lib/rstudio-server/monitor/log: exists: true owner: rstudio-server group: rstudio-server + /var/lib/rstudio-server/conf: + exists: true + owner: rstudio-server + group: rstudio-server + /var/lib/rstudio-server/body: + exists: true + owner: rstudio-server + group: rstudio-server + /var/lib/rstudio-server/proxy: + exists: true + owner: rstudio-server + group: rstudio-server + /var/lib/rstudio-launcher: + exists: true + owner: rstudio-server + group: rstudio-server + mode: "2775" + /var/log/rstudio: + exists: true + owner: rstudio-server + group: rstudio-server + mode: "2775" + /var/run/rstudio-server: + exists: true + owner: rstudio-server + group: rstudio-server + mode: "2775" # Check for code-server executable (path varies based on RStudio Workbench version) {{ '{{ $version_split := split "." "' | safe }}{{ Image.Version }}{{ '" }}' | safe }} {% raw -%} From 37a1b17b818ac4b3f56329226fa6929d6e2f31da Mon Sep 17 00:00:00 2001 From: Sean Sinnott Date: Wed, 27 May 2026 20:49:04 -0400 Subject: [PATCH 2/8] Fix /var/run/rstudio-server ownership for Kubernetes --- workbench/template/Containerfile.ubuntu2204.jinja2 | 6 ++---- workbench/template/Containerfile.ubuntu2404.jinja2 | 6 ++---- workbench/template/test/goss.yaml.jinja2 | 3 --- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/workbench/template/Containerfile.ubuntu2204.jinja2 b/workbench/template/Containerfile.ubuntu2204.jinja2 index 131a5e5..ac25e5e 100644 --- a/workbench/template/Containerfile.ubuntu2204.jinja2 +++ b/workbench/template/Containerfile.ubuntu2204.jinja2 @@ -106,14 +106,12 @@ RUN mkdir -p /var/lib/rstudio-server/monitor/log \ /var/lib/rstudio-server/proxy \ /var/lib/rstudio-launcher \ /var/log/rstudio \ - /var/run/rstudio-server \ && chown -R rstudio-server:rstudio-server \ /var/lib/rstudio-server \ /var/lib/rstudio-launcher \ /var/log/rstudio \ - /var/run/rstudio-server \ - && chmod -R g+w /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio /var/run/rstudio-server \ - && find /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio /var/run/rstudio-server -type d -exec chmod g+s {} + \ + && chmod -R g+w /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio \ + && find /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio -type d -exec chmod g+s {} + \ && mkdir -p /startup/custom/ \ && mkdir -p /startup/user-provisioning/ \ && printf '\n# allow home directory creation\nsession required pam_mkhomedir.so skel=/etc/skel umask=0077\n' >> /etc/pam.d/common-session \ diff --git a/workbench/template/Containerfile.ubuntu2404.jinja2 b/workbench/template/Containerfile.ubuntu2404.jinja2 index e72574c..3ae4d98 100644 --- a/workbench/template/Containerfile.ubuntu2404.jinja2 +++ b/workbench/template/Containerfile.ubuntu2404.jinja2 @@ -106,14 +106,12 @@ RUN mkdir -p /var/lib/rstudio-server/monitor/log \ /var/lib/rstudio-server/proxy \ /var/lib/rstudio-launcher \ /var/log/rstudio \ - /var/run/rstudio-server \ && chown -R rstudio-server:rstudio-server \ /var/lib/rstudio-server \ /var/lib/rstudio-launcher \ /var/log/rstudio \ - /var/run/rstudio-server \ - && chmod -R g+w /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio /var/run/rstudio-server \ - && find /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio /var/run/rstudio-server -type d -exec chmod g+s {} + \ + && chmod -R g+w /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio \ + && find /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio -type d -exec chmod g+s {} + \ && mkdir -p /startup/custom/ \ && mkdir -p /startup/user-provisioning/ \ && printf '\n# allow home directory creation\nsession required pam_mkhomedir.so skel=/etc/skel umask=0077\n' >> /etc/pam.d/common-session \ diff --git a/workbench/template/test/goss.yaml.jinja2 b/workbench/template/test/goss.yaml.jinja2 index 564b7f6..d4d6466 100644 --- a/workbench/template/test/goss.yaml.jinja2 +++ b/workbench/template/test/goss.yaml.jinja2 @@ -116,9 +116,6 @@ file: mode: "2775" /var/run/rstudio-server: exists: true - owner: rstudio-server - group: rstudio-server - mode: "2775" # Check for code-server executable (path varies based on RStudio Workbench version) {{ '{{ $version_split := split "." "' | safe }}{{ Image.Version }}{{ '" }}' | safe }} {% raw -%} From c7edfbd7e2e8e5568880cf61267ddba673562d89 Mon Sep 17 00:00:00 2001 From: Sean Sinnott Date: Wed, 27 May 2026 21:01:59 -0400 Subject: [PATCH 3/8] Use sudo -u instead of su in goss monitor log test --- workbench/template/test/goss.yaml.jinja2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workbench/template/test/goss.yaml.jinja2 b/workbench/template/test/goss.yaml.jinja2 index d4d6466..108f02d 100644 --- a/workbench/template/test/goss.yaml.jinja2 +++ b/workbench/template/test/goss.yaml.jinja2 @@ -215,7 +215,7 @@ file: command: "Ensure rstudio-server has permissions to log directory": - exec: su rstudio-server -c 'touch /var/lib/rstudio-server/monitor/log/rstudio-server.log' + exec: sudo -u rstudio-server touch /var/lib/rstudio-server/monitor/log/rstudio-server.log exit-status: 0 "Ensure server log can be created": exec: touch /var/log/rstudio-server.log From d6195b2b797cbab987a7834abbdb28150cbe4128 Mon Sep 17 00:00:00 2001 From: Sean Sinnott Date: Thu, 28 May 2026 12:56:21 -0400 Subject: [PATCH 4/8] Reserve rstudio-server UID/GID 999 before apt installs Move the pre-create groupadd/useradd to the first RUN after the ENV block so the stable identifier is locked in before any apt packages that may create system users from the 999-down range. --- workbench/template/Containerfile.ubuntu2204.jinja2 | 14 +++++++------- workbench/template/Containerfile.ubuntu2404.jinja2 | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/workbench/template/Containerfile.ubuntu2204.jinja2 b/workbench/template/Containerfile.ubuntu2204.jinja2 index ac25e5e..cc75c0a 100644 --- a/workbench/template/Containerfile.ubuntu2204.jinja2 +++ b/workbench/template/Containerfile.ubuntu2204.jinja2 @@ -34,6 +34,13 @@ ENV PWB_DIAGNOSTIC_DIR=/var/log/rstudio ENV PWB_DIAGNOSTIC_ENABLE=false ENV PWB_EXIT_AFTER_VERIFY=false +### Pre-create rstudio-server user so deb postinst finds it and UID/GID stays 999 across image rebuilds ### +RUN groupadd --system --gid 999 rstudio-server \ + && useradd --system --uid 999 --gid 999 \ + --no-create-home --home-dir /var/lib/rstudio-server \ + --shell /usr/sbin/nologin \ + rstudio-server + ### Setup environment ### {{ apt.run_setup() }} @@ -50,13 +57,6 @@ COPY {{ Path.Version }}/deps/ubuntu-22.04_packages.txt /tmp/packages.txt ### Install wait-for-it ### COPY --chmod=0755 {{ Path.Image }}/scripts/wait-for-it.sh /usr/local/bin/wait-for-it.sh -### Pre-create rstudio-server user so deb postinst finds it and UID/GID stays 999 across image rebuilds ### -RUN groupadd --system --gid 999 rstudio-server \ - && useradd --system --uid 999 --gid 999 \ - --no-create-home --home-dir /var/lib/rstudio-server \ - --shell /usr/sbin/nologin \ - rstudio-server - ### Install Workbench {{ Image.Version }} ### COPY --chmod=0755 {{ Path.Version }}/scripts/install_workbench.sh /tmp/install_workbench.sh RUN {% if Image.DownloadURL is defined %}DOWNLOAD_URL="{{ Image.DownloadURL }}" {% endif %}\ diff --git a/workbench/template/Containerfile.ubuntu2404.jinja2 b/workbench/template/Containerfile.ubuntu2404.jinja2 index 3ae4d98..0278350 100644 --- a/workbench/template/Containerfile.ubuntu2404.jinja2 +++ b/workbench/template/Containerfile.ubuntu2404.jinja2 @@ -34,6 +34,13 @@ ENV PWB_DIAGNOSTIC_DIR=/var/log/rstudio ENV PWB_DIAGNOSTIC_ENABLE=false ENV PWB_EXIT_AFTER_VERIFY=false +### Pre-create rstudio-server user so deb postinst finds it and UID/GID stays 999 across image rebuilds ### +RUN groupadd --system --gid 999 rstudio-server \ + && useradd --system --uid 999 --gid 999 \ + --no-create-home --home-dir /var/lib/rstudio-server \ + --shell /usr/sbin/nologin \ + rstudio-server + ### Setup environment ### {{ apt.run_setup() }} @@ -50,13 +57,6 @@ COPY {{ Path.Version }}/deps/ubuntu-24.04_packages.txt /tmp/packages.txt ### Install wait-for-it ### COPY --chmod=0755 {{ Path.Image }}/scripts/wait-for-it.sh /usr/local/bin/wait-for-it.sh -### Pre-create rstudio-server user so deb postinst finds it and UID/GID stays 999 across image rebuilds ### -RUN groupadd --system --gid 999 rstudio-server \ - && useradd --system --uid 999 --gid 999 \ - --no-create-home --home-dir /var/lib/rstudio-server \ - --shell /usr/sbin/nologin \ - rstudio-server - ### Install Workbench {{ Image.Version }} ### COPY --chmod=0755 {{ Path.Version }}/scripts/install_workbench.sh /tmp/install_workbench.sh RUN {% if Image.DownloadURL is defined %}DOWNLOAD_URL="{{ Image.DownloadURL }}" {% endif %}\ From 2710effd059c91dcecaa365829d278d5663af08f Mon Sep 17 00:00:00 2001 From: Sean Sinnott Date: Thu, 28 May 2026 16:02:53 -0400 Subject: [PATCH 5/8] Gate rstudio-server permission setup to development images --- workbench/template/Containerfile.ubuntu2204.jinja2 | 6 ++++++ workbench/template/Containerfile.ubuntu2404.jinja2 | 6 ++++++ workbench/template/test/goss.yaml.jinja2 | 14 +++++++++++--- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/workbench/template/Containerfile.ubuntu2204.jinja2 b/workbench/template/Containerfile.ubuntu2204.jinja2 index cc75c0a..d99d89a 100644 --- a/workbench/template/Containerfile.ubuntu2204.jinja2 +++ b/workbench/template/Containerfile.ubuntu2204.jinja2 @@ -34,6 +34,7 @@ ENV PWB_DIAGNOSTIC_DIR=/var/log/rstudio ENV PWB_DIAGNOSTIC_ENABLE=false ENV PWB_EXIT_AFTER_VERIFY=false +{% if Image.IsDevelopmentVersion %} ### Pre-create rstudio-server user so deb postinst finds it and UID/GID stays 999 across image rebuilds ### RUN groupadd --system --gid 999 rstudio-server \ && useradd --system --uid 999 --gid 999 \ @@ -41,6 +42,7 @@ RUN groupadd --system --gid 999 rstudio-server \ --shell /usr/sbin/nologin \ rstudio-server +{% endif %} ### Setup environment ### {{ apt.run_setup() }} @@ -101,6 +103,7 @@ COPY "{{ Path.Version }}/conf/jupyter/*" "{{ Path.Version }}/conf/launcher/*" "{ ### Configure Workbench ### RUN mkdir -p /var/lib/rstudio-server/monitor/log \ +{% if Image.IsDevelopmentVersion %} /var/lib/rstudio-server/conf \ /var/lib/rstudio-server/body \ /var/lib/rstudio-server/proxy \ @@ -112,6 +115,9 @@ RUN mkdir -p /var/lib/rstudio-server/monitor/log \ /var/log/rstudio \ && chmod -R g+w /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio \ && find /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio -type d -exec chmod g+s {} + \ +{% else %} + && chown -R rstudio-server:rstudio-server /var/lib/rstudio-server/monitor \ +{% endif %} && mkdir -p /startup/custom/ \ && mkdir -p /startup/user-provisioning/ \ && printf '\n# allow home directory creation\nsession required pam_mkhomedir.so skel=/etc/skel umask=0077\n' >> /etc/pam.d/common-session \ diff --git a/workbench/template/Containerfile.ubuntu2404.jinja2 b/workbench/template/Containerfile.ubuntu2404.jinja2 index 0278350..7153a8c 100644 --- a/workbench/template/Containerfile.ubuntu2404.jinja2 +++ b/workbench/template/Containerfile.ubuntu2404.jinja2 @@ -34,6 +34,7 @@ ENV PWB_DIAGNOSTIC_DIR=/var/log/rstudio ENV PWB_DIAGNOSTIC_ENABLE=false ENV PWB_EXIT_AFTER_VERIFY=false +{% if Image.IsDevelopmentVersion %} ### Pre-create rstudio-server user so deb postinst finds it and UID/GID stays 999 across image rebuilds ### RUN groupadd --system --gid 999 rstudio-server \ && useradd --system --uid 999 --gid 999 \ @@ -41,6 +42,7 @@ RUN groupadd --system --gid 999 rstudio-server \ --shell /usr/sbin/nologin \ rstudio-server +{% endif %} ### Setup environment ### {{ apt.run_setup() }} @@ -101,6 +103,7 @@ COPY "{{ Path.Version }}/conf/jupyter/*" "{{ Path.Version }}/conf/launcher/*" "{ ### Configure Workbench ### RUN mkdir -p /var/lib/rstudio-server/monitor/log \ +{% if Image.IsDevelopmentVersion %} /var/lib/rstudio-server/conf \ /var/lib/rstudio-server/body \ /var/lib/rstudio-server/proxy \ @@ -112,6 +115,9 @@ RUN mkdir -p /var/lib/rstudio-server/monitor/log \ /var/log/rstudio \ && chmod -R g+w /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio \ && find /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio -type d -exec chmod g+s {} + \ +{% else %} + && chown -R rstudio-server:rstudio-server /var/lib/rstudio-server/monitor \ +{% endif %} && mkdir -p /startup/custom/ \ && mkdir -p /startup/user-provisioning/ \ && printf '\n# allow home directory creation\nsession required pam_mkhomedir.so skel=/etc/skel umask=0077\n' >> /etc/pam.d/common-session \ diff --git a/workbench/template/test/goss.yaml.jinja2 b/workbench/template/test/goss.yaml.jinja2 index 108f02d..88c1a58 100644 --- a/workbench/template/test/goss.yaml.jinja2 +++ b/workbench/template/test/goss.yaml.jinja2 @@ -8,14 +8,14 @@ user: rstudio-server: exists: true uid: 999 - gid: 999 + gid: {% if Image.IsDevelopmentVersion %}999{% else %}{% raw %}{{ if and (eq .Env.IMAGE_VARIANT "Standard") (and (eq .Env.IMAGE_OS_NAME "ubuntu") (eq .Env.IMAGE_OS_VERSION "24.04")) }}997{{ else }}999{{ end }}{% endraw %}{% endif %} groups: - rstudio-server group: rstudio-server: exists: true - gid: 999 + gid: {% if Image.IsDevelopmentVersion %}999{% else %}{% raw %}{{ if and (eq .Env.IMAGE_VARIANT "Standard") (and (eq .Env.IMAGE_OS_NAME "ubuntu") (eq .Env.IMAGE_OS_VERSION "24.04")) }}997{{ else }}999{{ end }}{% endraw %}{% endif %} package: rstudio-server: @@ -82,6 +82,7 @@ file: # Check for rstudio-launcher executable /usr/lib/rstudio-server/bin/rstudio-launcher: exists: true + {%- if Image.IsDevelopmentVersion %} # Check for rstudio-server runtime directories with correct ownership and setgid /var/lib/rstudio-server: exists: true @@ -116,6 +117,13 @@ file: mode: "2775" /var/run/rstudio-server: exists: true + {%- else %} + # Check for rstudio-server monitor log directory + /var/lib/rstudio-server/monitor/log: + exists: true + owner: rstudio-server + group: rstudio-server + {%- endif %} # Check for code-server executable (path varies based on RStudio Workbench version) {{ '{{ $version_split := split "." "' | safe }}{{ Image.Version }}{{ '" }}' | safe }} {% raw -%} @@ -215,7 +223,7 @@ file: command: "Ensure rstudio-server has permissions to log directory": - exec: sudo -u rstudio-server touch /var/lib/rstudio-server/monitor/log/rstudio-server.log + exec: {% if Image.IsDevelopmentVersion %}sudo -u rstudio-server touch /var/lib/rstudio-server/monitor/log/rstudio-server.log{% else %}su rstudio-server -c 'touch /var/lib/rstudio-server/monitor/log/rstudio-server.log'{% endif %} exit-status: 0 "Ensure server log can be created": exec: touch /var/log/rstudio-server.log From 1a640bd0c2ba5323687eedd08948ea3056e3754a Mon Sep 17 00:00:00 2001 From: Sean Sinnott Date: Thu, 28 May 2026 16:20:39 -0400 Subject: [PATCH 6/8] Make rstudio-server pre-create idempotent and assert UID/GID 999 --- .../template/Containerfile.ubuntu2204.jinja2 | 20 ++++++++++++++----- .../template/Containerfile.ubuntu2404.jinja2 | 20 ++++++++++++++----- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/workbench/template/Containerfile.ubuntu2204.jinja2 b/workbench/template/Containerfile.ubuntu2204.jinja2 index d99d89a..2b13a5a 100644 --- a/workbench/template/Containerfile.ubuntu2204.jinja2 +++ b/workbench/template/Containerfile.ubuntu2204.jinja2 @@ -36,11 +36,21 @@ ENV PWB_EXIT_AFTER_VERIFY=false {% if Image.IsDevelopmentVersion %} ### Pre-create rstudio-server user so deb postinst finds it and UID/GID stays 999 across image rebuilds ### -RUN groupadd --system --gid 999 rstudio-server \ - && useradd --system --uid 999 --gid 999 \ - --no-create-home --home-dir /var/lib/rstudio-server \ - --shell /usr/sbin/nologin \ - rstudio-server +# Idempotent so a cached layer (or the deb postinst) that already created the +# account does not fail the build. +RUN if ! getent group rstudio-server >/dev/null; then \ + groupadd --system --gid 999 rstudio-server; \ + fi \ + && if ! getent passwd rstudio-server >/dev/null; then \ + useradd --system --uid 999 --gid rstudio-server \ + --no-create-home --home-dir /var/lib/rstudio-server \ + --shell /usr/sbin/nologin \ + rstudio-server; \ + fi \ + && if [ "$(id -u rstudio-server)" != 999 ] || [ "$(id -g rstudio-server)" != 999 ]; then \ + echo "ERROR: rstudio-server must be uid/gid 999, got uid=$(id -u rstudio-server) gid=$(id -g rstudio-server)" >&2; \ + exit 1; \ + fi {% endif %} ### Setup environment ### diff --git a/workbench/template/Containerfile.ubuntu2404.jinja2 b/workbench/template/Containerfile.ubuntu2404.jinja2 index 7153a8c..4f6543e 100644 --- a/workbench/template/Containerfile.ubuntu2404.jinja2 +++ b/workbench/template/Containerfile.ubuntu2404.jinja2 @@ -36,11 +36,21 @@ ENV PWB_EXIT_AFTER_VERIFY=false {% if Image.IsDevelopmentVersion %} ### Pre-create rstudio-server user so deb postinst finds it and UID/GID stays 999 across image rebuilds ### -RUN groupadd --system --gid 999 rstudio-server \ - && useradd --system --uid 999 --gid 999 \ - --no-create-home --home-dir /var/lib/rstudio-server \ - --shell /usr/sbin/nologin \ - rstudio-server +# Idempotent so a cached layer (or the deb postinst) that already created the +# account does not fail the build. +RUN if ! getent group rstudio-server >/dev/null; then \ + groupadd --system --gid 999 rstudio-server; \ + fi \ + && if ! getent passwd rstudio-server >/dev/null; then \ + useradd --system --uid 999 --gid rstudio-server \ + --no-create-home --home-dir /var/lib/rstudio-server \ + --shell /usr/sbin/nologin \ + rstudio-server; \ + fi \ + && if [ "$(id -u rstudio-server)" != 999 ] || [ "$(id -g rstudio-server)" != 999 ]; then \ + echo "ERROR: rstudio-server must be uid/gid 999, got uid=$(id -u rstudio-server) gid=$(id -g rstudio-server)" >&2; \ + exit 1; \ + fi {% endif %} ### Setup environment ### From 4927d2d9ac99372a7b3da995eb8358411d43b7ba Mon Sep 17 00:00:00 2001 From: Sean Sinnott Date: Thu, 28 May 2026 17:17:49 -0400 Subject: [PATCH 7/8] Drop unassertable mode check on rstudio-launcher dir The launcher resets /var/lib/rstudio-launcher to 0755 on startup, so the build-time setgid mode never survives to test time. Assert only ownership. --- workbench/template/test/goss.yaml.jinja2 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workbench/template/test/goss.yaml.jinja2 b/workbench/template/test/goss.yaml.jinja2 index 88c1a58..06316b0 100644 --- a/workbench/template/test/goss.yaml.jinja2 +++ b/workbench/template/test/goss.yaml.jinja2 @@ -105,11 +105,12 @@ file: exists: true owner: rstudio-server group: rstudio-server + # rstudio-launcher resets its scratch directory to 0755 on startup, so we + # only assert ownership here; the build-time setgid mode does not survive. /var/lib/rstudio-launcher: exists: true owner: rstudio-server group: rstudio-server - mode: "2775" /var/log/rstudio: exists: true owner: rstudio-server From 18228adf874be1f42797460a19dd0706ff7ca555 Mon Sep 17 00:00:00 2001 From: Sean Sinnott Date: Thu, 28 May 2026 17:25:01 -0400 Subject: [PATCH 8/8] Run supervisord as non-root under /var/run/supervisor on dev images Move the supervisord socket and pidfile into a group-writable /var/run/supervisor directory and drop the root user pin, so supervisord can run under an arbitrary Kubernetes UID in the rstudio-server group. Create and setgid the directory in the Containerfiles and assert it in goss. Gated to development images to match the rest of this branch. --- .../template/Containerfile.ubuntu2204.jinja2 | 6 ++++-- .../template/Containerfile.ubuntu2404.jinja2 | 6 ++++-- .../template/startup/supervisord.conf.jinja2 | 15 ++++++++++++--- workbench/template/test/goss.yaml.jinja2 | 5 +++++ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/workbench/template/Containerfile.ubuntu2204.jinja2 b/workbench/template/Containerfile.ubuntu2204.jinja2 index 2b13a5a..6b812eb 100644 --- a/workbench/template/Containerfile.ubuntu2204.jinja2 +++ b/workbench/template/Containerfile.ubuntu2204.jinja2 @@ -119,12 +119,14 @@ RUN mkdir -p /var/lib/rstudio-server/monitor/log \ /var/lib/rstudio-server/proxy \ /var/lib/rstudio-launcher \ /var/log/rstudio \ + /var/run/supervisor \ && chown -R rstudio-server:rstudio-server \ /var/lib/rstudio-server \ /var/lib/rstudio-launcher \ /var/log/rstudio \ - && chmod -R g+w /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio \ - && find /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio -type d -exec chmod g+s {} + \ + /var/run/supervisor \ + && chmod -R g+w /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio /var/run/supervisor \ + && find /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio /var/run/supervisor -type d -exec chmod g+s {} + \ {% else %} && chown -R rstudio-server:rstudio-server /var/lib/rstudio-server/monitor \ {% endif %} diff --git a/workbench/template/Containerfile.ubuntu2404.jinja2 b/workbench/template/Containerfile.ubuntu2404.jinja2 index 4f6543e..c205cee 100644 --- a/workbench/template/Containerfile.ubuntu2404.jinja2 +++ b/workbench/template/Containerfile.ubuntu2404.jinja2 @@ -119,12 +119,14 @@ RUN mkdir -p /var/lib/rstudio-server/monitor/log \ /var/lib/rstudio-server/proxy \ /var/lib/rstudio-launcher \ /var/log/rstudio \ + /var/run/supervisor \ && chown -R rstudio-server:rstudio-server \ /var/lib/rstudio-server \ /var/lib/rstudio-launcher \ /var/log/rstudio \ - && chmod -R g+w /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio \ - && find /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio -type d -exec chmod g+s {} + \ + /var/run/supervisor \ + && chmod -R g+w /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio /var/run/supervisor \ + && find /var/lib/rstudio-server /var/lib/rstudio-launcher /var/log/rstudio /var/run/supervisor -type d -exec chmod g+s {} + \ {% else %} && chown -R rstudio-server:rstudio-server /var/lib/rstudio-server/monitor \ {% endif %} diff --git a/workbench/template/startup/supervisord.conf.jinja2 b/workbench/template/startup/supervisord.conf.jinja2 index 7180a82..0eb6b0c 100644 --- a/workbench/template/startup/supervisord.conf.jinja2 +++ b/workbench/template/startup/supervisord.conf.jinja2 @@ -1,13 +1,22 @@ ; supervisor config file +{%- if Image.IsDevelopmentVersion %} +{%- set supervisor_socket = "/var/run/supervisor/supervisor.sock" %} +{%- set supervisor_pidfile = "/var/run/supervisor/supervisord.pid" %} +{%- else %} +{%- set supervisor_socket = "/var/run/supervisor.sock" %} +{%- set supervisor_pidfile = "/var/run/supervisord.pid" %} +{%- endif %} [unix_http_server] -file=/var/run/supervisor.sock ; (the path to the socket file) +file={{ supervisor_socket }} ; (the path to the socket file) chmod=0700 ; sockef file mode (default 0700) [supervisord] logfile=/dev/stdout ; (main log file;default $CWD/supervisord.log) +{%- if not Image.IsDevelopmentVersion %} user=root -pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) +{%- endif %} +pidfile={{ supervisor_pidfile }} ; (supervisord pidfile;default supervisord.pid) ; should configure each program to use stdout/stderr ; childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) logfile_maxbytes=0 @@ -22,7 +31,7 @@ nodaemon=true supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] -serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket +serverurl=unix://{{ supervisor_socket }} ; use a unix:// URL for a unix socket ; The [include] section can just contain the "files" setting. This ; setting can list multiple files (separated by whitespace or diff --git a/workbench/template/test/goss.yaml.jinja2 b/workbench/template/test/goss.yaml.jinja2 index 06316b0..62a5078 100644 --- a/workbench/template/test/goss.yaml.jinja2 +++ b/workbench/template/test/goss.yaml.jinja2 @@ -118,6 +118,11 @@ file: mode: "2775" /var/run/rstudio-server: exists: true + /var/run/supervisor: + exists: true + owner: rstudio-server + group: rstudio-server + mode: "2775" {%- else %} # Check for rstudio-server monitor log directory /var/lib/rstudio-server/monitor/log: