Skip to content

feat(deploy): Dockerfile + nginx for Bunnyshell ephemeral env - #4125

Open
rvignesh89 wants to merge 1 commit into
masterfrom
bunnyshell
Open

rvignesh89 wants to merge 1 commit into
masterfrom
bunnyshell

Conversation

@rvignesh89

@rvignesh89 rvignesh89 commented Aug 9, 2026 •

Copy link
Copy Markdown
Contributor

Container build for the staff console so it can run as a component of a Bunnyshell ephemeral environment. Orchestrated by bunnyshell.yaml in the backend repo (glific#5524).

What's included

  • Dockerfile — multi-stage Vite build; VITE_GLIFIC_BACKEND_URL build arg (bare backend hostname; config/index.ts derives the /api + /socket URLs)
  • nginx.conf — single-page-app serving
  • .dockerignore

Infra only — no application code changes.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added Docker support for building and running the staff console.
    • Added production serving through Nginx on port 80.
    • Enabled single-page application routing with fallback navigation.
    • Added configurable backend and application environment settings during builds.
  • Chores

    • Excluded dependencies, build artifacts, environment files, logs, and development metadata from Docker build contexts.

Container build for the staff console so it can run as a component of a
Bunnyshell environment (orchestrated by glific/bunnyshell.yaml):

- Dockerfile — multi-stage Vite build; VITE_GLIFIC_BACKEND_URL build arg
  (bare backend hostname; config/index.ts derives /api + /socket URLs)
- nginx.conf — single-page-app serving
- .dockerignore

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DnEEUjf5kpVzsmQbbdkZpd
@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The change adds Docker build-context exclusions, a multi-stage Dockerfile, and an Nginx configuration. The build stage installs dependencies with Yarn, generates flow-editor assets, and runs the Vite build with configurable environment variables. The runtime stage serves the generated files on port 80. Nginx provides SPA fallback routing and disables caching for /index.html.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

A rabbit packs the app just right,
Leaves logs and secrets out of sight.
Yarn hops, Vite gleams,
Nginx serves dreams,
SPA paths now land just right.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the Docker and Nginx deployment support for Bunnyshell ephemeral environments.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bunnyshell

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

❤️ Share

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

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

@github-actions
github-actions Bot temporarily deployed to pull request August 9, 2026 02:49 Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Dockerfile`:
- Around line 13-22: Update the Docker build-argument flow around
VITE_GLIFIC_BACKEND_URL so the caller passes the required bare backend hostname
instead of leaving it empty; align the relevant buildspec argument names with
this Dockerfile declaration. Before removing or changing VITE_GLIFIC_API,
VITE_WEB_SOCKET, or VITE_FLOW_EDITOR_API, verify that no other build path
consumes them, and preserve any still-required arguments.
- Around line 33-37: Update the runtime stage based on nginx:1.27-alpine to run
as a non-root user, preferably by using nginxinc/nginx-unprivileged. Ensure
nginx.conf listens on port 8080, and keep the EXPOSE declaration and Bunnyshell
service target aligned with that port.

In `@nginx.conf`:
- Around line 12-14: Update the Cache-Control value in the `/index.html`
location block to `no-store` if the documented policy requires preventing caches
from storing the response; otherwise retain `no-cache` and align the
documentation with that revalidation-only behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c202cb9c-ac1e-4ac8-84d8-e3280df0ff49

📥 Commits

Reviewing files that changed from the base of the PR and between c90293f and ad43b10.

📒 Files selected for processing (3)
  • .dockerignore
  • Dockerfile
  • nginx.conf

Comment thread Dockerfile
Comment on lines +13 to +22
ARG VITE_GLIFIC_BACKEND_URL
# Leave prefix/port empty: when VITE_GLIFIC_BACKEND_URL is set, config/index.ts uses the
# host verbatim over https:443, so an "api." prefix or :4001 port would break the URL.
ARG VITE_API_PREFIX=""
ARG VITE_GLIFIC_API_PORT=""
ARG VITE_APPLICATION_NAME="Glific: Two way communication platform"
ENV VITE_GLIFIC_BACKEND_URL=$VITE_GLIFIC_BACKEND_URL \
VITE_API_PREFIX=$VITE_API_PREFIX \
VITE_GLIFIC_API_PORT=$VITE_GLIFIC_API_PORT \
VITE_APPLICATION_NAME=$VITE_APPLICATION_NAME

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Align the Docker build arguments with the existing build path.

buildspec.yml.sample passes VITE_GLIFIC_API, VITE_WEB_SOCKET, and VITE_FLOW_EDITOR_API on Lines 14-19. This Dockerfile declares none of those arguments. Therefore, VITE_GLIFIC_BACKEND_URL remains empty when that build path is used.

src/config/index.ts then falls back to window.location.hostname. Deployments with a separate backend can send API and socket requests to the staff-console host.

Update the caller and pass VITE_GLIFIC_BACKEND_URL as the required bare backend hostname. Remove or update the legacy arguments only after confirming that no other build path consumes them.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Dockerfile` around lines 13 - 22, Update the Docker build-argument flow
around VITE_GLIFIC_BACKEND_URL so the caller passes the required bare backend
hostname instead of leaving it empty; align the relevant buildspec argument
names with this Dockerfile declaration. Before removing or changing
VITE_GLIFIC_API, VITE_WEB_SOCKET, or VITE_FLOW_EDITOR_API, verify that no other
build path consumes them, and preserve any still-required arguments.

Comment thread Dockerfile
Comment on lines +33 to +37
FROM nginx:1.27-alpine AS runtime
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env sh
set -eu
docker run --rm --entrypoint id nginx:1.27-alpine -u

Repository: glific/glific-frontend

Length of output: 204


🌐 Web query:

nginxinc docker-nginx 1.27 alpine Dockerfile USER nginx non-root port 80

💡 Result:

Running the official NGINX Docker image (e.g., nginx:1.27-alpine) as a non-root user and attempting to bind to port 80 will fail because ports numbered 1–1024 are privileged; a non-root user does not have permission to bind to them [1][2]. If your goal is to run NGINX in a container without root privileges, you have two primary options: 1. Use the official unprivileged NGINX image: The NGINX maintainers provide a dedicated image, nginxinc/nginx-unprivileged, which is preconfigured to run as a non-root user [3][4][2]. This image listens on port 8080 by default (avoiding the need for root privileges), has the NGINX user directive removed, and moves the PID file and temporary paths to writable locations like /tmp [3][4][2]. You should update your Dockerfile or compose file to use this image and map your host port to 8080 instead of 80 [4][2]. 2. Configure the official NGINX image manually: If you must use the standard official NGINX image, you cannot simply add a USER instruction in your Dockerfile to switch to the nginx user [2]. To make it work, you must: * Change the listening port in your NGINX configuration (e.g., server { listen 8080; }) to a value above 1024 [1][2]. * Modify your nginx.conf to redirect the PID file and all temporary path directives (such as client_body_temp_path, proxy_temp_path, etc.) to directories that the non-root user has write access to, such as /tmp [5][6][2]. * Ensure the container is started with a user that has the necessary permissions for the configured directories [5][2]. In summary, for production hardening or strict security requirements, using the nginxinc/nginx-unprivileged image is the recommended best practice as it significantly reduces the configuration overhead required to safely run NGINX without root access [3][2].

Citations:


🌐 Web query:

nginxinc docker-nginx 1.27 alpine Dockerfile USER nginx 1.27-alpine group nginx

💡 Result:

In the official nginx:1.27-alpine Docker image, a system user and group named "nginx" are created during the build process [1][2][3]. The Dockerfile explicitly executes the following command to set this up: addgroup -g 101 -S nginx && adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx [1][2][3] However, the Docker image does not contain a USER instruction (e.g., USER nginx). Consequently, the container starts by default as the root user [4][5]. While the container runs as root, the NGINX worker processes are designed to drop privileges and run as the "nginx" user (UID 101, GID 101) [4][5]. If you wish to run the entire container process as a non-root user, you must add a USER instruction to your own Dockerfile derived from this image or use Docker's built-in options to specify a user at runtime [4][5]. Note that simply changing the user requires you to ensure that the user has the necessary permissions for the directories NGINX uses (such as logs, cache, and PID files), which may require adjusting your NGINX configuration [4][5].

Citations:


Run the runtime image as a non-root user.

nginx:1.27-alpine creates the nginx user but does not set USER, so this stage starts as root and the master process retains elevated privileges. Use nginxinc/nginx-unprivileged for a preconfigured unprivileged image, or switch to a non-root user with writable PID, cache, and temp directories and move the listen port above 1024. If the non-root setup listens on port 8080, update nginx.conf, EXPOSE, and the Bunnyshell service target together.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Dockerfile` around lines 33 - 37, Update the runtime stage based on
nginx:1.27-alpine to run as a non-root user, preferably by using
nginxinc/nginx-unprivileged. Ensure nginx.conf listens on port 8080, and keep
the EXPOSE declaration and Bunnyshell service target aligned with that port.

Source: Linters/SAST tools

Comment thread nginx.conf
Comment on lines +12 to +14
location = /index.html {
add_header Cache-Control "no-cache";
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | sed -n '1,120p'

echo "== nginx.conf present and relevant lines =="
if git ls-files | grep -qx 'nginx.conf'; then
  nl -ba nginx.conf | sed -n '1,80p'
else
  fd -a 'nginx.conf$' .
fi

echo "== search for PR/cache statements =="
rg -n -i 'caching|cache|cache control|Cache-Control|no-store|no-cache|index.html|disabled|disable' . -g '!*.lock' -g '!node_modules' | sed -n '1,200p'

Repository: glific/glific-frontend

Length of output: 23798


🌐 Web query:

MDN Cache-Control no-cache storage allowed revalidation no-store not stored

💡 Result:

The no-cache and no-store directives serve distinct purposes in HTTP caching, and they are often misunderstood [1][2]. no-cache The no-cache directive indicates that a response can be stored in caches, but it cannot be reused to satisfy subsequent requests without first being validated with the origin server [3][4][5]. It does not mean "do not cache" [3][6]. When a cache has a no-cache response, it must send a conditional request (using headers like If-None-Match or If-Modified-Since) to the origin [1][2][7]. If the origin confirms the content is still valid (e.g., returning a 304 Not Modified status), the cache can then serve the stored response [1][7][8]. no-store The no-store directive is the mechanism to prevent caching entirely [3][6]. It instructs caches (both private and shared) not to store any part of the request or the corresponding response [3][4][9]. It requires that no information be intentionally kept in non-volatile storage, and caches should make a best-effort attempt to remove the information from volatile storage as soon as possible after forwarding it [9][5]. In summary, no-cache permits storage but mandates revalidation before use, while no-store prohibits storage altogether [1][2]. For sensitive data, such as personal or financial information, no-store is the appropriate choice [1][2][7].

Citations:


Use no-store if /index.html must not be cached.

Cache-Control: no-cache permits caches to store the response and only requires revalidation before reuse. If the intended policy is to disable caching storage, use no-store; otherwise keep no-cache but align it with the documented policy.

Proposed cache policy
-        add_header Cache-Control "no-cache";
+        add_header Cache-Control "no-store";
📝 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
location = /index.html {
add_header Cache-Control "no-cache";
}
location = /index.html {
add_header Cache-Control "no-store";
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nginx.conf` around lines 12 - 14, Update the Cache-Control value in the
`/index.html` location block to `no-store` if the documented policy requires
preventing caches from storing the response; otherwise retain `no-cache` and
align the documentation with that revalidation-only behavior.

@codecov

codecov Bot commented Aug 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.20%. Comparing base (245df27) to head (ad43b10).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #4125   +/-   ##
=======================================
  Coverage   82.19%   82.20%           
=======================================
  Files         346      346           
  Lines       15119    15119           
  Branches     3582     3582           
=======================================
+ Hits        12427    12428    +1     
+ Misses       1634     1633    -1     
  Partials     1058     1058           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cypress

cypress Bot commented Aug 9, 2026

Copy link
Copy Markdown

Glific    Run #13435

Run Properties:  status check passed Passed #13435  •  git commit 9a926b7586 ℹ️: Merge ad43b10e10f78e2aa7d9cb9a91b63702c41c0e80 into c90293f14861762a138cbd4297e5...
Project Glific
Branch Review bunnyshell
Run status status check passed Passed #13435
Run duration 07m 25s
Commit git commit 9a926b7586 ℹ️: Merge ad43b10e10f78e2aa7d9cb9a91b63702c41c0e80 into c90293f14861762a138cbd4297e5...
Committer Vignesh Rajasekaran
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 32
⚠️ You've recorded test results over your free plan limit.
Upgrade your plan to view test results.
View all changes introduced in this branch ↗︎

This branch was previously deployed

1 inactive deployment
pull request — ad43b10e Deployed Aug 9, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant