Skip to content

OP13 KSUN

OP13 KSUN #47

Workflow file for this run

name: OP13 KSUN
env:
TZ: Asia/Shanghai
ANDROID_VERSION: android15
KERNEL_VERSION: "6.6"
SUB_VERSION: "89"
DEVICE_NAME: OP13
DEVICE_CODENAME: sun
CCTV18_BUILD_REPO: cctv18/oppo_oplus_realme_sm8750
CCTV18_COMMON_REPO: cctv18/android_kernel_common_oneplus_sm8750
CCTV18_TOOLCHAIN_RELEASE: LLVM-Clang18-r510928
CCACHE_DIR: ${{ github.workspace }}/.ccache_op13_ksun_cctv18_v92
CCACHE_MAXSIZE: 8G
on:
workflow_dispatch:
inputs:
profile:
description: "Daily-driver profile. stock_daily is the recommended default."
required: true
type: choice
options:
- stock_daily
- stock_plus
- minimal_safe
- debug_only
default: stock_daily
ksun_ref:
description: "KernelSU-Next ref. For clean CCTV18 KSUN lane keep dev-susfs unless you are testing a known-good commit."
required: true
type: string
default: "dev-susfs"
susfs_enable:
description: "Enable CCTV18 susfs4oki only. No WildKernels/TheWildJames SUSFS patch tree is used."
required: true
type: boolean
default: true
susfs_ref:
description: "CCTV18 susfs4oki branch/ref. OP13 Android 15/16 6.6 should use oki-android15-6.6."
required: true
type: string
default: "oki-android15-6.6"
susfs_patch_policy:
description: "strict fails on any reject; audited_cctv18 allows only the known task_mmu reject; native_cctv18 audits but continues like CCTV18."
required: true
type: choice
options:
- audited_cctv18
- strict
- native_cctv18
default: audited_cctv18
hook_mode:
description: "KernelSU hook/audit mode. cctv18_susfs_auto is recommended for clean KSUN dev-susfs; strict_none_hook_test only passes if the KSUN tree exposes CONFIG_KSU_NONE_HOOK."
required: true
type: choice
options:
- cctv18_susfs_auto
- hybrid_compat
- strict_none_hook_test
default: cctv18_susfs_auto
cctv18_kernel_ref:
description: "CCTV18 OP13 6.6.118 source branch/ref (update this when a new OTA bumps the kernel)."
required: true
type: string
default: "oneplus/sm8750_b_16.0.0_oneplus_13_6.6.118"
kernel_suffix:
description: "Stock-like LOCALVERSION without leading dash (this is the real uname -r). Leave default for current OP13 stock mimic / best app compatibility."
required: true
type: string
default: "android15-8-g93e223c276e7-abogki500782043-4k"
kernel_name:
description: "Display name shown in kernel-manager apps and the flash banner (does NOT change uname -r). Customise this freely, e.g. 'OX13-KSUN'."
required: false
type: string
default: "PJZ110 | KernelSU-Next [StockLike] + CCTV18 SUSFS (OP-OX)"
stock_mimic:
description: "Keep uname -r stock-like by using only the supplied kernel_suffix as LOCALVERSION."
required: true
type: boolean
default: true
optimise:
description: "O2 is the stable daily-driver default. O3 is test-only."
required: true
type: choice
options:
- O2
- O3
default: O2
adios:
description: "Apply CCTV18 ADIOS scheduler patch if it exists and dry-run applies cleanly."
required: true
type: boolean
default: true
baseband_guard:
description: "Apply CCTV18 Baseband Guard patch if it exists and dry-run applies cleanly."
required: true
type: boolean
default: true
better_net:
description: "Enable netfilter/ipset/TTL support for useful advanced networking without making BBR default."
required: true
type: boolean
default: true
bbr_mode:
description: "enabled compiles TCP BBR in (selectable at runtime, not forced default). Recommended for daily use."
required: true
type: choice
options:
- off
- enabled
- default
default: enabled
zram_lz4:
description: "Enable kernel ZRAM + LZ4/LZ4HC/ZSTD support in config. This is config-only, not a random patch mix."
required: true
type: boolean
default: true
zram_comp:
description: "Preferred ZRAM default compressor when kernel config supports CONFIG_ZRAM_DEF_COMP."
required: true
type: choice
options:
- lz4
- lzo-rle
- zstd
default: lz4
ntsync:
description: "Enable NTSYNC config if available."
required: true
type: boolean
default: true
unicode_fix:
description: "Apply CCTV18 Unicode-related patch if present and dry-run applies cleanly."
required: true
type: boolean
default: true
droidspaces:
description: "Enable Droidspaces/container namespace options. Off is safer for normal phone use."
required: true
type: boolean
default: false
rekernel:
description: "Apply Re:Kernel patch when present (best-effort, dry-run gated; skips if it does not apply cleanly)."
required: true
type: boolean
default: true
package_ak3:
description: "Create fixed AnyKernel3 flashable ZIP plus raw Image."
required: true
type: boolean
default: true
clean_ccache:
description: "Delete ccache before building. Use only when you suspect cache contamination."
required: true
type: boolean
default: false
BUILD_TIME:
description: "Custom build time string. Enter F to use current UTC; enter stock timestamp string for stock-like build time."
required: false
type: string
default: "F"
upload_debug:
description: "Always upload logs, final config, rejects, UTS, Image and ZIPs."
required: true
type: boolean
default: true
concurrency:
group: op13-ksun-cctv18-clean-v92-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
actions: read
jobs:
build:
name: "${{ inputs.profile }} | KSUN=${{ inputs.ksun_ref }} | CCTV18 SUSFS=${{ inputs.susfs_enable }}"
runs-on: ubuntu-24.04
timeout-minutes: 360
permissions:
contents: read
actions: read
env:
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
CCACHE_NOHASHDIR: "true"
CCACHE_HARDLINK: "true"
steps:
- name: "Runner disk preflight"
id: disk
shell: bash
run: |
set -euo pipefail
echo "Memory and swap:"
free -h || true
echo ""
echo "Disk usage:"
df -hT || true
root_free_mb="$(df -Pm / | awk 'NR==2 {print $4}' || echo 0)"
echo "root_free_mb=$root_free_mb" >> "$GITHUB_OUTPUT"
if [ "$root_free_mb" -lt 25000 ]; then
echo "use_cleanup=true" >> "$GITHUB_OUTPUT"
else
echo "use_cleanup=false" >> "$GITHUB_OUTPUT"
fi
- name: "Extra disk cleanup"
if: steps.disk.outputs.use_cleanup == 'true'
shell: bash
run: |
set -euo pipefail
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android /usr/local/share/boost /usr/local/share/powershell /opt/hostedtoolcache/CodeQL || true
sudo docker image prune -a -f || true
sudo docker system prune -af || true
sudo apt-get clean || true
df -hT || true
- name: "Checkout"
uses: actions/checkout@v5
with:
fetch-depth: 1
- name: "Git auth for non-interactive clones"
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
git config --global credential.helper store
git config --global core.askPass true
git config --global url."https://x-access-token:${GH_TOKEN}@github.com/".insteadOf "https://github.com/"
- name: "Setup ccache directory"
shell: bash
run: |
set -euo pipefail
mkdir -p "$CCACHE_DIR"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
- name: "Restore ccache"
uses: actions/cache@v4
with:
path: ${{ env.CCACHE_DIR }}
key: ccache-${{ runner.os }}-op13-ksun-cctv18-v92-${{ inputs.profile }}-${{ inputs.susfs_enable }}-${{ inputs.ksun_ref }}-${{ github.ref_name }}
restore-keys: |
ccache-${{ runner.os }}-op13-ksun-cctv18-v92-${{ inputs.profile }}-${{ inputs.susfs_enable }}-
ccache-${{ runner.os }}-op13-ksun-cctv18-v92-
- name: "Install build dependencies"
shell: bash
run: |
set -euo pipefail
sudo apt-get -o Acquire::Retries=3 update -qq
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
aria2 ca-certificates curl wget git unzip zip tar xz-utils zstd rsync file jq \
build-essential gcc g++ make bc bison flex gawk python3 python-is-python3 \
libssl-dev libelf-dev libncurses-dev zlib1g-dev liblz4-tool dwarves \
ccache clang lld llvm patch kmod
sudo apt-get clean
echo "Runner: $(uname -a)"
ccache --version || true
- name: "Sync kernel sources"
shell: bash
run: |
set -euo pipefail
rm -rf kernel_workspace cctv18_assets _ox_debug artifacts ak3_work zram_tuner_work
mkdir -p kernel_workspace _ox_debug artifacts
echo "==> Cloning CCTV18 build assets only"
git clone --depth=1 "https://github.com/${CCTV18_BUILD_REPO}.git" cctv18_assets
git -C cctv18_assets rev-parse HEAD | tee _ox_debug/cctv18_assets_commit.txt
cd kernel_workspace
echo "==> Downloading CCTV18 OP13 common kernel source: ${{ inputs.cctv18_kernel_ref }}"
aria2c -s16 -x16 -k1M --retry-wait=5 --max-tries=5 \
"https://github.com/${CCTV18_COMMON_REPO}/archive/refs/heads/${{ inputs.cctv18_kernel_ref }}.zip" \
-o common.zip
unzip -q common.zip
src_dir="$(find . -maxdepth 1 -type d -name 'android_kernel_common_oneplus_sm8750-*' -print -quit)"
if [ -z "$src_dir" ]; then
echo "::error::Could not locate extracted OP13 common kernel directory."
find . -maxdepth 2 -type d | sort
exit 1
fi
mv "$src_dir" common
rm -f common.zip
echo "==> Downloading CCTV18 LLVM/Clang18 and build-tools"
aria2c -s16 -x16 -k1M --retry-wait=5 --max-tries=5 \
"https://github.com/cctv18/oneplus_sm8650_toolchain/releases/download/${CCTV18_TOOLCHAIN_RELEASE}/clang-r510928.zip" \
-o clang.zip
unzip -q clang.zip -d clang18
rm -f clang.zip
aria2c -s16 -x16 -k1M --retry-wait=5 --max-tries=5 \
"https://github.com/cctv18/oneplus_sm8650_toolchain/releases/download/${CCTV18_TOOLCHAIN_RELEASE}/build-tools.zip" \
-o build-tools.zip
unzip -q build-tools.zip
rm -f build-tools.zip
echo "==> Removing ABI export guard files and dirty suffix noise"
rm -f common/android/abi_gki_protected_exports_* || true
if [ -f common/scripts/setlocalversion ]; then
sed -i 's/ -dirty//g' common/scripts/setlocalversion
sed -i '$i res=$(echo "$res" | sed '\''s/-dirty//g'\'')' common/scripts/setlocalversion || true
fi
echo "==> Source layout" | tee ../_ox_debug/source-layout.txt
find . -maxdepth 2 -type d | sort | tee -a ../_ox_debug/source-layout.txt
- name: "Configure ccache limits"
shell: bash
run: |
set -euo pipefail
if [ "${{ inputs.clean_ccache }}" = "true" ]; then
rm -rf "$CCACHE_DIR"
fi
mkdir -p "$CCACHE_DIR"
ccache -M "$CCACHE_MAXSIZE"
ccache -o compression=true
ccache -z || true
ccache -s || true
- name: "Integrate KernelSU-Next"
id: ksun
shell: bash
run: |
set -euo pipefail
cd kernel_workspace
export PATH="$GITHUB_WORKSPACE/kernel_workspace/clang18/bin:$GITHUB_WORKSPACE/kernel_workspace/build-tools/path/linux-x86:$PATH"
echo "==> Installing KernelSU-Next via CCTV18-compatible pershoot dev-susfs setup path"
echo "Requested KSUN ref: ${{ inputs.ksun_ref }}"
curl -LSs "https://raw.githubusercontent.com/pershoot/KernelSU-Next/refs/heads/dev-susfs/kernel/setup.sh" | bash -s "${{ inputs.ksun_ref }}"
if [ -d common/drivers/kernelsu ]; then
KSU_TREE="common/drivers/kernelsu"
elif [ -d KernelSU-Next ]; then
KSU_TREE="KernelSU-Next"
elif [ -d common/KernelSU-Next ]; then
KSU_TREE="common/KernelSU-Next"
else
echo "::error::KernelSU-Next tree was not found after setup."
find . -maxdepth 4 -type d | sort | sed -n '1,240p'
exit 1
fi
echo "KSU_TREE=$KSU_TREE" | tee -a "$GITHUB_ENV"
echo "ksu_tree=$KSU_TREE" >> "$GITHUB_OUTPUT"
if [ -d "$KSU_TREE/.git" ]; then
git -C "$KSU_TREE" rev-parse HEAD | tee ../_ox_debug/ksun_commit.txt || true
fi
KSU_KBUILD="common/drivers/kernelsu/kernel/Kbuild"
if [ -f "$KSU_KBUILD" ]; then
KSU_VERSION="33129"
if [ -d "$KSU_TREE/.git" ]; then
cnt="$(git -C "$KSU_TREE" rev-list --count HEAD 2>/dev/null || true)"
if [ -n "$cnt" ]; then KSU_VERSION="$((cnt + 30000))"; fi
fi
KSU_TAG="v3.2.0"
sed -i "s/^KSU_VERSION_FALLBACK := .*/KSU_VERSION_FALLBACK := $KSU_VERSION/g" "$KSU_KBUILD" || true
sed -i "s/^KSU_VERSION_TAG_FALLBACK := .*/KSU_VERSION_TAG_FALLBACK := $KSU_TAG/g" "$KSU_KBUILD" || true
echo "KSUVER=$KSU_VERSION" >> "$GITHUB_ENV"
echo "KSUTAG=$KSU_TAG" >> "$GITHUB_ENV"
echo "ksuver=$KSU_VERSION" >> "$GITHUB_OUTPUT"
fi
# CCTV18 local manager signature compatibility patch only. This is not a SUSFS source mix.
if [ -f "$GITHUB_WORKSPACE/cctv18_assets/other_patch/apk_sign.patch" ] && [ -d common/drivers/kernelsu ]; then
echo "==> Applying CCTV18 apk_sign.patch"
( cd common/drivers/kernelsu && patch -p2 -N -F 3 < "$GITHUB_WORKSPACE/cctv18_assets/other_patch/apk_sign.patch" ) || true
fi
- name: "Apply CCTV18-only SUSFS"
if: ${{ inputs.susfs_enable == true }}
shell: bash
run: |
set -euo pipefail
cd kernel_workspace
rm -rf susfs4ksu
echo "==> Cloning CCTV18 SUSFS only: cctv18/susfs4oki @ ${{ inputs.susfs_ref }}"
git clone --depth=1 --branch "${{ inputs.susfs_ref }}" https://github.com/cctv18/susfs4oki.git susfs4ksu
git -C susfs4ksu rev-parse HEAD | tee ../_ox_debug/cctv18_susfs_commit.txt
git -C susfs4ksu remote -v | tee ../_ox_debug/cctv18_susfs_remote.txt
SUSFS_PATCH="susfs4ksu/kernel_patches/50_add_susfs_in_gki-${ANDROID_VERSION}-${KERNEL_VERSION}.patch"
if [ ! -f "$SUSFS_PATCH" ]; then
echo "::error::CCTV18 SUSFS common patch not found: $SUSFS_PATCH"
find susfs4ksu/kernel_patches -maxdepth 3 -type f | sort
exit 1
fi
cp -af susfs4ksu/kernel_patches/fs/. common/fs/
cp -af susfs4ksu/kernel_patches/include/linux/. common/include/linux/
cp -f "$SUSFS_PATCH" common/
# v92: 69_hide_stuff.patch is deliberately NOT staged for this lane.
# It has 4 hunks against fs/proc/task_mmu.c. Hunks 1, 2 and 4 (which ADD
# show_vma_header_prefix_fake(), "struct dentry *dentry;" and the "bypass:"
# label) match near-stock context and apply, but hunk 3 -- the only hunk
# that USES all three -- needs SUSFS's "bypass_orig_flow:" label as context.
# This lane's audited policy intentionally tolerates a task_mmu.c SUSFS
# reject, so hunk 3 fails and leaves three orphaned symbols behind:
# error: unused function 'show_vma_header_prefix_fake'
# warning: unused variable 'dentry' / unused label 'bypass'
# The ReSukiSU and SukiSU lanes have never applied this patch and both
# build and boot correctly, so skipping it here costs nothing: it is
# supplementary /proc hiding, while SUSFS provides the real hiding.
echo "==> Skipping 69_hide_stuff.patch for the KSUN stable lane (see comment above)."
rm -f common/69_hide_stuff.patch
cd common
# ---- v92: upstream security fix CVE-2026-43499 (rtmutex) ----
# NULL-pointer dereference in remove_waiter(): when called via
# rt_mutex_start_proxy_lock(), waiter->task may be NULL (never enqueued).
# From cctv18/oppo_oplus_realme_sm8750, the asset repo already cloned here.
# CCTV18's own 6.6.118 builder applies it unconditionally (no "|| true").
# SAFETY: touches ONLY kernel/locking/rtmutex.c and rtmutex_api.c -- no
# headers, so no struct/prototype change and no GKI 2.0 KMI impact.
# Verified absent from the 6.6.118 source. All-or-nothing: skip + warn
# rather than half-patch core locking code.
CVE_PATCH="$GITHUB_WORKSPACE/cctv18_assets/other_patch/cve-2026-43499-rtmutex-6.6.patch"
if [ -f "$CVE_PATCH" ]; then
if patch --dry-run -p1 -N -F 3 < "$CVE_PATCH" \
> "$GITHUB_WORKSPACE/_ox_debug/dryrun-cve-2026-43499.log" 2>&1; then
patch -p1 -N -F 3 < "$CVE_PATCH" \
> "$GITHUB_WORKSPACE/_ox_debug/apply-cve-2026-43499.log" 2>&1
if grep -q "waiter_task" kernel/locking/rtmutex.c; then
echo "==> CVE-2026-43499 rtmutex security patch APPLIED and verified."
echo "CVE-2026-43499: applied" > "$GITHUB_WORKSPACE/_ox_debug/cve-status.txt"
else
echo "::warning::CVE-2026-43499 patch reported success but the fix marker is missing. Treating as NOT applied."
echo "CVE-2026-43499: NOT applied (verification failed)" > "$GITHUB_WORKSPACE/_ox_debug/cve-status.txt"
fi
else
echo "::warning::CVE-2026-43499 rtmutex patch would not apply cleanly. Skipped -- kernel is NOT patched for this CVE."
echo "CVE-2026-43499: SKIPPED (dry-run failed)" > "$GITHUB_WORKSPACE/_ox_debug/cve-status.txt"
cat "$GITHUB_WORKSPACE/_ox_debug/dryrun-cve-2026-43499.log" || true
fi
else
echo "::warning::CVE-2026-43499 patch not found in cctv18_assets/other_patch; skipping."
echo "CVE-2026-43499: patch file not found" > "$GITHUB_WORKSPACE/_ox_debug/cve-status.txt"
fi
echo "==> Applying CCTV18 SUSFS patch with policy: ${{ inputs.susfs_patch_policy }}"
set +e
patch -p1 -N -F 3 < "50_add_susfs_in_gki-${ANDROID_VERSION}-${KERNEL_VERSION}.patch" 2>&1 | tee "$GITHUB_WORKSPACE/_ox_debug/cctv18-susfs-patch.log"
patch_rc=${PIPESTATUS[0]}
set -e
if [ "$patch_rc" -ne 0 ]; then
echo "SUSFS patch returned rc=$patch_rc" | tee -a "$GITHUB_WORKSPACE/_ox_debug/cctv18-susfs-patch.log"
find . -name '*.rej' -print | sort | tee "$GITHUB_WORKSPACE/_ox_debug/susfs-rejects.txt"
reject_count="$(wc -l < "$GITHUB_WORKSPACE/_ox_debug/susfs-rejects.txt" | tr -d ' ')"
only_task_mmu="false"
if [ "$reject_count" = "1" ] && grep -qx './fs/proc/task_mmu.c.rej' "$GITHUB_WORKSPACE/_ox_debug/susfs-rejects.txt"; then
only_task_mmu="true"
fi
if [ "${{ inputs.susfs_patch_policy }}" = "strict" ]; then
echo "::error::SUSFS patch reject found and strict policy is enabled."
exit 1
elif [ "${{ inputs.susfs_patch_policy }}" = "audited_cctv18" ] && [ "$only_task_mmu" != "true" ]; then
echo "::error::Unexpected SUSFS reject. audited_cctv18 only allows ./fs/proc/task_mmu.c.rej."
exit 1
else
echo "::warning::Continuing with audited CCTV18 SUSFS reject handling. No non-CCTV18 SUSFS source is imported."
while read -r rej; do
[ -n "$rej" ] || continue
safe="$(echo "$rej" | sed 's#^./##; s#[/ ]#_#g')"
cp -f "$rej" "$GITHUB_WORKSPACE/_ox_debug/${safe}" || true
rm -f "$rej"
done < "$GITHUB_WORKSPACE/_ox_debug/susfs-rejects.txt"
fi
fi
if [ -f 69_hide_stuff.patch ]; then
# v92 FIX (KSUN build failure on 6.6.118):
# 69_hide_stuff.patch modifies fs/proc/task_mmu.c and its hunks use
# SUSFS's "bypass_orig_flow:" label as CONTEXT -- i.e. it assumes the
# SUSFS task_mmu.c hunk already applied. This lane's audited policy
# deliberately TOLERATES a ./fs/proc/task_mmu.c reject, so that context
# can be absent. Applying with "|| true" then left the file half-patched:
# "struct dentry *dentry;" and the "bypass:" label were inserted while
# the hunks that USE them failed, producing
# error: unused variable 'dentry' [-Werror,-Wunused-variable]
# error: unused label 'bypass' [-Werror,-Wunused-label]
# Fix: dry-run first and apply ALL-OR-NOTHING, matching the discipline
# already used by clean_apply_optional_patch below. If it cannot apply
# fully, skip it entirely rather than contaminate task_mmu.c. This patch
# is supplementary /proc hiding only -- SUSFS provides the real hiding,
# and the ReSukiSU/SukiSU lanes skip it outright and boot fine.
echo "==> Checking CCTV18 69_hide_stuff.patch (all-or-nothing)"
if patch --dry-run -p1 -N -F 3 < 69_hide_stuff.patch \
> "$GITHUB_WORKSPACE/_ox_debug/dryrun-69_hide_stuff.log" 2>&1; then
echo "==> Applying CCTV18 69_hide_stuff.patch (dry-run clean)"
patch -p1 -N -F 3 < 69_hide_stuff.patch \
> "$GITHUB_WORKSPACE/_ox_debug/apply-69_hide_stuff.log" 2>&1 || true
else
echo "::warning::69_hide_stuff.patch would not apply cleanly (expected when the SUSFS task_mmu.c hunk rejected); skipping it to avoid partial patch contamination."
cat "$GITHUB_WORKSPACE/_ox_debug/dryrun-69_hide_stuff.log" || true
fi
# Safety net (defence in depth): if task_mmu.c somehow still ends up
# with an orphaned label/declaration, strip them here rather than
# failing deep in the compile with -Werror. Both checks are
# conservative: they only fire when the symbol has NO real user.
if [ -f fs/proc/task_mmu.c ]; then
if grep -qE '^[[:space:]]*bypass:[[:space:]]*$' fs/proc/task_mmu.c \
&& ! grep -q 'goto bypass;' fs/proc/task_mmu.c; then
echo "::warning::Removing orphaned 'bypass:' label from fs/proc/task_mmu.c"
sed -i '/^[[:space:]]*bypass:[[:space:]]*$/d' fs/proc/task_mmu.c
fi
if grep -qE '^[[:space:]]*struct dentry \*dentry;[[:space:]]*$' fs/proc/task_mmu.c \
&& ! grep -qE '\bdentry[[:space:]]*(=|->)' fs/proc/task_mmu.c; then
echo "::warning::Removing orphaned 'struct dentry *dentry;' from fs/proc/task_mmu.c"
sed -i '/^[[:space:]]*struct dentry \*dentry;[[:space:]]*$/d' fs/proc/task_mmu.c
fi
fi
fi
if find . -name '*.rej' -print -quit | grep -q .; then
echo "::error::Unexpected patch rejects remain after CCTV18 SUSFS stage."
find . -name '*.rej' -print | tee "$GITHUB_WORKSPACE/_ox_debug/rejects-after-susfs-stage.txt"
exit 1
fi
- name: "KSUN SELinux policy-query compatibility guard"
if: ${{ inputs.susfs_enable == true }}
shell: bash
run: |
set -euo pipefail
cd kernel_workspace/common
mkdir -p "$GITHUB_WORKSPACE/_ox_debug"
{
echo "==> KernelSU-Next + CCTV18 SELinux policy-query compatibility guard"
echo "KSUN reaches final link, then fails on SELinux policy-query symbols without this guard."
echo "The failure was unresolved SELinux policy-query symbols, not root/SUSFS integration."
echo "For the stable daily-driver KSUN lane, disable only the source-level SELinux policy-query replacement blocks in hooks.c and selinuxfs.c."
echo "This does not import another SUSFS tree and does not touch the core SUSFS fs/include payload."
} | tee "$GITHUB_WORKSPACE/_ox_debug/selinux-policy-query-guard.log"
python3 - <<'PY'
from pathlib import Path
paths = [Path('security/selinux/hooks.c'), Path('security/selinux/selinuxfs.c')]
changed = []
for path in paths:
if not path.exists():
continue
src = path.read_text(encoding='utf-8', errors='ignore')
original = src
# CCTV18's 50_add_susfs patch adds source-level SELinux policy-query wrappers
# under CONFIG_KSU_SUSFS. KernelSU-Next does not provide the backup_sepolicy
# and *_with_policy symbols needed by those wrappers, causing final link failure.
# Gate those wrappers behind a symbol we intentionally do not enable for this
# stable KSUN lane. Core SUSFS and KernelSU-Next remain enabled.
src = src.replace(
'#ifdef CONFIG_KSU_SUSFS\n',
'#if defined(CONFIG_KSU_SUSFS) && defined(CONFIG_KSU_SUSFS_SELINUX_POLICY_HIDE)\n'
)
if src != original:
path.write_text(src, encoding='utf-8')
changed.append(str(path))
out = Path('../../_ox_debug/selinux-policy-query-guard-files.txt')
out.write_text('\n'.join(changed) + ('\n' if changed else 'none\n'), encoding='utf-8')
print('Guarded files:', ', '.join(changed) if changed else 'none')
PY
echo "==> SELinux symbol scan after guard" | tee -a "$GITHUB_WORKSPACE/_ox_debug/selinux-policy-query-guard.log"
for sym in backup_sepolicy security_context_to_sid_with_policy security_sid_to_context_with_policy security_compute_av_user_with_policy; do
echo "--- $sym ---" | tee -a "$GITHUB_WORKSPACE/_ox_debug/selinux-policy-query-guard.log"
grep -Rsn "$sym" security/selinux | tee -a "$GITHUB_WORKSPACE/_ox_debug/selinux-policy-query-guard.log" || true
done
- name: "Apply optional CCTV18 feature patches"
shell: bash
run: |
set -euo pipefail
cd kernel_workspace/common
find_patch_by_regex() {
local regex="$1"
find "$GITHUB_WORKSPACE/cctv18_assets" -type f | grep -Ei "$regex" | sort | head -n 1 || true
}
clean_apply_optional_patch() {
local label="$1"
local enabled="$2"
local regex="$3"
if [ "$enabled" != "true" ]; then
echo "Skipping $label: disabled" | tee -a "$GITHUB_WORKSPACE/_ox_debug/optional-patches.log"
return 0
fi
local patch_file
patch_file="$(find_patch_by_regex "$regex" || true)"
if [ -z "$patch_file" ]; then
echo "Optional patch not found for $label; skipping." | tee -a "$GITHUB_WORKSPACE/_ox_debug/optional-patches.log"
return 0
fi
echo "Checking optional patch for $label: $patch_file" | tee -a "$GITHUB_WORKSPACE/_ox_debug/optional-patches.log"
if patch --dry-run -p1 -N -F 3 < "$patch_file" > "$GITHUB_WORKSPACE/_ox_debug/dryrun-${label//[^A-Za-z0-9]/_}.log" 2>&1; then
echo "Applying optional patch for $label" | tee -a "$GITHUB_WORKSPACE/_ox_debug/optional-patches.log"
patch -p1 -N -F 3 < "$patch_file" >> "$GITHUB_WORKSPACE/_ox_debug/apply-${label//[^A-Za-z0-9]/_}.log" 2>&1
else
echo "::warning::Optional patch for $label did not apply cleanly; skipped to avoid partial patch contamination."
cat "$GITHUB_WORKSPACE/_ox_debug/dryrun-${label//[^A-Za-z0-9]/_}.log" || true
fi
}
clean_apply_optional_patch "adios" "${{ inputs.adios }}" "(^|/).*adios.*\.patch$"
clean_apply_optional_patch "baseband_guard" "${{ inputs.baseband_guard }}" "(^|/).*(baseband|bbg).*\.patch$"
clean_apply_optional_patch "unicode" "${{ inputs.unicode_fix }}" "(^|/).*unicode.*\.patch$"
clean_apply_optional_patch "rekernel" "${{ inputs.rekernel }}" "(^|/).*(rekernel|re-kernel).*\.patch$"
if find . -name '*.rej' -print -quit | grep -q .; then
echo "::error::Patch rejects found after optional patch stage."
find . -name '*.rej' -print | tee "$GITHUB_WORKSPACE/_ox_debug/rejects-after-optional-stage.txt"
exit 1
fi
- name: "Enable features via defconfig"
shell: bash
run: |
set -euo pipefail
cd kernel_workspace/common
export PATH="$GITHUB_WORKSPACE/kernel_workspace/clang18/bin:$GITHUB_WORKSPACE/kernel_workspace/build-tools/path/linux-x86:$PATH"
export ARCH=arm64
export SUBARCH=arm64
export LLVM=1
export LLVM_IAS=1
MAKE_ARGS=(O=out ARCH=arm64 LLVM=1 LLVM_IAS=1)
echo "==> Toolchain check"
which clang | tee "$GITHUB_WORKSPACE/_ox_debug/clang-path.txt"
clang --version | tee "$GITHUB_WORKSPACE/_ox_debug/clang-version.txt"
echo "==> Generating gki_defconfig"
make "${MAKE_ARGS[@]}" gki_defconfig
cfg="out/.config"
if [ ! -f "$cfg" ]; then
echo "::error::Missing generated .config"
exit 1
fi
cfg_sym() { local s="$1"; echo "${s#CONFIG_}"; }
set_y() { scripts/config --file "$cfg" -e "$(cfg_sym "$1")" || true; }
set_m() { scripts/config --file "$cfg" -m "$(cfg_sym "$1")" || true; }
set_n() { scripts/config --file "$cfg" -d "$(cfg_sym "$1")" || true; }
set_str() { scripts/config --file "$cfg" --set-str "$(cfg_sym "$1")" "$2" || true; }
echo "==> Applying v92 daily-driver config profile: ${{ inputs.profile }}"
set_y CONFIG_KSU
echo "==> Requested KernelSU hook/audit mode: ${{ inputs.hook_mode }}"
case "${{ inputs.hook_mode }}" in
cctv18_susfs_auto)
# Clean CCTV18 KSUN lane uses pershoot KernelSU-Next dev-susfs.
# That Kconfig does not expose CONFIG_KSU_NONE_HOOK; KSU depends on KPROBES || SUSFS.
# Therefore the correct clean audit is CONFIG_KSU=y + CONFIG_KSU_SUSFS=y, not forcing a foreign hook selector.
true
;;
hybrid_compat)
# Keep KernelSU-Next/CCTV18 default selection with no artificial hook selector forcing.
true
;;
strict_none_hook_test)
# Test-only: only useful if you change KSUN source to a tree that actually exposes CONFIG_KSU_NONE_HOOK.
set_y CONFIG_KSU_NONE_HOOK
set_n CONFIG_KSU_MANUAL_HOOK
set_n CONFIG_KSU_KPROBES_HOOK
set_n CONFIG_KSU_WITH_KPROBES
;;
esac
if [ "${{ inputs.susfs_enable }}" = "true" ]; then
# v92: only the 10 SUSFS options that ACTUALLY EXIST in the root driver.
# Verified against the Kconfig of all three projects (SukiSU-Ultra,
# ReSukiSU, pershoot/KernelSU-Next) -- each defines exactly these 10.
# REMOVED because no project defines them, so olddefconfig silently
# dropped them and they only created false confidence:
# CONFIG_KSU_SUSFS_TRY_UMOUNT
# CONFIG_KSU_SUSFS_SUS_SU (deprecated upstream)
# CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT
# CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT
# Per-app unmounting is handled by the manager's App Profile
# ("umount modules"), not by a kernel config symbol.
for opt in \
CONFIG_KSU_SUSFS \
CONFIG_KSU_SUSFS_SUS_PATH \
CONFIG_KSU_SUSFS_SUS_MOUNT \
CONFIG_KSU_SUSFS_SUS_KSTAT \
CONFIG_KSU_SUSFS_SUS_MAP \
CONFIG_KSU_SUSFS_SPOOF_UNAME \
CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG \
CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS \
CONFIG_KSU_SUSFS_OPEN_REDIRECT; do
set_y "$opt"
done
# Battery/performance: SUSFS kernel logging is pure overhead on a daily
# driver (it logs on SUSFS operations). Upstream defaults it to y; we
# force it off.
set_n CONFIG_KSU_SUSFS_ENABLE_LOG
fi
if [ "${{ inputs.stock_mimic }}" = "true" ]; then
set_str CONFIG_LOCALVERSION "-${{ inputs.kernel_suffix }}"
else
set_str CONFIG_LOCALVERSION "-${{ inputs.kernel_suffix }}-ox"
fi
set_n CONFIG_LOCALVERSION_AUTO
set_y CONFIG_LTO_CLANG_THIN
set_n CONFIG_LTO_NONE
case "${{ inputs.optimise }}" in
O2)
set_y CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE
set_n CONFIG_CC_OPTIMIZE_FOR_SIZE
set_n CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3
;;
O3)
set_y CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3
;;
esac
if [ "${{ inputs.zram_lz4 }}" = "true" ]; then
echo "==> Enabling ZRAM + LZ4/LZ4HC/ZSTD config support"
for opt in \
CONFIG_ZRAM \
CONFIG_ZSMALLOC \
CONFIG_CRYPTO_LZ4 \
CONFIG_CRYPTO_LZ4HC \
CONFIG_CRYPTO_ZSTD \
CONFIG_LZ4_COMPRESS \
CONFIG_LZ4_DECOMPRESS \
CONFIG_ZSTD_COMPRESS \
CONFIG_ZSTD_DECOMPRESS; do
set_y "$opt"
done
set_y CONFIG_ZRAM_WRITEBACK
set_y CONFIG_ZRAM_MULTI_COMP
set_str CONFIG_ZRAM_DEF_COMP "${{ inputs.zram_comp }}"
fi
if [ "${{ inputs.better_net }}" = "true" ]; then
for opt in \
CONFIG_NETFILTER \
CONFIG_NETFILTER_ADVANCED \
CONFIG_NETFILTER_XTABLES \
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE \
CONFIG_NETFILTER_XT_MATCH_COMMENT \
CONFIG_NETFILTER_XT_MATCH_CONNTRACK \
CONFIG_NETFILTER_XT_MATCH_MARK \
CONFIG_NETFILTER_XT_TARGET_MARK \
CONFIG_NETFILTER_XT_TARGET_HL \
CONFIG_NETFILTER_XT_MATCH_HL \
CONFIG_IP_SET \
CONFIG_IP_SET_BITMAP_IP \
CONFIG_IP_SET_BITMAP_IPMAC \
CONFIG_IP_SET_BITMAP_PORT \
CONFIG_IP_SET_HASH_IP \
CONFIG_IP_SET_HASH_IPMARK \
CONFIG_IP_SET_HASH_IPPORT \
CONFIG_IP_SET_HASH_IPPORTIP \
CONFIG_IP_SET_HASH_IPPORTNET \
CONFIG_IP_SET_HASH_IPMAC \
CONFIG_IP_SET_HASH_MAC \
CONFIG_IP_SET_HASH_NET \
CONFIG_IP_SET_HASH_NETNET \
CONFIG_IP_SET_HASH_NETPORT \
CONFIG_IP_SET_HASH_NETPORTNET \
CONFIG_IP_SET_HASH_NETIFACE \
CONFIG_IP_SET_LIST_SET \
CONFIG_NETFILTER_XT_SET; do
set_y "$opt"
done
# v92: symbol-name corrections verified against the real 6.6.118
# net/netfilter Kconfig. The following DID NOT EXIST and were silently
# dropped by olddefconfig, so these features were never actually built:
# CONFIG_NETFILTER_XT_TARGET_HL -> real symbol is ..._TARGET_HL
# CONFIG_NETFILTER_XT_MATCH_TTL -> real symbol is ..._MATCH_HL
# (upstream merged them: "adds the HL (for IPv6) and TTL (for IPv4)")
# CONFIG_NETFILTER_XT_MATCH_SET -> real symbol is CONFIG_NETFILTER_XT_SET
# (without it CONFIG_IP_SET is unusable from iptables)
# The extra IP_SET_* variants match CCTV18's own builder and make ipset
# actually usable for firewall / ad-block modules.
scripts/config --file "$cfg" --set-val CONFIG_IP_SET_MAX 65534 || true
fi
# Avoid the previous DEFAULT_BBR choice warning by clearing DEFAULT_BBR before handling BBR mode.
set_n CONFIG_DEFAULT_BBR || true
case "${{ inputs.bbr_mode }}" in
off)
set_n CONFIG_TCP_CONG_BBR
;;
enabled)
set_y CONFIG_TCP_CONG_BBR
;;
default)
set_y CONFIG_TCP_CONG_BBR
set_y CONFIG_DEFAULT_BBR || true
;;
esac
if [ "${{ inputs.ntsync }}" = "true" ]; then
set_y CONFIG_NTSYNC
fi
if [ "${{ inputs.droidspaces }}" = "true" ]; then
for opt in CONFIG_TMPFS_XATTR CONFIG_TMPFS_POSIX_ACL CONFIG_PID_NS CONFIG_USER_NS CONFIG_UTS_NS CONFIG_IPC_NS; do
set_y "$opt"
done
fi
case "${{ inputs.profile }}" in
minimal_safe)
set_n CONFIG_TCP_CONG_BBR
set_n CONFIG_IP_SET
set_n CONFIG_NTSYNC
;;
debug_only)
set_y CONFIG_KSU_SUSFS_ENABLE_LOG
;;
stock_plus)
set_y CONFIG_NTSYNC
;;
esac
echo "==> Running olddefconfig directly; no yes pipe, no SIGPIPE false failure"
make "${MAKE_ARGS[@]}" olddefconfig
cp -f out/.config "$GITHUB_WORKSPACE/_ox_debug/final.config"
echo "==> Final KSUN/SUSFS hook audit" | tee "$GITHUB_WORKSPACE/_ox_debug/hook-mode-audit.txt"
{
echo "Requested hook/audit mode: ${{ inputs.hook_mode }}"
echo "Detected KSUN hook selector symbols, if any:"
grep -E 'CONFIG_KSU(_NONE_HOOK|_MANUAL_HOOK|_KPROBES_HOOK|_WITH_KPROBES|_SUSFS)=' out/.config || true
echo "Detected generic KPROBES state:"
grep -E 'CONFIG_KPROBES=' out/.config || true
echo "KernelSU Kconfig hook selector availability:"
if grep -Rqs 'config KSU_NONE_HOOK' ../KernelSU-Next/kernel ./drivers/kernelsu 2>/dev/null; then
echo "KSU_NONE_HOOK symbol exists in this KSUN tree"
else
echo "KSU_NONE_HOOK symbol NOT exposed by this clean CCTV18/pershoot dev-susfs KSUN tree"
fi
} | tee -a "$GITHUB_WORKSPACE/_ox_debug/hook-mode-audit.txt"
if ! grep -q '^CONFIG_KSU=y' out/.config; then
echo "::error::CONFIG_KSU=y missing after olddefconfig."
exit 1
fi
if [ "${{ inputs.susfs_enable }}" = "true" ]; then
if ! grep -q '^CONFIG_KSU_SUSFS=y' out/.config; then
echo "::error::CONFIG_KSU_SUSFS=y missing after olddefconfig. This is the real blocker for clean CCTV18 SUSFS."
exit 1
fi
fi
if [ "${{ inputs.hook_mode }}" = "strict_none_hook_test" ]; then
if ! grep -Rqs 'config KSU_NONE_HOOK' ../KernelSU-Next/kernel ./drivers/kernelsu 2>/dev/null; then
echo "::error::strict_none_hook_test requested, but this clean KSUN dev-susfs tree does not expose CONFIG_KSU_NONE_HOOK. Use cctv18_susfs_auto for this branch."
exit 1
fi
if ! grep -q '^CONFIG_KSU_NONE_HOOK=y' out/.config; then
echo "::error::strict_none_hook_test requested, but CONFIG_KSU_NONE_HOOK=y is not present after olddefconfig."
exit 1
fi
fi
echo "==> Final config scan"
grep -E 'CONFIG_KSU|CONFIG_LOCALVERSION|CONFIG_TCP_CONG_BBR|CONFIG_DEFAULT_BBR|CONFIG_IP_SET|CONFIG_NTSYNC|CONFIG_LTO|CONFIG_CC_OPTIMIZE|CONFIG_NETFILTER_XT_TARGET_HL|CONFIG_ADIOS|CONFIG_BBG|CONFIG_BASEBAND|CONFIG_ZRAM|CONFIG_ZSMALLOC|CONFIG_CRYPTO_LZ4|CONFIG_LZ4|CONFIG_ZSTD' out/.config | tee "$GITHUB_WORKSPACE/_ox_debug/config-scan.txt" || true
# ---- v92 SUSFS config audit ----
# Verifies that every SUSFS option we asked for actually landed as =y in
# the FINAL .config. Previously four options were requested that no root
# project defines, so olddefconfig silently dropped them and the build
# looked correct while the features were absent. This turns that class of
# silent failure into a visible warning.
{
echo "SUSFS config audit (expected =y unless noted)"
for s in CONFIG_KSU_SUSFS CONFIG_KSU_SUSFS_SUS_PATH CONFIG_KSU_SUSFS_SUS_MOUNT \
CONFIG_KSU_SUSFS_SUS_KSTAT CONFIG_KSU_SUSFS_SUS_MAP \
CONFIG_KSU_SUSFS_SPOOF_UNAME CONFIG_KSU_SUSFS_SPOOF_CMDLINE_OR_BOOTCONFIG \
CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS CONFIG_KSU_SUSFS_OPEN_REDIRECT; do
if grep -q "^${s}=y" out/.config; then
echo " OK ${s}=y"
else
echo " MISSING ${s} (requested but not enabled)"
echo "::warning::SUSFS option ${s} was requested but is NOT enabled in the final .config."
fi
done
if grep -q "^CONFIG_KSU_SUSFS_ENABLE_LOG=y" out/.config; then
echo " NOTE CONFIG_KSU_SUSFS_ENABLE_LOG=y (expected off for battery)"
echo "::warning::SUSFS kernel logging is ON; this costs battery on a daily driver."
else
echo " OK CONFIG_KSU_SUSFS_ENABLE_LOG disabled (battery-friendly)"
fi
} | tee "$GITHUB_WORKSPACE/_ox_debug/susfs-config-audit.txt" || true
- name: "Build kernel"
id: build
shell: bash
run: |
set -euo pipefail
cd kernel_workspace/common
export PATH="$GITHUB_WORKSPACE/kernel_workspace/clang18/bin:$GITHUB_WORKSPACE/kernel_workspace/build-tools/path/linux-x86:$PATH"
export ARCH=arm64
export SUBARCH=arm64
export LLVM=1
export LLVM_IAS=1
export CCACHE_DIR="$CCACHE_DIR"
export CCACHE_BASEDIR="$GITHUB_WORKSPACE/kernel_workspace"
export CCACHE_NOHASHDIR=true
export CCACHE_COMPILERCHECK=none
export KBUILD_BUILD_USER="ox1d3x3"
export KBUILD_BUILD_HOST="op13-cctv18-ksun"
if [ "${{ inputs.BUILD_TIME }}" = "F" ]; then
export KBUILD_BUILD_TIMESTAMP="$(date -u '+%a %b %d %H:%M:%S UTC %Y')"
else
export KBUILD_BUILD_TIMESTAMP="${{ inputs.BUILD_TIME }}"
fi
echo "==> KBUILD_BUILD_TIMESTAMP=$KBUILD_BUILD_TIMESTAMP"
# ---- v92: unconditional task_mmu.c orphan repair (runs after ALL patching) ----
# CCTV18's 69_hide_stuff.patch has 4 hunks against fs/proc/task_mmu.c:
# hunk 2 -> adds "struct dentry *dentry;" (generic context, applies to stock)
# hunk 4 -> adds "bypass:" label (generic context, applies to stock)
# hunk 1 -> adds show_vma_header_prefix_fake (needs SUSFS context)
# hunk 3 -> adds the USES: "dentry = ..." and "goto bypass;" (needs SUSFS's
# "bypass_orig_flow:" label as context)
# This lane's audited policy deliberately tolerates a task_mmu.c SUSFS reject,
# so hunks 1+3 can fail while 2+4 succeed, leaving the declaration and label
# with no users:
# error: unused variable 'dentry' [-Werror,-Wunused-variable]
# error: unused label 'bypass' [-Werror,-Wunused-label]
# This repair is deliberately placed here -- in the build step, unconditional
# and independent of which patch path ran -- because an earlier attempt that
# lived inside the "if [ -f 69_hide_stuff.patch ]" block did not prevent the
# failure. Removing an unused declaration/label cannot change runtime
# behaviour; both are no-ops once the code that would use them is absent.
echo "==> task_mmu.c orphan scan (BEFORE repair):"
grep -nE 'show_vma_header_prefix_fake|struct dentry \*dentry;|^[[:space:]]*bypass:|goto bypass;' fs/proc/task_mmu.c || echo " none found (clean)"
python3 - <<'ORPHANFIX'
import re, pathlib
p = pathlib.Path('fs/proc/task_mmu.c')
if not p.exists():
print('task_mmu.c not found; skipping orphan repair')
else:
s = p.read_text(errors='ignore'); orig = s
# Orphaned label: "bypass:" with no "goto bypass;" anywhere.
if re.search(r'^[ \t]*bypass:[ \t]*$', s, re.M) and not re.search(r'goto\s+bypass\s*;', s):
s = re.sub(r'^[ \t]*bypass:[ \t]*\n', '', s, flags=re.M)
print('removed orphaned "bypass:" label')
# Orphaned declaration: "struct dentry *dentry;" with no assignment to the
# local variable. Member accesses like "f_path.dentry" / "->dentry" are NOT
# uses of this local, so they are excluded via the (?<![.>]) lookbehind.
if re.search(r'^[ \t]*struct dentry \*dentry;[ \t]*$', s, re.M):
used = re.search(r'(?<![.>])\bdentry\b\s*(=[^=]|->)', s)
if not used:
s = re.sub(r'^[ \t]*struct dentry \*dentry;[ \t]*\n', '', s, flags=re.M)
print('removed orphaned "struct dentry *dentry;" declaration')
if s != orig:
p.write_text(s)
print('task_mmu.c orphan repair applied')
else:
print('task_mmu.c: no orphaned symbols found (nothing to repair)')
ORPHANFIX
echo "==> task_mmu.c orphan scan (AFTER repair):"
grep -nE 'show_vma_header_prefix_fake|struct dentry \*dentry;|^[[:space:]]*bypass:|goto bypass;' fs/proc/task_mmu.c || echo " none found (clean)"
MAKE_ARGS=(O=out ARCH=arm64 LLVM=1 LLVM_IAS=1 CC="ccache clang")
# v92 safety valve: downstream hiding patches can leave cosmetically-unused
# symbols behind when a dependent hunk rejects. Downgrade ONLY these two
# warning classes from errors so a cosmetic leftover can never again kill an
# otherwise-good build. Everything else stays -Werror.
export KCFLAGS="${KCFLAGS:-} -Wno-error=unused-variable -Wno-error=unused-label -Wno-error=unused-function"
echo "==> KCFLAGS=$KCFLAGS"
echo "==> Building Image"
make -j"$(nproc --all)" "${MAKE_ARGS[@]}" KCFLAGS="$KCFLAGS" Image 2>&1 | tee "$GITHUB_WORKSPACE/_ox_debug/build.log"
image="out/arch/arm64/boot/Image"
if [ ! -s "$image" ]; then
echo "::error::Kernel Image was not produced."
find out -maxdepth 6 -type f -name 'Image*' -printf '%p %s bytes\n' | tee "$GITHUB_WORKSPACE/_ox_debug/image-search.txt" || true
exit 1
fi
cp -f "$image" "$GITHUB_WORKSPACE/artifacts/Image_OP13_KSUN_CCTV18_clean_stocklike_v92"
sha256sum "$GITHUB_WORKSPACE/artifacts/Image_OP13_KSUN_CCTV18_clean_stocklike_v92" | tee "$GITHUB_WORKSPACE/artifacts/Image_OP13_KSUN_CCTV18_clean_stocklike_v92.sha256"
uts="unknown"
if [ -f out/include/generated/utsrelease.h ]; then
cp -f out/include/generated/utsrelease.h "$GITHUB_WORKSPACE/_ox_debug/utsrelease.h"
uts="$(sed -n 's/^#define UTS_RELEASE "\(.*\)"/\1/p' out/include/generated/utsrelease.h | head -n1)"
fi
echo "UTS_RELEASE=$uts" | tee "$GITHUB_WORKSPACE/_ox_debug/uts.txt"
echo "uts=$uts" >> "$GITHUB_OUTPUT"
ccache -s | tee "$GITHUB_WORKSPACE/_ox_debug/ccache-final.txt" || true
- name: "Package AnyKernel3"
if: ${{ inputs.package_ak3 == true }}
shell: bash
run: |
set -euo pipefail
rm -rf ak3_work
git clone --depth=1 https://github.com/osm0sis/AnyKernel3.git ak3_work
git -C ak3_work rev-parse HEAD | tee "$GITHUB_WORKSPACE/_ox_debug/anykernel3_commit.txt"
# --- AK3 naming-convention guard (v92) ---
# AK3 renamed its anykernel.sh settings to UPPERCASE. We write both
# spellings, but if upstream ever changes convention AGAIN this guard
# makes it obvious in the log instead of silently shipping a zip that
# aborts at flash time with "Flash failed".
if grep -q '\$BLOCK' ak3_work/tools/ak3-core.sh; then
echo "AK3 convention: UPPERCASE (\$BLOCK) - our uppercase vars will be used."
elif grep -q '\$block' ak3_work/tools/ak3-core.sh; then
echo "AK3 convention: lowercase (\$block) - our legacy aliases will be used."
else
echo "::warning::Could not detect AK3 boot-partition variable convention in ak3-core.sh. Flashing may fail; inspect _ox_debug/anykernel3_commit.txt."
fi
# --- Bundle a best-effort RAM Expansion fix module into the AK3 zip ---
mkdir -p ak3_work/ramfix
cat > ak3_work/ramfix/module.prop <<'RAMFIXPROP'
id=op13_ram_expansion_fix
name=OP13 RAM Expansion Fix
version=v1
versionCode=1
author=ox1d3x3
description=Restores OnePlus RAM Expansion (extended RAM) under root by re-asserting persist.sys.oplus.nandswap.condition on each boot. Bundled with the kernel.
RAMFIXPROP
cat > ak3_work/ramfix/service.sh <<'RAMFIXSVC'
#!/system/bin/sh
MODDIR=${0%/*}
until [ "$(getprop sys.boot_completed)" = "1" ]; do sleep 2; done
sleep 8
resetprop persist.sys.oplus.nandswap.condition true 2>/dev/null || setprop persist.sys.oplus.nandswap.condition true 2>/dev/null || true
for n in /sys/block/zram0/hybridswap_dev_life /sys/block/zram*/hybridswap_dev_life; do
[ -e "$n" ] && echo 1 > "$n" 2>/dev/null || true
done
RAMFIXSVC
chmod 0755 ak3_work/ramfix/service.sh
rm -rf ak3_work/.git ak3_work/.github ak3_work/README.md || true
cp -f artifacts/Image_OP13_KSUN_CCTV18_clean_stocklike_v92 ak3_work/Image
cat > ak3_work/anykernel.sh <<'AK3'
### AnyKernel3 Ramdisk Mod Script
## osm0sis @ xda-developers
## OX1D3X3 OP13 KSUN + CCTV18 clean SUSFS package
### AnyKernel setup
# global properties
properties() { '
kernel.string=${{ inputs.kernel_name }}
do.devicecheck=0
do.modules=0
do.systemless=0
do.cleanup=1
do.cleanuponabort=0
do.check_boot_version=0
device.name1=
device.name2=
device.name3=
device.name4=
device.name5=
supported.versions=
supported.patchlevels=
supported.vendorpatchlevels=
'; } # end properties
### AnyKernel install
## boot shell variables
# OP13 / PJZ110 is A/B slot device. Use partition-name detection, not old omap path.
# v92 FLASH FIX: AnyKernel3 upstream renamed these settings to UPPERCASE
# (BLOCK, IS_SLOT_DEVICE, ...). This workflow clones AK3 master unpinned,
# so a fresh build picks up the new ak3-core.sh, which IGNORES the old
# lowercase names. With $BLOCK unset, AK3 cannot resolve the boot
# partition and aborts immediately after "Installing..." -> "Flash failed".
# We therefore set BOTH spellings: uppercase for current AK3, lowercase
# for older/pinned AK3 revisions. Harmless either way.
BLOCK=boot
IS_SLOT_DEVICE=auto
SLOT_SELECT=active
RAMDISK_COMPRESSION=auto
PATCH_VBMETA_FLAG=auto
NO_MAGISK_CHECK=1
# legacy lowercase aliases (older AnyKernel3)
block=boot
is_slot_device=auto
slot_select=active
ramdisk_compression=auto
patch_vbmeta_flag=auto
no_magisk_check=1
# import functions/variables and setup patching - see for reference (DO NOT REMOVE)
. tools/ak3-core.sh
# --- OX1D3X3 CUSTOM START ---
ui_print ' '
ui_print '===================================================='
ui_print ' __ __ __ '
ui_print ' \ \ / //_ |'
ui_print ' \ V / | |'
ui_print ' > < | |'
ui_print ' / . \ | |'
ui_print ' /_/ \_\ |_|'
ui_print '===================================================='
ui_print ' '
ui_print 'PJZ110 | KernelSU-Next [StockLike Daily] + CCTV18 SUSFS'
ui_print 'Kernel : 6.6.118-${{ inputs.kernel_suffix }}'
ui_print 'Hook : ${{ inputs.hook_mode }}'
ui_print 'Audit : CONFIG_KSU + CONFIG_KSU_SUSFS required'
ui_print 'Build : #${{ github.run_number }} (${{ inputs.kernel_suffix }})'
ui_print 'Builder: @Ox1d3x3'
ui_print 'Credits: @cctv18, KernelSU-Next, osm0sis, @mrcxlinux'
ui_print 'Source : CCTV18 susfs4oki only - no mixed SUSFS patch tree'
ui_print 'ZRAM : kernel config=${{ inputs.zram_lz4 }} / preferred=${{ inputs.zram_comp }}'
ui_print ' '
device="$(getprop ro.product.device 2>/dev/null || true)"
model="$(getprop ro.product.model 2>/dev/null || true)"
android="$(getprop ro.build.version.release 2>/dev/null || true)"
patch="$(getprop ro.build.version.security_patch 2>/dev/null || true)"
slot="$(getprop ro.boot.slot_suffix 2>/dev/null || true)"
[ -z "$slot" ] && slot="$(getprop ro.boot.slot 2>/dev/null || true)"
if [ -n "$device" ]; then ui_print "Device : $device ($model)"; fi
if [ -n "$android" ]; then ui_print "Android: $android"; fi
if [ -n "$patch" ]; then ui_print "Patch : $patch"; fi
if [ -n "$slot" ]; then ui_print "Slot : $slot"; fi
ui_print 'Target : active boot partition'
ui_print ' '
# Best-effort open project page (may be ignored in recovery)
if command -v cmd >/dev/null 2>&1; then
(cmd activity start --user 0 -a android.intent.action.VIEW -d 'https://github.com/ox1d3x3/Op13_Susfs_kernel' >/dev/null 2>&1 &) || true
elif command -v am >/dev/null 2>&1; then
(am start --user 0 -a android.intent.action.VIEW -d 'https://github.com/ox1d3x3/Op13_Susfs_kernel' >/dev/null 2>&1 &) || true
fi
# --- OX1D3X3 CUSTOM END ---
# GKI check
kernel_version=$(cat /proc/version | awk -F '-' '{print $1}' | awk '{print $3}')
case $kernel_version in
5.1*) ksu_supported=true ;;
6.1*) ksu_supported=true ;;
6.6*) ksu_supported=true ;;
*) ksu_supported=false ;;
esac
ui_print ' '
ui_print ' -> Thank you for using this kernel'
$ksu_supported || abort ' -> Non-GKI device, abort.'
# boot install
split_boot
if [ -f "$SPLITIMG/ramdisk.cpio" ]; then
unpack_ramdisk
write_boot
else
flash_boot
fi
ui_print ' '
# --- OX RAM Expansion auto-install (best effort; needs decrypted /data) ---
if [ -d /data/adb/modules ] && [ -d "$home/ramfix" ]; then
ui_print ' Installing bundled RAM Expansion fix...'
RFM=/data/adb/modules/op13_ram_expansion_fix
mkdir -p "$RFM"
cp -f "$home/ramfix/module.prop" "$RFM/module.prop" 2>/dev/null
cp -f "$home/ramfix/service.sh" "$RFM/service.sh" 2>/dev/null
chmod 0755 "$RFM/service.sh" 2>/dev/null
rm -f "$RFM/disable" "$RFM/remove" "$RFM/update" 2>/dev/null
ui_print ' RAM Expansion fix installed (applies after reboot).'
else
ui_print ' RAM Expansion: /data not mounted - use X1 Kernel Manager instead.'
fi
ui_print ' Reboot Your System '
ui_print ' '
ui_print ' '
AK3
sed -i 's/^ //' ak3_work/anykernel.sh
chmod 0755 ak3_work/anykernel.sh
cat > ak3_work/OX_CCTV18_CLEAN_BUILD_INFO.txt <<EOF
OX1D3X3 OP13 KSUN + CCTV18 CLEAN SUSFS v92
Device: OnePlus 13 / sun / PJZ110
Kernel source: cctv18/android_kernel_common_oneplus_sm8750 @ ${{ inputs.cctv18_kernel_ref }}
Build assets: cctv18/oppo_oplus_realme_sm8750
Root: KernelSU-Next via CCTV18-compatible pershoot dev-susfs setup path, ref=${{ inputs.ksun_ref }}
SUSFS: cctv18/susfs4oki only, ref=${{ inputs.susfs_ref }}
SUSFS patch policy: ${{ inputs.susfs_patch_policy }}
WildKernels SUSFS patch tree: NOT USED
TheWildJames kernel_patches: NOT USED
Profile: ${{ inputs.profile }}
Optimise: ${{ inputs.optimise }}
ZRAM/LZ4 config: ${{ inputs.zram_lz4 }} / compressor=${{ inputs.zram_comp }}
ZRAM runtime tuner: X1 Kernel Manager module (separate tuner zip removed)
UTS_RELEASE: ${{ steps.build.outputs.uts }}
Built UTC: $(date -u '+%Y-%m-%d %H:%M:%S')
EOF
sed -i 's/^ //' ak3_work/OX_CCTV18_CLEAN_BUILD_INFO.txt
zip_name="AK3_OP13_KSUN_CCTV18_clean_stocklike_v92_${{ github.run_number }}_FLASH_THIS.zip"
( cd ak3_work && zip -r9 "../artifacts/$zip_name" . >/dev/null )
sha256sum "artifacts/$zip_name" | tee "artifacts/$zip_name.sha256"
echo "==> AnyKernel3 package scan"
unzip -p "artifacts/$zip_name" anykernel.sh | sed -n '1,130p' | tee _ox_debug/packaged-anykernel.sh.txt
if unzip -p "artifacts/$zip_name" anykernel.sh | grep -q 'omap_hsmmc'; then
echo "::error::Packaged anykernel.sh still contains old omap boot path."
exit 1
fi
if unzip -p "artifacts/$zip_name" anykernel.sh | grep -q 'ExampleKernel'; then
echo "::error::Packaged anykernel.sh still contains default ExampleKernel banner."
exit 1
fi
if ! unzip -p "artifacts/$zip_name" anykernel.sh | grep -q 'OX1D3X3 CUSTOM START'; then
echo "::error::OX1D3X3 custom install banner was not packaged."
exit 1
fi
if ! unzip -p "artifacts/$zip_name" anykernel.sh | grep -q 'KernelSU-Next \[StockLike Daily\]'; then
echo "::error::OX install info banner was not packaged."
exit 1
fi
- name: "Clean-source audit and debug collection"
if: always()
shell: bash
run: |
set -euo pipefail
mkdir -p _ox_debug artifacts
{
echo "Workflow: OP13 KSUN CCTV18 Clean StockLike Daily v92"
echo "Profile: ${{ inputs.profile }}"
echo "KSUN ref: ${{ inputs.ksun_ref }}"
echo "SUSFS enabled: ${{ inputs.susfs_enable }}"
echo "SUSFS ref: ${{ inputs.susfs_ref }}"
echo "SUSFS patch policy: ${{ inputs.susfs_patch_policy }}"
echo "Hook mode: ${{ inputs.hook_mode }}"
echo "Kernel ref: ${{ inputs.cctv18_kernel_ref }}"
echo "Stock mimic: ${{ inputs.stock_mimic }}"
echo "Kernel name: ${{ inputs.kernel_name }}"
echo "Build time input: ${{ inputs.BUILD_TIME }}"
echo "BBR mode: ${{ inputs.bbr_mode }}"
echo "Better net: ${{ inputs.better_net }}"
echo "ZRAM/LZ4: ${{ inputs.zram_lz4 }} / ${{ inputs.zram_comp }}"
echo "No WildKernels SUSFS patch tree is cloned or used."
echo "No TheWildJames kernel_patches tree is cloned or used."
echo "UTS: ${{ steps.build.outputs.uts }}"
} | tee _ox_debug/build-summary.txt
if [ -d kernel_workspace/susfs4ksu ]; then
git -C kernel_workspace/susfs4ksu remote -v | tee _ox_debug/susfs-remote-final.txt || true
fi
if [ -d cctv18_assets ]; then
git -C cctv18_assets remote -v | tee _ox_debug/cctv18-assets-remote.txt || true
fi
if [ -d kernel_workspace/common ]; then
find kernel_workspace/common -name '*.rej' -o -name '*.orig' 2>/dev/null | sort | tee _ox_debug/rejects-orig-files.txt || true
fi
find artifacts _ox_debug -maxdepth 3 -type f -printf '%p %s bytes\n' 2>/dev/null | sort | tee _ox_debug/artifact-preview.txt || true
if [ -f "$GITHUB_STEP_SUMMARY" ]; then
{
echo "# OP13 KSUN + CCTV18 Clean StockLike Daily v92"
echo ""
echo "## Verdict"
echo "- Main flashable zip uses fixed AnyKernel3 OP13 boot detection."
echo "- SUSFS source: CCTV18 only."
echo "- ZRAM/LZ4 config enabled: ${{ inputs.zram_lz4 }} / ${{ inputs.zram_comp }}."
echo "- ZRAM runtime tuning: use the X1 Kernel Manager module (separate tuner zip removed)."
echo ""
echo "## Outputs"
find artifacts -maxdepth 1 -type f -printf '- `%f`\n' 2>/dev/null | sort
} >> "$GITHUB_STEP_SUMMARY"
fi
- name: "Upload build outputs"
if: always() && (inputs.upload_debug == true || success())
uses: actions/upload-artifact@v6
with:
name: OP13-KSUN-CCTV18-CLEAN-STOCKLIKE-v92-${{ github.run_number }}
path: |
artifacts/**
_ox_debug/**
if-no-files-found: warn
compression-level: 6
retention-days: 14
- name: "Summary"
if: always()
shell: bash
run: |
set -euo pipefail
if [ ! -s artifacts/Image_OP13_KSUN_CCTV18_clean_stocklike_v92 ]; then
echo "::error::Build failed before producing Image. Download OP13-KSUN-CCTV18-CLEAN-STOCKLIKE-v92 debug artifact."
exit 1
fi
if [ "${{ inputs.package_ak3 }}" = "true" ] && ! ls artifacts/AK3_OP13_KSUN_CCTV18_clean_stocklike_v92_*_FLASH_THIS.zip >/dev/null 2>&1; then
echo "::error::Image built but AnyKernel3 flashable ZIP was not produced."
exit 1
fi
echo "✅ OP13 KSUN + CCTV18-only SUSFS clean stock-like daily-driver build completed."
echo "✅ Fixed AnyKernel3 boot partition detection: BLOCK=boot, IS_SLOT_DEVICE=auto, SLOT_SELECT=active."
echo "✅ No WildKernels/TheWildJames SUSFS patch tree was used."