Skip to content

feat(NVIDIA Driver): show support versions - #8

Merged
Christoph (ich777) merged 9 commits into
unraid:masterfrom
SimonFair:Show-supported-versions
Mar 19, 2026
Merged

feat(NVIDIA Driver): show support versions#8
Christoph (ich777) merged 9 commits into
unraid:masterfrom
SimonFair:Show-supported-versions

Conversation

@SimonFair

@SimonFair SimonFair commented Mar 17, 2026

Copy link
Copy Markdown
Contributor
image

Summary by CodeRabbit

  • New Features

    • Per‑GPU detection with detailed compatibility rows, recommendations, and diagnostics.
    • Aggregated driver metadata with normalized versions, candidate/legacy selection, and display of installed driver.
    • Architecture ↔ chip mapping with optional remote fetch, caching, and local fallback.
    • UI enhancements: loading/errors for GPU support fetch, rendered per‑GPU info, and HTML‑escaped labels.
  • Bug Fixes

    • Driver options now disable/dim incompatible choices to prevent invalid selections.

@coderabbitai

coderabbitai Bot commented Mar 17, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds a static architecture mapping JSON, new PHP libraries to detect GPUs and determine recommended NVIDIA drivers (including remote NVIDIA data fetch, local heuristics and caching), and page/UI changes to present per‑GPU recommendations and enable/disable driver options.

Changes

Cohort / File(s) Summary
Architecture mapping
architecture-mapping.json
New JSON mapping chip prefixes to architectures and classifying architectures by kernel module support (proprietary / both / open).
Driver/device logic
source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php
New PHP utilities to parse/normalize driver versions, derive branch majors, select best versions, normalize PCI device IDs, map devices → required branches, query NVIDIA support pages, compute valid driver lists, and expose public functions for compatibility checks.
GPU detection & recommendation
source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php
New PHP module to load/normalize architecture mapping (remote/cache/local), resolve chip codename → architecture, extract lspci/nvidia-smi metadata, compute candidate and recommended drivers per GPU, and return JSON rows.
UI integration / page
source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page
Replaced multiple direct version calls with nvidia_get_nvidia_versions() and candidate lists; added client JS (escapeHtml, renderGpuSupportRows, applyDriverOptionSupport, loadGpuSupport), require for card-support, and UI wiring to fetch/display GPU support JSON and enable/disable driver options.
Cross-cutting
source/usr/local/emhttp/plugins/nvidia-driver/...
Introduces caching, timeouts, remote fetch fallbacks, normalization logic, and new public PHP functions; no existing exported signatures were removed.

Sequence Diagram(s)

sequenceDiagram
    participant Browser
    participant UIPage as "nvidia-driver.page (Server)"
    participant CardLib as "card-support.php / gpu-support.php"
    participant System as "Local system (lspci, nvidia-smi)"
    participant NVIDIA as "NVIDIA remote pages"

    Browser->>UIPage: Load page & call loadGpuSupport()
    UIPage->>CardLib: Request GPU support JSON
    CardLib->>System: Run lspci / nvidia-smi (cached)
    CardLib->>CardLib: Resolve chip codename -> architecture (local mapping)
    CardLib->>NVIDIA: Fetch versions / supportedchips (remote, timeout & cache)
    NVIDIA-->>CardLib: Return version/support data
    CardLib->>CardLib: Compute candidate & recommended drivers per‑GPU
    CardLib-->>UIPage: Return JSON rows
    UIPage-->>Browser: Respond with JSON
    Browser->>Browser: renderGpuSupportRows(rows) & applyDriverOptionSupport(rows)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I am a rabbit, whiskers quick and bright,
I hop through chips from morning to night,
Mapping GK to GB with a twitch and a cheer,
Fetching versions and drivers far and near,
I nudge each GPU to the driver it should hear 🐇✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.78% 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 pull request title follows the conventional commits format with the 'feat:' prefix as required and accurately describes the main feature being added.
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 unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code
📝 Coding Plan
  • Generate coding plan for human review comments

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

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

Inline comments:
In `@source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php`:
- Around line 135-151: The generic Tesla pattern in $branch_340_patterns (the
'/\btesla\b/' entry used by the foreach + preg_match that returns '340') is
matching modern/datacenter Tesla models and misclassifying them; replace the
bare brand token with explicit early-Tesla model patterns (only match the known
pre-Fermi model names you want routed to branch 340, e.g. explicit C1xx/C2xx or
early-series model identifiers or other manufacturer model codes) so that only
those early models trigger return '340', and remove the generic '/\btesla\b/'
entry so later 390/470 checks can correctly classify K80/modern Teslas.
- Around line 316-341: nvidia_driver_device_id_check_from_nvidia currently calls
file_get_contents for supportedchips.html on every invocation; memoize the
fetched HTML per driver version by introducing a static (or global) cache array
keyed by $normalized_version inside nvidia_driver_device_id_check_from_nvidia,
check the cache before calling file_get_contents, store the result (including
failure) into that cache after the fetch, and reuse it for subsequent calls;
keep the existing $url, $context and $fetch_timeout logic but only perform
network I/O when the cache miss occurs so per-GPU loops in gpu-support.php reuse
the same README content.
- Around line 13-23: The regex in nvidia_extract_version doesn't accept a
leading "v" (so "v590.48.01" returns null); update the preg_match in function
nvidia_extract_version to allow an optional leading "v" before the numeric
capture and make it case-insensitive so inputs like "v590.48.01" or "V590.48.01"
match—e.g., change the pattern used in preg_match to permit an optional "v" (v?)
immediately before the captured group and add the i flag, while keeping the
captured group as the numeric version so the function still returns only the
digits.

In `@source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php`:
- Around line 292-299: The current condition treats any kernel_module_support
value other than 'proprietary-only' as allowing open modules; change the logic
so that $open_recommended is only preferred when the entry explicitly indicates
open-module support (e.g., $entry['kernel_module_support'] === 'open' or
contains a specific token for open support) rather than just not being
'proprietary-only'. Update the conditional that sets
$support['recommended_driver'] to check $entry['kernel_module_support'] for an
explicit open-capable value before verifying $open_recommended and
in_array($open_recommended, $support['valid_drivers'], true), ensuring
Pascal/Volta cards without explicit open support won't be recommended
$open_recommended.

In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page`:
- Around line 148-176: The intersection logic currently includes unresolved rows
(where row.fetch_ok_count === 0) causing supportedAll to become empty and
disabling all driver radios; update the rows.forEach intersection builder to
skip any row with fetch_ok_count === 0 (use row.valid_drivers only for rows that
successfully fetched), initialize supportedAll from the first resolved row, and
intersect subsequent resolved rows only; after the loop, treat supportedAll ===
null as "no resolved data" (do not disable all radios) and treat
supportedAll.size === 0 as an explicit incompatibility state (disable radios or
mark them incompatible) instead of silently blanking the form—apply the same fix
to the similar block referenced at options handling (the code that queries
'input[name="drv_version"]') so unresolved lookups don't yield an empty set that
disables every option.
- Around line 178-191: The UI currently only hides/enables the "latest_nos"
radio based on proprietaryOnlyAll, so rows with kernel_module_support ===
'unknown' remain visible/enabled; update the logic around openOption/openParent
by treating 'unknown' as unsafe: compute a hasUnknown = rows.some(row =>
String((row && row.kernel_module_support) || '').toLowerCase() === 'unknown')
and then change the visibility/disable checks to use (proprietaryOnlyAll ||
hasUnknown) so the open-source option (openOption/openParent) is hidden and
disabled whenever any row is 'unknown' or all rows are 'proprietary-only'.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a17d7f16-8a08-4742-9583-30f23909b0a6

📥 Commits

Reviewing files that changed from the base of the PR and between 6316ed0 and 5ac0e4e.

📒 Files selected for processing (4)
  • architecture-mapping.json
  • source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php
  • source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php
  • source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page

Comment thread source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php Outdated
Comment thread source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page
Comment thread source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page
@ich777

Copy link
Copy Markdown
Collaborator

Hi Simon, thanks for the PR, I'll look into it later today.

From a quick scroll through, one thing I'd really prefer is not displaying GPU generations on the plugin page. That would mean we'd need to push a plugin update every time a new generation releases. Most users wouldn't care about that info anyway, but I guess an update might still be necessary even if the values aren't shown, since the plugin page backend needs to know about new generations anyways.

The compilation itself isn't difficult, but packaging adds quite a bit of time (around 20-30 minutes more), and the backend would need significant changes.

My plan was actually to drop the proprietary packages (except for the 580 - it seems that this is now the legacy driver) and only compile the open-source drivers going forward.

grafik

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php (2)

193-199: Inefficient cache check: lspci is executed before checking cache.

The shell command runs unconditionally on line 193, then the cache is checked afterward. This wastes an exec call when cache exists.

♻️ Proposed fix: check cache first
-$lspci_query = shell_exec('lspci -nn 2>/dev/null');
-if (is_file('/tmp/lspci_output.txt')) {
-  $cached_lspci = `@file_get_contents`('/tmp/lspci_output.txt');
-  if ($cached_lspci !== false && trim($cached_lspci) !== '') {
-    $lspci_query = $cached_lspci;
-  }
-}
+$lspci_query = null;
+if (is_file('/tmp/lspci_output.txt')) {
+  $cached_lspci = `@file_get_contents`('/tmp/lspci_output.txt');
+  if ($cached_lspci !== false && trim($cached_lspci) !== '') {
+    $lspci_query = $cached_lspci;
+  }
+}
+if ($lspci_query === null) {
+  $lspci_query = shell_exec('lspci -nn 2>/dev/null');
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php` around
lines 193 - 199, The code currently runs shell_exec('lspci -nn 2>/dev/null')
into $lspci_query before checking the cache file, causing an unnecessary exec
when cached data exists; change the logic so you first check if
'/tmp/lspci_output.txt' exists and read its contents into $lspci_query (using
`@file_get_contents` and trim check), and only call shell_exec('lspci -nn
2>/dev/null') to populate $lspci_query if the cache is missing or empty; keep
using the same variable name $lspci_query and preserve the existing truthiness
checks so downstream code is unaffected.

42-82: Consider handling stale cache when remote fetch fails.

When the cache is expired and the remote fetch fails, the code falls through to the local file (line 84). However, if both remote and local file fail, the stale cache (if it exists) could still be useful. Currently, stale cache data is only used within TTL.

This is a minor edge case - the hardcoded defaults provide a reasonable fallback. No change required unless you want maximum resilience.

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

In `@source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php` around
lines 42 - 82, When the remote fetch fails, fall back to a stale cache if
available: after the remote read ($remote_json) fails, check for the existence
of $cache_file (and optionally read $cache_time_file) to load $cached_json,
json_decode it and pass it through
nvidia_normalize_architecture_mapping($cached_data, $default); if normalization
returns a non-empty array return it. Keep the existing normal cache write paths
unchanged, and ensure you only use the stale cached data as a fallback when
remote fetch fails and before falling back to local files.
source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page (1)

205-211: Consider clearing selection when all options are disabled.

When incompatibleAll is true, all options are disabled but the currently selected option remains checked (albeit disabled). This is acceptable given the opacity feedback, but you could optionally uncheck it for clarity.

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

In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page` around
lines 205 - 211, When all driver options are disabled (e.g., when
incompatibleAll is true) the currently selected input stays checked; update the
logic around the selected variable (the code that does
document.querySelector('input[name="drv_version"]:checked')) to detect if there
are no enabled inputs
(document.querySelector('input[name="drv_version"]:not(:disabled') returns null)
and, in that case, clear the selection by setting selected.checked = false (or
removeAttribute('checked')) so no option remains checked when all are disabled;
keep the existing branch that selects the first enabled option when one exists.
source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php (1)

282-300: Minor optimization opportunity in fallback logic.

The two loops over $available_versions (lines 283-289 and 293-299) could be combined by collecting versions and filtering afterward. However, this is a minor concern since the array is typically small.

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

In `@source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php`
around lines 282 - 300, The two separate loops over $available_versions in the
'current' branch can be merged: iterate once over $available_versions inside the
elseif ($required_branch === 'current') block, call
nvidia_extract_version($version) and nvidia_driver_major(...) once per element
and collect normalized versions with their majors (e.g., into a temporary
array), then build $valid_versions by filtering that temp array for majors not
equal to 470, 390, or 340; if the resulting $valid_versions is empty, apply a
second filter on the same temp array to select entries where
nvidia_driver_major(...) === (int)$current_branch_major and populate
$valid_versions — update references to nvidia_extract_version,
nvidia_driver_major, $valid_versions, and $current_branch_major accordingly and
remove the duplicated loops.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php`:
- Around line 282-300: The two separate loops over $available_versions in the
'current' branch can be merged: iterate once over $available_versions inside the
elseif ($required_branch === 'current') block, call
nvidia_extract_version($version) and nvidia_driver_major(...) once per element
and collect normalized versions with their majors (e.g., into a temporary
array), then build $valid_versions by filtering that temp array for majors not
equal to 470, 390, or 340; if the resulting $valid_versions is empty, apply a
second filter on the same temp array to select entries where
nvidia_driver_major(...) === (int)$current_branch_major and populate
$valid_versions — update references to nvidia_extract_version,
nvidia_driver_major, $valid_versions, and $current_branch_major accordingly and
remove the duplicated loops.

In `@source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php`:
- Around line 193-199: The code currently runs shell_exec('lspci -nn
2>/dev/null') into $lspci_query before checking the cache file, causing an
unnecessary exec when cached data exists; change the logic so you first check if
'/tmp/lspci_output.txt' exists and read its contents into $lspci_query (using
`@file_get_contents` and trim check), and only call shell_exec('lspci -nn
2>/dev/null') to populate $lspci_query if the cache is missing or empty; keep
using the same variable name $lspci_query and preserve the existing truthiness
checks so downstream code is unaffected.
- Around line 42-82: When the remote fetch fails, fall back to a stale cache if
available: after the remote read ($remote_json) fails, check for the existence
of $cache_file (and optionally read $cache_time_file) to load $cached_json,
json_decode it and pass it through
nvidia_normalize_architecture_mapping($cached_data, $default); if normalization
returns a non-empty array return it. Keep the existing normal cache write paths
unchanged, and ensure you only use the stale cached data as a fallback when
remote fetch fails and before falling back to local files.

In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page`:
- Around line 205-211: When all driver options are disabled (e.g., when
incompatibleAll is true) the currently selected input stays checked; update the
logic around the selected variable (the code that does
document.querySelector('input[name="drv_version"]:checked')) to detect if there
are no enabled inputs
(document.querySelector('input[name="drv_version"]:not(:disabled') returns null)
and, in that case, clear the selection by setting selected.checked = false (or
removeAttribute('checked')) so no option remains checked when all are disabled;
keep the existing branch that selects the first enabled option when one exists.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 28a51fa5-f729-4e1a-9f77-031d0ff169b3

📥 Commits

Reviewing files that changed from the base of the PR and between 5ac0e4e and c59580b.

📒 Files selected for processing (3)
  • source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php
  • source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php
  • source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page

@SimonFair

Copy link
Copy Markdown
Contributor Author

Code RabBit (@CodeRabbit) re check

@coderabbitai

coderabbitai Bot commented Mar 17, 2026

Copy link
Copy Markdown

@SimonFair, I'll kick off a fresh full review of the PR now, taking into account the latest changes.

✅ Actions performed

Full review triggered.

@SimonFair
SimonFair marked this pull request as ready for review March 17, 2026 14:35

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (3)
source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php (1)

412-416: Variable shadowing in loop reduces readability.

Line 413 reassigns $version inside the foreach loop that iterates over $candidate_versions. While this works correctly, it shadows the loop variable and can confuse readers or cause subtle bugs if the loop body is extended later.

♻️ Proposed fix
   foreach ($candidate_versions as $version) {
-    $version = nvidia_extract_version($version);
-    if ($version === null) {
+    $normalized = nvidia_extract_version($version);
+    if ($normalized === null) {
       continue;
     }
 
-    $check = nvidia_driver_device_id_check_from_nvidia($version, $normalized_id, $fetch_timeout);
+    $check = nvidia_driver_device_id_check_from_nvidia($normalized, $normalized_id, $fetch_timeout);
     $checked_versions[] = $check;
 
     if (!empty($check['supported'])) {
-      $valid_versions[] = $version;
+      $valid_versions[] = $normalized;
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php`
around lines 412 - 416, The foreach loop over $candidate_versions reassigns the
loop variable $version after calling nvidia_extract_version, causing variable
shadowing; change the inner variable to a new name (e.g., $extractedVersion or
$parsed_version) so the loop variable remains untouched, update the null-check
to use that new variable and replace subsequent uses of the extracted value
accordingly (refer to the foreach over $candidate_versions and the call to
nvidia_extract_version).
source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php (2)

142-145: Remote URL fetches from GitHub raw may be unreliable.

Line 144 fetches architecture mapping from github.com/unraid/unraid-nvidia-driver/raw/master/.... GitHub raw URLs can be rate-limited or blocked in some network environments, and using master branch means any change to the repo immediately affects production systems.

Consider:

  1. Using a versioned/tagged URL or CDN
  2. Documenting that the remote fetch is optional (local fallback exists)
  3. Ensuring the 5-second timeout (line 67) doesn't cause UX issues when GitHub is slow
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php` around
lines 142 - 145, The call to nvidia_load_architecture_mapping currently uses an
unpinned GitHub raw URL which can be rate-limited or changed unexpectedly;
update the call to use a versioned or tagged URL (or configurable CDN) instead
of the master raw URL, make the remote fetch optional with clear documentation
that a local file is the fallback, and surface/configure the existing 5-second
timeout used by the fetch so it can be increased or handled gracefully to avoid
UX hangs; reference the nvidia_load_architecture_mapping invocation and the
fetch timeout setting so you add a configurable URL/tag constant, a flag or
docstring noting the local fallback, and timeout handling around the remote
fetch.

149-166: Duplicated version-fetching logic with nvidia-driver.page.

Lines 149-166 duplicate the version-fetching shell commands and candidate_versions assembly that also appear in nvidia-driver.page (lines 15-54). This creates maintenance burden and potential for drift between the two files.

Consider extracting shared version-fetching logic into a reusable include or function within card-support.php.

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

In `@source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php` around
lines 149 - 166, Extract the duplicated version-fetching logic (the shell_exec
calls that set $latest_v, $latest_prb_v, $latest_nfb_v, $latest_nos_v, the
file('/tmp/nvidia_driver') read into $eachlines/$available_versions, and the
assembly of $candidate_versions) into a single reusable function (e.g.,
get_nvidia_versions()) inside card-support.php, export or include that file
where needed, then replace the block in gpu-support.php with a call that returns
$available_versions and $candidate_versions; ensure the new function accepts no
args and preserves the same trimming/array_filter behavior and empty-string
checks so callers (gpu-support.php and nvidia-driver.page) get identical
outputs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php`:
- Around line 265-300: The function nvidia_valid_drivers_for_device_id currently
returns no drivers when nvidia_required_branch_for_device_id($device_id, ...)
yields 'unknown'; change the control flow so that 'unknown' falls back to the
same logic used for 'current' (i.e., iterate $available_versions, call
nvidia_extract_version and nvidia_driver_major, accept majors that are not
470/390/340, and if that produces none, fallback to matching
(int)$current_branch_major), ensuring you reference and use
nvidia_extract_version, nvidia_driver_major and $current_branch_major exactly as
in the current branch block and return the accumulated $valid_versions.

---

Nitpick comments:
In `@source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php`:
- Around line 412-416: The foreach loop over $candidate_versions reassigns the
loop variable $version after calling nvidia_extract_version, causing variable
shadowing; change the inner variable to a new name (e.g., $extractedVersion or
$parsed_version) so the loop variable remains untouched, update the null-check
to use that new variable and replace subsequent uses of the extracted value
accordingly (refer to the foreach over $candidate_versions and the call to
nvidia_extract_version).

In `@source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php`:
- Around line 142-145: The call to nvidia_load_architecture_mapping currently
uses an unpinned GitHub raw URL which can be rate-limited or changed
unexpectedly; update the call to use a versioned or tagged URL (or configurable
CDN) instead of the master raw URL, make the remote fetch optional with clear
documentation that a local file is the fallback, and surface/configure the
existing 5-second timeout used by the fetch so it can be increased or handled
gracefully to avoid UX hangs; reference the nvidia_load_architecture_mapping
invocation and the fetch timeout setting so you add a configurable URL/tag
constant, a flag or docstring noting the local fallback, and timeout handling
around the remote fetch.
- Around line 149-166: Extract the duplicated version-fetching logic (the
shell_exec calls that set $latest_v, $latest_prb_v, $latest_nfb_v,
$latest_nos_v, the file('/tmp/nvidia_driver') read into
$eachlines/$available_versions, and the assembly of $candidate_versions) into a
single reusable function (e.g., get_nvidia_versions()) inside card-support.php,
export or include that file where needed, then replace the block in
gpu-support.php with a call that returns $available_versions and
$candidate_versions; ensure the new function accepts no args and preserves the
same trimming/array_filter behavior and empty-string checks so callers
(gpu-support.php and nvidia-driver.page) get identical outputs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 97f74c17-8aba-40c2-997d-8894bc617bcb

📥 Commits

Reviewing files that changed from the base of the PR and between 6316ed0 and c59580b.

📒 Files selected for processing (4)
  • architecture-mapping.json
  • source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php
  • source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php
  • source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php (1)

190-196: Minor inefficiency: lspci is always executed even when cache is used.

The shell_exec('lspci -nn') runs unconditionally on line 190, but then the result may be overwritten by cached data on lines 192-195. Consider checking for the cache first to avoid the unnecessary shell execution.

🔧 Proposed fix
-$lspci_query = shell_exec('lspci -nn 2>/dev/null');
+$lspci_query = null;
 if (is_file('/tmp/lspci_output.txt')) {
   $cached_lspci = `@file_get_contents`('/tmp/lspci_output.txt');
   if ($cached_lspci !== false && trim($cached_lspci) !== '') {
     $lspci_query = $cached_lspci;
   }
 }
+if ($lspci_query === null) {
+  $lspci_query = shell_exec('lspci -nn 2>/dev/null');
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php` around
lines 190 - 196, Avoid running shell_exec('lspci -nn 2>/dev/null')
unconditionally: first check the cache file '/tmp/lspci_output.txt' with
is_file() and read it via file_get_contents(); if the cache contains non-empty
data assign it to $lspci_query, otherwise call shell_exec('lspci -nn
2>/dev/null') to populate $lspci_query (and optionally write the output to the
cache). Update the logic around $lspci_query, is_file('/tmp/lspci_output.txt')
and `@file_get_contents`('/tmp/lspci_output.txt') so the shell command is only
executed when no valid cache exists.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php`:
- Around line 190-196: Avoid running shell_exec('lspci -nn 2>/dev/null')
unconditionally: first check the cache file '/tmp/lspci_output.txt' with
is_file() and read it via file_get_contents(); if the cache contains non-empty
data assign it to $lspci_query, otherwise call shell_exec('lspci -nn
2>/dev/null') to populate $lspci_query (and optionally write the output to the
cache). Update the logic around $lspci_query, is_file('/tmp/lspci_output.txt')
and `@file_get_contents`('/tmp/lspci_output.txt') so the shell command is only
executed when no valid cache exists.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7fe9f050-ab92-473b-9ebc-dfe837575d18

📥 Commits

Reviewing files that changed from the base of the PR and between c59580b and 38faaa5.

📒 Files selected for processing (3)
  • source/usr/local/emhttp/plugins/nvidia-driver/include/card-support.php
  • source/usr/local/emhttp/plugins/nvidia-driver/include/gpu-support.php
  • source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page

@SimonFair
SimonFair marked this pull request as draft March 17, 2026 16:06

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page`:
- Line 325: The value attribute for the radio input uses unescaped dynamic data
($lines2) which risks HTML injection; update the input generation so the value
attribute uses the same escaping as data-driver-version (i.e., call
htmlspecialchars on $lines2 or cast to string then htmlspecialchars) and keep
the existing checked logic and data-driver-version call to
nvidia_extract_version unchanged so both attributes are consistently escaped.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7531831b-3a97-4ab2-bcee-8a56b699f094

📥 Commits

Reviewing files that changed from the base of the PR and between 38faaa5 and 4fc71f3.

📒 Files selected for processing (1)
  • source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page

Comment thread source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (1)
source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page (1)

160-209: ⚠️ Potential issue | 🟠 Major

Disable update action when no compatible driver is selectable.

When compatibility intersection is empty, all radios become disabled, but the update action remains clickable. That can still submit an empty/invalid selection from changeVersion() (Line 73). Disable the button when no enabled option exists.

🔧 Proposed fix
     var selected = document.querySelector('input[name="drv_version"]:checked');
     if (selected && selected.disabled) {
       var firstEnabled = document.querySelector('input[name="drv_version"]:not(:disabled)');
       if (firstEnabled) {
         firstEnabled.checked = true;
       }
     }
+
+    var updateButton = document.querySelector('input[type="button"][value="Update & Download"]');
+    if (updateButton) {
+      var hasEnabledOption = !!document.querySelector('input[name="drv_version"]:not(:disabled)');
+      updateButton.disabled = !hasEnabledOption;
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page` around
lines 160 - 209, When the compatibility intersection is empty all driver radio
inputs are disabled but the update action (the button that calls
changeVersion()) remains enabled; query that update button element (the DOM
element used to trigger changeVersion()) and set its disabled state based on
whether any enabled 'input[name="drv_version"]' exists. Concretely: after you
finish disabling/enabling radios (and after selecting firstEnabled), compute
hasEnabled =
Boolean(document.querySelector('input[name="drv_version"]:not(:disabled)'));
then set updateButton.disabled = !hasEnabled (and ensure you obtain updateButton
via the same selector/reference used elsewhere to invoke changeVersion()). Also
ensure you update this disabled state in both the incompatibleAll branch and the
openOption/hideOpen handling so the button reflects the final radio
availability.
🧹 Nitpick comments (1)
source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page (1)

14-19: Harden version metadata reads with safe defaults.

This block assumes every key exists in $version_data. A partial payload can cascade into warnings and break later array operations. Please default missing values defensively.

💡 Proposed hardening
-$version_data = nvidia_get_nvidia_versions();
-$latest_v = $version_data['latest_v'];
-$latest_prb_v = $version_data['latest_prb_v'];
-$latest_nfb_v = $version_data['latest_nfb_v'];
-$latest_nos_v = $version_data['latest_nos_v'];
+$version_data = nvidia_get_nvidia_versions();
+if (!is_array($version_data)) {
+  $version_data = [];
+}
+$latest_v = (string)($version_data['latest_v'] ?? '');
+$latest_prb_v = (string)($version_data['latest_prb_v'] ?? '');
+$latest_nfb_v = (string)($version_data['latest_nfb_v'] ?? '');
+$latest_nos_v = (string)($version_data['latest_nos_v'] ?? '');
@@
-$available_versions = $version_data['available_versions'];
-$candidate_versions = $version_data['candidate_versions'];
+$available_versions = is_array($version_data['available_versions'] ?? null) ? $version_data['available_versions'] : [];
+$candidate_versions = is_array($version_data['candidate_versions'] ?? null) ? $version_data['candidate_versions'] : [];

Also applies to: 34-37, 46-49

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

In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page` around
lines 14 - 19, The assignments from nvidia_get_nvidia_versions() assume all keys
exist and can error on partial payloads; update the code that sets $latest_v,
$latest_prb_v, $latest_nfb_v, $latest_nos_v (and the analogous assignments later
in the file) to read each key defensively and provide a safe default when the
key is missing or null (e.g. use isset()/array_key_exists() or the
null-coalescing equivalent) so downstream array operations never receive
undefined values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page`:
- Around line 298-310: The visible version labels (e.g. the echo outputs like
echo "v$latest_v", echo "v$latest_prb_v", echo "v$latest_nfb_v", echo
"v$latest_nos_v" and the unraid version used in the version_compare echo) are
not escaped; wrap those displayed strings with htmlspecialchars (or equivalent)
before rendering so the UI shows escaped text and prevents HTML injection.
Locate the echo usages around the radio inputs and replace the raw outputs with
escaped equivalents (e.g. htmlspecialchars("v".$latest_v, ENT_QUOTES, 'UTF-8'))
for the variables $latest_v, $latest_prb_v, $latest_nfb_v, $latest_nos_v and any
echoed $unraid_version['version'].

---

Duplicate comments:
In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page`:
- Around line 160-209: When the compatibility intersection is empty all driver
radio inputs are disabled but the update action (the button that calls
changeVersion()) remains enabled; query that update button element (the DOM
element used to trigger changeVersion()) and set its disabled state based on
whether any enabled 'input[name="drv_version"]' exists. Concretely: after you
finish disabling/enabling radios (and after selecting firstEnabled), compute
hasEnabled =
Boolean(document.querySelector('input[name="drv_version"]:not(:disabled)'));
then set updateButton.disabled = !hasEnabled (and ensure you obtain updateButton
via the same selector/reference used elsewhere to invoke changeVersion()). Also
ensure you update this disabled state in both the incompatibleAll branch and the
openOption/hideOpen handling so the button reflects the final radio
availability.

---

Nitpick comments:
In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page`:
- Around line 14-19: The assignments from nvidia_get_nvidia_versions() assume
all keys exist and can error on partial payloads; update the code that sets
$latest_v, $latest_prb_v, $latest_nfb_v, $latest_nos_v (and the analogous
assignments later in the file) to read each key defensively and provide a safe
default when the key is missing or null (e.g. use isset()/array_key_exists() or
the null-coalescing equivalent) so downstream array operations never receive
undefined values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f78b0a63-77ff-4122-8a54-77061b5cdfd6

📥 Commits

Reviewing files that changed from the base of the PR and between 4fc71f3 and 589f4cb.

📒 Files selected for processing (1)
  • source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page

Comment thread source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page`:
- Around line 325-326: The visible version label prints $lines2 unescaped which
creates an XSS risk and is inconsistent with other labels; update the label next
to the radio input (the block using nvidia_extract_version($lines2) and $lines2)
to wrap the displayed value with htmlspecialchars(..., ENT_QUOTES) and likewise
fix the other occurrence that echoes $cur_drv_v by escaping it with
htmlspecialchars($cur_drv_v, ENT_QUOTES) so all visible version labels match the
existing escaping pattern.
- Around line 298-300: The radio inputs for driver selection (the <input>
elements with name="drv_version" and data-driver-version attributes for values
like "latest" and "latest_prb") are not explicitly self-closed, which lets the
HTML parser infer DOM structure; update each radio <input> (all occurrences
where name="drv_version" and similar radio controls) to be explicitly closed
(add a trailing "/>" immediately after the input attributes) before any
following label/markup (e.g., before the <font> or <b> tags) so the inputs are
valid void elements and the DOM structure is deterministic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 54b39563-168c-4234-be3b-3fddcd441f4a

📥 Commits

Reviewing files that changed from the base of the PR and between 589f4cb and 105d8e3.

📒 Files selected for processing (1)
  • source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page

Comment thread source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page Outdated
Comment thread source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (1)
source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page (1)

268-269: Orphaned closing tags without matching openers.

These </tr> and </table> tags don't have corresponding opening tags in the current structure. The next <table> opens on line 293. This appears to be leftover from previous changes and should be removed for cleaner HTML structure.

♻️ Proposed fix
-        </tr>
-    </table>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page` around
lines 268 - 269, Remove the orphaned closing tags "</tr>" and "</table>" that
appear before the next "<table>" element; these stray closers have no matching
openers and should be deleted so the HTML structure is valid (search for the
standalone "</tr>" and "</table>" entries in the block and remove them), then
verify the surrounding markup still balances and validate the HTML.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page`:
- Line 262: The inline PHP short-echo that runs nvidia-smi (the `<?=` ...
backtick command producing raw GPU output) must not be printed raw; capture the
command output into a variable (e.g. $gpu_info via shell_exec or backticks),
escape it with htmlspecialchars or htmlentities to prevent XSS, then convert
preserved line breaks with nl2br (or otherwise insert <br/> after escaping) and
echo the escaped/converted string instead of the raw command output; remove the
sed-inserted raw `<br/>` in the command and ensure the final echo uses the
escaped variable.

---

Nitpick comments:
In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page`:
- Around line 268-269: Remove the orphaned closing tags "</tr>" and "</table>"
that appear before the next "<table>" element; these stray closers have no
matching openers and should be deleted so the HTML structure is valid (search
for the standalone "</tr>" and "</table>" entries in the block and remove them),
then verify the surrounding markup still balances and validate the HTML.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0f0137b4-f5f4-45e9-a2d4-e23946705ebd

📥 Commits

Reviewing files that changed from the base of the PR and between 105d8e3 and 26fd4f0.

📒 Files selected for processing (1)
  • source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page

Comment thread source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (1)
source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page (1)

90-100: ⚠️ Potential issue | 🟠 Major

Disable the action when filtering leaves no valid radio.

If filtering disables every drv_version option, the previously checked radio can remain selected and Update & Download stays clickable. changeVersion() can still consume that stale value.

🔧 Proposed change
 function resetDriverOptionSupport() {
     var options = document.querySelectorAll('input[name="drv_version"]');
     options.forEach(function(option) {
       option.disabled = false;
       var parent = option.closest('p');
       if (parent) {
         parent.style.opacity = '1';
         parent.style.display = '';
       }
     });
+    var updateButton = document.querySelector('input[type="button"][value="Update & Download"]');
+    if (updateButton) {
+      updateButton.disabled = false;
+    }
 }
 ...
+    var updateButton = document.querySelector('input[type="button"][value="Update & Download"]');
     var selected = document.querySelector('input[name="drv_version"]:checked');
-    if (selected && selected.disabled) {
-      var firstEnabled = document.querySelector('input[name="drv_version"]:not(:disabled)');
-      if (firstEnabled) {
-        firstEnabled.checked = true;
-      }
-    }
+    var firstEnabled = document.querySelector('input[name="drv_version"]:not(:disabled)');
+    if (selected && selected.disabled) {
+      if (firstEnabled) {
+        firstEnabled.checked = true;
+      } else {
+        selected.checked = false;
+      }
+    }
+    if (updateButton) {
+      updateButton.disabled = !firstEnabled;
+    }

Also applies to: 211-259

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

In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page` around
lines 90 - 100, When filtering can disable every 'drv_version' option,
resetDriverOptionSupport must also clear any previously checked/stale radio and
prevent changeVersion() from reading it: inside resetDriverOptionSupport iterate
inputs[name="drv_version"] and if none remain enabled, remove the checked
attribute (and set checked=false) from any radio, and disable/hide the UI action
that triggers changeVersion (the Update & Download control) so it cannot be
clicked; also ensure changeVersion() only reads a radio that is both checked and
not disabled. Apply the same fix where filtering logic exists (the block around
functions referenced at lines 211-259).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page`:
- Around line 151-153: Remove the UI rendering of GPU architecture by deleting
the conditional that checks and appends row.architecture (the block using
row.architecture and escapeHtml). Locate the code that builds the HTML string
where "Architecture: <code>' + escapeHtml(row.architecture)" is appended and
remove that entire if (row.architecture) { ... } branch so the architecture row
is no longer produced.
- Around line 177-260: The update_version handler in include/exec.sh currently
writes the requested version directly to config without validation; modify the
update_version handler to validate the incoming version string against the
canonical list of allowed versions (use the same source as gpu-support.php:
available_versions and candidate_versions from gpu-support.php or an exported
list/function it provides) and reject any value not present in those lists by
returning an error (non-zero exit code / HTTP error response) and not updating
the config; ensure the validation compares the exact driver identifier used in
the UI (the drv_version values / mappedVersion) and include a clear error path
in update_version that logs the invalid value and aborts the write.

---

Duplicate comments:
In `@source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page`:
- Around line 90-100: When filtering can disable every 'drv_version' option,
resetDriverOptionSupport must also clear any previously checked/stale radio and
prevent changeVersion() from reading it: inside resetDriverOptionSupport iterate
inputs[name="drv_version"] and if none remain enabled, remove the checked
attribute (and set checked=false) from any radio, and disable/hide the UI action
that triggers changeVersion (the Update & Download control) so it cannot be
clicked; also ensure changeVersion() only reads a radio that is both checked and
not disabled. Apply the same fix where filtering logic exists (the block around
functions referenced at lines 211-259).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6a31e428-59da-495b-bbc0-fa2a3bedeaef

📥 Commits

Reviewing files that changed from the base of the PR and between 9f26698 and 5272d94.

📒 Files selected for processing (1)
  • source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page

Comment thread source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page
Comment thread source/usr/local/emhttp/plugins/nvidia-driver/nvidia-driver.page
@SimonFair
SimonFair marked this pull request as ready for review March 18, 2026 09:47
@ich777
Christoph (ich777) merged commit 38caf92 into unraid:master Mar 19, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants