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
51 changes: 51 additions & 0 deletions .github/workflows/custom-image-android.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Build UE Android runner image

on:
push:
workflow_dispatch:
schedule:
- cron: '0 6 * * 1'

env:
REGISTRY: ghcr.io

jobs:
create-image:
name: Create Android image with UE Docker images
runs-on: unreal-image-creating-runner-linux
snapshot: unreal-image-android

permissions:
contents: read
packages: read

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683

- name: Free up disk space
run: ./scripts/clean-storage-linux.sh

- name: Log in to GitHub package registry
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

# Android images carry the Android SDK/NDK platform files and are large, so the set is limited to
# the versions Android is actually tested on (5.4+). Add '5.8' here once its image is published.
- name: Pull Unreal Engine Docker images
run: |
set -e
tags=("5.4" "5.5" "5.6" "5.7")
for tag in "${tags[@]}"; do
echo "=== Pulling ${{ env.REGISTRY }}/getsentry/unreal-docker:${tag}-android ==="
docker pull "${{ env.REGISTRY }}/getsentry/unreal-docker:${tag}-android"
echo "=== Free disk space after pulling ${tag}-android ==="
df -h /
done

- name: Verify pulled images
run: |
docker images --filter "reference=${{ env.REGISTRY }}/getsentry/unreal-docker" --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
49 changes: 49 additions & 0 deletions .github/workflows/custom-image-linux.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Build UE Linux runner image

on:
push:
workflow_dispatch:

Check notice on line 5 in .github/workflows/custom-image-linux.yml

View check run for this annotation

@sentry/warden / warden: security-review

Unfiltered `push` trigger runs branch-controlled scripts on snapshot-persistent self-hosted image runners

The `custom-image-*` workflows trigger on any `push` with no `branches:` filter, check out the pushed ref, and run repo-local scripts (`./scripts/clean-storage-linux.sh` / `clean-storage-win.ps1`) on persistent self-hosted runners (`unreal-image-creating-runner-*`) whose disk is captured via `snapshot:` into a base image reused by future jobs. A contributor with write access can push a modified script to any feature branch to execute code on the runner before the snapshot boundary, persistently poisoning every downstream runner image. Add a `branches: [main]` filter so only trusted refs build the images.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unfiltered push trigger runs branch-controlled scripts on snapshot-persistent self-hosted image runners

The custom-image-* workflows trigger on any push with no branches: filter, check out the pushed ref, and run repo-local scripts (./scripts/clean-storage-linux.sh / clean-storage-win.ps1) on persistent self-hosted runners (unreal-image-creating-runner-*) whose disk is captured via snapshot: into a base image reused by future jobs. A contributor with write access can push a modified script to any feature branch to execute code on the runner before the snapshot boundary, persistently poisoning every downstream runner image. Add a branches: [main] filter so only trusted refs build the images.

Evidence
  • on: push in custom-image-android.yml and custom-image-windows.yml has no branches: filter, so any push to any branch triggers the workflow.
  • The Free up disk space step runs ./scripts/clean-storage-linux.sh / clean-storage-win.ps1 directly from the checked-out ref, so a modified script on the pushed branch executes verbatim on the runner.
  • runs-on: unreal-image-creating-runner-linux/-windows with snapshot: unreal-image-* indicates the runner state is captured into a reusable base image, so pre-snapshot code execution persists into future images.
  • Precondition: the push trigger only fires for repository write-access users (not forks), limiting the actor to trusted collaborators, which bounds impact.

Identified by Warden security-review · 9HZ-CTN

schedule:
- cron: '0 6 * * 1'

env:
REGISTRY: ghcr.io

jobs:
create-image:
name: Create Linux image with UE Docker images
runs-on: unreal-image-creating-runner-linux
snapshot: unreal-image-linux

permissions:
contents: read
packages: read

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683

- name: Free up disk space
run: ./scripts/clean-storage-linux.sh

- name: Log in to GitHub package registry
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Pull Unreal Engine Docker images
run: |
set -e
tags=("4.27" "5.2" "5.3" "5.4" "5.5" "5.6" "5.7")
for tag in "${tags[@]}"; do
echo "=== Pulling ${{ env.REGISTRY }}/getsentry/unreal-docker:${tag}-linux ==="
docker pull "${{ env.REGISTRY }}/getsentry/unreal-docker:${tag}-linux"
echo "=== Free disk space after pulling ${tag}-linux ==="
df -h /
done

- name: Verify pulled images
run: |
docker images --filter "reference=${{ env.REGISTRY }}/getsentry/unreal-docker" --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
54 changes: 54 additions & 0 deletions .github/workflows/custom-image-windows.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Build UE Windows runner image

on:
push:
workflow_dispatch:
schedule:
- cron: '0 6 * * 1'

env:
REGISTRY: ghcr.io

jobs:
create-image:
name: Create Windows image with UE Docker images
runs-on: unreal-image-creating-runner-windows
snapshot: unreal-image-windows

permissions:
contents: read
packages: read

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683

- name: Free up disk space
shell: pwsh
run: ./scripts/clean-storage-win.ps1

- name: Log in to GitHub package registry
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Pull Unreal Engine Docker images
shell: pwsh
run: |
$tags = @('4.27', '5.5', '5.6', '5.7')
foreach ($tag in $tags) {
Write-Host "=== Pulling ${{ env.REGISTRY }}/getsentry/unreal-docker:$tag ==="
docker pull "${{ env.REGISTRY }}/getsentry/unreal-docker:$tag"
if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to pull image for tag $tag"
exit 1
}
Write-Host "=== Free disk space after pulling $tag ==="
Get-PSDrive -PSProvider FileSystem | Format-Table -AutoSize Name, @{Name='Used(GB)';Expression={[math]::Round($_.Used/1GB,2)}}, @{Name='Free(GB)';Expression={[math]::Round($_.Free/1GB,2)}}
}

- name: Verify pulled images
run: |
docker images --filter "reference=${{ env.REGISTRY }}/getsentry/unreal-docker" --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
75 changes: 75 additions & 0 deletions scripts/clean-storage-linux.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -euo pipefail

print_space_freed() {
local step_name="$1"
local current_space
current_space=$(df -BM --output=avail / | tail -1 | tr -dc '0-9')
local freed=$((current_space - last_reported_space))
local freed_gb
local current_gb
freed_gb=$(awk "BEGIN { printf \"%.2f\", $freed / 1024 }")
current_gb=$(awk "BEGIN { printf \"%.2f\", $current_space / 1024 }")
echo "After $step_name - Freed: ${freed_gb} GB, Current free space: ${current_gb} GB"
last_reported_space=$current_space
total_freed=$((total_freed + freed))
}

initial_space=$(df -BM --output=avail / | tail -1 | tr -dc '0-9')
last_reported_space=$initial_space
total_freed=0

initial_gb=$(awk "BEGIN { printf \"%.2f\", $initial_space / 1024 }")
echo "Initial free space: ${initial_gb} GB"

sudo swapoff -a || true
sudo rm -f /swapfile
print_space_freed "Swap removal"

sudo rm -rf /usr/local/lib/android
print_space_freed "Android SDK removal"

sudo rm -rf /usr/share/dotnet
print_space_freed ".NET removal"

sudo rm -rf /usr/share/swift
print_space_freed "Swift removal"

sudo rm -rf /usr/local/share/powershell
print_space_freed "PowerShell removal"

sudo rm -rf /usr/local/.ghcup
sudo rm -rf /opt/ghc
print_space_freed "Haskell removal"

sudo rm -rf /usr/local/lib/node_modules
print_space_freed "Node modules removal"

sudo rm -rf /usr/local/share/boost
print_space_freed "Boost removal"

sudo rm -rf /usr/lib/google-cloud-sdk
print_space_freed "Google Cloud SDK removal"

sudo rm -rf /usr/lib/jvm
print_space_freed "JVM removal"

sudo rm -rf /opt/pipx
print_space_freed "pipx removal"

if [[ -n "${AGENT_TOOLSDIRECTORY:-}" ]]; then
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
print_space_freed "Agent toolcache removal"
fi

sudo apt-get clean
sudo rm -rf /var/lib/apt/lists/*
print_space_freed "APT cleanup"

final_space=$(df -BM --output=avail / | tail -1 | tr -dc '0-9')
final_gb=$(awk "BEGIN { printf \"%.2f\", $final_space / 1024 }")
total_freed_gb=$(awk "BEGIN { printf \"%.2f\", $total_freed / 1024 }")

echo "Initial free space: ${initial_gb} GB"
echo "Final free space: ${final_gb} GB"
echo "Total space gained: ${total_freed_gb} GB"
Loading