Starry latest upstream (push) #57
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Starry upstream release | |
| run-name: Starry ${{ inputs.upstream_ref || 'latest upstream' }} (${{ github.event_name }}) | |
| on: | |
| push: | |
| branches: | |
| - main | |
| schedule: | |
| - cron: "17 20 * * *" | |
| workflow_dispatch: | |
| inputs: | |
| upstream_ref: | |
| description: "Official rustdesk-server release tag; blank uses the latest formal release" | |
| required: false | |
| type: string | |
| publish: | |
| description: "Publish release assets and GHCR image after every check succeeds" | |
| required: false | |
| default: false | |
| type: boolean | |
| force: | |
| description: "Rebuild even if this Starry release tag already exists" | |
| required: false | |
| default: false | |
| type: boolean | |
| concurrency: | |
| group: starry-upstream-release | |
| cancel-in-progress: false | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_AUDIT_VERSION: 0.22.2 | |
| CARGO_TERM_COLOR: always | |
| CROSS_REVISION: 88f49ff79e777bef6d3564531636ee4d3cc2f8d2 | |
| DEBIAN_TEST_IMAGE: debian:bookworm-slim@sha256:abd67ffcfa541b485a3dff59865ab629aa048a6c613e639d36e7456b0b229241 | |
| IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/rustdesk-server-starry | |
| RUST_TOOLCHAIN: 1.97.1 | |
| RUSTSEC_ADVISORY_DB_REVISION: 2f08fbb85332687b721f2f22706d07448369451b | |
| jobs: | |
| resolve: | |
| name: Resolve upstream and Starry versions | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| upstream_ref: ${{ steps.version.outputs.upstream_ref }} | |
| upstream_version: ${{ steps.version.outputs.upstream_version }} | |
| patch_version: ${{ steps.version.outputs.patch_version }} | |
| release_tag: ${{ steps.version.outputs.release_tag }} | |
| deb_version: ${{ steps.version.outputs.deb_version }} | |
| publish: ${{ steps.version.outputs.publish }} | |
| skip: ${{ steps.version.outputs.skip }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - name: Resolve release policy | |
| id: version | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| REQUESTED_REF: ${{ inputs.upstream_ref }} | |
| REQUESTED_PUBLISH: ${{ inputs.publish }} | |
| FORCE_BUILD: ${{ inputs.force }} | |
| AUTO_ENABLED: ${{ vars.STARRY_RELEASE_ENABLED }} | |
| run: | | |
| set -euo pipefail | |
| upstream_ref="${REQUESTED_REF:-}" | |
| if [ -z "$upstream_ref" ]; then | |
| upstream_ref="$(gh api repos/rustdesk/rustdesk-server/releases/latest --jq .tag_name)" | |
| fi | |
| patch_version="$(tr -d '[:space:]' < PATCH_VERSION)" | |
| if ! printf '%s' "$patch_version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then | |
| echo "PATCH_VERSION must use X.Y.Z" >&2 | |
| exit 1 | |
| fi | |
| release_status="$(sed -n 's/^status: //p' RELEASE_STATUS)" | |
| release_status_version="$(sed -n 's/^patch_version: //p' RELEASE_STATUS)" | |
| if [ "$release_status_version" != "$patch_version" ] \ | |
| || ! printf '%s' "$release_status" | grep -Eq '^(BLOCKED|APPROVED)$'; then | |
| echo "RELEASE_STATUS is invalid or does not match PATCH_VERSION" >&2 | |
| exit 1 | |
| fi | |
| upstream_version="${upstream_ref#v}" | |
| if ! printf '%s' "$upstream_version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+([._-][A-Za-z0-9.-]+)?$'; then | |
| echo "Automatic releases require a version-like upstream ref: $upstream_ref" >&2 | |
| exit 1 | |
| fi | |
| release_tag="${upstream_version}-patch-v${patch_version}" | |
| deb_upstream="$(printf '%s' "$upstream_version" | tr '-' '~')" | |
| deb_version="${deb_upstream}+patch.${patch_version}-1" | |
| publish=false | |
| if [ "${GITHUB_EVENT_NAME}" = schedule ] && [ "${AUTO_ENABLED:-false}" = true ]; then | |
| publish=true | |
| elif [ "${GITHUB_EVENT_NAME}" = workflow_dispatch ] && [ "${REQUESTED_PUBLISH:-false}" = true ]; then | |
| publish=true | |
| fi | |
| if [ "$publish" = true ] && [ "$release_status" != APPROVED ]; then | |
| echo "Publication is blocked by RELEASE_STATUS" >&2 | |
| exit 1 | |
| fi | |
| skip=false | |
| if [ "${GITHUB_EVENT_NAME}" = schedule ] && [ "${AUTO_ENABLED:-false}" != true ]; then | |
| skip=true | |
| elif [ "${GITHUB_EVENT_NAME}" != push ] && [ "${FORCE_BUILD:-false}" != true ] \ | |
| && gh release view "$release_tag" >/dev/null 2>&1; then | |
| skip=true | |
| fi | |
| { | |
| echo "upstream_ref=$upstream_ref" | |
| echo "upstream_version=$upstream_version" | |
| echo "patch_version=$patch_version" | |
| echo "release_tag=$release_tag" | |
| echo "deb_version=$deb_version" | |
| echo "publish=$publish" | |
| echo "skip=$skip" | |
| } >> "$GITHUB_OUTPUT" | |
| { | |
| echo "## Starry release resolution" | |
| echo | |
| echo "- Upstream: \`rustdesk/rustdesk-server@$upstream_ref\`" | |
| echo "- Starry tag: \`$release_tag\`" | |
| echo "- Publish after validation: \`$publish\`" | |
| echo "- Release gate: \`$release_status\`" | |
| echo "- Skip: \`$skip\`" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| source: | |
| name: Apply and verify the overlay | |
| needs: resolve | |
| if: needs.resolve.outputs.skip != 'true' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| outputs: | |
| upstream_commit: ${{ steps.upstream.outputs.upstream_commit }} | |
| upstream_common_commit: ${{ steps.upstream.outputs.upstream_common_commit }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - name: Validate the published Compose examples | |
| run: | | |
| set -euo pipefail | |
| docker compose \ | |
| --env-file examples/.env.example \ | |
| -f examples/compose.yaml \ | |
| config --quiet | |
| docker compose \ | |
| --env-file examples/center/.env.example \ | |
| -f examples/center/compose.bootstrap.yaml \ | |
| config --quiet | |
| docker compose \ | |
| --env-file examples/center/.env.example \ | |
| -f examples/center/compose.yaml \ | |
| config --quiet | |
| docker compose \ | |
| --env-file examples/relay/.env.example \ | |
| -f examples/relay/compose.yaml \ | |
| config --quiet | |
| docker compose \ | |
| --env-file examples/control-agent/.env.example \ | |
| -f examples/control-agent/compose.yaml \ | |
| config --quiet | |
| - name: Validate bilingual documentation and local links | |
| run: | | |
| python3 scripts/check_docs.py | |
| python3 -m unittest discover -s scripts -p 'test_docs.py' | |
| - name: Validate versioned contracts and least-privilege API surface | |
| run: python3 scripts/check_contracts.py | |
| - name: Validate immutable workflow inputs | |
| run: python3 scripts/check_workflows.py | |
| - name: Fetch the exact official source | |
| id: upstream | |
| env: | |
| UPSTREAM_REF: ${{ needs.resolve.outputs.upstream_ref }} | |
| run: | | |
| set -euo pipefail | |
| git init _upstream | |
| git -C _upstream remote add origin https://github.com/rustdesk/rustdesk-server.git | |
| git -C _upstream fetch --depth 1 origin \ | |
| "refs/tags/${UPSTREAM_REF}:refs/tags/${UPSTREAM_REF}" | |
| upstream_commit="$(git -C _upstream rev-parse "${UPSTREAM_REF}^{commit}")" | |
| git -C _upstream checkout --detach "$upstream_commit" | |
| git -C _upstream submodule update --init --recursive --depth 1 | |
| upstream_common_commit="$(git -C _upstream/libs/hbb_common rev-parse HEAD)" | |
| { | |
| echo "upstream_commit=$upstream_commit" | |
| echo "upstream_common_commit=$upstream_common_commit" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Apply the Starry overlay twice | |
| run: | | |
| set -euo pipefail | |
| python3 scripts/apply_overlay.py _upstream | |
| first_digest="$({ | |
| find _upstream/src _upstream/tests _upstream/contracts \ | |
| _upstream/libs/hbb_common/protos _upstream/PATCH_VERSION \ | |
| _upstream/libs/hbb_common/src _upstream/Cargo.toml \ | |
| _upstream/Cargo.lock _upstream/Cross.toml \ | |
| _upstream/libs/hbb_common/Cargo.toml \ | |
| -type f ! -name version.rs -print0 \ | |
| | LC_ALL=C sort -z \ | |
| | xargs -0 sha256sum | |
| } | sha256sum | cut -d' ' -f1)" | |
| python3 scripts/apply_overlay.py _upstream | |
| second_digest="$({ | |
| find _upstream/src _upstream/tests _upstream/contracts \ | |
| _upstream/libs/hbb_common/protos _upstream/PATCH_VERSION \ | |
| _upstream/libs/hbb_common/src _upstream/Cargo.toml \ | |
| _upstream/Cargo.lock _upstream/Cross.toml \ | |
| _upstream/libs/hbb_common/Cargo.toml \ | |
| -type f ! -name version.rs -print0 \ | |
| | LC_ALL=C sort -z \ | |
| | xargs -0 sha256sum | |
| } | sha256sum | cut -d' ' -f1)" | |
| test "$first_digest" = "$second_digest" | |
| python3 -m py_compile scripts/apply_overlay.py scripts/check_workflows.py | |
| git -C _upstream diff --check | |
| - uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c | |
| with: | |
| toolchain: ${{ env.RUST_TOOLCHAIN }} | |
| - name: Verify the fixed patched dependency graph | |
| run: | | |
| set -euo pipefail | |
| cmp overlay/Cargo.lock _upstream/Cargo.lock | |
| cargo metadata --manifest-path _upstream/Cargo.toml \ | |
| --format-version 1 --locked >/dev/null | |
| cmp overlay/Cargo.lock _upstream/Cargo.lock | |
| - name: Archive patched source deterministically | |
| run: >- | |
| tar --exclude=.git --sort=name --mtime='UTC 1970-01-01' | |
| --owner=0 --group=0 --numeric-owner -C _upstream -cf - . | |
| | gzip -n > patched-source.tar.gz | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: patched-source | |
| path: patched-source.tar.gz | |
| if-no-files-found: error | |
| retention-days: 3 | |
| compression-level: 0 | |
| overwrite: true | |
| security-evidence: | |
| name: Secret scan, workflow lint, and source SBOM | |
| needs: resolve | |
| if: needs.resolve.outputs.skip != 'true' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Install checksum-pinned security tools | |
| run: sh scripts/install_ci_tools.sh "${RUNNER_TEMP}/starry-tools" | |
| - name: Lint workflow syntax | |
| run: | | |
| "${RUNNER_TEMP}/starry-tools/actionlint" | |
| - name: Scan full Git history for secrets | |
| run: >- | |
| "${RUNNER_TEMP}/starry-tools/gitleaks" git . --config .gitleaks.toml | |
| --redact --no-banner --exit-code 1 | |
| - name: Generate source SBOM | |
| run: >- | |
| "${RUNNER_TEMP}/starry-tools/syft" scan dir:. | |
| -o spdx-json=starry-source.spdx.json | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: starry-source-sbom-${{ github.sha }} | |
| path: starry-source.spdx.json | |
| if-no-files-found: error | |
| retention-days: 7 | |
| overwrite: true | |
| test: | |
| name: Protocol, rules, fallback, and binary checks | |
| needs: | |
| - resolve | |
| - source | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 60 | |
| steps: | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: patched-source | |
| - name: Extract source | |
| run: mkdir _upstream && tar -xzf patched-source.tar.gz -C _upstream | |
| - uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c | |
| with: | |
| toolchain: ${{ env.RUST_TOOLCHAIN }} | |
| components: rustfmt | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| with: | |
| repository: RustSec/advisory-db | |
| ref: ${{ env.RUSTSEC_ADVISORY_DB_REVISION }} | |
| path: _rustsec-advisory-db | |
| fetch-depth: 1 | |
| persist-credentials: false | |
| - name: Audit the fixed Rust dependency graph | |
| run: | | |
| set -euo pipefail | |
| cargo install cargo-audit --version "${CARGO_AUDIT_VERSION}" --locked | |
| test "$(cargo-audit --version)" = "cargo-audit ${CARGO_AUDIT_VERSION}" | |
| cargo audit --db _rustsec-advisory-db --no-fetch \ | |
| --file _upstream/Cargo.lock --deny unsound --json \ | |
| | tee starry-rustsec-audit.json | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: starry-rustsec-audit-${{ github.sha }} | |
| path: starry-rustsec-audit.json | |
| if-no-files-found: error | |
| retention-days: 7 | |
| overwrite: true | |
| - name: Verify overlay formatting | |
| run: | | |
| rustfmt --edition 2021 --check \ | |
| _upstream/src/starry_config.rs \ | |
| _upstream/src/allocation_explain.rs \ | |
| _upstream/src/connection_auth.rs \ | |
| _upstream/src/control_agent.rs \ | |
| _upstream/src/control_agent/auth.rs \ | |
| _upstream/src/control_agent/config_store.rs \ | |
| _upstream/src/control_agent/local_client.rs \ | |
| _upstream/src/bin/starry-control-agent.rs \ | |
| _upstream/src/database.rs \ | |
| _upstream/src/fast_relay.rs \ | |
| _upstream/src/profile_activation.rs \ | |
| _upstream/src/secure_tcp.rs \ | |
| _upstream/src/geo_relay.rs \ | |
| _upstream/src/geo_relay/rules.rs \ | |
| _upstream/src/local_control.rs \ | |
| _upstream/src/relay_observer.rs \ | |
| _upstream/src/relay_quality.rs \ | |
| _upstream/src/websocket_signal.rs \ | |
| _upstream/src/websocket_signal/session.rs \ | |
| _upstream/src/websocket_signal/routing.rs \ | |
| _upstream/src/websocket_signal/relay_health.rs \ | |
| _upstream/tests/mixed_relay.rs \ | |
| _upstream/tests/local_control.rs \ | |
| _upstream/tests/connection_auth_transport.rs \ | |
| _upstream/tests/control_agent.rs \ | |
| _upstream/tests/protocol_contract.rs \ | |
| _upstream/tests/websocket_signal.rs | |
| - name: Run all library tests serially | |
| run: cargo test --manifest-path _upstream/Cargo.toml --locked --lib -j 1 | |
| - name: Check all server binaries serially | |
| run: cargo check --manifest-path _upstream/Cargo.toml --locked --bins -j 1 | |
| - name: Lock authentication protobuf and client-compatible denial fixtures | |
| run: >- | |
| cargo test --manifest-path _upstream/Cargo.toml --locked | |
| --test protocol_contract -j 1 | |
| - name: Exercise HBBS WebSocket registration and cross-transport signalling | |
| run: >- | |
| cargo test --manifest-path _upstream/Cargo.toml --locked | |
| --test websocket_signal -j 1 -- --nocapture | |
| - name: Hold 1,000 registered WebSocket sessions and verify Ping/Pong | |
| run: | | |
| set -euo pipefail | |
| ulimit -n 8192 | |
| cargo test --manifest-path _upstream/Cargo.toml --locked \ | |
| --test websocket_signal -j 1 \ | |
| hbbs_sustains_one_thousand_registered_idle_websockets -- \ | |
| --ignored --exact --nocapture --test-threads=1 | |
| - name: Lock the official mixed WebSocket and native Relay contract | |
| run: >- | |
| cargo test --manifest-path _upstream/Cargo.toml --locked | |
| --test mixed_relay -j 1 -- --nocapture | |
| - name: Enforce connection JWT across every signalling transport | |
| run: >- | |
| cargo test --manifest-path _upstream/Cargo.toml --locked | |
| --test connection_auth_transport -j 1 -- --nocapture | |
| - name: Exercise bounded loopback-only local control | |
| run: >- | |
| cargo test --manifest-path _upstream/Cargo.toml --locked | |
| --test local_control -j 1 -- --nocapture | |
| - name: Exercise mTLS Control Agent and atomic configuration transactions | |
| run: >- | |
| cargo test --manifest-path _upstream/Cargo.toml --locked | |
| --test control_agent -j 1 -- --nocapture | |
| linux: | |
| name: Linux amd64 static binaries | |
| needs: | |
| - resolve | |
| - source | |
| - security-evidence | |
| - test | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 90 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - arch: amd64 | |
| target: x86_64-unknown-linux-musl | |
| steps: | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: patched-source | |
| - name: Extract source | |
| run: mkdir _upstream && tar -xzf patched-source.tar.gz -C _upstream | |
| - uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c | |
| with: | |
| toolchain: ${{ env.RUST_TOOLCHAIN }} | |
| targets: ${{ matrix.target }} | |
| - name: Install the exact cross compiler driver | |
| run: >- | |
| cargo install cross | |
| --git https://github.com/cross-rs/cross | |
| --rev "${CROSS_REVISION}" | |
| --locked | |
| - name: Cross-compile static binaries | |
| working-directory: _upstream | |
| run: >- | |
| cross build --target "${{ matrix.target }}" | |
| --locked --release --bins | |
| - name: Collect Linux release assets | |
| env: | |
| ARCH: ${{ matrix.arch }} | |
| TARGET: ${{ matrix.target }} | |
| RELEASE_TAG: ${{ needs.resolve.outputs.release_tag }} | |
| run: | | |
| set -euo pipefail | |
| mkdir artifact | |
| for binary in hbbs hbbr rustdesk-utils starry-control-agent; do | |
| install -m 0755 "_upstream/target/${TARGET}/release/${binary}" \ | |
| "artifact/${binary}-${RELEASE_TAG}-linux-${ARCH}" | |
| done | |
| tar --sort=name --mtime='UTC 1970-01-01' \ | |
| --owner=0 --group=0 --numeric-owner \ | |
| -C "_upstream/target/${TARGET}/release" -cf - \ | |
| hbbs hbbr rustdesk-utils starry-control-agent \ | |
| | gzip -n > \ | |
| "artifact/rustdesk-server-starry-${RELEASE_TAG}-linux-${ARCH}.tar.gz" | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: linux-${{ matrix.arch }} | |
| path: artifact/ | |
| if-no-files-found: error | |
| retention-days: 3 | |
| compression-level: 0 | |
| overwrite: true | |
| windows: | |
| name: Experimental Windows amd64 compatibility | |
| needs: | |
| - resolve | |
| - source | |
| - test | |
| runs-on: windows-2025 | |
| continue-on-error: true | |
| timeout-minutes: 90 | |
| steps: | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: patched-source | |
| - name: Extract source | |
| shell: pwsh | |
| run: | | |
| New-Item -ItemType Directory -Path _upstream | Out-Null | |
| tar -xzf patched-source.tar.gz -C _upstream | |
| - uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c | |
| with: | |
| toolchain: ${{ env.RUST_TOOLCHAIN }} | |
| - name: Build Windows binaries | |
| run: cargo build --manifest-path _upstream/Cargo.toml --locked --release --bins | |
| - name: Collect Windows release assets | |
| shell: pwsh | |
| env: | |
| RELEASE_TAG: ${{ needs.resolve.outputs.release_tag }} | |
| run: | | |
| New-Item -ItemType Directory -Path artifact | Out-Null | |
| # The writable Control Agent is supported and release-tested on Linux. | |
| foreach ($binary in @('hbbs', 'hbbr', 'rustdesk-utils')) { | |
| Copy-Item -LiteralPath "_upstream/target/release/$binary.exe" -Destination "artifact/$binary-$env:RELEASE_TAG-windows-amd64.exe" | |
| } | |
| Compress-Archive -Path artifact/*.exe -DestinationPath "artifact/rustdesk-server-starry-$env:RELEASE_TAG-windows-amd64.zip" | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: windows-amd64 | |
| path: artifact/ | |
| if-no-files-found: error | |
| retention-days: 3 | |
| compression-level: 0 | |
| overwrite: true | |
| deb: | |
| name: Debian ${{ matrix.arch }} packages | |
| needs: | |
| - resolve | |
| - linux | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| arch: | |
| - amd64 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: linux-${{ matrix.arch }} | |
| path: input | |
| - name: Build independent DEB packages | |
| env: | |
| ARCH: ${{ matrix.arch }} | |
| RELEASE_TAG: ${{ needs.resolve.outputs.release_tag }} | |
| DEB_VERSION: ${{ needs.resolve.outputs.deb_version }} | |
| run: | | |
| set -euo pipefail | |
| chmod +x scripts/build_deb.sh | |
| scripts/build_deb.sh hbbs "input/hbbs-${RELEASE_TAG}-linux-${ARCH}" \ | |
| "$ARCH" "$DEB_VERSION" artifact | |
| scripts/build_deb.sh hbbr "input/hbbr-${RELEASE_TAG}-linux-${ARCH}" \ | |
| "$ARCH" "$DEB_VERSION" artifact | |
| scripts/build_deb.sh utils "input/rustdesk-utils-${RELEASE_TAG}-linux-${ARCH}" \ | |
| "$ARCH" "$DEB_VERSION" artifact | |
| scripts/build_deb.sh agent \ | |
| "input/starry-control-agent-${RELEASE_TAG}-linux-${ARCH}" \ | |
| "$ARCH" "$DEB_VERSION" artifact | |
| for package in artifact/*.deb; do | |
| dpkg-deb --info "$package" >/dev/null | |
| dpkg-deb --contents "$package" >/dev/null | |
| done | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: deb-${{ matrix.arch }} | |
| path: artifact/*.deb | |
| if-no-files-found: error | |
| retention-days: 3 | |
| compression-level: 0 | |
| overwrite: true | |
| image-test: | |
| name: Docker image smoke test ${{ matrix.arch }} | |
| needs: | |
| - resolve | |
| - linux | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| arch: | |
| - amd64 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: linux-${{ matrix.arch }} | |
| path: input | |
| - name: Prepare Docker context | |
| env: | |
| ARCH: ${{ matrix.arch }} | |
| RELEASE_TAG: ${{ needs.resolve.outputs.release_tag }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p "docker/${ARCH}" | |
| install -m 0755 "input/hbbs-${RELEASE_TAG}-linux-${ARCH}" "docker/${ARCH}/hbbs" | |
| install -m 0755 "input/hbbr-${RELEASE_TAG}-linux-${ARCH}" "docker/${ARCH}/hbbr" | |
| install -m 0755 "input/rustdesk-utils-${RELEASE_TAG}-linux-${ARCH}" \ | |
| "docker/${ARCH}/rustdesk-utils" | |
| install -m 0755 \ | |
| "input/starry-control-agent-${RELEASE_TAG}-linux-${ARCH}" \ | |
| "docker/${ARCH}/starry-control-agent" | |
| - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4 | |
| with: | |
| driver-opts: image=moby/buildkit@sha256:28a898719c18a33f4e8000685287fa36fd0dd9560c6440227d3a732d79bb41d8 | |
| - name: Build the architecture image | |
| env: | |
| ARCH: ${{ matrix.arch }} | |
| run: | | |
| docker buildx build --load --platform "linux/${ARCH}" \ | |
| --build-arg "TARGETARCH=${ARCH}" \ | |
| --tag "starry-smoke:${ARCH}" docker | |
| - name: Smoke-test all commands | |
| env: | |
| ARCH: ${{ matrix.arch }} | |
| run: | | |
| set -euo pipefail | |
| docker run --rm --platform "linux/${ARCH}" "starry-smoke:${ARCH}" hbbs --help | |
| docker run --rm --platform "linux/${ARCH}" "starry-smoke:${ARCH}" hbbr --help | |
| docker run --rm --platform "linux/${ARCH}" "starry-smoke:${ARCH}" \ | |
| rustdesk-utils genkeypair >/dev/null | |
| docker run --rm --platform "linux/${ARCH}" "starry-smoke:${ARCH}" \ | |
| starry-control-agent /does-not-exist >/dev/null 2>&1 || test "$?" -ne 127 | |
| state_dir="$(mktemp -d)" | |
| container="$(docker run -d --platform "linux/${ARCH}" \ | |
| -v "${state_dir}:/root" "starry-smoke:${ARCH}" \ | |
| hbbs --starry-config=/root/starry/config.yaml)" | |
| cleanup() { | |
| docker rm -f "$container" >/dev/null 2>&1 || true | |
| } | |
| trap cleanup EXIT | |
| for _ in $(seq 1 20); do | |
| if [ -f "${state_dir}/starry/config.yaml" ] \ | |
| && [ -f "${state_dir}/starry/config.example.yaml" ]; then | |
| break | |
| fi | |
| if [ "$(docker inspect --format '{{.State.Running}}' "$container")" != true ]; then | |
| echo "HBBS stopped before generating the external configuration" >&2 | |
| docker logs "$container" >&2 || true | |
| exit 1 | |
| fi | |
| sleep 1 | |
| done | |
| test -f "${state_dir}/starry/config.yaml" | |
| test ! -s "${state_dir}/starry/config.yaml" | |
| cmp "${state_dir}/starry/config.example.yaml" config/config.example.yaml | |
| cleanup | |
| trap - EXIT | |
| package-test: | |
| name: Debian package install and runtime ${{ matrix.arch }} | |
| needs: | |
| - resolve | |
| - deb | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 25 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| arch: | |
| - amd64 | |
| steps: | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: deb-${{ matrix.arch }} | |
| path: packages | |
| - name: Install packages and exercise every command | |
| env: | |
| ARCH: ${{ matrix.arch }} | |
| run: | | |
| set -euo pipefail | |
| docker run --rm --platform "linux/${ARCH}" \ | |
| -v "${PWD}/packages:/packages:ro" \ | |
| "${DEBIAN_TEST_IMAGE}" sh -euxc ' | |
| printf "#!/bin/sh\nexit 101\n" > /usr/sbin/policy-rc.d | |
| chmod 0755 /usr/sbin/policy-rc.d | |
| apt-get update | |
| DEBIAN_FRONTEND=noninteractive apt-get install -y /packages/*.deb | |
| dpkg-query -W \ | |
| rustdesk-server-starry-hbbs \ | |
| rustdesk-server-starry-hbbr \ | |
| rustdesk-server-starry-utils \ | |
| rustdesk-server-starry-control-agent | |
| test "$(id -un rustdesk-starry)" = rustdesk-starry | |
| test "$(stat -c %a /etc/rustdesk-server-starry/managed/config.yaml)" = 640 | |
| test "$(stat -c %a /etc/rustdesk-server-starry/control-agent.yaml)" = 640 | |
| /usr/bin/hbbs --help | |
| /usr/bin/hbbr --help | |
| /usr/bin/rustdesk-utils genkeypair >/dev/null | |
| /usr/bin/starry-control-agent /does-not-exist >/dev/null 2>&1 || test "$?" -ne 127 | |
| ' | |
| release-candidate: | |
| name: Assemble auditable release candidate | |
| needs: | |
| - resolve | |
| - source | |
| - security-evidence | |
| - test | |
| - linux | |
| - deb | |
| - image-test | |
| - package-test | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: linux-amd64 | |
| path: _artifacts/linux-amd64 | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: deb-amd64 | |
| path: _artifacts/deb | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: starry-source-sbom-${{ github.sha }} | |
| path: _artifacts/source-sbom | |
| - name: Prepare image context and final release files | |
| env: | |
| RELEASE_TAG: ${{ needs.resolve.outputs.release_tag }} | |
| PATCH_VERSION: ${{ needs.resolve.outputs.patch_version }} | |
| UPSTREAM_REF: ${{ needs.resolve.outputs.upstream_ref }} | |
| UPSTREAM_COMMIT: ${{ needs.source.outputs.upstream_commit }} | |
| UPSTREAM_COMMON_COMMIT: ${{ needs.source.outputs.upstream_common_commit }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p candidate/docker/amd64 candidate/release-assets | |
| cp docker/Dockerfile candidate/docker/Dockerfile | |
| for arch in amd64; do | |
| install -m 0755 "_artifacts/linux-${arch}/hbbs-${RELEASE_TAG}-linux-${arch}" \ | |
| "candidate/docker/${arch}/hbbs" | |
| install -m 0755 "_artifacts/linux-${arch}/hbbr-${RELEASE_TAG}-linux-${arch}" \ | |
| "candidate/docker/${arch}/hbbr" | |
| install -m 0755 \ | |
| "_artifacts/linux-${arch}/rustdesk-utils-${RELEASE_TAG}-linux-${arch}" \ | |
| "candidate/docker/${arch}/rustdesk-utils" | |
| install -m 0755 \ | |
| "_artifacts/linux-${arch}/starry-control-agent-${RELEASE_TAG}-linux-${arch}" \ | |
| "candidate/docker/${arch}/starry-control-agent" | |
| done | |
| cp _artifacts/linux-amd64/* candidate/release-assets/ | |
| cp _artifacts/deb/* candidate/release-assets/ | |
| cp _artifacts/source-sbom/starry-source.spdx.json \ | |
| candidate/release-assets/ | |
| cp config/config.example.yaml candidate/release-assets/config.example.yaml | |
| cp examples/compose.yaml candidate/release-assets/compose.yaml | |
| cp examples/.env.example candidate/release-assets/compose.env.example | |
| python3 scripts/export_docs.py release \ | |
| --output candidate/release-assets \ | |
| --ref "$GITHUB_SHA" --repository "$GITHUB_REPOSITORY" | |
| tar --sort=name --mtime='UTC 1970-01-01' \ | |
| --owner=0 --group=0 --numeric-owner -cf - \ | |
| examples config docs/examples \ | |
| | gzip -n > \ | |
| "candidate/release-assets/deployment-examples-${RELEASE_TAG}.tar.gz" | |
| cat > candidate/release-assets/BUILD-INPUTS.txt <<EOF | |
| repository=${GITHUB_REPOSITORY} | |
| source_commit=${GITHUB_SHA} | |
| upstream_repository=rustdesk/rustdesk-server | |
| upstream_ref=${UPSTREAM_REF} | |
| upstream_commit=${UPSTREAM_COMMIT} | |
| upstream_hbb_common_commit=${UPSTREAM_COMMON_COMMIT} | |
| release_tag=${RELEASE_TAG} | |
| rust_toolchain=${RUST_TOOLCHAIN} | |
| cross_revision=${CROSS_REVISION} | |
| EOF | |
| - name: Generate final-filesystem SBOM and checksums | |
| run: | | |
| set -euo pipefail | |
| sh scripts/install_ci_tools.sh "${RUNNER_TEMP}/starry-tools" | |
| "${RUNNER_TEMP}/starry-tools/syft" scan \ | |
| dir:candidate/release-assets \ | |
| -o spdx-json=candidate/starry-release.spdx.json | |
| mv candidate/starry-release.spdx.json candidate/release-assets/ | |
| ( | |
| cd candidate/release-assets | |
| checksums="$(mktemp)" | |
| find . -maxdepth 1 -type f ! -name SHA256SUMS \ | |
| -printf '%f\0' | LC_ALL=C sort -z | xargs -0 sha256sum -- \ | |
| > "$checksums" | |
| mv "$checksums" SHA256SUMS | |
| sha256sum --check SHA256SUMS | |
| ) | |
| - name: Verify candidate contents and Docker context | |
| env: | |
| RELEASE_TAG: ${{ needs.resolve.outputs.release_tag }} | |
| run: | | |
| set -euo pipefail | |
| test -s candidate/release-assets/SHA256SUMS | |
| test -s candidate/release-assets/starry-release.spdx.json | |
| test -s candidate/release-assets/starry-source.spdx.json | |
| test "$(find candidate/release-assets -maxdepth 1 -name '*.deb' | wc -l)" -eq 4 | |
| test "$(find candidate/release-assets -maxdepth 1 -name '*.tar.gz' | wc -l)" -eq 2 | |
| test "$(find candidate/release-assets -maxdepth 1 -name '*.zip' | wc -l)" -eq 0 | |
| for arch in amd64; do | |
| for binary in hbbs hbbr rustdesk-utils starry-control-agent; do | |
| test -x "candidate/docker/${arch}/${binary}" | |
| done | |
| done | |
| ! find candidate -type f \ | |
| \( -name '*.key' -o -name '*.pem' -o -name '*.p12' \) -print -quit \ | |
| | grep -q . | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: starry-release-candidate-${{ needs.resolve.outputs.release_tag }} | |
| path: candidate/ | |
| if-no-files-found: error | |
| retention-days: 7 | |
| compression-level: 0 | |
| overwrite: true | |
| publish: | |
| name: Publish release and linux/amd64 image | |
| needs: | |
| - resolve | |
| - release-candidate | |
| if: needs.resolve.outputs.skip != 'true' && needs.resolve.outputs.publish == 'true' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 45 | |
| permissions: | |
| attestations: write | |
| contents: write | |
| id-token: write | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: starry-release-candidate-${{ needs.resolve.outputs.release_tag }} | |
| path: candidate | |
| - name: Re-verify candidate checksums before signing | |
| working-directory: candidate/release-assets | |
| run: sha256sum --check SHA256SUMS | |
| - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4 | |
| with: | |
| driver-opts: image=moby/buildkit@sha256:28a898719c18a33f4e8000685287fa36fd0dd9560c6440227d3a732d79bb41d8 | |
| - uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ github.token }} | |
| - name: Create or verify immutable annotated release tag | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RELEASE_TAG: ${{ needs.resolve.outputs.release_tag }} | |
| run: | | |
| set -euo pipefail | |
| verify_tag() { | |
| local tag_object_sha | |
| test "$(gh api \ | |
| "repos/${GITHUB_REPOSITORY}/git/ref/tags/${RELEASE_TAG}" \ | |
| --jq .object.type)" = tag | |
| tag_object_sha="$(gh api \ | |
| "repos/${GITHUB_REPOSITORY}/git/ref/tags/${RELEASE_TAG}" \ | |
| --jq .object.sha)" | |
| printf '%s' "$tag_object_sha" | grep -Eq '^[0-9a-f]{40}$' | |
| test "$(gh api \ | |
| "repos/${GITHUB_REPOSITORY}/git/tags/${tag_object_sha}" \ | |
| --jq .tag)" = "$RELEASE_TAG" | |
| test "$(gh api \ | |
| "repos/${GITHUB_REPOSITORY}/git/tags/${tag_object_sha}" \ | |
| --jq .object.type)" = commit | |
| test "$(gh api \ | |
| "repos/${GITHUB_REPOSITORY}/git/tags/${tag_object_sha}" \ | |
| --jq .object.sha)" = "$GITHUB_SHA" | |
| } | |
| if gh api "repos/${GITHUB_REPOSITORY}/git/ref/tags/${RELEASE_TAG}" \ | |
| >/dev/null 2>&1; then | |
| verify_tag | |
| echo "exact annotated tag already exists: $RELEASE_TAG" | |
| exit 0 | |
| fi | |
| tag_object_sha="$(gh api --method POST \ | |
| "repos/${GITHUB_REPOSITORY}/git/tags" \ | |
| -f tag="$RELEASE_TAG" \ | |
| -f message="rustdesk-server-starry ${RELEASE_TAG}" \ | |
| -f object="$GITHUB_SHA" -f type=commit --jq .sha)" | |
| printf '%s' "$tag_object_sha" | grep -Eq '^[0-9a-f]{40}$' | |
| gh api --method POST "repos/${GITHUB_REPOSITORY}/git/refs" \ | |
| -f ref="refs/tags/${RELEASE_TAG}" -f sha="$tag_object_sha" \ | |
| --jq .ref | grep -Fx "refs/tags/${RELEASE_TAG}" | |
| verify_tag | |
| - name: Push the final linux/amd64 image | |
| id: final-image | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7 | |
| with: | |
| context: candidate/docker | |
| platforms: linux/amd64 | |
| push: true | |
| provenance: mode=max | |
| sbom: true | |
| tags: | | |
| ${{ env.IMAGE_NAME }}:${{ needs.resolve.outputs.release_tag }} | |
| ${{ env.IMAGE_NAME }}:latest | |
| labels: | | |
| org.opencontainers.image.title=rustdesk-server-starry | |
| org.opencontainers.image.source=https://github.com/${{ github.repository }} | |
| org.opencontainers.image.url=https://github.com/${{ github.repository }}/releases/tag/${{ needs.resolve.outputs.release_tag }} | |
| org.opencontainers.image.documentation=https://github.com/${{ github.repository }}/blob/${{ github.sha }}/docs/container/CONTAINER.md | |
| org.opencontainers.image.version=${{ needs.resolve.outputs.release_tag }} | |
| org.opencontainers.image.revision=${{ github.sha }} | |
| org.opencontainers.image.licenses=AGPL-3.0-only | |
| org.opencontainers.image.description=patch-v1.3.0 Starry HBBS with connection authentication, GEO Relay quality scoring, safe configuration activation, WebSocket signalling, and an optional mTLS Control Agent; the same image bundles HBBR with compatible Relay data forwarding plus active probes and load telemetry, while account/API services and MMDB data are not included | |
| annotations: | | |
| index:org.opencontainers.image.title=rustdesk-server-starry | |
| index:org.opencontainers.image.source=https://github.com/${{ github.repository }} | |
| index:org.opencontainers.image.url=https://github.com/${{ github.repository }}/releases/tag/${{ needs.resolve.outputs.release_tag }} | |
| index:org.opencontainers.image.documentation=https://github.com/${{ github.repository }}/blob/${{ github.sha }}/docs/container/CONTAINER.md | |
| index:org.opencontainers.image.version=${{ needs.resolve.outputs.release_tag }} | |
| index:org.opencontainers.image.revision=${{ github.sha }} | |
| index:org.opencontainers.image.licenses=AGPL-3.0-only | |
| index:org.opencontainers.image.description=patch-v1.3.0 Starry HBBS with connection authentication, GEO Relay quality scoring, safe configuration activation, WebSocket signalling, and an optional mTLS Control Agent; the same image bundles HBBR with compatible Relay data forwarding plus active probes and load telemetry, while account/API services and MMDB data are not included | |
| - name: Record image and OpenAPI/schema publication summary | |
| env: | |
| PUSHED_DIGEST: ${{ steps.final-image.outputs.digest }} | |
| RELEASE_TAG: ${{ needs.resolve.outputs.release_tag }} | |
| run: | | |
| set -euo pipefail | |
| printf '%s' "$PUSHED_DIGEST" | grep -Eq '^sha256:[0-9a-f]{64}$' | |
| image_ref="${IMAGE_NAME}:${RELEASE_TAG}" | |
| registry_digest="$(docker buildx imagetools inspect "$image_ref" \ | |
| | sed -n 's/^Digest:[[:space:]]*//p' | head -n 1)" | |
| test "$registry_digest" = "$PUSHED_DIGEST" | |
| manifest_json="${RUNNER_TEMP}/starry-image-index.json" | |
| docker buildx imagetools inspect "${IMAGE_NAME}@${PUSHED_DIGEST}" \ | |
| --raw > "$manifest_json" | |
| linux_amd64_count="$(jq '[.manifests[] | select( | |
| .platform.os == "linux" and .platform.architecture == "amd64" | |
| )] | length' "$manifest_json")" | |
| test "$linux_amd64_count" = 1 | |
| linux_amd64_digest="$(jq -r '.manifests[] | select( | |
| .platform.os == "linux" and .platform.architecture == "amd64" | |
| ) | .digest' "$manifest_json")" | |
| printf '%s' "$linux_amd64_digest" \ | |
| | grep -Eq '^sha256:[0-9a-f]{64}$' | |
| upstream_ref="$(sed -n 's/^upstream_ref=//p' \ | |
| candidate/release-assets/BUILD-INPUTS.txt)" | |
| upstream_commit="$(sed -n 's/^upstream_commit=//p' \ | |
| candidate/release-assets/BUILD-INPUTS.txt)" | |
| upstream_common_commit="$(sed -n \ | |
| 's/^upstream_hbb_common_commit=//p' \ | |
| candidate/release-assets/BUILD-INPUTS.txt)" | |
| python3 scripts/write_release_summary.py \ | |
| --output candidate/release-assets/STARRY-RELEASE-SUMMARY.json \ | |
| --release-tag "$RELEASE_TAG" \ | |
| --source-commit "$GITHUB_SHA" \ | |
| --upstream-ref "$upstream_ref" \ | |
| --upstream-commit "$upstream_commit" \ | |
| --upstream-hbb-common-commit "$upstream_common_commit" \ | |
| --image-reference "$image_ref" \ | |
| --image-index-digest "$PUSHED_DIGEST" \ | |
| --image-linux-amd64-digest "$linux_amd64_digest" | |
| jq -e \ | |
| --arg tag "$RELEASE_TAG" \ | |
| --arg source "$GITHUB_SHA" \ | |
| --arg index "$PUSHED_DIGEST" \ | |
| --arg amd64 "$linux_amd64_digest" \ | |
| '.release.tag == $tag and .release.source_commit == $source | |
| and .image.index_digest == $index | |
| and .image.platforms["linux/amd64"] == $amd64' \ | |
| candidate/release-assets/STARRY-RELEASE-SUMMARY.json >/dev/null | |
| ( | |
| cd candidate/release-assets | |
| checksums="$(mktemp)" | |
| find . -maxdepth 1 -type f ! -name SHA256SUMS \ | |
| -printf '%f\0' | LC_ALL=C sort -z | xargs -0 sha256sum -- \ | |
| > "$checksums" | |
| mv "$checksums" SHA256SUMS | |
| sha256sum --check SHA256SUMS | |
| ) | |
| - name: Sign build provenance for every candidate subject | |
| id: provenance | |
| uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3.2.0 | |
| with: | |
| subject-checksums: candidate/release-assets/SHA256SUMS | |
| - name: Sign the candidate SBOM assertion | |
| id: sbom-attestation | |
| uses: actions/attest-sbom@4651f806c01d8637787e274ac3bdf724ef169f34 # v3.0.0 | |
| with: | |
| subject-checksums: candidate/release-assets/SHA256SUMS | |
| sbom-path: candidate/release-assets/starry-release.spdx.json | |
| - name: Attach portable Sigstore bundles and refresh checksums | |
| env: | |
| PROVENANCE_BUNDLE: ${{ steps.provenance.outputs.bundle-path }} | |
| SBOM_BUNDLE: ${{ steps.sbom-attestation.outputs.bundle-path }} | |
| run: | | |
| set -euo pipefail | |
| cp "$PROVENANCE_BUNDLE" \ | |
| candidate/release-assets/BUILD-PROVENANCE.sigstore.json | |
| cp "$SBOM_BUNDLE" \ | |
| candidate/release-assets/SBOM-ATTESTATION.sigstore.json | |
| ( | |
| cd candidate/release-assets | |
| checksums="$(mktemp)" | |
| find . -maxdepth 1 -type f ! -name SHA256SUMS \ | |
| -printf '%f\0' | LC_ALL=C sort -z | xargs -0 sha256sum -- \ | |
| > "$checksums" | |
| mv "$checksums" SHA256SUMS | |
| sha256sum --check SHA256SUMS | |
| ) | |
| - name: Publish GitHub release assets | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RELEASE_TAG: ${{ needs.resolve.outputs.release_tag }} | |
| UPSTREAM_REF: ${{ needs.resolve.outputs.upstream_ref }} | |
| PATCH_VERSION: ${{ needs.resolve.outputs.patch_version }} | |
| run: | | |
| set -euo pipefail | |
| notes_file="candidate/release-assets/RELEASE-NOTES-patch-v${PATCH_VERSION}.md" | |
| chinese_notes="docs/releases/RELEASE-NOTES-patch-v${PATCH_VERSION}.zh-CN.md" | |
| test -f "$notes_file" | |
| test -f "$chinese_notes" | |
| cat > release-notes.md <<EOF | |
| Based on official rustdesk/rustdesk-server ${UPSTREAM_REF}. | |
| Container image: https://github.com/${GITHUB_REPOSITORY}/pkgs/container/rustdesk-server-starry | |
| Recommended Docker deployment: https://github.com/${GITHUB_REPOSITORY}/wiki/Docker-Deployment | |
| Container guide: https://github.com/${GITHUB_REPOSITORY}/blob/${GITHUB_SHA}/docs/container/CONTAINER.md | |
| Single-host Compose asset: https://github.com/${GITHUB_REPOSITORY}/releases/download/${RELEASE_TAG}/compose.yaml | |
| Control Agent sidecar example: https://github.com/${GITHUB_REPOSITORY}/blob/${RELEASE_TAG}/examples/control-agent/compose.yaml | |
| 中文发布说明:https://github.com/${GITHUB_REPOSITORY}/blob/${GITHUB_SHA}/${chinese_notes} | |
| Verify binaries, packages, documentation, and the deployment-example | |
| archive against \`SHA256SUMS\` before use. | |
| EOF | |
| cat "$notes_file" >> release-notes.md | |
| if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then | |
| gh release upload "$RELEASE_TAG" candidate/release-assets/* --clobber | |
| gh release edit "$RELEASE_TAG" --notes-file release-notes.md --latest | |
| else | |
| gh release create "$RELEASE_TAG" candidate/release-assets/* \ | |
| --title "rustdesk-server-starry $RELEASE_TAG" \ | |
| --notes-file release-notes.md \ | |
| --latest | |
| fi | |
| - name: Write publication summary | |
| env: | |
| PUSHED_DIGEST: ${{ steps.final-image.outputs.digest }} | |
| RELEASE_TAG: ${{ needs.resolve.outputs.release_tag }} | |
| run: | | |
| { | |
| echo "## Starry publication completed" | |
| echo | |
| echo "- Release: \`$RELEASE_TAG\`" | |
| echo "- Image: \`${IMAGE_NAME}:$RELEASE_TAG\`" | |
| echo "- Image index: \`$PUSHED_DIGEST\`" | |
| echo "- Rolling image: \`${IMAGE_NAME}:latest\`" | |
| echo "- Contract digest summary: \`STARRY-RELEASE-SUMMARY.json\`" | |
| } >> "$GITHUB_STEP_SUMMARY" |