Skip to content

Conversation

@cleot
Copy link
Contributor

@cleot cleot commented Dec 2, 2025

User description

Generates config.js at startup

Test image deployed to clowder-wildcat0:


PR Type

Enhancement


Description

  • Enable runtime environment configuration in Docker containers

  • Create centralized env module with fallback to build-time values

  • Generate config.js at startup from Docker environment variables

  • Add comprehensive tests for runtime environment resolution


Diagram Walkthrough

flowchart LR
  A["Docker Environment Variables"] -->|"entrypoint.sh generates"| B["config.js with window.__ENV__"]
  B -->|"loaded in index.html"| C["Browser Runtime"]
  C -->|"env.ts reads from"| D["env module"]
  D -->|"fallback to"| E["Build-time import.meta.env"]
  D -->|"used by"| F["meta.ts, api-client.ts, keycloak.tsx"]
Loading

File Walkthrough

Relevant files
Enhancement
5 files
env.ts
New centralized environment resolution module                       
+34/-0   
meta.ts
Migrate to centralized env module                                               
+6/-4     
api-client.ts
Use centralized env for API base URL                                         
+2/-1     
keycloak.tsx
Use centralized env for Keycloak config                                   
+4/-3     
index.html
Load config.js before main application                                     
+1/-0     
Tests
1 files
env.test.ts
Comprehensive tests for runtime env resolution                     
+86/-0   
Configuration changes
5 files
config.js
Placeholder for runtime environment config                             
+1/-0     
00-env-config.sh
Generate config.js from Docker environment                             
+15/-0   
Dockerfile
Add jq and entrypoint scripts for env config                         
+5/-0     
default.conf.template
Disable caching for config.js endpoint                                     
+4/-0     
docker-compose.yml
Pass additional env vars to container                                       
+2/-0     
Documentation
1 files
.env.example
Add VITE_API_MOCKING_ENABLED example                                         
+1/-0     
Miscellaneous
1 files
main.tsx
Export App component for testing                                                 
+2/-0     

@cleot cleot self-assigned this Dec 2, 2025
@cleot cleot requested a review from Copilot December 2, 2025 17:47
Copilot finished reviewing on behalf of cleot December 2, 2025 17:49
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR enables runtime configuration of environment variables in Docker deployments by generating a config.js file at container startup, allowing the same Docker image to be configured differently across environments without rebuilding.

Key changes:

  • Introduced src/lib/env.ts module that reads environment variables from window.__ENV__ (runtime) with fallback to import.meta.env (build-time)
  • Modified environment variable access throughout the codebase to use the new env module
  • Added Docker entrypoint script to generate config.js from runtime environment variables

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/lib/env.ts New module for runtime/build-time environment variable resolution with fallback logic
src/lib/api-client.ts Updated to use centralized env module instead of direct import.meta.env access
src/keycloak.tsx Updated to use centralized env module for Keycloak configuration
src/constants/meta.ts Refactored to consume values from env module
public/config.js Placeholder file that initializes window.ENV object
index.html Added script tag to load config.js before main application
docker/nginx/templates/default.conf.template Added no-cache header for config.js endpoint
docker/entrypoint.d/00-env-config.sh Shell script to generate config.js from environment variables at container startup
Dockerfile Added entrypoint script installation to Docker build
docker-compose.yml Added VITE_API_MOCKING_ENABLED to environment variables list
.env.example Added VITE_API_MOCKING_ENABLED example value
Comments suppressed due to low confidence (1)

docker/entrypoint.d/00-env-config.sh:12

  • The shell script generates JavaScript with unquoted string values, which could lead to JavaScript syntax errors if any environment variable contains special characters (like quotes, newlines, or backslashes).

For example, if VITE_API_BASE_URL contains a quote character, the generated JavaScript would be invalid. Consider using JSON.stringify-like escaping or a safer approach:

cat <<'EOF' > /usr/share/nginx/html/config.js
window.__ENV__ = {
  VITE_API_BASE_URL: JSON.stringify(process.env.VITE_API_BASE_URL || ""),
  // ... other variables
}
EOF

Or use a more robust approach with proper escaping:

# Using jq or similar tool to safely generate JSON
cat > /usr/share/nginx/html/config.js <<EOF
window.__ENV__ = $(jq -n \
  --arg api_url "${VITE_API_BASE_URL}" \
  --arg api_mocking "${VITE_API_MOCKING_ENABLED}" \
  --arg keycloak_url "${VITE_KEYCLOAK_URL}" \
  --arg keycloak_realm "${VITE_KEYCLOAK_REALM}" \
  --arg keycloak_client "${VITE_KEYCLOAK_CLIENT_ID}" \
  --arg crowdin "${VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING}" \
  '{VITE_API_BASE_URL: $api_url, VITE_API_MOCKING_ENABLED: $api_mocking, VITE_KEYCLOAK_URL: $keycloak_url, VITE_KEYCLOAK_REALM: $keycloak_realm, VITE_KEYCLOAK_CLIENT_ID: $keycloak_client, VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING: $crowdin}')
EOF
cat <<EOF > /usr/share/nginx/html/config.js
window.__ENV__ = {
  VITE_API_BASE_URL: "${VITE_API_BASE_URL}",
  VITE_API_MOCKING_ENABLED: "${VITE_API_MOCKING_ENABLED}",
  VITE_KEYCLOAK_URL: "${VITE_KEYCLOAK_URL}",
  VITE_KEYCLOAK_REALM: "${VITE_KEYCLOAK_REALM}",
  VITE_KEYCLOAK_CLIENT_ID: "${VITE_KEYCLOAK_CLIENT_ID}",
  VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING: "${VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING}"
}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Dec 2, 2025

Deploying wildcat-dashboard with  Cloudflare Pages  Cloudflare Pages

Latest commit: e918e3d
Status: ✅  Deploy successful!
Preview URL: https://e26f83d2.wildcat-dashboard.pages.dev
Branch Preview URL: https://cleot-enable-docker-env.wildcat-dashboard.pages.dev

View logs

@codecov
Copy link

codecov bot commented Dec 2, 2025

Codecov Report

❌ Patch coverage is 62.50000% with 12 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/constants/meta.ts 0.00% 5 Missing ⚠️
src/keycloak.tsx 0.00% 4 Missing ⚠️
src/lib/api-client.ts 0.00% 2 Missing ⚠️
public/config.js 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@cleot cleot requested a review from Copilot December 2, 2025 21:21
Copilot finished reviewing on behalf of cleot December 2, 2025 21:26
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


cat <<EOF > /usr/share/nginx/html/config.js
window.__ENV__ = ${JSON_ENV};
EOF
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

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

The generated config.js file is placed in /usr/share/nginx/html/config.js, but there's no verification that the file was successfully created or that the jq command succeeded. Consider adding error handling to ensure the config.js file is generated correctly. For example:

if [ ! -f /usr/share/nginx/html/config.js ]; then
  echo "Error: Failed to generate config.js"
  exit 1
fi
Suggested change
EOF
EOF
if [ ! -f /usr/share/nginx/html/config.js ]; then
echo "Error: Failed to generate config.js"
exit 1
fi

Copilot uses AI. Check for mistakes.
@cleot cleot marked this pull request as ready for review December 2, 2025 21:51
@cleot cleot requested review from mtbitcr and stefanbitcr December 2, 2025 21:51
@qodo-code-review
Copy link

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing audit logs: New runtime configuration usage and auth header injection add critical request behavior
but no added logging exists to audit when/what base URL or auth state is applied.

Referred Code
import { client as heyApiClient } from "@/generated/client/client.gen"
import * as sdk from "@/generated/client/sdk.gen"
import { env } from "@/lib/env"
import keycloak from "../keycloak"

heyApiClient.setConfig({
  baseUrl: env.apiBaseUrl,
})

// Add the auth token interceptor
heyApiClient.interceptors.request.use((request) => {
  if (keycloak.token!) {
    let headers = request.headers

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Env edge cases: The entrypoint script writes config.js without validating required envs or handling
missing/empty values, which may cause runtime failures without clear diagnostics.

Referred Code
#!/usr/bin/env sh
set -e

JSON_ENV=$(jq -n \
  --arg VITE_API_BASE_URL "$VITE_API_BASE_URL" \
  --arg VITE_API_MOCKING_ENABLED "$VITE_API_MOCKING_ENABLED" \
  --arg VITE_KEYCLOAK_URL "$VITE_KEYCLOAK_URL" \
  --arg VITE_KEYCLOAK_REALM "$VITE_KEYCLOAK_REALM" \
  --arg VITE_KEYCLOAK_CLIENT_ID "$VITE_KEYCLOAK_CLIENT_ID" \
  --arg VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING "$VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING" \
  '{VITE_API_BASE_URL: $VITE_API_BASE_URL, VITE_API_MOCKING_ENABLED: $VITE_API_MOCKING_ENABLED, VITE_KEYCLOAK_URL: $VITE_KEYCLOAK_URL, VITE_KEYCLOAK_REALM: $VITE_KEYCLOAK_REALM, VITE_KEYCLOAK_CLIENT_ID: $VITE_KEYCLOAK_CLIENT_ID, VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING: $VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING}')

cat <<EOF > /usr/share/nginx/html/config.js
window.__ENV__ = ${JSON_ENV};
EOF

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Unvalidated inputs: External configuration from window.ENV is consumed without validation (e.g., URL
format, booleans), which could enable misconfiguration or injection in downstream
requests.

Referred Code
type RuntimeEnv = Partial<{
  VITE_API_BASE_URL: string
  VITE_API_MOCKING_ENABLED: string
  VITE_KEYCLOAK_URL: string
  VITE_KEYCLOAK_REALM: string
  VITE_KEYCLOAK_CLIENT_ID: string
  VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING: string
}>

const runtimeEnv: RuntimeEnv =
  typeof window !== "undefined" ? (window as { __ENV__?: RuntimeEnv }).__ENV__ ?? {} : {}

const fallbackEnv = import.meta.env as ImportMetaEnv & RuntimeEnv

const getEnvValue = <K extends keyof RuntimeEnv>(key: K): RuntimeEnv[K] | undefined => {
  const value = runtimeEnv[key]

  if (value !== undefined && value !== null && value !== "") {
    return value
  }



 ... (clipped 13 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Automate environment variable handling

Modify the entrypoint script to dynamically build the configuration object by
gathering all environment variables prefixed with VITE_. This removes the need
to manually list each variable, making the system more maintainable.

Examples:

docker/entrypoint.d/00-env-config.sh [4-11]
JSON_ENV=$(jq -n \
  --arg VITE_API_BASE_URL "$VITE_API_BASE_URL" \
  --arg VITE_API_MOCKING_ENABLED "$VITE_API_MOCKING_ENABLED" \
  --arg VITE_KEYCLOAK_URL "$VITE_KEYCLOAK_URL" \
  --arg VITE_KEYCLOAK_REALM "$VITE_KEYCLOAK_REALM" \
  --arg VITE_KEYCLOAK_CLIENT_ID "$VITE_KEYCLOAK_CLIENT_ID" \
  --arg VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING "$VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING" \
  '{VITE_API_BASE_URL: $VITE_API_BASE_URL, VITE_API_MOCKING_ENABLED: $VITE_API_MOCKING_ENABLED, VITE_KEYCLOAK_URL: $VITE_KEYCLOAK_URL, VITE_KEYCLOAK_REALM: $VITE_KEYCLOAK_REALM, VITE_KEYCLOAK_CLIENT_ID: $VITE_KEYCLOAK_CLIENT_ID, VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING: $VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING}')

Solution Walkthrough:

Before:

# docker/entrypoint.d/00-env-config.sh

# Manually list each environment variable
JSON_ENV=$(jq -n \
  --arg VITE_API_BASE_URL "$VITE_API_BASE_URL" \
  --arg VITE_KEYCLOAK_URL "$VITE_KEYCLOAK_URL" \
  # ... and so on for each variable
  '{
    VITE_API_BASE_URL: $VITE_API_BASE_URL,
    VITE_KEYCLOAK_URL: $VITE_KEYCLOAK_URL,
    # ... and so on for each variable
  }')

# Write to config.js
echo "window.__ENV__ = ${JSON_ENV};" > /path/to/config.js

After:

# docker/entrypoint.d/00-env-config.sh

JSON_ENV='{}'

# Automatically find all variables starting with VITE_
for var in $(printenv | grep '^VITE_'); do
  key=$(echo "$var" | cut -d= -f1)
  value=$(echo "$var" | cut -d= -f2-)

  # Dynamically add key-value pair to JSON object
  JSON_ENV=$(echo "$JSON_ENV" | jq --arg k "$key" --arg v "$value" '. + {($k): $v}')
done

# Write to config.js
echo "window.__ENV__ = ${JSON_ENV};" > /path/to/config.js
Suggestion importance[1-10]: 7

__

Why: This is a valuable suggestion that improves the maintainability and scalability of the new runtime configuration system by automating the process in 00-env-config.sh, reducing manual effort and potential errors.

Medium
Possible issue
Validate required environment variables properly

Replace unsafe non-null assertions (!) on environment variables with a
validation function that throws an error if a required variable is missing,
ensuring the application fails fast.

src/lib/env.ts [25-34]

+const getRequiredEnvValue = <K extends keyof RuntimeEnv>(key: K): string => {
+  const value = getEnvValue(key)
+  if (!value) {
+    throw new Error(`Missing required environment variable: ${key}`)
+  }
+  return value as string
+}
+
 export const env = {
   devModeEnabled: fallbackEnv.DEV,
-  apiBaseUrl: getEnvValue("VITE_API_BASE_URL")!,
+  apiBaseUrl: getRequiredEnvValue("VITE_API_BASE_URL"),
   apiMocksEnabled: (getEnvValue("VITE_API_MOCKING_ENABLED") ?? "false") === "true",
-  keycloakUrl: getEnvValue("VITE_KEYCLOAK_URL")!,
-  keycloakRealm: getEnvValue("VITE_KEYCLOAK_REALM")!,
-  keycloakClientId: getEnvValue("VITE_KEYCLOAK_CLIENT_ID")!,
+  keycloakUrl: getRequiredEnvValue("VITE_KEYCLOAK_URL"),
+  keycloakRealm: getRequiredEnvValue("VITE_KEYCLOAK_REALM"),
+  keycloakClientId: getRequiredEnvValue("VITE_KEYCLOAK_CLIENT_ID"),
   crowdinInContextToolingEnabled:
     (getEnvValue("VITE_BITCR_DEV_INCLUDE_CROWDIN_IN_CONTEXT_TOOLING") ?? "false") === "true",
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that using non-null assertions for environment variables is unsafe and can lead to runtime errors. Implementing a fail-fast mechanism significantly improves the application's robustness and debuggability.

Medium
  • More

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants