Bläddra i källkod

Add SukiSU-Ultra root flavor (builtin branch) and No Root option

- root-setup: new sukisu-ultra flavor (SukiSU-Ultra/SukiSU-Ultra)
- main.yml: SukiSU-Ultra + No Root dispatch choices, builtin-tip pin
  (PIN_SUKISU_ULTRA), root matrix entries, manager resolution
  (build-manager.yml artifacts Manager/Spoofed-Manager), release-notes
  render, verified-pin promotion; All stays next/kernelsu/resukisu
- build.yml: skip root-setup for none, No Root build metadata,
  sukisu-ultra uses pinned SUSFS (ships SUSFS in-tree, no 10_enable)
- managers.yml: SukiSU-Ultra + No Root choices, fetch + source paths,
  key secrets, gradle build, notes preview
- pins script, THIRD_PARTY_NOTICES, build-from-fork docs updated
TheWildJames 3 dagar sedan
förälder
incheckning
d278c3d63c

+ 7 - 2
.github/actions/root-setup/action.yml

@@ -2,7 +2,7 @@ name: Setup pinned root implementation
 description: Clone exactly one supported root implementation at a verified commit
 inputs:
   flavor:
-    description: 'kernelsu, next, or resukisu'
+    description: 'kernelsu, next, resukisu, or sukisu-ultra'
     required: true
   commit:
     description: 'Full immutable commit SHA'
@@ -35,6 +35,11 @@ runs:
             directory="ReSukiSU"
             manager="ReSukiSU Manager"
             ;;
+          sukisu-ultra)
+            repo="https://github.com/SukiSU-Ultra/SukiSU-Ultra.git"
+            directory="SukiSU-Ultra"
+            manager="SukiSU-Ultra Manager"
+            ;;
           *)
             echo "Unsupported root flavor: $flavor" >&2
             exit 2
@@ -46,7 +51,7 @@ runs:
           exit 2
         fi
 
-        for candidate in KernelSU KernelSU-Next ReSukiSU; do
+        for candidate in KernelSU KernelSU-Next ReSukiSU SukiSU-Ultra; do
           if [ "$candidate" != "$directory" ] && [ -e "$candidate" ]; then
             echo "Refusing mixed root implementations: found $candidate." >&2
             exit 1

+ 1 - 1
.github/actions/susfs/action.yml

@@ -21,7 +21,7 @@ inputs:
     description: 'Kernel sublevel'
     required: true
   root_flavor:
-    description: 'Selected root implementation (kernelsu / next / resukisu). KernelSU (tiann main) needs the 10_enable_susfs_for_ksu patch; other flavors already ship SUSFS.'
+    description: 'Selected root implementation (kernelsu / next / resukisu / sukisu-ultra). KernelSU (tiann main) needs the 10_enable_susfs_for_ksu patch; other flavors already ship SUSFS.'
     required: false
     default: ""
 

+ 1 - 0
.github/scripts/update_verified_pins.py

@@ -23,6 +23,7 @@ PINS = [
     ("PIN_NOMOUNT", "NOMOUNT_SHA", "APPROVE_NOMOUNT"),
     ("PIN_KERNELSU", "KERNELSU_SHA", "APPROVE_KERNELSU"),
     ("PIN_RESUKISU", "RESUKISU_SHA", "APPROVE_RESUKISU"),
+    ("PIN_SUKISU_ULTRA", "SUKISU_ULTRA_SHA", "APPROVE_SUKISU_ULTRA"),
     # SUSFS is intentionally excluded: it is always resolved at latest so it
     # stays API-matched to the always-latest KernelSU-Next tree.
 ]

+ 16 - 4
.github/workflows/build.yml

@@ -171,12 +171,23 @@ jobs:
         os_patch_level: ${{ inputs.os_patch_level }}
 
     - name: Setup Selected Root Implementation
-      if: inputs.root_flavor != ''
+      if: inputs.root_flavor != '' && inputs.root_flavor != 'none'
       uses: ./.github/actions/root-setup
       with:
         flavor: ${{ inputs.root_flavor }}
         commit: ${{ inputs.root_commit }}
 
+    - name: Mark No Root build metadata
+      if: inputs.root_flavor == 'none'
+      shell: bash
+      run: |
+        {
+          echo "ROOT_IMPLEMENTATION=none"
+          echo "ROOT_MANAGER=N/A"
+          echo "ROOT_VERSION=N/A"
+          echo "ROOT_COMMIT=N/A"
+        } >> "$GITHUB_ENV"
+
     - name: Disable SUSFS for ReSukiSU without SUSFS feature
       if: inputs.root_flavor == 'resukisu' && !contains(inputs.feature_set, 'SUSFS')
       uses: ./.github/actions/set-kernel-config
@@ -191,7 +202,8 @@ jobs:
         set -euo pipefail
         # KernelSU-Next (next) always uses the latest susfs4ksu gki branch tip so
         # SUSFS stays API-matched to the always-latest KernelSU-Next tree. All
-        # other roots (kernelsu, resukisu) use the pinned verified SUSFS commit.
+        # other roots (kernelsu, resukisu, sukisu-ultra) use the pinned
+        # verified SUSFS commit.
         if [ "${{ inputs.root_flavor }}" = "next" ]; then
           BRANCH="gki-${{ inputs.android_version }}-${{ inputs.kernel_version }}"
           SUSFS_COMMIT="$(git ls-remote https://gitlab.com/simonpunk/susfs4ksu.git "refs/heads/${BRANCH}" | cut -f1)"
@@ -227,7 +239,7 @@ jobs:
             #   if (func) / if (func != NULL) both trigger -Werror:
             #     -Wpointer-bool-conversion  vs  -Wtautological-pointer-compare
             # For the function form,  &func != NULL  silences both (clang note).
-            # For the pointer form (resukisu/next, no 10_enable) we want ptr != NULL.
+            # For the pointer form (resukisu/next/sukisu-ultra, no 10_enable) we want ptr != NULL.
             if grep -q "extern void security_dump_masked_av_fn" "$f"; then
               echo "[*] $f is extern-function form (10_enable applied), patching with &"
               sed -i 's/if (security_dump_masked_av_fn)/if (\&security_dump_masked_av_fn)/g' "$f"
@@ -621,7 +633,7 @@ jobs:
         compression-level: 9
 
     - name: Write Build-verified only artifact metadata
-      if: success() && inputs.root_flavor != ''
+      if: success() && inputs.root_flavor != '' && inputs.root_flavor != 'none'
       shell: bash
       env:
         GH_TOKEN: ${{ github.token }}

+ 61 - 16
.github/workflows/main.yml

@@ -61,6 +61,8 @@ on:
           - KernelSU-Next
           - KernelSU
           - ReSukiSU
+          - SukiSU-Ultra
+          - No Root
           - All
         default: All
       use_susfs:
@@ -134,6 +136,7 @@ jobs:
       susfs_commit_android16_6_12_resukisu: ${{ steps.resolve.outputs.susfs_commit_android16_6_12_resukisu }}
       ksu_commit: ${{ steps.resolve.outputs.ksu_commit }}
       resukisu_commit: ${{ steps.resolve.outputs.resukisu_commit }}
+      sukisu_ultra_commit: ${{ steps.resolve.outputs.sukisu_ultra_commit }}
       kernel_patches_commit: ${{ steps.resolve.outputs.kernel_patches_commit }}
       anykernel3_commit: ${{ steps.resolve.outputs.anykernel3_commit }}
       droidspaces_commit: ${{ steps.resolve.outputs.droidspaces_commit }}
@@ -179,6 +182,7 @@ jobs:
           PIN_NOMOUNT="d0f57d5c37ff02aae2299daded57919153240cb3"
           PIN_KERNELSU="3c1240625655978f319a98398031100b80e9da7c"
           PIN_RESUKISU="3c1882886dbbb54f4aae7ddf205f8ccde32c2a34"
+          PIN_SUKISU_ULTRA="e2912817f4e1b194e582a06e0b5eacf6a3fb7083"
           declare -A PIN_SUSFS=(
             [susfs_commit_android12_5_10]="ec785f47d49f7b3871ca9356f450411020af7017"
             [susfs_commit_android13_5_10]="ed3d6d9c9a2652e1c70f153f5358701e996d646c"
@@ -219,16 +223,20 @@ jobs:
           echo "kernelsu_branch=dev" >> "$GITHUB_OUTPUT"
 
           # Selected root implementation(s). Maps the human-facing choice
-          # (KernelSU-Next / KernelSU / ReSukiSU / All) to internal root-setup
-          # flavors (next / kernelsu / resukisu). Every build always has a root;
-          # 'All' emits a matrix of all three root flavors plus each pinned commit.
+          # (KernelSU-Next / KernelSU / ReSukiSU / SukiSU-Ultra / No Root / All)
+          # to internal root-setup flavors (next / kernelsu / resukisu /
+          # sukisu-ultra / none). 'All' emits a matrix of the three core root
+          # flavors plus each pinned commit; SukiSU-Ultra and No Root are
+          # opt-in only and never part of 'All'.
           #
-          # kernelsu and resukisu pin in verified mode; KernelSU-Next (next) always
-          # builds at latest.
+          # kernelsu, resukisu, and sukisu-ultra pin in verified mode;
+          # KernelSU-Next (next) always builds at latest.
           KERNELSU_COMMIT="$(pick "$PIN_KERNELSU" https://github.com/tiann/KernelSU.git refs/heads/main)"
           RESUKISU_COMMIT="$(pick "$PIN_RESUKISU" https://github.com/ReSukiSU/ReSukiSU.git refs/heads/main)"
+          SUKISU_ULTRA_COMMIT="$(pick "$PIN_SUKISU_ULTRA" https://github.com/SukiSU-Ultra/SukiSU-Ultra.git refs/heads/builtin)"
           emit ksu_commit "$KERNELSU_COMMIT"
           emit resukisu_commit "$RESUKISU_COMMIT"
+          emit sukisu_ultra_commit "$SUKISU_ULTRA_COMMIT"
           if [ "${{ inputs.use_susfs }}" = "true" ]; then
             NEXT_COMMIT="$(resolve_sha https://github.com/pershoot/KernelSU-Next.git refs/heads/dev-susfs)"
           else
@@ -255,6 +263,16 @@ jobs:
               emit root_commit "$RESUKISU_COMMIT"
               ROOT_MATRIX="[$(mk_entry resukisu ReSukiSU "$RESUKISU_COMMIT")]"
               ;;
+            SukiSU-Ultra)
+              echo "root_flavor=sukisu-ultra" >> "$GITHUB_OUTPUT"
+              emit root_commit "$SUKISU_ULTRA_COMMIT"
+              ROOT_MATRIX="[$(mk_entry sukisu-ultra SukiSU-Ultra "$SUKISU_ULTRA_COMMIT")]"
+              ;;
+            "No Root")
+              echo "root_flavor=none" >> "$GITHUB_OUTPUT"
+              echo "root_commit=" >> "$GITHUB_OUTPUT"
+              ROOT_MATRIX='[{"root_flavor":"none","variant":"NoRoot","root_commit":""}]'
+              ;;
             All)
               # Fan out to all three root variants, each with its pinned commit.
               ROOT_MATRIX="[$(mk_entry next KernelSU-Next "$NEXT_COMMIT"),$(mk_entry kernelsu KernelSU "$KERNELSU_COMMIT"),$(mk_entry resukisu ReSukiSU "$RESUKISU_COMMIT")]"
@@ -302,8 +320,9 @@ jobs:
 
           # Each selected root must ship ALL manager APK builds. KernelSU-Next publishes
           # its manager APKs (manager + manager-spoofed) from the official dev-tip
-          # build-manager-ci run; kernelsu (KernelSU) and ReSukiSU expose theirs as
-          # CI-run artifacts. All three are pinned to an exact commit.
+          # build-manager-ci run; kernelsu (KernelSU), ReSukiSU, and SukiSU-Ultra
+          # expose theirs as CI-run artifacts. All are pinned to an exact commit.
+          # No Root ships no manager.
           resolve_one() { # flavor
             local flavor="$1"
             local owner repo wf stock
@@ -371,6 +390,26 @@ jobs:
                 printf '{"flavor":"%s","owner":"%s","repo":"%s","source":"run","run_id":%s,"stock":"%s","want":"Manager-release,Spoofed-Manager-release"}' \
                   "$flavor" "$owner" "$repo" "$run_id" "$stock"
                 ;;
+              sukisu-ultra)
+                owner="SukiSU-Ultra"; repo="SukiSU-Ultra"; wf="build-manager.yml"
+                stock=$(git ls-remote https://github.com/SukiSU-Ultra/SukiSU-Ultra.git refs/heads/main | awk '{print $1; exit}')
+                run_id=$(curl -fsSL --retry 5 --retry-delay 5 --retry-all-errors \
+                  "https://api.github.com/repos/${owner}/${repo}/actions/workflows/${wf}/runs?head_sha=${stock}" \
+                  | jq -r '.workflow_runs[0].id // empty')
+                if [[ -z "${run_id}" ]]; then
+                  echo "No manager build for stock ${stock}, falling back to latest successful run" >&2
+                  fb=$(curl -fsSL --retry 5 --retry-delay 5 --retry-all-errors "https://api.github.com/repos/${owner}/${repo}/actions/workflows/${wf}/runs?branch=main&status=success&per_page=1")
+                  run_id=$(echo "$fb" | jq -r '.workflow_runs[0].id // empty')
+                  stock=$(echo "$fb" | jq -r '.workflow_runs[0].head_sha // empty')
+                  if [[ -n "$run_id" ]]; then echo "Fallback to ${stock} run ${run_id}" >&2; fi
+                  if [[ -z "${run_id}" ]]; then
+                    echo "ERROR: no ${repo} manager build exists for stock commit ${stock}" >&2
+                    exit 1
+                  fi
+                fi
+                printf '{"flavor":"%s","owner":"%s","repo":"%s","source":"run","run_id":%s,"stock":"%s","want":"Manager,Spoofed-Manager"}' \
+                  "$flavor" "$owner" "$repo" "$run_id" "$stock"
+                ;;
               *)
                 echo "skipping unknown flavor: $flavor" >&2
                 return 0
@@ -386,6 +425,7 @@ jobs:
             KernelSU-Next) LIST=$(jq -c -n '[inputs]' <<< "$(resolve_one next)") ;;
             KernelSU) LIST=$(jq -c -n '[inputs]' <<< "$(resolve_one kernelsu)") ;;
             ReSukiSU) LIST=$(jq -c -n '[inputs]' <<< "$(resolve_one resukisu)") ;;
+            SukiSU-Ultra) LIST=$(jq -c -n '[inputs]' <<< "$(resolve_one sukisu-ultra)") ;;
             *) echo "Skipping manager resolution (no root flavor / none)." ;;
           esac
           if [ -n "$LIST" ]; then
@@ -401,13 +441,14 @@ jobs:
         run: |
           set -euo pipefail
 
-          # Every build always has a root implementation (no 'none' option), so
-          # SUSFS always has a root to hook into -- no extra guard needed.
+          # Root is optional now ('No Root' builds ship no root implementation),
+          # so SUSFS on a No Root build applies kernel-side only.
 
           # A Release/Pre-Release ships whichever manger build(s) were resolved
           # in the manager step above (exact match per root flavor). No root
           # restriction applies here anymore -- KernelSU-Next, KernelSU, ReSukiSU,
-          # or 'All' are all valid release targets.
+          # SukiSU-Ultra, or 'All' are all valid release targets ('No Root'
+          # ships no manager).
 
           FEATURES=""
           [ "${{ inputs.use_susfs }}" = "true" ] && FEATURES="${FEATURES}SUSFS+"
@@ -851,9 +892,11 @@ jobs:
         NOMOUNT_SHA: ${{ needs.resolve-sources.outputs.nomount_commit }}
         KERNELSU_SHA: ${{ needs.resolve-sources.outputs.ksu_commit }}
         RESUKISU_SHA: ${{ needs.resolve-sources.outputs.resukisu_commit }}
+        SUKISU_ULTRA_SHA: ${{ needs.resolve-sources.outputs.sukisu_ultra_commit }}
         APPROVE_NOMOUNT: ${{ inputs.use_nomount }}
         APPROVE_KERNELSU: ${{ (inputs.root_flavor == 'KernelSU' || inputs.root_flavor == 'All') }}
         APPROVE_RESUKISU: ${{ (inputs.root_flavor == 'ReSukiSU' || inputs.root_flavor == 'All') }}
+        APPROVE_SUKISU_ULTRA: ${{ inputs.root_flavor == 'SukiSU-Ultra' }}
 
     - name: Commit promoted pins
       if: always() && steps.promote.conclusion == 'success'
@@ -1425,6 +1468,7 @@ jobs:
           NOMOUNT_COMMIT: ${{ needs.resolve-sources.outputs.nomount_commit }}
           KSU_COMMIT: ${{ needs.resolve-sources.outputs.ksu_commit }}
           RESUKISU_COMMIT: ${{ needs.resolve-sources.outputs.resukisu_commit }}
+          SUKISU_ULTRA_COMMIT: ${{ needs.resolve-sources.outputs.sukisu_ultra_commit }}
           KERNELSU_COMMIT: ${{ needs.resolve-sources.outputs.kernelsu_commit }}
           KERNEL_PATCHES_COMMIT: ${{ needs.resolve-sources.outputs.kernel_patches_commit }}
           ANYKERNEL3_COMMIT: ${{ needs.resolve-sources.outputs.anykernel3_commit }}
@@ -1473,6 +1517,7 @@ jobs:
           ksun_commit=env("KSUN_COMMIT","")
           ksu_commit=env("KSU_COMMIT","")
           resukisu_commit=env("RESUKISU_COMMIT","")
+          sukisu_ultra_commit=env("SUKISU_ULTRA_COMMIT","")
           kernelsu_commit=env("KERNELSU_COMMIT","")
           nm=env("NOMOUNT_COMMIT","")
           kp=env("KERNEL_PATCHES_COMMIT","")
@@ -1485,12 +1530,12 @@ jobs:
               _next_url="https://github.com/pershoot/KernelSU-Next/commit/"
           else:
               _next_url="https://github.com/KernelSU-Next/KernelSU-Next/commit/"
-          _root_urls={"next":_next_url,"kernelsu":"https://github.com/tiann/KernelSU/commit/","resukisu":"https://github.com/ReSukiSU/ReSukiSU/commit/"}
-          _root_commits={"next":_rmatrix.get("next","") or kernelsu_commit,"kernelsu":_rmatrix.get("kernelsu","") or ksu_commit,"resukisu":_rmatrix.get("resukisu","") or resukisu_commit}
+          _root_urls={"next":_next_url,"kernelsu":"https://github.com/tiann/KernelSU/commit/","resukisu":"https://github.com/ReSukiSU/ReSukiSU/commit/","sukisu-ultra":"https://github.com/SukiSU-Ultra/SukiSU-Ultra/commit/"}
+          _root_commits={"next":_rmatrix.get("next","") or kernelsu_commit,"kernelsu":_rmatrix.get("kernelsu","") or ksu_commit,"resukisu":_rmatrix.get("resukisu","") or resukisu_commit,"sukisu-ultra":_rmatrix.get("sukisu-ultra","") or sukisu_ultra_commit}
           _flavors0=[m.get("flavor","") for m in parse_managers(env("MANAGER_LIST","")) if m.get("flavor","")]
           if not _flavors0:
-              _flavors0={"KernelSU-Next":["next"],"KernelSU":["kernelsu"],"ReSukiSU":["resukisu"],"All":["next","kernelsu","resukisu"]}.get(root,["next","kernelsu","resukisu"])
-          _labels0={"next":"KernelSU-Next","kernelsu":"KernelSU","resukisu":"ReSukiSU"}
+              _flavors0={"KernelSU-Next":["next"],"KernelSU":["kernelsu"],"ReSukiSU":["resukisu"],"SukiSU-Ultra":["sukisu-ultra"],"No Root":[],"All":["next","kernelsu","resukisu"]}.get(root,["next","kernelsu","resukisu"])
+          _labels0={"next":"KernelSU-Next","kernelsu":"KernelSU","resukisu":"ReSukiSU","sukisu-ultra":"SukiSU-Ultra"}
           _rc=[]
           for _fl0 in _flavors0:
               _c=_root_commits.get(_fl0,"")
@@ -1528,8 +1573,8 @@ jobs:
           sus_map_resukisu={"android12-5.10":env("SUSFS_ANDROID12_5_10_RESUKISU",""),"android13-5.10":env("SUSFS_ANDROID13_5_10_RESUKISU",""),"android13-5.15":env("SUSFS_ANDROID13_5_15_RESUKISU",""),"android14-5.15":env("SUSFS_ANDROID14_5_15_RESUKISU",""),"android14-6.1":env("SUSFS_ANDROID14_6_1_RESUKISU",""),"android15-6.6":env("SUSFS_ANDROID15_6_6_RESUKISU",""),"android16-6.12":env("SUSFS_ANDROID16_6_12_RESUKISU","")}
           _flavors=[m.get("flavor","") for m in parse_managers(env("MANAGER_LIST","")) if m.get("flavor","")]
           if not _flavors:
-              _flavors={"KernelSU-Next":["next"],"KernelSU":["kernelsu"],"ReSukiSU":["resukisu"],"All":["next","kernelsu","resukisu"]}.get(root,["next","kernelsu","resukisu"])
-          _labels={"next":"KernelSU-Next","kernelsu":"KernelSU","resukisu":"ReSukiSU"}
+              _flavors={"KernelSU-Next":["next"],"KernelSU":["kernelsu"],"ReSukiSU":["resukisu"],"SukiSU-Ultra":["sukisu-ultra"],"No Root":[],"All":["next","kernelsu","resukisu"]}.get(root,["next","kernelsu","resukisu"])
+          _labels={"next":"KernelSU-Next","kernelsu":"KernelSU","resukisu":"ReSukiSU","sukisu-ultra":"SukiSU-Ultra"}
           _susfs_url="https://gitlab.com/simonpunk/susfs4ksu"
           lines.append("| SUSFS branch |" + "".join(f" {_labels.get(_fl,_fl)} |" for _fl in _flavors))
           lines.append("|---" * (len(_flavors) + 1) + "|")

+ 75 - 3
.github/workflows/managers.yml

@@ -15,6 +15,8 @@ on:
           - KernelSU-Next
           - KernelSU
           - ReSukiSU
+          - SukiSU-Ultra
+          - No Root
           - KernelSU-Next-SUSFS
         default: All
       kernelsu_next_commit:
@@ -32,6 +34,11 @@ on:
         required: false
         type: string
         default: ""
+      sukisu_ultra_commit:
+        description: "Pin SukiSU-Ultra manager to this commit (40-char SHA, empty = latest main tip)"
+        required: false
+        type: string
+        default: ""
       kernelsu_next_susfs_commit:
         description: "Pin KernelSU-Next SUSFS (pershoot dev-susfs) manager to this commit (40-char SHA, empty = latest dev-susfs tip)"
         required: false
@@ -64,6 +71,11 @@ on:
         required: false
         type: string
         default: ""
+      sukisu_ultra_commit:
+        description: "Pin SukiSU-Ultra manager commit"
+        required: false
+        type: string
+        default: ""
       kernelsu_next_susfs_commit:
         description: "Pin KernelSU-Next SUSFS manager commit"
         required: false
@@ -92,6 +104,7 @@ jobs:
           INPUT_NEXT_COMMIT: ${{ inputs.kernelsu_next_commit }}
           INPUT_KSU_COMMIT: ${{ inputs.kernelsu_commit }}
           INPUT_RESUKISU_COMMIT: ${{ inputs.resukisu_commit }}
+          INPUT_SUKISU_ULTRA_COMMIT: ${{ inputs.sukisu_ultra_commit }}
           INPUT_NEXT_SUSFS_COMMIT: ${{ inputs.kernelsu_next_susfs_commit }}
         run: |
           set -euo pipefail
@@ -99,8 +112,9 @@ jobs:
           # Exact extraction of main.yml#resolve-managers / manager step.
           # Each selected root must ship ALL manager APK builds. KernelSU-Next publishes
           # its manager APKs (manager + manager-spoofed) from the official dev-tip
-          # build-manager-ci run; kernelsu (KernelSU) and ReSukiSU expose theirs as
-          # CI-run artifacts. All three are pinned to an exact commit.
+          # build-manager-ci run; kernelsu (KernelSU), ReSukiSU, and SukiSU-Ultra
+          # expose theirs as CI-run artifacts. All are pinned to an exact commit.
+          # No Root ships no manager.
 
           retry() {
             local n=0
@@ -261,6 +275,37 @@ jobs:
                   "$flavor" "$owner" "$repo" "$run_id" "$stock"
                 ;;
 
+              sukisu-ultra)
+                owner="SukiSU-Ultra"; repo="SukiSU-Ultra"; wf="build-manager.yml"
+                if [[ -n "${INPUT_SUKISU_ULTRA_COMMIT:-}" ]]; then
+                  stock="$INPUT_SUKISU_ULTRA_COMMIT"
+                  if ! [[ "$stock" =~ ^[0-9a-f]{40}$ ]]; then
+                    echo "ERROR: sukisu_ultra_commit must be a 40-char SHA (got: $stock)" >&2
+                    exit 1
+                  fi
+                else
+                  stock=$(resolve_sha https://github.com/SukiSU-Ultra/SukiSU-Ultra.git refs/heads/main)
+                fi
+                run_id=$(curl -fsSL --retry 5 --retry-delay 5 --retry-all-errors \
+                  "https://api.github.com/repos/${owner}/${repo}/actions/workflows/${wf}/runs?head_sha=${stock}" \
+                  | jq -r '.workflow_runs[0].id // empty')
+                if [[ -z "${run_id}" ]]; then
+                  if [[ -z "${INPUT_SUKISU_ULTRA_COMMIT:-}" ]]; then
+                    echo "No manager build for stock ${stock}, falling back to latest successful run" >&2
+                    fb=$(curl -fsSL --retry 5 --retry-delay 5 --retry-all-errors "https://api.github.com/repos/${owner}/${repo}/actions/workflows/${wf}/runs?branch=main&status=success&per_page=1")
+                    run_id=$(echo "$fb" | jq -r '.workflow_runs[0].id // empty')
+                    stock=$(echo "$fb" | jq -r '.workflow_runs[0].head_sha // empty')
+                    if [[ -n "$run_id" ]]; then echo "Fallback to ${stock} run ${run_id}" >&2; fi
+                  fi
+                  if [[ -z "${run_id}" ]]; then
+                    echo "ERROR: no ${repo} manager build exists for stock commit ${stock}" >&2
+                    exit 1
+                  fi
+                fi
+                printf '{"flavor":"%s","owner":"%s","repo":"%s","source":"run","run_id":%s,"stock":"%s","want":"Manager,Spoofed-Manager"}' \
+                  "$flavor" "$owner" "$repo" "$run_id" "$stock"
+                ;;
+
               *)
                 echo "skipping unknown flavor: $flavor" >&2
                 return 0
@@ -277,6 +322,7 @@ jobs:
             KernelSU-Next-SUSFS) LIST=$(jq -c -n '[inputs]' <<< "$(resolve_one next-susfs)") ;;
             KernelSU) LIST=$(jq -c -n '[inputs]' <<< "$(resolve_one kernelsu)") ;;
             ReSukiSU) LIST=$(jq -c -n '[inputs]' <<< "$(resolve_one resukisu)") ;;
+            SukiSU-Ultra) LIST=$(jq -c -n '[inputs]' <<< "$(resolve_one sukisu-ultra)") ;;
             *) echo "Skipping manager resolution (no root flavor / none)." ;;
           esac
           if [ -n "$LIST" ]; then
@@ -419,6 +465,9 @@ jobs:
           - flavor: resukisu
             repo: https://github.com/ReSukiSU/ReSukiSU.git
             ref: main
+          - flavor: sukisu-ultra
+            repo: https://github.com/SukiSU-Ultra/SukiSU-Ultra.git
+            ref: main
     steps:
       - name: Gate on root_flavor filter
         id: gate
@@ -435,6 +484,7 @@ jobs:
             KernelSU-Next-SUSFS) [[ "$FLAVOR" == "next-susfs" ]] && echo "run=true" >> "$GITHUB_OUTPUT" || echo "run=false" >> "$GITHUB_OUTPUT" ;;
             KernelSU) [[ "$FLAVOR" == "kernelsu" ]] && echo "run=true" >> "$GITHUB_OUTPUT" || echo "run=false" >> "$GITHUB_OUTPUT" ;;
             ReSukiSU) [[ "$FLAVOR" == "resukisu" ]] && echo "run=true" >> "$GITHUB_OUTPUT" || echo "run=false" >> "$GITHUB_OUTPUT" ;;
+            SukiSU-Ultra) [[ "$FLAVOR" == "sukisu-ultra" ]] && echo "run=true" >> "$GITHUB_OUTPUT" || echo "run=false" >> "$GITHUB_OUTPUT" ;;
             *) echo "run=false" >> "$GITHUB_OUTPUT" ;;
           esac
 
@@ -447,6 +497,7 @@ jobs:
           KSU_NEXT_SUSFS_COMMIT: ${{ inputs.kernelsu_next_susfs_commit }}
           KSU_COMMIT: ${{ inputs.kernelsu_commit }}
           RESUKISU_COMMIT: ${{ inputs.resukisu_commit }}
+          SUKISU_ULTRA_COMMIT: ${{ inputs.sukisu_ultra_commit }}
         run: |
           set -euo pipefail
           flavor="${{ matrix.flavor }}"
@@ -455,6 +506,7 @@ jobs:
             next-susfs) pin="$KSU_NEXT_SUSFS_COMMIT" ;;
             kernelsu) pin="$KSU_COMMIT" ;;
             resukisu) pin="$RESUKISU_COMMIT" ;;
+            sukisu-ultra) pin="$SUKISU_ULTRA_COMMIT" ;;
           esac
           if [[ -n "${pin:-}" ]]; then
             echo "sha=$pin" >> "$GITHUB_OUTPUT"
@@ -590,6 +642,9 @@ jobs:
           - flavor: resukisu
             repo: https://github.com/ReSukiSU/ReSukiSU.git
             ref: main
+          - flavor: sukisu-ultra
+            repo: https://github.com/SukiSU-Ultra/SukiSU-Ultra.git
+            ref: main
           - flavor: next-susfs
             repo: https://github.com/pershoot/KernelSU-Next.git
             ref: dev-susfs
@@ -610,6 +665,7 @@ jobs:
             KernelSU-Next-SUSFS) [[ "$FLAVOR" == "next-susfs" ]] && echo "run=true" >> "$GITHUB_OUTPUT" || echo "run=false" >> "$GITHUB_OUTPUT" ;;
             KernelSU) [[ "$FLAVOR" == "kernelsu" ]] && echo "run=true" >> "$GITHUB_OUTPUT" || echo "run=false" >> "$GITHUB_OUTPUT" ;;
             ReSukiSU) [[ "$FLAVOR" == "resukisu" ]] && echo "run=true" >> "$GITHUB_OUTPUT" || echo "run=false" >> "$GITHUB_OUTPUT" ;;
+            SukiSU-Ultra) [[ "$FLAVOR" == "sukisu-ultra" ]] && echo "run=true" >> "$GITHUB_OUTPUT" || echo "run=false" >> "$GITHUB_OUTPUT" ;;
             *) echo "run=false" >> "$GITHUB_OUTPUT" ;;
           esac
           cat "$GITHUB_OUTPUT"
@@ -623,6 +679,7 @@ jobs:
           KSU_NEXT_SUSFS_COMMIT: ${{ inputs.kernelsu_next_susfs_commit }}
           KSU_COMMIT: ${{ inputs.kernelsu_commit }}
           RESUKISU_COMMIT: ${{ inputs.resukisu_commit }}
+          SUKISU_ULTRA_COMMIT: ${{ inputs.sukisu_ultra_commit }}
         run: |
           set -euo pipefail
           flavor="${{ matrix.flavor }}"
@@ -631,6 +688,7 @@ jobs:
             next-susfs) pin="$KSU_NEXT_SUSFS_COMMIT" ;;
             kernelsu) pin="$KSU_COMMIT" ;;
             resukisu) pin="$RESUKISU_COMMIT" ;;
+            sukisu-ultra) pin="$SUKISU_ULTRA_COMMIT" ;;
           esac
           if [[ -n "${pin:-}" ]]; then
             if ! [[ "$pin" =~ ^[0-9a-f]{40}$ ]]; then
@@ -751,6 +809,10 @@ jobs:
           RESUKISU_KEYSTORE_PASSWORD: ${{ secrets.RESUKISU_KEYSTORE_PASSWORD }}
           RESUKISU_KEY_ALIAS: ${{ secrets.RESUKISU_KEY_ALIAS }}
           RESUKISU_KEY_PASSWORD: ${{ secrets.RESUKISU_KEY_PASSWORD }}
+          SUKISU_ULTRA_KEYSTORE: ${{ secrets.SUKISU_ULTRA_KEYSTORE }}
+          SUKISU_ULTRA_KEYSTORE_PASSWORD: ${{ secrets.SUKISU_ULTRA_KEYSTORE_PASSWORD }}
+          SUKISU_ULTRA_KEY_ALIAS: ${{ secrets.SUKISU_ULTRA_KEY_ALIAS }}
+          SUKISU_ULTRA_KEY_PASSWORD: ${{ secrets.SUKISU_ULTRA_KEY_PASSWORD }}
         run: |
           set -euo pipefail
           dir="$SRC_DIR"
@@ -768,6 +830,7 @@ jobs:
               next|next-susfs) b64="${NEXT_KEYSTORE:-}"; pw="${NEXT_KEYSTORE_PASSWORD:-}"; alias="${NEXT_KEY_ALIAS:-}"; kp="${NEXT_KEY_PASSWORD:-}" ;;
               kernelsu) b64="${KERNELSU_KEYSTORE:-}"; pw="${KERNELSU_KEYSTORE_PASSWORD:-}"; alias="${KERNELSU_KEY_ALIAS:-}"; kp="${KERNELSU_KEY_PASSWORD:-}" ;;
               resukisu) b64="${RESUKISU_KEYSTORE:-}"; pw="${RESUKISU_KEYSTORE_PASSWORD:-}"; alias="${RESUKISU_KEY_ALIAS:-}"; kp="${RESUKISU_KEY_PASSWORD:-}" ;;
+              sukisu-ultra) b64="${SUKISU_ULTRA_KEYSTORE:-}"; pw="${SUKISU_ULTRA_KEYSTORE_PASSWORD:-}"; alias="${SUKISU_ULTRA_KEY_ALIAS:-}"; kp="${SUKISU_ULTRA_KEY_PASSWORD:-}" ;;
             esac
             if [ -n "${b64:-}" ] && [ -n "${pw:-}" ] && [ -n "${alias:-}" ]; then
               echo "Using your persistent key for $flavor (alias=$alias)"
@@ -839,6 +902,13 @@ jobs:
               ./randomizer 2>&1 | tail -20 || true
               gradle_build "clean assembleRelease" || true
             fi
+          elif [ "$flavor" = "sukisu-ultra" ]; then
+            # Upstream SukiSU-Ultra: clean assembleRelease, spoofed via randomizer
+            gradle_build "clean assembleRelease" || true
+            if [ -x ./randomizer ]; then
+              ./randomizer 2>&1 | tail -20 || true
+              gradle_build "clean assembleRelease" || true
+            fi
           fi
           # Collect (only release variants for resukisu)
           out="/tmp/manager_apks_${flavor}"
@@ -984,6 +1054,7 @@ jobs:
           NEXT_COMMIT: ${{ inputs.kernelsu_next_commit }}
           KSU_COMMIT: ${{ inputs.kernelsu_commit }}
           RESUKISU_COMMIT: ${{ inputs.resukisu_commit }}
+          SUKISU_ULTRA_COMMIT: ${{ inputs.sukisu_ultra_commit }}
           NEXT_SUSFS_COMMIT: ${{ inputs.kernelsu_next_susfs_commit }}
           MANAGER_LIST_FETCH: ${{ needs.resolve-managers.outputs.manager_list }}
         run: |
@@ -998,6 +1069,7 @@ jobs:
               "KernelSU-Next": env("NEXT_COMMIT") or "latest dev tip",
               "KernelSU": env("KSU_COMMIT") or "latest main tip",
               "ReSukiSU": env("RESUKISU_COMMIT") or "latest tip",
+              "SukiSU-Ultra": env("SUKISU_ULTRA_COMMIT") or "latest tip",
               "KernelSU-Next-SUSFS": env("NEXT_SUSFS_COMMIT") or "latest dev-susfs tip",
           }
           # enrich from fetch path manager_list (pure commit info, same style as prebuilt)
@@ -1005,7 +1077,7 @@ jobs:
           if raw:
               try:
                   for m in json.loads(raw):
-                      label = {"next":"KernelSU-Next","kernelsu":"KernelSU","resukisu":"ReSukiSU","next-susfs":"KernelSU-Next-SUSFS"}.get(m.get("flavor",""), "")
+                      label = {"next":"KernelSU-Next","kernelsu":"KernelSU","resukisu":"ReSukiSU","sukisu-ultra":"SukiSU-Ultra","next-susfs":"KernelSU-Next-SUSFS"}.get(m.get("flavor",""), "")
                       if label and m.get("stock"):
                           commits[label] = m["stock"]
               except: pass

+ 1 - 1
.github/workflows/prepare.yml

@@ -22,7 +22,7 @@ on:
         type: string
         default: ""
       root_flavor:
-        description: "Mutually exclusive root implementation (kernelsu, next, or resukisu)"
+        description: "Mutually exclusive root implementation (kernelsu, next, resukisu, sukisu-ultra, or none)"
         required: false
         type: string
         default: ""

+ 1 - 0
THIRD_PARTY_NOTICES.md

@@ -9,6 +9,7 @@
 | KernelSU | [tiann/KernelSU](https://github.com/tiann/KernelSU) | GPL-3.0 |
 | KernelSU-Next | [KernelSU-Next/KernelSU-Next](https://github.com/KernelSU-Next/KernelSU-Next) | GPL-3.0 |
 | ReSukiSU | [ReSukiSU/ReSukiSU](https://github.com/ReSukiSU/ReSukiSU) | GPL-3.0 |
+| SukiSU-Ultra | [SukiSU-Ultra/SukiSU-Ultra](https://github.com/SukiSU-Ultra/SukiSU-Ultra) | GPL-3.0 |
 | KSU-Next SUSFS | [pershoot/KernelSU-Next](https://github.com/pershoot/KernelSU-Next) | GPL-3.0 |
 | susfs4ksu | [simonpunk/susfs4ksu](https://gitlab.com/simonpunk/susfs4ksu) | GPL-3.0+ |
 | NoMount | [maxsteeel/nomount](https://github.com/maxsteeel/nomount) | GPL-3.0 |

+ 2 - 2
docs/build-from-fork.md

@@ -74,11 +74,11 @@ Recommended settings for a first build:
 | OS patch level | One unique date or `lts` | Selects one matrix row. A numeric sublevel can match multiple dates. |
 | Kernel Branding | Your short brand name | Changes the kernel's local version string. |
 | Commit mode | `verified` | Uses the project's verified component pins where pins are supported. |
-| Root Flavor | One implementation | Produces one kernel instead of KernelSU-Next, KernelSU, and ReSukiSU builds. |
+| Root Flavor | One implementation | Produces one kernel instead of KernelSU-Next, KernelSU, and ReSukiSU builds. `SukiSU-Ultra` and `No Root` are opt-in only and are not part of `All`. |
 | Feature toggles | Keep the defaults initially | Establishes a known baseline before customizing features. |
 | Test release notes | `false` | `true` skips the kernel builds and only previews release notes. |
 
-There is no rootless build option. Choose one of `KernelSU-Next`, `KernelSU`, or `ReSukiSU`. Install the matching manager after flashing; see [Post-install Setup](post-install.md).
+Root Flavor choices are `KernelSU-Next`, `KernelSU`, `ReSukiSU`, `SukiSU-Ultra`, `No Root`, or `All`. `All` builds only KernelSU-Next, KernelSU, and ReSukiSU. `No Root` produces a kernel with no root implementation (and no manager APK). Install the matching manager after flashing a rooted build; see [Post-install Setup](post-install.md).
 
 ### Example: Current Android 15 / Linux 6.6 LTS