Skip to content

Refactor: Protect GUI from fatal PHP errors#2421

Merged
limetech merged 11 commits into
unraid:masterfrom
Squidly271:POC/safeeval
Oct 15, 2025
Merged

Refactor: Protect GUI from fatal PHP errors#2421
limetech merged 11 commits into
unraid:masterfrom
Squidly271:POC/safeeval

Conversation

@Squidly271

@Squidly271 Squidly271 commented Oct 4, 2025

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Per-page flag to control whether dynamic page content is executed (applied to Add Container).
  • Bug Fixes

    • Fewer blank pages or broken tabs when dynamic content fails.
    • Improved reliability and clearer error reporting for pages with failing dynamic content.
  • Refactor

    • Centralized, safer handling for dynamic content with guarded execution, error containment, and clearer failure signaling.

@coderabbitai

coderabbitai Bot commented Oct 4, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Layouts and PageBuilder now prepare generated eval payloads ($evalContent/$evalFile) and either eval them directly when an Eval flag is truthy or delegate execution to a new buffered, guarded helper (evalContent.php) that runs and safeguards evals; AddContainer.page now sets Eval="true".

Changes

Cohort / File(s) Summary of Changes
Add Container Page
emhttp/plugins/dynamix.docker.manager/AddContainer.page
Added Eval="true" attribute to the page header so its generated content will be evaluated directly.
Default Page Layouts — Conditional Eval
emhttp/plugins/dynamix/include/DefaultPageLayout.php, emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabbed.php, emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabless.php
Replaced unconditional eval('?>'.generateContent(...)) with prepared $evalContent and $evalFile and a gated execution: when a page/button Eval flag is truthy eval($evalContent) is used; otherwise the code includes evalContent.php which runs a buffered, guarded evaluation. Adjusted loops/placement to compute eval payloads before choosing execution path.
Eval Helper
emhttp/plugins/dynamix/include/evalContent.php
Added new helper that validates $evalContent, starts output buffering, installs a custom error handler that converts fatal errors to exceptions, executes eval, restores handlers/buffers, logs errors including $evalFile context, emits a console error on failure, and exposes success/failure to the caller.
Page Enablement Logic
emhttp/plugins/dynamix/include/PageBuilder.php
page_enabled now builds $evalContent/$evalFile/$evalNoBanner, includes evalContent.php to evaluate Cond in the guarded buffered context, and returns the conjunction of $enabled and the guarded $evalSuccess.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant UI as Browser
  participant Layout as DefaultPageLayout (PHP)
  participant EvalH as evalContent.php
  participant Log as Logger

  UI->>Layout: Request page/button render
  Note right of Layout: prepare $evalContent and $evalFile
  alt Eval flag is true
    Layout->>Layout: eval($evalContent)
  else Eval flag is false
    Layout->>EvalH: include evalContent.php (buffered, guarded eval)
    rect rgb(240,248,255)
      Note right of EvalH: start output buffer\ninstall error handler\nexecute eval
    end
    alt eval succeeds
      EvalH-->>Layout: output flushed, $evalSuccess = true
    else eval fails
      EvalH->>Log: log error with $evalFile context
      EvalH-->>Layout: $evalSuccess = false (console.error emitted)
    end
  end
  Layout-->>UI: Rendered content (based on eval outcome)
Loading
sequenceDiagram
  autonumber
  participant PB as PageBuilder::page_enabled
  participant EvalH as evalContent.php
  participant Log as Logger

  PB->>PB: build $evalContent (Cond), set $evalFile, $evalNoBanner=true
  PB->>EvalH: include evalContent.php (guarded eval)
  alt eval succeeds
    EvalH-->>PB: $evalSuccess = true (enabled remains)
  else eval fails
    EvalH->>Log: log failure with $evalFile
    EvalH-->>PB: $evalSuccess = false
  end
  PB-->>PB: return ($enabled && $evalSuccess)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I nudged the flag, Eval set to true,
A buffered hush let the code peek through.
If faults arise, the logs will say,
Soft paws mend bugs along the way.
Hippity-hop — pages anew. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly describes the primary refactor to protect the GUI from fatal PHP errors by introducing guarded evaluation logic and error handling. It clearly reflects the core purpose of the changes without extraneous details. Teammates scanning the history will understand the main intent at a glance.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between de8974f and f053ef5.

📒 Files selected for processing (1)
  • emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php

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

@github-actions

github-actions Bot commented Oct 4, 2025

Copy link
Copy Markdown

🔧 PR Test Plugin Available

A test plugin has been generated for this PR that includes the modified files.

Version: 2025.10.09.2148
Build: View Workflow Run

📥 Installation Instructions:

Install via Unraid Web UI:

  1. Go to Plugins → Install Plugin
  2. Copy and paste this URL:
https://preview.dl.unraid.net/pr-plugins/pr-2421/webgui-pr-2421.plg
  1. Click Install

Alternative: Direct Download

⚠️ Important Notes:

  • Testing only: This plugin is for testing PR changes
  • Backup included: Original files are automatically backed up
  • Easy removal: Files are restored when plugin is removed
  • Conflicts: Remove this plugin before installing production updates

📝 Modified Files:

Click to expand file list
emhttp/plugins/dynamix.docker.manager/AddContainer.page
emhttp/plugins/dynamix/include/DefaultPageLayout.php
emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabbed.php
emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabless.php
emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php
emhttp/plugins/dynamix/include/PageBuilder.php

🔄 To Remove:

Navigate to Plugins → Installed Plugins and remove webgui-pr-2421, or run:

plugin remove webgui-pr-2421

🤖 This comment is automatically generated and will be updated with each new push to this PR.

@Squidly271 Squidly271 marked this pull request as draft October 4, 2025 05:20

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabbed.php (1)

46-76: Correct evalContent include path across this file.

Both includes on Line 51 and Line 75 target $docroot/webGui/.../evalContent.php, but the helper actually ships under plugins/dynamix/include/.... The include therefore fails and any tab content without Eval="true" never runs, breaking the tabs. Update both spots (and any others) to reference the real location.

-                        include "$docroot/webGui/include/DefaultPageLayout/evalContent.php";
+                        include "$docroot/plugins/dynamix/include/DefaultPageLayout/evalContent.php";
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95bc896 and 7109522.

📒 Files selected for processing (5)
  • emhttp/plugins/dynamix.docker.manager/AddContainer.page (1 hunks)
  • emhttp/plugins/dynamix/include/DefaultPageLayout.php (2 hunks)
  • emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabbed.php (2 hunks)
  • emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabless.php (1 hunks)
  • emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-05-30T00:50:13.286Z
Learnt from: zackspear
PR: unraid/webgui#2212
File: emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabbed.php:37-47
Timestamp: 2025-05-30T00:50:13.286Z
Learning: The .page template system in unraid/webgui is legacy implementation. There is no current appetite to change the eval() usage in .page template files like MainContentTabbed.php, even when security concerns are raised.

Applied to files:

  • emhttp/plugins/dynamix/include/DefaultPageLayout.php
🧬 Code graph analysis (3)
emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabbed.php (1)
emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php (1)
  • generateContent (124-138)
emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabless.php (1)
emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php (1)
  • generateContent (124-138)
emhttp/plugins/dynamix/include/DefaultPageLayout.php (2)
emhttp/plugins/dynamix/include/PageBuilder.php (2)
  • annotate (140-142)
  • includePageStylesheets (131-138)
emhttp/plugins/dynamix/include/Translations.php (1)
  • parse_text (63-66)

Comment thread emhttp/plugins/dynamix/include/DefaultPageLayout.php

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9608ba6 and 61e3b26.

📒 Files selected for processing (1)
  • emhttp/plugins/dynamix/include/PageBuilder.php (1 hunks)
🔇 Additional comments (1)
emhttp/plugins/dynamix/include/PageBuilder.php (1)

47-47: LGTM: Necessary global declaration.

Adding $docroot to the global declarations is required for the include path on line 54.

Comment thread emhttp/plugins/dynamix/include/PageBuilder.php

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 61e3b26 and 906e86e.

📒 Files selected for processing (1)
  • emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php (1 hunks)

Comment thread emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php Outdated
@ljm42 ljm42 added the 7.3 label Oct 4, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php (2)

8-31: Consider using a finally block for reliable buffer cleanup.

While the current code cleans the output buffer in both success and error paths, using a finally block would guarantee cleanup even if unexpected errors occur outside the explicit catch scenarios.

Consider this refactor:

 $evalSuccess = false;
 ob_start();
 try {
     set_error_handler(function($severity, $message, $file, $line) use ($evalFile) {
         // Convert catchable errors to exceptions
         if ($severity & (E_USER_ERROR | E_RECOVERABLE_ERROR)) {
             throw new ErrorException($message, 0, $severity, $file, $line);
         } else {
             error_log("PHP Warning/notice in $evalFile");
         }
         // Let other error types be handled normally
         return false;
     });
     eval($evalContent);
-    restore_error_handler();
     $evalSuccess = true;
-    ob_end_flush();
 } catch (Throwable $e) {
-    restore_error_handler();
     error_log("Error evaluating content in $evalFile: ".$e->getMessage()."\nStack trace:\n".$e->getTraceAsString());
     ob_clean();
     echo "<script>console.error('".htmlspecialchars("Error evaluating content in $evalFile: ".$e->getMessage())."');</script>";
-    ob_end_flush();   
+} finally {
+    restore_error_handler();
+    if (ob_get_level() > 0) {
+        ob_end_flush();
+    }
 }

1-7: Add validation for required variables.

The file expects $evalContent and $evalFile to be provided by the caller but doesn't validate their presence. Adding validation would make debugging easier if these variables are missing.

Add validation at the beginning:

 <?php
 // This evaluates the contents of PHP code.  Has to be "included" because the code is evaluated in the context of the calling page.
 // $evalContent is the PHP code to evaluate.
 // $evalFile is the file that the code is being evaluated in
 // If an error occurs, a banner warning (disappearing in 10 seconds) is added to the page.
 // The PHP error logged will also include the path of the .page file for easier debugging
 
+if (!isset($evalContent) || !isset($evalFile)) {
+    error_log("evalContent.php: Missing required variables (\$evalContent or \$evalFile)");
+    return;
+}
+
 $evalSuccess = false;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d3edef and 392a014.

📒 Files selected for processing (1)
  • emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php (1 hunks)

Comment thread emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php Outdated
Comment thread emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php Outdated
@ljm42 ljm42 added 7.2 and removed 7.3 labels Oct 8, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php (2)

17-26: Error handler checks uncatchable error types.

The severity check on line 19 includes E_ERROR, E_CORE_ERROR, and E_COMPILE_ERROR, which cannot be caught by custom error handlers in PHP—they terminate script execution before the handler runs. Only E_RECOVERABLE_ERROR and E_USER_ERROR from that list are actually catchable.

Apply this diff to check only catchable error types:

 set_error_handler(function($severity, $message, $file, $line) use ($evalFile) {
-    // Only convert errors (not warnings, notices, etc.) to exceptions
-    if ($severity & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR)) {
+    // Convert catchable errors to exceptions
+    if ($severity & (E_USER_ERROR | E_RECOVERABLE_ERROR)) {
         throw new ErrorException($message, 0, $severity, $file, $line);
     } else {
         error_log("PHP Warning/notice in $evalFile");
     }
-    // Let warnings and notices be handled normally
+    // Let other error types be handled normally
     return false;
 });

33-33: Fix the typo in the error log message.

There's an extra closing parenthesis before the colon in the error log message.

Apply this diff:

-    error_log("Error evaluating content in $evalFile): ".$e->getMessage()."\nStack trace:\n".$e->getTraceAsString());
+    error_log("Error evaluating content in $evalFile: ".$e->getMessage()."\nStack trace:\n".$e->getTraceAsString());
🧹 Nitpick comments (1)
emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php (1)

22-22: Log the actual warning/notice message for debugging.

The error log currently only indicates a warning/notice occurred in the file but doesn't include the actual message, file location, or line number, making debugging difficult.

Apply this diff to include the full error details:

-      error_log("PHP Warning/notice in $evalFile");
+      error_log("PHP Warning/notice in $evalFile: $message at $file:$line");
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 392a014 and 8fa55ad.

📒 Files selected for processing (1)
  • emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php (1 hunks)
🔇 Additional comments (1)
emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php (1)

8-13: LGTM!

The initialization and validation logic is correct. Setting $evalSuccess to false by default and providing a fallback for $evalFile ensures proper tracking and error reporting.

Comment thread emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php Outdated
Comment thread emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php Outdated
@Squidly271

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 9, 2025

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (4)
emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php (3)

5-6: Update the comment to match actual behavior.

The comment states "a banner warning (disappearing in 10 seconds) is added to the page," but the current implementation (line 43) only outputs a console.error() message—no banner UI is generated.

Apply this diff to correct the comment:

-// If an error occurs, a banner warning (disappearing in 10 seconds) is added to the page.
+// If an error occurs, an error message is logged to the browser console.
 // The PHP error logged will also include the path of the .page file for easier debugging

17-33: Error handler checks uncatchable error types.

Line 23 includes E_ERROR, E_CORE_ERROR, and E_COMPILE_ERROR in the fatal errors bitmask, but these error types cannot be caught by custom error handlers in PHP—they terminate script execution before the handler runs. Only E_RECOVERABLE_ERROR and E_USER_ERROR from this list are actually catchable.

Apply this diff to check only catchable error types:

-    $fatalErrors = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR;
+    // Only catchable error types: E_RECOVERABLE_ERROR and E_USER_ERROR
+    $fatalErrors = E_USER_ERROR | E_RECOVERABLE_ERROR;

43-43: Use json_encode for safer JavaScript output.

Using htmlspecialchars() for JavaScript string escaping is insufficient. If $evalFile or the error message contains single quotes, backslashes, or line breaks, it will break the JavaScript string literal and potentially introduce XSS vulnerabilities.

Apply this diff to use json_encode() for proper escaping:

-  echo "<script>console.error('".htmlspecialchars("Error evaluating content in $evalFile: ".$e->getMessage())."');</script>";
+  $errorMessage = "Error evaluating content in $evalFile: ".$e->getMessage();
+  echo "<script>console.error(".json_encode($errorMessage).");</script>";
emhttp/plugins/dynamix/include/DefaultPageLayout.php (1)

136-146: Fix evalContent include path; avoid direct eval bypassing safety

  • The include points to webGui/include/... which likely doesn’t exist; evalContent.php lives under plugins/dynamix/include/... per this PR. This will fatally fail and break button actions.
  • Using eval($evalContent) when Eval=true bypasses the new guard and can still take down the page on fatals. Prefer routing Eval=true through the guarded helper (or unify on the helper).

Apply the path fix:

-        include "$docroot/webGui/include/DefaultPageLayout/evalContent.php";
+        include "$docroot/plugins/dynamix/include/DefaultPageLayout/evalContent.php";

Option A (recommended): flip logic so Eval=true uses the guard:

-        if ( filter_var($button['Eval']??false, FILTER_VALIDATE_BOOLEAN) ) {
-            eval($evalContent);
-        } else {
-            include "$docroot/plugins/dynamix/include/DefaultPageLayout/evalContent.php";
-        }
+        if ( filter_var($button['Eval']??false, FILTER_VALIDATE_BOOLEAN) ) {
+            include "$docroot/plugins/dynamix/include/DefaultPageLayout/evalContent.php";
+        } else {
+            eval($evalContent);
+        }

Option B (safest): always go through the helper and drop the direct eval:

-        if ( filter_var($button['Eval']??false, FILTER_VALIDATE_BOOLEAN) ) {
-            eval($evalContent);
-        } else {
-            include "$docroot/plugins/dynamix/include/DefaultPageLayout/evalContent.php";
-        }
+        include "$docroot/plugins/dynamix/include/DefaultPageLayout/evalContent.php";

Run these checks to catch other occurrences and ensure consistency:

#!/bin/bash
# Wrong include path occurrences
rg -nP "include\s+[\"']\$docroot/webGui/include/DefaultPageLayout/evalContent\.php[\"']" -C2

# Correct include path occurrences
rg -nP "include\s+[\"']\$docroot/plugins/dynamix/include/DefaultPageLayout/evalContent\.php[\"']" -C2

# Direct evals of $evalContent
rg -nP --type=php -C2 '\beval\s*\(\s*\$evalContent\s*\)'
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95bc896 and 31e4100.

📒 Files selected for processing (6)
  • emhttp/plugins/dynamix.docker.manager/AddContainer.page (1 hunks)
  • emhttp/plugins/dynamix/include/DefaultPageLayout.php (3 hunks)
  • emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabbed.php (2 hunks)
  • emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabless.php (1 hunks)
  • emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php (1 hunks)
  • emhttp/plugins/dynamix/include/PageBuilder.php (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-04T05:22:33.141Z
Learnt from: Squidly271
PR: unraid/webgui#2421
File: emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabless.php:23-0
Timestamp: 2025-10-04T05:22:33.141Z
Learning: In the Unraid webgui repository, `emhttp/webGui` is a symlink that points to `plugins/dynamix`. Therefore, paths using `$docroot/webGui/...` correctly resolve to `$docroot/plugins/dynamix/...` at runtime.

Applied to files:

  • emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabless.php
📚 Learning: 2025-05-30T00:50:13.286Z
Learnt from: zackspear
PR: unraid/webgui#2212
File: emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabbed.php:37-47
Timestamp: 2025-05-30T00:50:13.286Z
Learning: The .page template system in unraid/webgui is legacy implementation. There is no current appetite to change the eval() usage in .page template files like MainContentTabbed.php, even when security concerns are raised.

Applied to files:

  • emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabbed.php
🔇 Additional comments (6)
emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabless.php (1)

22-30: LGTM! Guarded evaluation implemented correctly.

The conditional evaluation logic properly handles both paths:

  • When Eval is true: direct evaluation for pages that opt out of safety
  • When Eval is false/absent: delegates to evalContent.php for error-protected evaluation

The implementation correctly uses filter_var() for boolean validation and maintains the necessary context variables. Based on learnings, the webGui symlink path resolves correctly at runtime.

emhttp/plugins/dynamix/include/PageBuilder.php (1)

45-55: LGTM! Safe condition evaluation integrated correctly.

The refactoring properly delegates condition evaluation to evalContent.php:

  • $docroot is correctly added to the global scope for the include path
  • $evalContent constructs the condition check as an assignment statement
  • $evalSuccess is properly initialized and updated by the included file (shares function scope)
  • Return logic requires both $enabled (condition result) and $evalSuccess (execution safety)

This ensures page conditions are evaluated with error protection, preventing fatal errors from disabling the entire interface.

emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabbed.php (1)

46-52: LGTM! Guarded evaluation implemented correctly in both locations.

The conditional evaluation logic is properly implemented in two places:

  1. Lines 46-52: For pages without titles that have content (e.g., parent pages like Share.page)
  2. Lines 69-77: For tab panel content rendering

Both implementations correctly:

  • Construct $evalContent and $evalFile for context
  • Use filter_var() with FILTER_VALIDATE_BOOLEAN for proper flag parsing
  • Route to direct eval() when Eval=true, or delegate to evalContent.php for error-protected evaluation when Eval=false/absent

Based on learnings, this change respects the legacy .page template system while adding a safety layer for error-prone content.

Also applies to: 69-77

emhttp/plugins/dynamix/include/DefaultPageLayout.php (3)

149-152: Confirm evaluation flow for $pages (styles only here)

This loop now only annotates and includes stylesheets; no eval. Please confirm the guarded evaluation for $pages content is now handled in HeadInlineJS/MainContent to avoid regressions.


81-81: No functional change

Whitespace-only change; no action needed.


169-169: LGTM

Closing tag adjustment is fine.

Comment thread emhttp/plugins/dynamix.docker.manager/AddContainer.page
Simple protection -> assigns default in case of an error

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
emhttp/plugins/dynamix/include/PageBuilder.php (1)

21-25: Good safety improvement with error handling.

The try-catch block appropriately protects against fatal errors from eval(). Catching Throwable ensures both Error and Exception types are handled, and returning the default value is a reasonable fallback for a getter function.

Optional: Consider adding error logging for debugging.

While silently returning the default is reasonable, logging the error (e.g., via my_logger()) could aid in debugging malformed key expressions during development.

Apply this diff to add optional error logging:

 try {
   eval("\$var=$key;");
 } catch (Throwable $e) {
+  my_logger("Failed to evaluate key '$key': {$e->getMessage()}");
   return $default;
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 31e4100 and de8974f.

📒 Files selected for processing (1)
  • emhttp/plugins/dynamix/include/PageBuilder.php (2 hunks)
🔇 Additional comments (1)
emhttp/plugins/dynamix/include/PageBuilder.php (1)

51-58: No breaking changes detected for page_enabled.

The only caller (if (page_enabled($page))) correctly handles the boolean return value.

@Squidly271 Squidly271 marked this pull request as ready for review October 14, 2025 16:18
@limetech limetech merged commit e31fda9 into unraid:master Oct 15, 2025
2 checks passed
@Squidly271 Squidly271 deleted the POC/safeeval branch November 5, 2025 01:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants