Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 44 additions & 113 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,46 +73,6 @@
with:
unity-version: ${{ matrix.unity-version }}

package-validation:
name: UPM Package validation
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.head_ref || github.ref }}
ssh-key: ${{ secrets.CI_DEPLOY_KEY }}

- name: Download UPM package
uses: ./.github/actions/wait-for-artifact
with:
name: package-release

- name: Check snapshot
id: snapshot-check
shell: pwsh
run: |
$ErrorActionPreference = 'Continue'
& ./test/Scripts.Tests/test-pack-contents.ps1
"result=$LASTEXITCODE" >> $env:GITHUB_OUTPUT

- name: Update snapshot for dependency bumps
if: steps.snapshot-check.outputs.result != '0' && github.event_name == 'pull_request' && startsWith(github.head_ref, 'deps/')
run: |
./test/Scripts.Tests/test-pack-contents.ps1 accept
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add test/Scripts.Tests/package-release.zip.snapshot
git commit -m "Update package release snapshot"
git push

- name: Fail on unexpected snapshot changes
if: steps.snapshot-check.outputs.result != '0' && !(github.event_name == 'pull_request' && startsWith(github.head_ref, 'deps/'))
run: |
Write-Error "Package contents do not match snapshot. Run './test/Scripts.Tests/test-pack-contents.ps1 accept' locally and commit the update."
exit 1

# This produces the `samples/IntegrationTest` as `test-${{ matrix.unity-version }}`.
test-create:
name: Create ${{ matrix.unity-version }} Test Project
if: ${{ !startsWith(github.ref, 'refs/heads/release/') }}
Expand Down Expand Up @@ -189,26 +149,6 @@
restore-keys: |
it-library-ubuntu-${{ matrix.unity-version }}-

- name: Restore cached build without Sentry
id: cache-build-nosentry
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: samples/IntegrationTest/Build-NoSentry
key: build-nosentry-${{ matrix.build_platform }}-${{ matrix.unity-version }}

- name: Build without Sentry SDK
if: steps.cache-build-nosentry.outputs.cache-hit != 'true'
run: ./test/Scripts.Integration.Test/build-project.ps1 -UnityPath "$env:UNITY_PATH" -Platform "$env:BUILD_PLATFORM" -BuildDirName "Build-NoSentry"
env:
BUILD_PLATFORM: ${{ matrix.build_platform }}

- name: Save cached build without Sentry
if: github.ref == 'refs/heads/main' && steps.cache-build-nosentry.outputs.cache-hit != 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: samples/IntegrationTest/Build-NoSentry
key: build-nosentry-${{ matrix.build_platform }}-${{ matrix.unity-version }}

- name: Download UPM package
uses: ./.github/actions/wait-for-artifact
with:
Expand All @@ -220,46 +160,18 @@
- name: Add Sentry to the project
run: ./test/Scripts.Integration.Test/add-sentry.ps1 -UnityPath "$env:UNITY_PATH" -PackagePath "test-package-release"

- name: Download DependencyConflict package
uses: ./.github/actions/wait-for-artifact
with:
name: dependency-conflict-package
path: dependency-conflict-package

- name: Add DependencyConflict to the project
if: ${{ !startsWith(matrix.unity-version, '2021') }}
run: ./test/Scripts.Integration.Test/add-dependency-conflict.ps1 -PackagePath "dependency-conflict-package"

- name: Disable DependencyConflict (WebGL 2021)
if: ${{ startsWith(matrix.unity-version, '2021') }}
run: ./test/Scripts.Integration.Test/add-dependency-conflict.ps1 -Disable

- name: Configure Sentry
run: ./test/Scripts.Integration.Test/configure-sentry.ps1 -UnityPath "$env:UNITY_PATH" -Platform "$env:BUILD_PLATFORM"
env:
BUILD_PLATFORM: ${{ matrix.build_platform }}
SENTRY_DSN: ${{ secrets.SENTRY_TEST_DSN }}
SENTRY_DSN: http://capture@127.0.0.1:8787/1 # TEMPORARY: envelope capture, see docs/envelope-capture.md

- name: Build Project
run: ./test/Scripts.Integration.Test/build-project.ps1 -UnityPath "$env:UNITY_PATH" -Platform "$env:BUILD_PLATFORM" -UnityVersion "$env:UNITY_VERSION"
env:
BUILD_PLATFORM: ${{ matrix.build_platform }}
UNITY_VERSION: ${{ matrix.unity-version }}

- name: Compare build sizes
run: ./test/Scripts.Integration.Test/measure-build-size.ps1 -Path1 "samples/IntegrationTest/Build-NoSentry" -Path2 "samples/IntegrationTest/Build" -Platform "$env:BUILD_PLATFORM" -UnityVersion "$env:UNITY_VERSION"
env:
BUILD_PLATFORM: ${{ matrix.build_platform }}
UNITY_VERSION: ${{ matrix.unity-version }}

- name: Upload build size measurement
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: build-size-${{ matrix.platform }}-${{ matrix.unity-version }}
path: build-size-measurements/*.json
retention-days: 1

# We create tar explicitly because upload-artifact is slow for many files.
- name: Create archive
run: |
Remove-Item -Recurse -Force samples/IntegrationTest/Build/*_BackUpThisFolder_ButDontShipItWithYourGame -ErrorAction SilentlyContinue
Expand Down Expand Up @@ -294,7 +206,7 @@
secrets:
UNITY_LICENSE_SERVER_CONFIG: ${{ secrets.UNITY_LICENSE_SERVER_CONFIG }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_TEST_DSN: ${{ secrets.SENTRY_TEST_DSN }}
SENTRY_TEST_DSN: http://capture@127.0.0.1:8787/1 # TEMPORARY: envelope capture, see docs/envelope-capture.md
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.create-unity-matrix.outputs.unity-matrix) }}
Expand All @@ -308,7 +220,7 @@
needs: [test-build-android, create-unity-matrix]
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_TEST_DSN: ${{ secrets.SENTRY_TEST_DSN }}
SENTRY_TEST_DSN: http://capture@127.0.0.1:8787/1 # TEMPORARY: envelope capture, see docs/envelope-capture.md
uses: ./.github/workflows/test-run-android.yml
with:
unity-version: ${{ matrix.unity-version }}
Expand All @@ -329,7 +241,7 @@
secrets:
UNITY_LICENSE_SERVER_CONFIG: ${{ secrets.UNITY_LICENSE_SERVER_CONFIG }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_TEST_DSN: ${{ secrets.SENTRY_TEST_DSN }}
SENTRY_TEST_DSN: http://capture@127.0.0.1:8787/1 # TEMPORARY: envelope capture, see docs/envelope-capture.md
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.create-unity-matrix.outputs.unity-matrix) }}
Expand Down Expand Up @@ -362,7 +274,7 @@
init-type: ${{ matrix.init-type }}
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_TEST_DSN: ${{ secrets.SENTRY_TEST_DSN }}
SENTRY_TEST_DSN: http://capture@127.0.0.1:8787/1 # TEMPORARY: envelope capture, see docs/envelope-capture.md
strategy:
fail-fast: false
matrix:
Expand All @@ -386,7 +298,7 @@
needs: [test-build-webgl, create-unity-matrix]
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_TEST_DSN: ${{ secrets.SENTRY_TEST_DSN }}
SENTRY_TEST_DSN: http://capture@127.0.0.1:8787/1 # TEMPORARY: envelope capture, see docs/envelope-capture.md
strategy:
fail-fast: false
matrix:
Expand All @@ -402,7 +314,7 @@
secrets:
UNITY_LICENSE_SERVER_CONFIG: ${{ secrets.UNITY_LICENSE_SERVER_CONFIG }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_TEST_DSN: ${{ secrets.SENTRY_TEST_DSN }}
SENTRY_TEST_DSN: http://capture@127.0.0.1:8787/1 # TEMPORARY: envelope capture, see docs/envelope-capture.md
strategy:
fail-fast: false
matrix:
Expand All @@ -418,7 +330,7 @@
secrets:
UNITY_LICENSE_SERVER_CONFIG: ${{ secrets.UNITY_LICENSE_SERVER_CONFIG }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_TEST_DSN: ${{ secrets.SENTRY_TEST_DSN }}
SENTRY_TEST_DSN: http://capture@127.0.0.1:8787/1 # TEMPORARY: envelope capture, see docs/envelope-capture.md
strategy:
fail-fast: false
matrix:
Expand All @@ -434,7 +346,7 @@
secrets:
UNITY_LICENSE_SERVER_CONFIG: ${{ secrets.UNITY_LICENSE_SERVER_CONFIG }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_TEST_DSN: ${{ secrets.SENTRY_TEST_DSN }}
SENTRY_TEST_DSN: http://capture@127.0.0.1:8787/1 # TEMPORARY: envelope capture, see docs/envelope-capture.md
strategy:
fail-fast: false
matrix:
Expand All @@ -449,7 +361,7 @@
needs: [test-build-linux, create-unity-matrix]
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_TEST_DSN: ${{ secrets.SENTRY_TEST_DSN }}
SENTRY_TEST_DSN: http://capture@127.0.0.1:8787/1 # TEMPORARY: envelope capture, see docs/envelope-capture.md
strategy:
fail-fast: false
matrix:
Expand All @@ -464,10 +376,10 @@
test-run-windows:
name: Run Windows ${{ matrix.backend }} ${{ matrix.unity-version }} Integration Test
if: ${{ !startsWith(github.ref, 'refs/heads/release/') }}
needs: [test-build-windows, create-unity-matrix]
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_TEST_DSN: ${{ secrets.SENTRY_TEST_DSN }}
SENTRY_TEST_DSN: http://capture@127.0.0.1:8787/1 # TEMPORARY: envelope capture, see docs/envelope-capture.md

Check failure on line 382 in .github/workflows/ci.yml

View check run for this annotation

@sentry/warden / warden: security-review

[4BH-LDB] SENTRY_AUTH_TOKEN written into uploaded Android capture artifacts (additional location)

On CI runs with the Sentry secret available, Android's captured `upload-proguard` request metadata includes the Bearer token and is uploaded in the `symbols-android-*` artifact, allowing artifact readers to recover the credential. Redact authorization headers before writing capture metadata or exclude the metadata files from the artifact.
strategy:
fail-fast: false
matrix:
Expand All @@ -485,7 +397,7 @@
needs: [test-build-macos, create-unity-matrix]
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_TEST_DSN: ${{ secrets.SENTRY_TEST_DSN }}
SENTRY_TEST_DSN: http://capture@127.0.0.1:8787/1 # TEMPORARY: envelope capture, see docs/envelope-capture.md
strategy:
fail-fast: false
matrix:
Expand All @@ -497,21 +409,40 @@
platform: macos
backend: ${{ matrix.backend }}

build-size-summary:
name: Build Size
# Merges the per-job envelope artifacts into a single `envelopes-all` download.
# See docs/envelope-capture.md.
collect-envelopes:
name: Collect captured envelopes
runs-on: ubuntu-latest
if: ${{ !startsWith(github.ref, 'refs/heads/release/') }}
needs: [test-build-webgl, test-build-android, test-compile-ios, test-build-linux, test-build-windows, test-build-macos]
if: ${{ always() }}
needs: [test-run-android, test-run-ios, test-run-webgl, test-run-linux, test-run-windows, test-run-macos]
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Download all build size measurements
- name: Download all envelope artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: build-size-*
path: build-size-measurements
pattern: envelopes-*
merge-multiple: true
path: envelopes

- name: Summarize corpus
run: |
"## Captured envelopes`n" >> $env:GITHUB_STEP_SUMMARY
"| Platform | Payloads | Test actions |" >> $env:GITHUB_STEP_SUMMARY
"| --- | --- | --- |" >> $env:GITHUB_STEP_SUMMARY
$total = 0
Get-ChildItem -Path envelopes -Recurse -Filter index.jsonl | Sort-Object { $_.Directory.Name } | ForEach-Object {
$entries = Get-Content $_.FullName | ForEach-Object { $_ | ConvertFrom-Json }
$total += $entries.Count
$actions = ($entries | ForEach-Object { $_.label } | Sort-Object -Unique) -join ", "
"| $($_.Directory.Name) | $($entries.Count) | $actions |" >> $env:GITHUB_STEP_SUMMARY
}
"`nTotal: $total payloads" >> $env:GITHUB_STEP_SUMMARY

- name: Upload combined corpus
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: envelopes-all
path: envelopes/
if-no-files-found: error
retention-days: 14

- name: Create consolidated summary
shell: pwsh
run: ./scripts/create-build-size-summary.ps1
55 changes: 19 additions & 36 deletions .github/workflows/test-build-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,24 +60,6 @@
restore-keys: |
it-library-ubuntu-${{ env.UNITY_VERSION }}-

- name: Restore cached build without Sentry
id: cache-build-nosentry
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: samples/IntegrationTest/Build-NoSentry
key: build-nosentry-Android-${{ inputs.unity-version }}

- name: Build without Sentry SDK
if: steps.cache-build-nosentry.outputs.cache-hit != 'true'
run: ./test/Scripts.Integration.Test/build-project.ps1 -UnityPath "$env:UNITY_PATH" -Platform "Android" -BuildDirName "Build-NoSentry"

- name: Save cached build without Sentry
if: github.ref == 'refs/heads/main' && steps.cache-build-nosentry.outputs.cache-hit != 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: samples/IntegrationTest/Build-NoSentry
key: build-nosentry-Android-${{ inputs.unity-version }}

- name: Download UPM package
uses: ./.github/actions/wait-for-artifact
with:
Expand All @@ -89,14 +71,10 @@
- name: Add Sentry to the project
run: ./test/Scripts.Integration.Test/add-sentry.ps1 -UnityPath "$env:UNITY_PATH" -PackagePath "test-package-release"

- name: Download DependencyConflict package
uses: ./.github/actions/wait-for-artifact
with:
name: dependency-conflict-package
path: dependency-conflict-package

- name: Add DependencyConflict to the project
run: ./test/Scripts.Integration.Test/add-dependency-conflict.ps1 -PackagePath "dependency-conflict-package"
# Envelope capture: sentry-cli takes its upload URL from the DSN, so every debug file it
# uploads during the build lands in the capture output. See docs/envelope-capture.md.
- name: Start envelope capture server
run: ./test/Scripts.Integration.Test/start-capture-server.ps1 -Platform "android-${{ env.UNITY_VERSION }}" -Output "test/IntegrationTest/symbols/android-${{ env.UNITY_VERSION }}"

Check failure on line 77 in .github/workflows/test-build-android.yml

View check run for this annotation

@sentry/warden / warden: security-review

SENTRY_AUTH_TOKEN written into uploaded Android capture artifacts

On CI runs with the Sentry secret available, Android's captured `upload-proguard` request metadata includes the Bearer token and is uploaded in the `symbols-android-*` artifact, allowing artifact readers to recover the credential. Redact authorization headers before writing capture metadata or exclude the metadata files from the artifact.
Comment on lines +76 to +77

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SENTRY_AUTH_TOKEN written into uploaded Android capture artifacts

On CI runs with the Sentry secret available, Android's captured upload-proguard request metadata includes the Bearer token and is uploaded in the symbols-android-* artifact, allowing artifact readers to recover the credential. Redact authorization headers before writing capture metadata or exclude the metadata files from the artifact.

Evidence
  • .github/workflows/test-build-android.yml starts envelope-capture-server.py with output under test/IntegrationTest/symbols/android-${{ env.UNITY_VERSION }} and always uploads test/IntegrationTest/symbols/ as an artifact.
  • CliConfiguration reads SENTRY_AUTH_TOKEN and sets cliOptions.Auth; SentryCli.CreateSentryProperties writes that value as auth.token, which sentry-cli uses for build-time uploads.
  • test/Scripts.Integration.Test/Editor/Builder.cs enables Android debug and release minification, while DebugSymbolUpload registers upload-proguard for minified builds.
  • The capture server only special-cases /chunk-upload/ and /assemble/; the proguard POST reaches the generic handler, which writes dict(self.headers) into .meta.json and index.jsonl beneath the artifact output.
Also found at 1 additional location
  • .github/workflows/ci.yml:379-382

Identified by Warden · security-review · 4BH-LDB


- name: Configure Sentry
run: ./test/Scripts.Integration.Test/configure-sentry.ps1 -UnityPath "$env:UNITY_PATH" -Platform "Android"
Expand All @@ -109,16 +87,6 @@
- name: Assert symbols and sources were uploaded (Runtime)
run: ./test/Scripts.Integration.Test/assert-symbol-upload.ps1 -LogPath samples/IntegrationTest/Logs/sentry-symbols-upload.log

- name: Compare build sizes (Runtime)
run: ./test/Scripts.Integration.Test/measure-build-size.ps1 -Path1 "samples/IntegrationTest/Build-NoSentry" -Path2 "samples/IntegrationTest/Build" -Platform "Android" -UnityVersion "$env:UNITY_VERSION"

- name: Upload build size measurement
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: build-size-Android-${{ env.UNITY_VERSION }}
path: build-size-measurements/*.json
retention-days: 1

- name: Bundle build & symbol-upload logs with the APK (Runtime)
run: |
Copy-Item unity.log samples/IntegrationTest/Build/ -ErrorAction SilentlyContinue
Expand Down Expand Up @@ -176,3 +144,18 @@
!samples/IntegrationTest/Build/*_BackUpThisFolder_ButDontShipItWithYourGame
retention-days: 14 # Lower retention period - we only need this to retry CI.

- name: Stop envelope capture server
if: ${{ always() }}
run: |
try { Invoke-WebRequest -Uri "http://127.0.0.1:8787/STOP" -TimeoutSec 5 -UseBasicParsing | Out-Null }
catch { Write-Host "Capture server already gone" }

- name: Upload captured debug files
if: ${{ always() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: symbols-android-${{ env.UNITY_VERSION }}
path: test/IntegrationTest/symbols/
if-no-files-found: warn
retention-days: 14

Loading
Loading