Skip to content

Conversation

@findolor
Copy link
Collaborator

@findolor findolor commented Nov 12, 2025

Motivation

Solution

Checks

By submitting this for review, I'm confirming I've done the following:

  • made this PR as small as possible
  • unit-tested any new functionality
  • linked any relevant issues or PRs
  • included screenshots (if this involves a front-end change)

Summary by CodeRabbit

  • New Features

    • Added Docker container support for reproducible builds and deployment.
    • Container startup automates CLI install, repository setup, build/artifact extraction, local DB sync, optional artifact upload, and cleanup.
  • Behavior Changes

    • Artifact upload flow now prefers DigitalOcean Spaces with Cloudflare R2 as an alternative.
    • CLI binary naming/path default changed.
    • Cleanup no longer removes the extracted CLI binary (retained after run).

✏️ Tip: You can customize this high-level summary in your review settings.

@findolor findolor requested review from 0xgleb and hardyjosh November 12, 2025 07:39
@findolor findolor self-assigned this Nov 12, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 12, 2025

Walkthrough

Adds a Dockerfile and an executable entrypoint that set up Nix on Ubuntu 22.04, clone a pinned repo, build and extract a CLI via nix, run a local DB sync, upload artifacts (DigitalOcean Spaces or Cloudflare R2), and swaps r2-upload.sh for do-spaces-upload.sh in the flake steps.

Changes

Cohort / File(s) Summary
Container build
Dockerfile
New Dockerfile (base ubuntu:22.04) that installs Nix with flakes and daemon, clones a pinned commit, initializes submodules, runs prep scripts, builds a CLI via nix develop, extracts and makes the CLI executable, and sets an ENTRYPOINT.
Entrypoint script
scripts/docker-entrypoint.sh
New executable Bash entrypoint: strict shell options, resolves script/project dirs, changes to project root, downloads/prepares CLI binary, runs DB sync, selects upload path by UPLOAD_BACKEND (spaces → DigitalOcean Spaces, r2 → Cloudflare R2, other → error), runs cleanup, and exits.
Flake step change
flake.nix
Replace r2-upload.sh with do-spaces-upload.sh in the local-db-pipeline steps array; step invocation loop remains.
Cleanup script
scripts/cleanup.sh
Removed deletion of the CLI binary path; now only removes archive and local DB directory.
Sync script
scripts/sync.sh
Updated default CLI binary name from rain_orderbook_cli to rain-orderbook-cli; rest of sync flow unchanged.

Sequence Diagram(s)

sequenceDiagram
    participant Container as Container Runtime
    participant Entrypoint as docker-entrypoint.sh
    participant Repo as Remote Git
    participant Nix as Nix Build Env
    participant CLI as Built CLI
    participant DB as Local DB
    participant Storage as Cloud Storage

    Note over Container,Entrypoint: Container start → ENTRYPOINT
    Container->>Entrypoint: start
    Entrypoint->>Entrypoint: set -euo pipefail, resolve dirs, cd project
    Entrypoint->>Repo: clone pinned commit & init submodules
    Entrypoint->>Nix: run prep scripts & nix develop to build CLI
    Nix->>CLI: produce CLI artifact
    Entrypoint->>CLI: extract & chmod
    Entrypoint->>DB: run sync via CLI
    alt UPLOAD_BACKEND == "spaces"
        Entrypoint->>Storage: upload artifacts → DigitalOcean Spaces
    else UPLOAD_BACKEND == "r2"
        Entrypoint->>Storage: upload artifacts → Cloudflare R2
    else
        Entrypoint-->>Entrypoint: fail unsupported backend
    end
    Entrypoint->>Entrypoint: cleanup artifacts (archive, local DB)
    Entrypoint->>Container: exit
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay extra attention to:
    • Dockerfile: Nix installation flags, daemon enablement, flake enablement, pinned clone, submodule init, exact nix develop invocation and artifact paths, ENTRYPOINT correctness.
    • scripts/docker-entrypoint.sh: strict-shell behavior, path resolution, environment assumptions (UPLOAD_BACKEND, credentials), branching logic for uploads, and error/exit handling.
    • flake.nix: ensure do-spaces-upload.sh exists and ordering matches pipeline expectations.
    • scripts/cleanup.sh and scripts/sync.sh: confirm the changed binary name and retained cleanup semantics.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a Dockerfile. It is concise and directly related to the primary modification across multiple files that establish Docker containerization.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dockerfile

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e0b0e51 and c354426.

📒 Files selected for processing (2)
  • Dockerfile (1 hunks)
  • scripts/docker-entrypoint.sh (1 hunks)
🧰 Additional context used
🪛 Checkov (3.2.334)
Dockerfile

[low] 1-20: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-20: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)
Dockerfile

[warning] 5-5: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)

🔇 Additional comments (4)
scripts/docker-entrypoint.sh (4)

2-2: Approve strict error handling with set -euo pipefail.

The use of set -euo pipefail ensures the script fails fast on errors, undefined variables, and pipe failures. This is excellent defensive programming for a container entrypoint.


9-9: Approve environment variable with sensible default.

The UPLOAD_BACKEND environment variable with a default value of "spaces" provides good flexibility while ensuring the script has a fallback behavior.


17-30: Approve robust backend selection with case statement and validation.

The case statement properly validates the UPLOAD_BACKEND value and exits with an error if an unknown backend is specified. This prevents silent failures from typos or misconfiguration.


1-35: All referenced scripts exist and are executable.

Verification confirms that the five external scripts called by the entrypoint script are all present and executable, so no runtime failures will occur due to missing dependencies.

Dockerfile Outdated
Comment on lines 1 to 20
FROM debian:bookworm-slim

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bash \
ca-certificates \
curl \
findutils \
gzip \
tar \
awscli \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY scripts ./scripts

ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Add a HEALTHCHECK instruction for container orchestration.

The container lacks a HEALTHCHECK instruction, which prevents orchestration platforms (Docker Swarm, Kubernetes) from automatically detecting unhealthy instances and restarting them.

Consider adding a HEALTHCHECK instruction to verify the container's readiness. For example:

  FROM debian:bookworm-slim
  
  ENV DEBIAN_FRONTEND=noninteractive
  
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
+   CMD curl -f http://localhost:8080/health || exit 1

Adjust the health check endpoint and interval based on your application's behavior. If the application does not expose a health endpoint, you could check for the existence of a marker file created after successful initialization.

🧰 Tools
🪛 Checkov (3.2.334)

[low] 1-20: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-20: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)

[warning] 5-5: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)

🤖 Prompt for AI Agents
In Dockerfile around lines 1 to 20, there is no HEALTHCHECK instruction which
prevents orchestration tools from detecting unhealthy containers; add a
HEALTHCHECK that periodically probes an appropriate readiness endpoint or marker
file inside the container (for example, curl --fail http://localhost:PORT/health
or test -f /var/run/app-ready) with sensible interval, timeout and retries so
the runtime can mark and restart unhealthy instances; place the HEALTHCHECK
after ENTRYPOINT or at end of file and tune interval, timeout and retries to
match your app startup/behavior.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Establish a non-root user to mitigate privilege escalation risks.

The container runs as root by default. This violates the principle of least privilege and increases security risk if the container is compromised or runs untrusted code.

Add a non-root user and switch to it before the entrypoint. Apply this diff:

  RUN apt-get update \
      && apt-get install -y --no-install-recommends \
          bash \
          ca-certificates \
          curl \
          findutils \
          gzip \
          tar \
          awscli \
      && rm -rf /var/lib/apt/lists/*
  
+ RUN useradd -m -u 1000 appuser
+ 
  WORKDIR /app
  
  COPY scripts ./scripts
  
+ RUN chown -R appuser:appuser /app
+ USER appuser
+ 
  ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]

Verify that the entrypoint scripts do not require root privileges.


I'll verify the review comment by examining the entrypoint script and checking if it requires root privileges.


---

🏁 Script executed:

```shell
#!/bin/bash
# Find and examine the docker-entrypoint.sh script
find . -name "docker-entrypoint.sh" -type f | head -20

Length of output: 30


🏁 Script executed:

#!/bin/bash
# If found, check the contents and permissions of entrypoint script and related scripts
if [ -f "./scripts/docker-entrypoint.sh" ]; then
  echo "=== docker-entrypoint.sh ==="
  cat ./scripts/docker-entrypoint.sh
  echo ""
  echo "=== All scripts in ./scripts directory ==="
  ls -la ./scripts/
  echo ""
  echo "=== Checking for root-requiring operations in scripts ==="
  grep -r -i "apt-get\|apt\|apt-key\|usermod\|useradd\|groupadd\|chown\|chmod.*root\|sudo" ./scripts/ || echo "No obvious root-requiring ops found"
fi

Length of output: 1379


🏁 Script executed:

#!/bin/bash
# Check directory structure and permissions
echo "=== Checking if /app exists or would be created ==="
if [ -d "./app" ]; then
  ls -la ./app/
else
  echo "./app directory does not exist in repo root (will be created at runtime)"
fi

Length of output: 124


I need to examine the subscripts called by the entrypoint to ensure they don't require root privileges.


---

🏁 Script executed:

```shell
#!/bin/bash
# Examine each subscript for root-requiring operations
for script in download-binary.sh sync.sh cleanup.sh do-spaces-upload.sh r2-upload.sh; do
  echo "=== $script ==="
  cat "./scripts/$script"
  echo ""
done

Length of output: 6469


Establish a non-root user to mitigate privilege escalation risks.

The container runs as root by default. This violates the principle of least privilege and increases security risk if the container is compromised or runs untrusted code.

Verification confirms that all scripts called by the entrypoint (download-binary.sh, sync.sh, cleanup.sh, do-spaces-upload.sh, r2-upload.sh) perform only user-level operations: curl, tar, mkdir, chmod, AWS CLI configuration, and file I/O. None require elevated privileges.

Add a non-root user and switch to it before the entrypoint. Apply this diff:

  RUN apt-get update \
      && apt-get install -y --no-install-recommends \
          bash \
          ca-certificates \
          curl \
          findutils \
          gzip \
          tar \
          awscli \
      && rm -rf /var/lib/apt/lists/*
  
+ RUN useradd -m -u 1000 appuser
+ 
  WORKDIR /app
  
  COPY scripts ./scripts
  
+ RUN chown -R appuser:appuser /app
+ USER appuser
+ 
  ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bash \
ca-certificates \
curl \
findutils \
gzip \
tar \
awscli \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY scripts ./scripts
ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]
FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bash \
ca-certificates \
curl \
findutils \
gzip \
tar \
awscli \
&& rm -rf /var/lib/apt/lists/*
RUN useradd -m -u 1000 appuser
WORKDIR /app
COPY scripts ./scripts
RUN chown -R appuser:appuser /app
USER appuser
ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]
🧰 Tools
🪛 Checkov (3.2.334)

[low] 1-20: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-20: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)

[warning] 5-5: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)

🤖 Prompt for AI Agents
In Dockerfile lines 1-20, the image currently runs as root; create a non-root
user and use it for the container to reduce privilege risk. Add steps to create
a dedicated user and group (e.g., addgroup/adduser or useradd), create/own the
/app directory and any required dirs, set a sensible HOME, and switch the image
to that user with the USER instruction before ENTRYPOINT; ensure files copied
into /app (scripts) are chowned to the new user so the entrypoint can execute
them without root.

Comment on lines +11 to +33
echo "⬇️ Downloading CLI binary"
./scripts/download-binary.sh

echo "🔁 Syncing local DB"
./scripts/sync.sh

case "$UPLOAD_BACKEND" in
spaces)
echo "☁️ Uploading artifacts to DigitalOcean Spaces"
./scripts/do-spaces-upload.sh
;;
r2)
echo "☁️ Uploading artifacts to Cloudflare R2"
./scripts/r2-upload.sh
;;
*)
echo "❌ Unknown UPLOAD_BACKEND value: $UPLOAD_BACKEND"
exit 1
;;
esac

echo "🧹 Cleaning up artifacts"
./scripts/cleanup.sh
Copy link

@coderabbitai coderabbitai bot Nov 12, 2025

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider adding optional timeout handling and graceful degradation for long-running scripts.

Each script call runs without a timeout. If any script hangs (e.g., network connectivity issues), the container will hang indefinitely, potentially blocking orchestration platforms from starting new instances.

Consider wrapping script calls with timeout and adding optional fallback logic:

- echo "⬇️  Downloading CLI binary"
- ./scripts/download-binary.sh
+ echo "⬇️  Downloading CLI binary"
+ timeout 300 ./scripts/download-binary.sh || {
+   echo "⚠️  Download failed (exit code: $?)"
+   [ "${ALLOW_DOWNLOAD_FAILURE:-false}" = "true" ] && echo "Continuing anyway..." || exit 1
+ }

This approach:

  • Adds a 5-minute timeout (adjust as needed)
  • Allows scripts to optionally fail gracefully via env vars (e.g., ALLOW_DOWNLOAD_FAILURE)
  • Prevents indefinite hangs

Adjust timeout values and failure-tolerance based on your expected script execution times and operational requirements.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
echo "⬇️ Downloading CLI binary"
./scripts/download-binary.sh
echo "🔁 Syncing local DB"
./scripts/sync.sh
case "$UPLOAD_BACKEND" in
spaces)
echo "☁️ Uploading artifacts to DigitalOcean Spaces"
./scripts/do-spaces-upload.sh
;;
r2)
echo "☁️ Uploading artifacts to Cloudflare R2"
./scripts/r2-upload.sh
;;
*)
echo "❌ Unknown UPLOAD_BACKEND value: $UPLOAD_BACKEND"
exit 1
;;
esac
echo "🧹 Cleaning up artifacts"
./scripts/cleanup.sh
echo "⬇️ Downloading CLI binary"
timeout 300 ./scripts/download-binary.sh || {
echo "⚠️ Download failed (exit code: $?)"
[ "${ALLOW_DOWNLOAD_FAILURE:-false}" = "true" ] && echo "Continuing anyway..." || exit 1
}
echo "🔁 Syncing local DB"
./scripts/sync.sh
case "$UPLOAD_BACKEND" in
spaces)
echo "☁️ Uploading artifacts to DigitalOcean Spaces"
./scripts/do-spaces-upload.sh
;;
r2)
echo "☁️ Uploading artifacts to Cloudflare R2"
./scripts/r2-upload.sh
;;
*)
echo "❌ Unknown UPLOAD_BACKEND value: $UPLOAD_BACKEND"
exit 1
;;
esac
echo "🧹 Cleaning up artifacts"
./scripts/cleanup.sh
🤖 Prompt for AI Agents
In scripts/docker-entrypoint.sh around lines 11 to 33, the script calls
(download-binary.sh, sync.sh, upload scripts, cleanup.sh) run without timeouts
and can hang indefinitely; wrap each invocation with a configurable timeout
(e.g., TIMEOUT_SECS env var) using the timeout utility, capture the exit status,
and if it times out or fails use per-step env flags (e.g.,
ALLOW_DOWNLOAD_FAILURE, ALLOW_SYNC_FAILURE, ALLOW_UPLOAD_FAILURE,
ALLOW_CLEANUP_FAILURE) to decide whether to continue or exit non-zero; ensure
you log a clear message on timeout/failure, respect the allow flags to either
proceed with a warning or abort the entrypoint with exit 1, and set reasonable
defaults for TIMEOUT_SECS and allow flags so operational behavior is
predictable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

not needed

Copy link

Choose a reason for hiding this comment

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

@findolor, understood! I've noted your decision on the timeout handling.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (3)
Dockerfile (3)

5-14: Pin package versions to ensure reproducible builds.

Unpinned apt packages can install different versions on subsequent rebuilds, leading to non-deterministic behavior and difficult-to-reproduce issues. This is flagged by Hadolint (DL3008) and is a best practice for production images.

Apply this diff to pin package versions:

  RUN apt-get update \
      && apt-get install -y --no-install-recommends \
-     bash \
-     ca-certificates \
-     curl \
-     findutils \
-     gzip \
-     tar \
-     awscli \
+     bash=5.2-2+deb12u1 \
+     ca-certificates=20230311 \
+     curl=7.88.1-10+deb12u5 \
+     findutils=4.9.0-4 \
+     gzip=1.12-1+deb12u1 \
+     tar=1.34+dfsg-1.2+deb12u1 \
+     awscli=1.27.162-1 \
      && rm -rf /var/lib/apt/lists/*

Verify exact versions available in Debian Bookworm via apt-cache policy <package> or the Debian package tracker.


5-20: Create a non-root user and switch to it before executing the entrypoint.

The container runs as root by default, violating the principle of least privilege. This increases security risk if the container is compromised or runs untrusted code. Previous review verification confirmed that all scripts (download-binary.sh, sync.sh, cleanup.sh, do-spaces-upload.sh, r2-upload.sh) perform only user-level operations and do not require root privileges.

Add a non-root user, transfer ownership of /app, and switch to the new user:

  RUN apt-get update \
      && apt-get install -y --no-install-recommends \
          bash \
          ca-certificates \
          curl \
          findutils \
          gzip \
          tar \
          awscli \
      && rm -rf /var/lib/apt/lists/*
  
+ RUN useradd -m -u 1000 appuser
+ 
  WORKDIR /app
  
  COPY scripts ./scripts
  
+ RUN chown -R appuser:appuser /app
+ USER appuser
+ 
  CMD ["bash", "-c", "while true; do /app/scripts/docker-entrypoint.sh; sleep 300; done"]

20-20: Add HEALTHCHECK instruction for container orchestration and error handling.

The Dockerfile lacks a HEALTHCHECK instruction, which prevents orchestration platforms (Docker Swarm, Kubernetes) from automatically detecting unhealthy instances and restarting them. Additionally, the loop structure with a fixed 5-minute interval means failed script execution will silently retry in 5 minutes rather than fail fast or log errors.

Add a HEALTHCHECK instruction and consider logging/error handling:

  FROM debian:bookworm-slim
  
  ENV DEBIAN_FRONTEND=noninteractive
  
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
+   CMD test -f /tmp/docker-entrypoint.success || exit 1
  
  RUN apt-get update \
      && apt-get install -y --no-install-recommends \
          bash \
          ca-certificates \
          curl \
          findutils \
          gzip \
          tar \
          awscli \
      && rm -rf /var/lib/apt/lists/*
  
  WORKDIR /app
  
  COPY scripts ./scripts
  
  CMD ["bash", "-c", "while true; do /app/scripts/docker-entrypoint.sh && touch /tmp/docker-entrypoint.success || rm -f /tmp/docker-entrypoint.success; sleep 300; done"]

Alternatively, if the entrypoint script creates a marker file or exposes a health endpoint, use that instead of /tmp/docker-entrypoint.success. Verify with the entrypoint script author the appropriate health signal.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c354426 and 1199715.

📒 Files selected for processing (1)
  • Dockerfile (1 hunks)
🧰 Additional context used
🪛 Checkov (3.2.334)
Dockerfile

[low] 1-20: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-20: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)
Dockerfile

[warning] 5-5: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)

🔇 Additional comments (1)
Dockerfile (1)

16-18: No issues found — entrypoint script is properly committed and executable.

The script ./scripts/docker-entrypoint.sh exists in the repository and is marked executable (permissions: -rwxr-xr-x). The Dockerfile dependency on line 20 is satisfied.

Dockerfile Outdated
Comment on lines 1 to 4
FROM debian:bookworm-slim

ENV DEBIAN_FRONTEND=noninteractive

Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Use lightweight base image with explicit versioning.

The choice of debian:bookworm-slim is appropriate for a lightweight production image. However, using an unversioned tag (bookworm-slim) means rebuilds may pull a different image snapshot over time. Consider pinning to a specific digest or date-based tag (e.g., debian:bookworm-20250101-slim) for reproducibility.

🧰 Tools
🪛 Checkov (3.2.334)

[low] 1-20: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-20: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🤖 Prompt for AI Agents
In Dockerfile around lines 1 to 4, the base image uses the floating tag
`debian:bookworm-slim`; update it to a reproducible pin by replacing the tag
with either a date-based/tagged release (e.g., `debian:bookworm-YYYYMMDD-slim`)
or the specific image digest (e.g., `debian@sha256:<digest>`). Fetch the desired
digest from Docker Hub or your registry for the exact image you want, and update
the FROM line to use that digest or an explicit dated tag to ensure builds are
reproducible.

Dockerfile Outdated

COPY scripts ./scripts

CMD ["bash", "-c", "while true; do /app/scripts/docker-entrypoint.sh; sleep 300; done"]
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Clarify the operational intent of the 5-minute polling interval.

The loop runs the entrypoint script every 5 minutes (300 seconds). This suggests a scheduled job or periodic sync pattern rather than a long-running service. Verify this is intentional and document:

  • Why polling vs. event-driven or one-shot execution?
  • What happens if the script fails—should it fail fast or retry silently?
  • Should errors be logged to stdout/stderr for container orchestration visibility?
  • Is 5 minutes the correct interval for the use case?

Consider adding structured logging and explicit exit codes so failures are visible to Docker/Kubernetes log aggregation and monitoring systems.

🧰 Tools
🪛 Checkov (3.2.334)

[low] 1-20: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-20: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🤖 Prompt for AI Agents
In Dockerfile around line 20, the CMD loops to run docker-entrypoint.sh every
300s but lacks documentation and failure handling; update the Dockerfile and
entrypoint to (1) document the intended operational model (polling vs
event-driven/one-shot and why 5 minutes was chosen), (2) make the interval
configurable via an env var (e.g., POLL_INTERVAL) instead of hardcoding 300, (3)
ensure the entrypoint emits structured logs to stdout/stderr and returns
non-zero exit codes on fatal errors, and (4) decide/log retry policy (fail-fast
vs silent retry) and implement it in the script (e.g., on failure log error with
context and either exit with code or continue based on a RETRY_ON_FAIL flag) so
container orchestrators can observe failures.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1199715 and 0a93703.

📒 Files selected for processing (1)
  • Dockerfile.orderbook (1 hunks)
🧰 Additional context used
🪛 Checkov (3.2.334)
Dockerfile.orderbook

[low] 1-41: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-41: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)
Dockerfile.orderbook

[warning] 3-3: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)


[info] 29-29: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 30-30: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 31-31: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 32-32: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 33-33: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

🔇 Additional comments (1)
Dockerfile.orderbook (1)

21-21: All verification checks passed—no action required.

The file scripts/docker-entrypoint.sh exists, is executable, and has a valid shebang (#!/usr/bin/env bash). The script is properly structured with correct error handling (set -euo pipefail). The Docker ENTRYPOINT reference on line 41 will work correctly.

Comment on lines 1 to 41
FROM ubuntu:22.04

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
xz-utils \
&& rm -rf /var/lib/apt/lists/*

ENV NIX_CONFIG="experimental-features = nix-command flakes"

RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
&& . /etc/profile.d/nix.sh \
&& nix --version

ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"

WORKDIR /app

COPY scripts ./scripts

ARG REMOTE_REPO_URL=https://github.com/rainlanguage/rain.orderbook
ARG REMOTE_REPO_COMMIT=07a94259de218dd58de34fe3a5289c965cf277b6

RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
WORKDIR /app/rain.orderbook
RUN git checkout "$REMOTE_REPO_COMMIT"
RUN cp .env.example .env
RUN git submodule update --init --recursive
RUN bash ./prep-base.sh
RUN nix run .#rainix-ob-cli-artifact
RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
RUN chmod +x /app/rain_orderbook_cli

WORKDIR /app

ENV CLI_BIN=/app/rain_orderbook_cli

ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider adding a HEALTHCHECK instruction for orchestration and monitoring.

The image lacks a health check endpoint. Add a HEALTHCHECK to allow container orchestrators (Docker Compose, Kubernetes) to monitor the CLI's readiness and restart unhealthy instances.

 ENV CLI_BIN=/app/rain_orderbook_cli
 
+HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
+  CMD "$CLI_BIN" --version > /dev/null 2>&1 || exit 1
+
 ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]

Adjust the command and intervals based on the actual CLI's health-check capability.

🧰 Tools
🪛 Checkov (3.2.334)

[low] 1-41: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-41: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)

[warning] 3-3: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)


[info] 29-29: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 30-30: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 31-31: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 32-32: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 33-33: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

🤖 Prompt for AI Agents
In Dockerfile.orderbook around lines 1 to 41, there's no HEALTHCHECK, so add a
HEALTHCHECK instruction that invokes the CLI health or quick-readiness command
(use $CLI_BIN or a known subcommand like --health or --version if no explicit
health command exists) and configure sensible intervals/retries (e.g.,
start-period 30s, interval 30s, timeout 5s, retries 3); place the HEALTHCHECK
near the end of the Dockerfile after ENV CLI_BIN and before ENTRYPOINT and
ensure it uses SHELL form or exec form to run the binary and return appropriate
exit codes for healthy/unhealthy.

⚠️ Potential issue | 🟠 Major

Add a non-root user to mitigate container escape risks.

The container runs as root by default. Create a dedicated user for least-privilege execution, even if the entrypoint requires elevated privileges.

 FROM ubuntu:22.04
 
 RUN apt-get update \
     && apt-get install -y --no-install-recommends \
     ca-certificates \
     curl \
     git \
     xz-utils \
     && rm -rf /var/lib/apt/lists/*
+
+RUN groupadd -r raindb && useradd -r -g raindb raindb
 
 ENV NIX_CONFIG="experimental-features = nix-command flakes"
 ...
 
 WORKDIR /app
+RUN chown -R raindb:raindb /app
+
+USER raindb
 
 ENV CLI_BIN=/app/rain_orderbook_cli
 
 ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]

If docker-entrypoint.sh requires root (e.g., for mounting volumes or network config), use USER raindb to drop privileges after initialization, or invoke the entrypoint with explicit root elevation where needed.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
FROM ubuntu:22.04
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
xz-utils \
&& rm -rf /var/lib/apt/lists/*
ENV NIX_CONFIG="experimental-features = nix-command flakes"
RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
&& . /etc/profile.d/nix.sh \
&& nix --version
ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"
WORKDIR /app
COPY scripts ./scripts
ARG REMOTE_REPO_URL=https://github.com/rainlanguage/rain.orderbook
ARG REMOTE_REPO_COMMIT=07a94259de218dd58de34fe3a5289c965cf277b6
RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
WORKDIR /app/rain.orderbook
RUN git checkout "$REMOTE_REPO_COMMIT"
RUN cp .env.example .env
RUN git submodule update --init --recursive
RUN bash ./prep-base.sh
RUN nix run .#rainix-ob-cli-artifact
RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
RUN chmod +x /app/rain_orderbook_cli
WORKDIR /app
ENV CLI_BIN=/app/rain_orderbook_cli
ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]
FROM ubuntu:22.04
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
xz-utils \
&& rm -rf /var/lib/apt/lists/*
RUN groupadd -r raindb && useradd -r -g raindb raindb
ENV NIX_CONFIG="experimental-features = nix-command flakes"
RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
&& . /etc/profile.d/nix.sh \
&& nix --version
ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"
WORKDIR /app
COPY scripts ./scripts
ARG REMOTE_REPO_URL=https://github.com/rainlanguage/rain.orderbook
ARG REMOTE_REPO_COMMIT=07a94259de218dd58de34fe3a5289c965cf277b6
RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
WORKDIR /app/rain.orderbook
RUN git checkout "$REMOTE_REPO_COMMIT"
RUN cp .env.example .env
RUN git submodule update --init --recursive
RUN bash ./prep-base.sh
RUN nix run .#rainix-ob-cli-artifact
RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
RUN chmod +x /app/rain_orderbook_cli
WORKDIR /app
RUN chown -R raindb:raindb /app
USER raindb
ENV CLI_BIN=/app/rain_orderbook_cli
ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]
🧰 Tools
🪛 Checkov (3.2.334)

[low] 1-41: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-41: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)

[warning] 3-3: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)


[info] 29-29: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 30-30: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 31-31: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 32-32: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 33-33: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

🤖 Prompt for AI Agents
In Dockerfile.orderbook around lines 1 to 41, the image currently runs as root
which is a security risk; add a non-root user and switch to it after any
root-only initialization steps. Create a dedicated user (e.g., raindb) and
group, set a proper HOME, chown the /app files and any runtime directories to
that user, and use USER raindb before the ENTRYPOINT so the container runs with
least privilege; if some commands (like installing Nix or preparing artifacts)
must run as root, keep them before the chown and USER switch and ensure the
entrypoint script can handle dropped privileges or perform escalation only when
necessary.

Comment on lines 3 to 9
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
xz-utils \
&& rm -rf /var/lib/apt/lists/*
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Pin versions for apt packages to prevent supply-chain vulnerabilities.

The packages ca-certificates, curl, git, and xz-utils are installed without version pinning. This can pull different versions across builds, risking outdated or vulnerable packages. Pin each package to a specific version.

 RUN apt-get update \
     && apt-get install -y --no-install-recommends \
-    ca-certificates \
-    curl \
-    git \
-    xz-utils \
+    ca-certificates=20240110 \
+    curl=7.81.0-1ubuntu1.15 \
+    git=1:2.34.1-1ubuntu1.10 \
+    xz-utils=5.2.5-2ubuntu1 \
     && rm -rf /var/lib/apt/lists/*

(Replace version numbers with versions appropriate for ubuntu:22.04. Run apt-cache policy <package> in an ubuntu:22.04 container to find exact versions.)

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
xz-utils \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates=20240110 \
curl=7.81.0-1ubuntu1.15 \
git=1:2.34.1-1ubuntu1.10 \
xz-utils=5.2.5-2ubuntu1 \
&& rm -rf /var/lib/apt/lists/*
🧰 Tools
🪛 Hadolint (2.14.0)

[warning] 3-3: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)

Comment on lines 19 to 40
WORKDIR /app

COPY scripts ./scripts

ARG REMOTE_REPO_URL=https://github.com/rainlanguage/rain.orderbook
ARG REMOTE_REPO_COMMIT=07a94259de218dd58de34fe3a5289c965cf277b6

RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
WORKDIR /app/rain.orderbook
RUN git checkout "$REMOTE_REPO_COMMIT"
RUN cp .env.example .env
RUN git submodule update --init --recursive
RUN bash ./prep-base.sh
RUN nix run .#rainix-ob-cli-artifact
RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
RUN chmod +x /app/rain_orderbook_cli

WORKDIR /app

ENV CLI_BIN=/app/rain_orderbook_cli

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Consolidate consecutive RUN instructions to reduce image layers.

Lines 26–35 execute 10 consecutive RUN instructions (git clone, checkout, copy, submodule init, build, extract, rename, chmod). Consolidating them reduces image size and improves cache efficiency. Combine git operations (lines 26–30) and build/extract operations (lines 32–35) into two RUN blocks.

-WORKDIR /app
-
-COPY scripts ./scripts
+WORKDIR /app
 
-ARG REMOTE_REPO_URL=https://github.com/rainlanguage/rain.orderbook
-ARG REMOTE_REPO_COMMIT=07a94259de218dd58de34fe3a5289c965cf277b6
+COPY scripts ./scripts
 
-RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
-WORKDIR /app/rain.orderbook
-RUN git checkout "$REMOTE_REPO_COMMIT"
-RUN cp .env.example .env
-RUN git submodule update --init --recursive
-RUN bash ./prep-base.sh
-RUN nix run .#rainix-ob-cli-artifact
-RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
-RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
-RUN chmod +x /app/rain_orderbook_cli
+ARG REMOTE_REPO_URL=https://github.com/rainlanguage/rain.orderbook
+ARG REMOTE_REPO_COMMIT=07a94259de218dd58de34fe3a5289c965cf277b6
+
+RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook \
+    && cd /app/rain.orderbook \
+    && git checkout "$REMOTE_REPO_COMMIT" \
+    && cp .env.example .env \
+    && git submodule update --init --recursive \
+    && bash ./prep-base.sh
+
+RUN cd /app/rain.orderbook \
+    && nix run .#rainix-ob-cli-artifact \
+    && tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app \
+    && mv /app/rain-orderbook-cli /app/rain_orderbook_cli \
+    && chmod +x /app/rain_orderbook_cli
🧰 Tools
🪛 Hadolint (2.14.0)

[info] 29-29: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 30-30: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 31-31: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 32-32: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 33-33: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

🤖 Prompt for AI Agents
In Dockerfile.orderbook around lines 19 to 40, there are many consecutive RUN
instructions creating extra image layers; consolidate them into two RUN blocks:
one that performs repository setup (git clone into /app/rain.orderbook, set
WORKDIR, checkout the commit, copy .env.example to .env, and git submodule
update --init --recursive and run prep-base.sh) and a second that performs the
build and install steps (nix run the artifact, extract the tarball, move the
extracted binary to /app/rain_orderbook_cli and chmod +x). Ensure WORKDIR is set
appropriately before each consolidated RUN and combine the commands with && so
failures stop the build.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (2)
Dockerfile (2)

1-41: [Duplicate] Establish a non-root user to mitigate privilege escalation risks.

This critical security issue was flagged in the prior review and remains unresolved. The container runs as root by default, violating the principle of least privilege and increasing security risk.

Prior verification confirmed all scripts (download-binary.sh, sync.sh, cleanup.sh, do-spaces-upload.sh, r2-upload.sh) perform only user-level operations and do not require root. Implement the suggested fix:

  RUN apt-get update \
      && apt-get install -y --no-install-recommends \
          ca-certificates \
          curl \
          git \
          xz-utils \
      && rm -rf /var/lib/apt/lists/*
  
+ RUN useradd -m -u 1000 appuser
+ 
  ENV NIX_CONFIG="experimental-features = nix-command flakes"
  
  RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
      && . /etc/profile.d/nix.sh \
      && nix --version
  
  ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"
  
  WORKDIR /app
  
  COPY scripts ./scripts
  
+ RUN chown -R appuser:appuser /app
+ USER appuser

41-41: Add HEALTHCHECK instruction for container orchestration.

The container lacks a HEALTHCHECK instruction, preventing orchestration tools (Docker Swarm, Kubernetes) from detecting unhealthy instances. Add a health check:

  ENV CLI_BIN=/app/rain_orderbook_cli
  
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
+   CMD test -f /app/.health-marker || exit 1

Adjust the health check mechanism (e.g., curl to a health endpoint, test for a marker file, or verify a process) based on the entrypoint's actual behavior. If the entrypoint maintains persistent state (e.g., a lock file or marker), test for its existence. If it exposes an HTTP endpoint, use curl instead.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a93703 and f50ae5a.

📒 Files selected for processing (1)
  • Dockerfile (1 hunks)
🧰 Additional context used
🪛 Checkov (3.2.334)
Dockerfile

[low] 1-41: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-41: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)
Dockerfile

[warning] 3-3: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)


[info] 29-29: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 30-30: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 31-31: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 32-32: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 33-33: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

🔇 Additional comments (1)
Dockerfile (1)

3-9: Rewritten Review Comment:

Pin package versions in apt-get for reproducible builds.

Unpinned apt packages create non-deterministic builds and difficult-to-reproduce issues. Pin versions explicitly. However, the specific versions suggested in the original comment are outdated. Instead, verify current available versions:

apt-cache policy ca-certificates curl git xz-utils

Or check the Ubuntu package tracker for Ubuntu 22.04 (jammy) to find the appropriate versions before pinning.

Likely an incorrect or invalid review comment.

Dockerfile Outdated
Comment on lines 29 to 35
RUN cp .env.example .env
RUN git submodule update --init --recursive
RUN bash ./prep-base.sh
RUN nix run .#rainix-ob-cli-artifact
RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
RUN chmod +x /app/rain_orderbook_cli
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Consolidate consecutive RUN instructions to reduce image layers.

Multiple sequential RUN instructions (lines 29-35) create unnecessary layers, increasing image size. Consolidate them into a single RUN statement:

- RUN cp .env.example .env
- RUN git submodule update --init --recursive
- RUN bash ./prep-base.sh
- RUN nix run .#rainix-ob-cli-artifact
- RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
- RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
- RUN chmod +x /app/rain_orderbook_cli
+ RUN cp .env.example .env \
+     && git submodule update --init --recursive \
+     && bash ./prep-base.sh \
+     && nix run .#rainix-ob-cli-artifact \
+     && tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app \
+     && mv /app/rain-orderbook-cli /app/rain_orderbook_cli \
+     && chmod +x /app/rain_orderbook_cli

This is especially important for a "lightweight" image.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
RUN cp .env.example .env
RUN git submodule update --init --recursive
RUN bash ./prep-base.sh
RUN nix run .#rainix-ob-cli-artifact
RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
RUN chmod +x /app/rain_orderbook_cli
RUN cp .env.example .env \
&& git submodule update --init --recursive \
&& bash ./prep-base.sh \
&& nix run .#rainix-ob-cli-artifact \
&& tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app \
&& mv /app/rain-orderbook-cli /app/rain_orderbook_cli \
&& chmod +x /app/rain_orderbook_cli
🧰 Tools
🪛 Hadolint (2.14.0)

[info] 29-29: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 30-30: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 31-31: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 32-32: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 33-33: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

🤖 Prompt for AI Agents
In Dockerfile around lines 29 to 35, multiple consecutive RUN instructions (cp
.env.example .env; git submodule update --init --recursive; bash ./prep-base.sh;
nix run .#rainix-ob-cli-artifact; tar -xzf
crates/cli/bin/rain-orderbook-cli.tar.gz -C /app; mv /app/rain-orderbook-cli
/app/rain_orderbook_cli; chmod +x /app/rain_orderbook_cli) create extra image
layers—consolidate them into a single RUN by chaining the commands with && (or
using a shell block with line-continuations) so they execute in one layer,
include a safe shell header (e.g., set -euo pipefail) to fail early, and perform
any temporary-file cleanup in the same RUN so no unnecessary artifacts persist
between layers.

Dockerfile Outdated
Comment on lines 39 to 41
ENV CLI_BIN=/app/rain_orderbook_cli

ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Document the operational model and entrypoint behavior.

The Dockerfile sets an ENTRYPOINT but no CMD. Clarify in a README or comments:

  • Is this a one-shot execution or a long-running service?
  • If polling/looping occurs, is it in the entrypoint script or via orchestration?
  • How should errors be handled? Should the container exit or retry?
  • What logs or signals indicate success/failure?

This ensures users and operators understand the intended behavior, especially if the entrypoint implements polling or async operations.

🧰 Tools
🪛 Checkov (3.2.334)

[low] 1-41: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-41: Ensure that a user for the container has been created

(CKV_DOCKER_3)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f50ae5a and 26a6bee.

📒 Files selected for processing (2)
  • Dockerfile (1 hunks)
  • flake.nix (1 hunks)
🧰 Additional context used
🪛 Checkov (3.2.334)
Dockerfile

[low] 1-40: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-40: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)
Dockerfile

[warning] 3-3: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)


[info] 30-30: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 31-31: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 32-32: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 33-33: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 36-36: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

🔇 Additional comments (3)
Dockerfile (2)

38-40: Verify the entrypoint execution flow and dependencies.

The entrypoint runs local-db-pipeline from the Nix flake at /app, which orchestrates scripts from /app/scripts. This depends on several runtime conditions that should be verified:

  1. The flake.nix and flake.lock copied to /app are valid and up-to-date
  2. The scripts referenced in the pipeline exist and are executable
  3. Required environment variables are set (or have sensible defaults)
  4. The /app/rain_orderbook_cli binary extracted earlier is accessible

Consider adding a validation step before the final ENTRYPOINT to catch configuration issues at build time rather than runtime:

RUN nix develop -c local-db-pipeline --help || \
    (echo "ERROR: local-db-pipeline not available in flake" && exit 1)

Alternatively, run a dry-run or syntax check of the pipeline during the build phase.


21-21: The review comment is based on an incorrect assumption.

The scripts are already executable in the repository (all have -rwxr-xr-x permissions). Since COPY preserves file permissions during the Docker build, the scripts will remain executable in the container. The suggested chmod +x is unnecessary and the concern about runtime failure is not applicable.

Likely an incorrect or invalid review comment.

flake.nix (1)

57-57: The script name change is verified and properly configured.

Both do-spaces-upload.sh and r2-upload.sh exist and are fully implemented. The docker-entrypoint.sh supports both backends via the UPLOAD_BACKEND environment variable (defaulting to "spaces"), routing to the appropriate script based on configuration. The change in flake.nix from r2-upload.sh to do-spaces-upload.sh aligns with the default configuration and does not introduce breaking changes—deployments can still use R2 by setting UPLOAD_BACKEND=r2.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (5)
Dockerfile (5)

33-33: Fix the incorrect Nix command syntax.

The command nix develop -c .#rainix-ob-cli-artifact is syntactically invalid. The -c flag expects a command to execute within the development shell, not a flake reference starting with .#. This will cause the build to fail.

Based on context (building a CLI artifact), this should be:

- RUN nix develop -c .#rainix-ob-cli-artifact
+ RUN nix run .#rainix-ob-cli-artifact

If rainix-ob-cli-artifact is instead a development shell command, verify the correct invocation by consulting the rain.orderbook repository's flake.nix.


13-15: Verify Nix installer integrity to mitigate supply-chain risk.

The Nix installer is fetched via an unauthenticated remote script. Consider pinning the installer version, verifying the download signature, or switching to an official Nix base image (which pre-bundles Nix and avoids dynamic installation).

This was flagged in previous reviews; proceed based on your threat model and operational requirements.

If continuing with dynamic installation, add version pinning and integrity checks:

- RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
+ RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon --no-channel-add" \

Alternatively, use a Nix-enabled base image like nixos/nix to avoid the installation step entirely.


1-40: Add a HEALTHCHECK instruction for container orchestration.

The container lacks a HEALTHCHECK instruction, which prevents orchestration platforms (Docker Swarm, Kubernetes) from automatically detecting unhealthy instances. For a background polling/sync task, this is optional but recommended.

If the entrypoint script creates a marker file on successful initialization, you can check for it:

+ HEALTHCHECK --interval=60s --timeout=10s --start-period=10s --retries=2 \
+   CMD test -f /tmp/app-ready || exit 1

Alternatively, update the entrypoint script to create /tmp/app-ready after successful sync/upload.


1-40: Create a non-root user and run the container as that user.

The container runs as root by default, violating the principle of least privilege and increasing security risk if the container is compromised or runs untrusted code. This was flagged in previous reviews.

Verification of the scripts confirms that all entrypoint operations (download-binary.sh, sync.sh, cleanup.sh, do-spaces-upload.sh, r2-upload.sh) perform only user-level operations: curl, tar, mkdir, chmod, AWS CLI configuration, and file I/O—none require elevated privileges.

Add a non-root user and apply appropriate ownership. Insert after line 9:

  RUN apt-get update \
      && apt-get install -y --no-install-recommends \
          ca-certificates \
          curl \
          git \
          xz-utils \
      && rm -rf /var/lib/apt/lists/*
  
+ RUN useradd -m -u 1000 appuser
+ 
  ENV NIX_CONFIG="experimental-features = nix-command flakes"
  
  RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
      && . /etc/profile.d/nix.sh \
      && nix --version
  
  ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"
  
  WORKDIR /app
  
  COPY scripts ./scripts
  COPY flake.nix flake.lock ./
  
+ RUN chown -R appuser:appuser /app
+ USER appuser

Also update line 40 ENTRYPOINT to run as the appuser.


30-36: Consolidate consecutive RUN instructions to reduce image layers.

Multiple sequential RUN instructions (lines 30–36) create unnecessary layers, significantly increasing image size. For a "lightweight" image, consolidate into a single RUN statement with proper error handling.

Apply this diff:

- RUN cp .env.example .env
- RUN git submodule update --init --recursive
- RUN ["bash", "-lc", "set -euo pipefail; exec ./prep-base.sh"]
- RUN nix develop -c .#rainix-ob-cli-artifact
- RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
- RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
- RUN chmod +x /app/rain_orderbook_cli
+ RUN set -euo pipefail && \
+     cp .env.example .env && \
+     git submodule update --init --recursive && \
+     bash ./prep-base.sh && \
+     nix run .#rainix-ob-cli-artifact && \
+     tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app && \
+     mv /app/rain-orderbook-cli /app/rain_orderbook_cli && \
+     chmod +x /app/rain_orderbook_cli && \
+     rm -rf .git

Note: This also corrects the Nix syntax error on line 33 (see below).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 26a6bee and 8d05993.

📒 Files selected for processing (1)
  • Dockerfile (1 hunks)
🧰 Additional context used
🪛 Checkov (3.2.334)
Dockerfile

[low] 1-40: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-40: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)
Dockerfile

[warning] 3-3: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)


[info] 30-30: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 31-31: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 36-36: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

Comment on lines +27 to +29
RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
WORKDIR /app/rain.orderbook
RUN git checkout "$REMOTE_REPO_COMMIT"
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Optimize git clone with shallow history to reduce image size.

For a "lightweight" image, a full git clone with history inflates the final layer. Use a shallow clone to reduce size.

Apply this diff:

- RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
- WORKDIR /app/rain.orderbook
- RUN git checkout "$REMOTE_REPO_COMMIT"
+ RUN git clone --depth=1 --single-branch "$REMOTE_REPO_URL" /app/rain.orderbook \
+     && cd /app/rain.orderbook \
+     && git fetch --depth=1 origin "$REMOTE_REPO_COMMIT":refs/heads/target \
+     && git checkout "$REMOTE_REPO_COMMIT"
  WORKDIR /app/rain.orderbook

This reduces git history bundled in the image.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In Dockerfile around lines 27-29, the current git clone pulls full history;
replace it with a shallow clone to reduce image size: if REMOTE_REPO_COMMIT is a
branch or tag use git clone --depth=1 --branch "$REMOTE_REPO_COMMIT"
"$REMOTE_REPO_URL" /app/rain.orderbook, otherwise initialize the repo, add
remote and fetch only the specific commit with git init /app/rain.orderbook &&
cd /app/rain.orderbook && git remote add origin "$REMOTE_REPO_URL" && git fetch
--depth=1 origin "$REMOTE_REPO_COMMIT" && git checkout FETCH_HEAD; keep WORKDIR
/app/rain.orderbook as-is.

Dockerfile Outdated

WORKDIR /app

ENTRYPOINT ["nix", "develop", "-c", "local-db-pipeline"]
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix the broken ENTRYPOINT command.

The current ENTRYPOINT attempts to run local-db-pipeline, which does not exist in the image. Per the PR summary, a new docker-entrypoint.sh script has been added to orchestrate the pipeline. The ENTRYPOINT should invoke that script instead.

Replace line 40 with:

- ENTRYPOINT ["nix", "develop", "-c", "local-db-pipeline"]
+ ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]

Ensure that /app/scripts/docker-entrypoint.sh is executable (verified on line 36 with chmod +x, but confirm ownership is set correctly for the non-root user if one is added).

🧰 Tools
🪛 Checkov (3.2.334)

[low] 1-40: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-40: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🤖 Prompt for AI Agents
In Dockerfile around line 40, the ENTRYPOINT currently calls a non-existent
binary `local-db-pipeline`; replace it to invoke the newly added orchestration
script `/app/scripts/docker-entrypoint.sh`. Update the ENTRYPOINT to execute
that script (e.g., use the shell or exec form to run
/app/scripts/docker-entrypoint.sh) and confirm earlier in the Dockerfile that
the script is made executable (chmod +x) and that its ownership/permissions are
appropriate for any non-root user added to the image so the entrypoint can run
under that user.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (5)
Dockerfile (5)

30-32: Optimize git clone with shallow history to reduce image size.

For a "lightweight" image, a full git clone with history inflates the layer. Use shallow cloning to minimize size.

Since REMOTE_REPO_COMMIT is a specific commit hash, apply:

-RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
-WORKDIR /app/rain.orderbook
-RUN git checkout "$REMOTE_REPO_COMMIT"
+RUN git clone --depth=1 "$REMOTE_REPO_URL" /app/rain.orderbook \
+    && cd /app/rain.orderbook \
+    && git fetch --depth=1 origin "$REMOTE_REPO_COMMIT":refs/heads/target \
+    && git checkout "$REMOTE_REPO_COMMIT"
+WORKDIR /app/rain.orderbook

This reduces git history bundled in the image layer.


43-43: Replace non-existent ENTRYPOINT binary with the new entrypoint script.

The current ENTRYPOINT invokes nix develop -c local-db-pipeline, but local-db-pipeline does not exist in the image. According to the PR summary, a new scripts/docker-entrypoint.sh orchestration script has been added.

Replace the ENTRYPOINT to invoke the new script:

-ENTRYPOINT ["nix", "develop", "-c", "local-db-pipeline"]
+ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]

Ensure that:

  1. /app/scripts/docker-entrypoint.sh exists and is executable (line 39 sets chmod +x for the CLI binary, but the entrypoint script must also be executable).
  2. If a non-root user is added (see below), ensure the script and containing directory are owned by that user.

33-39: Consolidate consecutive RUN instructions into a single layer to reduce image size.

Lines 33–39 contain seven sequential RUN instructions that create unnecessary image layers, increasing size. For a "lightweight" image, consolidation is essential.

Consolidate into a single RUN with a strict shell header (set -euo pipefail):

-RUN cp .env.example .env
-RUN git submodule update --init --recursive
-RUN ./prep-base.sh
-RUN nix develop -c .#rainix-ob-cli-artifact
-RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
-RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
-RUN chmod +x /app/rain_orderbook_cli
+RUN set -euo pipefail && \
+    cp .env.example .env && \
+    git submodule update --init --recursive && \
+    ./prep-base.sh && \
+    nix run .#rainix-ob-cli-artifact && \
+    tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app && \
+    mv /app/rain-orderbook-cli /app/rain_orderbook_cli && \
+    chmod +x /app/rain_orderbook_cli

Note: Update nix develop -c .#rainix-ob-cli-artifact to the correct syntax (see separate critical issue comment).


1-43: Add a HEALTHCHECK instruction for container orchestration monitoring.

The image lacks a HEALTHCHECK, preventing Docker Swarm and Kubernetes from automatically detecting and recovering unhealthy instances.

Add a HEALTHCHECK at the end of the Dockerfile:

+ HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
+   CMD test -f /app/rain_orderbook_cli || exit 1

If the entrypoint script creates a marker file on successful startup (e.g., /tmp/app-ready), use:

+ HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
+   CMD test -f /tmp/app-ready || exit 1

Adjust interval, timeout, and start-period based on your application's initialization time. I can help update scripts/docker-entrypoint.sh to create such a marker if needed.


13-15: Secure the Nix installer by verifying integrity or using a pre-installed Nix image.

The current approach downloads and executes the Nix installer via unauthenticated curl, which is a real supply-chain risk. For production use, prefer installers that provide cryptographic signatures or reproducible artifacts; verify signatures and hashes, or use official, audited install methods.

Choose one of:

Option A (Recommended): Use the official Nix base image:

-FROM ubuntu:22.04
+FROM nixos/nix:2.5.1

This avoids dynamic installation and supplies a pinned, verified Nix version.

Option B: Verify installer integrity:
If ubuntu is required, download and verify the installer before execution:

-RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
+RUN set -euo pipefail && \
+    INSTALLER_URL="https://nixos.org/nix/install" && \
+    INSTALLER_SHA256="..." && \
+    curl --proto '=https' --tlsv1.2 -fL "$INSTALLER_URL" -o /tmp/nix-installer && \
+    echo "$INSTALLER_SHA256  /tmp/nix-installer" | sha256sum -c - && \
+    bash /tmp/nix-installer --daemon && \
+    rm /tmp/nix-installer

Retrieve the correct SHA256 from the official Nix release channels and apply one of these approaches.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8d05993 and c068b76.

📒 Files selected for processing (1)
  • Dockerfile (1 hunks)
🧰 Additional context used
🪛 Checkov (3.2.334)
Dockerfile

[low] 1-43: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-43: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)
Dockerfile

[warning] 3-3: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)


[info] 33-33: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 36-36: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 37-37: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 38-38: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 39-39: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

🔇 Additional comments (1)
Dockerfile (1)

1-9: Pin base image digest, update ca-certificates version, and address Nix daemon installation blocker.

The current digest for ubuntu:22.04 is sha256:adbb90115a21969d2fe6fa7f9af4253e16d45f8d4c1e930182610c4731962658. The package versions for curl, git, and xz-utils in your review are correct; however, ca-certificates version is 20240203~22.04.1, not 20230311ubuntu0.22.04.1 as suggested.

Scripts in ./scripts/ (cleanup.sh, download-binary.sh, sync.sh, do-spaces-upload.sh, r2-upload.sh) do not require root privileges and are compatible with non-root execution.

Critical issue: The Nix daemon installation (lines 11–13) requires root privileges. This runs before any USER directive can be applied, blocking the non-root user approach as currently proposed. The Nix daemon setup must either:

  • Remain as a root step (current structure), or
  • Be restructured to allow non-root operation (requires investigation into Nix daemon rootless mode)

Additionally, prep-base.sh (called from the cloned external repo at line 28) and the local-db-pipeline entrypoint (from the nix flake) cannot be verified without access to the external repository; you must confirm these do not require root privileges.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (6)
Dockerfile (6)

1-1: Pin the base image to a specific digest for reproducible, secure builds.

The floating tag ubuntu:22.04 can pull different snapshots on subsequent rebuilds, leading to non-deterministic behavior and potential security drift.

Replace with a pinned digest (e.g., ubuntu@sha256:<digest>) to ensure reproducible builds. Fetch the digest using: docker manifest inspect ubuntu:22.04 | grep digest | head -1.


3-9: Pin apt package versions for reproducible builds.

Unpinned packages install different versions on subsequent rebuilds, breaking reproducibility. Always pin versions for production images.

Apply this diff with pinned Jammy package versions:

  RUN apt-get update \
      && apt-get install -y --no-install-recommends \
-     ca-certificates \
-     curl \
-     git \
-     xz-utils \
+     ca-certificates=20230311ubuntu0.22.04.1 \
+     curl=7.81.0-1ubuntu1.21 \
+     git=1:2.34.1-1ubuntu1.15 \
+     xz-utils=5.2.5-2ubuntu1 \
      && rm -rf /var/lib/apt/lists/*

13-15: Secure the Nix installer fetch: verify integrity or use a pre-built image.

The Nix installer is fetched via an unauthenticated remote script, creating a supply-chain attack surface. Consider using an official Nix base image with pre-installed Nix, or verify the installer signature before execution.

If staying with the current approach, add integrity verification:

- RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
+ RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon --no-channel-add" \

40-40: Fix the broken ENTRYPOINT: replace non-existent local-db-pipeline with the new entrypoint script.

The current ENTRYPOINT calls nix develop -c local-db-pipeline, which does not exist in the image. Per the AI summary, a new scripts/docker-entrypoint.sh has been added to orchestrate the pipeline. The ENTRYPOINT should invoke that script instead.

- ENTRYPOINT ["nix", "develop", "-c", "local-db-pipeline"]
+ ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]

Ensure /app/scripts/docker-entrypoint.sh is:

  • Executable (verified on line 36 with chmod +x)
  • Owned by the non-root user (if one is added; see security comment below)

1-40: Establish a non-root user to mitigate privilege escalation risks.

The container runs as root by default, violating the principle of least privilege. This increases security risk if the container is compromised or runs untrusted code.

Add a non-root user after installing packages and before copying application files. Apply this diff:

  RUN apt-get update \
      && apt-get install -y --no-install-recommends \
          ca-certificates \
          curl \
          git \
          xz-utils \
      && rm -rf /var/lib/apt/lists/*
  
+ RUN useradd -m -u 1000 appuser
+ 
  ENV NIX_CONFIG="experimental-features = nix-command flakes"
  
  RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
      && . /etc/profile.d/nix.sh \
      && nix --version
  
  ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"
  
  WORKDIR /app
  
  COPY scripts ./scripts
  COPY flake.nix flake.lock ./
  
+ RUN chown -R appuser:appuser /app
+ 
  ARG REMOTE_REPO_URL=https://github.com/rainlanguage/rain.orderbook
  ARG REMOTE_REPO_COMMIT=07a94259de218dd58de34fe3a5289c965cf277b6
  
  RUN ... (consolidated build commands)
+ 
+ USER appuser

Verify that all scripts copied into the image (scripts/) perform only user-level operations and do not require elevated privileges.


1-40: Add a HEALTHCHECK instruction for container orchestration.

The container lacks a HEALTHCHECK instruction, preventing orchestration platforms (Docker Swarm, Kubernetes) from automatically detecting unhealthy instances and restarting them.

Add a HEALTHCHECK instruction to verify the container's readiness. Since the operational model (polling interval, sync behavior) is not yet documented, consider a simple file-existence check or a generic startup probe:

+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
+   CMD test -f /app/.sync-complete || exit 1

Alternatively, if the entrypoint script creates a marker file on success, adjust the check accordingly. Document the operational model (see separate comment below).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c068b76 and d38fe10.

📒 Files selected for processing (1)
  • Dockerfile (1 hunks)
🧰 Additional context used
🪛 Checkov (3.2.334)
Dockerfile

[low] 1-40: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-40: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)
Dockerfile

[warning] 3-3: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)


[info] 30-30: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 31-31: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 32-32: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 33-33: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 36-36: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

Dockerfile Outdated
Comment on lines 1 to 40
FROM ubuntu:22.04

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
xz-utils \
&& rm -rf /var/lib/apt/lists/*

ENV NIX_CONFIG="experimental-features = nix-command flakes"

RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
&& . /etc/profile.d/nix.sh \
&& nix --version

ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"

WORKDIR /app

COPY scripts ./scripts
COPY flake.nix flake.lock ./

ARG REMOTE_REPO_URL=https://github.com/rainlanguage/rain.orderbook
ARG REMOTE_REPO_COMMIT=07a94259de218dd58de34fe3a5289c965cf277b6

RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
WORKDIR /app/rain.orderbook
RUN git checkout "$REMOTE_REPO_COMMIT"
RUN cp .env.example .env
RUN git submodule update --init --recursive
RUN bash -euo pipefail -c "./prep-base.sh"
RUN nix develop -c .#rainix-ob-cli-artifact
RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
RUN chmod +x /app/rain_orderbook_cli

WORKDIR /app

ENTRYPOINT ["nix", "develop", "-c", "local-db-pipeline"]
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Document the operational model and entrypoint behavior.

The Dockerfile defines an ENTRYPOINT but provides no documentation about the intended behavior. Clarify:

  • Is this a one-shot execution or a long-running service?
  • What polling interval or loop behavior does the entrypoint implement?
  • How should errors be handled—fail fast or silent retry?
  • What logs or marker files indicate success/failure?
  • How should users/operators invoke and monitor this container?

Add documentation (e.g., README.md or inline comments) to ensure clarity for users and operators, especially if the entrypoint implements polling or async operations.

🧰 Tools
🪛 Checkov (3.2.334)

[low] 1-40: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-40: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)

[warning] 3-3: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)


[info] 30-30: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 31-31: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 32-32: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 33-33: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 36-36: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

🤖 Prompt for AI Agents
In Dockerfile around lines 1-40: the ENTRYPOINT is set to "nix develop -c
local-db-pipeline" but there is no documentation describing whether this
container is one-shot or long-running, what polling/retry behavior the
entrypoint implements, how errors are surfaced, what logs/marker files indicate
success or failure, or how operators should run and monitor the container;
update the repo by adding a short README.md (or Dockerfile inline comments) that
states: the intended operational model (one-shot vs daemon), exact entrypoint
command and expected lifecycle, poll intervals or loop semantics if any,
error-handling policy (fail fast vs retry and backoff), where logs are written
and any success/failure marker files or exit codes to watch, and example docker
run / kubernetes spec and minimal monitoring/healthcheck guidance so operators
can invoke and observe the container reliably.

Dockerfile Outdated
Comment on lines 27 to 36
RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
WORKDIR /app/rain.orderbook
RUN git checkout "$REMOTE_REPO_COMMIT"
RUN cp .env.example .env
RUN git submodule update --init --recursive
RUN bash -euo pipefail -c "./prep-base.sh"
RUN nix develop -c .#rainix-ob-cli-artifact
RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
RUN chmod +x /app/rain_orderbook_cli
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

❓ Verification inconclusive

Consolidate consecutive RUN instructions and optimize git clone for image size.

Seven consecutive RUN instructions (lines 30–36) create unnecessary layers, inflating image size. For a "lightweight" image, consolidate into a single RUN statement with chained commands. Also, use a shallow clone to reduce git history.

- RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
- WORKDIR /app/rain.orderbook
- RUN git checkout "$REMOTE_REPO_COMMIT"
- RUN cp .env.example .env
- RUN git submodule update --init --recursive
- RUN bash -euo pipefail -c "./prep-base.sh"
- RUN nix develop -c .#rainix-ob-cli-artifact
- RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
- RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
- RUN chmod +x /app/rain_orderbook_cli
+ RUN set -euo pipefail \
+     && git clone --depth=1 "$REMOTE_REPO_URL" /app/rain.orderbook \
+     && cd /app/rain.orderbook \
+     && git fetch --depth=1 origin "$REMOTE_REPO_COMMIT":refs/heads/target \
+     && git checkout "$REMOTE_REPO_COMMIT" \
+     && cp .env.example .env \
+     && git submodule update --init --recursive \
+     && bash ./prep-base.sh \
+     && nix run .#rainix-ob-cli-artifact \
+     && tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app \
+     && mv /app/rain-orderbook-cli /app/rain_orderbook_cli \
+     && chmod +x /app/rain_orderbook_cli

Note: This also fixes the invalid Nix syntax on line 33 (see comment below).


I need to verify several key claims in the review comment before rewriting it. Let me gather information:

I need to verify one more detail about the Nix command syntax to be thorough:

Revise suggested fix: Consolidate RUN instructions correctly without breaking build semantics.

The layer consolidation recommendation is valid Docker practice, but the proposed solution contains critical errors:

  1. Nix command is semantically different, not syntactically invalid: nix develop --command (or -c) is used to run commands within a development environment, while nix run executes a program from a derivation, looking for a binary matching the package name. These serve different purposes. Changing nix develop -c .#rainix-ob-cli-artifact to nix run .#rainix-ob-cli-artifact will produce different behavior and likely fail if the artifact output is not a runnable app.

  2. Shallow clone with arbitrary commits is fragile: To fetch a specific commit SHA with shallow clone, the server must support uploadpack.allowReachableSHA1InWant, and shallow clones create unexpected behavior issues limiting which Git commands are possible, and are strongly discouraged.

Consolidate the RUN instructions using && with proper error handling and set -euo pipefail, but keep the original git checkout approach (full clone then checkout specific commit). Consider using shallow clone only if the server explicitly supports it and testing is performed.

🧰 Tools
🪛 Hadolint (2.14.0)

[info] 30-30: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 31-31: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 32-32: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 33-33: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 36-36: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (7)
Dockerfile (7)

3-9: Pin apt package versions for reproducible builds.

Unpinned packages install different versions on rebuilds, breaking reproducibility and complicating debugging. For a production "lightweight" image, pin exact versions.

Apply this diff with pinned versions for Ubuntu 22.04 Jammy:

  RUN apt-get update \
      && apt-get install -y --no-install-recommends \
-     ca-certificates \
-     curl \
-     git \
-     xz-utils \
+     ca-certificates=20230311ubuntu0.22.04.1 \
+     curl=7.81.0-1ubuntu1.21 \
+     git=1:2.34.1-1ubuntu1.15 \
+     xz-utils=5.2.5-2ubuntu1 \
      && rm -rf /var/lib/apt/lists/*

13-15: Secure the Nix installer against supply-chain attacks.

Piping an unauthenticated remote script to bash is a security risk. Consider using a base image with Nix preinstalled, pinning the installer version, or verifying the script integrity via checksum/signature.

For increased security, replace the dynamic installation with a nix-enabled base image or add integrity verification:

- RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
+ RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon --no-channel-add" \

Alternatively, use an official NixOS base image where Nix is preinstalled and verified.


1-41: Add a HEALTHCHECK instruction for container orchestration.

The container lacks a HEALTHCHECK instruction, preventing orchestration platforms (Kubernetes, Docker Swarm) from automatically detecting unhealthy instances and restarting them.

Add a HEALTHCHECK instruction at the end of the Dockerfile:

+ WORKDIR /app
+ RUN chown -R appuser:appuser /app
+ USER appuser
  
  ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]
+ 
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
+   CMD test -f /tmp/local-db-sync-complete || exit 1

Adjust the health check based on your application's behavior (e.g., check for a marker file created by the entrypoint script on successful completion, or verify logs).


19-37: Establish a non-root user to mitigate privilege escalation risks.

The container runs as root by default, violating the principle of least privilege. This increases security risk if the container is compromised or runs untrusted code.

Add a non-root user and switch to it before the entrypoint. Apply this diff:

  WORKDIR /app
  
  COPY scripts ./scripts
  COPY flake.nix flake.lock ./
  
+ RUN useradd -m -u 1000 appuser
+ 
  ARG REMOTE_REPO_URL=https://github.com/rainlanguage/rain.orderbook
  ARG REMOTE_REPO_COMMIT=07a94259de218dd58de34fe3a5289c965cf277b6
  
  RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
  WORKDIR /app/rain.orderbook
  RUN git checkout "$REMOTE_REPO_COMMIT"
  RUN cp .env.example .env
  RUN git submodule update --init --recursive
  RUN bash -euo pipefail -c 'echo ">> prep-base.sh starting"; ./prep-base.sh; rc=$?; echo ">> prep-base.sh exited with code $rc"; exit $rc'
  RUN nix develop -c .#rainix-ob-cli-artifact
  RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
  RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
  RUN chmod +x /app/rain_orderbook_cli
  
  WORKDIR /app
+ RUN chown -R appuser:appuser /app
+ USER appuser

All scripts in ./scripts/ perform only user-level operations (curl, tar, mkdir, file I/O) and do not require elevated privileges.


41-41: Fix the broken ENTRYPOINT command.

The current ENTRYPOINT attempts to run local-db-pipeline, which does not exist in the image. Per the PR, a new docker-entrypoint.sh script has been added to orchestrate the pipeline. The ENTRYPOINT must invoke that script instead.

Replace line 41 with:

- ENTRYPOINT ["nix", "develop", "-c", "local-db-pipeline"]
+ ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]

The script will be copied to /app/scripts/ (line 21) and is already executable (755 permissions).


27-37: Consolidate consecutive RUN instructions to reduce image layers and size.

Seven consecutive RUN instructions (lines 27–37) create unnecessary layers, inflating the image size. For a "lightweight" image, consolidate them into a single RUN statement with && chaining and a shell header for fail-fast behavior.

Apply this diff (after fixing the Nix syntax on line 34):

- RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
- WORKDIR /app/rain.orderbook
- RUN git checkout "$REMOTE_REPO_COMMIT"
- RUN cp .env.example .env
- RUN git submodule update --init --recursive
- RUN bash -euo pipefail -c 'echo ">> prep-base.sh starting"; ./prep-base.sh; rc=$?; echo ">> prep-base.sh exited with code $rc"; exit $rc'
- RUN nix develop -c .#rainix-ob-cli-artifact
- RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
- RUN mv /app/rain-orderbook-cli /app/rain_orderbook_cli
- RUN chmod +x /app/rain_orderbook_cli
+ RUN set -euo pipefail && \
+     git clone "$REMOTE_REPO_URL" /app/rain.orderbook && \
+     cd /app/rain.orderbook && \
+     git checkout "$REMOTE_REPO_COMMIT" && \
+     cp .env.example .env && \
+     git submodule update --init --recursive && \
+     bash -c 'echo ">> prep-base.sh starting"; ./prep-base.sh; rc=$?; echo ">> prep-base.sh exited with code $rc"; exit $rc' && \
+     nix develop -c rainix-ob-cli-artifact && \
+     tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app && \
+     mv /app/rain-orderbook-cli /app/rain_orderbook_cli && \
+     chmod +x /app/rain_orderbook_cli

Note: Replace nix develop -c rainix-ob-cli-artifact with the correct form (either nix run .#rainix-ob-cli-artifact or nix develop -c rainix-ob-cli-artifact based on your flake.nix) once verified.


34-34: Fix invalid Nix syntax: -c flag requires a command, not a flake reference.

The command nix develop -c .#rainix-ob-cli-artifact is syntactically invalid. The -c flag expects a command to execute, not a flake reference. This will fail at build time.

Given the context (line 35 extracts crates/cli/bin/rain-orderbook-cli.tar.gz), rainix-ob-cli-artifact is a package from the imported rainix outputs. Use nix run instead:

- RUN nix develop -c .#rainix-ob-cli-artifact
+ RUN nix run .#rainix-ob-cli-artifact
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d38fe10 and 7b16062.

📒 Files selected for processing (1)
  • Dockerfile (1 hunks)
🧰 Additional context used
🪛 Checkov (3.2.334)
Dockerfile

[low] 1-41: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-41: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)
Dockerfile

[warning] 3-3: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)


[info] 30-30: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 31-31: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 33-33: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 36-36: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 37-37: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

@@ -0,0 +1,41 @@
FROM ubuntu:22.04
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Pin the base image to a specific digest for reproducible, secure builds.

The floating tag ubuntu:22.04 can pull different snapshots on subsequent rebuilds, creating non-deterministic builds vulnerable to supply chain attacks. Pin to a specific digest to ensure reproducible builds.

Once you obtain the digest, replace line 1 with: FROM ubuntu@sha256:<digest>


🌐 Web query:

What is the current sha256 digest for ubuntu:22.04?

💡 Result:

The digest for ubuntu:22.04 (manifest list) is:

sha256:adbb90115a21969d2fe6fa7f9af4253e16d45f8d4c1e930182610c4731962658

(as seen on Docker image metadata — retrieved 2025-11-24). [1]

Sources:
[1] docker.io/library/ubuntu:22.04 image metadata.


Pin the base image to a specific digest for reproducible, secure builds.

The floating tag ubuntu:22.04 can pull different snapshots on subsequent rebuilds, creating non-deterministic builds vulnerable to supply chain attacks. Replace line 1 with the pinned digest to ensure reproducibility:

FROM ubuntu@sha256:adbb90115a21969d2fe6fa7f9af4253e16d45f8d4c1e930182610c4731962658
🧰 Tools
🪛 Checkov (3.2.334)

[low] 1-41: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-41: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🤖 Prompt for AI Agents
In Dockerfile at lines 1-1, the base image uses the floating tag "ubuntu:22.04"
which can lead to non-reproducible builds; replace that line with a pinned image
digest (e.g., FROM
ubuntu@sha256:adbb90115a21969d2fe6fa7f9af4253e16d45f8d4c1e930182610c4731962658)
so the build always pulls the exact same image and update any CI/docs that
reference the unpinned tag.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (4)
Dockerfile (4)

1-1: Pin the base image digest for reproducible builds.

Using the floating tag ubuntu:22.04 allows different image snapshots across rebuilds, breaking reproducibility and introducing supply-chain risks.

Apply this diff to pin the digest:

-FROM ubuntu:22.04
+FROM ubuntu@sha256:adbb90115a21969d2fe6fa7f9af4253e16d45f8d4c1e930182610c4731962658

1-39: Add non-root user to follow least privilege principle.

The container runs as root, violating security best practices and increasing risk if compromised. All operations (git clone, tar, nix commands) can run as a non-root user.

Apply this diff:

 RUN apt-get update \
     && apt-get install -y --no-install-recommends \
     ca-certificates \
     curl \
     git \
     xz-utils \
-    && rm -rf /var/lib/apt/lists/*
+    && rm -rf /var/lib/apt/lists/* \
+    && useradd -m -u 1000 nixuser
 
 ENV NIX_CONFIG="experimental-features = nix-command flakes"
 
 RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
     && . /etc/profile.d/nix.sh \
-    && nix --version
+    && nix --version \
+    && chown -R nixuser:nixuser /nix /app
 
 ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"
 
+USER nixuser
 WORKDIR /app

Ensure the user is set before WORKDIR so all subsequent operations run as nixuser.


1-39: Add HEALTHCHECK for container orchestration.

Without a HEALTHCHECK, orchestration platforms cannot detect unhealthy containers or perform automatic restarts.

Add a HEALTHCHECK appropriate for your pipeline. For a batch job:

 WORKDIR /app
 
+HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
+  CMD test -f /tmp/pipeline-running || exit 1
+
 ENTRYPOINT ["nix", "run", ".#local-db-pipeline"]

Update your pipeline scripts to create /tmp/pipeline-running on start and remove it on completion, or check for process existence.


27-35: Consider consolidating RUN instructions to reduce image layers.

Multiple consecutive RUN statements create unnecessary layers, increasing the final image size—relevant for a "lightweight" image.

Apply this diff to consolidate:

-RUN git clone "$REMOTE_REPO_URL" /app/rain.orderbook
-WORKDIR /app/rain.orderbook
-RUN git checkout "$REMOTE_REPO_COMMIT"
-RUN cp .env.example .env
-RUN git submodule update --init --recursive
-RUN bash ./prep-base.sh
-RUN nix develop -c rainix-ob-cli-artifact
-RUN tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app
-RUN chmod +x /app/rain-orderbook-cli
+WORKDIR /app/rain.orderbook
+RUN set -euo pipefail \
+    && git clone "$REMOTE_REPO_URL" . \
+    && git checkout "$REMOTE_REPO_COMMIT" \
+    && cp .env.example .env \
+    && git submodule update --init --recursive \
+    && bash ./prep-base.sh \
+    && nix develop -c rainix-ob-cli-artifact \
+    && tar -xzf crates/cli/bin/rain-orderbook-cli.tar.gz -C /app \
+    && chmod +x /app/rain-orderbook-cli

Note: Full clone retained because submodules are needed (line 31).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 776f0e8 and 06ccdbb.

📒 Files selected for processing (4)
  • Dockerfile (1 hunks)
  • flake.nix (1 hunks)
  • scripts/cleanup.sh (0 hunks)
  • scripts/sync.sh (1 hunks)
💤 Files with no reviewable changes (1)
  • scripts/cleanup.sh
🧰 Additional context used
🪛 Checkov (3.2.334)
Dockerfile

[low] 1-39: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-39: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)
Dockerfile

[warning] 3-3: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)


[info] 30-30: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 31-31: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 32-32: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 33-33: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 34-34: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 35-35: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

🔇 Additional comments (4)
Dockerfile (2)

24-25: Good use of build arguments for configuration.

The ARG declarations allow customization of the cloned repository and commit while providing sensible defaults.


39-39: ENTRYPOINT uses Nix-managed pipeline—verify operational requirements.

The ENTRYPOINT runs nix run .#local-db-pipeline, which executes the pipeline defined in flake.nix. This leverages Nix for dependency management and is architecturally sound.

However, ensure the operational model is documented:

  • Is this a one-shot job or long-running service?
  • How should orchestrators (Docker Compose, Kubernetes) monitor success/failure?
  • What logs indicate pipeline completion or errors?
scripts/sync.sh (1)

21-21: CLI binary path change verified and consistent throughout codebase.

The transition from rain_orderbook_cli to rain-orderbook-cli is complete and consistent:

  • No stale underscore references remain
  • New hyphenated name appears in all relevant locations: Dockerfile (34-35), scripts/sync.sh (21), scripts/cleanup.sh (14-15), and scripts/download-binary.sh (23, 34)
  • Aligns with Unix naming conventions
flake.nix (1)

54-58: Correct the narrative about removed scripts.

The review comment claims that r2-upload.sh and download-binary.sh were removed, but these scripts still exist in the repository and are actively referenced in scripts/docker-entrypoint.sh:

  • download-binary.sh is called unconditionally on line 12
  • r2-upload.sh is conditionally called on line 24 for the R2 backend

Additionally, the flake.nix pipeline (sync.sh → do-spaces-upload.sh → cleanup.sh) is inconsistent with docker-entrypoint.sh, which includes download-binary.sh and conditionally branches on UPLOAD_BACKEND. Verify whether these execution paths should remain separate or if they need to be aligned.

Likely an incorrect or invalid review comment.

Comment on lines +3 to +9
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
xz-utils \
&& rm -rf /var/lib/apt/lists/*
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

❓ Verification inconclusive

Pin apt package versions for reproducible builds.

Unpinned packages will install different versions on subsequent rebuilds, breaking reproducibility—critical for a production image.

Verify current Ubuntu 22.04 (Jammy) package versions and pin them:

Once verified, update the Dockerfile:

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
    ca-certificates=<version> \
    curl=<version> \
    git=<version> \
    xz-utils=<version> \
    && rm -rf /var/lib/apt/lists/*

🏁 Script executed:

#!/bin/bash
# Description: Fetch exact package versions from Ubuntu 22.04

docker run --rm ubuntu:22.04 bash -c "
  apt-get update -qq && 
  apt-cache policy ca-certificates curl git xz-utils | 
  grep -E 'Candidate:|Installed:' 
"

Length of output: 44


Let me search for the current Ubuntu 22.04 package versions:

Pin apt package versions for reproducible builds.

Unpinned packages install different versions on subsequent rebuilds, breaking reproducibility—critical for production images. Update the Dockerfile with the current Ubuntu 22.04 versions:

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
    ca-certificates=20240203~22.04.1 \
    curl=7.81.0-1ubuntu1.21 \
    git=1:2.34.1-1ubuntu1.15 \
    xz-utils=5.2.5-2ubuntu1 \
    && rm -rf /var/lib/apt/lists/*
🧰 Tools
🪛 Hadolint (2.14.0)

[warning] 3-3: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)

🤖 Prompt for AI Agents
In Dockerfile around lines 3 to 9, the apt-get install invocation uses unpinned
package versions which prevents reproducible builds; update the apt-get install
line to pin each package to the provided Ubuntu 22.04 package versions
(ca-certificates=20240203~22.04.1, curl=7.81.0-1ubuntu1.21,
git=1:2.34.1-1ubuntu1.15, xz-utils=5.2.5-2ubuntu1) while keeping the surrounding
apt-get update and cleanup commands intact so builds install the exact versions.

Comment on lines +13 to +15
RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
&& . /etc/profile.d/nix.sh \
&& nix --version
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Verify Nix installer integrity or use a Nix base image.

The installer is fetched and executed without signature verification, creating a supply-chain vulnerability.

Consider these alternatives:

Option 1 (Recommended for lightweight): Use an official Nix base image:

-FROM ubuntu:22.04
+FROM nixos/nix:2.19.2

-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-    ca-certificates \
-    curl \
-    git \
-    xz-utils \
-    && rm -rf /var/lib/apt/lists/*
-
 ENV NIX_CONFIG="experimental-features = nix-command flakes"
-
-RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
-    && . /etc/profile.d/nix.sh \
-    && nix --version
-
-ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"

Option 2: Pin and verify the installer:

-RUN bash -lc "sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon" \
+RUN curl --proto '=https' --tlsv1.2 -L https://releases.nixos.org/nix/nix-2.19.2/install -o /tmp/nix-install.sh \
+    && echo "<expected-sha256>  /tmp/nix-install.sh" | sha256sum -c - \
+    && bash /tmp/nix-install.sh --daemon --no-channel-add \
     && . /etc/profile.d/nix.sh \
     && nix --version

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In Dockerfile around lines 13 to 15, the Nix installer is fetched and executed
without any integrity or authenticity checks, creating a supply-chain risk;
replace this by either using an official Nix base image (recommended) to avoid
runtime installation, or if you must install at build time, pin the installer
URL and checksum and verify the downloaded archive and its GPG signature before
executing (download installer and signature separately, verify signature against
Nix project keys, check file checksum, then run), and ensure the Dockerfile
fails the build if verification does not succeed.

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.

3 participants