Skip to content

add: firebird#9

Merged
Asuniia merged 1 commit intomainfrom
feat/firebird
Apr 20, 2026
Merged

add: firebird#9
Asuniia merged 1 commit intomainfrom
feat/firebird

Conversation

@Asuniia
Copy link
Copy Markdown
Contributor

@Asuniia Asuniia commented Apr 20, 2026

Summary by CodeRabbit

  • New Features

    • Firebird database engine is now available as a configuration option in the agent and database setup workflows, alongside existing SQL options.
    • Firebird services are automatically configured with generated credentials, Docker Compose specifications, port assignments, and persistent volume management for data persistence.
  • Dependencies

    • Added PyYAML as a new project dependency.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 20, 2026

📝 Walkthrough

Walkthrough

The pull request introduces Firebird database support throughout the agent infrastructure by adding Firebird as a selectable database option, generating corresponding Docker Compose service definitions with credentials and port allocation, improving YAML placeholder injection for service templates, and updating project dependencies to include PyYAML.

Changes

Cohort / File(s) Summary
Firebird Database Support
commands/agent.py, commands/db.py, templates/compose.py
Added Firebird as a selectable database engine with automatic port allocation (3050), credential generation, and Docker Compose service snippet integration. Enhanced YAML marker detection in compose file insertion logic to locate networks: and volumes: sections more robustly with newline-prefix matching.
Template Enhancement
commands/agent.py
Ensures fetched agent.yml template contains {{EXTRA_SERVICES}} and {{EXTRA_VOLUMES}} placeholders, injecting them relative to networks: section or appending to file end if missing.
Project Dependencies
pyproject.toml
Added pyyaml >=6.0.0 as a project dependency to support YAML template processing.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A Firebird takes flight, through our database migration,
With Dockerized grace and port allocation,
Templates now flex with placeholders divine,
And YAML paths parse with precision so fine—
One database engine, infinitely blessed! 🔥

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'add: firebird' directly reflects the main change: adding Firebird database support across multiple files including new compose snippets, port configurations, and database initialization logic.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/firebird

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (2)
commands/db.py (2)

290-309: ⚠️ Potential issue | 🟠 Major

Don’t locate the end of volumes: by searching only for networks:.

A valid compose file can have another top-level section after volumes: before networks:; this logic would insert the new volume into the wrong section. Since PyYAML is now a dependency, prefer parsing/updating the top-level volumes mapping instead of string-splicing YAML.

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

In `@commands/db.py` around lines 290 - 309, The current string-splice logic
around vol_pos/end_of_volumes on new_content is brittle; instead parse
new_content with PyYAML (yaml.safe_load), merge the new volumes into the
top-level "volumes" mapping (parse vol_snippet as YAML and update/extend the
dict), then dump the updated document back to YAML (yaml.safe_dump) and assign
to new_content; update code that references vol_pos, end_of_volumes and the
final append branch to use this parsing/merge approach so volumes are added to
the correct top-level mapping rather than by searching for "networks:".

254-327: ⚠️ Potential issue | 🟠 Major

Use randomized filename and store the full Firebird database path.

Firebird uses a hardcoded mirror.fdb name, breaking the pattern established by PostgreSQL, MySQL, and MongoDB which all generate unique identifiers. Multiple Firebird instances will collide in databases.json, all appearing as mirror.fdb. Additionally, the code only stores the filename, but the official Firebird Docker image places database files at /var/lib/firebird/data—remote clients need the full server-side path for connection strings.

🐛 Proposed fix
         elif db_engine == "firebird":
             db_port = get_free_port()
             db_user = "alice"
             db_pass = secrets.token_hex(8)
-            db_name = "mirror.fdb"
+            db_file = f"fb_{secrets.token_hex(4)}.fdb"
+            db_path = f"/var/lib/firebird/data/{db_file}"
             service_name = f"db-firebird-{secrets.token_hex(2)}"
             var_prefix = service_name.upper().replace("-", "_")
             env_vars[f"{var_prefix}_PORT"] = str(db_port)
-            env_vars[f"{var_prefix}_DB"] = db_name
+            env_vars[f"{var_prefix}_DB"] = db_file
             env_vars[f"{var_prefix}_USER"] = db_user
             env_vars[f"{var_prefix}_PASS"] = db_pass
@@
             {
-                "name": db_name,
-                "database": db_name,
+                "name": db_file,
+                "database": db_path,
                 "type": db_engine,
                 "username": db_user,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@commands/db.py` around lines 254 - 327, The Firebird setup hardcodes
db_name="mirror.fdb" and stores only the filename in env_vars and
add_db_to_json, causing collisions and missing server-side path; change db_name
to include a randomized identifier (e.g., use secrets.token_hex or service_name)
and set the env var and stored "database" value to the full server-side path
(/var/lib/firebird/data/<db_name>) instead of just the filename; update
env_vars[f"{var_prefix}_DB"] and the payload passed to add_db_to_json so
"database" and any written env file/reference use the full path while keeping
"name" as the logical filename or service identifier, and ensure volumes snippet
still uses the same randomized volume name (service_name-data).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@commands/agent.py`:
- Around line 396-433: The Firebird branch currently hardcodes
db_name="mirror.fdb" causing duplicate names and storing only a filename; change
it to generate a unique filename (e.g., use service_name or a uuid:
"{service_name}.fdb" or similar) and set the stored "database" value to the full
container path where the volume is mounted (e.g.,
"/var/lib/firebird/data/{unique_filename}"). Update the variables used in
AGENT_FIREBIRD_SNIPPET replacements and env_vars so the snippet still gets the
filename/DB env var if needed, and ensure add_db_to_json receives "name"
(display name) and "database" (absolute server-side path) accordingly; keep
volumes_list.append(f"{service_name}-data") unchanged. Ensure references:
db_name, service_name, AGENT_FIREBIRD_SNIPPET, env_vars, volumes_list, and
add_db_to_json are updated consistently.

In `@templates/compose.py`:
- Around line 73-76: Change the FIREBIRD root password placeholder in the
compose template from ${PASSWORD} to ${ROOT_PASSWORD} (update
templates/compose.py where FIREBIRD_ROOT_PASSWORD is set) and update the
rendering logic that builds environment substitutions in commands/db.py and
commands/agent.py to generate a distinct root secret (e.g., var_prefix +
"_ROOT_PASS") and apply it by adding a replacement for "${ROOT_PASSWORD}" using
.replace("${ROOT_PASSWORD}", f"${{{var_prefix}_ROOT_PASS}}"); ensure the app
user password generation/placeholder for ${PASSWORD} remains unchanged.

---

Outside diff comments:
In `@commands/db.py`:
- Around line 290-309: The current string-splice logic around
vol_pos/end_of_volumes on new_content is brittle; instead parse new_content with
PyYAML (yaml.safe_load), merge the new volumes into the top-level "volumes"
mapping (parse vol_snippet as YAML and update/extend the dict), then dump the
updated document back to YAML (yaml.safe_dump) and assign to new_content; update
code that references vol_pos, end_of_volumes and the final append branch to use
this parsing/merge approach so volumes are added to the correct top-level
mapping rather than by searching for "networks:".
- Around line 254-327: The Firebird setup hardcodes db_name="mirror.fdb" and
stores only the filename in env_vars and add_db_to_json, causing collisions and
missing server-side path; change db_name to include a randomized identifier
(e.g., use secrets.token_hex or service_name) and set the env var and stored
"database" value to the full server-side path (/var/lib/firebird/data/<db_name>)
instead of just the filename; update env_vars[f"{var_prefix}_DB"] and the
payload passed to add_db_to_json so "database" and any written env
file/reference use the full path while keeping "name" as the logical filename or
service identifier, and ensure volumes snippet still uses the same randomized
volume name (service_name-data).
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4be2caea-b857-4179-968d-3493f5eb2e59

📥 Commits

Reviewing files that changed from the base of the PR and between d1d8db9 and 122057c.

📒 Files selected for processing (4)
  • commands/agent.py
  • commands/db.py
  • pyproject.toml
  • templates/compose.py
📜 Review details
🧰 Additional context used
🪛 Ruff (0.15.10)
commands/db.py

[warning] 276-276: Unnecessary mode argument

Remove mode argument

(UP015)

🔇 Additional comments (1)
pyproject.toml (1)

11-12: LGTM.

The dependency addition is valid for the YAML-related compose/template work in this PR.

Comment thread commands/agent.py
Comment on lines +396 to +433
elif db_engine == "firebird":
fb_port = get_free_port()
db_user = "alice"
db_pass = secrets.token_hex(8)
db_name = "mirror.fdb"
service_name = f"db-firebird-{secrets.token_hex(2)}"

var_prefix = service_name.upper().replace("-", "_")
env_vars[f"{var_prefix}_PORT"] = str(fb_port)
env_vars[f"{var_prefix}_DB"] = db_name
env_vars[f"{var_prefix}_USER"] = db_user
env_vars[f"{var_prefix}_PASS"] = db_pass

snippet = (
AGENT_FIREBIRD_SNIPPET.replace("${SERVICE_NAME}", service_name)
.replace("${PORT}", f"${{{var_prefix}_PORT}}")
.replace("${VOL_NAME}", f"{service_name}-data")
.replace("${DB_NAME}", f"${{{var_prefix}_DB}}")
.replace("${USER}", f"${{{var_prefix}_USER}}")
.replace("${PASSWORD}", f"${{{var_prefix}_PASS}}")
)

extra_services += snippet
volumes_list.append(f"{service_name}-data")

add_db_to_json(
path,
{
"name": db_name,
"database": db_name,
"type": "firebird",
"username": db_user,
"password": db_pass,
"port": fb_port,
"host": "localhost",
"generated_id": str(uuid.uuid4()),
},
)
Copy link
Copy Markdown

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:

# Check the current code structure around lines 396-436
sed -n '390,440p' commands/agent.py | head -60

Repository: Portabase/cli

Length of output: 2123


🏁 Script executed:

# Find the AGENT_FIREBIRD_SNIPPET definition
rg "AGENT_FIREBIRD_SNIPPET" -B 5 -A 30

Repository: Portabase/cli

Length of output: 8829


🏁 Script executed:

# Search for how the database config (from add_db_to_json) is used
rg "add_db_to_json" -B 2 -A 10

Repository: Portabase/cli

Length of output: 9545


🏁 Script executed:

# Check if there are any other Firebird-related constants or templates
rg -i "firebird" --type py -l

Repository: Portabase/cli

Length of output: 110


🌐 Web query:

Firebird Docker official database location and path requirements

💡 Result:

The official Firebird Docker image (firebirdsql/firebird) uses /var/lib/firebird/data as the default location for database files. This directory is declared as a VOLUME in the image, making it the recommended mount point for persistent data storage. Key details: - Databases created via the FIREBIRD_DATABASE environment variable are stored by default in /var/lib/firebird/data (e.g., /var/lib/firebird/data/mirror.fdb). - Absolute paths outside this directory are allowed for databases. - Usage example: docker run -v ./host/data:/var/lib/firebird/data firebirdsql/firebird - To persist data, always mount a host directory or Docker volume to /var/lib/firebird/data to avoid data loss on container restart/removal. - Firebird configuration files like databases.conf can be mounted separately at /opt/firebird/databases.conf if needed for aliases. This is confirmed across official sources including the GitHub repo, Docker Hub page, and FirebirdSQL.org announcement recognizing these as official images (updated as recently as 3 months ago).

Citations:


🌐 Web query:

Firebird TCP/IP connection string database path requirements

💡 Result:

For Firebird TCP/IP connections, the connection string format is: [hostname/IP]:[port]:database_identifier, where database_identifier is either a database alias (defined in aliases.conf on the server) or the absolute path to the database file on the server machine. Key requirements for the database path: - Must be the absolute path as it exists on the server's filesystem. - Use forward slashes (/) for paths on both Windows and Linux servers; backslashes () are supported on Windows but forward slashes are preferred for cross-platform consistency. Backslashes are invalid on POSIX (Linux) servers. - Examples: - Linux server: serverhost:/opt/firebird/databases/employee.fdb or serverhost:employee (alias) - Windows server: serverhost:c:/databases/mydatabase.fdb or serverhost:MyAlias - Optional port: serverhost/3051:/path/to/db.fdb (default port 3050) - URL-style (Firebird 3+): inet://serverhost:3051/path/to/db.fdb - Local loopback: localhost:/path/to/db.fdb or inet://localhost/path/to/db.fdb The path is interpreted by the server, so use server-native format. Aliases are recommended over full paths for security and portability. This applies to current versions including Firebird 5 (latest stable as of 2024 docs). No Firebird 6 released yet.

Citations:


Use a unique filename and store the full server-side path for Firebird database connectivity.

The current code hardcodes db_name = "mirror.fdb" and stores it as "database": db_name in the database config. This causes two problems:

  1. TCP connections fail: The "database" field stores only the filename, but Firebird TCP/IP connections require the server-side absolute path (e.g., /var/lib/firebird/data/mirror.fdb), not just a filename. Clients connecting to the container over the network need this full path.

  2. Duplicate names: All generated Firebird instances share the identical name mirror.fdb, making them indistinguishable in database listings and removal operations.

The container's volume is already correctly mounted at /var/lib/firebird/data in the Docker template, but the stored connection metadata doesn't reflect this.

🐛 Proposed fix
             elif db_engine == "firebird":
                 fb_port = get_free_port()
                 db_user = "alice"
                 db_pass = secrets.token_hex(8)
-                db_name = "mirror.fdb"
+                db_file = f"fb_{secrets.token_hex(4)}.fdb"
+                db_path = f"/var/lib/firebird/data/{db_file}"
                 service_name = f"db-firebird-{secrets.token_hex(2)}"

                 var_prefix = service_name.upper().replace("-", "_")
                 env_vars[f"{var_prefix}_PORT"] = str(fb_port)
-                env_vars[f"{var_prefix}_DB"] = db_name
+                env_vars[f"{var_prefix}_DB"] = db_file
                 env_vars[f"{var_prefix}_USER"] = db_user
                 env_vars[f"{var_prefix}_PASS"] = db_pass
@@
                     path,
                     {
-                        "name": db_name,
-                        "database": db_name,
+                        "name": db_file,
+                        "database": db_path,
                         "type": "firebird",
                         "username": db_user,
                         "password": db_pass,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@commands/agent.py` around lines 396 - 433, The Firebird branch currently
hardcodes db_name="mirror.fdb" causing duplicate names and storing only a
filename; change it to generate a unique filename (e.g., use service_name or a
uuid: "{service_name}.fdb" or similar) and set the stored "database" value to
the full container path where the volume is mounted (e.g.,
"/var/lib/firebird/data/{unique_filename}"). Update the variables used in
AGENT_FIREBIRD_SNIPPET replacements and env_vars so the snippet still gets the
filename/DB env var if needed, and ensure add_db_to_json receives "name"
(display name) and "database" (absolute server-side path) accordingly; keep
volumes_list.append(f"{service_name}-data") unchanged. Ensure references:
db_name, service_name, AGENT_FIREBIRD_SNIPPET, env_vars, volumes_list, and
add_db_to_json are updated consistently.

Comment thread templates/compose.py
Comment on lines +73 to +76
- FIREBIRD_DATABASE=${DB_NAME}
- FIREBIRD_USER=${USER}
- FIREBIRD_PASSWORD=${PASSWORD}
- FIREBIRD_ROOT_PASSWORD=${PASSWORD}
Copy link
Copy Markdown

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, locate and examine templates/compose.py
find . -name "compose.py" -type f | head -20

Repository: Portabase/cli

Length of output: 79


🏁 Script executed:

# Search for files containing FIREBIRD configuration
rg -l "FIREBIRD" --type py | head -20

Repository: Portabase/cli

Length of output: 110


🏁 Script executed:

# Read templates/compose.py to verify the code and context
cat -n templates/compose.py | head -100

Repository: Portabase/cli

Length of output: 2535


🏁 Script executed:

# Check for FIREBIRD_ROOT_PASSWORD usage in the codebase
rg "FIREBIRD_ROOT_PASSWORD" --type py -B 2 -A 2

Repository: Portabase/cli

Length of output: 323


🏁 Script executed:

# Check for ROOT_PASSWORD usage more broadly
rg "ROOT_PASSWORD" --type py

Repository: Portabase/cli

Length of output: 248


🏁 Script executed:

# Check for PASSWORD variable handling and rendering
rg "PASSWORD" templates/compose.py -B 2 -A 2

Repository: Portabase/cli

Length of output: 726


🏁 Script executed:

# Check how PASSWORD is generated and used in the renderer/agent code
rg "PASSWORD" commands/ --type py -B 3 -A 3

Repository: Portabase/cli

Length of output: 4679


🏁 Script executed:

# Look for where these variables are rendered/substituted
rg "\$\{PASSWORD\}" --type py -B 2 -A 2

Repository: Portabase/cli

Length of output: 39


🏁 Script executed:

# Check if there's any code that parses or handles the PASSWORD variable
rg "render\|substitute\|PASSWORD" commands/ --type py | head -30

Repository: Portabase/cli

Length of output: 39


🏁 Script executed:

# Check if ROOT_PASSWORD is already supported in the rendering logic
rg "ROOT_PASSWORD\|root_pass\|ROOT_PASS" commands/db.py commands/agent.py --type py -B 2 -A 2

Repository: Portabase/cli

Length of output: 39


🏁 Script executed:

# Check for any environment variable generation or secret handling
rg "secrets\|generate\|token" commands/db.py --type py | head -20

Repository: Portabase/cli

Length of output: 39


🏁 Script executed:

# Look at the full context of the replace logic in commands/db.py for Firebird
sed -n '1,150p' commands/db.py | tail -100

Repository: Portabase/cli

Length of output: 3279


🏁 Script executed:

# Search for the Firebird-specific handling in db.py
rg "firebird" commands/db.py -i -B 5 -A 10

Repository: Portabase/cli

Length of output: 3457


🏁 Script executed:

# Look at commands/db.py to see the full Firebird handling
cat -n commands/db.py | grep -A 30 "firebird"

Repository: Portabase/cli

Length of output: 5051


🏁 Script executed:

# Let me check if there's any mention of separate root password handling elsewhere in the codebase
rg "root_pass\|root-pass\|ROOT_PASS" --type py -i

Repository: Portabase/cli

Length of output: 39


🏁 Script executed:

# Check the agent.py for similar Firebird handling
rg "firebird" commands/agent.py -i -B 5 -A 10

Repository: Portabase/cli

Length of output: 4529


Use a separate Firebird root password.

${PASSWORD} is used for both the app user and FIREBIRD_ROOT_PASSWORD, so any app credential leak also grants SYSDBA admin access. Add a distinct root-password placeholder and have the renderers generate a separate secret.

This requires two changes:

  1. Update the template in templates/compose.py line 76 to use ${ROOT_PASSWORD} instead of ${PASSWORD}
  2. Update the Firebird rendering logic in commands/db.py (lines 254–272) and commands/agent.py to generate a separate root password and add .replace("${ROOT_PASSWORD}", f"${{{var_prefix}_ROOT_PASS}}")
Template change needed
       - FIREBIRD_DATABASE=${DB_NAME}
       - FIREBIRD_USER=${USER}
       - FIREBIRD_PASSWORD=${PASSWORD}
-      - FIREBIRD_ROOT_PASSWORD=${PASSWORD}
+      - FIREBIRD_ROOT_PASSWORD=${ROOT_PASSWORD}
       - FIREBIRD_DATABASE_DEFAULT_CHARSET=UTF8
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@templates/compose.py` around lines 73 - 76, Change the FIREBIRD root password
placeholder in the compose template from ${PASSWORD} to ${ROOT_PASSWORD} (update
templates/compose.py where FIREBIRD_ROOT_PASSWORD is set) and update the
rendering logic that builds environment substitutions in commands/db.py and
commands/agent.py to generate a distinct root secret (e.g., var_prefix +
"_ROOT_PASS") and apply it by adding a replacement for "${ROOT_PASSWORD}" using
.replace("${ROOT_PASSWORD}", f"${{{var_prefix}_ROOT_PASS}}"); ensure the app
user password generation/placeholder for ${PASSWORD} remains unchanged.

@Asuniia Asuniia merged commit b1fdf60 into main Apr 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant