diff --git a/.github/workflows/validate-5tratsmack-metadata.yml b/.github/workflows/validate-5tratsmack-metadata.yml index aaedce9..bb227c7 100644 --- a/.github/workflows/validate-5tratsmack-metadata.yml +++ b/.github/workflows/validate-5tratsmack-metadata.yml @@ -3,12 +3,16 @@ name: Validate 5tratSmack store metadata on: pull_request: paths: + - "README.md" - "willitmod-dev-5tratsmack/**" + - "scripts/validate-5tratsmack-metadata.py" - ".github/workflows/validate-5tratsmack-metadata.yml" push: branches: [main] paths: + - "README.md" - "willitmod-dev-5tratsmack/**" + - "scripts/validate-5tratsmack-metadata.py" - ".github/workflows/validate-5tratsmack-metadata.yml" permissions: @@ -21,53 +25,4 @@ jobs: - uses: actions/checkout@v4 - name: Check compatible manifests and versions - run: | - python3 - <<'PY' - from pathlib import Path - import re - - app_dir = Path("willitmod-dev-5tratsmack") - primary = app_dir / "5tratstore-app.yml" - compatibility = app_dir / "umbrel-app.yml" - compose = app_dir / "docker-compose.yml" - - for path in (primary, compatibility, compose): - if not path.is_file() or not path.stat().st_size: - raise SystemExit(f"missing required store file: {path}") - - primary_bytes = primary.read_bytes() - compatibility_bytes = compatibility.read_bytes() - if primary_bytes != compatibility_bytes: - raise SystemExit( - "5tratstore-app.yml and umbrel-app.yml must remain byte-identical" - ) - - manifest_text = primary_bytes.decode("utf-8") - compose_text = compose.read_text(encoding="utf-8") - - def one(pattern: str, text: str, label: str) -> str: - matches = re.findall(pattern, text, flags=re.MULTILINE) - if len(matches) != 1: - raise SystemExit(f"expected one {label}, found {len(matches)}") - return matches[0] - - manifest_version = one( - r'^version:\s*["\']?([^"\'\s]+)', manifest_text, "manifest version" - ) - app_version = one( - r'^\s{6}APP_VERSION:\s*["\']?([^"\'\s]+)', compose_text, "APP_VERSION" - ) - release_tag = one( - r'^\s{6}FIVETRAT_RELEASE_TAG:\s*["\']?([^"\'\s]+)', - compose_text, - "FIVETRAT_RELEASE_TAG", - ) - if len({manifest_version, app_version, release_tag}) != 1: - raise SystemExit( - "store version mismatch: " - f"manifest={manifest_version}, APP_VERSION={app_version}, " - f"FIVETRAT_RELEASE_TAG={release_tag}" - ) - - print(f"5tratSmack store metadata is consistent at {manifest_version}") - PY + run: python3 scripts/validate-5tratsmack-metadata.py diff --git a/README.md b/README.md index 03fedb7..ead6a0b 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Development/test app store for WillItMod apps. - **AxeDGB** (`willitmod-dev-dgb`) - `0.9.179-dev` - **AxePPC** (`willitmod-dev-ppc`) - `0.2.30-dev` - **AxeXEC** (`willitmod-dev-xec`) - `0.1.14-dev` -- **5tratSmack** (`willitmod-dev-5tratsmack`) - `0.11.10` +- **5tratSmack** (`willitmod-dev-5tratsmack`) - `0.11.11` - **PowPow** (`willitmod-dev-powpow`) - `0.2.31-dev` Use the app manifest in each app directory as the current source of truth for the store-visible version number. diff --git a/scripts/validate-5tratsmack-metadata.py b/scripts/validate-5tratsmack-metadata.py new file mode 100644 index 0000000..295d492 --- /dev/null +++ b/scripts/validate-5tratsmack-metadata.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +from pathlib import Path +import re + + +REPO_ROOT = Path(__file__).resolve().parents[1] +APP_DIR = REPO_ROOT / "willitmod-dev-5tratsmack" + +EXPECTED_VERSION = "0.11.11" +EXPECTED_PHASE = "RC1" +EXPECTED_SOURCE_REVISION = "bd3aa4dbb0e915c7593e461ebf09546654d49134" +EXPECTED_APP_REF = ( + "ghcr.io/willitmod/5tratsmack-app:0.11.11-rc.bd3aa4dbb0e9@" + "sha256:329b820a39beed7be4441d3c10ce694d7dedc579b62d494084bfcfe8c7755909" +) +EXPECTED_CKPOOL_REF = ( + "ghcr.io/willitmod/5tratsmack-ckpool:0.11.3-rc.a992f40e96d4@" + "sha256:95a1a5f343d579206a0f8bb3c961cafa7500b5d487211a0cfb7b989cf34b895e" +) + +primary = APP_DIR / "5tratstore-app.yml" +compatibility = APP_DIR / "umbrel-app.yml" +compose = APP_DIR / "docker-compose.yml" +readme = REPO_ROOT / "README.md" + +for path in (primary, compatibility, compose, readme): + if not path.is_file() or not path.stat().st_size: + raise SystemExit(f"missing required store file: {path}") + +primary_bytes = primary.read_bytes() +compatibility_bytes = compatibility.read_bytes() +if primary_bytes != compatibility_bytes: + raise SystemExit("5tratstore-app.yml and umbrel-app.yml must remain byte-identical") + +manifest_text = primary_bytes.decode("utf-8") +compose_text = compose.read_text(encoding="utf-8") +readme_text = readme.read_text(encoding="utf-8") + + +def one(pattern: str, text: str, label: str) -> str: + matches = re.findall(pattern, text, flags=re.MULTILINE) + if len(matches) != 1: + raise SystemExit(f"expected one {label}, found {len(matches)}") + return matches[0] + + +manifest_version = one( + r'^version:\s*["\']?([^"\'\s]+)', manifest_text, "manifest version" +) +manifest_id = one(r"^id:\s*([^\s]+)", manifest_text, "manifest id") +source_revision = one( + r"^# Release source revision:\s*([0-9a-f]{40})$", + compose_text, + "release source revision", +) +app_version = one( + r'^\s{6}APP_VERSION:\s*["\']?([^"\'\s]+)', compose_text, "APP_VERSION" +) +release_phase = one( + r'^\s{6}APP_RELEASE_PHASE:\s*["\']?([^"\'\s]+)', + compose_text, + "APP_RELEASE_PHASE", +) +release_tag = one( + r'^\s{6}FIVETRAT_RELEASE_TAG:\s*["\']?([^"\'\s]+)', + compose_text, + "FIVETRAT_RELEASE_TAG", +) +app_revision = one( + r"^\s{6}APP_REVISION:\s*([0-9a-f]{40})$", compose_text, "APP_REVISION" +) + +if manifest_id != "willitmod-dev-5tratsmack": + raise SystemExit(f"unexpected manifest id: {manifest_id}") +if {manifest_version, app_version, release_tag} != {EXPECTED_VERSION}: + raise SystemExit( + "store version mismatch: " + f"manifest={manifest_version}, APP_VERSION={app_version}, " + f"FIVETRAT_RELEASE_TAG={release_tag}, expected={EXPECTED_VERSION}" + ) +if release_phase != EXPECTED_PHASE: + raise SystemExit( + f"unexpected APP_RELEASE_PHASE: {release_phase}, expected {EXPECTED_PHASE}" + ) +if source_revision != EXPECTED_SOURCE_REVISION or app_revision != EXPECTED_SOURCE_REVISION: + raise SystemExit( + "source revision mismatch: " + f"comment={source_revision}, APP_REVISION={app_revision}, " + f"expected={EXPECTED_SOURCE_REVISION}" + ) + +app_refs = re.findall( + r"^\s+(?:image|APP_IMAGE):\s*(ghcr\.io/willitmod/5tratsmack-app:\S+)$", + compose_text, + flags=re.MULTILINE, +) +if app_refs != [EXPECTED_APP_REF, EXPECTED_APP_REF]: + raise SystemExit(f"app image references are not the tested candidate: {app_refs}") + +ckpool_refs = re.findall( + r"^\s+(?:image|CKPOOL_IMAGE):\s*(ghcr\.io/willitmod/5tratsmack-ckpool:\S+)$", + compose_text, + flags=re.MULTILINE, +) +if ckpool_refs != [EXPECTED_CKPOOL_REF, EXPECTED_CKPOOL_REF]: + raise SystemExit(f"CKPool references changed during the app-only release: {ckpool_refs}") + +required_compose_lines = ( + " APP_CHANNEL: DEV", + " FIVETRAT_STORE_UPDATE_CHANNEL: dev", + ' FIVETRAT_UPDATER_ENABLED: "0"', +) +for line in required_compose_lines: + if compose_text.count(line) != 1: + raise SystemExit(f"expected one exact compose line: {line}") + +expected_readme_line = ( + "- **5tratSmack** (`willitmod-dev-5tratsmack`) - `0.11.11`" +) +if readme_text.count(expected_readme_line) != 1: + raise SystemExit("README current-version entry is not exactly 0.11.11") + +for release_note_fragment in ( + "authenticated 5tratumOS DEV catalogue", + "never offers a downgrade", + "default-on 5% development contribution", +): + if release_note_fragment not in manifest_text: + raise SystemExit(f"release notes missing: {release_note_fragment}") + +print( + "5tratSmack DEV metadata verified: " + f"version={EXPECTED_VERSION} source={EXPECTED_SOURCE_REVISION} " + "app candidate pinned; CKPool unchanged" +) diff --git a/willitmod-dev-5tratsmack/5tratstore-app.yml b/willitmod-dev-5tratsmack/5tratstore-app.yml index ad00431..a9daa39 100644 --- a/willitmod-dev-5tratsmack/5tratstore-app.yml +++ b/willitmod-dev-5tratsmack/5tratstore-app.yml @@ -2,7 +2,7 @@ manifestVersion: 1 id: willitmod-dev-5tratsmack category: altcoin name: 5tratSmack -version: "0.11.10" +version: "0.11.11" tagline: Home-miner 5TRAT node, wallet, solo pool and atomic trade lab description: >- Install and synchronize a complete 5TRAT node, create or restore an encrypted @@ -37,18 +37,14 @@ path: "" defaultUsername: "" defaultPassword: "" releaseNotes: >- - Jackpot and reliability update: Pink and Gold bonuses settle to the previous - block's payout script while the current miner remains output zero; malformed - metadata and invalid payouts fail closed. Restores the transparent 0.11.8 - development contribution, enabled by default at 5%, adjustable or optional, - and paid only as a disclosed coinbase output after any prior-winner jackpot. - Since 0.11.9 did not retain opt-outs, upgrades return to that 5% default. It - never withdraws wallet funds. The dashboard labels last-known fiat values, - excludes them from order pricing, shows rejected candidates, and replays full - retained history. Exact-config restart acknowledgement, live Stratum checks, - cached incremental scans and atomic locked state updates improve reliability - and performance. The 0.11.9 private local/global trade separation remains, - and existing wallets, blockchain, pool and trading data are retained. + Update-channel correctness release: the in-app updater now refreshes and + reads the authenticated 5tratumOS DEV catalogue explicitly instead of using + version fields selected through the system's default store channel. It + rejects non-DEV or malformed catalogue data, clearly reports installations + newer than the catalogue, and never offers a downgrade. The 0.11.10 jackpot, + reliability, last-known fiat labelling, private local/global trade separation + and transparent default-on 5% development contribution remain unchanged. + Existing wallets, blockchain, pool and trading data are retained. widgets: - id: sync type: text-with-progress diff --git a/willitmod-dev-5tratsmack/docker-compose.yml b/willitmod-dev-5tratsmack/docker-compose.yml index e0d1c5d..3725822 100644 --- a/willitmod-dev-5tratsmack/docker-compose.yml +++ b/willitmod-dev-5tratsmack/docker-compose.yml @@ -1,6 +1,6 @@ version: "3.7" -# Release source revision: a992f40e96d47348e6a0afa6bc6b70e5e67cbc18 +# Release source revision: bd3aa4dbb0e915c7593e461ebf09546654d49134 x-node-environment: &node-environment FIVETRAT_NETWORK: main @@ -197,7 +197,7 @@ services: start_period: 90s app: - image: ghcr.io/willitmod/5tratsmack-app:0.11.10-rc.a992f40e96d4@sha256:77873ff141b17e18dd42e6d5bbdbd5fcd3d1f07047b26772e91718b92f3d1a41 + image: ghcr.io/willitmod/5tratsmack-app:0.11.11-rc.bd3aa4dbb0e9@sha256:329b820a39beed7be4441d3c10ce694d7dedc579b62d494084bfcfe8c7755909 restart: unless-stopped depends_on: init_permissions: @@ -206,18 +206,18 @@ services: condition: service_started environment: APP_ID: 5tratsmack - APP_VERSION: 0.11.10 + APP_VERSION: 0.11.11 APP_CHANNEL: DEV - APP_RELEASE_PHASE: RC2 + APP_RELEASE_PHASE: RC1 APP_PLATFORM: 5TRATUMOS APP_SELF_RESTART_ENABLED: "0" FIVETRAT_UPDATER_ENABLED: "0" FIVETRAT_STORE_UPDATE_APP_ID: 5tratsmack FIVETRAT_STORE_UPDATE_CHANNEL: dev FIVETRAT_INSTALL_REVISION: dev-store - FIVETRAT_RELEASE_TAG: 0.11.10 - APP_IMAGE: ghcr.io/willitmod/5tratsmack-app:0.11.10-rc.a992f40e96d4@sha256:77873ff141b17e18dd42e6d5bbdbd5fcd3d1f07047b26772e91718b92f3d1a41 - APP_REVISION: a992f40e96d47348e6a0afa6bc6b70e5e67cbc18 + FIVETRAT_RELEASE_TAG: 0.11.11 + APP_IMAGE: ghcr.io/willitmod/5tratsmack-app:0.11.11-rc.bd3aa4dbb0e9@sha256:329b820a39beed7be4441d3c10ce694d7dedc579b62d494084bfcfe8c7755909 + APP_REVISION: bd3aa4dbb0e915c7593e461ebf09546654d49134 BCH2_NODE_IMAGE: ghcr.io/willitmod/5tratsmack-core:0.11.2@sha256:7bf02513144c7a157965fb8e9ad5865f5e84fa679afa7cb61fc0a8e140a40070 CKPOOL_IMAGE: ghcr.io/willitmod/5tratsmack-ckpool:0.11.3-rc.a992f40e96d4@sha256:95a1a5f343d579206a0f8bb3c961cafa7500b5d487211a0cfb7b989cf34b895e FIVETRAT_MUX_IDENTITY_URL: http://172.17.0.1:21222/api/integrations/workers diff --git a/willitmod-dev-5tratsmack/umbrel-app.yml b/willitmod-dev-5tratsmack/umbrel-app.yml index ad00431..a9daa39 100644 --- a/willitmod-dev-5tratsmack/umbrel-app.yml +++ b/willitmod-dev-5tratsmack/umbrel-app.yml @@ -2,7 +2,7 @@ manifestVersion: 1 id: willitmod-dev-5tratsmack category: altcoin name: 5tratSmack -version: "0.11.10" +version: "0.11.11" tagline: Home-miner 5TRAT node, wallet, solo pool and atomic trade lab description: >- Install and synchronize a complete 5TRAT node, create or restore an encrypted @@ -37,18 +37,14 @@ path: "" defaultUsername: "" defaultPassword: "" releaseNotes: >- - Jackpot and reliability update: Pink and Gold bonuses settle to the previous - block's payout script while the current miner remains output zero; malformed - metadata and invalid payouts fail closed. Restores the transparent 0.11.8 - development contribution, enabled by default at 5%, adjustable or optional, - and paid only as a disclosed coinbase output after any prior-winner jackpot. - Since 0.11.9 did not retain opt-outs, upgrades return to that 5% default. It - never withdraws wallet funds. The dashboard labels last-known fiat values, - excludes them from order pricing, shows rejected candidates, and replays full - retained history. Exact-config restart acknowledgement, live Stratum checks, - cached incremental scans and atomic locked state updates improve reliability - and performance. The 0.11.9 private local/global trade separation remains, - and existing wallets, blockchain, pool and trading data are retained. + Update-channel correctness release: the in-app updater now refreshes and + reads the authenticated 5tratumOS DEV catalogue explicitly instead of using + version fields selected through the system's default store channel. It + rejects non-DEV or malformed catalogue data, clearly reports installations + newer than the catalogue, and never offers a downgrade. The 0.11.10 jackpot, + reliability, last-known fiat labelling, private local/global trade separation + and transparent default-on 5% development contribution remain unchanged. + Existing wallets, blockchain, pool and trading data are retained. widgets: - id: sync type: text-with-progress