This repository ships releases via the manual GitHub Actions workflow
Release. Every release produces:
- a Git tag
vX.Y.Zon the chosen commit, - a GitHub Release with auto-generated notes,
- a
BTCPayServer.Plugins.RgbUtexo.btcpayartifact attached to the release, - a
BTCPayServer.Plugins.RgbUtexo.btcpay.sha256checksum file next to it.
The same artifact can later be uploaded by hand into a BTCPay Server instance or referenced when re-pointing plugin-builder.btcpayserver.org to a tag.
The workflow is manual on purpose. Pushing a tag does not cut a release — you trigger it from the Actions tab when you are ready.
- Bump the version in
btcpay.plugin.jsonandBTCPayServer.Plugins.RgbUtexo.csprojon a branch. - Open a PR, merge it into
main(or whichever branch you release from). - GitHub → Actions → Release → Run workflow.
- Pick the branch (or tag) under Use workflow from, type the same version into the version field, click Run workflow.
- Wait for the green check, grab the artifact from the new
Release,
and (optionally) update
gitRefon plugin-builder to the new tag.
Two files must be in sync — the workflow refuses to run otherwise.
btcpay.plugin.json
{
"version": "1.0.7"
}BTCPayServer.Plugins.RgbUtexo.csproj
<Version>1.0.7</Version>Use SemVer: MAJOR.MINOR.PATCH. Pre-releases like
1.0.7-rc1 are accepted; if you use one, also tick the prerelease
checkbox when running the workflow.
Commit the bump on its own:
git checkout -b chore/bump-1.0.7
# edit the two files
git commit -am "Bump version to 1.0.7"
git push -u origin chore/bump-1.0.7
# open & merge a PR into mainGitHub → Actions → Release → Run workflow.
| Field | What to put |
|---|---|
| Use workflow from | the branch (usually main) or an existing tag |
| version | 1.0.7 — exactly the value from the manifest, no v |
| prerelease | tick only for -rc, -beta, etc. |
What the workflow does, in order:
- Checks out the chosen ref with submodules (
submodules/btcpayserveris required to compile the plugin). - Validates that the input
versionmatches bothbtcpay.plugin.jsonand<Version>in the.csproj. dotnet publish -c ReleasewithDeterministic=trueandContinuousIntegrationBuild=true.- Sanity-checks the publish output: the plugin DLL and manifest are
present, and
BTCPayServer.dll(the host) is not packed in. - Zips the publish output into
BTCPayServer.Plugins.RgbUtexo.btcpayand computes its SHA-256. - Tags the commit:
- if
vX.Y.Zdoes not exist — creates it and pushes; - if it already points to the same commit — reuses it;
- if it points to a different commit — fails (we do not move tags).
- if
- Creates (or replaces, with
--cleanup-tag=false) the GitHub ReleasevX.Y.Z, attaches the artifact and its.sha256, and runs--generate-notesso commit messages since the previous tag become the release body. - Writes a one-line summary with the artifact’s SHA-256 and the release URL into the run’s job summary.
-
Open the new release at
https://github.com/UTEXO-Protocol/rgb-btcpay-plugin/releases/tag/vX.Y.Zand skim the auto-generated notes. Edit them if needed — they are not set in stone. -
Optional: download
BTCPayServer.Plugins.RgbUtexo.btcpayand verify the hash locally:sha256sum -c BTCPayServer.Plugins.RgbUtexo.btcpay.sha256
-
Update the BTCPay plugin registry (manual UI step on plugin-builder.btcpayserver.org → RGB Utexo → settings): change
gitReffrommaintorefs/tags/vX.Y.Zso the official registry build is pinned to an immutable ref. New builds there will then be reproducible against this tag.
If you need to rebuild the artifact for the same version (for example a CI flake on the first run):
- Run the workflow again with the same
versionand the same ref. - The tag stays put; only the GitHub Release and its assets are recreated.
If a release was wrong and you want to retag the version on a different commit, you must first delete the tag manually:
git push origin :refs/tags/v1.0.7
git tag -d v1.0.7…and then re-run the workflow from the new ref. Do this only before anyone (registry, demo server, users) has pulled the artifact — otherwise cut a new patch version instead.
The plugin ships native code (Rust-built librgblib.*) inside a NuGet
package; a single compromise of UTEXO-Protocol's CI would let an attacker
substitute that bundle and gain code execution inside every BTCPay process
loading the plugin. To make such a substitution detectable and verifiable,
the release pipeline applies the following controls.
| Field | Value |
|---|---|
| Package | RgbLib |
| Version | 0.3.0-beta.21.1 |
| Source | nuget.org (no longer vendored in nuget_packages/) |
| Size | ~46 MB (linux-x64 .so + osx-arm64 .dylib + win-x64 .dll + managed glue) |
| Built from | UTEXO-Protocol/rgb-lib-c-sharp v0.3.0-beta.21.1 (managed bindings tracking native rgb-lib v0.3.0-beta.21) |
NuGet contentHash (SHA-512, base64) |
kbTmP4OUB4heYfqAnezwlBcXpvJgexPzKg2Vl1EYcRUNbROs3Rp5hxn0YslwoSpaRcLuYUsaHFZ55mUIXS0kMQ== |
| SLSA attestation | attached to the v0.3.0-beta.21.1 GitHub Release (RgbLib.0.3.0-beta.21.1.nupkg.intoto.jsonl) |
The .nupkg is no longer vendored inside this repository. dotnet restore
pulls it from nuget.org, and packages.lock.json (§5.2) records its
SHA-512 — any substitution upstream breaks the build.
The same .nupkg is also attached to the v0.3.0-beta.21.1 GitHub
Release
together with a SLSA Level 3 build attestation, which lets you verify
that the package was built by the expected workflow from the expected
commit:
# install once
go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest
TAG=v0.3.0-beta.21.1
gh release download "$TAG" \
--repo UTEXO-Protocol/rgb-lib-c-sharp \
--pattern 'RgbLib.*.nupkg' \
--pattern '*.intoto.jsonl'
slsa-verifier verify-artifact RgbLib.*.nupkg \
--provenance-path RgbLib.*.nupkg.intoto.jsonl \
--source-uri github.com/UTEXO-Protocol/rgb-lib-c-sharp \
--source-tag "$TAG"The bump from
0.3.0-beta.21to0.3.0-beta.21.1resyncs the C# managed bindings with the native ABI of rgb-libv0.3.0-beta.21— the first publication of0.3.0-beta.21shipped with bindings still targetingv0.3.0-beta.18and is broken at runtime.0.3.0-beta.21is unlisted on nuget.org;0.3.0-beta.21.1is the canonical build.
packages.lock.json is checked in and contains a
SHA-512 contentHash for every direct and transitive dependency (43
entries at the time of writing). The project file enables two flags:
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<RestoreLockedMode Condition="'$(ContinuousIntegrationBuild)' == 'true'">true</RestoreLockedMode>What this gives:
- Every CI run uses
dotnet restore --locked-mode -p:ContinuousIntegrationBuild=true. Any package whose computedcontentHashdoes not match the one inpackages.lock.jsonfails the restore. Silent substitution of any dependency on nuget.org breaks the build instead of shipping to users. - Local developer restores stay flexible (
RestoreLockedModeis gated onContinuousIntegrationBuild), but any dependency change requires regenerating and committing the lockfile.
To regenerate the lockfile locally after a deliberate dependency change:
# the lockfile must include the conditional BTCPay ProjectReference,
# so the submodule has to be initialized first — otherwise restore
# silently records a smaller set of dependencies and the next CI run
# fails with "A new project reference to btcpayserver was found".
git submodule update --init --recursive
dotnet restore BTCPayServer.Plugins.RgbUtexo.csproj --force-evaluate
git add packages.lock.jsonEvery GitHub Release produced by Release is
accompanied by a SLSA Level 3 build attestation generated by the upstream
slsa-framework/slsa-github-generator
reusable workflow (generator_generic_slsa3.yml@v2.1.0).
The attestation is a signed in-toto JSON document that records:
- the SHA-256 of
BTCPayServer.Plugins.RgbUtexo.btcpay, - the commit and ref the build ran on,
- the exact GitHub Actions workflow file and runner identity,
- the timestamp of the build.
It is signed keyless via Sigstore using an
OIDC token minted for the workflow run (no long-lived private key), and
the signature is recorded in the public Rekor
transparency log. The resulting *.intoto.jsonl file is attached to the
same Release as the artifact.
To verify a release as an end user:
# install once
go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest
# download both files from the release page
TAG=v1.0.6
gh release download "$TAG" \
--repo UTEXO-Protocol/rgb-btcpay-plugin \
--pattern 'BTCPayServer.Plugins.RgbUtexo.btcpay' \
--pattern '*.intoto.jsonl'
# verify
slsa-verifier verify-artifact BTCPayServer.Plugins.RgbUtexo.btcpay \
--provenance-path *.intoto.jsonl \
--source-uri github.com/UTEXO-Protocol/rgb-btcpay-plugin \
--source-tag "$TAG"A PASSED: SLSA verification passed output means the artifact was built
by the expected workflow on the expected source commit and has not been
modified since. Any mismatch (different builder, different commit,
modified artifact) makes the verifier exit non-zero.