diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..b4e8a69
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,120 @@
+name: Publish to NuGet.org
+
+# Publishes the exact package that was attached to a GitHub release. It does not build one: the
+# assets uploaded by package.yml are downloaded and pushed as-is, so what reaches NuGet.org is
+# byte for byte what the release carries and what the tests passed against.
+#
+# Authentication is trusted publishing (OIDC). NuGet.org verifies a short-lived, GitHub-signed
+# token against a policy naming this repository, this workflow file and the release environment,
+# then issues an API key valid for one hour. There is no long-lived secret to leak or rotate.
+#
+# Publishing to NuGet.org cannot be undone: a package can be unlisted but never deleted. Two
+# deliberate human steps therefore stand in front of it — publishing the GitHub release, and
+# approving the release environment.
+
+on:
+ release:
+ types: [published]
+ workflow_dispatch:
+ inputs:
+ tag:
+ description: 'Release tag to publish, for example v1.0.0'
+ required: true
+ type: string
+
+permissions:
+ contents: read
+
+concurrency:
+ group: publish-${{ github.event.release.tag_name || inputs.tag }}
+ cancel-in-progress: false
+
+env:
+ DOTNET_NOLOGO: true
+ DOTNET_CLI_TELEMETRY_OPTOUT: true
+
+jobs:
+ publish:
+ name: Push to NuGet.org
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+
+ # Gates the job on the required reviewer configured for this environment, and scopes the
+ # trusted publishing policy: a token from any other environment will not be accepted.
+ environment:
+ name: release
+ url: https://www.nuget.org/packages/MiniLzoSharp
+
+ permissions:
+ # Lets GitHub mint the OIDC token that NuGet.org exchanges for a short-lived API key.
+ id-token: write
+ # Reading the release assets to publish.
+ contents: read
+
+ steps:
+ - name: Set up .NET
+ uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
+ with:
+ dotnet-version: '10.0.x'
+
+ - name: Download the release assets
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ TAG: ${{ github.event.release.tag_name || inputs.tag }}
+ run: |
+ set -euo pipefail
+
+ mkdir -p artifacts
+ gh release download "$TAG" --repo "${GITHUB_REPOSITORY}" --dir artifacts --pattern '*.nupkg' --pattern '*.snupkg'
+ ls -l artifacts
+
+ - name: Verify the assets before pushing
+ env:
+ TAG: ${{ github.event.release.tag_name || inputs.tag }}
+ run: |
+ set -euo pipefail
+
+ # The tag is the source of truth for the version, so confirm the package agrees with it
+ # rather than trusting the filename. Publishing the wrong version is not reversible.
+ version="${TAG#v}"
+ nupkg="artifacts/MiniLzoSharp.${version}.nupkg"
+
+ if [ ! -f "$nupkg" ]; then
+ echo "::error::Release $TAG has no asset named MiniLzoSharp.${version}.nupkg"
+ exit 1
+ fi
+
+ if ! unzip -p "$nupkg" 'MiniLzoSharp.nuspec' | grep -q "${version}"; then
+ echo "::error::$nupkg does not declare version ${version}."
+ exit 1
+ fi
+
+ # A package missing its licence would be published without the notice the GPL terms of
+ # both this work and the upstream LZO library require.
+ for entry in LICENSE README.md lib/net10.0/MiniLzoSharp.dll; do
+ if ! unzip -Z1 "$nupkg" | grep -qx "$entry"; then
+ echo "::error::$nupkg is missing $entry"
+ exit 1
+ fi
+ done
+
+ echo "Verified MiniLzoSharp ${version}, ready to push."
+
+ - name: Exchange the OIDC token for a short-lived NuGet API key
+ # Requested immediately before the push: NuGet's temporary keys last one hour, and each
+ # token buys exactly one key.
+ id: login
+ uses: NuGet/login@8d196754b4036150537f80ac539e15c2f1028841 # v1.2.0
+ with:
+ user: ${{ secrets.NUGET_USER }}
+
+ - name: Push
+ # The matching .snupkg is picked up automatically from the same directory.
+ # --skip-duplicate makes a re-run after a partial failure safe rather than an error.
+ run: |
+ set -euo pipefail
+
+ dotnet nuget push 'artifacts/*.nupkg' \
+ --api-key '${{ steps.login.outputs.NUGET_API_KEY }}' \
+ --source https://api.nuget.org/v3/index.json \
+ --skip-duplicate
diff --git a/src/MiniLzoSharp/MiniLzoSharp.csproj b/src/MiniLzoSharp/MiniLzoSharp.csproj
index 5f5e7fc..074338e 100644
--- a/src/MiniLzoSharp/MiniLzoSharp.csproj
+++ b/src/MiniLzoSharp/MiniLzoSharp.csproj
@@ -21,8 +21,10 @@
MiniLzoSharp
- A managed C# implementation of the MiniLZO (LZO1X-1) real-time compression codec,
- derived from the LZO library by Markus F.X.J. Oberhumer
+ Licensed GPL-2.0-or-later, inherited from the upstream LZO library: applications
+ that use this package take on GPL obligations of their own. A managed C#
+ implementation of the MiniLZO (LZO1X-1) real-time compression codec, derived from
+ the LZO library by Markus F.X.J. Oberhumer
(https://www.oberhumer.com/opensource/lzo/). Produces and consumes raw LZO1X blocks
interoperable with the upstream C implementation.
@@ -31,7 +33,9 @@
C# implementation Copyright (c) 2026 Alyx Dallagiacomo. Derived from the LZO library, Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer.
GPL-2.0-or-later
README.md
- https://www.oberhumer.com/opensource/lzo/
+ https://github.com/AlyxSharkBite/MiniLzoSharp
+ https://github.com/AlyxSharkBite/MiniLzoSharp
+ lzo;lzo1x;minilzo;compression;decompression