Skip to content
Open
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
5 changes: 3 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,12 @@ jobs:

## Verifying the Release Timestamp

From this new version onwards, in addition time-stamping the _git tag_ with [OpenTimestamps](https://opentimestamps.org/), we'll also now timestamp the manifest file along with its signature. Two new files are now included along with the rest of our release artifacts: ` manifest-roasbeef-${{ env.RELEASE_VERSION }}.txt.asc.ots`.
From this new version onwards, in addition time-stamping the _git tag_ with [OpenTimestamps](https://opentimestamps.org/), we'll also now timestamp the manifest file along with at least one developer signature. Timestamp proof files are included along with the rest of our release artifacts: `manifest-${{ env.RELEASE_VERSION }}.txt.ots` and one or more `manifest-<signer>-${{ env.RELEASE_VERSION }}.sig.ots` files.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit (pre-existing wording carried into this edited line): "in addition time-stamping the git tag" reads as missing a "to" — "in addition to time-stamping the git tag". Easy to fix while this line is already being rewritten.


Assuming you have the opentimestamps client installed locally, the timestamps can be verified with the following commands:
```
ots verify manifest-roasbeef-${{ env.RELEASE_VERSION }}.sig.ots -f manifest-roasbeef-${{ env.RELEASE_VERSION }}.sig
ots verify manifest-${{ env.RELEASE_VERSION }}.txt.ots -f manifest-${{ env.RELEASE_VERSION }}.txt
ots verify manifest-<signer>-${{ env.RELEASE_VERSION }}.sig.ots -f manifest-<signer>-${{ env.RELEASE_VERSION }}.sig
```

Alternatively, [the OpenTimestamps website](https://opentimestamps.org/) can be used to verify timestamps if one doesn't have a `bitcoind` instance accessible locally.
Expand Down
58 changes: 58 additions & 0 deletions .github/workflows/verify-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,64 @@ jobs:
name: Verify release signatures and binaries
runs-on: ubuntu-latest
steps:
- name: git checkout
uses: actions/checkout@v4
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

For workflow_dispatch with an older version input, actions/checkout@v4 checks out the default branch, so TRUSTED_SIGNERS is read from current master rather than the released tag's verify-install.sh. Harmless while the signer list only grows, but if a signer is ever removed a historical re-verify could behave inconsistently. Consider pinning ref: ${{ inputs.version || github.sha }}.


- name: Check final release OpenTimestamps asset
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Process note: this step runs on release: published, so if maintainers publish the release before uploading the .sig.ots/.txt.ots assets, the gate fails and the existing if: failure() handler reverts the release to draft. It's recoverable (upload assets, re-publish), but it's a behavioral change worth calling out in the release runbook — the first release after this merges is the most likely to trip on it.

env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ inputs.version || github.event.release.tag_name }}
run: |
set -euo pipefail

if [[ "${VERSION}" =~ \.rc[0-9]+$ ]]; then
echo "Release candidate ${VERSION}; skipping OpenTimestamps asset check."
exit 0
fi

REQUIRED_MANIFEST_OTS="manifest-${VERSION}.txt.ots"
TRUSTED_SIGNERS="$(sed -n \
's/^KEYS+=(.* \([^" ]*\)")$/\1/p' \
scripts/verify-install.sh)"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This sed is tightly coupled to the exact KEYS+=("<fp> <name>") line shape in verify-install.sh. If that format ever changes, TRUSTED_SIGNERS silently becomes empty and every final release fails with the generic "missing OTS proof" error. A defensive guard would turn that into a clear failure:

[[ -n "${TRUSTED_SIGNERS}" ]] || { echo "ERROR: no trusted signers parsed from verify-install.sh"; exit 1; }

(FWIW I verified the current regex extracts all 14 signers correctly and handles hyphenated names like ViktorT-11.)


ASSETS="$(gh release view "${VERSION}" \
--repo "${{ github.repository }}" \
--json assets \
--jq '.assets[].name')"

if ! grep -Fxq "${REQUIRED_MANIFEST_OTS}" <<< "${ASSETS}"; then
echo "ERROR: Final release ${VERSION} is missing ${REQUIRED_MANIFEST_OTS}."
exit 1
fi

MATCHING_SIG=""
MATCHING_SIG_OTS=""
while IFS= read -r asset; do
if [[ "${asset}" != manifest-*-"${VERSION}".sig.ots ]]; then
continue
fi

sig="${asset%.ots}"
signer="${sig%-$VERSION.sig}"
signer="${signer#manifest-}"
if grep -Fxq "${signer}" <<< "${TRUSTED_SIGNERS}" &&
grep -Fxq "${sig}" <<< "${ASSETS}"; then

MATCHING_SIG="${sig}"
MATCHING_SIG_OTS="${asset}"
break
fi
done <<< "${ASSETS}"

if [[ -z "${MATCHING_SIG_OTS}" ]]; then
echo "ERROR: Final release ${VERSION} is missing an OpenTimestamps proof for an uploaded manifest signature."
exit 1
fi

echo "Found required OpenTimestamps artifacts:"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Worth being explicit that this gate verifies the presence of the .ots asset names — it never runs ots verify on them, so a malformed/empty proof file would still pass. The trusted-signer + matching-.sig constraints make presence a reasonable bar, but the PR title ("require signer OTS proof") slightly oversells it: it requires the proof file, not a valid proof. Either tweak the wording or consider actually validating the timestamp if integrity is the goal.

echo " ${REQUIRED_MANIFEST_OTS}"
echo " ${MATCHING_SIG_OTS} for ${MATCHING_SIG}"

- name: Verify release
env:
VERSION: ${{ inputs.version || github.event.release.tag_name }}
Expand Down
Loading