diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3a14e129..221b651e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -158,3 +158,18 @@ jobs: cat coverage-summary.txt 2>/dev/null || echo 'no coverage output' echo '```' } >> "$GITHUB_STEP_SUMMARY" + + # The vendored branded icon is byte-pinned; see scripts/check-icon.sh for why + # drift is made loud rather than impossible. Cheap and dependency-free, so it + # runs as its own job and reports independently of the compile gates. + icon: + name: icon asset (sha256 pin) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + # Invoked through `bash` rather than relying on the file mode: a checkout + # that loses the executable bit would otherwise fail this gate for a + # reason that has nothing to do with the icon. + - run: bash scripts/check-icon.sh diff --git a/Cargo.lock b/Cargo.lock index 0a7478c6..20cd91cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -139,7 +139,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -150,7 +150,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1948,7 +1948,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -3072,6 +3072,7 @@ dependencies = [ "digstore-core 0.29.0", "digstore-crypto", "digstore-stage", + "embed-resource", "futures-util", "getrandom 0.2.17", "hex", @@ -3398,6 +3399,7 @@ dependencies = [ "dig-options 0.5.0", "digstore-chain", "digstore-core 0.29.0", + "embed-resource", "futures-core", "getrandom 0.2.17", "hex", @@ -3752,7 +3754,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3838,6 +3840,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "embed-resource" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbfdaacccebec3b28e4866b8973543c7647797db5ada1bdab552e48fe665fbbd" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml 1.1.5+spec-1.1.0", + "vswhom", + "winreg", +] + [[package]] name = "embedded-io" version = "0.4.0" @@ -3900,7 +3916,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -4536,7 +4552,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.5", "system-configuration", "tokio", "tower-service", @@ -4787,7 +4803,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -5169,7 +5185,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -5780,7 +5796,7 @@ dependencies = [ "quinn-udp", "rustc-hash 2.1.3", "rustls", - "socket2 0.5.10", + "socket2 0.6.5", "thiserror 2.0.20", "tokio", "tracing", @@ -5818,9 +5834,9 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2 0.6.5", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -6570,7 +6586,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -7020,7 +7036,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -7282,7 +7298,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix 1.1.4", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -7545,6 +7561,21 @@ dependencies = [ "winnow 0.7.15", ] +[[package]] +name = "toml" +version = "1.1.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12c0ba9680044b4ce98d391a62094047eada0d64860b80166c39f4a6b5640785" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.4", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -7959,6 +7990,26 @@ version = "0.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "walkdir" version = "2.5.0" @@ -8416,7 +8467,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -8815,6 +8866,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +dependencies = [ + "cfg-if 1.0.4", + "windows-sys 0.59.0", +] + [[package]] name = "wit-bindgen" version = "0.57.1" diff --git a/assets/dig.ico b/assets/dig.ico new file mode 100644 index 00000000..e10b838a Binary files /dev/null and b/assets/dig.ico differ diff --git a/assets/dig.rc b/assets/dig.rc new file mode 100644 index 00000000..d4e97fd2 --- /dev/null +++ b/assets/dig.rc @@ -0,0 +1,18 @@ +// Windows resource script for dig-node. +// +// Windows shows the LOWEST-ORDINAL icon resource as an executable's icon in +// Explorer, the taskbar and the Alt-Tab switcher, so the branded DIG mark must +// be ordinal 1 and must stay the only ICON statement in this file. +// +// `dig.ico` is the canonical, byte-pinned DIG icon (10 frames: 16/20/24/32/40/ +// 48/64/96/128/256, with hardened alpha at <=32 so the D's counter does not +// bleed shut at taskbar size). It is vendored verbatim and gated on its sha256 +// by `scripts/check-icon.sh` — never re-save or "optimize" it, as any rewrite +// changes the hash and breaks the gate in this repo and in every sibling repo +// that vendors the same bytes. +// +// Deliberately NOT declared here: an RT_MANIFEST resource. Declaring a +// manifest in both the .rc and the linker's /MANIFEST:EMBED lets one silently +// displace the other (CVT1100/LNK1123 if both name RT_MANIFEST). + +1 ICON "dig.ico" diff --git a/crates/dig-node-service/Cargo.toml b/crates/dig-node-service/Cargo.toml index 3666c163..399ba83a 100644 --- a/crates/dig-node-service/Cargo.toml +++ b/crates/dig-node-service/Cargo.toml @@ -393,3 +393,9 @@ async-trait = "0.1" # into a mock `dig.getContent` window, so the node's RPC tier verifies-then-fails-closed and records # the failed entry. `base64` matches dig-node-core's version. base64 = "0.22" + +# Compiles the branded DIG icon (`../../assets/dig.rc`) into a Windows resource that +# `build.rs` links into `dig-node`/`dign` (dig_ecosystem#2917). Not a `dig-*`/`chia-*` +# crate, so no cross-repo version lockstep applies here. +[target.'cfg(windows)'.build-dependencies] +embed-resource = "3" diff --git a/crates/dig-node-service/build.rs b/crates/dig-node-service/build.rs index 6b15f9c3..6c930da5 100644 --- a/crates/dig-node-service/build.rs +++ b/crates/dig-node-service/build.rs @@ -6,6 +6,10 @@ //! is emitted as a compile-time env var (`DIG_NODE_GIT_SHA`). When the build //! happens outside a git checkout (e.g. a packaged source tarball), the SHA is //! recorded as `"unknown"` rather than failing the build. +//! +//! On Windows this also embeds the branded DIG application icon +//! (`../../assets/dig.rc`, dig_ecosystem#2917) into the `dig-node` and `dign` +//! binaries only -- see `embed_icon` below for why `fake_beacon_cli` is excluded. use std::process::Command; @@ -15,6 +19,34 @@ fn main() { // Rerun if the checked-out commit moves, so the embedded SHA stays accurate. println!("cargo:rerun-if-changed=.git/HEAD"); println!("cargo:rerun-if-changed=.git/refs"); + + #[cfg(windows)] + embed_icon(); +} + +/// Compile the branded DIG icon into `dig-node` and `dign` only. +/// +/// `embed_resource::compile` (unscoped) emits `cargo:rustc-link-arg-bins`, which +/// reaches EVERY bin this crate produces -- including `fake_beacon_cli`, a test +/// fixture that stands in for the real (separate-repo) `dig-updater` beacon CLI +/// and must never carry the DIG brand. `compile_for` scopes the link line to the +/// two shipped binary names instead, so `fake_beacon_cli` stays icon-less. +/// +/// `.manifest_required()`/`.expect(..)` is deliberate: an environment that cannot +/// compile a resource must fail the build loudly rather than silently ship an +/// unbranded `dig-node`/`dign`. +#[cfg(windows)] +fn embed_icon() { + embed_resource::compile_for( + "../../assets/dig.rc", + &["dig-node", "dign"], + embed_resource::NONE, + ) + .manifest_required() + .expect("failed to compile assets/dig.rc — no usable Windows resource compiler?"); + + println!("cargo:rerun-if-changed=../../assets/dig.rc"); + println!("cargo:rerun-if-changed=../../assets/dig.ico"); } /// The short git SHA of HEAD, or `None` outside a git checkout / without git. diff --git a/crates/dig-wallet/Cargo.toml b/crates/dig-wallet/Cargo.toml index 922debf4..a791b4ca 100644 --- a/crates/dig-wallet/Cargo.toml +++ b/crates/dig-wallet/Cargo.toml @@ -13,6 +13,12 @@ path = "src/lib.rs" name = "dig-wallet" path = "src/main.rs" +# Compiles the branded DIG icon (`../../assets/dig.rc`) into a Windows resource that +# `build.rs` links into the `dig-wallet` binary (dig_ecosystem#2917). Not a `dig-*`/ +# `chia-*` crate, so no cross-repo version lockstep applies here. +[target.'cfg(windows)'.build-dependencies] +embed-resource = "3" + [dependencies] # Store-format libs from the digstore repo (git deps, pinned to the same rev as the # node — bump together). digstore-chain: BIP-39 seed + HD wallet scan + DIG-CAT + diff --git a/crates/dig-wallet/build.rs b/crates/dig-wallet/build.rs new file mode 100644 index 00000000..d26e88d6 --- /dev/null +++ b/crates/dig-wallet/build.rs @@ -0,0 +1,28 @@ +//! Build script: on Windows, embed the branded DIG application icon +//! (`../../assets/dig.rc`, dig_ecosystem#2917) into the `dig-wallet` binary. +//! +//! This crate has a single bin (`dig-wallet`), so the unscoped +//! `embed_resource::compile` -- which links to every bin the crate produces -- +//! is safe to use here (contrast `dig-node-service`, which must exclude its +//! `fake_beacon_cli` test fixture and therefore uses `compile_for` instead). +//! +//! `.manifest_required()`/`.expect(..)` is deliberate: an environment that +//! cannot compile a resource must fail the build loudly rather than silently +//! ship an unbranded binary. +//! +//! No-op on non-Windows. + +fn main() { + #[cfg(windows)] + embed_icon(); +} + +#[cfg(windows)] +fn embed_icon() { + embed_resource::compile("../../assets/dig.rc", embed_resource::NONE) + .manifest_required() + .expect("failed to compile assets/dig.rc — no usable Windows resource compiler?"); + + println!("cargo:rerun-if-changed=../../assets/dig.rc"); + println!("cargo:rerun-if-changed=../../assets/dig.ico"); +} diff --git a/scripts/check-icon.sh b/scripts/check-icon.sh new file mode 100644 index 00000000..ae096647 --- /dev/null +++ b/scripts/check-icon.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Assert the vendored DIG application icon is the canonical, byte-identical one. +# +# `assets/dig.ico` is deliberately vendored rather than pulled from a shared +# package: it changes approximately never, and a vendored copy costs no +# release-first cascade. The trade is that drift becomes possible, so this +# check makes drift LOUD — any re-save, re-export or "optimization" changes the +# hash and fails the build here instead of shipping a subtly different mark. +# +# The same literal is pinned in every DIG repo that vendors these bytes, so a +# mismatch means either this repo drifted or the icon was regenerated and every +# sibling repo must be updated in the same unit of work. +# +# Run from the repo root: scripts/check-icon.sh +set -euo pipefail + +readonly ICON="assets/dig.ico" +readonly EXPECTED_SHA256="2f0fb11a1254fc9275248dc340b7aa9c7236484a9531f8aaad2e4bcdf8900096" + +if [[ ! -f "$ICON" ]]; then + echo "FAIL: $ICON is missing." >&2 + exit 1 +fi + +actual="$(sha256sum "$ICON" | cut -d' ' -f1)" + +if [[ "$actual" != "$EXPECTED_SHA256" ]]; then + echo "FAIL: $ICON has drifted from the canonical DIG icon." >&2 + echo " expected sha256: $EXPECTED_SHA256" >&2 + echo " actual sha256: $actual" >&2 + echo "Restore the canonical bytes; do not re-save or re-export the icon." >&2 + exit 1 +fi + +echo "OK: $ICON matches the canonical DIG icon ($EXPECTED_SHA256)."