Skip to content

fix: improve prod Docker build (#15)#971

Merged
northdpole merged 2 commits into
mainfrom
fix/15-docker-prod-build
Jul 9, 2026
Merged

fix: improve prod Docker build (#15)#971
northdpole merged 2 commits into
mainfrom
fix/15-docker-prod-build

Conversation

@northdpole

Copy link
Copy Markdown
Collaborator

Summary

  • Add .venv/ to .dockerignore so local Python virtualenvs are not sent to the Docker build context (repo convention uses .venv, not only venv/).
  • Install system chromium in the prod Dockerfile node build stage before yarn install, mirroring PR #641 / Dockerfile-dev. This unblocks puppeteer postinstall on arm64 Linux without affecting amd64 CI (publish.yml runs on ubuntu-latest where both apt chromium and puppeteer's bundled binary are available).

Fixes #15 (build-context and arm64 yarn install portions).

Test plan

  • make docker-prod on arm64/macOS (after freeing Docker VM disk if needed)
  • make docker-prod on linux/amd64 (matches publish.yml)
  • Confirm .venv/ is excluded: docker build context size should not balloon when .venv exists locally

Notes

  • make lintblack passed; yarn lint failed locally due to pre-existing Yarn 4 / lockfile mismatch (unrelated to this diff).
  • Do not merge until CI is green.

Made with Cursor

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Summary by CodeRabbit

  • New Features
    • Improved app startup reliability by automatically applying the latest database updates and filling in a missing metadata field when needed.
  • Bug Fixes
    • Fixed an issue that could affect polling and interval cleanup in the UI.
    • Improved route and response handling for better frontend stability.
  • Chores
    • Updated build and project settings to avoid unnecessary files in packaging and type processing.

Walkthrough

This PR updates Docker build/runtime configuration—installing chromium, excluding .venv, and patching entrypoint migrations and SQLite schema—alongside frontend TypeScript fixes to ref types, an ElementType-based route contract, and minor build/tooling config adjustments in package.json and tsconfig.json.

Changes

Docker Build and Runtime

Layer / File(s) Summary
Dockerfile chromium install and ignore pattern
Dockerfile, .dockerignore
Adds a chromium install step to the build stage and excludes .venv/ in .dockerignore.
Entrypoint migration and SQLite schema patch
scripts/prod-docker-entrypoint.sh
Runs flask db upgrade heads and adds a Python/SQLite block that adds a document_metadata JSON column to cre and node tables if missing.

Frontend Type Corrections and Build Config

Layer / File(s) Summary
Route component type contract
application/frontend/src/routes.tsx
Changes the exported IRoute.component type from ReactNode | ReactNode[] to ElementType and updates the React import accordingly.
Ref and element type fixes
application/frontend/src/pages/Explorer/visuals/force-graph/forceGraph.tsx, application/frontend/src/pages/GapAnalysis/GapAnalysis.tsx, application/frontend/src/pages/chatbot/chatbot.tsx
Updates useRef types for fgRef and timerIdRef to browser-compatible, undefined-safe types with a conditional clearInterval guard, and changes the chatbot's rendered parts accumulator to React.ReactElement[].
Build and dependency config updates
package.json, tsconfig.json
Extends the postinstall script to delete node_modules/@types/minimatch and adds application/frontend/www to the TypeScript exclude list.

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

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Issue #15 calls for a distroless production container, but this PR only improves build/startup behavior and does not introduce a distroless image. Implement the distroless production container work, or update the linked issue if the scope is only Docker build fixes.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and reflects the main focus on production Docker build improvements.
Description check ✅ Passed The description matches the Docker build fixes and related container startup work in the PR.
Out of Scope Changes check ✅ Passed The listed changes all appear to support the production Docker build or runtime startup path.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/15-docker-prod-build

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

application/frontend/src/pages/Explorer/visuals/force-graph/forceGraph.tsx

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

application/frontend/src/pages/GapAnalysis/GapAnalysis.tsx

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

application/frontend/src/pages/chatbot/chatbot.tsx

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

  • 1 others

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.

northdpole and others added 2 commits July 9, 2026 16:29
Exclude .venv/ from build context and install system chromium in the
node build stage (mirrors PR #641) so yarn install succeeds on arm64.

Co-authored-by: Cursor <cursoragent@cursor.com>
Exclude built frontend assets from tsconfig, fix TypeScript errors
surfacing under node:lts, remove broken @types/minimatch stub on install,
and harden prod-docker-entrypoint (alembic heads + document_metadata +
upstream_sync) so the container serves standards data after startup.

Co-authored-by: Cursor <cursoragent@cursor.com>
@northdpole northdpole force-pushed the fix/15-docker-prod-build branch from db5e913 to a6949de Compare July 9, 2026 15:31

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
scripts/prod-docker-entrypoint.sh (1)

5-5: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer $(pwd) over legacy backticks.

Shellcheck flags the use of backticks (SC2006) and recommends declaring and assigning separately to avoid masking return values (SC2155).

♻️ Proposed fix
-export FLASK_APP=`pwd`/cre.py
+FLASK_APP="$(pwd)/cre.py"
+export FLASK_APP
🤖 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 `@scripts/prod-docker-entrypoint.sh` at line 5, The `prod-docker-entrypoint.sh`
setup is using legacy backticks in the `FLASK_APP` assignment, which shellcheck
flags and which can mask command return values. Update the `export
FLASK_APP=...` line to use `$(pwd)` instead of backticks, and keep the
assignment straightforward in the entrypoint script so the `FLASK_APP` value is
set cleanly.

Source: Linters/SAST tools

Dockerfile (1)

4-4: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add --no-install-recommends and clean apt cache to reduce image size.

Without --no-install-recommends, chromium pulls in many recommended packages that bloat the image and increase the attack surface. Cleaning the apt lists afterward prevents them from being baked into the layer.

♻️ Proposed fix
-RUN apt-get update && apt-get install -y chromium
+RUN apt-get update && apt-get install -y --no-install-recommends chromium \
+    && rm -rf /var/lib/apt/lists/*

Source: Linters/SAST tools

application/frontend/src/pages/GapAnalysis/GapAnalysis.tsx (1)

176-178: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider resetting timerIdRef.current to undefined after clearing.

After clearInterval, the ref still holds the stale interval ID. Subsequent stopPolling calls pass the !== undefined guard and call clearInterval on an already-cleared ID (harmless no-op, but misleading). Resetting to undefined keeps the ref's state accurate.

♻️ Suggested refactor
     const stopPolling = () => {
       if (timerIdRef.current !== undefined) {
         clearInterval(timerIdRef.current);
+        timerIdRef.current = undefined;
       }
     };
🤖 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 `@application/frontend/src/pages/GapAnalysis/GapAnalysis.tsx` around lines 176
- 178, In stopPolling, the timerIdRef.current value is left pointing to a
cleared interval ID after clearInterval, so update the GapAnalysis polling
cleanup to reset timerIdRef.current back to undefined immediately after clearing
it. Keep the existing guard, but make the ref state accurately reflect that no
interval is active so repeated stopPolling calls behave consistently.
🤖 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 `@scripts/prod-docker-entrypoint.sh`:
- Around line 7-18: Add a startup failure guard in the prod entrypoint so schema
patching never silently continues on error: the Python block that opens
sqlite3.connect(db_path) and loops over cre/node should first verify each table
exists before calling PRAGMA table_info and ALTER TABLE, and skip or fail
cleanly if it does not. Also add set -e at the top of the script so any failed
migration or Python exception stops startup instead of letting gunicorn launch
with a broken database schema.

---

Nitpick comments:
In `@application/frontend/src/pages/GapAnalysis/GapAnalysis.tsx`:
- Around line 176-178: In stopPolling, the timerIdRef.current value is left
pointing to a cleared interval ID after clearInterval, so update the GapAnalysis
polling cleanup to reset timerIdRef.current back to undefined immediately after
clearing it. Keep the existing guard, but make the ref state accurately reflect
that no interval is active so repeated stopPolling calls behave consistently.

In `@scripts/prod-docker-entrypoint.sh`:
- Line 5: The `prod-docker-entrypoint.sh` setup is using legacy backticks in the
`FLASK_APP` assignment, which shellcheck flags and which can mask command return
values. Update the `export FLASK_APP=...` line to use `$(pwd)` instead of
backticks, and keep the assignment straightforward in the entrypoint script so
the `FLASK_APP` value is set cleanly.
🪄 Autofix (Beta)

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.yml

Review profile: CHILL

Plan: Pro

Run ID: cddaef2c-b0c3-4f56-a85f-43339ec8e01a

📥 Commits

Reviewing files that changed from the base of the PR and between 0dd3823 and a6949de.

📒 Files selected for processing (9)
  • .dockerignore
  • Dockerfile
  • application/frontend/src/pages/Explorer/visuals/force-graph/forceGraph.tsx
  • application/frontend/src/pages/GapAnalysis/GapAnalysis.tsx
  • application/frontend/src/pages/chatbot/chatbot.tsx
  • application/frontend/src/routes.tsx
  • package.json
  • scripts/prod-docker-entrypoint.sh
  • tsconfig.json

Comment on lines +7 to +18
python - <<'PY'
import sqlite3

db_path = "/code/standards_cache.sqlite"
conn = sqlite3.connect(db_path)
for table in ("cre", "node"):
cols = {row[1] for row in conn.execute(f"PRAGMA table_info({table})")}
if "document_metadata" not in cols:
conn.execute(f"ALTER TABLE {table} ADD COLUMN document_metadata JSON")
conn.commit()
conn.close()
PY

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Handle missing tables and add set -e to prevent serving a broken app.

Two stability risks in this block:

  1. If the cre or node tables don't exist in standards_cache.sqlite (e.g., fresh database or flask db upgrade heads failed silently), PRAGMA table_info returns an empty set, "document_metadata" not in cols is True, and ALTER TABLE cre ADD COLUMN ... throws sqlite3.OperationalError: no such table. The exception is unhandled.

  2. The script has no set -e, so both the migration failure (line 6) and the Python crash are silently swallowed — gunicorn starts and serves an app with a broken database schema.

Consider guarding the ALTER TABLE with a table-existence check and adding set -e to the script so migration or schema-patch failures halt startup instead of silently serving a broken app.

🛡️ Proposed fix: guard ALTER TABLE and add set -e
 #! /bin/bash
 
+set -e
+
 export INSECURE_REQUESTS=1
 export FLASK_CONFIG="production"
 export FLASK_APP=`pwd`/cre.py
 flask db upgrade heads
 python - <<'PY'
 import sqlite3
 
 db_path = "/code/standards_cache.sqlite"
 conn = sqlite3.connect(db_path)
 for table in ("cre", "node"):
     cols = {row[1] for row in conn.execute(f"PRAGMA table_info({table})")}
-    if "document_metadata" not in cols:
+    if cols and "document_metadata" not in cols:
         conn.execute(f"ALTER TABLE {table} ADD COLUMN document_metadata JSON")
 conn.commit()
 conn.close()
 PY
🤖 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 `@scripts/prod-docker-entrypoint.sh` around lines 7 - 18, Add a startup failure
guard in the prod entrypoint so schema patching never silently continues on
error: the Python block that opens sqlite3.connect(db_path) and loops over
cre/node should first verify each table exists before calling PRAGMA table_info
and ALTER TABLE, and skip or fail cleanly if it does not. Also add set -e at the
top of the script so any failed migration or Python exception stops startup
instead of letting gunicorn launch with a broken database schema.

@northdpole northdpole merged commit 7d0634e into main Jul 9, 2026
9 checks passed
@northdpole northdpole deleted the fix/15-docker-prod-build branch July 9, 2026 15:39
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.

Create production docker container

1 participant