feat(installer): embed the branded DIG icon in the Windows binary - #69
Conversation
a34ba65 to
4ff91f1
Compare
Windows shows the lowest-ordinal icon resource as an executable's icon, so assets/dig.rc declares the canonical DIG mark as ordinal 1 and build.rs compiles it via embed-resource into the shipped binaries. The icon is vendored verbatim rather than shared through a package: it changes approximately never, so a vendored copy costs no release-first cascade. The trade is that drift becomes possible, so scripts/check-icon.sh pins its sha256 and CI fails loudly on any re-save. The existing asInvoker manifest is untouched and still reaches the unit-test harness: embed-resource links the icon with rustc-link-arg-bins only, so the os-error-740 elevation path is unaffected. Verified both RT_GROUP_ICON and RT_MANIFEST are present in the linked binary. Co-Authored-By: Claude <noreply@anthropic.com>
4ff91f1 to
5c00638
Compare
Correctness gate — PASSHead reviewed: The sha-gate non-vacuity answer (asked first, answered concretely)Non-vacuous. The comparison is
The warrant is NOT derived from the thing it guards, so it is not a tautology. Probed by mutation in a throwaway copy under
The literal also matches the blob actually committed on this head: One MUST-DO before merge — for the orchestrator, not the implementer (no code change possible)
So a future PR that swaps Elevation posture — verified, unchanged
The manifest-vs-icon collision is handled correctly: Test vacuityNo tests were added, so there is nothing vacuous to report — and there is genuine machine evidence in its place. Install-flow behaviourPackaging-only, as claimed. The diff is Readable-code barPasses. Intent-revealing names, guard-clause-only control flow, no nesting beyond one level, no dead code, and the comments are genuinely WHY rather than what — Log-and-move tickets (off-path hardening, NOT gating)
How this was verifiedRead every changed blob via Verdict: PASS — mergeable once |
DO NOT MERGE — gate round in progress. Kept as a draft until the gate verdicts return.
Closes DIG-Network/dig_ecosystem#2917 for the Windows leg of
dig-installer. This lane is thetemplate the four sibling repos copy.
What landed
assets/dig.ico2f0fb11a1254fc9275248dc340b7aa9c7236484a9531f8aaad2e4bcdf8900096, 50443 bytes.assets/dig.rc1 ICON— Windows renders the lowest-ordinal icon resource as the file's icon. Deliberately declares noRT_MANIFEST.build.rsembed_icon()alongside the existingembed_manifest().Cargo.tomlembed-resource = "3"as acfg(windows)build-dependency.scripts/check-icon.sh.github/workflows/ci.ymlicon asset (sha256 pin)job, runs on every PR.SPEC.mdsection 5.1Why vendored bytes plus a pin
Decided shape: no new repo, no new crate, no shared dependency, no release-first cascade. The asset
changes approximately never, so the cost of sharing it exceeds the cost of drift — provided drift is
made loud.
scripts/check-icon.shis what makes it loud, and it is proven falsifiable below.The manifest interaction — read this before copying into a sibling repo
The pre-existing
build.rsembeds anasInvokermanifest because Windows Installer Detectionauto-elevates binaries whose name contains "install"/"setup", and that auto-elevation makes even
cargo testfail to launch the test harness (ERROR_ELEVATION_REQUIRED, os error 740). Thatreasoning is load-bearing and is fully preserved.
Two facts a sibling lane needs:
.rc. It reaches the binary through the linker(
/MANIFEST:EMBED+/MANIFESTINPUT), and the icon reaches it through a linked.res. They aredifferent resource types and coexist — but declaring a manifest in both places is exactly the
combination where one silently displaces the other. Verified both are present in the linked
binary (evidence below).
embed_resource::compilelinks withcargo:rustc-link-arg-bins, notrustc-link-arg. Thatis the deliberate opposite of the manifest, which uses plain
rustc-link-argso it reaches theunit-test harness too. A test harness needs no icon, and leaving its link line untouched keeps
this change entirely off the os-error-740 path. A sibling repo that changes this to
compile_for_everythingis taking on risk it does not need.The result of
compileis checked with.manifest_required()rather than discarded: an environmentwithout a usable resource compiler would otherwise silently produce an unbranded binary, which is the
exact defect this PR exists to remove.
Blast radius checked
build.rsis the only existing symbol touched. It has no callers in the source graph — Cargo invokesit — so the blast radius is the linked artifacts of this crate: the
dig-installerbinary and theunit-test harness. Both were built and exercised (below).
assets/dig.rc,assets/dig.ico,scripts/check-icon.shand the CI job are new files with no dependents. No library code, no publicAPI, and no runtime behaviour changed. Independently confirmed by inspecting the linked PE's resource
directory, which is a stronger check than the call graph for a link-time change.
gitnexus was not used: this repo's worktree has no index, and the change is a build-script edit whose
true dependents are link-time artifacts that a call-graph index does not model. Blast radius was
established by reading
build.rsin full plus PE resource enumeration on the built binary.How verified
1. The drift gate is falsifiable (proven, not asserted).
The vendored file's sha was verified against the canonical source immediately after copying, before
any other step.
2. Both resources are in the linked binary. Enumerated via
EnumResourceNamesontarget/debug/dig-installer.exe:The manifest body was also confirmed present by byte-scanning the image for
asInvokerandrequestedExecutionLevel.3. The binary still runs.
dig-installer.exe --versionreturneddig-installer 0.43.0(pre-bump build).
4.
cargo teststill launches — the os-error-740 regression check.cargo test --locked:851 passed, 1 failed. The single failure is
secure::tests::the_defect_reproduces_on_a_real_directory_and_the_repair_clears_it(
Os { code: 5, PermissionDenied }, an ACL fixture needing elevation). Confirmed pre-existing: itfails identically on a clean
origin/mainworktree with none of these changes. Crucially, the harnesslaunched — an elevation regression would have failed to start at all, with zero tests reported.
5. The icon is visible on the shipped binary. Real Explorer windows over the built exe, captured
at two view modes; the DIG mark renders in both, and the D's counter stays open at the small size.
C:\tmp\icon-evidence\explorer-extra-large-icons.pngC:\tmp\icon-evidence\explorer-details-view.pngC:\tmp\icon-evidence\shell-extract-*.pngThese are real screen captures of Explorer, not renders of the source
.ico. They are not committedto the repo (large binaries in a source tree); paths are on the build host.
6.
cargo fmt --checkclean,cargo clippy --all-targets --locked -D warningsclean.Scope — Windows only, explicitly
This PR embeds a Windows resource and nothing else. Deferred to separate tickets and not
implied as done: macOS
.icns(bundle-only), Linux.desktop+ hicolor PNGs (packaging), and theicons carried by the generated
.msi/.pkg/.debpackages through their own packaging toolchains.Version
0.43.0to0.44.0(minor). New user-visible capability — the shipped binary is now branded —with no API, wire-format or behavioural break. Note the ticket brief said this repo was at 0.40.1;
mainis actually at 0.43.0, so the bump is from the real tip.Findings raised, not fixed here
build.rsgates on#[cfg(windows)], which is the host the build script runs on, not thebuild target. The
cfg(windows)build-dependency resolves the same way, so the new code isinternally consistent with the existing manifest logic and this PR does not change the distinction's
effect. But it means a cross-compile to Windows from a Linux host would embed neither the
manifest nor the icon, silently. Left alone deliberately rather than fixed as a drive-by; worth its
own ticket, and worth flagging to the sibling repos since some of them may cross-compile their
Windows artifacts.
Conflict note
PR #68 (
loop/2784-macos-e2e-tls) is open on this repo and will conflict on theCargo.tomlversionline. Whichever merges second rebases. No other file overlaps.