Skip to content

Optimize container size#2245

Open
RamRamez wants to merge 7 commits intostagingfrom
test-container-size
Open

Optimize container size#2245
RamRamez wants to merge 7 commits intostagingfrom
test-container-size

Conversation

@RamRamez
Copy link
Member

@RamRamez RamRamez commented Oct 25, 2025

Summary by CodeRabbit

  • Chores
    • Optimized container build and security; added Docker ignore to exclude dev artifacts
    • CI/CD update: publishing now runs for pull requests as well; deployment restricted to push events
    • Dependency updates and migration script adjustments; TypeScript build settings tuned
  • New Features
    • Expanded admin interface with additional management tabs
  • Refactor
    • Removed built-in HTML→PDF generation utility
  • Tests
    • Consolidated test helpers into shared utilities

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 25, 2025

Walkthrough

Added a .dockerignore; rewrote Dockerfile as a two-stage, non-root build; swapped bcrypt→bcryptjs across code and tests; removed HTML-to-PDF generation; added utility functions for random Ethereum addresses; updated TypeScript/build settings and package dependencies; adjusted CI gating and admin/Redis adminjs session prefixing.

Changes

Cohort / File(s) Summary
Docker build & context
Dockerfile, .dockerignore
Added .dockerignore; Dockerfile converted to multi-stage builder+production, consolidated apk/npm layers, runs build+prune, creates non-root nodejs user, uses --chown on copies, and sets NODE_ENV=production.
CI/CD workflow
.github/workflows/staging-pipeline.yml
publish job no longer gated to push-only (runs on push and pull_request); image tag changed to use ${{ github.sha }}; deploy job gated to run only on push.
Password hashing swap
package.json, migration/*createTestAdminUser*.ts, migration/*create_some_test_admi_users.ts, src/services/userService.ts, src/server/adminJs/tabs/usersTab.ts, src/services/userService.test.ts, README.md
Replaced bcrypt with bcryptjs in dependencies and imports; README example updated accordingly.
PDF generation removal
src/utils/documents.ts
Removed generatePDFDocument and HTML-to-PDF conversion flow; retained HTML generation and base64→IPFS image inlining.
TypeScript / build config & migrations
tsconfig.json, package.json, src/ormconfig.ts
Disabled declaration/sourceMap, expanded exclude for tests, updated deps (removed html-pdf-node, added/updated pg, redis, ioredis, typeorm, typescript), and made migrations path environment-aware (JS in production, TS otherwise). Migration npm scripts updated to reference built path.
Utils & tests refactor
src/utils/utils.ts, test/testUtils.ts, src/adapters/chainvine/chainvineMockAdapter.ts, migration/*
Added generateRandomEtheriumAddress and generateHexNumber to src/utils/utils.ts; removed their test-local implementations and updated imports in tests and adapters.
ORM / Redis config
src/orm.ts, src/ormconfig.ts
Switched cache client config to ioredis usage, expanded redis options (host, port, password, family:4, db:1); ormconfig migrations selection becomes env-aware.
AdminJS changes
src/server/adminJs/adminJs.ts
Reordered imports, added many admin tabs, and added prefix: 'adminjs:' to Redis session store configuration.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer (push/PR)
    participant GH as GitHub Actions
    participant Builder as Docker builder stage
    participant Prod as Docker production stage
    participant Reg as Container registry

    Dev->>GH: push or pull_request
    GH->>Builder: build job (npm ci, compile, npm run build && prune)
    Builder-->>Prod: COPY --from=builder (with --chown)
    Prod->>Reg: push image tagged with sha
    Note right of GH: publish runs on push & PR\ndeploy runs only on push
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to Dockerfile ownership/--chown and non-root user UID/GID correctness.
  • Verify that pruning devDependencies doesn't remove needed runtime deps and that copied paths match runtime expectations.
  • Confirm bcrypt→bcryptjs replacement has no subtle API differences in all call sites (migrations, tests, services).
  • Ensure removal of PDF generator has no remaining callers at runtime.
  • Check migrations path changes and updated migration scripts for CI/production correctness.

Possibly related PRs

Suggested labels

Code Review

Suggested reviewers

  • CarlosQ96
  • kkatusic

Poem

🐇 I hopped through code and swapped a salted key,
Pruned dev modules, chowned files with glee,
CI listens now to PR and push,
PDFs tucked away — tests find helpers hush,
Tiny paws drum — a tidier tree for me 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Optimize container size" directly relates to the primary changes in the pull request. The changeset includes significant container optimization efforts: a new .dockerignore file to exclude unnecessary artifacts, a substantially updated Dockerfile using a lighter base image (node:22-alpine), multi-stage builds, consolidation of RUN layers, and removal of devDependencies after build. The PR also replaces bcrypt with bcryptjs (a pure JavaScript alternative), removes the html-pdf-node dependency and associated PDF generation functionality, and updates various configurations—all changes that contribute to reducing the final container image size. While the PR includes some supporting infrastructure changes (import reorganization, utility migrations, CI/CD adjustments), these are in service of the stated objective and do not contradict the title.
✨ 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 test-container-size

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d88880f and 5f85f64.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • Dockerfile (2 hunks)
  • package.json (6 hunks)
  • src/orm.ts (1 hunks)
  • src/server/adminJs/adminJs.ts (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: publish
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
src/orm.ts (1)

49-56: LGTM: Redis cache configuration correctly updated for ioredis.

The cache type correctly changed to 'ioredis' and connection options are now explicit with family: 4 to force IPv4, which prevents potential IPv6 connection issues. This aligns with the ioredis ^5.8.2 upgrade in package.json.

src/server/adminJs/adminJs.ts (2)

72-75: LGTM: AdminJS session prefix improves Redis key isolation.

Adding prefix: 'adminjs:' to the RedisStore ensures AdminJS sessions are namespaced, preventing key collisions with other Redis-backed stores in the application.


105-108: LGTM: Session prefix consistently applied.

The session store in getCurrentAdminJsSession correctly uses the same 'adminjs:' prefix as the main router, ensuring consistent session key lookups.


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 and usage tips.

Copy link
Contributor

@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: 0

🧹 Nitpick comments (1)
Dockerfile (1)

36-36: Verify whether the patches folder is needed in the production stage.

The patches folder is copied to production (line 36) but is typically only required during the build process (in the builder stage). Confirm whether patches are applied at runtime or if this copy can be removed to further reduce the final image size.

If patches are not applied at runtime, remove line 36 from the production stage:

 # Copy package files and install only production dependencies
 COPY package*.json ./
-COPY patches ./patches

 RUN npm ci --omit=dev
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 37e1a3d and 1d63d26.

📒 Files selected for processing (3)
  • .dockerignore (1 hunks)
  • .github/workflows/staging-pipeline.yml (0 hunks)
  • Dockerfile (2 hunks)
💤 Files with no reviewable changes (1)
  • .github/workflows/staging-pipeline.yml
🔇 Additional comments (4)
.dockerignore (1)

1-24: Well-structured exclusion patterns for reduced build context.

The .dockerignore file appropriately excludes development artifacts, CI/CD configurations, IDE settings, and build outputs, which aligns with the multi-stage Docker build optimization. This reduces the build context size and accelerates Docker builds.

Dockerfile (3)

3-27: Multi-stage build effectively reduces final image size; layer consolidation is well-executed.

The refactor from single-stage to multi-stage build is the right approach for this PR objective. Builder dependencies (alpine-sdk, python3, ts-node, chromium) are correctly isolated to the builder stage and not included in the final image. Consolidating RUN commands (lines 12–18) also reduces layer bloat, and the use of npm ci --omit=dev (line 38) ensures only production dependencies are installed.

Also applies to: 30-49


44-49: Non-root user implementation is correct and improves security.

The addition of a dedicated non-root user (nodejs, UID 1001) with proper directory ownership and the switch to that user at runtime (line 49) follows Docker security best practices.


1-49: Verification confirmed: Entry point is properly defined.

The official node:20.11.0-alpine3.18 base image provides both an ENTRYPOINT and a default CMD. Additionally, the docker-compose configurations (production, staging, and local) all explicitly override the command with application-specific entry points (e.g., npm run start:docker:server). The container will function correctly whether run through docker-compose or directly from the base image.

Copy link
Contributor

@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: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d63d26 and a3a0c5b.

📒 Files selected for processing (2)
  • .github/workflows/staging-pipeline.yml (1 hunks)
  • Dockerfile (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/staging-pipeline.yml
🔇 Additional comments (4)
Dockerfile (4)

12-18: Good layer consolidation for image size reduction.

Combining the apk add, npm ci, and npm i -g ts-node commands into a single RUN instruction reduces intermediate layers and improves cache efficiency. This directly supports the PR's goal of optimizing container size.


27-27: Good pruning strategy.

Adding npm prune --omit=dev after the build removes dev dependencies from the production image, directly contributing to the container size reduction goal.


36-44: Strong security hardening with non-root user.

Creating a dedicated non-root user (nodejs, UID 1001) and applying proper ownership to copied artifacts significantly improves the security posture. Running containers as non-root prevents privilege escalation risks.


1-44: Verify that CMD or ENTRYPOINT is specified elsewhere.

The Dockerfile ends at the USER directive without an explicit CMD or ENTRYPOINT. If the original Dockerfile contained these, they may need to be preserved in the production stage. Verify that the application entry point is correctly defined, either in this Dockerfile or inherited through a base image/docker-compose configuration.

Dockerfile Outdated
Comment on lines 36 to 42
# Add non-root user for security before copying files with ownership
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001

# Copy built files from builder stage (assign ownership to non-root user)
COPY --from=builder --chown=nodejs:nodejs /usr/src/app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /usr/src/app/build ./build
COPY --chown=nodejs:nodejs migration ./migration
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Missing --from=builder flag on line 42.

Lines 40–41 correctly copy artifacts from the builder stage using --from=builder, but line 42 omits this flag. The migration directory will be copied from the build context instead of the builder stage, which is inconsistent and likely incorrect.

Apply this diff to fix the COPY instruction:

-COPY --chown=nodejs:nodejs migration ./migration
+COPY --from=builder --chown=nodejs:nodejs /usr/src/app/migration ./migration
📝 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
# Add non-root user for security before copying files with ownership
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
# Copy built files from builder stage (assign ownership to non-root user)
COPY --from=builder --chown=nodejs:nodejs /usr/src/app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /usr/src/app/build ./build
COPY --chown=nodejs:nodejs migration ./migration
# Add non-root user for security before copying files with ownership
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
# Copy built files from builder stage (assign ownership to non-root user)
COPY --from=builder --chown=nodejs:nodejs /usr/src/app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /usr/src/app/build ./build
COPY --from=builder --chown=nodejs:nodejs /usr/src/app/migration ./migration
🤖 Prompt for AI Agents
In Dockerfile around lines 36 to 42, the COPY for the migration directory is
missing the --from=builder flag so it pulls from the build context instead of
the builder stage; change the COPY to pull migration from the builder stage and
preserve ownership (i.e., use COPY --from=builder --chown=nodejs:nodejs
/usr/src/app/migration ./migration).

Copy link
Contributor

@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

🧹 Nitpick comments (1)
src/utils/utils.ts (1)

486-498: Utility functions correctly implemented.

The generateRandomEtheriumAddress and generateHexNumber functions are correctly implemented for generating random Ethereum-style addresses and hex strings. The address format (0x prefix + 40 hex characters) matches the Ethereum address specification.

Note: There's a minor typo in the function name - "Etherium" should be "Ethereum" - but since this code is being moved rather than newly written, changing it now would require updates across all existing usage sites.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc43b54 and d88880f.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • Dockerfile (2 hunks)
  • migration/1681125863016-create_some_test_admi_users.ts (1 hunks)
  • package.json (4 hunks)
  • src/adapters/chainvine/chainvineMockAdapter.ts (1 hunks)
  • src/ormconfig.ts (1 hunks)
  • src/services/userService.test.ts (1 hunks)
  • src/utils/utils.ts (2 hunks)
  • test/testUtils.ts (1 hunks)
  • tsconfig.json (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • tsconfig.json
  • migration/1681125863016-create_some_test_admi_users.ts
🔇 Additional comments (9)
src/services/userService.test.ts (3)

10-17: LGTM: Import consolidation looks clean.

The consolidated imports are well-organized, and moving generateRandomEtheriumAddress and generateRandomString to shared utils improves code reusability.


108-111: LGTM: bcryptjs usage in tests is correct.

The migration from bcrypt to bcryptjs is a drop-in replacement, and the usage of bcrypt.hash() with the salt rounds from the environment is correct. The tests should continue to function as expected.

Also applies to: 123-126


24-24: ****

The premise of this review is flawed. Both userService.ts (line 7) and userService.test.ts (line 24) use identical CommonJS require() for bcryptjs with matching eslint-disable comments. This is a consistent codebase pattern, not a test-file-specific deviation. Changing only the test file would create an inconsistency between the test and its implementation rather than resolve one. If bcryptjs requires ES6 import conversion for consistency, that change should apply to both files uniformly.

Likely an incorrect or invalid review comment.

package.json (1)

27-27: Good choice replacing bcrypt with bcryptjs.

The switch from bcrypt to bcryptjs eliminates native compilation requirements, which reduces Docker image complexity and improves cross-platform compatibility.

Dockerfile (2)

36-44: Excellent security hardening with non-root user.

The addition of a dedicated nodejs user (UID/GID 1001) and explicit ownership assignment during file copying significantly improves the container's security posture. Running as non-root is a Docker best practice that limits potential damage from container breakouts.


11-18: Good layer optimization with consolidated RUN command.

Combining package installation steps into a single RUN layer reduces image size and build time by minimizing the number of intermediate layers.

src/adapters/chainvine/chainvineMockAdapter.ts (1)

1-5: Good refactoring moving test helpers to shared utilities.

Moving generateRandomEtheriumAddress and generateHexNumber from test utilities to shared utilities improves code organization and makes these helpers available across the codebase without depending on test-specific modules.

test/testUtils.ts (1)

47-50: Refactoring completed successfully.

The import of generateHexNumber and generateRandomEtheriumAddress from shared utilities completes the code organization improvement, removing duplicate implementations and establishing a single source of truth for these helper functions.

src/ormconfig.ts (1)

32-36: Migrations are automatically included in the production build via TypeScript compilation.

The concern is already addressed by the existing configuration. The tsconfig.json has rootDir: "./" and outDir: "./build", and the migration/ directory is not excluded. When the build script runs tsc, TypeScript will automatically compile all migration files from migration/*.ts to build/migration/*.js, satisfying the production configuration's expectation of build/migration/*.js.

No additional action is required—the current setup correctly includes migrations in the compiled build output.

package.json Outdated
Comment on lines 65 to 67
"pg": "^8.16.3",
"rate-limit-redis": "^4.2.0",
"redis": "^4.7.1",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify new database client dependencies are actually used.

The additions of pg (PostgreSQL client) and redis appear in dependencies, but it's unclear if they're replacing existing clients or adding new functionality. The codebase may already use ioredis (line 55) for Redis connectivity.

Run the following script to check if these new dependencies are imported and used:


🏁 Script executed:

#!/bin/bash
# Check for pg and redis usage in source code

echo "=== Checking for 'pg' usage ==="
rg -n --type=ts "from ['\"]pg['\"]|require\(['\"]pg['\"]" src/

echo -e "\n=== Checking for 'redis' usage ==="
rg -n --type=ts "from ['\"]redis['\"]|require\(['\"]redis['\"]" src/

echo -e "\n=== Existing ioredis usage ==="
rg -n --type=ts "from ['\"]ioredis['\"]|require\(['\"]ioredis['\"]" src/ | head -5

Length of output: 161


I need to conduct a more comprehensive check to confirm whether these packages are truly unused throughout the entire codebase:

Let me verify if rate-limit-redis is actually being used in the codebase:


🏁 Script executed:

#!/bin/bash
# Check for rate-limit-redis usage
echo "=== Checking for rate-limit-redis usage ==="
rg -n --type=ts "from ['\"]rate-limit-redis['\"]|require\(['\"]rate-limit-redis['\"]" src/

echo -e "\n=== Checking for any redis store or rate limiter setup ==="
rg -n --type=ts "RedisStore|RateLimiter" src/ | head -20

echo -e "\n=== Checking for pg usage patterns (pool, query, etc) ==="
rg -n --type=ts "pgPool|pgClient|pg\.Pool|pg\.Client" src/ | head -10

Length of output: 611


I need to check how the Redis stores are being instantiated and which Redis client is passed to them:


🏁 Script executed:

#!/bin/bash
# Check RedisStore instantiation in bootstrap.ts
echo "=== RedisStore instantiation in bootstrap.ts (around line 221) ==="
sed -n '215,230p' src/server/bootstrap.ts

echo -e "\n=== connect-redis instantiation in adminJs.ts (around lines 72, 104) ==="
sed -n '70,76p' src/server/adminJs/adminJs.ts
echo "---"
sed -n '102,106p' src/server/adminJs/adminJs.ts

echo -e "\n=== Checking what redis object is imported in adminJs.ts ==="
sed -n '1,50p' src/server/adminJs/adminJs.ts | grep -n "redis"

Length of output: 1473


Remove unused dependencies: pg and redis packages are not imported or used.

Verification confirms both packages are unnecessary:

  • pg: Zero usage detected in the codebase
  • redis: The codebase uses ioredis exclusively; both rate-limit-redis (bootstrap.ts:221) and connect-redis (adminJs.ts:72, 104) are configured with ioredis clients, not the redis npm package

Remove both from dependencies in package.json lines 65-67.

🤖 Prompt for AI Agents
In package.json around lines 65 to 67, the dependencies "pg" and "redis" are
unused and should be removed; edit package.json to delete the "pg" and "redis"
entries from the dependencies list (leaving "rate-limit-redis" intact), then run
your package manager's install (npm/yarn/pnpm) to update lockfile and verify the
project still builds and tests pass.

Comment on lines +234 to +235
"db:migrate:run:production": "NODE_ENV=production npx typeorm migration:run -d ./build/src/ormconfig.js",
"db:migrate:rever:productiont": "NODE_ENV=production npx typeorm migration:revert -d ./build/src/ormconfig.js",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix typo in migration script name.

Line 235 contains a typo: db:migrate:rever:productiont should be db:migrate:revert:production (missing 't' in "revert" and extra 't' in "production").

Apply this diff:

-        "db:migrate:rever:productiont": "NODE_ENV=production npx typeorm migration:revert -d ./build/src/ormconfig.js",
+        "db:migrate:revert:production": "NODE_ENV=production npx typeorm migration:revert -d ./build/src/ormconfig.js",
📝 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
"db:migrate:run:production": "NODE_ENV=production npx typeorm migration:run -d ./build/src/ormconfig.js",
"db:migrate:rever:productiont": "NODE_ENV=production npx typeorm migration:revert -d ./build/src/ormconfig.js",
"db:migrate:run:production": "NODE_ENV=production npx typeorm migration:run -d ./build/src/ormconfig.js",
"db:migrate:revert:production": "NODE_ENV=production npx typeorm migration:revert -d ./build/src/ormconfig.js",
🤖 Prompt for AI Agents
In package.json around lines 234 to 235, the npm script key
"db:migrate:rever:productiont" is misspelled; rename it to
"db:migrate:revert:production" and keep the command value "NODE_ENV=production
npx typeorm migration:revert -d ./build/src/ormconfig.js" so the script name
correctly reads revert and production is spelled properly.

@RamRamez RamRamez changed the title Test container size Optimize container size Oct 27, 2025
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