Skip to content

Fix Cache Poisoning in Blockchain Integrity Check#632

Merged
RohanExploit merged 4 commits into
mainfrom
fix/cache-poisoning-9188716175601989125
Apr 5, 2026
Merged

Fix Cache Poisoning in Blockchain Integrity Check#632
RohanExploit merged 4 commits into
mainfrom
fix/cache-poisoning-9188716175601989125

Conversation

@RohanExploit
Copy link
Copy Markdown
Owner

@RohanExploit RohanExploit commented Apr 4, 2026

Fixes a logical bug where the application's integrity hash caches were being updated prior to successful database commits. This addresses the "cache poisoning" issue. If a database insert failed, the cache would maintain a hash that didn't exist in the database, breaking the hash chain for all future reports.


PR created automatically by Jules for task 9188716175601989125 started by @RohanExploit


Summary by cubic

Fixes cache poisoning by updating integrity hash caches only after successful DB commits. Unifies netlify.toml and uses relative paths under base = "frontend" to fix CI builds.

  • Bug Fixes

    • Move visit_last_hash_cache.set() and blockchain_last_hash_cache.set() after db.commit() in backend/routers/field_officer.py and backend/routers/issues.py.
    • Remove frontend/netlify.toml, migrate env vars to root netlify.toml, set npm install && npm run build, and use relative paths (publish = "dist") under base = "frontend" to avoid frontend/frontend/dist errors.
  • New Features

    • Add run_tests.sh to create a venv and run backend tests with pytest, pytest-asyncio, and pytest-mock.

Written for commit e9c9a07. Summary will update on new commits.

Summary by CodeRabbit

  • Bug Fixes

    • Cache updates for check-ins and issue creation now occur only after successful database commits, improving data consistency.
  • Chores

    • Added a script to set up a test environment and run backend tests.
    • Build process updated to install dependencies before running the frontend build and to set explicit build environment variables.
    • Removed an obsolete frontend Netlify configuration.

Move `blockchain_last_hash_cache.set()` and `visit_last_hash_cache.set()`
after the `db.commit()` logic in `backend/routers/issues.py` and
`backend/routers/field_officer.py`. This ensures that the cache is
not poisoned with hashes of records that failed to insert into the
database, preserving the blockchain integrity.
@google-labs-jules
Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings April 4, 2026 10:47
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 4, 2026

Deploy Preview for fixmybharat failed. Why did it fail? →

Name Link
🔨 Latest commit e9c9a07
🔍 Latest deploy log https://app.netlify.com/projects/fixmybharat/deploys/69d0f3bbec17470008c75107

@RohanExploit RohanExploit temporarily deployed to fix/cache-poisoning-9188716175601989125 - vishwaguru-backend PR #632 April 4, 2026 10:47 — with Render Destroyed
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 4, 2026

🙏 Thank you for your contribution, @RohanExploit!

PR Details:

Quality Checklist:
Please ensure your PR meets the following criteria:

  • Code follows the project's style guidelines
  • Self-review of code completed
  • Code is commented where necessary
  • Documentation updated (if applicable)
  • No new warnings generated
  • Tests added/updated (if applicable)
  • All tests passing locally
  • No breaking changes to existing functionality

Review Process:

  1. Automated checks will run on your code
  2. A maintainer will review your changes
  3. Address any requested changes promptly
  4. Once approved, your PR will be merged! 🎉

Note: The maintainers will monitor code quality and ensure the overall project flow isn't broken.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 28cf65b7-b827-493b-a4c0-6d219605fdc3

📥 Commits

Reviewing files that changed from the base of the PR and between 678d3c8 and e9c9a07.

📒 Files selected for processing (2)
  • frontend/netlify.toml
  • netlify.toml
💤 Files with no reviewable changes (1)
  • frontend/netlify.toml
🚧 Files skipped from review as they are similar to previous changes (1)
  • netlify.toml

📝 Walkthrough

Walkthrough

Cache writes for the blockchain last_hash were moved to occur only after successful database commits in the field-officer and issue endpoints. A new run_tests.sh script was added. The frontend Netlify config file was removed and the root netlify.toml build/env settings were updated.

Changes

Cohort / File(s) Summary
Cache Update Timing
backend/routers/field_officer.py, backend/routers/issues.py
Removed pre-commit visit_last_hash/last_hash cache writes; added identical cache updates after db.commit() / successful save so cache reflects persisted records.
Test Infrastructure
run_tests.sh
Added script that creates a Python venv, installs backend test deps plus pytest, pytest-asyncio, pytest-mock, and runs pytest backend/tests/ with TELEGRAM_BOT_TOKEN=test and PYTHONPATH set.
Netlify Build Config
netlify.toml, frontend/netlify.toml
Updated root netlify.toml build command to npm install && npm run build and added [build.environment] (NODE_VERSION="20", CI="false"). Removed frontend/netlify.toml (deleted frontend Netlify config).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

size/m, ECWoC26-ENDED

Poem

🐇 I hopped through code with careful paws,
Held off the cache until DB laws,
Committed truth, then set the key,
Tests now snug — come run with me! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.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
Title check ✅ Passed The title accurately describes the main change: fixing cache poisoning in blockchain integrity checks by moving cache updates after database commits.
Description check ✅ Passed The description provides comprehensive context about the cache poisoning bug, specific file changes, and rationale. However, it lacks structured coverage of the template's Type of Change checkboxes and Testing Done section.

✏️ 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 fix/cache-poisoning-9188716175601989125

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
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a cache-poisoning bug in the “blockchain” integrity-hash chaining logic by ensuring the “last hash” caches are only advanced after the corresponding database write has succeeded, preventing the cache from getting ahead of persisted state.

Changes:

  • Move blockchain_last_hash_cache update to after successful issue persistence in create_issue.
  • Move visit_last_hash_cache update to after successful field officer visit persistence in officer_check_in.
  • Add a run_tests.sh helper script for setting up a venv and running backend tests.

Reviewed changes

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

File Description
backend/routers/issues.py Delays integrity-hash cache advancement until after the issue is saved/committed.
backend/routers/field_officer.py Delays visit-hash cache advancement until after the visit is saved/committed.
run_tests.sh Adds a simple local test runner script (venv + pytest).

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

Comment thread backend/routers/issues.py
Comment on lines 210 to +214
# Offload blocking DB operations to threadpool
await run_in_threadpool(save_issue_db, db, new_issue)

# Update cache for next report AFTER successful DB commit
blockchain_last_hash_cache.set(data=integrity_hash, key="last_hash")
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

The cache update is now gated on save_issue_db completing successfully, but save_issue_db does both commit() and refresh(). If commit() succeeds and refresh() later raises (e.g., transient DB disconnect), the row is already persisted but the cache won’t be updated, leaving a stale last_hash that can cause the next integrity hash to chain from the wrong predecessor until TTL expiry. Consider updating the cache immediately after a confirmed commit (or restructuring save_issue_db / error handling so cache update happens once commit succeeds even if refresh/response building fails).

Copilot uses AI. Check for mistakes.
Comment on lines 146 to +150
db.refresh(new_visit)

# Update cache for next visit AFTER successful DB commit
visit_last_hash_cache.set(data=visit_hash, key="last_hash")

Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

Cache update happens after db.refresh(new_visit). If commit() succeeds but refresh() fails (separate DB round-trip), the visit row is persisted but the cache won’t advance, leaving last_hash stale and potentially breaking the visit hash chain for subsequent check-ins until the cache expires. Consider updating the cache immediately after a successful commit (and handling refresh errors separately) so the cache reflects the DB state once the transaction is committed.

Suggested change
db.refresh(new_visit)
# Update cache for next visit AFTER successful DB commit
visit_last_hash_cache.set(data=visit_hash, key="last_hash")
# Update cache as soon as the transaction is committed so the
# hash chain state stays aligned with persisted DB state even if
# the subsequent refresh round-trip fails.
visit_last_hash_cache.set(data=visit_hash, key="last_hash")
try:
db.refresh(new_visit)
except Exception:
logger.exception(
"Visit committed but failed to refresh FieldOfficerVisit; cache already updated"
)
raise HTTPException(
status_code=500,
detail="Visit was saved, but the server failed to load the saved visit details."
)

Copilot uses AI. Check for mistakes.
Comment thread run_tests.sh
Comment on lines +2 to +4
python -m venv venv
source venv/bin/activate
pip install -r backend/requirements.txt pytest pytest-asyncio pytest-mock
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

run_tests.sh uses python/pip without verifying they exist or stopping on failure. In this repo other scripts check for python3 (e.g. deploy-backend.sh) and gate subsequent steps on command exit codes. Consider switching to python3 -m venv / python3 -m pip and adding set -e (or explicit exit-code checks) so dependency install failures don’t get masked by later pytest output.

Suggested change
python -m venv venv
source venv/bin/activate
pip install -r backend/requirements.txt pytest pytest-asyncio pytest-mock
set -e
python3 -m venv venv
source venv/bin/activate
python3 -m pip install -r backend/requirements.txt pytest pytest-asyncio pytest-mock

Copilot uses AI. Check for mistakes.
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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/routers/field_officer.py`:
- Around line 148-150: The cache update prevents cache-poisoning but doesn't
prevent two concurrent check-ins from reading the same prev_hash and both
committing children, so serialize the chain linking: when persisting a visit in
the handler that computes visit_hash and reads prev_hash from
visit_last_hash_cache, perform an atomic compare-and-set (or DB-backed
conditional update) that only sets visit_last_hash_cache to visit_hash if its
current value equals the prev_hash you read; if the CAS fails, abort/refresh
prev_hash and retry the visit persist (or return a conflict) to avoid forks. Use
the existing visit_last_hash_cache.set/get primitives or add an atomic method
(e.g., compare_and_set) and update the route logic that writes visit_hash to
rely on that atomic operation.

In `@backend/routers/issues.py`:
- Around line 213-214: Concurrent issue creations still compute integrity_hash
from a stale prev_hash; fix by performing predecessor selection and the insert
inside a database transaction with serialization/locking so only one writer can
read/update the chain head at a time. Modify the /issues write path (the handler
that computes integrity_hash and calls session.add/commit) to: begin a
transaction, select the chain head row with a FOR UPDATE (or lock the single row
that stores last_hash) or use a SERIALIZABLE transaction isolation level,
compute integrity_hash using that locked value, insert the new link, commit, and
only after successful commit call
blockchain_last_hash_cache.set(data=integrity_hash, key="last_hash"). Ensure you
use the existing DB session/commit methods in the handler (replace the current
compute-then-commit flow around integrity_hash and session.commit) so
predecessor selection and insert are atomic.

In `@run_tests.sh`:
- Around line 1-5: Add shell strictness and explicit failure checks to the test
runner: enable "set -euo pipefail" (and optionally IFS=$'\n\t') at the top of
run_tests.sh so any command (python -m venv, source venv/bin/activate, pip
install) failing will abort; after "source venv/bin/activate" verify activation
succeeded (e.g., check that $VIRTUAL_ENV is non-empty) and exit with a clear
error if not; ensure pip install and pytest invocations are not run in a
subshell that masks errors so their non-zero exit codes propagate (keep
TELEGRAM_BOT_TOKEN=... pytest invocation as-is but let the script strict flags
cause CI to fail fast on errors).
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8d4844d1-5143-47c9-85e4-68aba2e73de2

📥 Commits

Reviewing files that changed from the base of the PR and between 6fee644 and e8e043e.

📒 Files selected for processing (3)
  • backend/routers/field_officer.py
  • backend/routers/issues.py
  • run_tests.sh

Comment on lines +148 to +150
# Update cache for next visit AFTER successful DB commit
visit_last_hash_cache.set(data=visit_hash, key="last_hash")

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

Good cache-poisoning fix, but concurrent check-ins can still break chain continuity.

At Line 148, updating cache post-commit is correct, but two concurrent requests can still read the same prev_hash before either commit and both persist children of the same parent hash. Because visit_last_hash_cache is a shared singleton (backend/cache.py:176-183), this can fork the integrity chain.

Suggested direction (serialize write-path chain linking)
- prev_hash = visit_last_hash_cache.get("last_hash")
- if prev_hash is None:
-     prev_visit = db.query(FieldOfficerVisit.visit_hash).order_by(FieldOfficerVisit.id.desc()).first()
-     prev_hash = prev_visit[0] if prev_visit and prev_visit[0] else ""
-     visit_last_hash_cache.set(data=prev_hash, key="last_hash")
+ # For write path, derive predecessor in the same DB transaction and lock ordering.
+ prev_visit = (
+     db.query(FieldOfficerVisit.visit_hash)
+     .order_by(FieldOfficerVisit.id.desc())
+     .with_for_update()
+     .first()
+ )
+ prev_hash = prev_visit[0] if prev_visit and prev_visit[0] else ""
...
 db.add(new_visit)
 db.commit()
 visit_last_hash_cache.set(data=visit_hash, key="last_hash")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/routers/field_officer.py` around lines 148 - 150, The cache update
prevents cache-poisoning but doesn't prevent two concurrent check-ins from
reading the same prev_hash and both committing children, so serialize the chain
linking: when persisting a visit in the handler that computes visit_hash and
reads prev_hash from visit_last_hash_cache, perform an atomic compare-and-set
(or DB-backed conditional update) that only sets visit_last_hash_cache to
visit_hash if its current value equals the prev_hash you read; if the CAS fails,
abort/refresh prev_hash and retry the visit persist (or return a conflict) to
avoid forks. Use the existing visit_last_hash_cache.set/get primitives or add an
atomic method (e.g., compare_and_set) and update the route logic that writes
visit_hash to rely on that atomic operation.

Comment thread backend/routers/issues.py
Comment on lines +213 to +214
# Update cache for next report AFTER successful DB commit
blockchain_last_hash_cache.set(data=integrity_hash, key="last_hash")
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

Post-commit cache update helps, but integrity_hash generation is still race-prone.

At Line 213, cache update timing is fixed, but concurrent /issues creations can still compute integrity_hash from the same stale prev_hash and commit divergent chain links. The write path needs transactional serialization for predecessor selection + insert.

Suggested direction (transactional predecessor selection)
- prev_hash = blockchain_last_hash_cache.get("last_hash")
- if prev_hash is None:
-     prev_issue = await run_in_threadpool(
-         lambda: db.query(Issue.integrity_hash).order_by(Issue.id.desc()).first()
-     )
-     prev_hash = prev_issue[0] if prev_issue and prev_issue[0] else ""
-     blockchain_last_hash_cache.set(data=prev_hash, key="last_hash")
+ # In write path, read predecessor from DB inside the same transaction with locking.
+ prev_issue = await run_in_threadpool(
+     lambda: db.query(Issue.integrity_hash).order_by(Issue.id.desc()).with_for_update().first()
+ )
+ prev_hash = prev_issue[0] if prev_issue and prev_issue[0] else ""
...
 await run_in_threadpool(save_issue_db, db, new_issue)
 blockchain_last_hash_cache.set(data=integrity_hash, key="last_hash")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/routers/issues.py` around lines 213 - 214, Concurrent issue creations
still compute integrity_hash from a stale prev_hash; fix by performing
predecessor selection and the insert inside a database transaction with
serialization/locking so only one writer can read/update the chain head at a
time. Modify the /issues write path (the handler that computes integrity_hash
and calls session.add/commit) to: begin a transaction, select the chain head row
with a FOR UPDATE (or lock the single row that stores last_hash) or use a
SERIALIZABLE transaction isolation level, compute integrity_hash using that
locked value, insert the new link, commit, and only after successful commit call
blockchain_last_hash_cache.set(data=integrity_hash, key="last_hash"). Ensure you
use the existing DB session/commit methods in the handler (replace the current
compute-then-commit flow around integrity_hash and session.commit) so
predecessor selection and insert are atomic.

Comment thread run_tests.sh
Comment on lines +1 to +5
#!/bin/bash
python -m venv venv
source venv/bin/activate
pip install -r backend/requirements.txt pytest pytest-asyncio pytest-mock
TELEGRAM_BOT_TOKEN=test PYTHONPATH=. pytest backend/tests/
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

Make the test runner fail fast to avoid misleading CI results.

Without strict shell flags, setup failures can be masked and the script may continue into pytest with a broken environment (e.g., failed venv activation or partial install).

Suggested hardening patch
 #!/bin/bash
+set -euo pipefail
+
 python -m venv venv
 source venv/bin/activate
-pip install -r backend/requirements.txt pytest pytest-asyncio pytest-mock
+python -m pip install --upgrade pip
+python -m pip install -r backend/requirements.txt pytest pytest-asyncio pytest-mock
 TELEGRAM_BOT_TOKEN=test PYTHONPATH=. pytest backend/tests/
🧰 Tools
🪛 Shellcheck (0.11.0)

[info] 3-3: Not following: venv/bin/activate was not specified as input (see shellcheck -x).

(SC1091)

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

In `@run_tests.sh` around lines 1 - 5, Add shell strictness and explicit failure
checks to the test runner: enable "set -euo pipefail" (and optionally
IFS=$'\n\t') at the top of run_tests.sh so any command (python -m venv, source
venv/bin/activate, pip install) failing will abort; after "source
venv/bin/activate" verify activation succeeded (e.g., check that $VIRTUAL_ENV is
non-empty) and exit with a clear error if not; ensure pip install and pytest
invocations are not run in a subshell that masks errors so their non-zero exit
codes propagate (keep TELEGRAM_BOT_TOKEN=... pytest invocation as-is but let the
script strict flags cause CI to fail fast on errors).

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="backend/routers/field_officer.py">

<violation number="1" location="backend/routers/field_officer.py:149">
P1: Cache update is placed after `db.refresh()`, so a refresh failure after a successful commit can leave the hash cache stale and break subsequent chain linkage.</violation>
</file>

<file name="backend/routers/issues.py">

<violation number="1" location="backend/routers/issues.py:214">
P2: Do not fail the request if post-commit cache update fails; this can return 500 after a successful DB write.</violation>
</file>

<file name="run_tests.sh">

<violation number="1" location="run_tests.sh:2">
P3: Without `set -e`, failures in `python -m venv` or `pip install` will be silently ignored and pytest will run in a broken environment, producing misleading CI results. Add `set -e` (or `set -euo pipefail`) and consider using `python3`/`python3 -m pip` for consistency with other project scripts (e.g., `deploy-backend.sh`).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

db.refresh(new_visit)

# Update cache for next visit AFTER successful DB commit
visit_last_hash_cache.set(data=visit_hash, key="last_hash")
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 4, 2026

Choose a reason for hiding this comment

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

P1: Cache update is placed after db.refresh(), so a refresh failure after a successful commit can leave the hash cache stale and break subsequent chain linkage.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/routers/field_officer.py, line 149:

<comment>Cache update is placed after `db.refresh()`, so a refresh failure after a successful commit can leave the hash cache stale and break subsequent chain linkage.</comment>

<file context>
@@ -148,6 +145,9 @@ def officer_check_in(request: OfficerCheckInRequest, db: Session = Depends(get_d
         db.refresh(new_visit)
         
+        # Update cache for next visit AFTER successful DB commit
+        visit_last_hash_cache.set(data=visit_hash, key="last_hash")
+
         logger.info(
</file context>
Fix with Cubic

Comment thread backend/routers/issues.py
await run_in_threadpool(save_issue_db, db, new_issue)

# Update cache for next report AFTER successful DB commit
blockchain_last_hash_cache.set(data=integrity_hash, key="last_hash")
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 4, 2026

Choose a reason for hiding this comment

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

P2: Do not fail the request if post-commit cache update fails; this can return 500 after a successful DB write.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/routers/issues.py, line 214:

<comment>Do not fail the request if post-commit cache update fails; this can return 500 after a successful DB write.</comment>

<file context>
@@ -212,6 +209,9 @@ async def create_issue(
             await run_in_threadpool(save_issue_db, db, new_issue)
+
+            # Update cache for next report AFTER successful DB commit
+            blockchain_last_hash_cache.set(data=integrity_hash, key="last_hash")
         else:
             # Don't create new issue, just return deduplication info
</file context>
Suggested change
blockchain_last_hash_cache.set(data=integrity_hash, key="last_hash")
try:
blockchain_last_hash_cache.set(data=integrity_hash, key="last_hash")
except Exception as cache_error:
logger.error(f"Error updating blockchain hash cache: {cache_error}", exc_info=True)
Fix with Cubic

Comment thread run_tests.sh
@@ -0,0 +1,5 @@
#!/bin/bash
python -m venv venv
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 4, 2026

Choose a reason for hiding this comment

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

P3: Without set -e, failures in python -m venv or pip install will be silently ignored and pytest will run in a broken environment, producing misleading CI results. Add set -e (or set -euo pipefail) and consider using python3/python3 -m pip for consistency with other project scripts (e.g., deploy-backend.sh).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At run_tests.sh, line 2:

<comment>Without `set -e`, failures in `python -m venv` or `pip install` will be silently ignored and pytest will run in a broken environment, producing misleading CI results. Add `set -e` (or `set -euo pipefail`) and consider using `python3`/`python3 -m pip` for consistency with other project scripts (e.g., `deploy-backend.sh`).</comment>

<file context>
@@ -0,0 +1,5 @@
+#!/bin/bash
+python -m venv venv
+source venv/bin/activate
+pip install -r backend/requirements.txt pytest pytest-asyncio pytest-mock
</file context>
Fix with Cubic

Adds `npm install` to the `netlify.toml` build command to ensure
dependencies are properly installed when building the frontend
from a subdirectory, resolving the Netlify CI check failures.
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@netlify.toml`:
- Line 2: Root netlify config is being ignored because base = "frontend" directs
Netlify to use the nested config; open the nested netlify.toml (the one
referenced by base) and remove the duplicate command entries, consolidating them
to a single command = "npm ci && npm run build", then remove the overridden
command and publish keys from the root netlify.toml so there is no
redundant/ignored configuration; ensure only one build command exists in the
frontend netlify.toml to avoid undefined behavior and keep base = "frontend"
unchanged.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6949f97a-2921-478b-8a08-40962dea71a9

📥 Commits

Reviewing files that changed from the base of the PR and between e8e043e and 678d3c8.

📒 Files selected for processing (1)
  • netlify.toml

Comment thread netlify.toml
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="netlify.toml">

<violation number="1" location="netlify.toml:2">
P1: This `command` change is ineffective. Because `base = "frontend"` is set on line 4, Netlify resolves configuration from `frontend/netlify.toml` (which exists in this repo), completely overriding the root file's `command` and `publish` values. To actually change the build command, update `frontend/netlify.toml` instead.</violation>

<violation number="2" location="netlify.toml:2">
P2: Use `npm ci` instead of `npm install` in the Netlify build command to keep deploy builds reproducible and aligned with lockfile-based installs.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread netlify.toml
Comment thread netlify.toml
Deleted `frontend/netlify.toml` and migrated its `[build.environment]`
variables (`NODE_VERSION="20"`, `CI="false"`) into the root `netlify.toml`.
Having multiple configurations was confusing the Netlify build system and
causing deployment failures ("Pages changed", "Header rules", "Redirect rules").
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 4, 2026

🔍 Quality Reminder

Thanks for the updates! Please ensure:
- Your changes don't break existing functionality
- All tests still pass
- Code quality standards are maintained

*The maintainers will verify that the overall project flow remains intact.*

Because `base = "frontend"` implies `netlify` resolves the `publish` directory
and runs commands strictly within the `frontend/` directory, prepending
`frontend/` or `cd frontend` creates invalid pathing (e.g.,
`frontend/frontend/dist`). Reverting the commands to relative
paths ensures the CI check runner can correctly find the generated
artifacts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants