Skip to content
Merged
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
96 changes: 96 additions & 0 deletions .github/workflows/public-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ on:
- main
pull_request:
workflow_dispatch:
inputs:
run_macos_self_hosted_mount:
description: Run the macFUSE mount test on a self-hosted macOS runner.
required: false
default: false
type: boolean

jobs:
public-depot:
Expand Down Expand Up @@ -37,6 +43,96 @@ jobs:
CACHE_MIN_FREE_BYTES: 2G
REQUIRE_FUSE: 1

windows-public-depot:
if: ${{ github.event_name == 'workflow_dispatch' }}
runs-on: windows-2022

steps:
- name: Check out
uses: actions/checkout@v4

- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x

- name: Install WinFsp
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$installer = Join-Path $env:RUNNER_TEMP "winfsp-2.1.25156.msi"
$log = Join-Path $env:RUNNER_TEMP "winfsp-install.log"
Invoke-WebRequest `
-Uri "https://github.com/winfsp/winfsp/releases/download/v2.1/winfsp-2.1.25156.msi" `
-OutFile $installer

$hash = (Get-FileHash $installer -Algorithm SHA256).Hash
if ($hash -ne "073A70E00F77423E34BED98B86E600DEF93393BA5822204FAC57A29324DB9F7A") {
throw "Unexpected WinFsp installer SHA256: $hash"
}

$process = Start-Process `
-FilePath msiexec.exe `
-ArgumentList "/i `"$installer`" /qn /norestart /l*v `"$log`"" `
-Wait `
-PassThru

if ($process.ExitCode -notin 0, 3010) {
Get-Content $log -ErrorAction SilentlyContinue
throw "WinFsp installer failed with exit code $($process.ExitCode)."
}

$fsptool = "${env:ProgramFiles(x86)}\WinFsp\bin\fsptool.exe"
if (Test-Path $fsptool) {
& $fsptool ver
}

- name: Test Windows public depot mount
shell: pwsh
run: scripts/ci/test-steam-depotfs-windows.ps1

macos-public-depot:
if: ${{ github.event_name == 'workflow_dispatch' }}
runs-on: macos-15

steps:
- name: Check out
uses: actions/checkout@v4

- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x

- name: Install macFUSE
run: scripts/ci/install-macfuse-macos.sh

- name: Test macOS public depot smoke
timeout-minutes: 10
run: scripts/ci/test-steam-depotfs-macos.sh
env:
MOUNT_DIR: /Volumes/SteamDepotFS-Test
RUN_MOUNT: 0

macos-self-hosted-public-depot:
if: ${{ github.event_name == 'workflow_dispatch' && inputs.run_macos_self_hosted_mount }}
runs-on: [self-hosted, macOS]

steps:
- name: Check out
uses: actions/checkout@v4

- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x

- name: Test self-hosted macOS public depot mount
timeout-minutes: 10
run: scripts/ci/test-steam-depotfs-macos.sh
env:
MOUNT_DIR: /Volumes/SteamDepotFS-Test

authenticated-depot:
if: ${{ github.event_name != 'pull_request' }}
runs-on: ubuntu-24.04
Expand Down
75 changes: 50 additions & 25 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,32 +42,58 @@ jobs:
mkdir -p dist
scripts/ci/compute-release-version.sh

- name: Publish Linux x64 build
- name: Publish release builds
if: ${{ steps.version.outputs.released == 'true' }}
shell: bash
run: |
version="${{ steps.version.outputs.version }}"
publish_dir="dist/publish/linux-x64"
archive_root="SteamDepotFS-$version-linux-x64"

dotnet publish src/SteamDepotFs/SteamDepotFs.csproj \
-c Release \
-r linux-x64 \
--self-contained true \
-p:UseAppHost=true \
-p:Version="$version" \
-p:AssemblyVersion="$version.0" \
-p:FileVersion="$version.0" \
-o "$publish_dir"

mkdir -p "dist/$archive_root"
cp -R "$publish_dir"/. "dist/$archive_root/"
cp README.md "dist/$archive_root/"
cp CHANGELOG.md "dist/$archive_root/"
cp LICENSE NOTICE THIRD-PARTY-NOTICES.md "dist/$archive_root/"
printf '%s\n' "$version" > "dist/$archive_root/VERSION"
tar -C dist -czf "dist/$archive_root.tar.gz" "$archive_root"
cp "dist/$archive_root.tar.gz" "dist/SteamDepotFS-linux-x64.tar.gz"
rids=(
linux-x64
linux-arm64
win-x64
win-arm64
osx-x64
osx-arm64
)

: > dist/release-assets.txt
for rid in "${rids[@]}"; do
publish_dir="dist/publish/$rid"
archive_root="SteamDepotFS-$version-$rid"

dotnet publish src/SteamDepotFs/SteamDepotFs.csproj \
-c Release \
-r "$rid" \
--self-contained true \
-p:UseAppHost=true \
-p:Version="$version" \
-p:AssemblyVersion="$version.0" \
-p:FileVersion="$version.0" \
-o "$publish_dir"

mkdir -p "dist/$archive_root"
cp -R "$publish_dir"/. "dist/$archive_root/"
cp README.md "dist/$archive_root/"
cp CHANGELOG.md "dist/$archive_root/"
cp LICENSE NOTICE THIRD-PARTY-NOTICES.md "dist/$archive_root/"
printf '%s\n' "$version" > "dist/$archive_root/VERSION"

if [[ "$rid" == win-* ]]; then
(cd dist && zip -qr "$archive_root.zip" "$archive_root")
cp "dist/$archive_root.zip" "dist/SteamDepotFS-$rid.zip"
{
echo "dist/$archive_root.zip"
echo "dist/SteamDepotFS-$rid.zip"
} >> dist/release-assets.txt
else
tar -C dist -czf "dist/$archive_root.tar.gz" "$archive_root"
cp "dist/$archive_root.tar.gz" "dist/SteamDepotFS-$rid.tar.gz"
{
echo "dist/$archive_root.tar.gz"
echo "dist/SteamDepotFS-$rid.tar.gz"
} >> dist/release-assets.txt
fi
done

- name: Commit changelog
if: ${{ steps.version.outputs.released == 'true' }}
Expand Down Expand Up @@ -101,10 +127,9 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
tag="${{ steps.version.outputs.tag }}"
version="${{ steps.version.outputs.version }}"
mapfile -t assets < dist/release-assets.txt
gh release create "$tag" \
"dist/SteamDepotFS-$version-linux-x64.tar.gz" \
"dist/SteamDepotFS-linux-x64.tar.gz" \
"${assets[@]}" \
--repo "$GITHUB_REPOSITORY" \
--title "$tag" \
--notes-file dist/RELEASE_NOTES.md
Expand Down
50 changes: 44 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,29 @@ It was created for GitHub workflows that operate on Steam game files but have li

## Installation

For CI or other projects, download the latest Linux x64 release archive. The release build is self-contained and does not require the .NET SDK:
For CI or other projects, download the release archive for the target platform. Release builds are self-contained and do not require the .NET SDK:

```bash
curl -L -o SteamDepotFS-linux-x64.tar.gz \
https://github.com/raidertool/SteamDepotFS/releases/latest/download/SteamDepotFS-linux-x64.tar.gz
tar -xzf SteamDepotFS-linux-x64.tar.gz
```

Release assets use these stable names:

| Platform | Asset |
| --- | --- |
| Windows x64 | `SteamDepotFS-win-x64.zip` |
| Windows arm64 | `SteamDepotFS-win-arm64.zip` |
| Linux x64 | `SteamDepotFS-linux-x64.tar.gz` |
| Linux arm64 | `SteamDepotFS-linux-arm64.tar.gz` |
| macOS Apple Silicon | `SteamDepotFS-osx-arm64.tar.gz` |
| macOS Intel | `SteamDepotFS-osx-x64.tar.gz` |

For mounted filesystem access on Windows, install WinFsp 2.1 or later:

https://winfsp.dev/rel/

For mounted filesystem access on Linux, install FUSE:

```bash
Expand All @@ -22,7 +37,13 @@ sudo apt-get install -y fuse3 libfuse2
sudo modprobe fuse || true
```

The `smoke`, `list`, and `read` commands do not require FUSE. Only `mount` requires FUSE.
For mounted filesystem access on macOS, install macFUSE:

https://macfuse.github.io/

On macOS 15.4 or later with macFUSE 5 or later, mount under `/Volumes/<name>` to use macFUSE's FSKit backend. Other macOS mount points use the kernel backend and may require approving the macFUSE system extension.

The `smoke`, `list`, `inspect`, and `read` commands do not require WinFsp or FUSE. Only `mount` requires an OS filesystem driver.

To build from source instead, install the .NET 8 SDK and run:

Expand Down Expand Up @@ -67,12 +88,29 @@ dotnet run --project src/SteamDepotFs/SteamDepotFs.csproj -c Release -- mount \
--mount-point /tmp/steam-depotfs
```

Unmount:
On Windows, use an unused drive letter or an empty directory mount point:

```powershell
SteamDepotFs.exe mount `
--app <app-id> `
--depot <depot-id> `
--mount-point X:
```

Unmount on Linux:

```bash
fusermount3 -u /tmp/steam-depotfs
```

Unmount on macOS:

```bash
diskutil unmount /tmp/steam-depotfs
```

Unmount on Windows by stopping the SteamDepotFS process, for example with `Ctrl+C` in the terminal running `mount`.

Anonymous login is used unless credentials are provided. Credentials can be passed as arguments or environment variables:

| Argument | Environment variable |
Expand Down Expand Up @@ -120,7 +158,7 @@ The default public smoke target is Spacewar:
- depot `481`
- branch `public`

That depot is small and works anonymously, so it is useful for validating Steam login, manifest resolution, CDN downloads, cache reuse, and FUSE mounting before testing private depots.
That depot is small and works anonymously, so it is useful for validating Steam login, manifest resolution, CDN downloads, cache reuse, and mounting before testing private depots.

Run the public test script:

Expand All @@ -137,7 +175,7 @@ scripts/bench/read-matrix.sh <app-id> <depot-id> <depot-path>

The script defaults to `--read-ahead-chunks` values `0 1 2`, `--max-chunk-concurrency` values `4 8 16`, and cold cache runs. Set `WARM_CACHE=1`, `ITERATIONS`, `OFFSET`, `LENGTH`, `READ_AHEAD_VALUES`, or `CONCURRENCY_VALUES` to tune the run.

The repository includes `.github/workflows/public-test.yml`, which runs the same public test on pushes and pull requests. The workflow builds the project, reads `installscript.vdf` from the Spacewar depot, mounts the depot through FUSE, and verifies the file is visible through the mounted filesystem.
The repository includes `.github/workflows/public-test.yml`, which runs the same public test on pushes and pull requests. The workflow builds the project, reads `installscript.vdf` from the Spacewar depot, mounts the depot through FUSE on Linux, and verifies the file is visible through the mounted filesystem. Manual runs also test WinFsp on Windows. GitHub-hosted macOS runners publish the native macOS binary, install macFUSE, and run the Steam smoke/read check; macFUSE mount validation is available through the `run_macos_self_hosted_mount` manual workflow input on a self-hosted macOS runner with macFUSE configured.

The workflow also includes an authenticated smoke test for pushes and manual runs. It logs in with configured Steam credentials, resolves the configured depot, and reads a small file from that depot. Configure either:

Expand All @@ -155,7 +193,7 @@ Releases are created directly from `main` after the `Depot tests` workflow succe
- `fix:`, `perf:`, `refactor:`, and `revert:` create a patch release
- docs-only or CI-only changes do not create a release

Each release publishes a Linux x64 archive with both a versioned asset name and the stable `SteamDepotFS-linux-x64.tar.gz` asset name for `releases/latest` downloads. CI also generates release notes for the GitHub release body, updates the tracked `CHANGELOG.md`, and includes that changelog inside the archive.
Each release publishes Windows, Linux, and macOS archives with both versioned asset names and stable `SteamDepotFS-<rid>` asset names for `releases/latest` downloads. CI also generates release notes for the GitHub release body, updates the tracked `CHANGELOG.md`, and includes that changelog inside each archive.

## License

Expand Down
16 changes: 16 additions & 0 deletions THIRD-PARTY-NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,16 @@ their own licenses.
| Package | Version | License | Authors | Project |
| --- | --- | --- | --- | --- |
| SteamKit2 | 3.4.0 | LGPL-2.1-only | SteamKit2 | https://github.com/SteamRE/SteamKit |
| winfsp.net | 2.1.25156 | GPL-3.0 with WinFsp Free/Libre and Open Source Software exception | Bill Zissimopoulos | https://github.com/winfsp/winfsp |
| Mono.Fuse.NETStandard | 1.1.0 | MIT | Jonathan Pryor, Alexey Kolpakov | https://github.com/alhimik45/Mono.Fuse.NETStandard |
| Mono.Posix.NETStandard | 1.0.0 | Package license URL: https://go.microsoft.com/fwlink/?linkid=869050 | Microsoft | https://go.microsoft.com/fwlink/?linkid=869051 |
| Microsoft.Win32.Registry | 5.0.0 | MIT | Microsoft | https://github.com/dotnet/runtime |
| protobuf-net | 3.2.56 | Apache-2.0 | Marc Gravell | https://github.com/protobuf-net/protobuf-net |
| protobuf-net.Core | 3.2.56 | Apache-2.0 | Marc Gravell | https://github.com/protobuf-net/protobuf-net |
| System.IO.FileSystem.AccessControl | 5.0.0 | MIT | Microsoft | https://github.com/dotnet/runtime |
| System.IO.Hashing | 10.0.1 | MIT | Microsoft | https://dot.net/ |
| System.Security.AccessControl | 5.0.0 | MIT | Microsoft | https://github.com/dotnet/runtime |
| System.Security.Principal.Windows | 5.0.0 | MIT | Microsoft | https://github.com/dotnet/runtime |
| ZstdSharp.Port | 0.8.7 | MIT | Oleg Stepanischev | https://github.com/oleg-st/ZstdSharp |

## LGPL Notice For SteamKit2
Expand All @@ -40,3 +45,14 @@ SteamDepotFS does not modify SteamKit2. If you receive a binary distribution
that includes SteamKit2, you may replace or relink the SteamKit2 library with
a modified compatible version under the terms of the LGPL-2.1-only license.
SteamDepotFS source and build instructions are available in this repository.

## WinFsp Notice

Windows binary distributions may include the WinFsp .NET binding. The WinFsp
source repository is available at:

https://github.com/winfsp/winfsp

WinFsp is distributed under GPL-3.0 with a special exception for Free/Libre
and Open Source Software. SteamDepotFS does not bundle the WinFsp kernel
driver; users install the WinFsp runtime separately.
Loading
Loading