From a763e56842f1580b37c8ca3a60ec8ec72c74eb50 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 04:28:22 +0000 Subject: [PATCH 1/7] chore: harden GitHub workflows --- .github/workflows/ci.yml | 20 ++++---- .github/workflows/codeql.yml | 63 +++++++++++++++++++++++++ .github/workflows/dependency-review.yml | 28 +++++++++++ .github/workflows/release.yml | 41 +++++++++------- 4 files changed, 128 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/dependency-review.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 774b6a67..46f454ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,10 +31,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Setup .NET SDK - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5 with: global-json-file: global.json cache: true @@ -89,7 +91,7 @@ jobs: - name: Upload test results if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: test-results path: artifacts/test-results @@ -97,7 +99,7 @@ jobs: - name: Upload MSBuild binlogs if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: msbuild-binlogs path: artifacts/binlogs @@ -123,10 +125,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Setup .NET SDK - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5 with: global-json-file: global.json cache: true @@ -176,7 +180,7 @@ jobs: } - name: Upload packaged CLI - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: luotsi-cli-${{ matrix.rid }} path: artifacts/packages/luotsi-cli-${{ matrix.rid }}.${{ matrix.archive_ext }} @@ -184,7 +188,7 @@ jobs: - name: Upload publish binlog if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: publish-binlog-${{ matrix.rid }} path: | diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..656acec4 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,63 @@ +name: CodeQL + +on: + push: + branches: + - main + - master + pull_request: + schedule: + - cron: "27 4 * * 1" + +permissions: + actions: read + contents: read + security-events: write + +concurrency: + group: codeql-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + DOTNET_NOLOGO: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + +jobs: + analyze: + name: Analyze C# + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Setup .NET SDK + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5 + with: + global-json-file: global.json + cache: true + cache-dependency-path: | + **/*.csproj + **/packages.lock.json + global.json + + - name: Initialize CodeQL + uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4 + with: + languages: csharp + build-mode: manual + + - name: Restore + shell: bash + run: dotnet restore Luotsi.sln --locked-mode + + - name: Build + shell: bash + run: dotnet build Luotsi.sln --configuration Release --no-restore + + - name: Analyze + uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 00000000..d49cca6d --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,28 @@ +name: Dependency Review + +on: + pull_request: + +permissions: + contents: read + +concurrency: + group: dependency-review-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + dependency-review: + name: Review dependency changes + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Dependency review + uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 + with: + fail-on-severity: high diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7e9227f1..1dd66a14 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,11 +11,6 @@ on: required: true type: string -permissions: - contents: write - id-token: write - attestations: write - concurrency: group: release-${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} cancel-in-progress: false @@ -33,6 +28,8 @@ jobs: name: Validate release tag runs-on: ubuntu-latest timeout-minutes: 5 + permissions: + contents: read outputs: tag: ${{ steps.version.outputs.tag }} version: ${{ steps.version.outputs.version }} @@ -40,9 +37,10 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 0 + persist-credentials: false - name: Resolve version id: version @@ -87,15 +85,18 @@ jobs: runs-on: windows-latest needs: validate-tag timeout-minutes: 20 + permissions: + contents: read steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ needs.validate-tag.outputs.tag }} + persist-credentials: false - name: Setup .NET SDK - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5 with: global-json-file: global.json cache: true @@ -133,7 +134,7 @@ jobs: - name: Upload validation diagnostics if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: release-validation-diagnostics path: | @@ -148,6 +149,8 @@ jobs: - validate-tag - validate timeout-minutes: 20 + permissions: + contents: read strategy: fail-fast: false matrix: @@ -167,12 +170,13 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ needs.validate-tag.outputs.tag }} + persist-credentials: false - name: Setup .NET SDK - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5 with: global-json-file: global.json cache: true @@ -238,7 +242,7 @@ jobs: "$($hash.Hash.ToLowerInvariant()) $(Split-Path $archive -Leaf)" | Set-Content "$archive.sha256" -Encoding ascii - name: Upload package - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: release-package-${{ matrix.rid }} path: | @@ -247,7 +251,7 @@ jobs: - name: Upload publish binlog if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: release-publish-binlog-${{ matrix.rid }} path: | @@ -263,15 +267,20 @@ jobs: - validate - package timeout-minutes: 10 + permissions: + contents: write + id-token: write + attestations: write steps: - name: Checkout tag - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ needs.validate-tag.outputs.tag }} + persist-credentials: false - name: Download release packages - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: pattern: release-package-* path: release-assets @@ -295,7 +304,7 @@ jobs: cat SHA256SUMS - name: Attest release assets - uses: actions/attest-build-provenance@v4 + uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4 with: subject-path: | release-assets/*.zip From 6eacfd3241ab15da94de5959a5279df21cafdc00 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 04:31:17 +0000 Subject: [PATCH 2/7] chore: expand codeql workflow coverage --- .github/workflows/codeql.yml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 656acec4..08238588 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -25,9 +25,17 @@ env: jobs: analyze: - name: Analyze C# + name: Analyze ${{ matrix.language }} runs-on: ubuntu-latest timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - language: actions + build-mode: none + - language: csharp + build-mode: manual steps: - name: Checkout @@ -36,6 +44,7 @@ jobs: persist-credentials: false - name: Setup .NET SDK + if: matrix.language == 'csharp' uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5 with: global-json-file: global.json @@ -48,14 +57,16 @@ jobs: - name: Initialize CodeQL uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4 with: - languages: csharp - build-mode: manual + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} - name: Restore + if: matrix.language == 'csharp' shell: bash run: dotnet restore Luotsi.sln --locked-mode - name: Build + if: matrix.language == 'csharp' shell: bash run: dotnet build Luotsi.sln --configuration Release --no-restore From 31bd9c9561afcd84e659fcd8ac0c0285dde42e7e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 04:41:07 +0000 Subject: [PATCH 3/7] chore: pin NuGet source mapping and Gradle wrapper checksum --- .../gradle/wrapper/gradle-wrapper.properties | 1 + NuGet.config | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 NuGet.config diff --git a/Luotsi.ViewServer.Android/gradle/wrapper/gradle-wrapper.properties b/Luotsi.ViewServer.Android/gradle/wrapper/gradle-wrapper.properties index c61a118f..80d82296 100644 --- a/Luotsi.ViewServer.Android/gradle/wrapper/gradle-wrapper.properties +++ b/Luotsi.ViewServer.Android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip +distributionSha256Sum=2ab2958f2a1e51120c326cad6f385153bb11ee93b3c216c5fccebfdfbb7ec6cb networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/NuGet.config b/NuGet.config new file mode 100644 index 00000000..4e800bf6 --- /dev/null +++ b/NuGet.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + From 86805cf2c9af1ac963221b6cc8cfa9a11f02cbc4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 04:57:18 +0000 Subject: [PATCH 4/7] chore: resolve merge conflicts with main --- .github/workflows/ci.yml | 6 +----- .github/workflows/release.yml | 6 +----- .../gradle/wrapper/gradle-wrapper.properties | 4 ---- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e98dca7a..b1871636 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -281,12 +281,8 @@ jobs: - name: Upload publish binlog if: always() -<<<<<<< HEAD - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 -======= continue-on-error: true - uses: actions/upload-artifact@v7 ->>>>>>> origin/main + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: publish-binlog-${{ matrix.rid }} path: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d3caeaff..5f00cb2b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -422,12 +422,8 @@ jobs: - name: Upload publish binlog if: always() -<<<<<<< HEAD - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 -======= continue-on-error: true - uses: actions/upload-artifact@v7 ->>>>>>> origin/main + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: release-publish-binlog-${{ matrix.rid }} path: | diff --git a/Luotsi.ViewServer.Android/gradle/wrapper/gradle-wrapper.properties b/Luotsi.ViewServer.Android/gradle/wrapper/gradle-wrapper.properties index aa0f0260..ac0d302a 100644 --- a/Luotsi.ViewServer.Android/gradle/wrapper/gradle-wrapper.properties +++ b/Luotsi.ViewServer.Android/gradle/wrapper/gradle-wrapper.properties @@ -1,12 +1,8 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip -<<<<<<< HEAD distributionSha256Sum=2ab2958f2a1e51120c326cad6f385153bb11ee93b3c216c5fccebfdfbb7ec6cb -networkTimeout=10000 -======= networkTimeout=60000 ->>>>>>> origin/main validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 1b3ceac3f301d96cc6fd716a1a3a332c4f920a4d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 05:21:46 +0000 Subject: [PATCH 5/7] Include NuGet.config in setup-dotnet cache dependency paths --- .github/workflows/ci.yml | 2 ++ .github/workflows/codeql.yml | 1 + .github/workflows/release.yml | 2 ++ 3 files changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1871636..80fd7ada 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,7 @@ jobs: **/*.csproj **/packages.lock.json global.json + NuGet.config - name: SDK diagnostics shell: pwsh @@ -207,6 +208,7 @@ jobs: **/*.csproj **/packages.lock.json global.json + NuGet.config - name: Setup Java uses: actions/setup-java@v5 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 08238588..97e9f2c9 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -53,6 +53,7 @@ jobs: **/*.csproj **/packages.lock.json global.json + NuGet.config - name: Initialize CodeQL uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5f00cb2b..6089249c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -109,6 +109,7 @@ jobs: **/*.csproj **/packages.lock.json global.json + NuGet.config - name: Restore shell: pwsh @@ -226,6 +227,7 @@ jobs: **/*.csproj **/packages.lock.json global.json + NuGet.config - name: Setup Java uses: actions/setup-java@v5 From 75ea94bce441bda03732e4d374c9701dc68fb89f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 05:35:07 +0000 Subject: [PATCH 6/7] chore: disable codeql workflow file --- .github/workflows/{codeql.yml => codeql.yml.disabled} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{codeql.yml => codeql.yml.disabled} (100%) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml.disabled similarity index 100% rename from .github/workflows/codeql.yml rename to .github/workflows/codeql.yml.disabled From 8ae0ba93889e47cf3d70d00df95511a8aa88ff5f Mon Sep 17 00:00:00 2001 From: Slideep Date: Fri, 29 May 2026 14:55:57 +0300 Subject: [PATCH 7/7] Harden workflow action pins and Android helper build --- .github/workflows/ci.yml | 93 +++++++++++++---- .github/workflows/codeql.yml.disabled | 75 -------------- .github/workflows/pages.yml | 12 ++- .github/workflows/release.yml | 143 +++++++++++++++++--------- 4 files changed, 178 insertions(+), 145 deletions(-) delete mode 100644 .github/workflows/codeql.yml.disabled diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80fd7ada..f656b04a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -129,7 +129,7 @@ jobs: - name: Upload coverage report if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: coverage-report path: artifacts/coverage-report @@ -150,10 +150,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 cache: npm @@ -171,10 +173,66 @@ jobs: working-directory: website run: npm run build + android-helper: + name: Build Android view helper + runs-on: windows-latest + timeout-minutes: 20 + + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Setup Java + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 + with: + distribution: temurin + java-version: "17" + cache: gradle + + - name: Build Android helper APK + shell: pwsh + run: | + $wrapper = ".\Luotsi.ViewServer.Android\gradlew.bat" + $arguments = @("--no-daemon", "-p", "Luotsi.ViewServer.Android", ":app:assembleRelease") + $maxAttempts = 3 + $exitCode = 0 + + for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) { + & $wrapper @arguments + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + break + } + + if ($attempt -eq $maxAttempts) { + exit $exitCode + } + + $delaySeconds = 20 * $attempt + Write-Warning "Android helper build failed with exit code $exitCode. Retrying in $delaySeconds seconds ($attempt/$maxAttempts)." + Start-Sleep -Seconds $delaySeconds + } + + $apk = "Luotsi.ViewServer.Android/app/build/outputs/apk/release/app-release.apk" + if (!(Test-Path -LiteralPath $apk)) { + throw "Android view helper release APK was not produced at $apk." + } + + - name: Upload Android helper APK + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: android-helper-apk + path: Luotsi.ViewServer.Android/app/build/outputs/apk/release/app-release.apk + if-no-files-found: error + publish: name: Publish ${{ matrix.rid }} runs-on: windows-latest - needs: validate + needs: + - validate + - android-helper timeout-minutes: 20 strategy: fail-fast: false @@ -210,24 +268,22 @@ jobs: global.json NuGet.config - - name: Setup Java - uses: actions/setup-java@v5 - with: - distribution: temurin - java-version: "17" - cache: gradle - - name: Verify locked restore shell: pwsh run: dotnet restore $env:SOLUTION --locked-mode /bl:artifacts/binlogs/publish-restore-${{ matrix.rid }}.binlog - - name: Build Android view helper + - name: Download Android view helper + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: android-helper-apk + path: Luotsi.ViewServer.Android/app/build/outputs/apk/release + + - name: Verify Android view helper shell: pwsh run: | - $wrapper = ".\Luotsi.ViewServer.Android\gradlew.bat" - & $wrapper -p Luotsi.ViewServer.Android :app:assembleRelease - if ($LASTEXITCODE -ne 0) { - exit $LASTEXITCODE + $helper = "Luotsi.ViewServer.Android/app/build/outputs/apk/release/app-release.apk" + if (!(Test-Path -LiteralPath $helper)) { + throw "Downloaded Android view helper APK is missing: $helper" } - name: Stage FFmpeg native libraries @@ -298,14 +354,15 @@ jobs: needs: - validate - website + - android-helper - publish if: always() steps: - name: Check required jobs shell: bash run: | - if [[ "${{ needs.validate.result }}" != "success" || "${{ needs.website.result }}" != "success" || "${{ needs.publish.result }}" != "success" ]]; then - echo "CI failed: validate=${{ needs.validate.result }}, website=${{ needs.website.result }}, publish=${{ needs.publish.result }}" + if [[ "${{ needs.validate.result }}" != "success" || "${{ needs.website.result }}" != "success" || "${{ needs.android-helper.result }}" != "success" || "${{ needs.publish.result }}" != "success" ]]; then + echo "CI failed: validate=${{ needs.validate.result }}, website=${{ needs.website.result }}, android-helper=${{ needs.android-helper.result }}, publish=${{ needs.publish.result }}" exit 1 fi echo "CI passed." diff --git a/.github/workflows/codeql.yml.disabled b/.github/workflows/codeql.yml.disabled deleted file mode 100644 index 97e9f2c9..00000000 --- a/.github/workflows/codeql.yml.disabled +++ /dev/null @@ -1,75 +0,0 @@ -name: CodeQL - -on: - push: - branches: - - main - - master - pull_request: - schedule: - - cron: "27 4 * * 1" - -permissions: - actions: read - contents: read - security-events: write - -concurrency: - group: codeql-${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - DOTNET_NOLOGO: true - DOTNET_CLI_TELEMETRY_OPTOUT: true - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - -jobs: - analyze: - name: Analyze ${{ matrix.language }} - runs-on: ubuntu-latest - timeout-minutes: 30 - strategy: - fail-fast: false - matrix: - include: - - language: actions - build-mode: none - - language: csharp - build-mode: manual - - steps: - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - - name: Setup .NET SDK - if: matrix.language == 'csharp' - uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5 - with: - global-json-file: global.json - cache: true - cache-dependency-path: | - **/*.csproj - **/packages.lock.json - global.json - NuGet.config - - - name: Initialize CodeQL - uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4 - with: - languages: ${{ matrix.language }} - build-mode: ${{ matrix.build-mode }} - - - name: Restore - if: matrix.language == 'csharp' - shell: bash - run: dotnet restore Luotsi.sln --locked-mode - - - name: Build - if: matrix.language == 'csharp' - shell: bash - run: dotnet build Luotsi.sln --configuration Release --no-restore - - - name: Analyze - uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4 diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 5269a0ca..901748d4 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -23,17 +23,19 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 cache: npm cache-dependency-path: website/package-lock.json - name: Configure GitHub Pages - uses: actions/configure-pages@v6 + uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6 - name: Install website dependencies working-directory: website @@ -44,7 +46,7 @@ jobs: run: npm run build - name: Upload Pages artifact - uses: actions/upload-pages-artifact@v5 + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5 with: path: website/dist @@ -59,4 +61,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v5 \ No newline at end of file + uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6089249c..49a0745f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -179,37 +179,19 @@ jobs: - name: Upload coverage report if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: release-coverage-report path: artifacts/coverage-report if-no-files-found: ignore - package: - name: Package ${{ matrix.rid }} - runs-on: ${{ matrix.runner }} - needs: - - validate-tag - - validate + android-helper: + name: Build Android view helper + runs-on: windows-latest + needs: validate-tag timeout-minutes: 20 permissions: contents: read - strategy: - fail-fast: false - matrix: - include: - - rid: win-x64 - archive_ext: zip - runner: windows-latest - - rid: linux-x64 - archive_ext: tar.gz - runner: ubuntu-latest - - rid: osx-x64 - archive_ext: tar.gz - runner: ubuntu-latest - - rid: osx-arm64 - archive_ext: tar.gz - runner: ubuntu-latest steps: - name: Checkout @@ -218,29 +200,14 @@ jobs: ref: ${{ needs.validate-tag.outputs.tag }} persist-credentials: false - - name: Setup .NET SDK - uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5 - with: - global-json-file: global.json - cache: true - cache-dependency-path: | - **/*.csproj - **/packages.lock.json - global.json - NuGet.config - - name: Setup Java - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: distribution: temurin java-version: "17" cache: gradle - - name: Verify locked restore - shell: pwsh - run: dotnet restore $env:SOLUTION --locked-mode /bl:artifacts/binlogs/release-publish-restore-${{ matrix.rid }}.binlog - - - name: Build Android view helper + - name: Build signed Android helper APK shell: pwsh env: LUOTSI_ANDROID_KEYSTORE_BASE64: ${{ secrets.LUOTSI_ANDROID_KEYSTORE_BASE64 }} @@ -267,13 +234,25 @@ jobs: Write-Host "Using Luotsi Android release signing key from GitHub secrets." Write-Host "Stamping Android helper version $env:LUOTSI_ANDROID_VERSION_NAME ($env:LUOTSI_ANDROID_VERSION_CODE)." - if ($IsWindows) { - & ".\Luotsi.ViewServer.Android\gradlew.bat" -p Luotsi.ViewServer.Android :app:assembleRelease - } else { - & bash "./Luotsi.ViewServer.Android/gradlew" -p Luotsi.ViewServer.Android :app:assembleRelease - } - if ($LASTEXITCODE -ne 0) { - exit $LASTEXITCODE + $wrapper = ".\Luotsi.ViewServer.Android\gradlew.bat" + $arguments = @("--no-daemon", "-p", "Luotsi.ViewServer.Android", ":app:assembleRelease") + $maxAttempts = 3 + $exitCode = 0 + + for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) { + & $wrapper @arguments + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + break + } + + if ($attempt -eq $maxAttempts) { + exit $exitCode + } + + $delaySeconds = 20 * $attempt + Write-Warning "Android helper build failed with exit code $exitCode. Retrying in $delaySeconds seconds ($attempt/$maxAttempts)." + Start-Sleep -Seconds $delaySeconds } $releaseApkDir = Join-Path $PWD "Luotsi.ViewServer.Android/app/build/outputs/apk/release" @@ -294,6 +273,76 @@ jobs: Write-Host "Android helper output: $($_.FullName)" } + - name: Upload Android helper APK + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: android-helper-apk + path: Luotsi.ViewServer.Android/app/build/outputs/apk/release/app-release.apk + if-no-files-found: error + + package: + name: Package ${{ matrix.rid }} + runs-on: ${{ matrix.runner }} + needs: + - validate-tag + - validate + - android-helper + timeout-minutes: 20 + permissions: + contents: read + strategy: + fail-fast: false + matrix: + include: + - rid: win-x64 + archive_ext: zip + runner: windows-latest + - rid: linux-x64 + archive_ext: tar.gz + runner: ubuntu-latest + - rid: osx-x64 + archive_ext: tar.gz + runner: ubuntu-latest + - rid: osx-arm64 + archive_ext: tar.gz + runner: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + ref: ${{ needs.validate-tag.outputs.tag }} + persist-credentials: false + + - name: Setup .NET SDK + uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5 + with: + global-json-file: global.json + cache: true + cache-dependency-path: | + **/*.csproj + **/packages.lock.json + global.json + NuGet.config + + - name: Verify locked restore + shell: pwsh + run: dotnet restore $env:SOLUTION --locked-mode /bl:artifacts/binlogs/release-publish-restore-${{ matrix.rid }}.binlog + + - name: Download Android view helper + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: android-helper-apk + path: Luotsi.ViewServer.Android/app/build/outputs/apk/release + + - name: Verify Android view helper + shell: pwsh + run: | + $helper = "Luotsi.ViewServer.Android/app/build/outputs/apk/release/app-release.apk" + if (!(Test-Path -LiteralPath $helper)) { + throw "Downloaded Android view helper APK is missing: $helper" + } + - name: Publish shell: pwsh run: >