diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 8be9519..07c9014 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -1,6 +1,7 @@ name: Check on: + workflow_dispatch: push: branches: [main] pull_request: @@ -42,3 +43,34 @@ jobs: ! grep -Fq '${GRIDPOOL_PAYOUT_ADDRESS:-}' gridlabs-gridpool/templates/init.sh grep -q 'boot_portal_config.local.json' gridlabs-gridpool/templates/gridpool-entrypoint.sh grep -q 'boot_portal_config.local.json' gridlabs-gridpool/templates/sv2-entrypoint.sh + - name: Verify release inputs and package contract + run: ./scripts/verify-package.sh + + secrets: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Scan repository history for secrets + run: >- + docker run --rm -v "$PWD:/repo" + ghcr.io/gitleaks/gitleaks@sha256:c00b6bd0aeb3071cbcb79009cb16a60dd9e0a7c60e2be9ab65d25e6bc8abbb7f + detect --source=/repo --redact --no-banner + + image-scan: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + image: + - ghcr.io/gridlabs-science/boot-protocol@sha256:8672c835b14f8fcad8a358e5b80ae945d6973b5039c706437b3b1c4bdff6f5d5 + - ghcr.io/gridlabs-science/gridpool-sv2-pool@sha256:3de54e9c51953d2b5089ae90a25b9a0fa046c18c4ae0139b768b77a4cf0ed50e + steps: + - uses: aquasecurity/trivy-action@v0.36.0 + with: + image-ref: ${{ matrix.image }} + format: table + severity: CRITICAL,HIGH + ignore-unfixed: true + exit-code: '1' diff --git a/.github/workflows/release-candidate.yml b/.github/workflows/release-candidate.yml new file mode 100644 index 0000000..89cecd5 --- /dev/null +++ b/.github/workflows/release-candidate.yml @@ -0,0 +1,38 @@ +name: Package release candidate + +on: + workflow_dispatch: + push: + tags: ['v*-beta.*'] + +permissions: + contents: read + id-token: write + attestations: write + +jobs: + package: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: ./scripts/verify-package.sh + - name: Create source package + run: | + tar -czf gridpool-umbrel.tar.gz gridlabs-gridpool + sha256sum gridpool-umbrel.tar.gz > gridpool-umbrel.tar.gz.sha256 + - name: Generate SPDX SBOM + uses: anchore/sbom-action@v0.24.0 + with: + path: gridlabs-gridpool + format: spdx-json + output-file: gridpool-umbrel.spdx.json + - uses: actions/attest-build-provenance@v2 + with: + subject-path: gridpool-umbrel.tar.gz + - uses: actions/upload-artifact@v4 + with: + name: gridpool-umbrel + path: | + gridpool-umbrel.tar.gz + gridpool-umbrel.tar.gz.sha256 + gridpool-umbrel.spdx.json diff --git a/README.md b/README.md index a7fe41f..924296a 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ This is a sideload beta. The application UI remains behind Umbrel authentication, the node participates outbound-only by default, and only the SV2 miner port plus the UDP peer-relay port are published. +The wrapper pins immutable, attested multi-architecture OCI image digests. It +does not follow a mutable branch or `latest` image. + ## Configure and install Clone and install the package, then open GridPool from the Umbrel dashboard. On @@ -47,8 +50,31 @@ token, SV2 authority keys, and the durable proof spool. Back it up before uninstalling or moving the app. Bitcoin chain data is owned by the separate Bitcoin app and is not duplicated. +Before upgrading or uninstalling, stop GridPool and back up the complete data +directory with ownership and permissions preserved. Record the node-ID +fingerprint shown by the GridPool UI. Never copy Bitcoin RPC credentials from +the generated config into a support bundle. + +Upgrade by replacing the app definition and recreating the app containers while +leaving `gridlabs-gridpool/data` in place. After startup, verify that the node ID, +payout address, Bitcoin authority, and SV2 authority are unchanged. + +For recovery, reinstall the same or a compatible package version, stop it, +restore the saved data directory, then start the app. Deleting `pool_state.json` +is not a supported recovery procedure. A normal Umbrel uninstall may remove app +data, so retain a verified external backup first. + +The legacy dashboard is disabled in the appliance package. Native SV2 is the +only supported miner-facing service; DATUM and raw SV1 remain absent. + ## Current limitations - Core IPC is intentionally not mounted across the app boundary. Standard `getblocktemplate`/`submitblock` RPC is used for both Core and Knots. - DATUM and Stratum V1 adapters are not included in the initial appliance beta. + +## Release verification + +```bash +./scripts/verify-package.sh +``` diff --git a/gridlabs-gridpool/docker-compose.yml b/gridlabs-gridpool/docker-compose.yml index 7dc1d01..9e3490e 100644 --- a/gridlabs-gridpool/docker-compose.yml +++ b/gridlabs-gridpool/docker-compose.yml @@ -5,7 +5,7 @@ services: APP_PORT: 5000 init: - image: ghcr.io/gridlabs-science/gridpool-sv2-pool:sha-bba078e + image: ghcr.io/gridlabs-science/gridpool-sv2-pool@sha256:3de54e9c51953d2b5089ae90a25b9a0fa046c18c4ae0139b768b77a4cf0ed50e user: "0:0" entrypoint: ["/bin/sh", "/templates/init.sh"] environment: @@ -20,7 +20,7 @@ services: - ${APP_DATA_DIR}/templates:/templates:ro gridpool: - image: ghcr.io/gridlabs-science/boot-protocol:sha-9ac862a + image: ghcr.io/gridlabs-science/boot-protocol@sha256:8672c835b14f8fcad8a358e5b80ae945d6973b5039c706437b3b1c4bdff6f5d5 depends_on: init: condition: service_completed_successfully @@ -43,7 +43,7 @@ services: retries: 4 sv2: - image: ghcr.io/gridlabs-science/gridpool-sv2-pool:sha-bba078e + image: ghcr.io/gridlabs-science/gridpool-sv2-pool@sha256:3de54e9c51953d2b5089ae90a25b9a0fa046c18c4ae0139b768b77a4cf0ed50e depends_on: init: condition: service_completed_successfully diff --git a/gridlabs-gridpool/templates/boot_portal_config.json.template b/gridlabs-gridpool/templates/boot_portal_config.json.template index 0a457c8..572bb37 100644 --- a/gridlabs-gridpool/templates/boot_portal_config.json.template +++ b/gridlabs-gridpool/templates/boot_portal_config.json.template @@ -9,7 +9,7 @@ "bitcoin_zmq_rawblock_endpoint": "${BITCOIN_ZMQ_RAWBLOCK}", "bitcoin_network": "mainnet", "enable_web_ui": true, - "enable_legacy_ui": true, + "enable_legacy_ui": false, "boot_network_id": "mainnet-beta", "boot_protocol_version": 22, "v22_activation_block_height": 959500, diff --git a/gridlabs-gridpool/umbrel-app.yml b/gridlabs-gridpool/umbrel-app.yml index cf33718..c533dd1 100644 --- a/gridlabs-gridpool/umbrel-app.yml +++ b/gridlabs-gridpool/umbrel-app.yml @@ -3,7 +3,7 @@ id: gridlabs-gridpool implements: [] category: bitcoin name: GridPool -version: "0.1.0-beta.5" +version: "0.2.2-beta.2" icon: https://raw.githubusercontent.com/gridlabs-science/gridpool-umbrel/main/gridlabs-gridpool/icon.svg tagline: Sovereign, non-custodial pooled mining description: >- @@ -21,7 +21,6 @@ path: "" defaultUsername: "" defaultPassword: "" releaseNotes: >- - Makes first-run payout setup entirely UI-driven. GridPool restarts itself - after setup and native SV2 starts from the persisted address without custom - Umbrel environment variables. + Early beta with V2.2 security hardening, native SV2 mining, attached-node + safety checks, authenticated UDP relay, and digest-pinned images. gallery: [] diff --git a/scripts/verify-package.sh b/scripts/verify-package.sh new file mode 100755 index 0000000..2034765 --- /dev/null +++ b/scripts/verify-package.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail + +compose="gridlabs-gridpool/docker-compose.yml" +template="gridlabs-gridpool/templates/boot_portal_config.json.template" + +for script in gridlabs-gridpool/templates/*.sh; do sh -n "$script"; done +ruby -e 'require "yaml"; YAML.load_file(ARGV[0])' "$compose" +ruby -e 'require "yaml"; YAML.load_file(ARGV[0])' gridlabs-gridpool/umbrel-app.yml + +references="$(grep -oE 'ghcr\.io/[^ @]+@sha256:[0-9a-f]{64}' "$compose" | sort -u)" +[[ "$(printf '%s\n' "$references" | sed '/^$/d' | wc -l)" -eq 2 ]] +! grep -Eq 'image: .*:sha-' "$compose" + +grep -q '"enable_legacy_ui": false' "$template" +grep -q '"enable_admin_api": false' "$template" +! grep -q 'env_file' "$compose" +! grep -Eq '(^|[[:space:]])(8332|28332|28333|34290|5000):' "$compose" +grep -q '34265:34265/tcp' "$compose" +grep -q '5001:5001/udp' "$compose" + +for reference in $references; do + if command -v docker >/dev/null 2>&1; then + inspection="$(docker buildx imagetools inspect "$reference")" + grep -q 'linux/amd64' <<<"$inspection" + grep -q 'linux/arm64' <<<"$inspection" + fi +done + +echo "Umbrel package contract and immutable release inputs verified"