1- name : Windows quality gate
1+ name : Windows and Android quality gate
22
33on :
44 push :
6969 - name : Test the fail-closed translation-key audit
7070 run : pnpm run test:i18n
7171
72+ - name : Test the fail-closed Android libbox release-evidence generator
73+ run : pnpm run test:license-android-libbox-release
74+
75+ - name : Test the fail-closed Windows sing-box release-evidence generator
76+ run : pnpm run test:license-windows-sing-box-release
77+
78+ - name : Test the sysproxy corresponding-source evidence verifier
79+ run : pnpm run test:license-sysproxy
80+
7281 - name : Test final release extraction safety logic
7382 run : pnpm run test:verify-release
7483
@@ -85,3 +94,173 @@ jobs:
8594 env :
8695 AIKOBOX_ELECTRON_SMOKE_TOKEN : aikobox-github-windows-electron-smoke-v1
8796 run : pnpm run smoke:electron:ci
97+
98+ android-quality :
99+ name : Analyze, test, and compile (Android arm64-v8a)
100+ runs-on : ubuntu-latest
101+ timeout-minutes : 75
102+ env :
103+ ANDROID_COMPILE_SDK : ' 36'
104+ ANDROID_NDK_VERSION : 28.0.13004108
105+ ANDROID_APP_NDK_VERSION : 28.2.13676358
106+ ANDROID_BUILD_TOOLS : 36.0.0
107+ FLUTTER_VERSION : 3.44.4
108+ GO_VERSION : 1.24.7
109+ LIBBOX_COMMIT : 25a600db24f7680ad9806ce5427bd0ab8afe1114
110+ LIBBOX_GOMOBILE_VERSION : v0.1.12
111+ ANDROID_APPLICATION_ID : com.aikobox.app
112+
113+ steps :
114+ - name : Check out source
115+ uses : actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
116+ with :
117+ persist-credentials : false
118+
119+ - name : Enable pnpm
120+ uses : pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
121+ with :
122+ version : 10.27.0
123+ run_install : false
124+
125+ - name : Set up Node.js
126+ uses : actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
127+ with :
128+ node-version : 22
129+ cache : pnpm
130+
131+ - name : Install verifier dependencies
132+ run : pnpm install --frozen-lockfile --ignore-scripts
133+
134+ - name : Verify the cross-platform release version contract
135+ shell : bash
136+ run : |
137+ set -euo pipefail
138+ node scripts/release-version-contract.mjs
139+ node --test scripts/release-version-contract.test.mjs
140+
141+ - name : Set up OpenJDK 17
142+ uses : actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5
143+ with :
144+ distribution : temurin
145+ java-version : ' 17'
146+ cache : gradle
147+
148+ - name : Set up Go 1.24.7
149+ uses : actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
150+ with :
151+ go-version : 1.24.7
152+ cache : false
153+
154+ - name : Install fixed Android SDK and NDK
155+ shell : bash
156+ run : |
157+ set -euo pipefail
158+ yes | sdkmanager --licenses >/dev/null
159+ sdkmanager \
160+ "platforms;android-${ANDROID_COMPILE_SDK}" \
161+ "build-tools;${ANDROID_BUILD_TOOLS}" \
162+ "ndk;${ANDROID_NDK_VERSION}" \
163+ "ndk;${ANDROID_APP_NDK_VERSION}"
164+ echo "ANDROID_NDK_HOME=${ANDROID_SDK_ROOT}/ndk/${ANDROID_NDK_VERSION}" >> "$GITHUB_ENV"
165+ echo "${ANDROID_SDK_ROOT}/build-tools/${ANDROID_BUILD_TOOLS}" >> "$GITHUB_PATH"
166+
167+ - name : Install Flutter 3.44.4
168+ shell : bash
169+ run : |
170+ set -euo pipefail
171+ metadata="$RUNNER_TEMP/flutter-releases.json"
172+ archive="$RUNNER_TEMP/flutter.tar.xz"
173+ curl --fail --location --retry 3 \
174+ https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json \
175+ --output "$metadata"
176+ archive_path="$(jq -r --arg version "$FLUTTER_VERSION" \
177+ '.releases[] | select(.channel == "stable" and .version == $version) | .archive' \
178+ "$metadata" | head -n1)"
179+ archive_sha="$(jq -r --arg version "$FLUTTER_VERSION" \
180+ '.releases[] | select(.channel == "stable" and .version == $version) | .sha256' \
181+ "$metadata" | head -n1)"
182+ test "$archive_path" = "stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz"
183+ test "$archive_sha" != "null" && test -n "$archive_sha"
184+ curl --fail --location --retry 3 \
185+ "https://storage.googleapis.com/flutter_infra_release/releases/${archive_path}" \
186+ --output "$archive"
187+ printf '%s %s\n' "$archive_sha" "$archive" | sha256sum --check -
188+ tar -xJf "$archive" -C "$RUNNER_TEMP"
189+ echo "$RUNNER_TEMP/flutter/bin" >> "$GITHUB_PATH"
190+
191+ - name : Verify fixed toolchain versions
192+ shell : bash
193+ run : |
194+ set -euo pipefail
195+ java --version 2>&1 | tee /tmp/java-version
196+ grep -E 'openjdk 17(\.| )' /tmp/java-version
197+ test "$(go env GOVERSION)" = "go${GO_VERSION}"
198+ flutter --version --machine > /tmp/flutter-version.json
199+ test "$(jq -r .frameworkVersion /tmp/flutter-version.json)" = "${FLUTTER_VERSION}"
200+ test -f "${ANDROID_NDK_HOME}/source.properties"
201+ grep -F "Pkg.Revision = ${ANDROID_NDK_VERSION}" "${ANDROID_NDK_HOME}/source.properties"
202+ grep -F "Pkg.Revision = ${ANDROID_APP_NDK_VERSION}" \
203+ "${ANDROID_SDK_ROOT}/ndk/${ANDROID_APP_NDK_VERSION}/source.properties"
204+
205+ - name : Build the locked arm64 libbox AAR
206+ shell : bash
207+ run : |
208+ set -euo pipefail
209+ git clone --filter=blob:none https://github.com/SagerNet/sing-box.git "$RUNNER_TEMP/sing-box"
210+ git -C "$RUNNER_TEMP/sing-box" checkout --detach "${LIBBOX_COMMIT}"
211+ test "$(git -C "$RUNNER_TEMP/sing-box" rev-parse HEAD)" = "${LIBBOX_COMMIT}"
212+ go install "github.com/sagernet/gomobile/cmd/gomobile@${LIBBOX_GOMOBILE_VERSION}"
213+ go install "github.com/sagernet/gomobile/cmd/gobind@${LIBBOX_GOMOBILE_VERSION}"
214+ (
215+ cd "$RUNNER_TEMP/sing-box"
216+ go run ./cmd/internal/build_libbox -target android -platform android/arm64
217+ )
218+ mkdir -p apps/android/android/app/libs
219+ cp "$RUNNER_TEMP/sing-box/libbox.aar" apps/android/android/app/libs/libbox.aar
220+ unzip -Z1 apps/android/android/app/libs/libbox.aar | tee /tmp/libbox-aar.txt
221+ test "$(grep -Ec '^jni/[^/]+/libbox\.so$' /tmp/libbox-aar.txt)" -eq 1
222+ grep -Fx 'jni/arm64-v8a/libbox.so' /tmp/libbox-aar.txt
223+ test -z "$(grep -E '^jni/[^/]+/.*\.so$' /tmp/libbox-aar.txt | grep -v '^jni/arm64-v8a/' || true)"
224+
225+ - name : Analyze and test Flutter application
226+ working-directory : apps/android
227+ shell : bash
228+ run : |
229+ set -euo pipefail
230+ chmod +x android/gradlew
231+ flutter pub get --enforce-lockfile
232+ flutter analyze --fatal-infos --fatal-warnings
233+ flutter test
234+ ./android/gradlew -p android lintDebug testDebugUnitTest
235+
236+ - name : Build signed debug APK for the quality gate
237+ working-directory : apps/android
238+ shell : bash
239+ run : |
240+ set -euo pipefail
241+ version="$(jq -r .version ../../package.json)"
242+ version_code="$(sed -n 's/^version: [^+]*+\([0-9][0-9]*\)$/\1/p' pubspec.yaml)"
243+ test -n "$version_code"
244+ flutter build apk \
245+ --debug \
246+ --target-platform android-arm64 \
247+ --build-name "$version" \
248+ --build-number "$version_code"
249+ apk="$(realpath build/app/outputs/flutter-apk/app-debug.apk)"
250+ sidecar="${apk}.sha256"
251+ digest="$(sha256sum "$apk" | cut -d' ' -f1)"
252+ printf '%s %s\n' "$digest" "$(basename "$apk")" > "$sidecar"
253+ signer_output="$(apksigner verify --verbose --print-certs "$apk")"
254+ certificate="$(printf '%s\n' "$signer_output" | sed -n 's/^Signer #1 certificate SHA-256 digest: //p')"
255+ node ../../scripts/verify-android-release.mjs \
256+ --apk "$apk" \
257+ --sha256 "$sidecar" \
258+ --apkanalyzer "$(command -v apkanalyzer)" \
259+ --apksigner "$(command -v apksigner)" \
260+ --application-id "$ANDROID_APPLICATION_ID" \
261+ --certificate-sha256 "$certificate" \
262+ --version "$version" \
263+ --version-code "$version_code"
264+
265+ - name : Test the Android release verifier
266+ run : node --test scripts/verify-android-release.test.mjs
0 commit comments