Skip to content

feat: add firebird#51

Merged
RambokDev merged 3 commits intomainfrom
feat/add-firebird
Mar 31, 2026
Merged

feat: add firebird#51
RambokDev merged 3 commits intomainfrom
feat/add-firebird

Conversation

@RambokDev
Copy link
Copy Markdown
Contributor

@RambokDev RambokDev commented Mar 30, 2026

Summary by CodeRabbit

  • New Features
    • Firebird support: health-check, backup, restore and sample seed data; multi-db local stack now includes Firebird.
  • Chores
    • Local DB orchestration moved to a new task runner and dedicated compose file; legacy Makefile DB targets removed; entrypoint updated to start DB stack.
    • Compose: removed some DB services and enabled consolidated DB config loading.
  • Tests
    • Added Firebird integration tests for ping and backup/restore.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

📝 Walkthrough

Walkthrough

Adds Firebird DB support across tooling, compose, config, domain implementation (ping/backup/restore using isql-fb/gbak), seed scripts, tests, and replaces Makefile workflows with a new justfile and per-DB compose orchestration. Also removes inline MariaDB/MySQL services from main compose.

Changes

Cohort / File(s) Summary
Compose & Docker
docker-compose.yml, docker-compose.databases.yml, docker/Dockerfile, docker/entrypoints/app-dev-entrypoint.sh
Enabled separate DB compose file, removed db-mariadb/db-mysql from main compose, added db-firebird service in new compose, installed firebird3.0-utils in build, and entrypoint now starts the databases compose first.
Tooling & scripts
Makefile, justfile, scripts/sqlite/seed.sh, scripts/firebird/seed.sql, scripts/*
Removed Makefile cluster/seed targets; added justfile with up and per-DB seed-* recipes including seed-firebird; added SQLite and Firebird seed scripts.
Config & data files
src/services/config.rs, databases.toml, databases.json
Added DbType::Firebird and mapping; adjusted MongoDB naming and entries; appended Firebird database entries and several new DB entries in databases.toml/databases.json.
Domain wiring
src/domain/mod.rs, src/domain/factory.rs
Registered firebird module and wired DbType::Firebird into DatabaseFactory for backup/restore creation.
Firebird domain implementation
src/domain/firebird/mod.rs, src/domain/firebird/database.rs, src/domain/firebird/ping.rs, src/domain/firebird/backup.rs, src/domain/firebird/restore.rs
New Firebird module implementing FirebirdDatabase with file_extension, ping (isql-fb probe with timeout), backup (gbak -b), and restore (gbak -c), including file-locking and subprocess handling.
Tests
src/tests/domain/firebird.rs, src/tests/domain/mod.rs
Added Firebird integration tests that start a Firebird container, assert ping, perform backup (compress/decompress) and test restore via factory-created DB instances.
Status & minor tweaks
src/services/status.rs, src/domain/redis/ping.rs, src/domain/valkey/ping.rs, src/domain/sqlite/backup.rs
Added per-database info logging for ping results; removed some conditional stderr logging in redis/valkey pings; added extra info logs in sqlite backup.
Developer files & volumes
docker-compose.yml (volumes), docker-compose.databases.yml (volumes)
Removed mariadb-data/mysql-data named volumes from main compose; new database-specific volumes declared in separate compose file.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Tests/Client
    participant Factory as DatabaseFactory
    participant App as Rust App / Firebird DB impl
    participant Container as db-firebird (container)
    participant GBak as gbak / isql-fb
    participant FS as Backup FS

    Test->>Factory: create_for_backup(cfg)
    Factory->>App: returns FirebirdDatabase
    Test->>App: db.ping()
    App->>Container: spawn isql-fb (probe SQL)
    Container->>App: stdout/stderr (probe result)
    App-->>Test: ping result

    Test->>App: db.backup(backup_dir)
    App->>App: acquire FileLock (generated_id, Backup)
    App->>Container: spawn gbak -b -v --user/--password -> output.fbk
    Container->>FS: writes output.fbk
    GBak-->>App: exit status / stderr
    App->>App: release FileLock
    App-->>Test: backup PathBuf
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 I hopped into Docker's den,
Built a Firebird, then back again,
gbak hummed a tune, isql said "ping!",
Locks held tight while archives sing,
A carrot for backups, safe and serene 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.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 'feat: add firebird' accurately reflects the main objective of the changeset, which is to introduce Firebird database support throughout the system.

✏️ 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/add-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: 1

Caution

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

⚠️ Outside diff range comments (1)
docker/Dockerfile (1)

92-104: ⚠️ Potential issue | 🔴 Critical

Missing firebird3.0-utils in production image will break Firebird functionality.

The base image (line 21) installs firebird3.0-utils, but the production stage starts from ubuntu:24.04 and does not include this package. The Firebird implementation relies on:

  • gbak for backup (src/domain/firebird/backup.rs)
  • gbak for restore (src/domain/firebird/restore.rs)
  • isql-fb for ping/health checks (src/domain/firebird/ping.rs)

All Firebird operations will fail at runtime with "command not found" errors.

🐛 Proposed fix to add firebird3.0-utils to production stage
 RUN apt-get update && apt-get install -y \
     redis-server \
     ca-certificates \
     tzdata \
     libpq5 \
     libreadline8 \
     libncurses6 \
     zlib1g \
     mariadb-client \
     sqlite3 \
     redis-tools \
     valkey \
+    firebird3.0-utils \
     && rm -rf /var/lib/apt/lists/*
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker/Dockerfile` around lines 92 - 104, The production Dockerfile stage is
missing the firebird3.0-utils package required by Firebird operations; add
installation of firebird3.0-utils to the apt-get install list in the production
stage (the RUN that currently installs redis-server, ca-certificates, tzdata,
libpq5, libreadline8, libncurses6, zlib1g, mariadb-client, sqlite3, redis-tools,
valkey) so that commands used by src/domain/firebird/backup.rs and
src/domain/firebird/restore.rs (gbak) and src/domain/firebird/ping.rs (isql-fb)
are available at runtime.
🧹 Nitpick comments (5)
src/services/config.rs (1)

167-179: Consider requiring username and password for Firebird.

Firebird is grouped with optional credentials (like MongoDB/Redis), but the backup and restore implementations pass cfg.username and cfg.password directly to gbak. If these are empty, the commands will likely fail at runtime. Other networked databases like PostgreSQL, MySQL, and MariaDB require these fields.

♻️ Proposed fix to require credentials for Firebird
             let username = match db.db_type {
-                DbType::Postgresql | DbType::Mysql | DbType::Mariadb => {
+                DbType::Postgresql | DbType::Mysql | DbType::Mariadb | DbType::Firebird => {
                     required(&db.username, &db.name, "username")?
                 }
                 _ => optional(&db.username),
             };

             let password = match db.db_type {
-                DbType::Postgresql | DbType::Mysql | DbType::Mariadb => {
+                DbType::Postgresql | DbType::Mysql | DbType::Mariadb | DbType::Firebird => {
                     required(&db.password, &db.name, "password")?
                 }
                 _ => optional(&db.password),
             };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/config.rs` around lines 167 - 179, The Firebird DB type is
currently treated as optional for credentials but backup/restore pass
cfg.username and cfg.password to gbak, so make Firebird require username and
password like Postgresql/Mysql/Mariadb: update the match arms that set username
and password (referencing db.db_type, DbType::Postgresql | DbType::Mysql |
DbType::Mariadb and the required(...) and optional(...) calls) to include
DbType::Firebird so required(&db.username, &db.name, "username")? and
required(&db.password, &db.name, "password")? are used for Firebird as well.
Makefile (1)

52-57: Consider using environment variables for consistency with other seed targets.

Other seed targets use environment variables ($$MYSQL_USER, $$PG_PASSWORD, etc.) from the .env file, but Firebird credentials are hardcoded. This inconsistency makes future maintenance harder.

♻️ Proposed refactor using environment variables
 seed-firebird:
 	`@echo` "Seeding Firebird..."
-	docker exec -i db-firebird isql -user alice -password fake_password /var/lib/firebird/data/mirror.fdb < ./scripts/firebird/seed.sql
+	docker exec -i db-firebird isql -user $$FIREBIRD_USER -password $$FIREBIRD_PASSWORD /var/lib/firebird/data/$$FIREBIRD_DATABASE < ./scripts/firebird/seed.sql
 	`@echo` "Verifying Firebird tables..."
-	docker exec -i db-firebird isql -user alice -password fake_password /var/lib/firebird/data/mirror.fdb \
+	docker exec -i db-firebird isql -user $$FIREBIRD_USER -password $$FIREBIRD_PASSWORD /var/lib/firebird/data/$$FIREBIRD_DATABASE \
 		-sql "SHOW TABLES;"

Then add corresponding variables to .env:

FIREBIRD_USER=alice
FIREBIRD_PASSWORD=fake_password
FIREBIRD_DATABASE=mirror.fdb
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Makefile` around lines 52 - 57, Replace the hardcoded Firebird credentials in
the seed-firebird target with environment variables and document them in .env:
change occurrences of "alice" to $$FIREBIRD_USER, "fake_password" to
$$FIREBIRD_PASSWORD, and "mirror.fdb" to $$FIREBIRD_DATABASE in the docker exec
lines inside the seed-firebird recipe so the target uses shell environment vars
(matches other seed targets); also add FIREBIRD_USER, FIREBIRD_PASSWORD, and
FIREBIRD_DATABASE entries to .env.
src/domain/firebird/database.rs (1)

30-40: Consider using RAII guard pattern for lock management.

If FileLock::release() fails after a successful backup, the backup result is discarded. Also, if the backup::run() call panics (unlikely but possible), the lock won't be released. A guard-based approach would be more robust.

That said, this follows the existing pattern in the codebase, so it's acceptable to keep as-is and address holistically later.

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

In `@src/domain/firebird/database.rs` around lines 30 - 40, The current backup()
implementation acquires a file lock with FileLock::acquire(...) and then calls
backup::run(...), but it manually calls FileLock::release(...) afterward which
can fail or be skipped if backup::run panics; replace this manual release with
an RAII guard that acquires the lock in FileLock::acquire and returns a guard
type (e.g., FileLockGuard) that releases the lock in Drop so backup() simply
creates the guard, calls backup::run(self.cfg.clone(), dir.to_path_buf(),
self.file_extension()).await, and returns the result; update FileLock::acquire
to return the guard (or add a new method returning a guard) and remove the
explicit FileLock::release call from backup().
src/domain/firebird/ping.rs (2)

47-49: Stdout check may produce false positives.

stdout.contains("1") could match unintended content like "10", "21", or other text containing "1". Consider a more precise check.

Proposed fix
-    if stdout.contains("1") {
+    // isql-fb outputs the result with whitespace; trim and check for standalone "1"
+    if stdout.lines().any(|line| line.trim() == "1") {
         return Ok(true);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/domain/firebird/ping.rs` around lines 47 - 49, The check using
stdout.contains("1") can yield false positives (matching "10", "21", etc.);
change the condition to ensure an exact match — e.g., replace
stdout.contains("1") with a strict comparison like stdout.trim() == "1" or parse
stdout to an integer and compare to 1 (using the stdout variable and the
surrounding conditional in ping.rs) so only an exact "1" result returns
Ok(true).

29-32: Add logging for timeout case to aid debugging.

When the ping times out, the function silently returns Ok(false) without any logging. This makes it difficult to distinguish between a timeout and other failure modes during troubleshooting.

Proposed fix
     let output = match timeout(Duration::from_secs(5), child.wait_with_output()).await {
         Ok(res) => res?,
-        Err(_) => return Ok(false),
+        Err(_) => {
+            error!("Firebird ping timed out for {}", cfg.name);
+            return Ok(false);
+        }
     };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/domain/firebird/ping.rs` around lines 29 - 32, The timeout branch in the
timeout(Duration::from_secs(5), child.wait_with_output()).await match currently
returns Ok(false) silently; update that Err(_) arm to log a warning/error before
returning, e.g. emit a clear message like "firebird ping timed out" and include
contextual details (the child/command or other available identifiers) using the
crate's logging facility (e.g. tracing::warn! or log::warn!) so timeouts are
distinguishable from other failures in the function containing timeout(...) and
child.wait_with_output().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/domain/firebird/restore.rs`:
- Line 9: The debug log in the Firebird restore implementation incorrectly says
"MongoDB"; update the debug! call that logs the start of the restore (the debug!
macro that formats with cfg.name) to reference "Firebird" (e.g., "Starting
Firebird restore for database {}") so the log accurately reflects the operation.

---

Outside diff comments:
In `@docker/Dockerfile`:
- Around line 92-104: The production Dockerfile stage is missing the
firebird3.0-utils package required by Firebird operations; add installation of
firebird3.0-utils to the apt-get install list in the production stage (the RUN
that currently installs redis-server, ca-certificates, tzdata, libpq5,
libreadline8, libncurses6, zlib1g, mariadb-client, sqlite3, redis-tools, valkey)
so that commands used by src/domain/firebird/backup.rs and
src/domain/firebird/restore.rs (gbak) and src/domain/firebird/ping.rs (isql-fb)
are available at runtime.

---

Nitpick comments:
In `@Makefile`:
- Around line 52-57: Replace the hardcoded Firebird credentials in the
seed-firebird target with environment variables and document them in .env:
change occurrences of "alice" to $$FIREBIRD_USER, "fake_password" to
$$FIREBIRD_PASSWORD, and "mirror.fdb" to $$FIREBIRD_DATABASE in the docker exec
lines inside the seed-firebird recipe so the target uses shell environment vars
(matches other seed targets); also add FIREBIRD_USER, FIREBIRD_PASSWORD, and
FIREBIRD_DATABASE entries to .env.

In `@src/domain/firebird/database.rs`:
- Around line 30-40: The current backup() implementation acquires a file lock
with FileLock::acquire(...) and then calls backup::run(...), but it manually
calls FileLock::release(...) afterward which can fail or be skipped if
backup::run panics; replace this manual release with an RAII guard that acquires
the lock in FileLock::acquire and returns a guard type (e.g., FileLockGuard)
that releases the lock in Drop so backup() simply creates the guard, calls
backup::run(self.cfg.clone(), dir.to_path_buf(), self.file_extension()).await,
and returns the result; update FileLock::acquire to return the guard (or add a
new method returning a guard) and remove the explicit FileLock::release call
from backup().

In `@src/domain/firebird/ping.rs`:
- Around line 47-49: The check using stdout.contains("1") can yield false
positives (matching "10", "21", etc.); change the condition to ensure an exact
match — e.g., replace stdout.contains("1") with a strict comparison like
stdout.trim() == "1" or parse stdout to an integer and compare to 1 (using the
stdout variable and the surrounding conditional in ping.rs) so only an exact "1"
result returns Ok(true).
- Around line 29-32: The timeout branch in the timeout(Duration::from_secs(5),
child.wait_with_output()).await match currently returns Ok(false) silently;
update that Err(_) arm to log a warning/error before returning, e.g. emit a
clear message like "firebird ping timed out" and include contextual details (the
child/command or other available identifiers) using the crate's logging facility
(e.g. tracing::warn! or log::warn!) so timeouts are distinguishable from other
failures in the function containing timeout(...) and child.wait_with_output().

In `@src/services/config.rs`:
- Around line 167-179: The Firebird DB type is currently treated as optional for
credentials but backup/restore pass cfg.username and cfg.password to gbak, so
make Firebird require username and password like Postgresql/Mysql/Mariadb:
update the match arms that set username and password (referencing db.db_type,
DbType::Postgresql | DbType::Mysql | DbType::Mariadb and the required(...) and
optional(...) calls) to include DbType::Firebird so required(&db.username,
&db.name, "username")? and required(&db.password, &db.name, "password")? are
used for Firebird as well.
🪄 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: dd57c251-55ae-40f5-af7b-b1b93d0181ad

📥 Commits

Reviewing files that changed from the base of the PR and between a1aa66f and 2ab293a.

📒 Files selected for processing (13)
  • Makefile
  • databases.json
  • docker-compose.yml
  • docker/Dockerfile
  • scripts/firebird/seed.sql
  • src/domain/factory.rs
  • src/domain/firebird/backup.rs
  • src/domain/firebird/database.rs
  • src/domain/firebird/mod.rs
  • src/domain/firebird/ping.rs
  • src/domain/firebird/restore.rs
  • src/domain/mod.rs
  • src/services/config.rs

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 30, 2026

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

🧹 Nitpick comments (3)
src/tests/domain/firebird.rs (1)

56-57: Don’t mask ping errors with unwrap_or(false) in tests.

Use expect(...) so failures preserve root-cause context.

Suggested fix
-    let reachable = db.ping().await.unwrap_or(false);
+    let reachable = db.ping().await.expect("firebird ping failed");
@@
-    let reachable = db.ping().await.unwrap_or(false);
+    let reachable = db.ping().await.expect("firebird ping failed before restore");

Also applies to: 93-95

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

In `@src/tests/domain/firebird.rs` around lines 56 - 57, Replace the use of
unwrap_or(false) which masks errors when calling db.ping().await in the tests:
change the lines using let reachable = db.ping().await.unwrap_or(false); (and
the other occurrences at the same file) to use expect(...) on the await result
so a failing ping preserves the original error context (i.e., call
db.ping().await.expect("ping failed in firebird test") and keep the reachable
variable logic the same).
docker-compose.databases.yml (2)

18-18: Consider pinning the MariaDB image version.

Using latest tag can lead to unexpected behavior when the image updates. Consider pinning to a specific version (e.g., mariadb:11) for reproducibility, similar to how mysql:9.5 is specified.

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

In `@docker-compose.databases.yml` at line 18, Replace the floating tag
"mariadb:latest" used in the service image declaration (currently "image:
mariadb:latest") with a pinned, explicit version (for example "mariadb:11" or
another tested patch version) to ensure reproducible builds; mirror the approach
used for "mysql:9.5" so the compose file uses fixed database image tags rather
than "latest".

142-158: The firebirdsql/firebird image includes a built-in healthcheck; adding an explicit one is optional.

The official firebirdsql/firebird image already includes a built-in healthcheck via docker-healthcheck.sh that checks port 3050. If you want to add a custom healthcheck for consistency with MongoDB services, note that the proposed command has syntax issues (the database path should use / not :). A simpler alternative is to use a port-based check: ["CMD", "nc", "-z", "127.0.0.1", "3050"]. However, since most other database services in this file (PostgreSQL, MariaDB, MySQL, Redis, Valkey) do not have explicit healthchecks, the built-in one is sufficient for a development environment.

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

In `@docker-compose.databases.yml` around lines 142 - 158, The db-firebird service
uses the official firebirdsql/firebird image which already provides a built-in
healthcheck, so remove any added/incorrect custom healthcheck or, if you prefer
consistency, replace the broken command with a simple port check (e.g., use nc
against 127.0.0.1:3050) instead of the incorrect database path syntax; locate
the db-firebird service (container_name: db-firebird, image:
firebirdsql/firebird) and either omit a custom healthcheck entirely or implement
the port-based CMD healthcheck.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docker-compose.databases.yml`:
- Around line 61-65: The healthcheck block currently invokes the removed "mongo"
shell (test: [ "CMD", "mongo", "--eval", "db.adminCommand('ping')" ]) which
fails on modern Mongo images; update the healthcheck to call "mongosh" instead
and keep the same eval expression (e.g., replace the test entry so it invokes
"mongosh" with the --eval "db.adminCommand('ping')" argument), mirroring how the
db-mongodb service uses mongosh so the container health check succeeds on
MongoDB 6+/7+ images.
- Around line 84-92: The sqlite service block (service name "sqlite") currently
lacks the networks configuration and should be attached to the same "portabase"
network as the other DB services; update the sqlite service to include a
networks key referencing "portabase" (and ensure the top-level networks:
portabase definition remains present) so the container joins the network like
the other services and can communicate as required.

In `@docker-compose.yml`:
- Line 22: Replace the hardcoded EDGE_KEY value in docker-compose.yml with an
environment-injected secret (e.g., set EDGE_KEY: "${EDGE_KEY}" or use
env_file/secrets in the same docker-compose.yml) and store the real token
outside the repo (in a .env or Docker secret manager); update deployment docs to
instruct providing EDGE_KEY via environment or secrets and remove the embedded
token from the repository history/commit if necessary.

In `@docker/entrypoints/app-dev-entrypoint.sh`:
- Around line 34-35: The preflight Docker check was commented out, removing
graceful startup handling; restore the call to check_docker before invoking
check_network so the script runs the Docker environment validation first
(re-enable the check_docker invocation above the check_network call), ensuring
any Docker-related failures are detected and reported early by the existing
check_docker routine.

In `@justfile`:
- Around line 47-54: The justfile target seed-all currently calls seed-mongo
twice and never invokes the seed-mysql-1gb target; update the seed-all recipe to
remove the duplicate "just seed-mongo" and replace it with "just seed-mysql-1gb"
so the sequence includes seed-mysql, seed-mysql-1gb, seed-postgres,
seed-postgres-1gb, seed-sqlite, and seed-firebird (refer to the seed-all target
and the individual targets seed-mongo, seed-mysql, seed-mysql-1gb,
seed-postgres, seed-postgres-1gb, seed-sqlite, seed-firebird to locate and edit
the lines).

In `@scripts/sqlite/seed.sh`:
- Around line 12-13: The script uses a recursive world-writable chmod (docker
exec -u 0 db-sqlite sh -c "chmod -R 777 /workspace/data") which is too
permissive; change it to only affect the DB file/dir with least privilege (e.g.,
ensure /workspace/data/app.db exists with touch, then set non-recursive and
tighter perms like chmod 660 /workspace/data/app.db and chmod 750
/workspace/data) and, if needed, set the correct ownership (chown) for the DB
process user instead of making everything 777; update the commands in seed.sh
that reference chmod -R 777 and touch so they target /workspace/data/app.db and
the parent dir only.

In `@src/tests/domain/firebird.rs`:
- Line 42: The test currently uses a hard-coded generated_id
("3c445eb4-c2c6-4bde-a423-ee1385dcf6d2") which causes cross-test contention;
replace the constant string used for the generated_id field in the test (the
struct initialization that sets generated_id) with a runtime-generated unique
value (e.g., Uuid::new_v4().to_string() or a timestamp-based ID) so each test
run gets a distinct generated_id; update any imports (e.g., add uuid::Uuid) if
necessary.
- Around line 16-27: Replace the floating "latest" image tag in
GenericImage::new with the pinned tag "jacobalberty/firebird:v4.0" and remove
the manual sleep; instead chain the container builder with the image health wait
(use .with_wait_for_healthcheck() after .with_exposed_port(3050.tcp())) so
startup waits for the built-in HEALTHCHECK, or if your testcontainers version
lacks healthcheck support use .with_wait_for_tcp(3050) to deterministically wait
for the port rather than tokio::time::sleep(Duration::from_secs(10)).

---

Nitpick comments:
In `@docker-compose.databases.yml`:
- Line 18: Replace the floating tag "mariadb:latest" used in the service image
declaration (currently "image: mariadb:latest") with a pinned, explicit version
(for example "mariadb:11" or another tested patch version) to ensure
reproducible builds; mirror the approach used for "mysql:9.5" so the compose
file uses fixed database image tags rather than "latest".
- Around line 142-158: The db-firebird service uses the official
firebirdsql/firebird image which already provides a built-in healthcheck, so
remove any added/incorrect custom healthcheck or, if you prefer consistency,
replace the broken command with a simple port check (e.g., use nc against
127.0.0.1:3050) instead of the incorrect database path syntax; locate the
db-firebird service (container_name: db-firebird, image: firebirdsql/firebird)
and either omit a custom healthcheck entirely or implement the port-based CMD
healthcheck.

In `@src/tests/domain/firebird.rs`:
- Around line 56-57: Replace the use of unwrap_or(false) which masks errors when
calling db.ping().await in the tests: change the lines using let reachable =
db.ping().await.unwrap_or(false); (and the other occurrences at the same file)
to use expect(...) on the await result so a failing ping preserves the original
error context (i.e., call db.ping().await.expect("ping failed in firebird test")
and keep the reachable variable logic the same).
🪄 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: 96c2a9e8-a067-48b8-8f91-57fe5a5743f2

📥 Commits

Reviewing files that changed from the base of the PR and between 2ab293a and 014eb16.

📒 Files selected for processing (12)
  • Makefile
  • docker-compose.databases.yml
  • docker-compose.yml
  • docker/entrypoints/app-dev-entrypoint.sh
  • justfile
  • scripts/sqlite/seed.sh
  • src/domain/firebird/ping.rs
  • src/domain/redis/ping.rs
  • src/domain/valkey/ping.rs
  • src/services/status.rs
  • src/tests/domain/firebird.rs
  • src/tests/domain/mod.rs
💤 Files with no reviewable changes (1)
  • Makefile
✅ Files skipped from review due to trivial changes (1)
  • src/tests/domain/mod.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/domain/firebird/ping.rs

Comment on lines +61 to +65
healthcheck:
test: [ "CMD", "mongo", "--eval", "db.adminCommand('ping')" ]
interval: 5s
timeout: 5s
retries: 10
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

Healthcheck uses deprecated mongo shell that doesn't exist in modern MongoDB images.

The mongo shell was removed in MongoDB 6.0+ and replaced with mongosh. Since this service uses mongo:latest (currently 7.x+), the healthcheck will fail because the mongo binary doesn't exist. The db-mongodb service correctly uses mongosh on line 75.

🔧 Proposed fix
     healthcheck:
-      test: [ "CMD", "mongo", "--eval", "db.adminCommand('ping')" ]
+      test: [ "CMD", "mongosh", "--eval", "db.adminCommand('ping')" ]
       interval: 5s
       timeout: 5s
       retries: 10
📝 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
healthcheck:
test: [ "CMD", "mongo", "--eval", "db.adminCommand('ping')" ]
interval: 5s
timeout: 5s
retries: 10
healthcheck:
test: [ "CMD", "mongosh", "--eval", "db.adminCommand('ping')" ]
interval: 5s
timeout: 5s
retries: 10
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker-compose.databases.yml` around lines 61 - 65, The healthcheck block
currently invokes the removed "mongo" shell (test: [ "CMD", "mongo", "--eval",
"db.adminCommand('ping')" ]) which fails on modern Mongo images; update the
healthcheck to call "mongosh" instead and keep the same eval expression (e.g.,
replace the test entry so it invokes "mongosh" with the --eval
"db.adminCommand('ping')" argument), mirroring how the db-mongodb service uses
mongosh so the container health check succeeds on MongoDB 6+/7+ images.

Comment on lines +84 to +92
sqlite:
container_name: db-sqlite
image: keinos/sqlite3
volumes:
- sqlite-data:/workspace/data
working_dir: /workspace
command: tail -f /dev/null
stdin_open: true
tty: true
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 | 🟡 Minor

SQLite service is missing network configuration.

Unlike all other services in this file, the sqlite service is not connected to the portabase network. If this is intentional (SQLite being file-based), this is fine. However, if consistency with other services or network access is needed, the network configuration should be added.

🔧 Proposed fix if network access is needed
   sqlite:
     container_name: db-sqlite
     image: keinos/sqlite3
     volumes:
       - sqlite-data:/workspace/data
     working_dir: /workspace
     command: tail -f /dev/null
     stdin_open: true
     tty: true
+    networks:
+      - portabase
📝 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
sqlite:
container_name: db-sqlite
image: keinos/sqlite3
volumes:
- sqlite-data:/workspace/data
working_dir: /workspace
command: tail -f /dev/null
stdin_open: true
tty: true
sqlite:
container_name: db-sqlite
image: keinos/sqlite3
volumes:
- sqlite-data:/workspace/data
working_dir: /workspace
command: tail -f /dev/null
stdin_open: true
tty: true
networks:
- portabase
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker-compose.databases.yml` around lines 84 - 92, The sqlite service block
(service name "sqlite") currently lacks the networks configuration and should be
attached to the same "portabase" network as the other DB services; update the
sqlite service to include a networks key referencing "portabase" (and ensure the
top-level networks: portabase definition remains present) so the container joins
the network like the other services and can communicate as required.

LOG: debug
TZ: "Europe/Paris"
EDGE_KEY: "eyJzZXJ2ZXJVcmwiOiJodHRwOi8vbG9jYWxob3N0Ojg4ODciLCJhZ2VudElkIjoiNGI1OTM2MGItNTNkMi00ZTZmLWE1ODctODcyMmQ1NDc1MTNmIiwibWFzdGVyS2V5QjY0IjoiQlhWM1hvbEM2NTZTVjdkTmdjV1BHUWxrKytycExJNmxHRGk3Q1BCNWllbz0ifQ=="
EDGE_KEY: "eyJzZXJ2ZXJVcmwiOiJodHRwOi8vbG9jYWxob3N0Ojg4ODciLCJhZ2VudElkIjoiZWQzNDNmOTUtNTU0Yi00NTAwLTkzZjAtMzEyODQzMjQ2M2RhIiwibWFzdGVyS2V5QjY0IjoiQlhWM1hvbEM2NTZTVjdkTmdjV1BHUWxrKytycExJNmxHRGk3Q1BCNWllbz0ifQ=="
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 | 🔴 Critical

Remove hardcoded EDGE_KEY from versioned config.

Line 22 embeds a credential-like token directly in source. This should be treated as secret leakage and replaced with environment injection.

Suggested fix
-      EDGE_KEY: "eyJzZXJ2ZXJVcmwiOiJodHRwOi8vbG9jYWxob3N0Ojg4ODciLCJhZ2VudElkIjoiZWQzNDNmOTUtNTU0Yi00NTAwLTkzZjAtMzEyODQzMjQ2M2RhIiwibWFzdGVyS2V5QjY0IjoiQlhWM1hvbEM2NTZTVjdkTmdjV1BHUWxrKytycExJNmxHRGk3Q1BCNWllbz0ifQ=="
+      EDGE_KEY: "${EDGE_KEY:?EDGE_KEY is required}"
📝 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
EDGE_KEY: "eyJzZXJ2ZXJVcmwiOiJodHRwOi8vbG9jYWxob3N0Ojg4ODciLCJhZ2VudElkIjoiZWQzNDNmOTUtNTU0Yi00NTAwLTkzZjAtMzEyODQzMjQ2M2RhIiwibWFzdGVyS2V5QjY0IjoiQlhWM1hvbEM2NTZTVjdkTmdjV1BHUWxrKytycExJNmxHRGk3Q1BCNWllbz0ifQ=="
EDGE_KEY: "${EDGE_KEY:?EDGE_KEY is required}"
🧰 Tools
🪛 Betterleaks (1.1.1)

[high] 22-22: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 22-22: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

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

In `@docker-compose.yml` at line 22, Replace the hardcoded EDGE_KEY value in
docker-compose.yml with an environment-injected secret (e.g., set EDGE_KEY:
"${EDGE_KEY}" or use env_file/secrets in the same docker-compose.yml) and store
the real token outside the repo (in a .env or Docker secret manager); update
deployment docs to instruct providing EDGE_KEY via environment or secrets and
remove the embedded token from the repository history/commit if necessary.

Comment on lines +34 to 35
#check_docker
check_network
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 | 🟡 Minor

Restore Docker preflight check before network/compose steps.

Commenting out check_docker removes graceful startup handling and can fail early with less actionable errors.

Suggested fix
-#check_docker
+check_docker
 check_network
📝 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
#check_docker
check_network
check_docker
check_network
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker/entrypoints/app-dev-entrypoint.sh` around lines 34 - 35, The preflight
Docker check was commented out, removing graceful startup handling; restore the
call to check_docker before invoking check_network so the script runs the Docker
environment validation first (re-enable the check_docker invocation above the
check_network call), ensuring any Docker-related failures are detected and
reported early by the existing check_docker routine.

Comment on lines +47 to +54
seed-all:
just seed-mongo
just seed-mysql
just seed-postgres
just seed-postgres-1gb
just seed-sqlite
just seed-mongo
just seed-firebird No newline at end of file
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

seed-all duplicates Mongo and skips MySQL 1GB seed.

Current chain runs seed-mongo twice and never calls seed-mysql-1gb, so full dataset seeding is inconsistent.

Suggested fix
 seed-all:
     just seed-mongo
     just seed-mysql
+    just seed-mysql-1gb
     just seed-postgres
     just seed-postgres-1gb
     just seed-sqlite
-    just seed-mongo
     just seed-firebird
📝 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
seed-all:
just seed-mongo
just seed-mysql
just seed-postgres
just seed-postgres-1gb
just seed-sqlite
just seed-mongo
just seed-firebird
seed-all:
just seed-mongo
just seed-mysql
just seed-mysql-1gb
just seed-postgres
just seed-postgres-1gb
just seed-sqlite
just seed-firebird
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@justfile` around lines 47 - 54, The justfile target seed-all currently calls
seed-mongo twice and never invokes the seed-mysql-1gb target; update the
seed-all recipe to remove the duplicate "just seed-mongo" and replace it with
"just seed-mysql-1gb" so the sequence includes seed-mysql, seed-mysql-1gb,
seed-postgres, seed-postgres-1gb, seed-sqlite, and seed-firebird (refer to the
seed-all target and the individual targets seed-mongo, seed-mysql,
seed-mysql-1gb, seed-postgres, seed-postgres-1gb, seed-sqlite, seed-firebird to
locate and edit the lines).

Comment on lines +12 to +13
docker exec -u 0 db-sqlite sh -c "chmod -R 777 /workspace/data"
docker exec -u 0 db-sqlite sh -c "touch /workspace/data/app.db"
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

Avoid recursive chmod -R 777 on the SQLite volume.

Line 12 makes the full data tree world-writable, which is too permissive even for dev flows. Scope permissions to the DB file/dir with least privilege.

Suggested hardening
-docker exec -u 0 db-sqlite sh -c "chmod -R 777 /workspace/data"
-docker exec -u 0 db-sqlite sh -c "touch /workspace/data/app.db"
+docker exec -u 0 db-sqlite sh -c "mkdir -p /workspace/data && touch /workspace/data/app.db && chmod 775 /workspace/data && chmod 664 /workspace/data/app.db"
📝 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
docker exec -u 0 db-sqlite sh -c "chmod -R 777 /workspace/data"
docker exec -u 0 db-sqlite sh -c "touch /workspace/data/app.db"
docker exec -u 0 db-sqlite sh -c "mkdir -p /workspace/data && touch /workspace/data/app.db && chmod 775 /workspace/data && chmod 664 /workspace/data/app.db"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/sqlite/seed.sh` around lines 12 - 13, The script uses a recursive
world-writable chmod (docker exec -u 0 db-sqlite sh -c "chmod -R 777
/workspace/data") which is too permissive; change it to only affect the DB
file/dir with least privilege (e.g., ensure /workspace/data/app.db exists with
touch, then set non-recursive and tighter perms like chmod 660
/workspace/data/app.db and chmod 750 /workspace/data) and, if needed, set the
correct ownership (chown) for the DB process user instead of making everything
777; update the commands in seed.sh that reference chmod -R 777 and touch so
they target /workspace/data/app.db and the parent dir only.

Comment on lines +16 to +27
let container = GenericImage::new("jacobalberty/firebird", "latest")
.with_exposed_port(3050.tcp())
.with_env_var("FIREBIRD_ROOT_PASSWORD", "fake_root_password")
.with_env_var("FIREBIRD_USER", "alice")
.with_env_var("FIREBIRD_PASSWORD", "fake_password")
.with_env_var("FIREBIRD_DATABASE", "mirror.fdb")
.with_env_var("FIREBIRD_DATABASE_DEFAULT_CHARSET", "UTF8")
.start()
.await
.expect("Firebird started");

tokio::time::sleep(Duration::from_secs(10)).await;
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

🌐 Web query:

For the testcontainers Rust version used here, what is the recommended readiness strategy for Firebird containers, and which pinned Firebird image tag should be used instead of latest for stable CI?

💡 Result:

For Testcontainers in Rust using the jacobalberty/firebird image, the recommended readiness strategy is WaitFor::Healthcheck, as the image includes a HEALTHCHECK command (docker-healthcheck.sh checking port 3050 connectivity). Alternatively, WaitFor::message_on_stdout for Firebird startup messages or a tcp connection check on port 3050 can be used. Use the pinned tag jacobalberty/firebird:v4.0 instead of latest for stable CI, as it corresponds to a specific Firebird 4.0 release, aligns with examples from other Testcontainers implementations (e.g., .NET module), and avoids breaking changes from latest (which points to an older build over 3 years old). v5.0 is also available but less commonly referenced for testing.

Citations:


🏁 Script executed:

# Check if the file exists and inspect lines 16-27
if [ -f "src/tests/domain/firebird.rs" ]; then
  echo "File found. Checking lines 16-27:"
  sed -n '16,27p' src/tests/domain/firebird.rs
  echo ""
  echo "Full context (lines 10-35):"
  sed -n '10,35p' src/tests/domain/firebird.rs
else
  echo "File not found at src/tests/domain/firebird.rs"
  find . -name "firebird.rs" -type f 2>/dev/null | head -5
fi

Repository: Portabase/agent

Length of output: 1612


Replace latest tag with pinned version and add proper health check strategy.

Using latest (Line 16) creates flaky CI across image updates. The jacobalberty/firebird image has a built-in HEALTHCHECK (port 3050), making the hardcoded 10s sleep (Line 27) unnecessary and non-deterministic.

Replace with jacobalberty/firebird:v4.0 and add .with_wait_for_healthcheck() to leverage the image's health check. If using an older testcontainers version without health check support, use .with_wait_for_tcp(3050) for deterministic port readiness instead of the fixed sleep.

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

In `@src/tests/domain/firebird.rs` around lines 16 - 27, Replace the floating
"latest" image tag in GenericImage::new with the pinned tag
"jacobalberty/firebird:v4.0" and remove the manual sleep; instead chain the
container builder with the image health wait (use .with_wait_for_healthcheck()
after .with_exposed_port(3050.tcp())) so startup waits for the built-in
HEALTHCHECK, or if your testcontainers version lacks healthcheck support use
.with_wait_for_tcp(3050) to deterministically wait for the port rather than
tokio::time::sleep(Duration::from_secs(10)).

password: "fake_password".to_string(),
port,
host,
generated_id: "3c445eb4-c2c6-4bde-a423-ee1385dcf6d2".to_string(),
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 | 🟡 Minor

Use a unique generated_id per test run.

A constant ID increases cross-test contention on lock/file paths tied to generated_id.

Suggested fix
-        generated_id: "3c445eb4-c2c6-4bde-a423-ee1385dcf6d2".to_string(),
+        generated_id: format!("firebird-test-{}", port),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tests/domain/firebird.rs` at line 42, The test currently uses a
hard-coded generated_id ("3c445eb4-c2c6-4bde-a423-ee1385dcf6d2") which causes
cross-test contention; replace the constant string used for the generated_id
field in the test (the struct initialization that sets generated_id) with a
runtime-generated unique value (e.g., Uuid::new_v4().to_string() or a
timestamp-based ID) so each test run gets a distinct generated_id; update any
imports (e.g., add uuid::Uuid) if necessary.

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: 1

🧹 Nitpick comments (5)
src/domain/firebird/ping.rs (2)

27-29: Ensure stdin is closed before waiting for output.

Taking stdin from the child process is correct, but the stdin handle should be explicitly dropped after writing to signal EOF to isql-fb. Currently, stdin goes out of scope at the end of the if let block, which should work, but making this explicit improves clarity and avoids potential deadlock if the compiler reorders.

♻️ Suggested improvement
     if let Some(mut stdin) = child.stdin.take() {
         stdin.write_all(query).await?;
+        drop(stdin); // Explicitly close stdin to signal EOF
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/domain/firebird/ping.rs` around lines 27 - 29, The code writes to the
child's stdin via child.stdin.take() and stdin.write_all(query).await but
doesn't explicitly close stdin; after awaiting write_all, explicitly drop the
stdin handle (e.g., call drop(stdin)) to ensure EOF is sent to isql-fb before
waiting for output — locate the child.stdin.take() /
stdin.write_all(query).await sequence in ping.rs and add the explicit drop of
stdin immediately after the awaited write.

49-51: Fragile success check - stdout.contains("1") may produce false positives.

The check stdout.contains("1") could incorrectly match version strings, row counts, or other output containing "1". The expected output from SELECT 1 FROM RDB$DATABASE; is a single row with value 1, but isql-fb output formatting may include headers or other text.

Consider a more precise pattern match or trimming/parsing the output.

♻️ Suggested improvement
-    if stdout.contains("1") {
+    // isql-fb outputs the result with column alignment; look for standalone "1"
+    if stdout.lines().any(|line| line.trim() == "1") {
         return Ok(true);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/domain/firebird/ping.rs` around lines 49 - 51, The success check using
stdout.contains("1") is too broad; update the check in ping.rs (the code reading
isql-fb output stored in stdout) to parse/trim output and match a precise
pattern such as the last non-empty line equaling "1" or a regex like ^\s*1\s*$
instead of contains, so headers/footer or other "1" occurrences won't produce
false positives; ensure you perform trim/split on stdout and verify the exact
value before returning Ok(true).
src/tests/domain/firebird.rs (2)

104-113: Replace verbose match with idiomatic assertion.

The match block with assert!(true) and assert!(false) is non-idiomatic and obscures test intent. Use unwrap(), expect(), or assert! directly on the result.

♻️ Suggested improvement
-    match db.restore(&backup_file).await {
-        Ok(_) => {
-            info!("Restore succeeded for {}", config.generated_id);
-            assert!(true)
-        }
-        Err(e) => {
-            error!("Restore failed for {}: {:?}", config.generated_id, e);
-            assert!(false)
-        }
-    }
+    db.restore(&backup_file)
+        .await
+        .expect("Restore should succeed");
+    info!("Restore succeeded for {}", config.generated_id);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tests/domain/firebird.rs` around lines 104 - 113, The match on
db.restore(&backup_file).await should be replaced with an idiomatic assertion:
call db.restore(&backup_file).await.expect(...) or .unwrap() so the test fails
with a clear message instead of assert!(true)/assert!(false); include
config.generated_id in the expect message for context (e.g.,
db.restore(&backup_file).await.expect(&format!("Restore failed for {}",
config.generated_id))). This change targets the restore call in the test
(db.restore, backup_file, config.generated_id) and removes the verbose match
block.

78-78: Remove or justify the 10-second sleep after backup.

This sleep appears arbitrary. If it's waiting for file system sync or some async completion, consider polling the file existence or using a more deterministic approach.

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

In `@src/tests/domain/firebird.rs` at line 78, The arbitrary
tokio::time::sleep(Duration::from_secs(10)).await; should be removed or replaced
with a deterministic wait: instead of sleeping 10s, poll for the expected backup
completion (e.g., loop using tokio::time::sleep with a short interval and check
file existence/metadata or a completion flag) and bound the loop with a timeout
(tokio::time::timeout) to fail deterministically; update the test in
src/tests/domain/firebird.rs to use that polling+timeout approach (replace the
direct call to tokio::time::sleep(Duration::from_secs(10)).await with a check
for the backup file or process completion).
docker-compose.databases.yml (1)

142-158: Firebird service configuration looks good; consider adding a healthcheck.

The Firebird service is well-configured with proper environment variables, volume mount, and network. For consistency with other database services and to enable dependent services to wait for readiness, consider adding a healthcheck.

♻️ Suggested healthcheck
   db-firebird:
     image: firebirdsql/firebird
     container_name: db-firebird
     restart: always
     environment:
       - FIREBIRD_ROOT_PASSWORD=fake_root_password
       - FIREBIRD_USER=alice
       - FIREBIRD_PASSWORD=fake_password
       - FIREBIRD_DATABASE=mirror.fdb
       - FIREBIRD_DATABASE_DEFAULT_CHARSET=UTF8
     volumes:
       - firebird-data:/var/lib/firebird/data
     ports:
       - "3060:3050"
+    healthcheck:
+      test: ["CMD-SHELL", "echo 'SELECT 1 FROM RDB$DATABASE;' | isql-fb -q -user alice -password fake_password localhost:/var/lib/firebird/data/mirror.fdb || exit 1"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
     networks:
       - portabase
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker-compose.databases.yml` around lines 142 - 158, Add a Docker
healthcheck entry to the db-firebird service to allow dependent services to wait
for readiness: add a healthcheck block under the db-firebird service that runs a
short command which verifies the database is accepting connections (for example
using gstat or isql and the existing
FIREBIRD_USER/FIREBIRD_PASSWORD/FIREBIRD_DATABASE env vars), and configure
sensible timing (e.g., interval ~30s, timeout ~10s, retries ~5, start_period
~30s) so Docker reports healthy/unhealthy reliably.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docker-compose.yml`:
- Around line 12-13: The compose mounts databases.json to /config/config.json
while DATABASES_CONFIG_FILE is set to "config.toml", causing the app to look for
/config/config.toml and fail; fix by either mounting databases.toml to
/config/config.toml (uncomment the databases.toml volume and remove or replace
the databases.json mount) or change DATABASES_CONFIG_FILE to "config.json" so it
matches the existing mount; key symbols to check/update: DATABASES_CONFIG_FILE,
the mounted filenames databases.json and databases.toml, and the resolved path
/config/config.toml referenced by the config loader.

---

Nitpick comments:
In `@docker-compose.databases.yml`:
- Around line 142-158: Add a Docker healthcheck entry to the db-firebird service
to allow dependent services to wait for readiness: add a healthcheck block under
the db-firebird service that runs a short command which verifies the database is
accepting connections (for example using gstat or isql and the existing
FIREBIRD_USER/FIREBIRD_PASSWORD/FIREBIRD_DATABASE env vars), and configure
sensible timing (e.g., interval ~30s, timeout ~10s, retries ~5, start_period
~30s) so Docker reports healthy/unhealthy reliably.

In `@src/domain/firebird/ping.rs`:
- Around line 27-29: The code writes to the child's stdin via child.stdin.take()
and stdin.write_all(query).await but doesn't explicitly close stdin; after
awaiting write_all, explicitly drop the stdin handle (e.g., call drop(stdin)) to
ensure EOF is sent to isql-fb before waiting for output — locate the
child.stdin.take() / stdin.write_all(query).await sequence in ping.rs and add
the explicit drop of stdin immediately after the awaited write.
- Around line 49-51: The success check using stdout.contains("1") is too broad;
update the check in ping.rs (the code reading isql-fb output stored in stdout)
to parse/trim output and match a precise pattern such as the last non-empty line
equaling "1" or a regex like ^\s*1\s*$ instead of contains, so headers/footer or
other "1" occurrences won't produce false positives; ensure you perform
trim/split on stdout and verify the exact value before returning Ok(true).

In `@src/tests/domain/firebird.rs`:
- Around line 104-113: The match on db.restore(&backup_file).await should be
replaced with an idiomatic assertion: call
db.restore(&backup_file).await.expect(...) or .unwrap() so the test fails with a
clear message instead of assert!(true)/assert!(false); include
config.generated_id in the expect message for context (e.g.,
db.restore(&backup_file).await.expect(&format!("Restore failed for {}",
config.generated_id))). This change targets the restore call in the test
(db.restore, backup_file, config.generated_id) and removes the verbose match
block.
- Line 78: The arbitrary tokio::time::sleep(Duration::from_secs(10)).await;
should be removed or replaced with a deterministic wait: instead of sleeping
10s, poll for the expected backup completion (e.g., loop using
tokio::time::sleep with a short interval and check file existence/metadata or a
completion flag) and bound the loop with a timeout (tokio::time::timeout) to
fail deterministically; update the test in src/tests/domain/firebird.rs to use
that polling+timeout approach (replace the direct call to
tokio::time::sleep(Duration::from_secs(10)).await with a check for the backup
file or process completion).
🪄 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: 848b1d65-dae1-4fcd-a7fb-a79f042d5f90

📥 Commits

Reviewing files that changed from the base of the PR and between 2ab293a and 05f795c.

📒 Files selected for processing (16)
  • Makefile
  • databases.json
  • databases.toml
  • docker-compose.databases.yml
  • docker-compose.yml
  • docker/entrypoints/app-dev-entrypoint.sh
  • justfile
  • scripts/sqlite/seed.sh
  • src/domain/firebird/ping.rs
  • src/domain/firebird/restore.rs
  • src/domain/redis/ping.rs
  • src/domain/sqlite/backup.rs
  • src/domain/valkey/ping.rs
  • src/services/status.rs
  • src/tests/domain/firebird.rs
  • src/tests/domain/mod.rs
💤 Files with no reviewable changes (1)
  • Makefile
✅ Files skipped from review due to trivial changes (5)
  • src/domain/valkey/ping.rs
  • src/domain/sqlite/backup.rs
  • src/domain/redis/ping.rs
  • src/tests/domain/mod.rs
  • src/services/status.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • docker/entrypoints/app-dev-entrypoint.sh
  • src/domain/firebird/restore.rs
  • databases.json
  • justfile
  • scripts/sqlite/seed.sh

Comment on lines +12 to +13
- ./databases.json:/config/config.json
#- ./databases.toml:/config/config.toml
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 | 🔴 Critical

Configuration file mismatch will cause startup failure.

DATABASES_CONFIG_FILE is set to "config.toml" (line 24), but the mounted volume is databases.json:/config/config.json (line 12), and the databases.toml mount is commented out (line 13).

Per src/services/config.rs:93-125, the app resolves the path as /config/config.toml, which won't exist. This will fail with "Config file not found" on startup.

Either:

  1. Uncomment line 13 and mount databases.toml to /config/config.toml, or
  2. Change DATABASES_CONFIG_FILE to "config.json"
🐛 Option 1: Mount the TOML file
       - ./databases.json:/config/config.json
-      `#-` ./databases.toml:/config/config.toml
+      - ./databases.toml:/config/config.toml
🐛 Option 2: Use JSON config
-      DATABASES_CONFIG_FILE: "config.toml"
+      DATABASES_CONFIG_FILE: "config.json"

Also applies to: 24-24

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

In `@docker-compose.yml` around lines 12 - 13, The compose mounts databases.json
to /config/config.json while DATABASES_CONFIG_FILE is set to "config.toml",
causing the app to look for /config/config.toml and fail; fix by either mounting
databases.toml to /config/config.toml (uncomment the databases.toml volume and
remove or replace the databases.json mount) or change DATABASES_CONFIG_FILE to
"config.json" so it matches the existing mount; key symbols to check/update:
DATABASES_CONFIG_FILE, the mounted filenames databases.json and databases.toml,
and the resolved path /config/config.toml referenced by the config loader.

@RambokDev RambokDev merged commit f37e4d2 into main Mar 31, 2026
3 checks passed
@RambokDev RambokDev deleted the feat/add-firebird branch March 31, 2026 13:10
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