Преглед на файлове

Add KowSU root flavor (KOWX712/KernelSU master), incompatible with SUSFS

TheWildJames преди 3 дни
родител
ревизия
9974038865
променени са 6 файла, в които са добавени 113 реда и са изтрити 23 реда
  1. 7 2
      .github/actions/root-setup/action.yml
  2. 7 0
      .github/workflows/build.yml
  3. 54 15
      .github/workflows/main.yml
  4. 42 4
      .github/workflows/managers.yml
  5. 1 0
      THIRD_PARTY_NOTICES.md
  6. 2 2
      docs/build-from-fork.md

+ 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, resukisu, or sukisu-ultra'
+    description: 'kernelsu, next, resukisu, sukisu-ultra, or kowsu'
     required: true
   commit:
     description: 'Full immutable commit SHA'
@@ -40,6 +40,11 @@ runs:
             directory="SukiSU-Ultra"
             manager="SukiSU-Ultra Manager"
             ;;
+          kowsu)
+            repo="https://github.com/KOWX712/KernelSU.git"
+            directory="KowSU"
+            manager="KowSU Manager"
+            ;;
           *)
             echo "Unsupported root flavor: $flavor" >&2
             exit 2
@@ -51,7 +56,7 @@ runs:
           exit 2
         fi
 
-        for candidate in KernelSU KernelSU-Next ReSukiSU SukiSU-Ultra; do
+        for candidate in KernelSU KernelSU-Next ReSukiSU SukiSU-Ultra KowSU; do
           if [ "$candidate" != "$directory" ] && [ -e "$candidate" ]; then
             echo "Refusing mixed root implementations: found $candidate." >&2
             exit 1

+ 7 - 0
.github/workflows/build.yml

@@ -170,6 +170,13 @@ jobs:
         sublevel: ${{ steps.extract.outputs.sublevel }}
         os_patch_level: ${{ inputs.os_patch_level }}
 
+    - name: Reject KowSU with SUSFS
+      if: inputs.root_flavor == 'kowsu' && (contains(inputs.feature_set, 'SUSFS') || inputs.feature_set == 'All')
+      shell: bash
+      run: |
+        echo "ERROR: KowSU does not work together with SUSFS — re-run with SUSFS off." >&2
+        exit 1
+
     - name: Setup Selected Root Implementation
       if: inputs.root_flavor != '' && inputs.root_flavor != 'none'
       uses: ./.github/actions/root-setup

+ 54 - 15
.github/workflows/main.yml

@@ -62,6 +62,7 @@ on:
           - KernelSU
           - ReSukiSU
           - SukiSU-Ultra
+          - KowSU
           - No Root
           - All
         default: All
@@ -144,6 +145,7 @@ jobs:
       ksu_commit: ${{ steps.resolve.outputs.ksu_commit }}
       resukisu_commit: ${{ steps.resolve.outputs.resukisu_commit }}
       sukisu_ultra_commit: ${{ steps.resolve.outputs.sukisu_ultra_commit }}
+      kowsu_commit: ${{ steps.resolve.outputs.kowsu_commit }}
       kernel_patches_commit: ${{ steps.resolve.outputs.kernel_patches_commit }}
       anykernel3_commit: ${{ steps.resolve.outputs.anykernel3_commit }}
       droidspaces_commit: ${{ steps.resolve.outputs.droidspaces_commit }}
@@ -240,11 +242,11 @@ jobs:
           echo "kernelsu_branch=dev" >> "$GITHUB_OUTPUT"
 
           # Selected root implementation(s). Maps the human-facing choice
-          # (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-Next / KernelSU / ReSukiSU / SukiSU-Ultra / KowSU /
+          # No Root / All) to internal root-setup flavors (next / kernelsu /
+          # resukisu / sukisu-ultra / kowsu / none). 'All' emits a matrix of
+          # the three core root flavors plus each pinned commit; SukiSU-Ultra,
+          # KowSU, and No Root are opt-in only and never part of 'All'.
           #
           # kernelsu, resukisu, and sukisu-ultra pin in verified mode;
           # KernelSU-Next (next) always builds at latest.
@@ -262,6 +264,10 @@ jobs:
           emit ksu_commit "$KERNELSU_COMMIT"
           emit resukisu_commit "$RESUKISU_COMMIT"
           emit sukisu_ultra_commit "$SUKISU_ULTRA_COMMIT"
+          # KowSU has no SUSFS support, so it always tracks latest on master
+          # (it can only ever run with SUSFS off — enforced below).
+          KOWSU_COMMIT="$(resolve_sha https://github.com/KOWX712/KernelSU.git refs/heads/master)"
+          emit kowsu_commit "$KOWSU_COMMIT"
           if [ "${{ inputs.use_susfs }}" = "true" ]; then
             NEXT_COMMIT="$(resolve_sha https://github.com/pershoot/KernelSU-Next.git refs/heads/dev-susfs)"
           else
@@ -293,6 +299,15 @@ jobs:
               emit root_commit "$SUKISU_ULTRA_COMMIT"
               ROOT_MATRIX="[$(mk_entry sukisu-ultra SukiSU-Ultra "$SUKISU_ULTRA_COMMIT")]"
               ;;
+            KowSU)
+              if [ "${{ inputs.use_susfs }}" = "true" ]; then
+                echo "ERROR: KowSU does not work together with SUSFS — re-run with SUSFS off." >&2
+                exit 1
+              fi
+              echo "root_flavor=kowsu" >> "$GITHUB_OUTPUT"
+              emit root_commit "$KOWSU_COMMIT"
+              ROOT_MATRIX="[$(mk_entry kowsu KowSU "$KOWSU_COMMIT")]"
+              ;;
             "No Root")
               echo "root_flavor=none" >> "$GITHUB_OUTPUT"
               echo "root_commit=" >> "$GITHUB_OUTPUT"
@@ -347,8 +362,8 @@ 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), ReSukiSU, and SukiSU-Ultra
-          # expose theirs as CI-run artifacts. All are pinned to an exact commit.
+          # build-manager-ci run; kernelsu (KernelSU), ReSukiSU, SukiSU-Ultra,
+          # and KowSU expose theirs as CI-run artifacts. All are pinned to an exact commit.
           # No Root ships no manager.
           resolve_one() { # flavor
             local flavor="$1"
@@ -437,6 +452,26 @@ jobs:
                 printf '{"flavor":"%s","owner":"%s","repo":"%s","source":"run","run_id":%s,"stock":"%s","want":"Manager,Spoofed-Manager"}' \
                   "$flavor" "$owner" "$repo" "$run_id" "$stock"
                 ;;
+              kowsu)
+                owner="KOWX712"; repo="KernelSU"; wf="build-manager.yml"
+                stock=$(git ls-remote https://github.com/KOWX712/KernelSU.git refs/heads/master | 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=master&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"}' \
+                  "$flavor" "$owner" "$repo" "$run_id" "$stock"
+                ;;
               *)
                 echo "skipping unknown flavor: $flavor" >&2
                 return 0
@@ -453,6 +488,7 @@ jobs:
             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)") ;;
+            KowSU) LIST=$(jq -c -n '[inputs]' <<< "$(resolve_one kowsu)") ;;
             *) echo "Skipping manager resolution (no root flavor / none)." ;;
           esac
           if [ -n "$LIST" ]; then
@@ -474,7 +510,7 @@ jobs:
           # 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,
-          # SukiSU-Ultra, or 'All' are all valid release targets ('No Root'
+          # SukiSU-Ultra, KowSU, or 'All' are all valid release targets ('No Root'
           # ships no manager).
 
           FEATURES=""
@@ -1496,6 +1532,7 @@ jobs:
           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 }}
+          KOWSU_COMMIT: ${{ needs.resolve-sources.outputs.kowsu_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 }}
@@ -1552,6 +1589,7 @@ jobs:
           ksu_commit=env("KSU_COMMIT","")
           resukisu_commit=env("RESUKISU_COMMIT","")
           sukisu_ultra_commit=env("SUKISU_ULTRA_COMMIT","")
+          kowsu_commit=env("KOWSU_COMMIT","")
           kernelsu_commit=env("KERNELSU_COMMIT","")
           nm=env("NOMOUNT_COMMIT","")
           kp=env("KERNEL_PATCHES_COMMIT","")
@@ -1564,12 +1602,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/","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}
+          _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/","kowsu":"https://github.com/KOWX712/KernelSU/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,"kowsu":_rmatrix.get("kowsu","") or kowsu_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"],"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"}
+              _flavors0={"KernelSU-Next":["next"],"KernelSU":["kernelsu"],"ReSukiSU":["resukisu"],"SukiSU-Ultra":["sukisu-ultra"],"KowSU":["kowsu"],"No Root":[],"All":["next","kernelsu","resukisu"]}.get(root,["next","kernelsu","resukisu"])
+          _labels0={"next":"KernelSU-Next","kernelsu":"KernelSU","resukisu":"ReSukiSU","sukisu-ultra":"SukiSU-Ultra","kowsu":"KowSU"}
           _rc=[]
           for _fl0 in _flavors0:
               _c=_root_commits.get(_fl0,"")
@@ -1608,15 +1646,16 @@ jobs:
           sus_map_sukisu_ultra={"android12-5.10":env("SUSFS_ANDROID12_5_10_SUKISU_ULTRA",""),"android13-5.10":env("SUSFS_ANDROID13_5_10_SUKISU_ULTRA",""),"android13-5.15":env("SUSFS_ANDROID13_5_15_SUKISU_ULTRA",""),"android14-5.15":env("SUSFS_ANDROID14_5_15_SUKISU_ULTRA",""),"android14-6.1":env("SUSFS_ANDROID14_6_1_SUKISU_ULTRA",""),"android15-6.6":env("SUSFS_ANDROID15_6_6_SUKISU_ULTRA",""),"android16-6.12":env("SUSFS_ANDROID16_6_12_SUKISU_ULTRA","")}
           _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"],"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"}
+              _flavors={"KernelSU-Next":["next"],"KernelSU":["kernelsu"],"ReSukiSU":["resukisu"],"SukiSU-Ultra":["sukisu-ultra"],"KowSU":["kowsu"],"No Root":[],"All":["next","kernelsu","resukisu"]}.get(root,["next","kernelsu","resukisu"])
+          _labels={"next":"KernelSU-Next","kernelsu":"KernelSU","resukisu":"ReSukiSU","sukisu-ultra":"SukiSU-Ultra","kowsu":"KowSU"}
           _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) + "|")
           for v in variants:
               _row=f"| gki-{v} |"
               for _fl in _flavors:
-                  _sm=sus_map_sukisu_ultra if _fl=="sukisu-ultra" else (sus_map_resukisu if _fl=="resukisu" else sus_map)
+                  # KowSU never ships SUSFS: render n/a rather than shared pins.
+                  _sm={} if _fl=="kowsu" else (sus_map_sukisu_ultra if _fl=="sukisu-ultra" else (sus_map_resukisu if _fl=="resukisu" else sus_map))
                   sha=_sm.get(v,"")
                   sha_s=f"[`{sha[:7]}`]({_susfs_url}/-/commit/{sha})" if sha else "_n/a_"
                   _row+=f" {sha_s} |"

+ 42 - 4
.github/workflows/managers.yml

@@ -16,6 +16,7 @@ on:
           - KernelSU
           - ReSukiSU
           - SukiSU-Ultra
+          - KowSU
           - No Root
           - KernelSU-Next-SUSFS
         default: All
@@ -112,8 +113,8 @@ 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), ReSukiSU, and SukiSU-Ultra
-          # expose theirs as CI-run artifacts. All are pinned to an exact commit.
+          # build-manager-ci run; kernelsu (KernelSU), ReSukiSU, SukiSU-Ultra,
+          # and KowSU expose theirs as CI-run artifacts. All are pinned to an exact commit.
           # No Root ships no manager.
 
           retry() {
@@ -306,6 +307,28 @@ jobs:
                   "$flavor" "$owner" "$repo" "$run_id" "$stock"
                 ;;
 
+              kowsu)
+                # KowSU has no SUSFS support and always tracks latest master.
+                owner="KOWX712"; repo="KernelSU"; wf="build-manager.yml"
+                stock=$(resolve_sha https://github.com/KOWX712/KernelSU.git refs/heads/master)
+                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=master&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"}' \
+                  "$flavor" "$owner" "$repo" "$run_id" "$stock"
+                ;;
+
               *)
                 echo "skipping unknown flavor: $flavor" >&2
                 return 0
@@ -323,6 +346,7 @@ jobs:
             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)") ;;
+            KowSU) LIST=$(jq -c -n '[inputs]' <<< "$(resolve_one kowsu)") ;;
             *) echo "Skipping manager resolution (no root flavor / none)." ;;
           esac
           if [ -n "$LIST" ]; then
@@ -468,6 +492,9 @@ jobs:
           - flavor: sukisu-ultra
             repo: https://github.com/SukiSU-Ultra/SukiSU-Ultra.git
             ref: main
+          - flavor: kowsu
+            repo: https://github.com/KOWX712/KernelSU.git
+            ref: master
     steps:
       - name: Gate on root_flavor filter
         id: gate
@@ -485,6 +512,7 @@ jobs:
             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" ;;
+            KowSU) [[ "$FLAVOR" == "kowsu" ]] && echo "run=true" >> "$GITHUB_OUTPUT" || echo "run=false" >> "$GITHUB_OUTPUT" ;;
             *) echo "run=false" >> "$GITHUB_OUTPUT" ;;
           esac
 
@@ -507,6 +535,7 @@ jobs:
             kernelsu) pin="$KSU_COMMIT" ;;
             resukisu) pin="$RESUKISU_COMMIT" ;;
             sukisu-ultra) pin="$SUKISU_ULTRA_COMMIT" ;;
+            kowsu) pin="" ;;
           esac
           if [[ -n "${pin:-}" ]]; then
             echo "sha=$pin" >> "$GITHUB_OUTPUT"
@@ -645,6 +674,9 @@ jobs:
           - flavor: sukisu-ultra
             repo: https://github.com/SukiSU-Ultra/SukiSU-Ultra.git
             ref: main
+          - flavor: kowsu
+            repo: https://github.com/KOWX712/KernelSU.git
+            ref: master
           - flavor: next-susfs
             repo: https://github.com/pershoot/KernelSU-Next.git
             ref: dev-susfs
@@ -666,6 +698,7 @@ jobs:
             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" ;;
+            KowSU) [[ "$FLAVOR" == "kowsu" ]] && echo "run=true" >> "$GITHUB_OUTPUT" || echo "run=false" >> "$GITHUB_OUTPUT" ;;
             *) echo "run=false" >> "$GITHUB_OUTPUT" ;;
           esac
           cat "$GITHUB_OUTPUT"
@@ -689,6 +722,7 @@ jobs:
             kernelsu) pin="$KSU_COMMIT" ;;
             resukisu) pin="$RESUKISU_COMMIT" ;;
             sukisu-ultra) pin="$SUKISU_ULTRA_COMMIT" ;;
+            kowsu) pin="" ;;
           esac
           if [[ -n "${pin:-}" ]]; then
             if ! [[ "$pin" =~ ^[0-9a-f]{40}$ ]]; then
@@ -894,6 +928,9 @@ jobs:
           elif [ "$flavor" = "kernelsu" ]; then
             # Upstream tiann: ./gradlew clean assembleRelease (repack is separate job — we just build manager here)
             gradle_build "clean assembleRelease" || gradle_build "assembleRelease" || true
+          elif [ "$flavor" = "kowsu" ]; then
+            # Upstream KowSU is tiann-style: clean assembleRelease
+            gradle_build "clean assembleRelease" || gradle_build "assembleRelease" || true
           elif [ "$flavor" = "resukisu" ]; then
             # Upstream ReSukiSU: assembleRelease + randomizer (only universal variants)
             gradle_build "clean assembleRelease" || true
@@ -1070,6 +1107,7 @@ jobs:
               "KernelSU": env("KSU_COMMIT") or "latest main tip",
               "ReSukiSU": env("RESUKISU_COMMIT") or "latest tip",
               "SukiSU-Ultra": env("SUKISU_ULTRA_COMMIT") or "latest tip",
+              "KowSU": "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)
@@ -1077,7 +1115,7 @@ jobs:
           if raw:
               try:
                   for m in json.loads(raw):
-                      label = {"next":"KernelSU-Next","kernelsu":"KernelSU","resukisu":"ReSukiSU","sukisu-ultra":"SukiSU-Ultra","next-susfs":"KernelSU-Next-SUSFS"}.get(m.get("flavor",""), "")
+                      label = {"next":"KernelSU-Next","kernelsu":"KernelSU","resukisu":"ReSukiSU","sukisu-ultra":"SukiSU-Ultra","kowsu":"KowSU","next-susfs":"KernelSU-Next-SUSFS"}.get(m.get("flavor",""), "")
                       if label and m.get("stock"):
                           commits[label] = m["stock"]
               except: pass
@@ -1087,7 +1125,7 @@ jobs:
           lines.append("## Features")
           lines.append("")
           if root == "All":
-              lines.append("- All manager flavors (KernelSU-Next, KernelSU, ReSukiSU, KernelSU-Next-SUSFS)")
+              lines.append("- All manager flavors (KernelSU-Next, KernelSU, ReSukiSU, SukiSU-Ultra, KernelSU-Next-SUSFS)")
           else:
               lines.append(f"- {root}")
           lines.append(f"- {'Built from source' if src else 'Fetched prebuilt (upstream CI)'}")

+ 1 - 0
THIRD_PARTY_NOTICES.md

@@ -10,6 +10,7 @@
 | 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 |
+| KowSU | [KOWX712/KernelSU](https://github.com/KOWX712/KernelSU) | 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. `SukiSU-Ultra` and `No Root` are opt-in only and are not part of `All`. |
+| Root Flavor | One implementation | Produces one kernel instead of KernelSU-Next, KernelSU, and ReSukiSU builds. `SukiSU-Ultra`, `KowSU`, and `No Root` are opt-in only and are not part of `All`. `KowSU` cannot be combined with SUSFS. |
 | 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. |
 
-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).
+Root Flavor choices are `KernelSU-Next`, `KernelSU`, `ReSukiSU`, `SukiSU-Ultra`, `KowSU`, `No Root`, or `All`. `All` builds only KernelSU-Next, KernelSU, and ReSukiSU. `KowSU` always tracks the latest `master` tip and errors out if SUSFS is enabled. `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