Move builds to prod-pins and add explicit update channels
Some checks failed
Validate authentication / Validate authentication (push) Failing after 1s
Some checks failed
Validate authentication / Validate authentication (push) Failing after 1s
This commit is contained in:
parent
3d824fde58
commit
e71d9c3118
15 changed files with 473 additions and 722 deletions
|
|
@ -20,6 +20,15 @@ contract="$repository_directory/iota-installer/bundle-files.txt"
|
|||
staging_directory="$(mktemp -d)"
|
||||
trap 'rm -rf "$staging_directory"' EXIT
|
||||
|
||||
case "$update_channel" in stable|canary) ;; *) echo "channel must be stable or canary" >&2; exit 2 ;; esac
|
||||
architecture="$(jq -r '.artifacts[0].architecture' "$release_manifest")"
|
||||
case "$architecture" in x86_64|aarch64) ;; *) echo "unsupported update architecture" >&2; exit 2 ;; esac
|
||||
expected_url="https://git.methanium.net/tensamin/prod-pins/releases/download/$update_channel/iota-update-linux-$architecture.json"
|
||||
if [[ "$update_manifest_url" != "$expected_url" || "$update_signature_url" != "$expected_url.sig" ]]; then
|
||||
echo "update URLs must match the selected prod-pins channel" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ ! "$product_version" =~ ^[0-9A-Za-z][0-9A-Za-z.+_-]*$ ]]; then
|
||||
echo "product version contains unsupported characters: $product_version" >&2
|
||||
exit 2
|
||||
|
|
|
|||
|
|
@ -22,6 +22,16 @@ staging_directory="$(mktemp -d)"
|
|||
artifacts="$staging_directory/artifacts.jsonl"
|
||||
trap 'rm -rf "$staging_directory"' EXIT
|
||||
|
||||
case "$channel" in stable|canary) ;; *) echo "channel must be stable or canary" >&2; exit 2 ;; esac
|
||||
case "$operating_system/$architecture" in linux/x86_64|linux/aarch64) ;; *) echo "unsupported update platform" >&2; exit 2 ;; esac
|
||||
source_sha="${IOTA_RELEASE_SOURCE_SHA:-$(git -C "$repository_directory" rev-parse HEAD)}"
|
||||
if [[ ! "$source_sha" =~ ^[0-9a-f]{40}$ ]]; then
|
||||
echo "IOTA_RELEASE_SOURCE_SHA must be a full source commit SHA" >&2
|
||||
exit 2
|
||||
fi
|
||||
product_version="${product_version}-${channel}-${source_sha}"
|
||||
signing_key_id="${IOTA_RELEASE_SIGNING_KEY_ID:-primary}"
|
||||
|
||||
if [[ ! "$release_sequence" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "release sequence must be a positive integer" >&2
|
||||
exit 2
|
||||
|
|
@ -42,7 +52,7 @@ while IFS=$'\t' read -r role artifact_path; do
|
|||
--arg os "$operating_system" \
|
||||
--arg architecture "$architecture" \
|
||||
--arg path "$artifact_path" \
|
||||
--arg url "$base_url/$asset_name" \
|
||||
--arg url "$base_url/$asset_name-$operating_system-$architecture" \
|
||||
--arg sha256 "$(sha256sum "$source_path" | cut -d ' ' -f 1)" \
|
||||
--argjson size "$(stat -c %s "$source_path")" \
|
||||
'{role: $role, os: $os, architecture: $architecture, path: $path, url: $url, sha256: $sha256, size: $size}' \
|
||||
|
|
@ -56,7 +66,7 @@ jq -s \
|
|||
--argjson release_sequence "$release_sequence" \
|
||||
--arg published_at "$published_at" \
|
||||
--arg expires_at "$expires_at" \
|
||||
--arg release_signing_key_id "primary" \
|
||||
--arg release_signing_key_id "$signing_key_id" \
|
||||
'{
|
||||
product_version: $product_version,
|
||||
channel: $channel,
|
||||
|
|
|
|||
84
scripts/releases.md
Normal file
84
scripts/releases.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# Unmanaged signed releases
|
||||
|
||||
Publishing belongs to prod-pins. Iota only builds and verifies release inputs.
|
||||
|
||||
## Operator commands
|
||||
|
||||
Run as root for the unmanaged system installation:
|
||||
|
||||
```sh
|
||||
iota update channel stable
|
||||
iota update channel canary
|
||||
iota update check
|
||||
iota update apply
|
||||
```
|
||||
|
||||
`iota update channel` shows the selected channel. Selection atomically persists
|
||||
`/etc/iota/update.env` without fetching or applying a release. The standalone
|
||||
`iota-updater` supports the same commands. Check and apply read this file directly,
|
||||
including the pinned public key and key ID. Process environment cannot replace
|
||||
the trust configuration. Channel selection preserves both trust values and all
|
||||
per-channel anti-replay state.
|
||||
|
||||
The manifest URL is
|
||||
`https://git.methanium.net/tensamin/prod-pins/releases/download/CHANNEL/iota-update-linux-ARCH.json`.
|
||||
The signature URL appends `.sig`. CHANNEL is `stable` or `canary`, ARCH is
|
||||
`x86_64` or `aarch64`. Apply can select a previously accepted target when the
|
||||
active release belongs to the other channel. It still rejects older sequences,
|
||||
sequence/version reuse and failed activation sequences. Same-channel explicit
|
||||
rollback remains respected.
|
||||
|
||||
The initial ZIP installer remains supported. It preserves existing update.env
|
||||
and removes a previously provisioned unattended update timer. The update service
|
||||
is an explicit oneshot apply operation with no timer.
|
||||
|
||||
## Release script contracts
|
||||
|
||||
```sh
|
||||
bash scripts/build-update-manifest.sh BINARY_DIRECTORY BASE_VERSION CHANNEL RELEASE_SEQUENCE PUBLISHED_AT EXPIRES_AT linux ARCH BASE_URL OUTPUT.json
|
||||
iota-release sign OUTPUT.json OUTPUT.json.sig
|
||||
bash scripts/build-release-bundle.sh BINARY_DIRECTORY PRODUCT_VERSION OUTPUT.json MANIFEST_URL PUBLIC_KEY SIGNATURE_URL CHANNEL SIGNING_KEY_ID OUTPUT.zip
|
||||
iota-bundle OUTPUT.zip
|
||||
```
|
||||
|
||||
The binary directory contains `iota`, `iota-daemon` and `iota-updater`.
|
||||
The manifest script emits PRODUCT_VERSION as `BASE_VERSION-CHANNEL-FULL_SOURCE_SHA`.
|
||||
Read `.product_version` from the generated manifest for the bundle command.
|
||||
Use an immutable release BASE_URL in prod-pins. Upload the binaries there as
|
||||
`iota-linux-ARCH`, `iota-daemon-linux-ARCH` and `iota-updater-linux-ARCH`.
|
||||
The signed artifact paths remain `bin/iota`, `bin/iota-daemon` and
|
||||
`bin/iota-updater`, with SHA-256 hashes and byte lengths.
|
||||
|
||||
Publish the manifest and signature under each mutable `stable` or `canary`
|
||||
release as `iota-update-linux-ARCH.json` and `iota-update-linux-ARCH.json.sig`.
|
||||
Sequences must increase per channel. Serialize publication per channel and
|
||||
reject a lower sequence or reuse with a different product version. Keep
|
||||
immutable binary assets available for already published manifests.
|
||||
|
||||
## Signature and workflow inputs
|
||||
|
||||
`IOTA_RELEASE_SIGNING_KEY` is a secret containing a 32-byte Ed25519 seed as
|
||||
64 hexadecimal characters. `iota-release sign` prints the derived 32-byte
|
||||
public key as hex. Compare it with the expected pinned public key before
|
||||
publishing or building installer trust configuration.
|
||||
|
||||
The detached signature is 64 Ed25519 bytes encoded as 128 hexadecimal
|
||||
characters. It signs `serde_json::to_vec` of the typed `ReleaseManifest`, in
|
||||
the Rust declaration field order, with nested artifacts in their declaration
|
||||
field order. It does not sign the pretty-printed JSON file bytes. Use the Rust
|
||||
signer rather than a generic JSON canonicalizer.
|
||||
|
||||
The prod-pins workflow needs:
|
||||
|
||||
- `IOTA_RELEASE_SIGNING_KEY`, secret signing seed.
|
||||
- `IOTA_RELEASE_SOURCE_SHA`, full 40-character Iota source commit SHA. Defaults
|
||||
to the local repository HEAD, so set it explicitly when building elsewhere.
|
||||
- `IOTA_RELEASE_SIGNING_KEY_ID`, defaults to `primary`.
|
||||
- Expected pinned public key, supplied as the bundle PUBLIC_KEY argument.
|
||||
- Base product version, channel, positive release sequence, RFC 3339 publication
|
||||
and expiry timestamps, architecture and immutable artifact BASE_URL.
|
||||
- A Forgejo API token with release upload access to `tensamin/prod-pins`.
|
||||
|
||||
Build the Rust release binaries plus `iota-release` and `iota-bundle`. Shell
|
||||
scripts require bash, git, coreutils, jq and zip. No Iota publishing workflow
|
||||
remains; verification runs in `.forgejo/workflows/validate.yml`.
|
||||
Loading…
Reference in a new issue