Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,11 @@ jobs:
exit 1
}

# Note: the local `hadolint` pre-commit hook (.pre-commit-config.yaml:81)
# runs ghcr.io/hadolint/hadolint pinned by digest to v2.14.0. We do NOT
# Note: the local `hadolint` hook in .pre-commit-config.yaml (search for
# `id: hadolint`; no line number, because this comment has already gone
# stale twice as that file shifted) runs ghcr.io/hadolint/hadolint pinned
# by digest. The version lives in that entry and is the single source of
# truth; do not restate it here, or this comment rots again. We do NOT
# install a host binary here — it would be dead code (never invoked by
# the hook) AND a supply-chain hole (latest tag, no checksum). Note:
# an earlier version of this comment claimed the hook already pinned
Expand Down
23 changes: 14 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,26 @@ repos:
# The upstream hadolint-docker hook (hadolint/hadolint's own
# .pre-commit-hooks.yaml) declares `entry: ghcr.io/hadolint/hadolint
# hadolint` with no image tag, so Docker resolves it to `:latest` on every
# run -- independent of the `rev:` pin above, which only pins which
# commit of the *hook definition* is used, not the Docker image it runs.
# When upstream published hadolint 2.15.1 as `latest`, CI silently
# started linting with a newer ruleset (new DL3066/DL3025 findings on
# unchanged Dockerfiles) with no corresponding change in this repo.
# run -- independent of any `rev:` pin, which only pins which commit of the
# *hook definition* is used, not the Docker image it runs. When upstream
# published hadolint 2.15.1 as `latest`, CI silently started linting with a
# newer ruleset (new DL3066/DL3025 findings on unchanged Dockerfiles) with no
# corresponding change in this repo, and `main` went red (issue #1695).
#
# Defined as a local hook instead, pinned to the immutable digest of the
# v2.14.0 image, so the linter version can only change via an explicit
# bump here.
# Defined as a local hook instead, pinned to an immutable digest, so the
# linter version can only change through an explicit edit to this line.
#
# Pinned to 2.15.1 -- the version that surfaced the findings -- rather than
# back to 2.14.0. Pinning to the older image would also have made CI green,
# but only by un-seeing findings that are real; the four it reported are
# fixed in the Dockerfiles rather than silenced. Bumping this digest is
# expected to require fixing whatever the new version finds.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- repo: local
hooks:
- id: hadolint
name: Lint Dockerfiles
language: docker_image
entry: ghcr.io/hadolint/hadolint:v2.14.0@sha256:27086352fd5e1907ea2b934eb1023f217c5ae087992eb59fde121dce9c9ff21e hadolint
entry: ghcr.io/hadolint/hadolint:v2.15.1@sha256:32dac94127fd60b7b7e3fbfc65e1383b9b5e25c9bfd7b8536de7a539fe68a12d hadolint
types: [dockerfile]

# Markdown linting
Expand Down
15 changes: 12 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,11 @@ COPY --from=frontend-builder --chown=cudly:cudly /frontend/dist /app/static
COPY --chown=cudly:cudly scripts/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

# Switch to non-root user
USER cudly
# Switch to non-root user. Numeric form so the identity is resolvable without
# the image's /etc/passwd: Kubernetes `runAsNonRoot` and similar admission
# checks cannot verify a name-form USER and will refuse to start the pod.
# 1000:1000 is exactly the uid:gid created above, so this is a rename only.
USER 1000:1000

# Environment defaults
ENV DB_MIGRATIONS_PATH=/app/migrations \
Expand All @@ -162,8 +165,14 @@ ENV DB_MIGRATIONS_PATH=/app/migrations \
EXPOSE 8080

# Health check (works for HTTP mode, ignored in Lambda mode)
#
# JSON (exec) form, but invoking /bin/sh explicitly: the `||` is a shell
# operator, so a bare exec-form list would hand `||` and `exit` to curl as
# literal arguments and the healthcheck would never report unhealthy correctly.
# This is the same process tree the shell form produced, written so the
# dependency on a shell is declared rather than implied.
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
CMD ["/bin/sh", "-c", "curl -f http://localhost:8080/health || exit 1"]

# Unified entrypoint handles both Lambda and HTTP modes
ENTRYPOINT ["/entrypoint.sh"]
Expand Down
11 changes: 8 additions & 3 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,16 @@ RUN if [ ! -f .air.toml ]; then air init; fi

EXPOSE 8080

# Create non-root user for security; grant ownership of app dir and Go paths
RUN addgroup -S devuser && adduser -S devuser -G devuser && \
# Create non-root user for security; grant ownership of app dir and Go paths.
# uid/gid are pinned explicitly rather than left to `adduser -S`, which picks
# the first free system id and so varies with the base image's existing users.
# A numeric USER below needs a value that is known here, not discovered later.
RUN addgroup -g 1001 devuser && \
adduser -D -u 1001 -G devuser devuser && \
chown -R devuser:devuser /app /root/go /root/.cache 2>/dev/null || true

USER devuser
# Numeric form so the identity is resolvable without the image's /etc/passwd.
USER 1001:1001
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# Start with Air for hot reload
CMD ["air", "-c", ".air.toml"]
4 changes: 3 additions & 1 deletion Dockerfile.test
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ WORKDIR /e2e

COPY --chown=e2e:e2e tests/e2e/ ./

USER e2e
# Numeric form so the identity is resolvable without the image's /etc/passwd.
# 10001 is exactly the uid created above, so this is a rename only.
USER 10001

# Pre-compile the test binary so `docker compose up` failures are runtime
# failures, not compile errors discovered after the stack is already up.
Expand Down
Loading