Skip to content

fix(docker): non-root web image and secret-proof dockerignore - #74

Merged
JOY (JOY) merged 1 commit into
devfrom
docker/nonroot-user-and-dockerignore
Sep 16, 2026
Merged

JOY (JOY) merged 1 commit into
devfrom
docker/nonroot-user-and-dockerignore

Conversation

@JOY

Copy link
Copy Markdown

What

Closes the HI-12 remainder of the audit:

  • Runner stage drops root - the app tree is copied with --chown=node:node (no duplicate copy-up layer) and the container switches to USER node after the root-only apt step. Runtime cache writes (Next ISR, prisma engines) keep working because node owns the tree.
  • .dockerignore blocks secrets - .env, .env.*, *.pem, *.key, .husky etc. can no longer be baked into image layers. The repo root context is shared by the api/v2 image build, so that image is protected too.

Evidence

  • git ls-files confirms no tracked .pem/.key/.env file is needed by any build step, so ignoring them is safe.
  • CI (fork-ci.yml) runs on this PR; deploy-docker only publishes after the type-check gate passes.

Risk

  • Runtime permission changes are not caught by the image build itself; the HEALTHCHECK and start.sh both run as node. If a stray write target outside /calcom appears, it will surface on the next prod deploy - start.sh only reads app files and talks to the DB.

🤖 Generated by ZCode

…ecrets

The runner stage operated as root (audit HI-12 remainder): a container
escape would land directly on root. Copy the app tree with --chown so
the unprivileged node user owns it (keeping runtime cache writes
working) and switch to USER node after the root-only apt step.

.dockerignore now excludes .env*, *.pem, *.key, *.p12, *.pfx and .husky
so local secrets cannot be baked into image layers. The root context is
shared by the api/v2 image build, which protects that image too.
@coderabbitai

coderabbitai Bot commented Sep 16, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 4a71bfaf-fec4-4d9a-a957-67936ca619d2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request updates .dockerignore to exclude sensitive environment and key files, and modifies the Dockerfile to run the container as the unprivileged node user with appropriate file ownership. Feedback on the changes includes changing the ownership of the /calcom directory itself to prevent permission issues, using the numeric UID 1000 instead of the username node for better compatibility with security scanners, and adding the --no-hsts flag to the wget healthcheck to avoid write failures in read-only filesystems.

Comment thread Dockerfile
@@ -101,14 +101,21 @@ WORKDIR /calcom

RUN apt-get update && apt-get install -y --no-install-recommends netcat-openbsd wget && rm -rf /var/lib/apt/lists/*

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

While COPY --chown=node:node correctly sets the ownership of the copied files, the /calcom directory itself was created by WORKDIR /calcom while running as root. This leaves the /calcom directory owned by root:root with 0755 permissions, which prevents the non-root node user from creating any new files or directories directly under /calcom at runtime (e.g., lockfiles, temporary files, or local cache directories).

To prevent potential Permission denied errors, change the ownership of the /calcom directory to node:node during the setup phase.

RUN apt-get update && apt-get install -y --no-install-recommends netcat-openbsd wget && rm -rf /var/lib/apt/lists/* && chown node:node /calcom

Comment thread Dockerfile

# HI-12: run as the unprivileged node user (uid 1000) shipped with the base
# image instead of root; apt above already ran as root.
USER node

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-medium medium

Using a non-numeric user name like USER node can cause issues with strict container security scanners, Kubernetes admission controllers (such as Kyverno or OPA Gatekeeper), and certain container runtimes that require or prefer numeric UIDs to verify non-root execution without inspecting the image's /etc/passwd file.

Since the node user in the official Node.js base image is guaranteed to have UID 1000, it is a best practice to use the numeric UID instead.

USER 1000

Comment thread Dockerfile
Comment on lines 119 to 120
HEALTHCHECK --interval=30s --timeout=30s --retries=5 \
CMD wget --spider http://localhost:3000 || exit 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

By default, wget attempts to write a .wget-hsts file to the user's home directory (/home/node). If the container is run with a read-only root filesystem (a common security best practice), this write operation will fail and may cause the healthcheck to fail or log warnings.

Adding the --no-hsts flag to wget disables HSTS tracking and prevents it from attempting to write to the filesystem, making the healthcheck more robust in read-only environments.

HEALTHCHECK --interval=30s --timeout=30s --retries=5 \
  CMD wget --no-hsts --spider http://localhost:3000 || exit 1

@JOY
JOY (JOY) merged commit a888fe0 into dev Sep 16, 2026
11 checks passed
@JOY
JOY (JOY) deleted the docker/nonroot-user-and-dockerignore branch September 16, 2026 17:17
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.

1 participant