Skip to content

Commit 9ea0942

Browse files
ImPanickclaude
authored andcommitted
docs(dist): lock in operator-execution guarantees (acquire/verify/footprint)
Makes the user-facing intent binding and verifiable so operator execution matches documented intent. Acquisition — two paths, same IUUT.exe (master doc §6.4, docs/INSTALL.md): - Path A: download the pre-built IUUT.exe + SHA256SUMS.txt from Releases, verify hash + Sigstore build-provenance attestation, double-click. - Path B: build from source via the §6.3 publish command. Integrity — "verified signed hashes" with zero certificate cost: - release.yml (new) on a vX.Y.Z tag: builds the self-contained single-file IUUT.exe + IUUT-portable.zip, emits SHA256SUMS.txt, and attests build provenance via actions/attest-build-provenance (Sigstore). Users verify with Get-FileHash + `gh attestation verify`. - Authenticode signing documented as a future upgrade (needs a cert). No-install / fire-and-forget / minimal footprint: - NG8: no installer, no admin/UAC, no registry, no Program Files, no Start-Menu entries, no machine-wide changes. - One state folder: %AppData%\IUUT\ (cache, DPAPI-encrypted key, logs), OR portable mode via an `IUUT.portable` marker -> .\IUUT-Data\ (nothing in AppData). Native single-file extraction pinned inside that folder. - Clean removal = delete the exe + the one folder. Save backups live inside the game's PlayerData folder by design (CONSTITUTION III), not scattered. Auto-link save dir + manual fallback made explicit in §7.1. Also: - Fixed the §7.5.1 cache-path inconsistency (%AppData%\IUUT\, was %AppData%\IcarusUltimateUtilityTool\). - IUUT.App.csproj: EnableCompressionInSingleFile in Release; footprint note. - publish-release.ps1 contract aligned (local dry-run; CI is canonical/attested). - README "Get IUUT" + doc index; DEVELOPMENT build-your-own-exe; CICD release-integrity model + runbook; MANUAL_CHECKLIST §11 (integrity) + §12 (footprint/portable); CHANGELOG. - Master doc bumped to 1.3.0 (§24). Verified: dotnet build 0/0, format clean, governance-lint clean (99 files). Agent: claude-code/2.1.149 Consulted: AGENTS.md, .agent/CONSTITUTION.md#III,#V,#VII, .agent/SECURITY_PROTOCOL.md#5, .agent/HANDOFF_PROTOCOL.md#9, docs/IUUT-PROJECT-DOCUMENTATION.md#3.3,#6.1,#6.3,#6.4,#7.1,#7.5.1,#19,#24 Co-Authored-By: Claude <noreply@anthropic.com>
1 parent e16e06b commit 9ea0942

10 files changed

Lines changed: 487 additions & 33 deletions

File tree

.github/workflows/release.yml

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
name: Release
2+
3+
# Produces the signed, verifiable IUUT.exe release.
4+
# Triggered when a human pushes a SemVer tag (vX.Y.Z). Agents propose release
5+
# readiness; humans tag (.agent/HANDOFF_PROTOCOL.md §9).
6+
#
7+
# Output (attached to the GitHub Release):
8+
# - IUUT.exe self-contained single-file, win-x64
9+
# - IUUT-portable.zip the same exe + IUUT.portable marker + README
10+
# - SHA256SUMS.txt SHA-256 of both artifacts
11+
# - a Sigstore build-provenance attestation (verifiable with `gh attestation verify`)
12+
#
13+
# Authority: docs/IUUT-PROJECT-DOCUMENTATION.md §6.4, §19; docs/CICD.md §5.
14+
15+
on:
16+
push:
17+
tags:
18+
- "v[0-9]+.[0-9]+.[0-9]+"
19+
- "v[0-9]+.[0-9]+.[0-9]+-*" # pre-release tags (e.g. v0.1.0-rc1)
20+
21+
permissions:
22+
contents: write # create the GitHub Release + upload assets
23+
id-token: write # required for Sigstore attestation
24+
attestations: write # required for actions/attest-build-provenance
25+
26+
env:
27+
DOTNET_CLI_TELEMETRY_OPTOUT: "1"
28+
DOTNET_NOLOGO: "1"
29+
30+
jobs:
31+
release:
32+
name: Build, attest, publish
33+
runs-on: windows-latest
34+
35+
steps:
36+
- name: Checkout
37+
uses: actions/checkout@v4
38+
39+
- name: Set up .NET 8 SDK
40+
uses: actions/setup-dotnet@v4
41+
with:
42+
dotnet-version: "8.0.x"
43+
44+
- name: Restore + test (gate the release on green)
45+
run: |
46+
dotnet restore IcarusUltimateUtilityTool.sln
47+
dotnet test IcarusUltimateUtilityTool.sln -c Release --logger "console;verbosity=minimal"
48+
49+
- name: Publish self-contained single-file IUUT.exe
50+
run: >
51+
dotnet publish src/IUUT.App/IUUT.App.csproj
52+
-c Release -r win-x64
53+
--self-contained true
54+
-p:PublishSingleFile=true
55+
-p:IncludeNativeLibrariesForSelfExtract=true
56+
-p:EnableCompressionInSingleFile=true
57+
-o publish
58+
59+
- name: Stage release artifacts
60+
shell: pwsh
61+
run: |
62+
New-Item -ItemType Directory -Force -Path dist | Out-Null
63+
Copy-Item publish/IUUT.exe dist/IUUT.exe
64+
65+
# Portable bundle: exe + portable marker + a short README
66+
New-Item -ItemType Directory -Force -Path portable | Out-Null
67+
Copy-Item publish/IUUT.exe portable/IUUT.exe
68+
New-Item -ItemType File -Force -Path portable/IUUT.portable | Out-Null
69+
@"
70+
IUUT portable mode.
71+
The presence of the 'IUUT.portable' file next to IUUT.exe makes IUUT keep
72+
all of its state in a 'IUUT-Data' folder beside the exe instead of in
73+
%AppData%\IUUT. See docs/INSTALL.md section 6.
74+
"@ | Set-Content -Path portable/README.txt -Encoding utf8
75+
Compress-Archive -Path portable/* -DestinationPath dist/IUUT-portable.zip -Force
76+
77+
- name: Generate SHA256SUMS.txt
78+
shell: pwsh
79+
run: |
80+
Push-Location dist
81+
Get-ChildItem -File -Exclude SHA256SUMS.txt | ForEach-Object {
82+
$h = (Get-FileHash $_.Name -Algorithm SHA256).Hash.ToLower()
83+
"$h $($_.Name)"
84+
} | Set-Content -Path SHA256SUMS.txt -Encoding ascii
85+
Get-Content SHA256SUMS.txt
86+
Pop-Location
87+
88+
- name: Attest build provenance
89+
uses: actions/attest-build-provenance@v1
90+
with:
91+
subject-path: |
92+
dist/IUUT.exe
93+
dist/IUUT-portable.zip
94+
95+
- name: Create GitHub Release
96+
uses: softprops/action-gh-release@v2
97+
with:
98+
files: |
99+
dist/IUUT.exe
100+
dist/IUUT-portable.zip
101+
dist/SHA256SUMS.txt
102+
generate_release_notes: true
103+
fail_on_unmatched_files: true

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ in `docs/GOVERNANCE_CHANGELOG.md`.
2727
- **DevOps groundwork:** `docs/DEVELOPMENT.md` and `docs/CICD.md` runbooks, Build & Test
2828
CI workflow, Dependabot config, `CONTRIBUTING.md`, `SECURITY.md`, this changelog,
2929
`CODEOWNERS`, and issue templates.
30+
- **Operator-execution guarantees:** `docs/INSTALL.md` operator guide; `release.yml`
31+
(single-file `IUUT.exe` + portable zip + `SHA256SUMS.txt` + Sigstore build-provenance
32+
attestation on a `vX.Y.Z` tag); master doc §6.4 (two acquisition paths, no-installer /
33+
no-admin / no-registry footprint, `%AppData%\IUUT\` default + `IUUT.portable` opt-in,
34+
clean removal) and §19 release pipeline + user verification.
35+
36+
### Fixed
37+
38+
- Steam name-cache path inconsistency in master doc §7.5.1 (now `%AppData%\IUUT\`).
3039

3140
### Notes
3241

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,22 @@ Two equally-valid jobs, from one Windows desktop app:
2121

2222
Three home-screen workflows: **Broken Save Recovery**, **Lazy Max**, and **Custom**.
2323

24+
## Get IUUT
25+
26+
Two ways to get the **same** single-file `IUUT.exe` — full guide in
27+
**[docs/INSTALL.md](docs/INSTALL.md)**:
28+
29+
- **Download (recommended):** grab `IUUT.exe` + `SHA256SUMS.txt` from
30+
[Releases](https://github.com/ImPanick/IUUT/releases), verify the hash and the
31+
build-provenance attestation (`gh attestation verify`), then double-click.
32+
- **Build it yourself:** clone and run the `dotnet publish` command in
33+
[docs/INSTALL.md §3](docs/INSTALL.md).
34+
35+
**No install, no admin, no registry.** IUUT is one `.exe`; its only footprint is a
36+
single `%AppData%\IUUT\` folder (or a portable `IUUT-Data\` beside the exe). Removal =
37+
delete the exe + that folder. The save folder auto-links on launch; if it can't be
38+
found you point IUUT at it once.
39+
2440
## Quick facts
2541

2642
| | |
@@ -95,6 +111,7 @@ pipeline and **[SECURITY.md](SECURITY.md)** for the disclosure policy.
95111
| --- | --- |
96112
| [docs/IUUT-PROJECT-DOCUMENTATION.md](docs/IUUT-PROJECT-DOCUMENTATION.md) | Master spec — vision, scope, save model, architecture, features, roadmap |
97113
| [Icarus-Analysis.md](Icarus-Analysis.md) | Save-format field guide (empirically verified) |
114+
| [docs/INSTALL.md](docs/INSTALL.md) | **Operator guide** — get, verify, run, footprint, portable, removal |
98115
| [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) | Local developer runbook |
99116
| [docs/CICD.md](docs/CICD.md) | CI/CD, branch protection, versioning, releases |
100117
| [AGENTS.md](AGENTS.md) + [.agent/](.agent/) | Multi-agent governance contract |

docs/CICD.md

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ Two GitHub Actions workflows gate every PR into `main`:
1919
| --- | --- | --- | --- |
2020
| **Governance Check** | `.github/workflows/governance-check.yml` | PR open/sync/edit | Validates PR-body contract sections, commit trailers, and runs `governance-lint.ps1` (PII + style). |
2121
| **Build & Test** | `.github/workflows/build.yml` | PR + push to main | Restore → build (warnings-as-errors) → test → `dotnet format --verify-no-changes`. |
22+
| **Release** | `.github/workflows/release.yml` | push of a `vX.Y.Z` tag | Build single-file `IUUT.exe` + portable zip → `SHA256SUMS.txt` → Sigstore build-provenance attestation → GitHub Release. |
2223

23-
Both must be green to merge. Neither builds artifacts — release packaging is a
24-
separate, human-triggered process (§5).
24+
The first two gate every merge. Release runs only on a tag and produces the verifiable
25+
artifacts (§5).
2526

2627
```
2728
┌──────────────┐ PR ┌─────────────────────┐
@@ -127,20 +128,33 @@ Milestones map to master doc §16: `0.1` MVP (Lazy Max + backup + Main-Menu veri
127128

128129
### Release runbook
129130

130-
1. Confirm `main` is green (both workflows).
131+
1. Confirm `main` is green (Governance Check + Build & Test).
131132
2. Open a `release-readiness` issue; an agent may assemble the checklist, a human signs off.
132-
3. Run the relevant items in `tests/MANUAL_CHECKLIST.md` (UI + game-load acceptance).
133-
4. Tag: `git tag vX.Y.Z && git push origin vX.Y.Z` (human only).
134-
5. `pwsh -File scripts/publish-release.ps1` produces the self-contained single-file
135-
`IUUT.exe` (~15–25 MB) plus a portable zip. *(Script is a stub until first code release.)*
136-
6. Create the GitHub Release; attach `IUUT.exe` + portable zip; paste the generated
137-
release notes (commit log since the previous tag, grouped by `<type>`).
133+
3. Run the relevant items in `tests/MANUAL_CHECKLIST.md` (UI + game-load + integrity/footprint).
134+
4. *(Optional)* Local dry-run: `pwsh -File scripts/publish-release.ps1` to inspect the
135+
artifacts + checksums before tagging. *(Stub until first code release.)*
136+
5. **Tag (human only):** `git tag vX.Y.Z && git push origin vX.Y.Z`.
137+
6. **`release.yml` runs automatically** and produces, on the GitHub Release:
138+
`IUUT.exe`, `IUUT-portable.zip`, `SHA256SUMS.txt`, generated release notes, and a
139+
Sigstore build-provenance attestation.
138140
7. Update `CHANGELOG.md` (move `Unreleased` items under the new version heading).
139141

140-
### Code signing (future)
142+
The artifacts are **verifiable by anyone** (no certificate needed): a checksum match
143+
plus `gh attestation verify IUUT.exe --repo ImPanick/IUUT` proves the binary is exactly
144+
what public CI built from the tagged commit. See master doc §19.2 and `docs/INSTALL.md` §4.
141145

142-
Optional, reduces SmartScreen friction (master doc §19). When a cert is available,
143-
`publish-release.ps1` signs `IUUT.exe`. Not required for early releases.
146+
### Integrity model — "verified signed hashes"
147+
148+
| Layer | Mechanism | Cost | Status |
149+
| --- | --- | --- | --- |
150+
| **Tamper detection** | `SHA256SUMS.txt` per release | free | active in `release.yml` |
151+
| **Provenance** | Sigstore attestation via `actions/attest-build-provenance` | free | active in `release.yml` |
152+
| **Reproducibility** | Acquisition Path B — build from source (master doc §6.4) | free | active |
153+
| **Publisher identity** | Authenticode code-signing of `IUUT.exe` | needs a code-signing cert | **future upgrade** |
154+
155+
The first three ship now and fully satisfy "verified signed hashes from the repo."
156+
Authenticode (which removes most SmartScreen prompts) is added when a certificate is
157+
obtained — a `chore(ci)` change to `release.yml` plus a CI signing secret.
144158

145159
---
146160

docs/DEVELOPMENT.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,33 @@ when CI runs the equivalent trailer check. Don't skip it.
7373
| Test (filter) | `dotnet test --filter "FullyQualifiedName~ProfileParser"` |
7474
| Run the WPF app | `dotnet run --project src/IUUT.App` |
7575
| Run the CLI | `dotnet run --project src/IUUT.Cli -- check` |
76+
| Build your own release `IUUT.exe` | see below |
7677
| Format (apply) | `dotnet format IcarusUltimateUtilityTool.sln` |
7778
| Format (verify, CI-style) | `dotnet format IcarusUltimateUtilityTool.sln --verify-no-changes` |
7879
| Governance lint | `pwsh -File scripts/governance-lint.ps1 -StagedOnly` |
7980

8081
The four gates CI enforces (mirror them locally before pushing): **build with no
8182
warnings**, **tests pass**, **format verifies clean**, **governance lint clean**.
8283

84+
### Build your own self-contained `IUUT.exe`
85+
86+
This is acquisition **Path B** for end users (master doc §6.4) and how you produce a
87+
local release artifact:
88+
89+
```powershell
90+
dotnet publish src/IUUT.App/IUUT.App.csproj `
91+
-c Release -r win-x64 `
92+
--self-contained true `
93+
-p:PublishSingleFile=true `
94+
-p:IncludeNativeLibrariesForSelfExtract=true
95+
```
96+
97+
Output: `src/IUUT.App/bin/Release/net8.0-windows/win-x64/publish/IUUT.exe` — a single
98+
~15–25 MB file with the .NET 8 runtime bundled; no install needed to run it. The
99+
canonical, attested release is built by `.github/workflows/release.yml` on a `vX.Y.Z`
100+
tag; `scripts/publish-release.ps1` is the local dry-run. See `docs/CICD.md` §5 and
101+
`docs/INSTALL.md`.
102+
83103
---
84104

85105
## 4. Project map

docs/INSTALL.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# Get & Run IUUT — Operator Guide
2+
3+
How to obtain, verify, and run **Icarus Ultimate Utility Tool (IUUT)**. No
4+
programming required for the download path.
5+
6+
> **The promise:** IUUT is a single `.exe`. You don't install anything, it doesn't
7+
> need administrator rights, it makes no system-wide changes, and removing it is
8+
> deleting one file and one folder. See the [footprint](#5-what-iuut-leaves-on-your-pc)
9+
> section for the exact list of what it touches.
10+
11+
---
12+
13+
## 1. Pick how you get it
14+
15+
| You want… | Use |
16+
| --- | --- |
17+
| The easy way — just download and run | **Path A: pre-built download** (§2) |
18+
| To compile it yourself and trust nothing but your own build | **Path B: build from source** (§3) |
19+
20+
Both give you the **identical** self-contained `IUUT.exe`.
21+
22+
---
23+
24+
## 2. Path A — download the pre-built `IUUT.exe` (recommended)
25+
26+
1. Go to the repository's **Releases** page:
27+
<https://github.com/ImPanick/IUUT/releases>
28+
2. From the latest release, download:
29+
- **`IUUT.exe`** (or **`IUUT-portable.zip`** if you want portable mode — see §6), and
30+
- **`SHA256SUMS.txt`**
31+
3. **Verify it** (strongly recommended — see §4). It takes ten seconds.
32+
4. **Double-click `IUUT.exe`.** That's it. No setup, no install, no admin prompt.
33+
34+
> Windows SmartScreen may show "Windows protected your PC" the first time, because
35+
> IUUT is not yet Authenticode-signed (a paid certificate is a future upgrade). Click
36+
> **More info → Run anyway**. Verifying the file first (§4) is exactly how you confirm
37+
> it's safe despite that warning.
38+
39+
---
40+
41+
## 3. Path B — build your own `IUUT.exe` from source
42+
43+
Requires the **.NET 8 SDK** (or newer — see `docs/DEVELOPMENT.md` §1). Then:
44+
45+
```powershell
46+
git clone https://github.com/ImPanick/IUUT.git
47+
cd IUUT
48+
49+
dotnet publish src/IUUT.App/IUUT.App.csproj `
50+
-c Release -r win-x64 `
51+
--self-contained true `
52+
-p:PublishSingleFile=true `
53+
-p:IncludeNativeLibrariesForSelfExtract=true
54+
```
55+
56+
Your `IUUT.exe` is written to
57+
`src/IUUT.App/bin/Release/net8.0-windows/win-x64/publish/IUUT.exe`.
58+
Copy it anywhere and double-click. This is a binary **you** produced from source —
59+
no need to trust our release at all.
60+
61+
---
62+
63+
## 4. Verify the download ("verified signed hashes")
64+
65+
Two independent checks. Do at least the first.
66+
67+
### 4a. Checksum (no tools needed beyond PowerShell)
68+
69+
```powershell
70+
(Get-FileHash .\IUUT.exe -Algorithm SHA256).Hash
71+
```
72+
73+
Compare the printed hash against the `IUUT.exe` line in `SHA256SUMS.txt`. They must
74+
match exactly (case-insensitive). A mismatch means the file is corrupted or tampered —
75+
do not run it.
76+
77+
### 4b. Build provenance (recommended; needs the free GitHub CLI)
78+
79+
```powershell
80+
gh attestation verify .\IUUT.exe --repo ImPanick/IUUT
81+
```
82+
83+
This cryptographically proves the `.exe` was built by IUUT's public CI from a specific
84+
tagged commit (Sigstore attestation) — not swapped out by someone else. A green result
85+
is the strongest assurance short of building it yourself.
86+
87+
---
88+
89+
## 5. What IUUT leaves on your PC
90+
91+
IUUT is deliberately tidy. The complete footprint:
92+
93+
| Item | Where | What it is |
94+
| --- | --- | --- |
95+
| The program | wherever you put `IUUT.exe` | The single executable. |
96+
| App state | `%AppData%\IUUT\` | Steam-name cache, your (encrypted) Steam Web API key if you set one, logs, and settings. The **only** folder IUUT creates. |
97+
| Save backups | inside your `…\Icarus\Saved\PlayerData\<SteamID>\` | Timestamped `.iuut-backup-…` copies made **before** every edit, next to the files they protect. Part of your save folder, not scattered. |
98+
99+
IUUT does **not**: run an installer, require admin, write to the Windows registry,
100+
install into Program Files, create Start-Menu entries or shortcuts, run a background
101+
service, auto-start with Windows, or phone home.
102+
103+
---
104+
105+
## 6. Portable mode (true fire-and-forget)
106+
107+
Want **nothing** in `%AppData%`? Run portable:
108+
109+
- Use the `IUUT-portable.zip` release (it includes the marker), **or**
110+
- Create an empty file named **`IUUT.portable`** next to `IUUT.exe`.
111+
112+
In portable mode, all app state goes in a **`IUUT-Data\`** folder beside the `.exe`.
113+
Put the exe + that folder on a USB stick and it travels with you, leaving the host PC
114+
completely untouched.
115+
116+
---
117+
118+
## 7. First run
119+
120+
1. **Read & accept the one-time disclaimer** (IUUT is unofficial; back up your saves;
121+
you're responsible for your edits).
122+
2. **Save folder auto-links.** IUUT looks for `%LOCALAPPDATA%\Icarus\Saved\`
123+
automatically. If found, you go straight to the profile picker.
124+
3. **If it can't find your saves** (game installed somewhere unusual), IUUT asks you to
125+
**Browse…** to your `Saved\` (or `PlayerData\`) folder once. It remembers your choice.
126+
4. **Pick your profile** by Steam display name and start with **Broken Save Recovery**,
127+
**Lazy Max**, or **Custom**.
128+
129+
---
130+
131+
## 8. Remove IUUT completely
132+
133+
There's nothing to uninstall:
134+
135+
1. Delete `IUUT.exe`.
136+
2. Delete `%AppData%\IUUT\` (or, in portable mode, the `IUUT-Data\` folder next to the exe).
137+
138+
Your Icarus saves and their backups are left untouched. (If you also want to discard
139+
the backups IUUT made, delete the `*.iuut-backup-*` files in your `PlayerData\<SteamID>\`
140+
folder — but you may want to keep them.)
141+
142+
---
143+
144+
## 9. Safety reminders
145+
146+
- **Back up your save folder** before big edits (IUUT also auto-backs-up each file).
147+
- **Close Icarus, or stay on the Main Menu**, while editing (see the in-app banner).
148+
- If you use **Steam Cloud**, verify sync direction after editing so an older cloud
149+
copy doesn't overwrite your edits.
150+
151+
---
152+
153+
*Operator runbook. The binding guarantees behind it live in
154+
`docs/IUUT-PROJECT-DOCUMENTATION.md` §6.4 and §19. Maintained per
155+
`.agent/AMENDMENT_PROCESS.md` §4. Last updated: 2026-05-25.*

0 commit comments

Comments
 (0)