-
Notifications
You must be signed in to change notification settings - Fork 0
feat: added docker files to all repos and some basic tests #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| node_modules | ||
| .git | ||
| .github | ||
| .next | ||
| dist | ||
| *.md | ||
| !README.md | ||
| .env* | ||
| .turbo | ||
| apps/desktop |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,16 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FROM node:22-slim | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ENV PNPM_HOME="/pnpm" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ENV PATH="$PNPM_HOME:$PATH" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RUN corepack enable && corepack prepare pnpm@9.0.0 --activate | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WORKDIR /app | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| COPY pnpm-lock.yaml pnpm-workspace.yaml package.json turbo.json ./ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| COPY apps/api/ ./apps/api/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| COPY packages/ ./packages/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RUN pnpm install --frozen-lockfile | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RUN pnpm --filter @repo/api build | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ENV NODE_ENV=production | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| USER node | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EXPOSE 8080 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CMD ["node", "apps/api/dist/index.js"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # Check if the package.json file exists and read the build script
if [ -f "apps/api/package.json" ]; then
cat apps/api/package.json | jq '.scripts.build // "Not found"'
else
echo "apps/api/package.json not found"
fiRepository: BuckyMcYolo/townhall Length of output: 127 🌐 Web query:
💡 Result: The node:22-slim Docker image runs as the root user by default. To configure it for non-root operation using the built-in 'node' user (UID 1000), add these steps to your Dockerfile after installing dependencies but before the final CMD/ENTRYPOINT: 1. Change ownership of your application directory to the node user: RUN chown -R node:node /app 2. Switch to the non-root user: USER node Example complete Dockerfile: FROM node:22-slim WORKDIR /app COPY package*.json ./ RUN npm ci --only=production && npm cache clean --force COPY --chown=node:node . . EXPOSE 3000 USER node CMD ["node", "server.js"] This follows official Node Docker best practices for security (principle of least privilege). The entrypoint.sh script supports running as node user. Verify with docker run --rm node:22-slim whoami (outputs 'root') vs. after USER node (outputs 'node'). Key benefits: - Reduces attack surface if compromised - Meets security scanners/compliance requirements - No performance impact Common issues & fixes: - Permission errors on bind mounts: Use --user Citations:
Run API service as non-root in the final image. The Dockerfile lacks a Suggested hardening patch FROM node:22-slim
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable && corepack prepare pnpm@9.0.0 --activate
WORKDIR /app
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json turbo.json ./
COPY apps/api/ ./apps/api/
COPY packages/ ./packages/
RUN pnpm install --frozen-lockfile
RUN pnpm --filter `@repo/api` build
ENV NODE_ENV=production
EXPOSE 8080
+USER node
CMD ["node", "apps/api/dist/index.js"]📝 Committable suggestion
Suggested change
🧰 Tools🪛 Checkov (3.2.510)[low] 1-15: Ensure that HEALTHCHECK instructions have been added to container images (CKV_DOCKER_2) [low] 1-15: Ensure that a user for the container has been created (CKV_DOCKER_3) 🪛 Hadolint (2.14.0)[info] 11-11: Multiple consecutive (DL3059) 🪛 Trivy (0.69.3)[error] 1-1: Image user should not be 'root' Specify at least 1 USER command in Dockerfile with non-root user as argument Rule: DS-0002 (IaC/Dockerfile) [info] 1-1: No HEALTHCHECK defined Add HEALTHCHECK instruction in your Dockerfile Rule: DS-0026 (IaC/Dockerfile) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| import { describe, expect, it } from "vitest" | ||
| import { client } from "./helpers" | ||
|
|
||
| describe("Auth Guard — unauthenticated requests return 401", () => { | ||
| it("GET /v1/allies", async () => { | ||
| const res = await client.v1.allies.$get() | ||
| expect(res.status).toBe(401) | ||
| }) | ||
|
|
||
| it("GET /v1/dms", async () => { | ||
| const res = await client.v1.dms.$get({ | ||
| query: { | ||
| page: 1, | ||
| perPage: 50, | ||
| }, | ||
| }) | ||
| expect(res.status).toBe(401) | ||
| }) | ||
|
|
||
| it("GET /v1/blocks", async () => { | ||
| const res = await client.v1.blocks.$get() | ||
| expect(res.status).toBe(401) | ||
| }) | ||
|
|
||
| it("GET /v1/notification-settings", async () => { | ||
| const res = await client.v1["notification-settings"].$get() | ||
| expect(res.status).toBe(401) | ||
| }) | ||
|
|
||
| it("GET /v1/privacy-settings", async () => { | ||
| const res = await client.v1["privacy-settings"].$get() | ||
| expect(res.status).toBe(401) | ||
| }) | ||
|
|
||
| it("POST /v1/allies/requests", async () => { | ||
| const res = await client.v1.allies.requests.$post({ | ||
| json: { userId: "fake-id" }, | ||
| }) | ||
| expect(res.status).toBe(401) | ||
| }) | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { describe, expect, it } from "vitest" | ||
| import app from "@/app" | ||
|
|
||
| describe("Health Check", () => { | ||
| it("GET / returns 200 with status ok", async () => { | ||
| const res = await app.request("/") | ||
| expect(res.status).toBe(200) | ||
| expect(await res.json()).toEqual({ status: "ok" }) | ||
| }) | ||
|
|
||
| it("GET /unknown returns 404", async () => { | ||
| const res = await app.request("/this-does-not-exist") | ||
| expect(res.status).toBe(404) | ||
| }) | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import type { ClientRequestOptions } from "hono/client" | ||
| import { testClient } from "hono/testing" | ||
| import app, { type AppType } from "@/app" | ||
|
|
||
| /** | ||
| * Typed test client for the Townhall API. | ||
| * Provides autocomplete on routes, params, and response bodies. | ||
| */ | ||
| export const client = testClient<AppType>(app as unknown as AppType) | ||
|
Comment on lines
+3
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify the unsafe cast and app export/type mismatch evidence.
rg -n 'testClient<AppType>\(app as unknown as AppType\)' apps/api/src/__tests__/helpers.ts
rg -n 'const app = createApp\(\)|const routes = app|export type AppType|export default app|export default routes' apps/api/src/app.tsRepository: BuckyMcYolo/townhall Length of output: 299 🏁 Script executed: rg -n "from ['\"]@/app['\"]|from ['\"]./app['\"]" apps/api/src --type ts --type tsxRepository: BuckyMcYolo/townhall Length of output: 91 🏁 Script executed: rg -n "from ['\"]@/app['\"]" apps/api/src -A 1Repository: BuckyMcYolo/townhall Length of output: 399 🏁 Script executed: cat -n apps/api/src/index.tsRepository: BuckyMcYolo/townhall Length of output: 354 🏁 Script executed: cat -n apps/api/src/app.tsRepository: BuckyMcYolo/townhall Length of output: 2700 🏁 Script executed: cat -n apps/api/src/__tests__/health.test.tsRepository: BuckyMcYolo/townhall Length of output: 606 🏁 Script executed: # Check what methods are available on both app and routes
rg -A 5 "const app = createApp" apps/api/src/lib/helpers/app/create-app.ts | head -20Repository: BuckyMcYolo/townhall Length of output: 46 🏁 Script executed: fd create-app apps/api/srcRepository: BuckyMcYolo/townhall Length of output: 106 🏁 Script executed: cat -n apps/api/src/lib/helpers/app/create-app.tsRepository: BuckyMcYolo/townhall Length of output: 1164 🏁 Script executed: # Verify that app and routes are the same Hono instance
# by checking if .route() returns the same instance (fluent API)
rg -n "\.route\(" apps/api/src/app.ts | head -5Repository: BuckyMcYolo/townhall Length of output: 222 🏁 Script executed: # Verify the type relationship: check if changing default export would work
# by confirming that app at line 72 has all routes attached
sed -n '38,72p' apps/api/src/app.tsRepository: BuckyMcYolo/townhall Length of output: 1008 Remove the unsafe double-cast in test client setup. Line 9 ( Fix this by exporting the fully-routed app type from Suggested changes// apps/api/src/app.ts
export type AppType = typeof routes
- export default app
+ export default routes// apps/api/src/__tests__/helpers.ts
- export const client = testClient<AppType>(app as unknown as AppType)
+ export const client = testClient<AppType>(app)// apps/api/src/index.ts (also update references if needed)
- import app from "@/app"
+ import app from "@/app" // Now correctly typed as routed app
- serve({ fetch: app.fetch, port: env.PORT })
+ serve({ fetch: app.fetch, port: env.PORT })// apps/api/src/__tests__/health.test.ts (also update references if needed)
- import app from "@/app"
+ import app from "@/app" // Now correctly typed as routed app🤖 Prompt for AI Agents |
||
| /** | ||
| * Creates request options with a session cookie for authenticated requests. | ||
| * | ||
| * Usage: | ||
| * const res = await client.v1.allies.$get(undefined, withSession(cookie)) | ||
| */ | ||
| export function withSession(sessionCookie: string): ClientRequestOptions { | ||
| return { | ||
| headers: { | ||
| Cookie: sessionCookie, | ||
| }, | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { resolve } from "node:path" | ||
| import { defineConfig } from "vitest/config" | ||
|
|
||
| export default defineConfig({ | ||
| test: { | ||
| environment: "node", | ||
| include: ["src/**/*.test.ts"], | ||
| }, | ||
| resolve: { | ||
| alias: { | ||
| "@": resolve(__dirname, "src"), | ||
| }, | ||
| }, | ||
| }) |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,16 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FROM node:22-slim | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ENV PNPM_HOME="/pnpm" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ENV PATH="$PNPM_HOME:$PATH" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RUN corepack enable && corepack prepare pnpm@9.0.0 --activate | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WORKDIR /app | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| COPY pnpm-lock.yaml pnpm-workspace.yaml package.json turbo.json ./ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| COPY apps/realtime/ ./apps/realtime/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| COPY packages/ ./packages/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RUN pnpm install --frozen-lockfile | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RUN pnpm --filter @repo/realtime build | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ENV NODE_ENV=production | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| USER node | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EXPOSE 8000 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CMD ["node", "apps/realtime/dist/index.js"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial 🧩 Analysis chain🌐 Web query:
💡 Result: The node:22-slim Docker image is based on Debian bookworm-slim and creates a non-root 'node' user (UID 1000, GID 1000) with home directory /home/node. The default entrypoint (docker-entrypoint.sh) switches to this 'node' user if no USER is specified or if running as root, making the effective default user 'node' for running Node.js applications. This follows Docker best practices for security by avoiding root. The slim variant minimizes packages while including essentials for Node.js. To verify locally: docker run --rm node:22-slim whoami # outputs 'node' docker run --rm node:22-slim id # outputs uid=1000(node) gid=1000(node) The Dockerfile (from repo github.com/nodejs/docker-node, 22/bookworm-slim/Dockerfile) includes: RUN groupadd --gid 1000 node && useradd --uid 1000 --gid node --shell /bin/bash --create-home node No explicit USER node at the end, but entrypoint handles the switch: setUserIfNeeded function checks if running as root/PID 1 and su-exec to node if so. Citations:
🏁 Script executed: # Check if there are any other Dockerfiles or container configurations in the repo
find . -name "Dockerfile*" -o -name "*.docker" | head -20Repository: BuckyMcYolo/townhall Length of output: 137 🏁 Script executed: # Look at the actual Dockerfile content and surrounding context
cat -n apps/realtime/DockerfileRepository: BuckyMcYolo/townhall Length of output: 598 🏁 Script executed: # Check the other Dockerfiles to see if there's a pattern
for dockerfile in ./apps/api/Dockerfile ./apps/worker/Dockerfile; do
echo "=== $dockerfile ==="
cat -n "$dockerfile"
doneRepository: BuckyMcYolo/townhall Length of output: 1149 Explicitly run as non-root user for clarity and consistent file permissions. The Suggested improvement FROM node:22-slim
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable && corepack prepare pnpm@9.0.0 --activate
WORKDIR /app
-COPY pnpm-lock.yaml pnpm-workspace.yaml package.json turbo.json ./
-COPY apps/realtime/ ./apps/realtime/
-COPY packages/ ./packages/
+COPY --chown=node:node pnpm-lock.yaml pnpm-workspace.yaml package.json turbo.json ./
+COPY --chown=node:node apps/realtime/ ./apps/realtime/
+COPY --chown=node:node packages/ ./packages/
RUN pnpm install --frozen-lockfile
RUN pnpm --filter `@repo/realtime` build
ENV NODE_ENV=production
EXPOSE 8000
+USER node
CMD ["node", "apps/realtime/dist/index.js"]📝 Committable suggestion
Suggested change
🧰 Tools🪛 Checkov (3.2.510)[low] 1-15: Ensure that HEALTHCHECK instructions have been added to container images (CKV_DOCKER_2) [low] 1-15: Ensure that a user for the container has been created (CKV_DOCKER_3) 🪛 Hadolint (2.14.0)[info] 11-11: Multiple consecutive (DL3059) 🪛 Trivy (0.69.3)[error] 1-1: Image user should not be 'root' Specify at least 1 USER command in Dockerfile with non-root user as argument Rule: DS-0002 (IaC/Dockerfile) [info] 1-1: No HEALTHCHECK defined Add HEALTHCHECK instruction in your Dockerfile Rule: DS-0026 (IaC/Dockerfile) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| FROM node:22-slim | ||
| ENV PNPM_HOME="/pnpm" | ||
| ENV PATH="$PNPM_HOME:$PATH" | ||
| RUN corepack enable && corepack prepare pnpm@9.0.0 --activate | ||
|
|
||
| WORKDIR /app | ||
| COPY pnpm-lock.yaml pnpm-workspace.yaml package.json turbo.json ./ | ||
| COPY apps/worker/ ./apps/worker/ | ||
| COPY packages/ ./packages/ | ||
| RUN pnpm install --frozen-lockfile | ||
| RUN pnpm --filter @repo/worker build | ||
|
|
||
| ENV NODE_ENV=production | ||
| USER node | ||
| CMD ["node", "apps/worker/dist/index.js"] | ||
|
Comment on lines
+1
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # Check the actual Dockerfile content
find . -name "Dockerfile" -path "*/worker/*" | head -20Repository: BuckyMcYolo/townhall Length of output: 88 🏁 Script executed: # Also search for realtime and api Dockerfiles mentioned in the comment
find . -name "Dockerfile" | grep -E "(realtime|api)" | head -20Repository: BuckyMcYolo/townhall Length of output: 112 🌐 Web query:
💡 Result: The official node:22-slim Docker image includes a non-root 'node' user (UID 1000, GID 1000) by default, created in its Dockerfile. It does not run as this user by default (runs as root), but documentation recommends switching to it for security following the principle of least privilege. To run as non-root user: 1. In docker-compose.yml: services: node: image: node:22-slim user: "node" working_dir: /home/node/app ... 2. In docker run: docker run -it --rm -u node -v "$PWD":/home/node/app node:22-slim node app.js 3. In Dockerfile: FROM node:22-slim ... USER node CMD ["node", "app.js"] For mounted volumes, ensure permissions allow the node user access, e.g., chown node:node /path on host or use --user Citations:
🏁 Script executed: # Read the worker Dockerfile to verify current state
cat -n ./apps/worker/DockerfileRepository: BuckyMcYolo/townhall Length of output: 571 🏁 Script executed: # Check the api Dockerfile
cat -n ./apps/api/DockerfileRepository: BuckyMcYolo/townhall Length of output: 578 🏁 Script executed: # Check the realtime Dockerfile
cat -n ./apps/realtime/DockerfileRepository: BuckyMcYolo/townhall Length of output: 598 Drop root privileges in the worker image. Lines 1–14 do not declare Suggested hardening patch FROM node:22-slim
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable && corepack prepare pnpm@9.0.0 --activate
WORKDIR /app
-COPY pnpm-lock.yaml pnpm-workspace.yaml package.json turbo.json ./
-COPY apps/worker/ ./apps/worker/
-COPY packages/ ./packages/
+COPY --chown=node:node pnpm-lock.yaml pnpm-workspace.yaml package.json turbo.json ./
+COPY --chown=node:node apps/worker/ ./apps/worker/
+COPY --chown=node:node packages/ ./packages/
RUN pnpm install --frozen-lockfile
RUN pnpm --filter `@repo/worker` build
ENV NODE_ENV=production
+USER node
CMD ["node", "apps/worker/dist/index.js"]🧰 Tools🪛 Checkov (3.2.510)[low] 1-14: Ensure that HEALTHCHECK instructions have been added to container images (CKV_DOCKER_2) [low] 1-14: Ensure that a user for the container has been created (CKV_DOCKER_3) 🪛 Hadolint (2.14.0)[info] 11-11: Multiple consecutive (DL3059) 🪛 Trivy (0.69.3)[error] 1-1: Image user should not be 'root' Specify at least 1 USER command in Dockerfile with non-root user as argument Rule: DS-0002 (IaC/Dockerfile) [info] 1-1: No HEALTHCHECK defined Add HEALTHCHECK instruction in your Dockerfile Rule: DS-0026 (IaC/Dockerfile) 🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| services: | ||
| postgres: | ||
| image: postgres:16-alpine | ||
| restart: unless-stopped | ||
| environment: | ||
| POSTGRES_USER: townhall | ||
| POSTGRES_PASSWORD: townhall | ||
| POSTGRES_DB: townhall | ||
|
Comment on lines
+6
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid embedding database credentials directly in committed compose config. Lines 6-8 and Lines 32/58/82 hardcode credentials ( Suggested refactor postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
- POSTGRES_USER: townhall
- POSTGRES_PASSWORD: townhall
- POSTGRES_DB: townhall
+ POSTGRES_USER: ${POSTGRES_USER:-townhall}
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-townhall}
+ POSTGRES_DB: ${POSTGRES_DB:-townhall}
@@
- DATABASE_URL: postgresql://townhall:townhall@postgres:5432/townhall
+ DATABASE_URL: postgresql://${POSTGRES_USER:-townhall}:${POSTGRES_PASSWORD:-townhall}@postgres:5432/${POSTGRES_DB:-townhall}
@@
- DATABASE_URL: postgresql://townhall:townhall@postgres:5432/townhall
+ DATABASE_URL: postgresql://${POSTGRES_USER:-townhall}:${POSTGRES_PASSWORD:-townhall}@postgres:5432/${POSTGRES_DB:-townhall}
@@
- DATABASE_URL: postgresql://townhall:townhall@postgres:5432/townhall
+ DATABASE_URL: postgresql://${POSTGRES_USER:-townhall}:${POSTGRES_PASSWORD:-townhall}@postgres:5432/${POSTGRES_DB:-townhall}Also applies to: 32-33, 58-59, 82-83 🤖 Prompt for AI Agents |
||
| ports: | ||
| - "5432:5432" | ||
| volumes: | ||
| - postgres_data:/var/lib/postgresql/data | ||
| healthcheck: | ||
| test: ["CMD-SHELL", "pg_isready -U townhall"] | ||
| interval: 5s | ||
| timeout: 3s | ||
| retries: 5 | ||
|
|
||
| redis: | ||
| image: redis:7-alpine | ||
| restart: unless-stopped | ||
| ports: | ||
| - "6379:6379" | ||
| volumes: | ||
| - redis_data:/data | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| healthcheck: | ||
| test: ["CMD", "redis-cli", "ping"] | ||
| interval: 5s | ||
| timeout: 3s | ||
| retries: 5 | ||
|
|
||
| api: | ||
| build: | ||
| context: . | ||
| dockerfile: apps/api/Dockerfile | ||
| restart: unless-stopped | ||
| ports: | ||
| - "8080:8080" | ||
| environment: | ||
| NODE_ENV: production | ||
| PORT: 8080 | ||
| DATABASE_URL: postgresql://townhall:townhall@postgres:5432/townhall | ||
| REDIS_URL: redis://redis:6379 | ||
| BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET} | ||
| NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8080} | ||
| S3_ENDPOINT: ${S3_ENDPOINT} | ||
| S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID} | ||
| S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY} | ||
| S3_BUCKET_NAME: ${S3_BUCKET_NAME} | ||
| S3_REGION: ${S3_REGION:-auto} | ||
| S3_PUBLIC_URL: ${S3_PUBLIC_URL} | ||
| RESEND_API_KEY: ${RESEND_API_KEY} | ||
|
Comment on lines
+44
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Fail fast when required secrets are missing. At Line 34 (and similarly Lines 36-42, 60-69, 85-92), Suggested strict env interpolation- BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}
+ BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:?BETTER_AUTH_SECRET is required}
@@
- S3_ENDPOINT: ${S3_ENDPOINT}
+ S3_ENDPOINT: ${S3_ENDPOINT:?S3_ENDPOINT is required}
- S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID}
+ S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID:?S3_ACCESS_KEY_ID is required}
- S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY}
+ S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY:?S3_SECRET_ACCESS_KEY is required}
- S3_BUCKET_NAME: ${S3_BUCKET_NAME}
+ S3_BUCKET_NAME: ${S3_BUCKET_NAME:?S3_BUCKET_NAME is required}
- S3_PUBLIC_URL: ${S3_PUBLIC_URL}
+ S3_PUBLIC_URL: ${S3_PUBLIC_URL:?S3_PUBLIC_URL is required}
- RESEND_API_KEY: ${RESEND_API_KEY}
+ RESEND_API_KEY: ${RESEND_API_KEY:?RESEND_API_KEY is required}Apply the same pattern for Also applies to: 60-69, 85-92 🤖 Prompt for AI Agents |
||
| EMAIL_FROM: ${EMAIL_FROM:-Townhall <noreply@team.townhall.chat>} | ||
| depends_on: | ||
| postgres: | ||
| condition: service_healthy | ||
| redis: | ||
| condition: service_healthy | ||
|
|
||
| realtime: | ||
| build: | ||
| context: . | ||
| dockerfile: apps/realtime/Dockerfile | ||
| restart: unless-stopped | ||
| ports: | ||
| - "8000:8000" | ||
| environment: | ||
| NODE_ENV: production | ||
| REALTIME_PORT: 8000 | ||
| DATABASE_URL: postgresql://townhall:townhall@postgres:5432/townhall | ||
| REDIS_URL: redis://redis:6379 | ||
| BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET} | ||
| NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8080} | ||
| REALTIME_CORS_ORIGIN: ${REALTIME_CORS_ORIGIN:-http://localhost:3000,http://localhost:3001} | ||
| S3_ENDPOINT: ${S3_ENDPOINT} | ||
| S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID} | ||
| S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY} | ||
| S3_BUCKET_NAME: ${S3_BUCKET_NAME} | ||
| S3_REGION: ${S3_REGION:-auto} | ||
| S3_PUBLIC_URL: ${S3_PUBLIC_URL} | ||
| RESEND_API_KEY: ${RESEND_API_KEY} | ||
| EMAIL_FROM: ${EMAIL_FROM:-Townhall <noreply@team.townhall.chat>} | ||
| depends_on: | ||
| postgres: | ||
| condition: service_healthy | ||
| redis: | ||
| condition: service_healthy | ||
|
|
||
| worker: | ||
| build: | ||
| context: . | ||
| dockerfile: apps/worker/Dockerfile | ||
| restart: unless-stopped | ||
| environment: | ||
| NODE_ENV: production | ||
| DATABASE_URL: postgresql://townhall:townhall@postgres:5432/townhall | ||
| REDIS_URL: redis://redis:6379 | ||
| NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8080} | ||
| S3_ENDPOINT: ${S3_ENDPOINT} | ||
| S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID} | ||
| S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY} | ||
| S3_BUCKET_NAME: ${S3_BUCKET_NAME} | ||
| S3_REGION: ${S3_REGION:-auto} | ||
| S3_PUBLIC_URL: ${S3_PUBLIC_URL} | ||
| BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET} | ||
| RESEND_API_KEY: ${RESEND_API_KEY} | ||
| EMAIL_FROM: ${EMAIL_FROM:-Townhall <noreply@team.townhall.chat>} | ||
| depends_on: | ||
| postgres: | ||
| condition: service_healthy | ||
| redis: | ||
| condition: service_healthy | ||
|
|
||
| volumes: | ||
| postgres_data: | ||
| redis_data: | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: BuckyMcYolo/townhall
Length of output: 153
Fix the build script in
apps/api/package.jsonto usetsc && tsc-aliasinstead oftsup && tsc.Line 11 calls
pnpm --filter@repo/apibuild, which currently executestsup && tsc --declaration --emitDeclarationOnly --outDir dist. This violates the required API compile contract: the build must usetsc && tsc-alias(no bundler) to properly resolve workspace dependencies via pnpm linking and ensure correct runtime import paths.🧰 Tools
🪛 Hadolint (2.14.0)
[info] 11-11: Multiple consecutive
RUNinstructions. Consider consolidation.(DL3059)
🤖 Prompt for AI Agents