From f203149f4f0d62c8c6ac78257025091716a8d2c1 Mon Sep 17 00:00:00 2001 From: WaterRain <109326062+CATMIAOZHI@users.noreply.github.com> Date: Tue, 4 Aug 2026 22:58:00 +0000 Subject: [PATCH] =?UTF-8?q?security:=20=E4=BF=AE=E5=A4=8D=20CI/Release=20w?= =?UTF-8?q?orkflow=20=E7=AD=BE=E5=90=8D=E5=87=AD=E6=8D=AE=E9=A3=8E?= =?UTF-8?q?=E9=99=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 所有 action 引用改为 commit SHA pin(checkout/setup-java/setup-android/action-gh-release/upload-artifact) - build.gradle.kts 移除硬编码签名密码 fallback,改用 takeIf 防御 null 和空字符串 - release.yml 构建完成后清理 release.jks(if: always()) - ci.yml 补充最小权限声明 permissions: contents: read --- .github/workflows/ci.yml | 29 ++++++++++++++++------------- .github/workflows/release.yml | 11 +++++++---- app/build.gradle.kts | 15 ++++++++++++--- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0947191..9e674a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,17 +5,20 @@ on: branches: [main] pull_request: +permissions: + contents: read + jobs: test: name: Unit Tests & Lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4 with: java-version: '17' distribution: 'temurin' - - uses: android-actions/setup-android@v3 + - uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3 with: packages: 'platforms;android-35 build-tools;35.0.0' @@ -27,7 +30,7 @@ jobs: - name: Upload test results if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: unit-test-results path: app/build/test-results/testDebugUnitTest/*.xml @@ -38,7 +41,7 @@ jobs: - name: Upload lint results if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: lint-results path: app/build/reports/lint-results-debug.* @@ -49,12 +52,12 @@ jobs: runs-on: ubuntu-latest needs: test steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4 with: java-version: '17' distribution: 'temurin' - - uses: android-actions/setup-android@v3 + - uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3 with: packages: 'platforms;android-35 build-tools;35.0.0' @@ -65,7 +68,7 @@ jobs: run: ./gradlew assembleDebug - name: Upload Debug APK - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: debug-apk path: app/build/outputs/apk/debug/app-debug.apk @@ -76,12 +79,12 @@ jobs: runs-on: ubuntu-latest needs: test steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4 with: java-version: '17' distribution: 'temurin' - - uses: android-actions/setup-android@v3 + - uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3 with: packages: 'platforms;android-35 build-tools;35.0.0' @@ -119,7 +122,7 @@ jobs: echo "✅ APK integrity verified: manifest + arsc + res/ all present" - name: Upload Release APK - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: release-apk path: app/build/outputs/apk/release/app-release.apk diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 07617c7..551c784 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,12 +10,12 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4 with: java-version: '17' distribution: 'temurin' - - uses: android-actions/setup-android@v3 + - uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3 with: packages: 'platforms;android-35 build-tools;35.0.0' - name: Decode Keystore @@ -28,10 +28,13 @@ jobs: run: | chmod +x gradlew ./gradlew assembleRelease + - name: Cleanup keystore (always run for security) + run: rm -f release.jks + if: always() - name: Rename & Release run: | cp app/build/outputs/apk/release/app-release.apk "RainyToken-${GITHUB_REF#refs/tags/}.apk" - - uses: softprops/action-gh-release@v2 + - uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2 with: name: "🎉 RainyToken ${{ github.ref_name }}" files: RainyToken-${{ github.ref_name }}.apk diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b4ad821..5d63054 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -32,9 +32,18 @@ android { val keystoreFile = rootProject.file("release.jks") if (keystoreFile.exists()) { storeFile = keystoreFile - storePassword = System.getenv("KEYSTORE_PASSWORD") ?: "RainyToken2026!" - keyAlias = System.getenv("KEYSTORE_ALIAS") ?: "rainy" - keyPassword = System.getenv("KEY_PASSWORD") ?: "RainyToken2026!" + // 凭据必须通过环境变量注入;缺失或为空时直接报错,不提供任何隐式 fallback + // 注意:GitHub Actions 中未设置的 secret 会被替换为空字符串(非 null), + // 因此用 takeIf { isNotBlank() } 同时防御 null 和空字符串 + storePassword = System.getenv("KEYSTORE_PASSWORD") + ?.takeIf { it.isNotBlank() } + ?: throw GradleException("KEYSTORE_PASSWORD env var not set or empty — cannot sign release") + keyAlias = System.getenv("KEYSTORE_ALIAS") + ?.takeIf { it.isNotBlank() } + ?: throw GradleException("KEYSTORE_ALIAS env var not set or empty — cannot sign release") + keyPassword = System.getenv("KEY_PASSWORD") + ?.takeIf { it.isNotBlank() } + ?: throw GradleException("KEY_PASSWORD env var not set or empty — cannot sign release") } else { // 仅在 CI 环境中 fallback 到 debug keystore(用于编译/资源完整性验证) // 本地构建缺少 release.jks 时直接报错,避免静默生成 debug 签名的 Release APK