-
Notifications
You must be signed in to change notification settings - Fork 8
feat: UI redesign, GitHub Actions CI, security hardening #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
mricharz
wants to merge
15
commits into
unraid:master
Choose a base branch
from
mricharz:pr/upstream-improvements
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
63a120d
feat: UI redesign, GitHub Actions CI, security hardening, beta branch
mricharz ec4698a
fix: treat NVIDIA installer exit code 8 as incompatible, not failure
mricharz 44a87fe
fix: detect incompatible builds by checking for output artifacts
mricharz c1c1c74
fix: detect latest kernel per major.minor branch, not just top 2
mricharz b7c6c25
fix: use awk for kernel branch dedup, avoid YAML-breaking newlines
mricharz 4a811df
fix: add actions:write permission for workflow_dispatch trigger
mricharz 75abebd
fix: limit kernel detection to top 3 major.minor branches
mricharz 0912bd4
fix: jq scoping bug in extra_builds cleanup, improve fallback logic
mricharz cf78125
feat: multi-GPU support with expandable details, rename labels
mricharz 5afa6ae
fix: review findings — dead code, unknown tag, conflict UX
mricharz 62fe3da
refactor: simplify — trim at assignment, CSS variables, rename has_pr…
mricharz 1c66bd7
fix: PR review findings — checkbox override, XSS escaping, version sort
mricharz ec4b2a2
fix: fail fast on empty driver versions, guard extra_builds rotation
mricharz 38dfd62
fix: add concurrency control to prevent overlapping auto-update runs
mricharz 61c194a
fix: stricter semver validation, fail on jq errors
mricharz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,253 @@ | ||
| name: Auto-detect and update build matrix | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: '0 4 * * *' # Daily at 04:00 UTC | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: write | ||
| actions: write | ||
|
|
||
| concurrency: | ||
| group: auto-update-matrix-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| detect-and-update: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 1 | ||
|
|
||
| - name: Install dependencies | ||
| run: sudo apt-get -y install jq tidy wget | ||
|
|
||
| - name: Detect NVIDIA driver versions | ||
| id: nvidia | ||
| run: | | ||
| RAW_DATA="$(wget -qO- https://www.nvidia.com/en-us/drivers/unix/ | tidy -quiet -wrap 4096 2>/dev/null | grep -A8 "Linux x86_64/AMD64/EM64T")" | ||
| PRB="$(echo "${RAW_DATA}" | grep -i "Latest Production Branch" | grep -oE '\b[0-9]+\.[0-9]+(\.[0-9]+)?\b')" | ||
| NFB="$(echo "${RAW_DATA}" | grep -i "Latest New Feature Branch" | grep -oE '\b[0-9]+\.[0-9]+(\.[0-9]+)?\b')" | ||
| BETA="$(echo "${RAW_DATA}" | grep -i "Latest Beta" | grep -oE '\b[0-9]+\.[0-9]+(\.[0-9]+)?\b')" | ||
| LEGACY="$(echo "${RAW_DATA}" | grep -i "Latest Legacy" | grep "(4" | head -1 | grep -oE '\b[0-9]+\.[0-9]+(\.[0-9]+)?\b')" | ||
|
|
||
| # Fallback to NVIDIA developer forum if fetch or parse failed | ||
| if [ -z "${RAW_DATA}" ] || { [ -z "${PRB}" ] && [ -z "${NFB}" ] && [ -z "${BETA}" ]; }; then | ||
| RAW_DATA="$(wget -qO- https://forums.developer.nvidia.com/t/current-graphics-driver-releases/28500 | tidy -quiet -wrap 4096 2>/dev/null || true)" | ||
| PRB="$(echo "${RAW_DATA}" | grep -i "^Current production branch" | grep -oE '\b[0-9]+\.[0-9]+(\.[0-9]+)?\b')" | ||
| NFB="$(echo "${RAW_DATA}" | grep -i "^Current new feature branch" | grep -oE '\b[0-9]+\.[0-9]+(\.[0-9]+)?\b')" | ||
| BETA="$(echo "${RAW_DATA}" | grep -i "^Current beta" | grep -oE '\b[0-9]+\.[0-9]+(\.[0-9]+)?\b')" | ||
| LEGACY="$(echo "${RAW_DATA}" | grep -i -A1 '>Legacy releases' | tail -1 | grep -oE '\b[0-9]+\.[0-9]+(\.[0-9]+)?\b')" | ||
| fi | ||
|
|
||
| if [ -z "${RAW_DATA}" ] || { [ -z "${PRB}" ] && [ -z "${NFB}" ]; }; then | ||
| echo "::error::Failed to fetch NVIDIA driver data from both sources" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "prb=${PRB}" >> "$GITHUB_OUTPUT" | ||
| echo "nfb=${NFB}" >> "$GITHUB_OUTPUT" | ||
| echo "beta=${BETA}" >> "$GITHUB_OUTPUT" | ||
| echo "legacy=${LEGACY}" >> "$GITHUB_OUTPUT" | ||
| echo "Detected: PRB=${PRB} NFB=${NFB} BETA=${BETA} LEGACY=${LEGACY}" | ||
|
|
||
| - name: Detect latest Unraid kernel versions | ||
| id: kernels | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| # Get kernel tags from upstream releases (format: 6.x.y-Unraid) | ||
| # Keep the latest kernel per major.minor branch (e.g. 6.12.x, 6.17.x, 6.18.x) | ||
| # so all active Unraid versions are covered | ||
| ALL_TAGS=$(gh api repos/unraid/unraid-nvidia-driver/releases \ | ||
| --paginate --jq '.[].tag_name' 2>/dev/null \ | ||
| | grep -E '^[0-9]+\.[0-9]+\.[0-9]+-Unraid$' \ | ||
| | sort -t. -k1,1nr -k2,2nr -k3,3nr) | ||
|
|
||
| if [ -z "$ALL_TAGS" ]; then | ||
| echo "::warning::No kernel tags found, keeping current kernel_versions" | ||
| echo "kernels=" >> "$GITHUB_OUTPUT" | ||
| exit 0 | ||
| fi | ||
|
|
||
| # Pick the latest patch version per major.minor branch, keep top 3 | ||
| KERNEL_TAGS=$(echo "$ALL_TAGS" | awk -F'[.-]' '!seen[$1"."$2]++' | head -3) | ||
| KERNEL_JSON=$(echo "$KERNEL_TAGS" | jq -R -c -s 'split("\n") | map(select(length > 0))') | ||
| echo "kernels=${KERNEL_JSON}" >> "$GITHUB_OUTPUT" | ||
| echo "Detected kernels: ${KERNEL_JSON}" | ||
|
|
||
| - name: Detect container runtime versions | ||
| id: runtimes | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| CONTAINER_TOOLKIT=$(gh api repos/unraid/nvidia-container-toolkit/releases/latest --jq '.tag_name' 2>/dev/null || echo "") | ||
| LIBNVIDIA=$(gh api repos/unraid/libnvidia-container/releases/latest --jq '.tag_name' 2>/dev/null || echo "") | ||
|
|
||
| # Ensure libnvidia-container matches toolkit version to prevent mismatches. | ||
| # Both repos release in sync; if versions differ, use the toolkit version | ||
| # and verify the matching libnvidia-container release exists. | ||
| if [ -n "${CONTAINER_TOOLKIT}" ] && [ -n "${LIBNVIDIA}" ] && [ "${CONTAINER_TOOLKIT}" != "${LIBNVIDIA}" ]; then | ||
| HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \ | ||
| -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ | ||
| "https://api.github.com/repos/unraid/libnvidia-container/releases/tags/${CONTAINER_TOOLKIT}") | ||
| if [ "${HTTP_CODE}" == "200" ]; then | ||
| LIBNVIDIA="${CONTAINER_TOOLKIT}" | ||
| fi | ||
| fi | ||
|
|
||
| echo "toolkit=${CONTAINER_TOOLKIT}" >> "$GITHUB_OUTPUT" | ||
| echo "libnvidia=${LIBNVIDIA}" >> "$GITHUB_OUTPUT" | ||
| echo "Detected: toolkit=${CONTAINER_TOOLKIT} libnvidia=${LIBNVIDIA}" | ||
|
|
||
| - name: Detect latest GCC tag | ||
| id: gcc | ||
| run: | | ||
| TOKEN=$(curl -s "https://ghcr.io/token?scope=repository:ich777/unraid_kernel:pull" | jq -r '.token') | ||
| GCC_TAG=$(curl -s -H "Authorization: Bearer $TOKEN" "https://ghcr.io/v2/ich777/unraid_kernel/tags/list" \ | ||
| | jq -r '.tags[]' | grep '^gcc_' | sort -V | tail -1) | ||
|
|
||
| if [ -z "${GCC_TAG}" ]; then | ||
| echo "::warning::Could not detect GCC tag, keeping current" | ||
| GCC_TAG=$(jq -r '.gcc_tag' build-matrix.json) | ||
| fi | ||
|
|
||
| echo "gcc_tag=${GCC_TAG}" >> "$GITHUB_OUTPUT" | ||
| echo "Detected GCC tag: ${GCC_TAG}" | ||
|
|
||
| - name: Update build-matrix.json | ||
| env: | ||
| NEW_PRB: ${{ steps.nvidia.outputs.prb }} | ||
| NEW_NFB: ${{ steps.nvidia.outputs.nfb }} | ||
| NEW_BETA: ${{ steps.nvidia.outputs.beta }} | ||
| NEW_KERNELS: ${{ steps.kernels.outputs.kernels }} | ||
| NEW_GCC: ${{ steps.gcc.outputs.gcc_tag }} | ||
| run: | | ||
| CUR_PRB=$(jq -r '.branches.production.driver_version' build-matrix.json) | ||
| CUR_NFB=$(jq -r '.branches.newfeature.driver_version' build-matrix.json) | ||
| CUR_BETA=$(jq -r '.branches.beta.driver_version' build-matrix.json) | ||
|
|
||
| jq --arg new_prb "${NEW_PRB}" \ | ||
| --arg new_nfb "${NEW_NFB}" \ | ||
| --arg new_beta "${NEW_BETA}" \ | ||
| --arg new_gcc "${NEW_GCC}" \ | ||
| --arg cur_prb "${CUR_PRB}" \ | ||
| --arg cur_nfb "${CUR_NFB}" \ | ||
| --arg cur_beta "${CUR_BETA}" \ | ||
| --argjson new_kernels "${NEW_KERNELS:-null}" \ | ||
| ' | ||
| # Update gcc_tag | ||
| (if ($new_gcc != "") then .gcc_tag = $new_gcc else . end) | ||
|
|
||
| # Update kernel versions if detected | ||
| | (if $new_kernels != null and ($new_kernels | length > 0) then | ||
| .kernel_versions = $new_kernels | ||
| else . end) | ||
|
|
||
| # Rotate production: old version → extra_builds, set new version | ||
| | (if ($new_prb != "") and ($cur_prb != "") and ($cur_prb != "null") and ($cur_prb != $new_prb) then | ||
| (if (.extra_builds | map(.driver_version) | index($cur_prb) | not) then | ||
| .extra_builds += [{"driver_version": $cur_prb, "module_types": ["proprietary", "opensource"]}] | ||
| else . end) | ||
| | .branches.production.driver_version = $new_prb | ||
| else . end) | ||
|
|
||
| # Rotate newfeature: old version → extra_builds, set new version | ||
| | (if ($new_nfb != "") and ($cur_nfb != "") and ($cur_nfb != "null") and ($cur_nfb != $new_nfb) then | ||
| (if (.extra_builds | map(.driver_version) | index($cur_nfb) | not) then | ||
| .extra_builds += [{"driver_version": $cur_nfb, "module_types": ["proprietary", "opensource"]}] | ||
| else . end) | ||
| | .branches.newfeature.driver_version = $new_nfb | ||
| else . end) | ||
|
|
||
| # Rotate beta: old version → extra_builds, set new version | ||
| | (if ($new_beta != "") and ($cur_beta != "") and ($cur_beta != "null") and ($cur_beta != $new_beta) then | ||
| (if (.extra_builds | map(.driver_version) | index($cur_beta) | not) then | ||
| .extra_builds += [{"driver_version": $cur_beta, "module_types": ["proprietary", "opensource"]}] | ||
| else . end) | ||
| | .branches.beta.driver_version = $new_beta | ||
| else . end) | ||
|
|
||
| # Remove from extra_builds any version that is now a branch version | ||
| | . as $root | .extra_builds = [ | ||
| .extra_builds[] | | ||
| select( | ||
| .driver_version != ($root.branches.production.driver_version // "") and | ||
| .driver_version != ($root.branches.newfeature.driver_version // "") and | ||
| .driver_version != ($root.branches.beta.driver_version // "") | ||
| ) | ||
| ] | ||
|
|
||
| # Deduplicate extra_builds | ||
| | .extra_builds = (.extra_builds | unique_by(.driver_version)) | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| ' build-matrix.json > build-matrix.json.tmp | ||
| mv build-matrix.json.tmp build-matrix.json | ||
|
|
||
| echo "Updated build-matrix.json:" | ||
| cat build-matrix.json | ||
|
|
||
| - name: Update versions.json | ||
| env: | ||
| NEW_PRB: ${{ steps.nvidia.outputs.prb }} | ||
| NEW_NFB: ${{ steps.nvidia.outputs.nfb }} | ||
| NEW_BETA: ${{ steps.nvidia.outputs.beta }} | ||
| NEW_LEGACY: ${{ steps.nvidia.outputs.legacy }} | ||
| TOOLKIT: ${{ steps.runtimes.outputs.toolkit }} | ||
| LIBNVIDIA: ${{ steps.runtimes.outputs.libnvidia }} | ||
| run: | | ||
| CUR_PRB=$(jq -r '.branches.production.current' versions.json) | ||
| CUR_NFB=$(jq -r '.branches.newfeature.current' versions.json) | ||
|
|
||
| jq --arg prb "${NEW_PRB}" \ | ||
| --arg nfb "${NEW_NFB}" \ | ||
| --arg beta "${NEW_BETA}" \ | ||
| --arg legacy "${NEW_LEGACY}" \ | ||
| --arg last_prb "${CUR_PRB}" \ | ||
| --arg last_nfb "${CUR_NFB}" \ | ||
| --arg toolkit "${TOOLKIT}" \ | ||
| --arg libnvidia "${LIBNVIDIA}" \ | ||
| ' | ||
| (if ($prb != "") then | ||
| .branches.production.current = $prb | ||
| | (if ($prb != $last_prb) then .branches.production.last_prb = $last_prb else . end) | ||
| else . end) | ||
| | (if ($nfb != "") then | ||
| .branches.newfeature.current = $nfb | ||
| | (if ($nfb != $last_nfb) then .branches.newfeature.last_nfb = $last_nfb else . end) | ||
| else . end) | ||
| | (if ($beta != "") then .branches.beta.current = $beta else . end) | ||
| | (if ($legacy != "") then .branches.legacy.current = $legacy else . end) | ||
| | (if ($toolkit | test("^[0-9]+(\\\\.[0-9]+)+$")) then .runtimes.containertoolkit.current = $toolkit else . end) | ||
| | (if ($libnvidia | test("^[0-9]+(\\\\.[0-9]+)+$")) then .runtimes.libnvidia.current = $libnvidia else . end) | ||
| ' versions.json > versions.json.tmp | ||
| mv versions.json.tmp versions.json | ||
|
|
||
| - name: Commit and push if changed | ||
| id: commit | ||
| run: | | ||
| if git diff --quiet; then | ||
| echo "No changes detected" | ||
| echo "changed=false" >> "$GITHUB_OUTPUT" | ||
| exit 0 | ||
| fi | ||
|
|
||
| git config user.name 'github-actions[bot]' | ||
| git config user.email 'github-actions[bot]@users.noreply.github.com' | ||
| git add build-matrix.json versions.json | ||
| git diff --cached --quiet && { echo "No staged changes"; echo "changed=false" >> "$GITHUB_OUTPUT"; exit 0; } | ||
| git commit -m "auto-update: detect new driver/kernel versions" | ||
| git push | ||
| echo "changed=true" >> "$GITHUB_OUTPUT" | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Trigger build workflow | ||
| if: steps.commit.outputs.changed == 'true' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| echo "Changes committed, triggering build workflow..." | ||
| gh workflow run "Build NVIDIA Driver Packages" --repo ${{ github.repository }} --ref ${{ github.ref_name }} | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fail fast when required driver versions are still empty after fallback.
At Line 42, the guard only checks
RAW_DATA. If HTML fetch succeeds but parsing misses key fields, the workflow continues with empty outputs and silently skips updates.🛠️ Proposed fix
🤖 Prompt for AI Agents