From ebfac2cefe23a6d2902bac3528cbd93ed3d4239e Mon Sep 17 00:00:00 2001 From: Jordan Ye <79342877+Jordan231111@users.noreply.github.com> Date: Sun, 31 May 2026 10:15:18 -0400 Subject: [PATCH 1/3] CI: replace bogus Compile-and-Release with real Windows tests The old build-and-release.yml g++-compiled Magisk.cpp (deleted, so it always failed) and, on tag push, ran a release step that would clobber hand-cut releases with nonexistent magisk.exe / NewblueStacksRoot.cmd. Replace it with .github/workflows/tests.yml (push/PR to main + manual): runs tests/Run-Tests.ps1 and tests/Run-Resolve-Tests.ps1 on windows-latest via 'powershell -File' (Windows PowerShell 5.1, exactly as the .cmd does), and a new tests/Check-Embedded-Sync.ps1 that fails if the engine/orchestrator embedded in blueStackRoot.cmd drift from tools\bsr_engine.ps1 / tools\bsr_magisk.ps1. No compiling, no releasing. --- .github/workflows/build-and-release.yml | 64 ------------------------- .github/workflows/tests.yml | 49 +++++++++++++++++++ tests/Check-Embedded-Sync.ps1 | 46 ++++++++++++++++++ todolist.md | 6 +++ 4 files changed, 101 insertions(+), 64 deletions(-) delete mode 100644 .github/workflows/build-and-release.yml create mode 100644 .github/workflows/tests.yml create mode 100644 tests/Check-Embedded-Sync.ps1 diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml deleted file mode 100644 index 65dc253..0000000 --- a/.github/workflows/build-and-release.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Compile and Release - -on: - push: - tags: - - '*' - workflow_dispatch: - inputs: - tag: - description: 'Tag for the release (e.g. v1.0.0)' - required: true - -# Add permissions to fix the 403 Forbidden error -permissions: - contents: write - packages: read - -jobs: - build: - runs-on: windows-latest - env: - RELEASE_TAG: ${{ github.event.inputs.tag || github.ref_name }} - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - # Add caching for faster builds - - name: Cache MinGW - uses: actions/cache@v4 - id: cache - with: - path: C:\winlibs - key: ${{ runner.os }}-mingw-14.2.0 - - - name: Download winlibs (GCC 14.1.0) - if: steps.cache.outputs.cache-hit != 'true' - run: | - Invoke-WebRequest -Uri "https://github.com/brechtsanders/winlibs_mingw/releases/download/14.2.0posix-19.1.7-12.0.0-msvcrt-r3/winlibs-x86_64-posix-seh-gcc-14.2.0-mingw-w64msvcrt-12.0.0-r3.zip" -OutFile winlibs.zip - 7z x winlibs.zip -oC:\winlibs - - - name: Add winlibs to PATH - run: echo "C:\winlibs\mingw64\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - # Add optimization flags to the compilation - - name: Compile C++ file with optimizations - run: g++ Magisk.cpp -o magisk.exe -O3 -s -DNDEBUG - - # Improved Create Release step - - name: Create GitHub Release - uses: softprops/action-gh-release@v2 - with: - tag_name: ${{ env.RELEASE_TAG }} - name: "BlueStacks Root ${{ env.RELEASE_TAG }}" - body: | - BlueStacks Root Tool Release ${{ env.RELEASE_TAG }} - - ## Files: - - `magisk.exe`: Compiled binary for rooting BlueStacks - - `NewblueStacksRoot.cmd`: Optimized script for rooting BlueStacks - files: | - magisk.exe - NewblueStacksRoot.cmd - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..24cc833 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,49 @@ +name: tests + +# Runs the PowerShell unit/integration tests on Windows and verifies the single-file build is in +# sync. No compiling, no auto-releasing -- releases are cut by hand. Replaces the old +# "Compile and Release" workflow, which built a since-deleted Magisk.cpp and could clobber releases. + +on: + push: + branches: [ main ] + paths-ignore: + - '**.md' + - 'docs/**' + - 'archive/**' + - 'recovered/**' + - 'LICENSE' + pull_request: + branches: [ main ] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: tests-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + name: Windows PowerShell tests + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + # The .cmd ships the engine + orchestrator embedded; make sure they match tools\*.ps1. + - name: Embedded build in sync with tools/ + shell: cmd + run: powershell -NoProfile -ExecutionPolicy Bypass -File tests\Check-Embedded-Sync.ps1 + + # Core engine: integrity patch, .bstk disk-mode, conf root flags, su round-trip, bootstrap. + # (Invoked via powershell.exe -File exactly as blueStackRoot.cmd does, i.e. Windows PowerShell 5.1.) + - name: Engine unit / integration tests + shell: cmd + run: powershell -NoProfile -ExecutionPolicy Bypass -File tests\Run-Tests.ps1 + + # Nothing-hardcoded guarantees: custom install/data paths + adb port (5555 is not assumed). + - name: Path + adb-port resolution tests + shell: cmd + run: powershell -NoProfile -ExecutionPolicy Bypass -File tests\Run-Resolve-Tests.ps1 diff --git a/tests/Check-Embedded-Sync.ps1 b/tests/Check-Embedded-Sync.ps1 new file mode 100644 index 0000000..3f26983 --- /dev/null +++ b/tests/Check-Embedded-Sync.ps1 @@ -0,0 +1,46 @@ +<# + Check-Embedded-Sync.ps1 -- CI guard for the single-file build. + + blueStackRoot.cmd carries the engine and the Magisk orchestrator embedded between marker lines. + They are authored in tools\bsr_engine.ps1 / tools\bsr_magisk.ps1 and spliced in by tools\reembed.ps1. + If someone edits a tools\*.ps1 without re-running reembed, the .cmd silently ships stale logic. + + This test extracts the embedded blocks exactly like the .cmd does at run time and compares them to + the tools\ sources (newline-normalised). Exit code 1 on any drift, 0 when in sync. + + Usage: powershell -NoProfile -ExecutionPolicy Bypass -File tests\Check-Embedded-Sync.ps1 +#> +$ErrorActionPreference = 'Stop' +$here = if ($PSScriptRoot) { $PSScriptRoot } elseif ($PSCommandPath) { Split-Path -Parent $PSCommandPath } else { (Get-Location).Path } +$repo = Split-Path -Parent $here +$cmd = Join-Path $repo 'blueStackRoot.cmd' +if (-not (Test-Path -LiteralPath $cmd)) { throw "blueStackRoot.cmd not found: $cmd" } +$t = [IO.File]::ReadAllText($cmd) + +function Norm([string]$s) { ($s -replace "`r`n", "`n").TrimEnd("`n", " ", "`t") } +function Extract([string]$tag) { + $b = '__BSR_' + $tag + '_' + 'BEGIN__'; $e = '__BSR_' + $tag + '_' + 'END__' + $i = $t.IndexOf($b); $j = $t.IndexOf($e) + if ($i -lt 0 -or $j -le $i) { throw "embedded block $tag not found in blueStackRoot.cmd" } + $i = $t.IndexOf([char]10, $i) + 1 + return $t.Substring($i, $j - $i) +} + +$fail = 0 +foreach ($p in @(@('ENGINE', 'tools\bsr_engine.ps1'), @('MAGISK', 'tools\bsr_magisk.ps1'))) { + $src = Join-Path $repo $p[1] + if (-not (Test-Path -LiteralPath $src)) { Write-Host " [FAIL] source missing: $($p[1])" -ForegroundColor Red; $fail++; continue } + $emb = Norm (Extract $p[0]) + $on = Norm ([IO.File]::ReadAllText($src)) + if ($emb -eq $on) { + Write-Host (" [PASS] {0,-7} embedded == {1} ({2} chars)" -f $p[0], $p[1], $emb.Length) -ForegroundColor Green + } else { + Write-Host (" [FAIL] {0,-7} embedded != {1} (embedded {2}, source {3} chars) -- run tools\reembed.ps1" -f $p[0], $p[1], $emb.Length, $on.Length) -ForegroundColor Red + $fail++ + } +} + +Write-Host "" +if ($fail) { Write-Host "RESULT: embedded blocks OUT OF SYNC ($fail) -- re-run tools\reembed.ps1 and commit blueStackRoot.cmd" -ForegroundColor Red; exit 1 } +Write-Host "RESULT: embedded blocks in sync with tools\ sources" -ForegroundColor Green +exit 0 diff --git a/todolist.md b/todolist.md index 7bf51a9..c6655c6 100644 --- a/todolist.md +++ b/todolist.md @@ -38,6 +38,12 @@ column below; coloured via PowerShell `Write-Host` so box-drawing renders regardless of code page. Typos re-prompt instantly (`:prompt`) instead of a full redraw. (Menu lives in the batch portion, so no re-embed is needed for these changes.) +- [x] **CI replaced:** dropped the bogus `Compile and Release` workflow (it `g++`-compiled a since-deleted + `Magisk.cpp` -- always failing -- and its release step would have clobbered hand-cut releases with + nonexistent `magisk.exe`/`NewblueStacksRoot.cmd`). New `.github/workflows/tests.yml` runs on push/PR + to `main`: `tests/Run-Tests.ps1` (28) + `tests/Run-Resolve-Tests.ps1` (22) on windows-latest, plus a + new `tests/Check-Embedded-Sync.ps1` guarding that the embedded engine/orchestrator still match + `tools\bsr_engine.ps1`/`bsr_magisk.ps1`. No auto-compile, no auto-release (releases are cut by hand). ## Open / nice-to-have - [ ] optional: dedicated per-instance Root.vhd (separate VHD + UUID) for a *bit-pristine* `/system` on From 96b88b61bc73ee867d4b9dbb6392074c72850dd7 Mon Sep 17 00:00:00 2001 From: Jordan Ye <79342877+Jordan231111@users.noreply.github.com> Date: Sun, 31 May 2026 10:19:32 -0400 Subject: [PATCH 2/3] tests: normalize 8.3 short paths in Run-Resolve-Tests On CI $env:TEMP is the 8.3 short form (C:\Users\RUNNER~1\...); the engine resolves the on-disk Root.vhd and returns the long path, so the exact-string VHD assertion mismatched purely on short-vs-long. Expand the fake DataDir root to its long form (GetLongPathName) at creation so all expected paths match what the engine returns. No product change. --- tests/Run-Resolve-Tests.ps1 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/Run-Resolve-Tests.ps1 b/tests/Run-Resolve-Tests.ps1 index 01a6974..aaee014 100644 --- a/tests/Run-Resolve-Tests.ps1 +++ b/tests/Run-Resolve-Tests.ps1 @@ -29,6 +29,18 @@ function Eq([string]$name, $expected, $actual) { Ok $name ("$expected" -eq "$act # Run the engine as a child process (exactly how blueStackRoot.cmd calls it). function Eng([string[]]$a) { & powershell -NoProfile -ExecutionPolicy Bypass -File $Engine @a 2>&1 } +# Expand any 8.3 short path component (e.g. CI's C:\Users\RUNNER~1\... for 'runneradmin') to its long +# form. The engine resolves the on-disk Root.vhd, so it returns the long path; without this the expected +# string (built from $env:TEMP, which the runner reports short) would mismatch purely on 8.3 vs long. +Add-Type -ErrorAction SilentlyContinue -Name Native -Namespace BSR -MemberDefinition ' +[System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] +public static extern uint GetLongPathName(string lpszShortPath, System.Text.StringBuilder lpszLongPath, uint cchBuffer);' +function Long([string]$p) { + if (-not $p) { return $p } + try { $sb = New-Object System.Text.StringBuilder 1024; $n = [BSR.Native]::GetLongPathName($p, $sb, 1024); if ($n -gt 0 -and $n -lt 1024) { return $sb.ToString() } } catch { } + return $p +} + # --------------------------------------------------------------------------- # Build a throwaway BlueStacks-shaped DataDir at a NON-default (custom) location. # --------------------------------------------------------------------------- @@ -47,7 +59,7 @@ function New-FakeData([string]$instance, [hashtable]$confKeys, [string]$tag = 'r '' [IO.File]::WriteAllText((Join-Path $eng "$instance.bstk"), $bstk) [IO.File]::WriteAllBytes((Join-Path $eng 'Root.vhd'), (New-Object byte[] 64)) - return $root + return (Long $root) # long-path form so expected paths match the engine's disk-resolved VHD path } function Resolve-Map([string]$dataDir, [string]$base) { $out = Eng @('-Action', 'Resolve', '-DataDir', $dataDir, '-Base', $base) From c554b7b03dfb5da06a1074bc7eeab5555707ef55 Mon Sep 17 00:00:00 2001 From: Jordan Ye <79342877+Jordan231111@users.noreply.github.com> Date: Sun, 31 May 2026 10:20:51 -0400 Subject: [PATCH 3/3] CI: bump actions/checkout v4 -> v5 (Node 24; clears Node 20 deprecation) --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 24cc833..989bec0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -30,7 +30,7 @@ jobs: runs-on: windows-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 # The .cmd ships the engine + orchestrator embedded; make sure they match tools\*.ps1. - name: Embedded build in sync with tools/