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
22 changes: 22 additions & 0 deletions .github/release-notes/v2.2.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# BadBuilderLinux v2.2.1

Maintenance release incorporating upstream BadBuilder changes through September 14, 2026, while preserving BadBuilderLinux's Linux-first design and security hardening.

## Changes

- **Windows UAC:** Include upstream's requireAdministrator manifest in the self-contained Windows x64 executable so launching it normally requests elevation. The explicit Windows administrator check remains in place.
- **Linux remains unprivileged:** The Linux application still runs as a normal user and requests sudo only for the narrowly scoped USB-disk preparation/cleanup helper.
- **Upstream integration:** Incorporate upstream's September changes into Git history. The fork already implemented submenu **Back** navigation, runtime-derived version display, and ABadAvatar 1.3 Beta support; those hardened implementations remain in place rather than being replaced by upstream's less constrained equivalents.
- **ABadAvatar 1.3 Beta:** Continue pinning the upstream beta asset to its exact release, filename, and SHA-256. It remains a beta; this release does **not** upgrade it to a new exploit version.

## Downloads

- BadBuilder-linux-x64 — self-contained Linux x64 executable
- BadBuilder-win-x64.exe — self-contained Windows x64 executable
- SHA256SUMS — SHA-256 checksums for both executables

Linux users may need to run chmod +x BadBuilder-linux-x64.

The automated release workflow builds and tests both operating systems and checks the executable version before publishing. Manual physical USB testing is not part of the GitHub Actions suite.

**Warning:** BadBuilder formats and erases the selected USB disk. Verify its exact device path before confirming. The ABadAvatar 1.3 Beta release advises disconnecting the Xbox 360 from the Internet before running the exploit.
150 changes: 150 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
name: Publish release

on:
push:
branches: [main]
paths:
- BadBuilder/BadBuilder.csproj
- .github/workflows/release.yml
workflow_dispatch:

permissions:
contents: read

concurrency:
group: badbuilder-release-main
cancel-in-progress: false

jobs:
prepare:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.version.outputs.tag }}
version: ${{ steps.version.outputs.version }}
needed: ${{ steps.version.outputs.needed }}
steps:
- uses: actions/checkout@v7
- name: Determine next release
id: version
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
version="$(sed -n 's/^[[:space:]]*<VersionPrefix>\([^<]*\)<\/VersionPrefix>.*/\1/p' BadBuilder/BadBuilder.csproj)"
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Unexpected VersionPrefix: $version" >&2
exit 1
fi
tag="v$version"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "version=$version" >> "$GITHUB_OUTPUT"
if gh release view "$tag" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "Release $tag already exists; no publication needed."
echo "needed=false" >> "$GITHUB_OUTPUT"
else
test -f ".github/release-notes/$tag.md" || { echo "Missing release notes for $tag" >&2; exit 1; }
echo "needed=true" >> "$GITHUB_OUTPUT"
fi

build:
needs: prepare
if: needs.prepare.outputs.needed == 'true'
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
rid: linux-x64
binary: BadBuilder
- os: windows-latest
rid: win-x64
binary: BadBuilder.exe
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
- uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x
cache: true
cache-dependency-path: '**/*.csproj'
- name: Restore
run: dotnet restore BadBuilder.Tests/BadBuilder.Tests.csproj
- name: Audit dependencies
run: dotnet list BadBuilder/BadBuilder.csproj package --vulnerable --include-transitive
- name: Build with warnings as errors
run: dotnet build BadBuilder.Tests/BadBuilder.Tests.csproj -c Release --no-restore
- name: Run unit tests
run: dotnet test BadBuilder.Tests/BadBuilder.Tests.csproj -c Release --no-build --no-restore
- name: Publish self-contained executable
run: dotnet publish BadBuilder/BadBuilder.csproj -c Release -r ${{ matrix.rid }} --self-contained true --no-restore -o dist
- name: Validate Linux executable version
if: runner.os == 'Linux'
shell: bash
run: |
set -euo pipefail
actual="$(./dist/BadBuilder --version)"
[[ "$actual" == "${{ needs.prepare.outputs.version }}"* ]] || { echo "Unexpected version: $actual"; exit 1; }
file dist/BadBuilder | grep -q ELF
- name: Validate Windows executable version
if: runner.os == 'Windows'
shell: pwsh
run: |
$actual = (./dist/BadBuilder.exe --version).Trim()
if (-not $actual.StartsWith('${{ needs.prepare.outputs.version }}')) {
throw "Unexpected version: $actual"
}
$bytes = [System.IO.File]::ReadAllBytes((Resolve-Path ./dist/BadBuilder.exe))
if ($bytes[0] -ne 77 -or $bytes[1] -ne 90) {
throw "Windows executable is missing the MZ header"
}
- uses: actions/upload-artifact@v7
with:
name: release-${{ matrix.rid }}
path: dist/${{ matrix.binary }}
if-no-files-found: error
compression-level: 0

publish:
needs: [prepare, build]
if: needs.prepare.outputs.needed == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v7
- uses: actions/download-artifact@v7
with:
name: release-linux-x64
path: release/linux
- uses: actions/download-artifact@v7
with:
name: release-win-x64
path: release/windows
- name: Assemble verified release assets
shell: bash
run: |
set -euo pipefail
mv release/linux/BadBuilder release/BadBuilder-linux-x64
mv release/windows/BadBuilder.exe release/BadBuilder-win-x64.exe
chmod +x release/BadBuilder-linux-x64
file release/BadBuilder-linux-x64 | grep -q ELF
file release/BadBuilder-win-x64.exe | grep -q PE32
cd release
sha256sum BadBuilder-linux-x64 BadBuilder-win-x64.exe > SHA256SUMS
sha256sum -c SHA256SUMS
- name: Create GitHub release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ needs.prepare.outputs.tag }}
shell: bash
run: |
set -euo pipefail
gh release create "$TAG" \
release/BadBuilder-linux-x64 \
release/BadBuilder-win-x64.exe \
release/SHA256SUMS \
--repo "$GITHUB_REPOSITORY" \
--target "$GITHUB_SHA" \
--title "BadBuilderLinux $TAG" \
--notes-file ".github/release-notes/$TAG.md"
2 changes: 1 addition & 1 deletion BadBuilder/BadBuilder.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<NuGetAuditMode>all</NuGetAuditMode>
<NuGetAuditLevel>low</NuGetAuditLevel>
<AnalysisLevel>latest-recommended</AnalysisLevel>
<VersionPrefix>2.2.0</VersionPrefix>
<VersionPrefix>2.2.1</VersionPrefix>
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
<PublishSingleFile Condition="'$(RuntimeIdentifier)' != ''">true</PublishSingleFile>
<SelfContained Condition="'$(RuntimeIdentifier)' != ''">true</SelfContained>
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ Two destructive tests are opt-in and never run in normal CI:

Set `BADBUILDER_LIVE_SMOKE=1` to resolve all upstream catalog sources without downloading an asset or touching a disk.

## Publishing a release

Releases are published by GitHub Actions after the VersionPrefix in BadBuilder/BadBuilder.csproj is increased on main. Add the corresponding release notes at .github/release-notes/vX.Y.Z.md before merging. The release.yml workflow builds and tests both supported x64 platforms, verifies the version strings and native binary formats, generates SHA-256 checksums, then creates the matching version tag and GitHub release. An already-published version is skipped. To retry a failed release, rerun the workflow from GitHub Actions.

## Offline archives

If release metadata is unavailable and no valid cache exists, BadBuilder asks for a local archive for every configured artifact. No configured built-in homebrew is silently skipped. Local files go through the same checksum, approval, extraction, layout, and preflight checks as downloads.
Expand Down
Loading