Skip to content

PostgreSQL replacement with SQLite - #435

Open
lferreira86 wants to merge 26 commits into
mainfrom
lf-sqlite-test
Open

PostgreSQL replacement with SQLite #435
lferreira86 wants to merge 26 commits into
mainfrom
lf-sqlite-test

Conversation

@lferreira86

@lferreira86 lferreira86 commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Branch to test replacement of PostgreSQL with SQLite backend database.

  • Update deploy scripts (.bat .sh and _gui.sh) to create dockerfile and env file to facilitate deployment
  • Changes on database ORM to replace PostgreSQL with SQLite

Summary by CodeRabbit

  • New Features
    • Interactive local Docker deployment across deploy.sh, deploy.bat, and deploy_gui.sh, with selectable DB backend (sqlite/postgres), new vs replace/reuse modes, and automatic host port selection
    • Runtime support for DB_BACKEND with improved PostgreSQL readiness and optional schema setup
    • New CLI to export user–project permission data to stdout or CSV, with optional Auth0 login enrichment
  • Documentation
    • Added a “Deployment Scripts (Local Docker)” guide with parameters and multi-deployment examples
  • Tests
    • Expanded unit test coverage for sqlite/postgres configuration and startup behavior
  • Chores
    • Ignore deployment-generated override/env artifacts; added Docker Compose orchestration files

Commit git ignore for SQLite test deployment
Replacement of PostgreSQL as default database used for the MDV platform. Replacing with SQLite to better handle users/credentials. But keeping PostgrSQL as an option when decided by the user to use it. The deployment scripts build the environment according to what the user desire.
@netlify

netlify Bot commented Apr 30, 2026

Copy link
Copy Markdown

Deploy Preview for mdv-dev ready!

Name Link
🔨 Latest commit 752fcae
🔍 Latest deploy log https://app.netlify.com/projects/mdv-dev/deploys/6a5a423513d3e50008b04a77
😎 Deploy Preview https://deploy-preview-435--mdv-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@lferreira86 lferreira86 changed the title PostgrSQL replacement with SQLite PostgreSQL replacement with SQLite Apr 30, 2026
@coderabbitai

coderabbitai Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds interactive local Docker deployment scripts and docs, per-deployment env/override ignore rules, DB backend handling validated by tests (sqlite vs postgres), and a new CLI to export user–project associations with optional Auth0 login enrichment and CSV output.

Changes

Local deployment documentation and tooling

Layer / File(s) Summary
Deployment documentation and ignore rules
README.md, .gitignore
README section documents local Docker deployment scripts, configuration options, backend-specific behavior for sqlite and postgres (including reuse autodetection), multi-deployment workflows, and local image guidance; .gitignore adds entries to exclude deployment-generated .env.* and .docker-deploy.*.override.yml files.
Deployment script initialization and interactive prompts
deploy.sh
Introduces deployment-scoped variables and an interactive prompt flow that derives deployment name, action (new/replace/exit/rename), host port suggestion/retention, and per-deployment env file target; captures previous env state (DB backend, host, schema, user) for reuse/cleanup decisions.
Database provisioning and storage mode selection
deploy.sh
Implements shared-postgres provisioning for reuse mode and interactive storage-mode selection (create/reuse/host) with host folder existence checks, cleanup flags, and cross-backend/storage transition detection.
Environment and authentication method generation
deploy.sh
Extends env output with DB_BACKEND, POSTGRES_MODE, SQLITE_DB_PATH, DB_HOST, and DB_SCHEMA fields; replaces fixed auth generation with interactive selectable auth methods (dev/auth0/shibboleth) emitting provider-specific secrets, redirects, and configuration variables.
Docker Compose patching, overrides, and execution
deploy.sh
Patches downloaded compose for chosen app port and data mount based on storage mode, generates per-deployment override compose files wiring env_file and conditionally configuring postgres service reuse/dedicated networking, implements replace/cleanup flows, runs different startup sequences for sqlite vs postgres (including schema creation and container lifecycle management).

Database backend flexibility

Layer / File(s) Summary
Flask app database backend and schema initialization
python/mdvtools/dbutils/mdv_server_app.py
App startup conditionally invokes wait_for_database only for postgres; load_config reads and validates DB_BACKEND (sqlite|postgres), builds SQLAlchemy URIs from SQLITE_DB_PATH or postgres env/secrets with defaults, configures search_path when DB_SCHEMA is set, and creates schemas on startup before connectivity verification.
Database backend test coverage
python/mdvtools/dbutils/test/unit/test_mdv_server_app.py
Unit tests verify DB_BACKEND propagation in config and app initialization, sqlite URI generation with defaults and custom SQLITE_DB_PATH, fallback to sqlite for unrecognized backends, and conditional wait_for_database invocation for postgres-only mode.

User–project reporting CLI tool

Layer / File(s) Summary
CLI module, Auth0 integration, and DataFrame export
python/mdvtools/scripts/users_projects_dataframe.py
Scaffolding and sys.path adjustments; _fetch_auth0_login_stats() validates Auth0 config and paginates management API users filtered by connection; load_users_projects_df() queries and joins user–project rows inside app context and optionally merges Auth0 login stats; main() CLI supports --csv, --no-print, and --with-auth0-login-stats flags with CSV export to parent-created directories and DataFrame return.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • Taylor-CCB-Group/MDV#229: Modifies database readiness logic in mdv_server_app.py, overlapping with DB backend initialization and schema handling.
  • Taylor-CCB-Group/MDV#231: Touches deployment script logic in deploy_gui.sh, directly overlapping with per-deployment env and DB-backend configuration behavior.
  • Taylor-CCB-Group/MDV#242: Alters create_flask_app test configuration behavior in mdv_server_app.py, sharing code points handling test startup with this PR's DB backend logic.

Suggested reviewers

  • xinaesthete

Poem

🐰 I hopped through scripts and compose today,
Envs and ports now find their way,
SQLite whispers, Postgres stands tall,
Auth0 sings and exports them all,
Docker dances—deployments play. 🐳

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 68.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective—replacing PostgreSQL with SQLite as the database backend—which is central to the PR's scope across deployment scripts, database configuration, and testing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lf-sqlite-test

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.

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

Caution

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

⚠️ Outside diff range comments (2)
deploy_gui.sh (1)

149-163: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid source "$env_file" in the GUI deploy path too.

That executes .env.<deployment> as shell code. It also means saved values containing shell syntax can be mutated or executed on the next run.

Suggested fix
-  # Source the existing .env file to retain values
-  source "$env_file"
+  # Read only the keys this script needs; do not execute the file.
+  while IFS='=' read -r key value; do
+    case "$key" in
+      DB_BACKEND|DB_HOST|DB_SCHEMA|DB_USER|DB_NAME)
+        printf -v "$key" '%s' "$value"
+        ;;
+    esac
+  done < "$env_file"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deploy_gui.sh` around lines 149 - 163, The create_or_validate_env_file
function currently uses source "$env_file", which executes .env.<deployment> as
shell code; replace this with a safe parser that reads the file contents without
executing them and extracts the DB_* keys, then assign PREV_DB_BACKEND,
PREV_DB_HOST, PREV_DB_SCHEMA, PREV_DB_USER, and PREV_DB_NAME from the parsed
values. Implement a non-executing reader (e.g., read the file line-by-line and
parse lines matching ^DB_[A-Z_]+=, stripping quotes and not evaluating
expressions) and use those parsed strings instead of sourcing in
create_or_validate_env_file so saved values cannot be executed or mutated on
load.
deploy.sh (1)

194-207: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't source .env.<deployment> here.

This turns the generated env file into executable shell code. A hand-edited value like $(...) or backticks will run on the next deploy, and ordinary secrets containing shell metacharacters can be misread as well.

Suggested fix
-  # Source existing .env file to retain values
-  [ -f "$env_file" ] && source "$env_file"
+  # Read only the keys this script needs; do not execute the file.
+  if [ -f "$env_file" ]; then
+    while IFS='=' read -r key value; do
+      case "$key" in
+        DB_BACKEND|DB_HOST|DB_SCHEMA|DB_USER|DB_NAME)
+          printf -v "$key" '%s' "$value"
+          ;;
+      esac
+    done < "$env_file"
+  fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deploy.sh` around lines 194 - 207, The script currently unsafely executes the
env file via "[ -f "$env_file" ] && source "$env_file""; remove that line and
instead safely parse only the required DB_* keys into PREV_DB_BACKEND,
PREV_DB_HOST, PREV_DB_SCHEMA, PREV_DB_USER, PREV_DB_NAME by reading env_file as
data (e.g., use grep -E '^DB_BACKEND=' env_file | cut -d= -f2- or a while
IFS='=' read -r key val; case "$key" in
DB_BACKEND|DB_HOST|DB_SCHEMA|DB_USER|DB_NAME) assign sanitized values ;; esac
done) so no shell evaluation occurs and only the specific variables populate the
PREV_DB_* variables referenced later.
🧹 Nitpick comments (5)
docker-compose.yml (2)

6-7: 💤 Low value

Port mapping differs from documentation default.

The compose file maps host port 5056 to container port 5055, but the README documentation states the auto-suggested port starts at 5055. This could cause confusion for users following the documentation.

Consider aligning with documentation by using 5055:5055 or updating the README to clarify that 5056 is the default when using docker-compose.yml directly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker-compose.yml` around lines 6 - 7, The docker-compose ports mapping
currently uses "5056:5055", which diverges from the README's documented default
of port 5055; update the ports entry in docker-compose.yml to "5055:5055" to
align with documentation (or alternatively update the README to explicitly note
that docker-compose uses 5056 on the host), ensuring the change is made at the
"ports" mapping line so behavior and docs match.

40-46: 💤 Low value

Consider adding a health check for PostgreSQL.

The mdv_db service lacks a health check, which means depends_on only ensures the container starts, not that PostgreSQL is ready to accept connections. While the application handles this via wait_for_database(), adding a health check would improve container orchestration reliability.

💡 Suggested health check
   mdv_db:
     image: postgres:16
     volumes:
       - postgres-data:/var/lib/postgresql/data
     env_file:
       - .env  # Load database credentials from the .env file
     restart: always
+    healthcheck:
+      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER:-postgres}"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker-compose.yml` around lines 40 - 46, Add a Docker healthcheck to the
mdv_db service so Compose can detect when Postgres is ready (rather than only
started); update the mdv_db service definition to include a healthcheck that
runs a Postgres readiness probe (e.g., using pg_isready or psql) with sensible
parameters (interval, timeout, retries, and start_period) so dependents wait for
a healthy state before starting; keep the existing application-level
wait_for_database() but add this healthcheck to improve orchestration
reliability.
postgres (1)

1-1: 💤 Low value

Ambiguous filename and missing context.

This file named postgres with no extension appears to contain a user prompt string for deployment scripts. Consider:

  1. Renaming to something clearer like prompts/sqlite-volume-prompt.txt or embedding this directly in the deployment scripts
  2. Adding a trailing newline for POSIX compliance

The current name postgres is misleading since the content relates to SQLite switching behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@postgres` at line 1, The file named "postgres" contains a prompt string
"Switching sqlite- Remove old app volume \"cartography_mdv-data\"? (y/n) [n]:"
which is misleading and lacks a trailing newline; rename or relocate this file
to a clearer path (e.g., prompts/sqlite-volume-prompt.txt) or embed the prompt
directly into the deployment script that invokes it (reference the exact prompt
string above when searching), and ensure the file ends with a POSIX-compliant
trailing newline; also update any references to the old filename to the new
location to avoid confusion.
python/mdvtools/scripts/users_projects_dataframe.py (2)

95-122: 💤 Low value

Auth0 stats fetched outside app context.

_fetch_auth0_login_stats() accesses app.config (lines 37-40) but is called on line 122 after the with app.app_context(): block has started the query but before context exit. The function itself doesn't use a context wrapper, which means it relies on the caller's context.

Currently this works because the call is inside the with block, but the function's implementation accesses app.config without ensuring a context exists. Consider either:

  1. Documenting this dependency
  2. Moving the call outside the context block since app.config doesn't require an active context
-        auth0_login_stats = _fetch_auth0_login_stats() if include_auth0_login_stats else {}
+    # Fetch Auth0 stats outside app context (config access doesn't require context)
+    auth0_login_stats = _fetch_auth0_login_stats() if include_auth0_login_stats else {}
+    
+    with app.app_context():
+        # Query database...
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/mdvtools/scripts/users_projects_dataframe.py` around lines 95 - 122,
The call to _fetch_auth0_login_stats relies on app config but the function
itself doesn't ensure a Flask app context; either make the function context-safe
or call it outside the with app.app_context(): specifically, update
_fetch_auth0_login_stats to obtain config via flask.current_app (or accept an
app parameter and use with app.app_context() internally) so it no longer depends
on the caller's context, or alternatively move the _fetch_auth0_login_stats()
invocation out of the with app.app_context(): block; refer to the
_fetch_auth0_login_stats symbol and the existing with app.app_context(): usage
to locate where to change.

134-135: 💤 Low value

Pyright false positive on DataFrame columns parameter.

The static analysis error on pd.DataFrame(columns=columns) is a known false positive with pandas type stubs. The code is correct at runtime. You can silence this with a type ignore comment if desired:

return pd.DataFrame(columns=columns)  # type: ignore[arg-type]

The same applies to line 164.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/mdvtools/scripts/users_projects_dataframe.py` around lines 134 - 135,
The Pyright false positive on the pd.DataFrame(columns=columns) call should be
silenced by adding a type ignore comment to the return statements; update the
two occurrences where you return an empty DataFrame (the branch starting with
"if not rows" that calls pd.DataFrame(columns=columns) and the similar return
around line 164) to include "# type: ignore[arg-type]" after the
pd.DataFrame(...) call so the static checker ignores the known pandas stub
mismatch for the columns parameter.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@deploy_gui.sh`:
- Around line 82-103: The DEPLOYMENT_NAME from the Zenity prompts (initial entry
and the rename branch) is not validated for unsafe characters and can inject
path separators or quotes into generated filenames (e.g.,
.env.${DEPLOYMENT_NAME}, .docker-deploy.${DEPLOYMENT_NAME}.override.yml) and
DB_SCHEMA; add the same safe-name validation used elsewhere immediately after
the initial DEPLOYMENT_NAME assignment and again after the rename prompt:
validate against a strict pattern (e.g., allow only [A-Za-z0-9._-] and forbid
slashes/quotes), and if the name fails validation show a zenity error and exit
(or reprompt) so only safe filenames are produced; update the logic that handles
DEPLOYMENT_NAME, the rename flow where DEPLOYMENT_NAME is reassigned, and any
subsequent checks that assume a valid name.
- Around line 59-67: The regex in get_existing_deployment_port() uses an
unescaped "->" which breaks the [[ ... =~ ... ]] expression; update the match
pattern to escape the greater-than so the shell parses it correctly, e.g. change
the conditional to: [[ "$ports_line" =~ (0\.0\.0\.0|\[::\]):([0-9]+)-\>5055 ]],
keeping the RHS unquoted so BASH_REMATCH[2] still captures the port; leave the
echo of BASH_REMATCH[2] unchanged.

In `@deploy.bat`:
- Around line 25-53: Validate and sanitize DEPLOYMENT_NAME every time it is set
(both initial prompt and inside the "rename" branch) before interpolating into
commands: add a validation step after the initial set /p DEPLOYMENT_NAME and
again after the rename prompt that rejects or re-prompts on any disallowed
characters (e.g. &|%!"^<>/\\ and whitespace) or enforces an allowlist pattern
(e.g. [A-Za-z0-9_.-]); if invalid, print an error and exit/reprompt. Apply this
same validation before using DEPLOYMENT_NAME in the docker filter loop, building
ENV_FILE, and any powershell/cmd redirections so you never interpolate an
unchecked value; reference the variables DEPLOYMENT_NAME, DEPLOY_ACTION,
HAS_EXISTING_DEPLOYMENT, and ENV_FILE when adding these checks.
- Line 2: The script enables delayed expansion globally with the setlocal
EnableDelayedExpansion directive which will corrupt secrets containing "!" when
reading or parsing values; modify the flow to DisableDelayedExpansion before any
secret reads or file parsing (references: set /p prompts used to capture secrets
and the file parsing logic mentioned around the original file parsing block),
then re-enable only where necessary (wrap only the blocks that require delayed
expansion around setlocal EnableDelayedExpansion) and ensure variables that are
later expanded as !VAR! (noted in the review around the expansions at lines
referenced) are handled with delayed expansion enabled only when those
expansions are safe; in short, switch to setlocal DisableDelayedExpansion before
secret capture/parsing and use setlocal EnableDelayedExpansion only for the
minimal blocks that need it, restoring previous state as needed.

In `@deploy.sh`:
- Around line 130-145: DEPLOYMENT_NAME is reused in filenames and DB schema and
isn't validated after user input or after the rename flow, allowing unsafe
values; add a whitelist validation (e.g., allow only [A-Za-z0-9._-] and forbid
sequences like ".." and characters like "/" and "\" and quotes) applied
immediately after setting DEPLOYMENT_NAME from deployment_name_input and again
after reading new_deployment_name in the rename branch (referencing
DEPLOYMENT_NAME and new_deployment_name), and if the value fails the regex or is
empty, print an error and exit 1 so only safe names are used for
.env.${DEPLOYMENT_NAME}, .docker-deploy.${DEPLOYMENT_NAME}.override.yml and
DB_SCHEMA.
- Around line 107-115: The regex in get_existing_deployment_port uses an
unescaped '>' causing a shell parse error; fix it by assigning the pattern to a
variable (e.g., port_pattern) and use that in the [[ ... =~ ... ]] test,
escaping the arrow as \-> (e.g., "(0\.0\.0\.0|\[::\]):([0-9]+)\->5055") so the
shell parses correctly and BASH_REMATCH[2] still contains the port.

In `@python/mdvtools/dbutils/mdv_server_app.py`:
- Around line 223-233: The code builds SQL by interpolating db_schema directly
into text(...) which risks SQL injection; change the CREATE SCHEMA call to
safely quote or validate the identifier before executing: obtain a safe quoted
identifier via schema_engine.dialect.identifier_preparer.quote(db_schema) (or
use sqlalchemy.schema.CreateSchema) and use that quoted value in the text() call
instead of raw f-string interpolation, and/or add a simple validation (e.g.,
allow only [A-Za-z0-9_\\-] or similar) on db_schema before attempting to create
the schema; update the block around create_engine, schema_engine, and
schema_connection to use the quoted identifier (or CreateSchema) when calling
schema_connection.execute(...) so the schema name cannot inject SQL.

In `@python/mdvtools/scripts/users_projects_dataframe.py`:
- Around line 42-55: The variables auth0_domain, client_id, client_secret, and
auth0_db_connection are checked with if not all(...) but Pyright still treats
them as Optional; add explicit runtime type narrowing before use (e.g., assert
statements or explicit casts) to guarantee they are str for GetToken and Auth0
calls: after the existing if-block add assertions like assert auth0_domain is
not None and assert client_id is not None etc., or cast each to str when passing
into GetToken(... ) and Auth0(...), ensuring symbols token_client,
mgmt_api_token, GetToken, and Auth0 receive properly narrowed string types.

---

Outside diff comments:
In `@deploy_gui.sh`:
- Around line 149-163: The create_or_validate_env_file function currently uses
source "$env_file", which executes .env.<deployment> as shell code; replace this
with a safe parser that reads the file contents without executing them and
extracts the DB_* keys, then assign PREV_DB_BACKEND, PREV_DB_HOST,
PREV_DB_SCHEMA, PREV_DB_USER, and PREV_DB_NAME from the parsed values. Implement
a non-executing reader (e.g., read the file line-by-line and parse lines
matching ^DB_[A-Z_]+=, stripping quotes and not evaluating expressions) and use
those parsed strings instead of sourcing in create_or_validate_env_file so saved
values cannot be executed or mutated on load.

In `@deploy.sh`:
- Around line 194-207: The script currently unsafely executes the env file via
"[ -f "$env_file" ] && source "$env_file""; remove that line and instead safely
parse only the required DB_* keys into PREV_DB_BACKEND, PREV_DB_HOST,
PREV_DB_SCHEMA, PREV_DB_USER, PREV_DB_NAME by reading env_file as data (e.g.,
use grep -E '^DB_BACKEND=' env_file | cut -d= -f2- or a while IFS='=' read -r
key val; case "$key" in DB_BACKEND|DB_HOST|DB_SCHEMA|DB_USER|DB_NAME) assign
sanitized values ;; esac done) so no shell evaluation occurs and only the
specific variables populate the PREV_DB_* variables referenced later.

---

Nitpick comments:
In `@docker-compose.yml`:
- Around line 6-7: The docker-compose ports mapping currently uses "5056:5055",
which diverges from the README's documented default of port 5055; update the
ports entry in docker-compose.yml to "5055:5055" to align with documentation (or
alternatively update the README to explicitly note that docker-compose uses 5056
on the host), ensuring the change is made at the "ports" mapping line so
behavior and docs match.
- Around line 40-46: Add a Docker healthcheck to the mdv_db service so Compose
can detect when Postgres is ready (rather than only started); update the mdv_db
service definition to include a healthcheck that runs a Postgres readiness probe
(e.g., using pg_isready or psql) with sensible parameters (interval, timeout,
retries, and start_period) so dependents wait for a healthy state before
starting; keep the existing application-level wait_for_database() but add this
healthcheck to improve orchestration reliability.

In `@postgres`:
- Line 1: The file named "postgres" contains a prompt string "Switching sqlite-
Remove old app volume \"cartography_mdv-data\"? (y/n) [n]:" which is misleading
and lacks a trailing newline; rename or relocate this file to a clearer path
(e.g., prompts/sqlite-volume-prompt.txt) or embed the prompt directly into the
deployment script that invokes it (reference the exact prompt string above when
searching), and ensure the file ends with a POSIX-compliant trailing newline;
also update any references to the old filename to the new location to avoid
confusion.

In `@python/mdvtools/scripts/users_projects_dataframe.py`:
- Around line 95-122: The call to _fetch_auth0_login_stats relies on app config
but the function itself doesn't ensure a Flask app context; either make the
function context-safe or call it outside the with app.app_context():
specifically, update _fetch_auth0_login_stats to obtain config via
flask.current_app (or accept an app parameter and use with app.app_context()
internally) so it no longer depends on the caller's context, or alternatively
move the _fetch_auth0_login_stats() invocation out of the with
app.app_context(): block; refer to the _fetch_auth0_login_stats symbol and the
existing with app.app_context(): usage to locate where to change.
- Around line 134-135: The Pyright false positive on the
pd.DataFrame(columns=columns) call should be silenced by adding a type ignore
comment to the return statements; update the two occurrences where you return an
empty DataFrame (the branch starting with "if not rows" that calls
pd.DataFrame(columns=columns) and the similar return around line 164) to include
"# type: ignore[arg-type]" after the pd.DataFrame(...) call so the static
checker ignores the known pandas stub mismatch for the columns parameter.
🪄 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

Run ID: fbdbc141-67fe-4a79-aaaf-152cd71dd38e

📥 Commits

Reviewing files that changed from the base of the PR and between 3c7659b and 71f8522.

📒 Files selected for processing (11)
  • .gitignore
  • README.md
  • deploy.bat
  • deploy.sh
  • deploy_gui.sh
  • docker-compose.yml
  • docker-sqlite.override.yml
  • postgres
  • python/mdvtools/dbutils/mdv_server_app.py
  • python/mdvtools/dbutils/test/unit/test_mdv_server_app.py
  • python/mdvtools/scripts/users_projects_dataframe.py

Comment thread deploy_gui.sh
Comment thread deploy_gui.sh
Comment on lines +82 to +103
DEPLOYMENT_NAME=$(zenity --entry --title="Deployment Name" --text="Deployment name:" --entry-text="mdv")
if [ -z "$DEPLOYMENT_NAME" ]; then
DEPLOYMENT_NAME="mdv"
fi

if docker ps -aq --filter "label=com.docker.compose.project=${DEPLOYMENT_NAME}" | grep -q .; then
DEPLOY_ACTION=$(zenity --list --radiolist \
--title="Existing Deployment Found" \
--text="Deployment '${DEPLOYMENT_NAME}' already exists. What would you like to do?" \
--column="Select" --column="Action" \
TRUE "redeploy" FALSE "rename" FALSE "exit")
if [ -z "$DEPLOY_ACTION" ] || [ "$DEPLOY_ACTION" = "exit" ]; then
exit 0
elif [ "$DEPLOY_ACTION" = "rename" ]; then
DEPLOYMENT_NAME=$(zenity --entry --title="New Deployment Name" --text="Enter a new deployment name:" --entry-text="${DEPLOYMENT_NAME}_new")
if [ -z "$DEPLOYMENT_NAME" ]; then
zenity --error --text="Deployment name cannot be empty."
exit 1
fi
if docker ps -aq --filter "label=com.docker.compose.project=${DEPLOYMENT_NAME}" | grep -q .; then
zenity --error --text="Deployment '${DEPLOYMENT_NAME}' already exists. Choose a different name."
exit 1

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Apply the same safe-name validation in the Zenity flow.

DEPLOYMENT_NAME is later reused in .env.${DEPLOYMENT_NAME}, .docker-deploy.${DEPLOYMENT_NAME}.override.yml, and DB_SCHEMA. Allowing path separators or quotes here can break file generation and later schema cleanup.

Suggested fix
   DEPLOYMENT_NAME=$(zenity --entry --title="Deployment Name" --text="Deployment name:" --entry-text="mdv")
   if [ -z "$DEPLOYMENT_NAME" ]; then
     DEPLOYMENT_NAME="mdv"
   fi
+  if [[ ! "$DEPLOYMENT_NAME" =~ ^[A-Za-z0-9._-]+$ ]]; then
+    zenity --error --text="Deployment name may only contain letters, numbers, dot, underscore, and dash."
+    exit 1
+  fi

Apply the same validation after the rename prompt too.

📝 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
DEPLOYMENT_NAME=$(zenity --entry --title="Deployment Name" --text="Deployment name:" --entry-text="mdv")
if [ -z "$DEPLOYMENT_NAME" ]; then
DEPLOYMENT_NAME="mdv"
fi
if docker ps -aq --filter "label=com.docker.compose.project=${DEPLOYMENT_NAME}" | grep -q .; then
DEPLOY_ACTION=$(zenity --list --radiolist \
--title="Existing Deployment Found" \
--text="Deployment '${DEPLOYMENT_NAME}' already exists. What would you like to do?" \
--column="Select" --column="Action" \
TRUE "redeploy" FALSE "rename" FALSE "exit")
if [ -z "$DEPLOY_ACTION" ] || [ "$DEPLOY_ACTION" = "exit" ]; then
exit 0
elif [ "$DEPLOY_ACTION" = "rename" ]; then
DEPLOYMENT_NAME=$(zenity --entry --title="New Deployment Name" --text="Enter a new deployment name:" --entry-text="${DEPLOYMENT_NAME}_new")
if [ -z "$DEPLOYMENT_NAME" ]; then
zenity --error --text="Deployment name cannot be empty."
exit 1
fi
if docker ps -aq --filter "label=com.docker.compose.project=${DEPLOYMENT_NAME}" | grep -q .; then
zenity --error --text="Deployment '${DEPLOYMENT_NAME}' already exists. Choose a different name."
exit 1
DEPLOYMENT_NAME=$(zenity --entry --title="Deployment Name" --text="Deployment name:" --entry-text="mdv")
if [ -z "$DEPLOYMENT_NAME" ]; then
DEPLOYMENT_NAME="mdv"
fi
if [[ ! "$DEPLOYMENT_NAME" =~ ^[A-Za-z0-9._-]+$ ]]; then
zenity --error --text="Deployment name may only contain letters, numbers, dot, underscore, and dash."
exit 1
fi
if docker ps -aq --filter "label=com.docker.compose.project=${DEPLOYMENT_NAME}" | grep -q .; then
DEPLOY_ACTION=$(zenity --list --radiolist \
--title="Existing Deployment Found" \
--text="Deployment '${DEPLOYMENT_NAME}' already exists. What would you like to do?" \
--column="Select" --column="Action" \
TRUE "redeploy" FALSE "rename" FALSE "exit")
if [ -z "$DEPLOY_ACTION" ] || [ "$DEPLOY_ACTION" = "exit" ]; then
exit 0
elif [ "$DEPLOY_ACTION" = "rename" ]; then
DEPLOYMENT_NAME=$(zenity --entry --title="New Deployment Name" --text="Enter a new deployment name:" --entry-text="${DEPLOYMENT_NAME}_new")
if [ -z "$DEPLOYMENT_NAME" ]; then
zenity --error --text="Deployment name cannot be empty."
exit 1
fi
if docker ps -aq --filter "label=com.docker.compose.project=${DEPLOYMENT_NAME}" | grep -q .; then
zenity --error --text="Deployment '${DEPLOYMENT_NAME}' already exists. Choose a different name."
exit 1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deploy_gui.sh` around lines 82 - 103, The DEPLOYMENT_NAME from the Zenity
prompts (initial entry and the rename branch) is not validated for unsafe
characters and can inject path separators or quotes into generated filenames
(e.g., .env.${DEPLOYMENT_NAME}, .docker-deploy.${DEPLOYMENT_NAME}.override.yml)
and DB_SCHEMA; add the same safe-name validation used elsewhere immediately
after the initial DEPLOYMENT_NAME assignment and again after the rename prompt:
validate against a strict pattern (e.g., allow only [A-Za-z0-9._-] and forbid
slashes/quotes), and if the name fails validation show a zenity error and exit
(or reprompt) so only safe filenames are produced; update the logic that handles
DEPLOYMENT_NAME, the rename flow where DEPLOYMENT_NAME is reassigned, and any
subsequent checks that assume a valid name.

Comment thread deploy.bat
@@ -1,4 +1,5 @@
@echo off
setlocal EnableDelayedExpansion

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's locate the deploy.bat file
find . -name "deploy.bat" -type f

Repository: Taylor-CCB-Group/MDV

Length of output: 77


🏁 Script executed:

# Read the deploy.bat file to examine the code structure
cat -n deploy.bat | head -50

Repository: Taylor-CCB-Group/MDV

Length of output: 2230


🏁 Script executed:

# Check the specific lines mentioned in the review
cat -n deploy.bat | sed -n '1,10p; 143,155p; 321,340p; 347,387p'

Repository: Taylor-CCB-Group/MDV

Length of output: 4536


🌐 Web query:

cmd.exe EnableDelayedExpansion exclamation mark ! character in variable value corruption

💡 Result:

In Windows batch, ! “corruption” is caused by delayed variable expansion: when delayed expansion is enabled, cmd parses exclamation marks as delimiters for !var! expansions, so any literal exclamation marks in data (especially inside FOR / FOR /F loops and parenthesized blocks) get consumed or transformed. What’s happening in your case - Your script enables delayed expansion (SETLOCAL ... ENABLEDELAYEDEXPANSION). - You then store line text containing ! into environment variables and later read it back using delayed expansion mechanics (directly or indirectly). With delayed expansion on, the cmd parser treats parts between !…! as variable references; if there’s a single ! (or there isn’t a matching variable), it effectively disappears/changes when expansions happen. - This is a known pitfall of delayed expansion interacting with FOR /F and variable contents containing !. Fix patterns (pick one) 1) Temporarily disable delayed expansion while capturing/handling the line - The common workaround is to toggle delayed expansion off for the specific block where you expand the FOR/F variable and store/use it, then turn it back on. Example pattern (based on the accepted solution for this exact symptom): setlocal EnableExtensions EnableDelayedExpansion for /f "tokens=*" %%a in (bang1.txt) do ( setlocal DisableDelayedExpansion set "line=%%a" setlocal EnableDelayedExpansion call :doit1 line endlocal endlocal ) 2) Toggle delayed expansion only around the variable assignment/read - Disable delayed expansion before you SET a variable that may contain !, and re-enable it only when you later need !var! behavior. - This is repeatedly recommended: literal ! must be preserved by having delayed expansion disabled during the “set/parse” of that literal. 3) Alternative escaping: escape literal ! when delayed expansion is required - You can escape ! as ^! in the command context where delayed expansion is enabled. - But this can be tricky depending on quoting and which parsing phase happens next; disabling delayed expansion is usually more reliable than manual caret-escaping. Bottom line - Yes: this is expected behavior from delayed expansion. - The reliable solution is to disable delayed expansion while you move/print/store data that can contain literal exclamation marks (or escape those literals as ^! when you must keep delayed expansion on).

Citations:


🌐 Web query:

batch script delayed expansion ! special character handling data loss

💡 Result:

In Windows batch scripts, enabling delayed expansion with setlocal EnableDelayedExpansion causes the exclamation mark ! to become a special delimiter for dynamic variable expansion (e.g., !var!). This leads to data loss when processing strings containing literal ! characters, such as filenames, paths, or text lines. When delayed expansion is enabled: - During variable assignment (e.g., set "var=%%f" in a FOR loop), ! in the source string (like a FOR parameter %%f) is interpreted as the start/end of a variable reference. - Unmatched ! are removed entirely. - Paired !var! are replaced by the value of var (empty if undefined), corrupting the string. This occurs because command lines are parsed in phases: percent expansion first, then delayed expansion after FOR parameters are expanded. FOR variables like %%f expand before delayed expansion, exposing embedded ! to interpretation. Examples of data loss: - Filename "file!name.txt" becomes "filename.txt" when assigned to a variable. - Paths with ! truncate after the first !. Official behavior confirmed in Microsoft docs: delayed expansion uses ! as variable delimiters, enabled via setlocal enabledelayedexpansion. Solutions to prevent data loss: 1. Temporarily disable delayed expansion when assigning variables holding potentially unsafe strings: for %%f in (*) do ( setlocal DisableDelayedExpansion set "safe=%%f" setlocal EnableDelayedExpansion echo(!safe! endlocal ) This preserves ! during assignment, as delayed expansion is off. 2. Use CALL for delayed expansion without enabling the feature globally: call set "result=%%varname%%" 3. Toggle per-line with nested SETLOCAL/ENDLOCAL or FOR tricks to pass values over ENDLOCAL. 4. Avoid delayed expansion in loops processing files: Use pure percent expansion or restructure code. Prioritize disabling delayed expansion during string capture from FOR loops or file reads. Re-enable only for safe variable reads. This is the standard fix in batch scripting communities (SS64, Stack Overflow). No changes in Windows up to 2026; behavior is by design for delayed expansion.

Citations:


Global delayed expansion will corrupt secrets containing ! characters.

In cmd.exe, EnableDelayedExpansion makes ! a special delimiter for variable expansion. When secrets are captured via set /p (lines 321, 328) or file parsing (line 148) and later expanded as !VAR! (lines 358, 370, 375), any literal ! in the value will be removed or misinterpreted, silently corrupting database passwords, Flask secrets, and API keys. This is documented behavior when delayed expansion parses variable contents.

Disable delayed expansion while reading and writing secret-bearing values, then re-enable only for blocks that need it:

setlocal DisableDelayedExpansion
set /p FLASK_SECRET_KEY=Enter FLASK_SECRET_KEY [...]:
setlocal EnableDelayedExpansion

Also applies to: 143-155, 321-340, 347-387

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deploy.bat` at line 2, The script enables delayed expansion globally with the
setlocal EnableDelayedExpansion directive which will corrupt secrets containing
"!" when reading or parsing values; modify the flow to DisableDelayedExpansion
before any secret reads or file parsing (references: set /p prompts used to
capture secrets and the file parsing logic mentioned around the original file
parsing block), then re-enable only where necessary (wrap only the blocks that
require delayed expansion around setlocal EnableDelayedExpansion) and ensure
variables that are later expanded as !VAR! (noted in the review around the
expansions at lines referenced) are handled with delayed expansion enabled only
when those expansions are safe; in short, switch to setlocal
DisableDelayedExpansion before secret capture/parsing and use setlocal
EnableDelayedExpansion only for the minimal blocks that need it, restoring
previous state as needed.

Comment thread deploy.bat
Comment on lines +25 to +53
set /p DEPLOYMENT_NAME=Deployment name [mdv]:
if "%DEPLOYMENT_NAME%"=="" set DEPLOYMENT_NAME=mdv
set HAS_EXISTING_DEPLOYMENT=0
for /f %%i in ('docker ps -aq --filter "label=com.docker.compose.project=%DEPLOYMENT_NAME%"') do set HAS_EXISTING_DEPLOYMENT=1
if "%HAS_EXISTING_DEPLOYMENT%"=="1" (
set /p DEPLOY_ACTION=Deployment "%DEPLOYMENT_NAME%" exists. Action ^(redeploy/rename/exit^) [redeploy]:
if /I "!DEPLOY_ACTION!"=="" set DEPLOY_ACTION=redeploy
if /I "!DEPLOY_ACTION!"=="exit" exit /b 0
if /I "!DEPLOY_ACTION!"=="rename" (
set /p DEPLOYMENT_NAME=New deployment name:
if "!DEPLOYMENT_NAME!"=="" (
echo Error: deployment name cannot be empty.
exit /b 1
)
set HAS_EXISTING_DEPLOYMENT=0
for /f %%i in ('docker ps -aq --filter "label=com.docker.compose.project=!DEPLOYMENT_NAME!"') do set HAS_EXISTING_DEPLOYMENT=1
if "!HAS_EXISTING_DEPLOYMENT!"=="1" (
echo Error: deployment "!DEPLOYMENT_NAME!" already exists. Please choose a different name.
exit /b 1
)
set DEPLOY_MODE=new
) else (
set DEPLOY_MODE=replace
)
) else (
set DEPLOY_MODE=new
echo No existing deployment found for "%DEPLOYMENT_NAME%". Using new mode.
)
set ENV_FILE=.env.%DEPLOYMENT_NAME%

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.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Validate DEPLOYMENT_NAME before interpolating it into cmd and PowerShell commands.

In this script the deployment name flows into docker, powershell, redirections, filenames, and DB_SCHEMA. Characters like &, |, %, !, <, >, /, and quotes can break the command line or target the wrong file entirely.

Suggested fix
 set /p DEPLOYMENT_NAME=Deployment name [mdv]:
 if "%DEPLOYMENT_NAME%"=="" set DEPLOYMENT_NAME=mdv
+echo(%DEPLOYMENT_NAME%| findstr /R "^[A-Za-z0-9][A-Za-z0-9._-]*$" >nul || (
+    echo Error: deployment name may only contain letters, numbers, dot, underscore, and dash.
+    exit /b 1
+)

Apply the same check after the rename prompt as well.

📝 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
set /p DEPLOYMENT_NAME=Deployment name [mdv]:
if "%DEPLOYMENT_NAME%"=="" set DEPLOYMENT_NAME=mdv
set HAS_EXISTING_DEPLOYMENT=0
for /f %%i in ('docker ps -aq --filter "label=com.docker.compose.project=%DEPLOYMENT_NAME%"') do set HAS_EXISTING_DEPLOYMENT=1
if "%HAS_EXISTING_DEPLOYMENT%"=="1" (
set /p DEPLOY_ACTION=Deployment "%DEPLOYMENT_NAME%" exists. Action ^(redeploy/rename/exit^) [redeploy]:
if /I "!DEPLOY_ACTION!"=="" set DEPLOY_ACTION=redeploy
if /I "!DEPLOY_ACTION!"=="exit" exit /b 0
if /I "!DEPLOY_ACTION!"=="rename" (
set /p DEPLOYMENT_NAME=New deployment name:
if "!DEPLOYMENT_NAME!"=="" (
echo Error: deployment name cannot be empty.
exit /b 1
)
set HAS_EXISTING_DEPLOYMENT=0
for /f %%i in ('docker ps -aq --filter "label=com.docker.compose.project=!DEPLOYMENT_NAME!"') do set HAS_EXISTING_DEPLOYMENT=1
if "!HAS_EXISTING_DEPLOYMENT!"=="1" (
echo Error: deployment "!DEPLOYMENT_NAME!" already exists. Please choose a different name.
exit /b 1
)
set DEPLOY_MODE=new
) else (
set DEPLOY_MODE=replace
)
) else (
set DEPLOY_MODE=new
echo No existing deployment found for "%DEPLOYMENT_NAME%". Using new mode.
)
set ENV_FILE=.env.%DEPLOYMENT_NAME%
set /p DEPLOYMENT_NAME=Deployment name [mdv]:
if "%DEPLOYMENT_NAME%"=="" set DEPLOYMENT_NAME=mdv
echo(%DEPLOYMENT_NAME%| findstr /R "^[A-Za-z0-9][A-Za-z0-9._-]*$" >nul || (
echo Error: deployment name may only contain letters, numbers, dot, underscore, and dash.
exit /b 1
)
set HAS_EXISTING_DEPLOYMENT=0
for /f %%i in ('docker ps -aq --filter "label=com.docker.compose.project=%DEPLOYMENT_NAME%"') do set HAS_EXISTING_DEPLOYMENT=1
if "%HAS_EXISTING_DEPLOYMENT%"=="1" (
set /p DEPLOY_ACTION=Deployment "%DEPLOYMENT_NAME%" exists. Action ^(redeploy/rename/exit^) [redeploy]:
if /I "!DEPLOY_ACTION!"=="" set DEPLOY_ACTION=redeploy
if /I "!DEPLOY_ACTION!"=="exit" exit /b 0
if /I "!DEPLOY_ACTION!"=="rename" (
set /p DEPLOYMENT_NAME=New deployment name:
if "!DEPLOYMENT_NAME!"=="" (
echo Error: deployment name cannot be empty.
exit /b 1
)
set HAS_EXISTING_DEPLOYMENT=0
for /f %%i in ('docker ps -aq --filter "label=com.docker.compose.project=!DEPLOYMENT_NAME!"') do set HAS_EXISTING_DEPLOYMENT=1
if "!HAS_EXISTING_DEPLOYMENT!"=="1" (
echo Error: deployment "!DEPLOYMENT_NAME!" already exists. Please choose a different name.
exit /b 1
)
set DEPLOY_MODE=new
) else (
set DEPLOY_MODE=replace
)
) else (
set DEPLOY_MODE=new
echo No existing deployment found for "%DEPLOYMENT_NAME%". Using new mode.
)
set ENV_FILE=.env.%DEPLOYMENT_NAME%
🧰 Tools
🪛 Blinter (1.0.112)

[error] 30-30: Potential command injection vulnerability. Explanation: User input used in commands without validation could allow malicious code execution. Recommendation: Validate and sanitize all user input before using in commands. Context: User input used in command without validation

(SEC001)


[error] 53-53: Unsafe SET command usage. Explanation: SET commands without proper validation or quoting can cause security issues. Recommendation: Always quote SET values and validate input: SET "var=safe value". Context: SET command value should be quoted for safety

(SEC002)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deploy.bat` around lines 25 - 53, Validate and sanitize DEPLOYMENT_NAME every
time it is set (both initial prompt and inside the "rename" branch) before
interpolating into commands: add a validation step after the initial set /p
DEPLOYMENT_NAME and again after the rename prompt that rejects or re-prompts on
any disallowed characters (e.g. &|%!"^<>/\\ and whitespace) or enforces an
allowlist pattern (e.g. [A-Za-z0-9_.-]); if invalid, print an error and
exit/reprompt. Apply this same validation before using DEPLOYMENT_NAME in the
docker filter loop, building ENV_FILE, and any powershell/cmd redirections so
you never interpolate an unchecked value; reference the variables
DEPLOYMENT_NAME, DEPLOY_ACTION, HAS_EXISTING_DEPLOYMENT, and ENV_FILE when
adding these checks.

Comment thread deploy.sh
Comment thread deploy.sh
Comment on lines +130 to +145
read -p "Deployment name [mdv]: " deployment_name_input
DEPLOYMENT_NAME=${deployment_name_input:-mdv}

if docker ps -aq --filter "label=com.docker.compose.project=${DEPLOYMENT_NAME}" | grep -q .; then
read -p "Deployment '${DEPLOYMENT_NAME}' exists. Action (redeploy/rename/exit) [redeploy]: " deploy_action_input
DEPLOY_ACTION=$(echo "${deploy_action_input:-redeploy}" | tr '[:upper:]' '[:lower:]' | xargs)
if [[ "$DEPLOY_ACTION" == "exit" ]]; then
echo "Exiting deployment."
exit 0
elif [[ "$DEPLOY_ACTION" == "rename" ]]; then
read -p "New deployment name: " new_deployment_name
if [[ -z "$new_deployment_name" ]]; then
echo -e "${RED}Error: deployment name cannot be empty.${NC}"
exit 1
fi
DEPLOYMENT_NAME="$new_deployment_name"

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Whitelist DEPLOYMENT_NAME before reusing it as a filename and schema.

This value is later written into .env.${DEPLOYMENT_NAME}, .docker-deploy.${DEPLOYMENT_NAME}.override.yml, and DB_SCHEMA. Names containing /, .., or " can escape the expected path or break the later schema cleanup SQL.

Suggested fix
   read -p "Deployment name [mdv]: " deployment_name_input
   DEPLOYMENT_NAME=${deployment_name_input:-mdv}
+  if [[ ! "$DEPLOYMENT_NAME" =~ ^[A-Za-z0-9._-]+$ ]]; then
+    echo -e "${RED}Error: deployment name may only contain letters, numbers, dot, underscore, and dash.${NC}"
+    exit 1
+  fi

Apply the same validation after the rename prompt as well.

📝 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
read -p "Deployment name [mdv]: " deployment_name_input
DEPLOYMENT_NAME=${deployment_name_input:-mdv}
if docker ps -aq --filter "label=com.docker.compose.project=${DEPLOYMENT_NAME}" | grep -q .; then
read -p "Deployment '${DEPLOYMENT_NAME}' exists. Action (redeploy/rename/exit) [redeploy]: " deploy_action_input
DEPLOY_ACTION=$(echo "${deploy_action_input:-redeploy}" | tr '[:upper:]' '[:lower:]' | xargs)
if [[ "$DEPLOY_ACTION" == "exit" ]]; then
echo "Exiting deployment."
exit 0
elif [[ "$DEPLOY_ACTION" == "rename" ]]; then
read -p "New deployment name: " new_deployment_name
if [[ -z "$new_deployment_name" ]]; then
echo -e "${RED}Error: deployment name cannot be empty.${NC}"
exit 1
fi
DEPLOYMENT_NAME="$new_deployment_name"
read -p "Deployment name [mdv]: " deployment_name_input
DEPLOYMENT_NAME=${deployment_name_input:-mdv}
if [[ ! "$DEPLOYMENT_NAME" =~ ^[A-Za-z0-9._-]+$ ]]; then
echo -e "${RED}Error: deployment name may only contain letters, numbers, dot, underscore, and dash.${NC}"
exit 1
fi
if docker ps -aq --filter "label=com.docker.compose.project=${DEPLOYMENT_NAME}" | grep -q .; then
read -p "Deployment '${DEPLOYMENT_NAME}' exists. Action (redeploy/rename/exit) [redeploy]: " deploy_action_input
DEPLOY_ACTION=$(echo "${deploy_action_input:-redeploy}" | tr '[:upper:]' '[:lower:]' | xargs)
if [[ "$DEPLOY_ACTION" == "exit" ]]; then
echo "Exiting deployment."
exit 0
elif [[ "$DEPLOY_ACTION" == "rename" ]]; then
read -p "New deployment name: " new_deployment_name
if [[ -z "$new_deployment_name" ]]; then
echo -e "${RED}Error: deployment name cannot be empty.${NC}"
exit 1
fi
DEPLOYMENT_NAME="$new_deployment_name"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deploy.sh` around lines 130 - 145, DEPLOYMENT_NAME is reused in filenames and
DB schema and isn't validated after user input or after the rename flow,
allowing unsafe values; add a whitelist validation (e.g., allow only
[A-Za-z0-9._-] and forbid sequences like ".." and characters like "/" and "\"
and quotes) applied immediately after setting DEPLOYMENT_NAME from
deployment_name_input and again after reading new_deployment_name in the rename
branch (referencing DEPLOYMENT_NAME and new_deployment_name), and if the value
fails the regex or is empty, print an error and exit 1 so only safe names are
used for .env.${DEPLOYMENT_NAME}, .docker-deploy.${DEPLOYMENT_NAME}.override.yml
and DB_SCHEMA.

Comment on lines +223 to +233
if db_schema:
schema_engine = create_engine(target_uri, isolation_level="AUTOCOMMIT")
schema_connection = None
try:
schema_connection = schema_engine.connect()
schema_connection.execute(text(f'CREATE SCHEMA IF NOT EXISTS "{db_schema}"'))
logger.info(f"Ensured database schema exists: {db_schema}")
finally:
if schema_connection:
schema_connection.close()
schema_engine.dispose()

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Potential SQL injection risk with schema name.

The schema name is interpolated directly into the SQL statement using an f-string. While DB_SCHEMA typically comes from environment variables controlled by deployment scripts, this pattern could be exploited if the schema name contains malicious SQL.

🛡️ Suggested fix using identifier quoting
                     try:
                         schema_connection = schema_engine.connect()
-                        schema_connection.execute(text(f'CREATE SCHEMA IF NOT EXISTS "{db_schema}"'))
+                        # Use quote_ident equivalent - PostgreSQL double-quote escaping
+                        safe_schema = db_schema.replace('"', '""')
+                        schema_connection.execute(text(f'CREATE SCHEMA IF NOT EXISTS "{safe_schema}"'))
                         logger.info(f"Ensured database schema exists: {db_schema}")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/mdvtools/dbutils/mdv_server_app.py` around lines 223 - 233, The code
builds SQL by interpolating db_schema directly into text(...) which risks SQL
injection; change the CREATE SCHEMA call to safely quote or validate the
identifier before executing: obtain a safe quoted identifier via
schema_engine.dialect.identifier_preparer.quote(db_schema) (or use
sqlalchemy.schema.CreateSchema) and use that quoted value in the text() call
instead of raw f-string interpolation, and/or add a simple validation (e.g.,
allow only [A-Za-z0-9_\\-] or similar) on db_schema before attempting to create
the schema; update the block around create_engine, schema_engine, and
schema_connection to use the quoted identifier (or CreateSchema) when calling
schema_connection.execute(...) so the schema name cannot inject SQL.

Comment thread python/mdvtools/scripts/users_projects_dataframe.py Outdated

@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 `@python/mdvtools/scripts/users_projects_dataframe.py`:
- Around line 42-47: The current validation in users_projects_dataframe.py only
checks types for auth0_domain, client_id, client_secret, and auth0_db_connection
so empty strings slip through; update the check to require non-empty strings
(e.g., isinstance(var, str) and var.strip()) for each of auth0_domain,
client_id, client_secret, and auth0_db_connection to enforce presence while
preserving type narrowing, and raise the existing "missing config" or ValueError
path when any of these are empty.
🪄 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

Run ID: 47ef7803-7e59-4b52-ab03-f7cdd37fb4d1

📥 Commits

Reviewing files that changed from the base of the PR and between 2fc4a90 and 0bf0e07.

📒 Files selected for processing (2)
  • python/mdvtools/dbutils/test/unit/test_mdv_server_app.py
  • python/mdvtools/scripts/users_projects_dataframe.py

Comment thread python/mdvtools/scripts/users_projects_dataframe.py
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Actionable comments posted: 0

@MarShaikh

Copy link
Copy Markdown
Collaborator

Hi @lferreira86, I was fixing some small issues raised by the CI and ran into these while trying to run the deploy.sh script locally.

  1. The if [[ "$ports_line" =~ (0\.0\.0\.0|\[::\]):([0-9]+)->5055 ]] in deploy.sh gave me a syntax error:
    conditional expression: unexpected token '>'. So I fixed it by moving the pattern into a variable,
local port_pattern='(0\.0\.0\.0|\[::\]|:::):([0-9]+)->5055' 
if [[ "$ports_line" =~ $port_pattern ]]
  1. Deploy and build use different compose files. deploy.sh runs against docker-local.yml, while docker compose build / make use docker-compose.yml. Is that split intentional, or could the deploy use the same compose file as the build?
  2. docker-compose.yml and docker-local.yml currently differ only by port (5056 vs 5055). Is there a reason to keep both, or could they be merged into one?
  3. The compose files load .env, while deploy.sh writes .env.<name>. I wanted to understand this better, is this a shared .env for secrets plus a per-deployment .env.<name> for config, or should the compose files reference .env.<name> directly?

@lferreira86

Copy link
Copy Markdown
Collaborator Author

Hi @lferreira86, I was fixing some small issues raised by the CI and ran into these while trying to run the deploy.sh script locally.

  1. The if [[ "$ports_line" =~ (0\.0\.0\.0|\[::\]):([0-9]+)->5055 ]] in deploy.sh gave me a syntax error:
    conditional expression: unexpected token '>'. So I fixed it by moving the pattern into a variable,
local port_pattern='(0\.0\.0\.0|\[::\]|:::):([0-9]+)->5055' 
if [[ "$ports_line" =~ $port_pattern ]]
  1. Deploy and build use different compose files. deploy.sh runs against docker-local.yml, while docker compose build / make use docker-compose.yml. Is that split intentional, or could the deploy use the same compose file as the build?
  2. docker-compose.yml and docker-local.yml currently differ only by port (5056 vs 5055). Is there a reason to keep both, or could they be merged into one?
  3. The compose files load .env, while deploy.sh writes .env.<name>. I wanted to understand this better, is this a shared .env for secrets plus a per-deployment .env.<name> for config, or should the compose files reference .env.<name> directly?

@MarShaikh, please check my answers below:
1 - Ok, i think this is a better solution;
2 and 3 - The deploy.sh prepare the deployment file, i don't remember which name it use for the final composer file, if docker-local or docker-compose, however we should merge this so there is no confusion with the deployment. The port is controlled as well by the deply.sh, it get the next available port and configure the deployment;
4 - the .env file is per deployment, because we can use different configuration for SQLite/PostgreSQL, including database reuse, shcema names, ports...

MarShaikh and others added 13 commits June 22, 2026 12:58
* - `_fetch_admin_auth_ids()`, resolves the admin role id, pages through its members (with rate-limit retry), returns a set of auth0 `user_ids`, replaces `_fetch_user_roles_with_retry()`.
  - `_process_single_user()`, `is_admin` = `auth0_id` in `context.admin_auth_ids`
  - `sync_users_to_db()`, calls `_fetch_admin_auth_ids()` once before the user loop; stores it on the context.
  - Removed now-dead code, and updated stale docstring

* rewrote the two tests that asserted per-user list_roles behavior
…ly the permissions file if given) once the app is healthy, then restart so the in-memory cache reflects the new rows
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.

3 participants