Skip to content

Staging#372

Closed
gkorland wants to merge 41 commits intomainfrom
staging
Closed

Staging#372
gkorland wants to merge 41 commits intomainfrom
staging

Conversation

@gkorland
Copy link
Copy Markdown
Contributor

@gkorland gkorland commented Jan 8, 2026

Summary by CodeRabbit

  • Chores
    • Added Dependabot entry for weekly GitHub Actions updates.
    • Minor build/runtime improvements in container setup.
  • New Features
    • Responses include HSTS header to enforce HTTPS (max-age=31536000; includeSubDomains; preload).
    • Schema viewer now uses a canvas-based renderer for improved rendering and interactions.
    • Optional Memory TTL support for per-user memory graphs.
  • Docs
    • README and example env updated with Memory TTL guidance.
  • Tests
    • Added tests validating the HSTS header on site and API endpoints.

Anchel123 and others added 13 commits December 30, 2025 13:53
…react-force-graph-2d

- Added @falkordb/canvas dependency to package.json and package-lock.json.
- Refactored SchemaViewer component to utilize FalkorDBCanvas for rendering schema data.
- Updated schema data handling to remap node IDs and create a nodesMap for efficient access.
- Removed all references and dependencies related to react-force-graph-2d.
- Implemented dynamic loading of canvas and adjusted theme colors for better visualization.
- Enhanced zoom and center functionalities to work with the new canvas implementation.
Bumps the pip group with 1 update in the / directory: [urllib3](https://github.com/urllib3/urllib3).


Updates `urllib3` from 2.6.2 to 2.6.3
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](urllib3/urllib3@2.6.2...2.6.3)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.6.3
  dependency-type: indirect
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
@overcut-ai
Copy link
Copy Markdown

overcut-ai bot commented Jan 8, 2026

Completed Working on "Code Review"

✅ Workflow completed successfully.


👉 View complete log

@railway-app
Copy link
Copy Markdown

railway-app bot commented Jan 8, 2026

🚅 Deployed to the QueryWeaver-pr-372 environment in queryweaver

Service Status Web Updated (UTC)
QueryWeaver ✅ Success (View Logs) Web Feb 3, 2026 at 12:55 pm

@railway-app railway-app bot temporarily deployed to queryweaver / QueryWeaver-pr-372 January 8, 2026 18:23 Destroyed
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jan 8, 2026

Note

Reviews paused

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

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds Dependabot Actions config, sets HSTS header in SecurityMiddleware with tests, introduces Redis-backed MEMORY_TTL for memory graphs, refactors SchemaViewer to use @falkordb/canvas (type changes + UI logic), updates frontend deps, tweaks Dockerfile, bumps jsonschema, and updates docs/examples.

Changes

Cohort / File(s) Summary
Dependabot configuration
.github/dependabot.yml
Added a GitHub Actions update entry scheduled weekly.
Security middleware / app factory
api/app_factory.py
SecurityMiddleware.dispatch now sets Strict-Transport-Security: max-age=31536000; includeSubDomains; preload on all responses.
HSTS tests
tests/test_hsts_header.py
New tests asserting HSTS header presence and directives for / and /graphs.
Frontend package manifest
app/package.json
Added @falkordb/canvas and preact; removed react-force-graph-2d.
SchemaViewer component (frontend)
app/src/components/schema/SchemaViewer.tsx
Large refactor: replaced ForceGraph2D with dynamic @falkordb/canvas usage, changed Schema types (node id → number, added userId, removed x/y/height), remapped legacy IDs to numeric IDs, added nodesMap, removed D3 force logic, and rewired rendering/interaction via canvas API.
Memory TTL & Redis integration
api/memory/graphiti_tool.py
Added optional MEMORY_TTL_SECONDS attribute and async _refresh_ttl to set Redis EXPIRE for per-user memory graphs; TTL refresh invoked after index creation; RedisError handled.
Environment & docs
.env.example, README.md
Added Memory TTL example and documentation describing MEMORY_TTL_SECONDS behavior and example value (604800).
Wordlist
.github/wordlist.txt
Added TTL entry.
Pipfile
Pipfile
Bumped jsonschema from ~=4.25.0 to ~=4.26.0.
Dockerfile
Dockerfile
Adjusted Node.js install flow, added curl, ca-certificates, gnupg to apt install, ensured clean Node.js setup and prints node/npm versions.

Sequence Diagram(s)

sequenceDiagram
  participant App as MemoryTool
  participant Falkor as FalkorDriver
  participant Redis as Redis
  App->>Falkor: create_vector_index(memory_db_name)
  Falkor-->>App: index_created
  alt MEMORY_TTL_SECONDS set
    App->>Redis: EXPIRE(memory_key, MEMORY_TTL_SECONDS)
    Redis-->>App: OK / Error
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰
I hop through headers, brisk and bright,
TTL set to keep things tight.
Canvas paints nodes, tidy and new,
Tests cheer, docs whisper “review.”
A rabbit nods—this patch feels right!

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Staging' is vague and does not convey any meaningful information about the actual changes in this pull request. Replace with a descriptive title that summarizes the main changes, such as 'Migrate to FalkorDB Canvas, add HSTS header, and implement memory TTL support'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch staging

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.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Jan 8, 2026

Dependency Review

The following issues were found:

  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ✅ 0 package(s) with unknown licenses.
  • ⚠️ 10 packages with OpenSSF Scorecard issues.

View full job summary

Bump urllib3 from 2.6.2 to 2.6.3 in the pip group across 1 directory
@railway-app railway-app bot temporarily deployed to queryweaver / QueryWeaver-pr-372 January 8, 2026 18:24 Destroyed
@railway-app railway-app bot temporarily deployed to queryweaver / staging January 8, 2026 18:24 Inactive
Copy link
Copy Markdown

@overcut-ai overcut-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.

Findings by severity

  • BLOCKER: 0
  • CRITICAL: 0
  • MAJOR: 1
  • MINOR: 0
  • SUGGESTION: 0
  • PRAISE: 0

Affected file: .github/dependabot.yml

Key theme

  1. Dependabot workflow alignment – the new github-actions entry currently raises PRs against main, breaking the intended staging-first gate used by other ecosystems.

Next steps

  • Specify target-branch: "staging" under the github-actions update entry so automation consistently targets the staging branch before hitting main.

No blocking or critical issues were identified, so this PR can proceed once the above adjustment is made.

Comment thread .github/dependabot.yml
@railway-app railway-app bot temporarily deployed to queryweaver / QueryWeaver-pr-372 January 24, 2026 19:05 Destroyed
@railway-app railway-app bot temporarily deployed to queryweaver / staging January 24, 2026 19:05 Inactive
Copy link
Copy Markdown
Contributor

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

Caution

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

⚠️ Outside diff range comments (1)
api/app_factory.py (1)

36-53: Apply HSTS to early-return responses too.

The 403 responses returned before call_next never receive the HSTS header, so it’s not truly applied to all responses.

🐛 Proposed fix
     async def dispatch(self, request: Request, call_next):
+        hsts_value = "max-age=31536000; includeSubDomains; preload"
+
+        def _apply_hsts(resp):
+            resp.headers["Strict-Transport-Security"] = hsts_value
+            return resp
+
         # Block directory access in static files
         if request.url.path.startswith(self.STATIC_PREFIX):
             # Remove /static/ prefix to get the actual path
             filename = request.url.path[len(self.STATIC_PREFIX) :]
             # Basic security check for directory traversal
             if not filename or "../" in filename or filename.endswith("/"):
-                return JSONResponse(status_code=403, content={"detail": "Forbidden"})
+                return _apply_hsts(
+                    JSONResponse(status_code=403, content={"detail": "Forbidden"})
+                )
 
         response = await call_next(request)
-
-        # Add HSTS header to prevent man-in-the-middle attacks
-        # max-age=31536000: 1 year in seconds
-        # includeSubDomains: apply to all subdomains
-        # preload: eligible for browser HSTS preload lists
-        hsts_value = "max-age=31536000; includeSubDomains; preload"
-        response.headers["Strict-Transport-Security"] = hsts_value
-
-        return response
+        return _apply_hsts(response)
🧹 Nitpick comments (2)
tests/test_hsts_header.py (1)

12-15: Close TestClient to avoid resource leaks.

Using a context manager in the fixture ensures the client is properly closed after each test.

♻️ Proposed update
     `@pytest.fixture`
     def client(self):
         """Create a test client."""
-        return TestClient(app)
+        with TestClient(app) as client:
+            yield client
api/app_factory.py (1)

47-52: Consider setting HSTS only on HTTPS responses.

Best practice is to emit HSTS only when the request is HTTPS (or forwarded as HTTPS).

♻️ Possible tweak
-        response.headers["Strict-Transport-Security"] = hsts_value
+        if request.url.scheme == "https":
+            response.headers["Strict-Transport-Security"] = hsts_value

dependabot bot and others added 6 commits January 26, 2026 14:04
Bumps [jsonschema](https://github.com/python-jsonschema/jsonschema) from 4.25.1 to 4.26.0.
- [Release notes](https://github.com/python-jsonschema/jsonschema/releases)
- [Changelog](https://github.com/python-jsonschema/jsonschema/blob/main/CHANGELOG.rst)
- [Commits](python-jsonschema/jsonschema@v4.25.1...v4.26.0)

---
updated-dependencies:
- dependency-name: jsonschema
  dependency-version: 4.26.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
feat: integrate @falkordb/canvas for schema visualization and remove …
@railway-app railway-app bot temporarily deployed to queryweaver / QueryWeaver-pr-372 February 3, 2026 09:29 Destroyed
@railway-app railway-app bot temporarily deployed to queryweaver / staging February 3, 2026 09:29 Inactive
Copy link
Copy Markdown
Contributor

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

🤖 Fix all issues with AI agents
In `@app/package.json`:
- Line 14: Remove the unnecessary direct dependency on "preact" from
package.json since it's only pulled in transitively by float-tooltip; delete the
"preact" entry and run an install to ensure no breakage. Also verify the
"@falkordb/canvas" dependency version: confirm that using
"@falkordb/canvas@0.0.29" is intentional (or bump to a stable release) by
checking changelogs/maintainer notes and run the app/tests to validate stability
before finalizing the change.

In `@app/src/components/schema/SchemaViewer.tsx`:
- Around line 189-197: The handleCenter callback contains a stray debug
console.log("Stop"); remove that console.log from the handleCenter function (in
the same block that references canvasRef.current and calls canvas.zoomToFit())
so the callback only retrieves the canvas and calls canvas.zoomToFit() when
present.
- Around line 289-293: The code directly accesses node.displayName[1] in the
ctx.fillText call which can throw if displayName is undefined or has fewer than
2 elements; update the rendering logic in SchemaViewer (the block around
ctx.fillText) to safely compute a text value first (e.g., const secondary =
Array.isArray(node.displayName) && node.displayName.length > 1 ?
node.displayName[1] : '') and then pass that safe secondary value to
ctx.fillText so missing or short displayName arrays don't cause runtime errors.
- Around line 150-155: The link-mapping fallback returns string IDs but
SchemaLink expects numbers; update the data.links mapping to coerce the resolved
IDs to numbers (use Number(...) or parseInt(..., 10)) for both source and target
when reading from oldIdToNewId or falling back to link.source/link.target, and
ensure this conversion is applied in the map callback that creates the new link
objects so source and target are always numbers (refer to data.links,
oldIdToNewId, and SchemaLink).
🧹 Nitpick comments (1)
app/src/components/schema/SchemaViewer.tsx (1)

85-90: Add error handling for the dynamic import.

If the dynamic import fails (e.g., network issues, bundle errors), the promise rejection is unhandled and canvasLoaded will remain false with no user feedback.

🛡️ Proposed fix
   // Load falkordb-canvas dynamically
   useEffect(() => {
-    import('@falkordb/canvas').then(() => {
-      setCanvasLoaded(true);
-    });
+    import('@falkordb/canvas')
+      .then(() => {
+        setCanvasLoaded(true);
+      })
+      .catch((error) => {
+        console.error('Failed to load canvas:', error);
+        toast({
+          title: 'Failed to Load Canvas',
+          description: 'Could not load the schema visualization component',
+          variant: 'destructive',
+        });
+      });
   }, []);

Comment thread app/package.json
Comment thread app/src/components/schema/SchemaViewer.tsx
Comment on lines +189 to +197
const handleCenter = useCallback(() => {
console.log("Stop");

const canvas = canvasRef.current;

if (canvas) {
canvas.zoomToFit();
}
}, []);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove debug console.log.

Line 190 contains a debug statement console.log("Stop") that should be removed before merging.

🧹 Proposed fix
   const handleCenter = useCallback(() => {
-    console.log("Stop");
-
     const canvas = canvasRef.current;

     if (canvas) {
       canvas.zoomToFit();
     }
   }, []);
📝 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
const handleCenter = useCallback(() => {
console.log("Stop");
const canvas = canvasRef.current;
if (canvas) {
canvas.zoomToFit();
}
}, []);
const handleCenter = useCallback(() => {
const canvas = canvasRef.current;
if (canvas) {
canvas.zoomToFit();
}
}, []);
🤖 Prompt for AI Agents
In `@app/src/components/schema/SchemaViewer.tsx` around lines 189 - 197, The
handleCenter callback contains a stray debug console.log("Stop"); remove that
console.log from the handleCenter function (in the same block that references
canvasRef.current and calls canvas.zoomToFit()) so the callback only retrieves
the canvas and calls canvas.zoomToFit() when present.

Comment on lines +289 to +293
ctx.fillText(
node.displayName[1],
node.x || 0,
(node.y || 0) - nodeHeight / 2 + headerHeight / 2 + padding / 2
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential runtime error accessing displayName[1].

node.displayName[1] is accessed without validating that displayName exists and has at least two elements. If the canvas library provides nodes with missing or incomplete displayName, this will throw a runtime error.

🛡️ Proposed fix
       ctx.fillText(
-        node.displayName[1],
+        node.displayName?.[1] ?? node.data?.name ?? '',
         node.x || 0,
         (node.y || 0) - nodeHeight / 2 + headerHeight / 2 + padding / 2
       );
📝 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
ctx.fillText(
node.displayName[1],
node.x || 0,
(node.y || 0) - nodeHeight / 2 + headerHeight / 2 + padding / 2
);
ctx.fillText(
node.displayName?.[1] ?? node.data?.name ?? '',
node.x || 0,
(node.y || 0) - nodeHeight / 2 + headerHeight / 2 + padding / 2
);
🤖 Prompt for AI Agents
In `@app/src/components/schema/SchemaViewer.tsx` around lines 289 - 293, The code
directly accesses node.displayName[1] in the ctx.fillText call which can throw
if displayName is undefined or has fewer than 2 elements; update the rendering
logic in SchemaViewer (the block around ctx.fillText) to safely compute a text
value first (e.g., const secondary = Array.isArray(node.displayName) &&
node.displayName.length > 1 ? node.displayName[1] : '') and then pass that safe
secondary value to ctx.fillText so missing or short displayName arrays don't
cause runtime errors.

@railway-app railway-app bot temporarily deployed to queryweaver / QueryWeaver-pr-372 February 3, 2026 12:42 Destroyed
@railway-app railway-app bot temporarily deployed to queryweaver / QueryWeaver-pr-372 February 12, 2026 15:09 Destroyed
@railway-app railway-app bot temporarily deployed to queryweaver / staging February 12, 2026 15:09 Inactive
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@api/memory/graphiti_tool.py`:
- Around line 73-78: The README claim that TTL is refreshed on every user
interaction is incorrect because _refresh_ttl is only called in create(); update
per-interaction methods (at least search_memories, add_new_memory,
save_query_memory and any other public handlers) to call await
self._refresh_ttl() after successful DB operations so the Redis EXPIRE for
self.memory_db_name using self.MEMORY_TTL_SECONDS is renewed, or alternatively
update the README if you prefer not to change runtime behavior.

In `@Dockerfile`:
- Around line 43-50: The RUN chain currently uses "apt-get update && apt-get
remove -y nodejs || true" which allows failures of apt-get update to be
swallowed; change that to ensure only the remove is optional by grouping the
remove with || true (e.g., "apt-get update && (apt-get remove -y nodejs ||
true)") or separate into two RUN steps so apt-get update failure fails the
build; also add --no-install-recommends to the "apt-get install -y nodejs"
invocation to avoid pulling unnecessary packages and keep the rest of the
sequence (curl setup_22.x, second apt-get update, rm -rf /var/lib/apt/lists/*,
and the final node --version && npm --version) intact.
🧹 Nitpick comments (1)
api/memory/graphiti_tool.py (1)

52-58: Class-level env parsing is fail-fast but could produce a confusing error on invalid input.

If MEMORY_TTL_SECONDS is set to a non-numeric string, int() raises a ValueError at import time with no indication which env var is at fault. A minor robustness improvement:

Suggested improvement
-    MEMORY_TTL_SECONDS: Optional[int] = (
-        int(os.environ["MEMORY_TTL_SECONDS"])
-        if os.environ.get("MEMORY_TTL_SECONDS")
-        else None
-    )
+    _raw_ttl = os.environ.get("MEMORY_TTL_SECONDS")
+    MEMORY_TTL_SECONDS: Optional[int] = int(_raw_ttl) if _raw_ttl else None

This is fine as-is for a fail-fast approach; just noting the UX for operators.

Comment on lines +73 to +78
async def _refresh_ttl(self) -> None:
"""Set a TTL on the memory graph key using Redis EXPIRE."""
try:
await db.execute_command("EXPIRE", self.memory_db_name, self.MEMORY_TTL_SECONDS)
except RedisError as e:
logging.warning("Failed to refresh TTL for %s: %s", self.memory_db_name, e)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find all calls to _refresh_ttl
rg -n --type=py '_refresh_ttl' .

Repository: FalkorDB/QueryWeaver

Length of output: 209


🏁 Script executed:

# Find all calls to create() on MemoryTool
rg -n --type=py 'create\(' . | grep -i memory

Repository: FalkorDB/QueryWeaver

Length of output: 406


🏁 Script executed:

# Check the graphiti_tool.py file to see the full implementation
cat -n api/memory/graphiti_tool.py | head -150

Repository: FalkorDB/QueryWeaver

Length of output: 6889


🏁 Script executed:

# Find the README and check what it says about TTL
find . -name "README*" -type f | head -5

Repository: FalkorDB/QueryWeaver

Length of output: 114


🏁 Script executed:

# Look for how MemoryTool is used - search for imports and instantiation
rg -n --type=py 'from.*graphiti_tool|import.*MemoryTool' .

Repository: FalkorDB/QueryWeaver

Length of output: 202


🏁 Script executed:

# Check text2sql.py around the create() calls to understand the pattern
sed -n '235,250p' api/core/text2sql.py

Repository: FalkorDB/QueryWeaver

Length of output: 697


🏁 Script executed:

# Check text2sql.py around line 725
sed -n '720,735p' api/core/text2sql.py

Repository: FalkorDB/QueryWeaver

Length of output: 761


🏁 Script executed:

# List all public methods in MemoryTool
rg -n --type=py '^\s+async def|^\s+def' api/memory/graphiti_tool.py

Repository: FalkorDB/QueryWeaver

Length of output: 1395


🏁 Script executed:

# Check README for the TTL statement
rg -n --type=md 'TTL|refresh' README.md | head -20

Repository: FalkorDB/QueryWeaver

Length of output: 427


🏁 Script executed:

# Get more context from the full MemoryTool implementation
sed -n '140,300p' api/memory/graphiti_tool.py

Repository: FalkorDB/QueryWeaver

Length of output: 7796


TTL is only refreshed during create(), not on every user interaction.

The README (line 69) states "The TTL is refreshed on every user interaction, so active users keep their memory." However, _refresh_ttl is only called inside create(). The per-interaction methods (search_memories, add_new_memory, save_query_memory, etc.) operate on an existing MemoryTool instance and do not refresh the TTL. This means active users with ongoing interactions can still lose their memory graphs if create() isn't invoked on every request.

Call _refresh_ttl in the per-interaction methods (at least the most common entry points like search_memories and add_new_memory), or update the README to reflect the actual behavior.

🤖 Prompt for AI Agents
In `@api/memory/graphiti_tool.py` around lines 73 - 78, The README claim that TTL
is refreshed on every user interaction is incorrect because _refresh_ttl is only
called in create(); update per-interaction methods (at least search_memories,
add_new_memory, save_query_memory and any other public handlers) to call await
self._refresh_ttl() after successful DB operations so the Redis EXPIRE for
self.memory_db_name using self.MEMORY_TTL_SECONDS is renewed, or alternatively
update the README if you prefer not to change runtime behavior.

Comment thread Dockerfile
Comment on lines +43 to +50
RUN apt-get update \
&& apt-get remove -y nodejs || true \
&& rm -rf /var/lib/apt/lists/* \
&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get update \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/* \
&& node --version && npm --version
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Operator precedence bug: || true swallows apt-get update failures too.

In shell, && and || are left-associative with equal precedence, so apt-get update && apt-get remove -y nodejs || true is parsed as (apt-get update && apt-get remove -y nodejs) || true. If apt-get update fails, the error is silently ignored.

Also, apt-get install -y nodejs on line 48 is missing --no-install-recommends, which inflates the image with unnecessary packages.

Proposed fix
-RUN apt-get update \
-    && apt-get remove -y nodejs || true \
-    && rm -rf /var/lib/apt/lists/* \
-    && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
-    && apt-get update \
-    && apt-get install -y nodejs \
-    && rm -rf /var/lib/apt/lists/* \
+RUN apt-get update \
+    && (apt-get remove -y nodejs || true) \
+    && rm -rf /var/lib/apt/lists/* \
+    && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
+    && apt-get update \
+    && apt-get install -y --no-install-recommends nodejs \
+    && rm -rf /var/lib/apt/lists/* \
     && node --version && npm --version
📝 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
RUN apt-get update \
&& apt-get remove -y nodejs || true \
&& rm -rf /var/lib/apt/lists/* \
&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get update \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/* \
&& node --version && npm --version
RUN apt-get update \
&& (apt-get remove -y nodejs || true) \
&& rm -rf /var/lib/apt/lists/* \
&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get update \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/* \
&& node --version && npm --version
🧰 Tools
🪛 Trivy (0.69.1)

[error] 43-50: 'apt-get' missing '--no-install-recommends'

'--no-install-recommends' flag is missed: 'apt-get update && apt-get remove -y nodejs || true && rm -rf /var/lib/apt/lists/* && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && apt-get update && apt-get install -y nodejs && rm -rf /var/lib/apt/lists/* && node --version && npm --version'

Rule: DS-0029

Learn more

(IaC/Dockerfile)

🤖 Prompt for AI Agents
In `@Dockerfile` around lines 43 - 50, The RUN chain currently uses "apt-get
update && apt-get remove -y nodejs || true" which allows failures of apt-get
update to be swallowed; change that to ensure only the remove is optional by
grouping the remove with || true (e.g., "apt-get update && (apt-get remove -y
nodejs || true)") or separate into two RUN steps so apt-get update failure fails
the build; also add --no-install-recommends to the "apt-get install -y nodejs"
invocation to avoid pulling unnecessary packages and keep the rest of the
sequence (curl setup_22.x, second apt-get update, rm -rf /var/lib/apt/lists/*,
and the final node --version && npm --version) intact.

@galshubeli galshubeli closed this Feb 16, 2026
@railway-app railway-app bot temporarily deployed to queryweaver / QueryWeaver-pr-391 February 16, 2026 07:39 Destroyed
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.

5 participants