Skip to content

feat: secure and validate environment configuration - #160

Merged
zeemscript merged 3 commits into
Deen-Bridge:devfrom
IamOluwatoyin:fix/env-configuration-and-validation
Jul 29, 2026
Merged

feat: secure and validate environment configuration#160
zeemscript merged 3 commits into
Deen-Bridge:devfrom
IamOluwatoyin:fix/env-configuration-and-validation

Conversation

@IamOluwatoyin

@IamOluwatoyin IamOluwatoyin commented Jul 29, 2026

Copy link
Copy Markdown
Contributor
  • Rewrite .env.example with only the variables the code reads; remove NEXT_PUBLIC_CLOUDINARY_API_SECRET, _API_KEY, _URL, DNB_API_URL, NEXT_PUBLIC_SOCKET_URL
  • Add lib/config/env.js with Zod schema that validates URLs, constrains STELLAR_NETWORK to testnet|mainnet, rejects NEXT_PUBLIC_*SECRET vars, and fails build with aggregated error messages
  • Source Firebase config from env vars with current values as defaults
  • Route all process.env reads through the validated config object
  • Update README configuration table with all variables and required column

Close #85

Summary by CodeRabbit

  • Configuration
    • Centralized runtime settings for API, AI, Firebase, Cloudinary, Jitsi, and Stellar, with stricter validation and safeguards against exposing secret values in public config.
    • Updated .env.example to switch the public backend endpoint to local, add AI FastAPI and Firebase variables, simplify Cloudinary config, add Jitsi JWT requirement, and remove the old backend URL entry.
    • AI and backend requests now consistently use the configured base URLs.
  • Documentation
    • Expanded the README β€œEnvironment Variables” section and aligned it with .env.example.
  • Bug Fixes
    • Improved Cloudinary upload progress behavior and refined upload error reporting.

- Rewrite .env.example with only the variables the code reads; remove
  NEXT_PUBLIC_CLOUDINARY_API_SECRET, _API_KEY, _URL, DNB_API_URL,
  NEXT_PUBLIC_SOCKET_URL
- Add lib/config/env.js with Zod schema that validates URLs, constrains
  STELLAR_NETWORK to testnet|mainnet, rejects NEXT_PUBLIC_*SECRET vars,
  and fails build with aggregated error messages
- Source Firebase config from env vars with current values as defaults
- Route all process.env reads through the validated config object
- Update README configuration table with all variables and required column
@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown

@IamOluwatoyin is attempting to deploy a commit to the Deen Bridge Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The change introduces centralized Zod-validated environment configuration, documents expanded variables, removes exposed Cloudinary credential examples, and updates API, Firebase, Jitsi, Stellar, and Cloudinary code to consume the shared configuration.

Changes

Environment configuration

Layer / File(s) Summary
Validated configuration contract
.env.example, lib/config/env.js, README.md
Environment variables are validated centrally, unsafe public secret names are rejected, fallbacks are logged outside production, and the documented template/table includes API, Jitsi, Stellar, Cloudinary, and Firebase settings.
Service configuration consumers
app/api/ai/*, components/organisms/dashboard/..., components/stellar/..., lib/actions/..., lib/config/axios.config.js, app/api/books/...
AI, backend API, Jitsi, Stellar, cached requests, and Axios now read values from the shared config object.
Firebase configuration wiring
lib/config/firebase.config.js
Firebase initialization now uses config.firebase instead of an inline configuration object.
Cloudinary upload handling
lib/utils/cloudinaryUpload.js
Cloudinary uploads use centralized configuration and update progress-callback conditions and error-message handling.

Estimated code review effort: 3 (Moderate) | ~25 minutes

πŸš₯ Pre-merge checks | βœ… 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning lib/utils/cloudinaryUpload.js also changes progress-callback behavior and error handling, which are unrelated to the environment-config work. Move those upload-behavior changes into a separate PR or revert them unless they were intentionally part of this env-config update.
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
Description Check βœ… Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check βœ… Passed The title is concise and accurately summarizes the main change: securing and validating environment configuration.
Linked Issues check βœ… Passed The PR addresses the #85 scope with env validation, config centralization, Firebase env vars, and updated .env.example/README docs.
✨ Finishing Touches πŸ’‘ 1
πŸ› οΈ Fix failing CI checks πŸ’‘
  • Fix failing CI checks
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests

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

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/api/books/[bookId]/preview/route.js (1)

9-10: 🩺 Stability & Availability | 🟠 Major | ⚑ Quick win

Await Next.js 15 request APIs. params and cookies() are still read synchronously here; switch to await params and await cookies() so this route stays compatible with the App Router APIs in Next.js 15.

πŸ€– 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 `@app/api/books/`[bookId]/preview/route.js around lines 9 - 10, Update the GET
route handler to await the Next.js 15 request APIs: resolve params
asynchronously before extracting bookId, and await the cookies() call wherever
it is used in the handler. Preserve the existing route behavior and
cookie/parameter handling after these asynchronous reads.

Source: Path instructions

🧹 Nitpick comments (1)
lib/config/env.js (1)

45-61: 🎯 Functional Correctness | πŸ”΅ Trivial | ⚑ Quick win

Required-field error message won't surface as intended.

NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME is required, but the custom message "Cloudinary cloud name is required" is only attached to .min(1, ...). When the variable is entirely unset (undefined), zod fails on the type check first and reports the generic "Expected string, received undefined" instead of your intended message β€” weakening the "clearly list missing... variables" goal from the PR.

🩹 Proposed fix
-  NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME: z
-    .string()
-    .min(1, "Cloudinary cloud name is required"),
+  NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME: z
+    .string({ required_error: "Cloudinary cloud name is required" })
+    .min(1, "Cloudinary cloud name is required"),
πŸ€– 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 `@lib/config/env.js` around lines 45 - 61, Update the
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME schema in envSchema so the custom β€œCloudinary
cloud name is required” message applies when the variable is undefined as well
as when it is empty. Preserve the field as required and keep the existing
validation behavior for non-empty values.
πŸ€– 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 @.env.example:
- Around line 17-18: Update the NEXT_PUBLIC_JITSI_DOMAIN example value to the
bare domain meet.jit.si without the https:// protocol, matching the jitsiDomain
getter default and README documentation.

In `@app/api/ai/chat/route.js`:
- Around line 7-8: Remove the raw console logs for message, chat_id, and user_id
in the chat handler, and apply the same production-safe redaction or removal to
full AI response and error payload logging in the surrounding handler. Do not
emit sensitive prompt content or user identifiers; use the existing structured
logger only with explicitly safe, retention-compliant fields.
- Line 10: Make configuration fallbacks development-only: in
app/api/ai/chat/route.js:10, app/api/ai/stream/route.js:14,
components/organisms/dashboard/ai/Ai-Sidebar.jsx:14,
lib/actions/ai/load-chat-history.js:12 and :36,
app/api/books/[bookId]/preview/route.js:5-6, lib/actions/cached-api.js:9, and
lib/config/axios.config.js:4 require the respective AI/API URL in production
instead of falling back to localhost; in
components/stellar/StellarProvider.jsx:19-21 require NEXT_PUBLIC_STELLAR_NETWORK
in production instead of defaulting to testnet. Preserve the existing
development fallbacks.

In `@components/organisms/dashboard/JaasMeetingClientSection.jsx`:
- Around line 54-55: Update the Jitsi domain configuration flow used by
JaasMeetingClientSection so blank or whitespace-only NEXT_PUBLIC_JITSI_DOMAIN
values are treated as unset before normalizeDomain receives them. Use the
existing default-domain fallback (such as meet.jit.si) or trim and reject blank
values in the configuration module, covering both referenced domain usages.

In `@lib/config/env.js`:
- Around line 110-131: Remove the live Firebase values from the firebase
configuration getter in lib/config/env.js, require every NEXT_PUBLIC_FIREBASE_*
variable explicitly, and raise a clear startup error when any is missing.
Replace the real Firebase values with generic placeholders in .env.example lines
24-30; rotating or restricting the previously committed key is a separate
follow-up.
- Around line 78-131: Update the configuration getters stellarNetwork,
jitsiDomain, jitsiRequireJwt, and firebase so every hardcoded fallback invokes
the existing warn helper with its environment key and fallback value before
returning that value. Preserve the current defaults and boolean behavior, while
replacing the repeated comma-operator pattern with the shared fallback approach
if available.

---

Outside diff comments:
In `@app/api/books/`[bookId]/preview/route.js:
- Around line 9-10: Update the GET route handler to await the Next.js 15 request
APIs: resolve params asynchronously before extracting bookId, and await the
cookies() call wherever it is used in the handler. Preserve the existing route
behavior and cookie/parameter handling after these asynchronous reads.

---

Nitpick comments:
In `@lib/config/env.js`:
- Around line 45-61: Update the NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME schema in
envSchema so the custom β€œCloudinary cloud name is required” message applies when
the variable is undefined as well as when it is empty. Preserve the field as
required and keep the existing validation behavior for non-empty values.
πŸͺ„ 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.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 28b356b4-a274-4cf3-88a5-d7be275e5372

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 3a1c665 and c6e93a7.

πŸ“’ Files selected for processing (14)
  • .env.example
  • README.md
  • app/api/ai/chat/route.js
  • app/api/ai/stream/route.js
  • app/api/books/[bookId]/preview/route.js
  • components/organisms/dashboard/JaasMeetingClientSection.jsx
  • components/organisms/dashboard/ai/Ai-Sidebar.jsx
  • components/stellar/StellarProvider.jsx
  • lib/actions/ai/load-chat-history.js
  • lib/actions/cached-api.js
  • lib/config/axios.config.js
  • lib/config/env.js
  • lib/config/firebase.config.js
  • lib/utils/cloudinaryUpload.js

Comment thread .env.example
Comment on lines 17 to +18
NEXT_PUBLIC_JITSI_DOMAIN=https://meet.jit.si
# NODE_ENV=production
DNB_API_URL=https://dnb-backend-api.onrender.com
NEXT_PUBLIC_API_URL=https://dnb-backend-api.onrender.com
NEXT_PUBLIC_STELLAR_NETWORK=testnet
# Jitsi Meet domain for video spaces

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.

πŸ—„οΈ Data Integrity & Integration | 🟑 Minor | ⚑ Quick win

Example value includes a protocol prefix that the code doesn't expect.

lib/config/env.js's jitsiDomain getter falls back to the bare domain "meet.jit.si" (no protocol), and the README documents the same bare-domain default. This example uses https://meet.jit.si. If a contributor copies this literally and downstream code builds a URL like https://${jitsiDomain}/... (or passes it to the Jitsi Meet External API, which expects a bare domain), the protocol gets duplicated.

🩹 Proposed fix
-NEXT_PUBLIC_JITSI_DOMAIN=https://meet.jit.si
+NEXT_PUBLIC_JITSI_DOMAIN=meet.jit.si
πŸ“ 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
NEXT_PUBLIC_JITSI_DOMAIN=https://meet.jit.si
# NODE_ENV=production
DNB_API_URL=https://dnb-backend-api.onrender.com
NEXT_PUBLIC_API_URL=https://dnb-backend-api.onrender.com
NEXT_PUBLIC_STELLAR_NETWORK=testnet
# Jitsi Meet domain for video spaces
NEXT_PUBLIC_JITSI_DOMAIN=meet.jit.si
# Jitsi Meet domain for video spaces
πŸ€– 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 @.env.example around lines 17 - 18, Update the NEXT_PUBLIC_JITSI_DOMAIN
example value to the bare domain meet.jit.si without the https:// protocol,
matching the jitsiDomain getter default and README documentation.

Comment thread app/api/ai/chat/route.js
Comment on lines 7 to 8
console.log("Sending message to AI:", message);
console.log("Chat ID:", chat_id, "User ID:", user_id);

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.

πŸ”’ Security & Privacy | 🟠 Major | ⚑ Quick win

Do not log raw AI prompts or user identifiers.

message, chat_id, and user_id may contain sensitive content or user identifiers. Remove these logs, or redact them through a production-safe structured logger with an explicit retention policy; the full response and error payload logs in this handler should be treated the same way.

πŸ€– 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 `@app/api/ai/chat/route.js` around lines 7 - 8, Remove the raw console logs for
message, chat_id, and user_id in the chat handler, and apply the same
production-safe redaction or removal to full AI response and error payload
logging in the surrounding handler. Do not emit sensitive prompt content or user
identifiers; use the existing structured logger only with explicitly safe,
retention-compliant fields.

Comment thread app/api/ai/chat/route.js
// Use environment variable or fallback to localhost
const AI_API_URL =
process.env.NEXT_PUBLIC_AI_API_URL || "http://localhost:8000";
const AI_API_URL = config.aiApiUrl;

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

Make environment fallbacks development-only. The centralized configuration currently allows missing production values to resolve to localhost or testnet, silently targeting the wrong service or Stellar network instead of failing startup.

  • app/api/ai/chat/route.js#L10-L10: require NEXT_PUBLIC_AI_API_URL in production.
  • app/api/ai/stream/route.js#L14-L14: apply the same production requirement to streaming requests.
  • components/organisms/dashboard/ai/Ai-Sidebar.jsx#L14-L14: prevent browser requests from falling back to the user’s localhost.
  • lib/actions/ai/load-chat-history.js#L12-L12: require the AI URL for chat-history loading.
  • lib/actions/ai/load-chat-history.js#L36-L36: require the AI URL for message-history loading.
  • app/api/books/[bookId]/preview/route.js#L5-L6: require NEXT_PUBLIC_API_URL before constructing the proxy URL.
  • lib/actions/cached-api.js#L9-L9: prevent cached API calls from using localhost in production.
  • lib/config/axios.config.js#L4-L4: prevent Axios from initializing against localhost in production.
  • components/stellar/StellarProvider.jsx#L19-L21: require NEXT_PUBLIC_STELLAR_NETWORK in production instead of defaulting to testnet.
πŸ“ Affects 8 files
  • app/api/ai/chat/route.js#L10-L10 (this comment)
  • app/api/ai/stream/route.js#L14-L14
  • components/organisms/dashboard/ai/Ai-Sidebar.jsx#L14-L14
  • lib/actions/ai/load-chat-history.js#L12-L12
  • lib/actions/ai/load-chat-history.js#L36-L36
  • app/api/books/[bookId]/preview/route.js#L5-L6
  • lib/actions/cached-api.js#L9-L9
  • lib/config/axios.config.js#L4-L4
  • components/stellar/StellarProvider.jsx#L19-L21
πŸ€– 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 `@app/api/ai/chat/route.js` at line 10, Make configuration fallbacks
development-only: in app/api/ai/chat/route.js:10, app/api/ai/stream/route.js:14,
components/organisms/dashboard/ai/Ai-Sidebar.jsx:14,
lib/actions/ai/load-chat-history.js:12 and :36,
app/api/books/[bookId]/preview/route.js:5-6, lib/actions/cached-api.js:9, and
lib/config/axios.config.js:4 require the respective AI/API URL in production
instead of falling back to localhost; in
components/stellar/StellarProvider.jsx:19-21 require NEXT_PUBLIC_STELLAR_NETWORK
in production instead of defaulting to testnet. Preserve the existing
development fallbacks.

Comment on lines +54 to 55
const domain = config.jitsiDomain;
const normalizedDomain = normalizeDomain(domain);

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.

🎯 Functional Correctness | 🟑 Minor | ⚑ Quick win

Treat a blank Jitsi domain as unset.

The shared schema accepts "", and config.jitsiDomain uses a nullish fallback, so an empty NEXT_PUBLIC_JITSI_DOMAIN reaches normalizeDomain(""). That can produce https:///... meeting URLs. Trim/reject blank values or preserve the previous || "meet.jit.si" fallback in the configuration module.

Also applies to: 82-84

πŸ€– 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 `@components/organisms/dashboard/JaasMeetingClientSection.jsx` around lines 54
- 55, Update the Jitsi domain configuration flow used by
JaasMeetingClientSection so blank or whitespace-only NEXT_PUBLIC_JITSI_DOMAIN
values are treated as unset before normalizeDomain receives them. Use the
existing default-domain fallback (such as meet.jit.si) or trim and reject blank
values in the configuration module, covering both referenced domain usages.

Comment thread lib/config/env.js
Comment on lines +78 to +131
get apiUrl() {
return (
env.NEXT_PUBLIC_API_URL ??
(warn("NEXT_PUBLIC_API_URL", "http://localhost:5000"),
"http://localhost:5000")
);
},

get aiApiUrl() {
return (
env.NEXT_PUBLIC_AI_API_URL ??
(warn("NEXT_PUBLIC_AI_API_URL", "http://localhost:8000"),
"http://localhost:8000")
);
},

get stellarNetwork() {
return env.NEXT_PUBLIC_STELLAR_NETWORK ?? "testnet";
},

get cloudinaryCloudName() {
return env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME;
},

get jitsiDomain() {
return env.NEXT_PUBLIC_JITSI_DOMAIN ?? "meet.jit.si";
},

get jitsiRequireJwt() {
return env.NEXT_PUBLIC_JITSI_REQUIRE_JWT === "true";
},

get firebase() {
return {
apiKey:
env.NEXT_PUBLIC_FIREBASE_API_KEY ??
"AIzaSyC8LlmtlWXvbcbyVbdyv4r-tDsGhhukdag",
authDomain:
env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN ??
"deen-bridge-22195.firebaseapp.com",
projectId:
env.NEXT_PUBLIC_FIREBASE_PROJECT_ID ?? "deen-bridge-22195",
storageBucket:
env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET ??
"deen-bridge-22195.firebasestorage.app",
messagingSenderId:
env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID ?? "368531944242",
appId:
env.NEXT_PUBLIC_FIREBASE_APP_ID ??
"1:368531944242:web:7994b11820741a69d35d2b",
measurementId:
env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID ?? "G-ZZ81THLVCC",
};
},

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.

🎯 Functional Correctness | 🟠 Major | ⚑ Quick win

Fallback warnings are inconsistent across getters.

Only apiUrl/aiApiUrl call warn() when falling back to a default (lines 80-83, 88-91). stellarNetwork (95), jitsiDomain (103), jitsiRequireJwt (107), and every field in firebase (112-129) silently use hardcoded defaults with no warning. This directly conflicts with the stated goal to "preserve sensible development fallbacks while warning when they are used" β€” a dev could unknowingly run against the wrong Stellar network or a stale Firebase project with zero console signal.

♻️ Suggested refactor: unify via a shared helper
+function withFallback(field, value, fallback) {
+  if (value === undefined) {
+    warn(field, fallback);
+    return fallback;
+  }
+  return value;
+}
+
 export const config = Object.freeze({
   get apiUrl() {
-    return (
-      env.NEXT_PUBLIC_API_URL ??
-      (warn("NEXT_PUBLIC_API_URL", "http://localhost:5000"),
-      "http://localhost:5000")
-    );
+    return withFallback("NEXT_PUBLIC_API_URL", env.NEXT_PUBLIC_API_URL, "http://localhost:5000");
   },
   get aiApiUrl() {
-    return (
-      env.NEXT_PUBLIC_AI_API_URL ??
-      (warn("NEXT_PUBLIC_AI_API_URL", "http://localhost:8000"),
-      "http://localhost:8000")
-    );
+    return withFallback("NEXT_PUBLIC_AI_API_URL", env.NEXT_PUBLIC_AI_API_URL, "http://localhost:8000");
   },
   get stellarNetwork() {
-    return env.NEXT_PUBLIC_STELLAR_NETWORK ?? "testnet";
+    return withFallback("NEXT_PUBLIC_STELLAR_NETWORK", env.NEXT_PUBLIC_STELLAR_NETWORK, "testnet");
   },
   get jitsiDomain() {
-    return env.NEXT_PUBLIC_JITSI_DOMAIN ?? "meet.jit.si";
+    return withFallback("NEXT_PUBLIC_JITSI_DOMAIN", env.NEXT_PUBLIC_JITSI_DOMAIN, "meet.jit.si");
   },
   get jitsiRequireJwt() {
-    return env.NEXT_PUBLIC_JITSI_REQUIRE_JWT === "true";
+    return withFallback("NEXT_PUBLIC_JITSI_REQUIRE_JWT", env.NEXT_PUBLIC_JITSI_REQUIRE_JWT, "false") === "true";
   },
   get firebase() {
     return {
       apiKey:
-        env.NEXT_PUBLIC_FIREBASE_API_KEY ??
-        "AIzaSyC8LlmtlWXvbcbyVbdyv4r-tDsGhhukdag",
+        withFallback("NEXT_PUBLIC_FIREBASE_API_KEY", env.NEXT_PUBLIC_FIREBASE_API_KEY, "AIzaSyC8LlmtlWXvbcbyVbdyv4r-tDsGhhukdag"),
       // ...apply the same pattern to authDomain, projectId, storageBucket,
       // messagingSenderId, appId, measurementId
     };
   },
 });

This also removes the repeated comma-operator idiom, which is easy to misread.

🧰 Tools
πŸͺ› Betterleaks (1.7.0)

[high] 114-114: Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches.

(gcp-api-key)

πŸ€– 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 `@lib/config/env.js` around lines 78 - 131, Update the configuration getters
stellarNetwork, jitsiDomain, jitsiRequireJwt, and firebase so every hardcoded
fallback invokes the existing warn helper with its environment key and fallback
value before returning that value. Preserve the current defaults and boolean
behavior, while replacing the repeated comma-operator pattern with the shared
fallback approach if available.

Comment thread lib/config/env.js
Comment on lines +110 to +131
get firebase() {
return {
apiKey:
env.NEXT_PUBLIC_FIREBASE_API_KEY ??
"AIzaSyC8LlmtlWXvbcbyVbdyv4r-tDsGhhukdag",
authDomain:
env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN ??
"deen-bridge-22195.firebaseapp.com",
projectId:
env.NEXT_PUBLIC_FIREBASE_PROJECT_ID ?? "deen-bridge-22195",
storageBucket:
env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET ??
"deen-bridge-22195.firebasestorage.app",
messagingSenderId:
env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID ?? "368531944242",
appId:
env.NEXT_PUBLIC_FIREBASE_APP_ID ??
"1:368531944242:web:7994b11820741a69d35d2b",
measurementId:
env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID ?? "G-ZZ81THLVCC",
};
},

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.

πŸ”’ Security & Privacy | 🟠 Major | ⚑ Quick win

Real Firebase Web API key/project identifiers hardcoded and duplicated across two files. The same live Firebase credentials appear both as source-code fallback defaults and as ".env.example" values, and Betterleaks independently flags both sites as a leaked GCP API key. As per path instructions, **/*.{js,jsx} files must "Flag hardcoded secrets, API keys, or wallet secret keys," so even though Firebase Web API keys aren't traditionally treated as high-secrecy secrets by Google, baking the actual project's live values into shipped code (rather than a placeholder) increases exposure surface and makes rotation/tracking harder.

  • lib/config/env.js#L110-L131: don't hardcode the real key/IDs as JS fallback defaults β€” require NEXT_PUBLIC_FIREBASE_* to be explicitly set (with a clear startup error if missing) instead of silently defaulting to production-identifying values baked into the bundle.
  • .env.example#L24-L30: replace the real project values with generic placeholders (e.g. your_firebase_api_key), consistent with how NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME already uses a placeholder in this file.

Since these values are already committed to git history, also consider rotating/restricting the Firebase Web API key (HTTP referrer + API restrictions in Google Cloud Console) as a follow-up, independent of this code change.

🧰 Tools
πŸͺ› Betterleaks (1.7.0)

[high] 114-114: Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches.

(gcp-api-key)

πŸ“ Affects 2 files
  • lib/config/env.js#L110-L131 (this comment)
  • .env.example#L24-L30
πŸ€– 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 `@lib/config/env.js` around lines 110 - 131, Remove the live Firebase values
from the firebase configuration getter in lib/config/env.js, require every
NEXT_PUBLIC_FIREBASE_* variable explicitly, and raise a clear startup error when
any is missing. Replace the real Firebase values with generic placeholders in
.env.example lines 24-30; rotating or restricting the previously committed key
is a separate follow-up.

Sources: Path instructions, Linters/SAST tools

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
README.md (1)

89-99: πŸ“ Maintainability & Code Quality | 🟑 Minor | ⚑ Quick win

List each Firebase environment variable explicitly.

NEXT_PUBLIC_FIREBASE_* is a wildcard rather than a usable variable name, so contributors cannot tell which keys are required or verify that their configuration is complete. Add one table row per exact Firebase key from .env.example, including its optional/default status.

πŸ€– 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 `@README.md` around lines 89 - 99, Update the environment-variable table in
README.md by replacing the wildcard NEXT_PUBLIC_FIREBASE_* row with one row for
each exact Firebase variable defined in .env.example. Include every key’s
required or optional/default status and retain the existing descriptions and
table structure.
.env.example (1)

33-35: πŸ—„οΈ Data Integrity & Integration | 🟑 Minor | ⚑ Quick win

Remove duplicate environment assignments.

NEXT_PUBLIC_API_URL and NEXT_PUBLIC_STELLAR_NETWORK are already defined elsewhere in .env.example. Keep each key in one location; duplicate assignments make the copied configuration ambiguous and may cause later values to override earlier ones.

πŸ€– 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 @.env.example around lines 33 - 35, Remove the duplicate NEXT_PUBLIC_API_URL
and NEXT_PUBLIC_STELLAR_NETWORK assignments from this section of .env.example,
retaining each key only in its existing canonical location. Keep the DNB_API_URL
assignment unchanged.

Source: Linters/SAST tools

πŸ€– 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 @.env.example:
- Line 34: Update the NEXT_PUBLIC_API_URL example value to http://localhost:5000
so it matches the documented development default and setup behavior.
- Line 33: Remove the unused DNB_API_URL entry from the environment example,
keeping NEXT_PUBLIC_API_URL as the documented frontend API variable. Do not
retain the variable unless it is also added to the environment schema and
README.

---

Outside diff comments:
In @.env.example:
- Around line 33-35: Remove the duplicate NEXT_PUBLIC_API_URL and
NEXT_PUBLIC_STELLAR_NETWORK assignments from this section of .env.example,
retaining each key only in its existing canonical location. Keep the DNB_API_URL
assignment unchanged.

In `@README.md`:
- Around line 89-99: Update the environment-variable table in README.md by
replacing the wildcard NEXT_PUBLIC_FIREBASE_* row with one row for each exact
Firebase variable defined in .env.example. Include every key’s required or
optional/default status and retain the existing descriptions and table
structure.
πŸͺ„ 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.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f0f65378-c41c-452f-9dc8-5d521c66565b

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between c6e93a7 and 23a0a99.

πŸ“’ Files selected for processing (4)
  • .env.example
  • README.md
  • app/api/books/[bookId]/preview/route.js
  • lib/config/axios.config.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/api/books/[bookId]/preview/route.js
  • lib/config/axios.config.js

Comment thread .env.example
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=G-ZZ81THLVCC
# Firebase Web SDK config values (not secrets, but environment-specific)
# NODE_ENV=production
DNB_API_URL=https://dnb-backend-api.onrender.com

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.

πŸ—„οΈ Data Integrity & Integration | 🟑 Minor | ⚑ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n '\bDNB_API_URL\b|\bNEXT_PUBLIC_API_URL\b' .

Repository: Deen-Bridge/dnb-frontend

Length of output: 817


Remove the unused DNB_API_URL entry from .env.example. The frontend reads NEXT_PUBLIC_API_URL; keeping DNB_API_URL here drifts from the validated env surface and can confuse contributors. If this variable is still needed, add it to the schema and README instead.

🧰 Tools
πŸͺ› dotenv-linter (4.0.0)

[warning] 33-33: [UnorderedKey] The DNB_API_URL key should go before the NEXT_PUBLIC_FIREBASE_API_KEY key

(UnorderedKey)

πŸ€– 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 @.env.example at line 33, Remove the unused DNB_API_URL entry from the
environment example, keeping NEXT_PUBLIC_API_URL as the documented frontend API
variable. Do not retain the variable unless it is also added to the environment
schema and README.

Comment thread .env.example
# Firebase Web SDK config values (not secrets, but environment-specific)
# NODE_ENV=production
DNB_API_URL=https://dnb-backend-api.onrender.com
NEXT_PUBLIC_API_URL=https://dnb-backend-api.onrender.com

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.

πŸ—„οΈ Data Integrity & Integration | 🟑 Minor | ⚑ Quick win

Align the example API URL with the documented development default.

.env.example points to the deployed backend, while README.md documents http://localhost:5000 as the default and setup copies this file directly. Use the local default here, or explicitly document why this example intentionally targets production.

🧰 Tools
πŸͺ› dotenv-linter (4.0.0)

[warning] 34-34: [DuplicatedKey] The NEXT_PUBLIC_API_URL key is duplicated

(DuplicatedKey)


[warning] 34-34: [UnorderedKey] The NEXT_PUBLIC_API_URL key should go before the NEXT_PUBLIC_FIREBASE_API_KEY key

(UnorderedKey)

πŸ€– 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 @.env.example at line 34, Update the NEXT_PUBLIC_API_URL example value to
http://localhost:5000 so it matches the documented development default and setup
behavior.

The Zod schema required NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME, causing the
build to fail when the variable is not set in CI. The runtime code in
cloudinaryUpload.js already validates the cloud name and throws a clear
error, so the schema should allow undefined and warn at access time.

@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

πŸ€– 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 `@lib/config/env.js`:
- Line 49: Update the NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME configuration handling
to reject blank values rather than accepting explicit empty strings. When the
setting is absent, either disable/gate Cloudinary or return the documented
β€œ(none)” fallback consistently with the warning. Ensure the Cloudinary uploader
cannot receive an unusable empty cloud name.
πŸͺ„ 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.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f114cec8-3451-4b22-a1fc-9a00a73ff4ac

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 23a0a99 and f85d978.

πŸ“’ Files selected for processing (1)
  • lib/config/env.js

Comment thread lib/config/env.js
NEXT_PUBLIC_API_URL: z.string().url().optional(),
NEXT_PUBLIC_AI_API_URL: z.string().url().optional(),
NEXT_PUBLIC_STELLAR_NETWORK: z.enum(["testnet", "mainnet"]).optional(),
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME: z.string().optional(),

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.

🎯 Functional Correctness | 🟠 Major | ⚑ Quick win

Reject unusable Cloudinary configuration instead of deferring failure.

z.string().optional() accepts an explicit empty value, and the getter returns that empty value unchanged. Since the Cloudinary uploader consumes this setting, invalid configuration can pass startup and fail only when an upload is attempted. Reject blank values or explicitly disable/gate Cloudinary when the setting is absent. Also, the warning says "(none)" is used, but no such fallback is returned.

Also applies to: 97-100

πŸ€– 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 `@lib/config/env.js` at line 49, Update the NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME
configuration handling to reject blank values rather than accepting explicit
empty strings. When the setting is absent, either disable/gate Cloudinary or
return the documented β€œ(none)” fallback consistently with the warning. Ensure
the Cloudinary uploader cannot receive an unusable empty cloud name.

@zeemscript
zeemscript merged commit b0f0abb into Deen-Bridge:dev Jul 29, 2026
2 of 3 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jul 31, 2026
Merged
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.

2 participants