Repository navigation
fix(env): secrets at rest: ignored staging, tightened modes, expiring mux payloads, doctor secrets hygiene (HACK-2165) - #764
Conversation
…rotation advice (HACK-2165) Audit F1 and lead item 2: - A private write (.hack/.env files, the project key, the encrypted store and its key) staged its complete contents in a `.<name>.<uuid>.tmp` sibling that no ignore entry covers, so a crash could leave a copy git would stage. Staging now happens in `.hack-staging/` next to the target: a private (0700) directory whose `.gitignore` of `*` exists before any staging file, so git never lists a leftover. The next write there sweeps leftovers older than ten minutes, and staging siblings from earlier versions of the same target. A linked or shared staging directory is refused. Store-internal writers (background commands, shared-host claims, the .internal compose override) keep sibling staging. - doctor's weak-key remedy said `mv .hack.secret.key .hack.secret.key.old` (a name git does not ignore) and to re-add secrets as argv values. It now keeps a 0600 copy of the old key outside the worktree until every secret is re-added, and re-adds with --value-stdin or the hidden prompt. Co-Authored-By: Claude <noreply@anthropic.com>
… read (HACK-2165) Audit S1 and lead item 1: a machine-local layer that predates private creation, or was made by hand, kept mode 0644 through writes, and its staging copy took that mode before the contents were written. A machine-local write now drops group and other bits from an existing layer, before the staging copy holds any content, and a write that changes nothing tightens the file in place. Shared layers keep their mode. Commands that read env layers (env, up/run paths, session) warn once per file on stderr about a loose machine-local file, after a successful read so a refusal stays one line. HACK-1680's keep-mode test now asserts the tightening. Co-Authored-By: Claude <noreply@anthropic.com>
…K-2165) Lead item 3: values staged in $TMPDIR/hack-mux-env-*/env.json stayed there when the pane never ran its command. A payload now expires after ten minutes: the pane refuses and removes an expired one, the staging process removes its payload when the limit passes (if it still runs), and the next staging sweeps this user's older payloads. Tests stage in a private directory, never the host's temporary directory. Co-Authored-By: Claude <noreply@anthropic.com>
Lead items 2 and 5 and the migration path: `hack doctor` reports, for the project and the global Hack home, secret-bearing files (local layers, .hack/.env files, project keys, encrypted store and key) that are loose, linked, owned by another user, tracked, or unignored; staging copies left by interrupted writes; terminal-session payloads that never ran; and "store present, key missing, cannot be read". `hack doctor --fix` tightens modes, adds missing ignore entries and removes Hack's own leftovers, printing each change; it never deletes a store, a key or a user's file, and never untracks. A doctor hint no longer suggests a secret value in argv. Docs: the env guide, the threat model, and an "after upgrading" step in the v5 upgrade guide. Co-Authored-By: Claude <noreply@anthropic.com>
…ACK-2165) Keeps writeTextFileAtomicIfChanged under the complexity limit after tightenExisting; no behavior change. Co-Authored-By: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…e layer staging (HACK-2165) Own-reviewer round on d74187c: - An existing `.hack-staging/.gitignore` (for example one a repository committed, checked out 0700 under umask 077) was trusted unread. It is now accepted only as a regular file of the user's holding exactly `*`; anything else refuses the write, so no staging copy can be visible to git. - The rotation remedy's `install` into a fixed name overwrote an earlier retired key. It now copies to a unique mktemp name and removes the key only once the copy is written. - Machine-local layer writes (writeTextFileAtomicIfChanged with tightenExisting) still staged as `.<name>.<uuid>.tmp` siblings, which only Hack's managed block ignores. They now stage in the private directory too; shared layers keep sibling staging. - Committed dotenv templates (.env.example, .sample, .template, .dist) are no longer reported as secret-bearing. - Tightening an unchanged layer is best effort (another user's file keeps working), and a missing store key is a warning on macOS while the keychain may still hold it. Co-Authored-By: Claude <noreply@anthropic.com>
|
@codex review |
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
Security findingsAdvisory findings (10)
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d8719bdac7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
…oject stores (HACK-2165) Bot review on d8719bd: - Concurrent first private writes in one directory could read the new `.hack-staging/.gitignore` before its creator wrote `*` and refuse. The ignore file is now staged complete and linked into place, so it never exists partially and a crash cannot leave an empty one. - An encrypted store or key configured inside the project checkout skipped the git checks. Such files are now checked like the project's own secrets (tracked is an error; unignored gets an anchored root .gitignore entry); files outside it stay exempt. Co-Authored-By: Claude <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9e060a3e36
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
🛡️ Codex Security Review · Automatically triggered
Here are some automated security review suggestions for this pull request.
Reviewed commit: 9e060a3e36
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
…ene refuses a linked .hack (HACK-2165) Bot review on 9e060a3: - On ExFAT/FAT, chmod cannot make the staging directory 0700, so every private write there was refused, regressing the documented first secret on such a drive. A staging directory of the user's own is now made 0700, and accepted at the mount-wide mode when the filesystem ignores chmod; a link or another user's directory is still refused, and the identity is re-checked before publishing. - doctor's secrets hygiene followed a `.hack` linked outside the project, so --fix could chmod or delete files there. A linked or non-directory `.hack` is now reported and not inspected, and every fix carries the identity of the directory it changes, checked again before the change (an ignore entry is never appended through a directory swapped after inspection). Co-Authored-By: Claude <noreply@anthropic.com>
…ct (HACK-2165) Bot security review on 9e060a3: a configured store or key under an in-project directory whose name begins with `..` (for example `..secrets/`) gave a relative path starting with "..", which was read as outside the project, so its git checks were skipped. Outside now means a `..` path segment or an absolute path. Co-Authored-By: Claude <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
🛡️ Codex Security Review · Automatically triggered
Here are some automated security review suggestions for this pull request.
Reviewed commit: 9ff7fb0892
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
…out or Hack home (HACK-2165) Bot security review on 9ff7fb0: a cloned repository's committed hack.config.json can point encryptedFile.path/keyPath at any file of the user's, and `hack doctor --fix` would then chmod it or remove old `.<name>.<uuid>.tmp` files beside it. Paths that only the project's configuration chose are now fixed, and their leftovers swept, only when their directory resolves (links followed) inside the checkout or the Hack home; elsewhere the finding is reported without a fix. The global configuration's paths are the user's own and keep their fixes. inspectSecretsHygiene is split into per-part helpers (no behavior change) to stay under the complexity limit. Co-Authored-By: Claude <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. 🚀 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
🛡️ Codex Security Review · Automatically triggered
Here are some automated security review suggestions for this pull request.
Reviewed commit: 553731fef3
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
…165) Bot security review on 553731f: a project-configured store or key inside the checkout but spelled through an alias (a link to the checkout, or another case on a case-insensitive disk) gave a relative path leaving the root, so its git checks were skipped. Containment now compares the resolved file directory with the resolved root, and git is asked about the resolved spelling. Co-Authored-By: Claude <noreply@anthropic.com>
…ectory (HACK-2165) Own-reviewer round on f00c17c: on a case-insensitive disk a store or key named `Store.key` in the configuration while git tracks `store.key` kept the configured case, so git's exact-case tracked check missed it. A regular file is now resolved itself (realpath of the file), so git is asked about its stored name; a link at the final component is still not followed. Co-Authored-By: Claude <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 40d6f8ee62
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Ready for lead: #764 (HACK-2165, secrets at rest), head Second-family review: Codex reviewer thread, clean at this exact head (round 17): Guard against deleting live inputs (HACK-2172 class):
and by Merges: real merges of Bot threads: all answered and resolved. CI at this head: green: Linux shards 4–8 (typecheck, privacy, lint in shard 8), test focus, docker-e2e, docs site, secret-scan. Not run (light PR): macOS shards 1–3, config compiler, candidate core, docker-e2e shards, runtime models/images, linux-process-lifetime.
Follow-ups:
|
…ACK-2165) findStaleMuxEnvironments built roots from the temp directory as given, while stageMuxEnvironment returns realpath'd paths, so on macOS (/var -> /private/var) the two named the same payload differently and two tests comparing them failed. The finder now resolves its base once, so hack doctor reports and removes payloads under the same spelling staging uses. The live-input check was already by resolved path (isLive compares the target as given and resolved against inputs as given and resolved); a new regression configures a key inside a stale payload by a linked temp directory spelling and checks it is neither offered nor removed. Regressions (a linked temp directory stands in for macOS /var on Linux): stale roots equal the resolved staged path; a key configured through the link survives inspection and --fix. Both fail without the change (the second only on the reported spelling; its protection held before). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
Add next.17 “what changed and what to do” notes to the release summary, both upgrade guides and the env guide. Users get concrete script migrations for hidden env values and native followed logs, the next.16 key-backup warning, and recovery guidance for partial cleanup. These describe merged source changes intended for next.17; they do not claim a release is published. The docs site remains pinned to next.16. #764 and #779 remain explicitly pending, and the recorded next.16 trials keep their original limits. | Subject | Merged contract checked at base `0a0bfdb8` | | --- | --- | | #747: native plain followed logs, streams, timestamps and structured session results | [native-log-follow.ts](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/src/backends/native-log-follow.ts), [followed-service-log contract](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/docs/reference/native-authored-commands.md#followed-service-logs) | | #767: metadata/`has_value`, scoped plaintext reads, terminal-only reveal, stdin secret writes, `env protect`, global-only lifecycle hooks/processes and YAML daemon API | [canonical prerelease wording](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/scripts/prerelease-plan.ts#L158), [env command](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/src/commands/env.ts), [env routes](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/src/daemon/routes/env.ts), [env contract](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/docs/env.md) | | #769 / HACK-2172 and #768/#783: protect live keys/config/YAML including filesystem aliases; cleanup receipts, partial removal and config-pointer reconciliation | [project-env-config.ts](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/src/lib/project-env-config.ts), [Doctor cleanup](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/src/commands/doctor.ts), [canonical cleanup note](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/scripts/prerelease-plan.ts#L164) | | #766: Doctor refuses unusable env layers | [doctor-secret-integrity.ts](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/src/lib/doctor-secret-integrity.ts) | | #773: loopback proxy ports, diagnosis without automatic repair | [proxy-loopback.ts](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/src/lib/proxy-loopback.ts), [Doctor](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/src/commands/doctor.ts) | | #770: inferred route readiness, 240-second grace, HTTP 200–499 limits and `service_healthy` exclusion | [http_probe.rs](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/packages/runtime-core/src/provider/http_probe.rs), [probe contract](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/docs/guides/native-candidate.md#native-http-readiness-probe) | | #778: bridge connection readiness after pool restart | [bridge.rs](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/packages/runtime-core/src/provider/bridge.rs) | | #758 and #776: merged startup fix and newer optional-daemon behavior, kept separate from next.16 | [project command](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/src/commands/project.ts), [Doctor](https://github.com/hack-dance/hack/blob/0a0bfdb8d1ee818d89bb49a2109bd88b0a9fea1b/src/commands/doctor.ts) | Validation at `f1d0d72fede5db6ce46f56039ba22a47911aa308`: - Persistent reviewer: clean after round 2. - Pinned Bun 1.4.4: docs prepare/check/typecheck and production site build pass. - Production-mode HTTP smoke: 95 docs, isolated searches/exports, redirects/refusals, 37 diagram blocks / 74 SVGs and 183 recipe links/anchors pass. The rendered upgrade guide returns 200 and contains the new guidance. - Privacy check, diff check and full-history Gitleaks pass (1,295 commits, no leaks). - Source citations and documented command forms checked against the merged base. Documentation only: no runtime, workflow, site pin, snapshot or global client changes. No live migration, keys, daemon, Docker or native VM tests were run. Lead owns batch integration and deployment. <!-- codesmith:footer --> --- <a href="https://backend.blacksmith.sh/track/run-proof?expires=1797183263&installation_model_id=17053&pr_number=785&ref=codesmith_pr_footer&repository=hack-dance%2Fhack&return_to=https%3A%2F%2Fgithub.com%2Fhack-dance%2Fhack%2Fpull%2F785&variant=run_proof_on_this_pr&signature=b04dd421a08341f70e804e671fd68678f102d1c4152146bdea18adf6de909981"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/proof-run-proof-on-this-pr-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/proof-run-proof-on-this-pr-light.svg"><img alt="Run Proof on this PR" src="https://pr-comments-assets.blacksmith.sh/codesmith/proof-run-proof-on-this-pr-dark-3x.png" width="168" height="28"></picture></a> <sup><a href="https://app.blacksmith.sh/hack-dance/codesmith/hack/pr/785?autoLogin=true&ref=codesmith_pr_footer">Open in [code]smith</a> · Need help on this PR? Tag <code>@codesmith-bot</code> with what you need.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> --------- Co-authored-by: Kit <344842+roodboi@users.noreply.github.com>
#779 (HACK-2177, retiring a store whose key is gone) and this branch each added resolveFileSecretStorePaths to src/lib/secret-store.ts; git merged both without a textual conflict, leaving a duplicate declaration. One definition remains: #779's, keeping its name and { active, storePath, keyPath } result for secret-store-retire.ts, now with this branch's opt-in strict mode (an unreadable or malformed configuration rejects instead of defaulting), which hack doctor's removal check uses. Doctor takes only storePath and keyPath from it for its hygiene scope. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…2165, HACK-2177) A retired store (<store>.retired-<stamp>/, from #779) may hold the only copy of values its key still opens. Hygiene's detectors never look inside one, but the removal check now refuses any target whose path, as given or resolved, has a retired-store component, both when findings are built and just before the unlink, with or without a scope. Regression: a store retired with retireEncryptedStoreFile survives inspection and --fix, and a guarded removal offered for its archived file (with and without a scope) is refused. It fails without the check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…d (HACK-2165) The retired-store and live-input checks treated a failed realpath of the target as "no resolved spelling", so an alias into a retired store whose resolution failed (EIO, say) passed both. Both now use realpathOrMissing: only a missing target has no resolved spelling; any other failure makes the target live and the removal is refused. Regression: an alias directory to a retired store, realpath failing with EIO for the target only, and a holding directory guard: the offered removal is refused with and without a scope. It fails without the change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
…t unknown (HACK-2165) livePaths added each input's realpath when it could and silently skipped it otherwise, so an alias whose resolution failed (EIO, say) left the resolved file unprotected. It now uses realpathOrMissing: a missing input has no resolved spelling, and any other failure makes the whole set unknown, so nothing is removed. Regression: a configured key reached through an alias directory whose resolution fails, at a leftover-shaped real path: no removal is offered and --fix keeps it. It fails without the change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Delightful! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
|
Ready for lead: #764 (HACK-2165), head Second-family review: Codex reviewer thread, clean at this exact head (round 21): Since 6af2a48:
Guard (updated): for doctor's Tests at this head: the merged tree typechecks. On this Linux host, CI at this head: Linux shards 4–8 (typecheck, privacy, lint), test focus, docker-e2e, docs site and secret-scan are green. The macOS shards 1–3 and the other heavy jobs are skipped on this light PR. Bot threads: Follow-ups: HACK-2181 (the automatic mux sweep, which doesn't consult configuration). Case-insensitive filesystem checks are covered by your macOS runs. |
Document next.17 recovery for an old secret store whose key is lost, and fold in merged #764's secrets-hygiene report and repairs. Users get two choices—restore the original key or retire the store reversibly—and a separate Doctor path for loose modes, staging leftovers and stale terminal payloads. Merged current `next` `d9df57c6` normally (no rebase). The conflict in `docs/guides/upgrade-to-v5.md` keeps both hygiene and retirement guidance. It replaces the old “separate change” wording and manual store-deletion advice. These changes remain **intended for next.17**; next.16's original behavior and key-backup warning stay explicit. | Claim | Source at merged base `d9df57c6` | | --- | --- | | Doctor severity, registered readers and restore-or-retire choices | [doctor-secret-integrity.ts](https://github.com/hack-dance/hack/blob/d9df57c626cb951d540ce23a41780275dbebd192/src/lib/doctor-secret-integrity.ts) | | Project selection, confirmation, `--allow-unchecked`, `--yes` and value-free retirement output | [secrets.ts](https://github.com/hack-dance/hack/blob/d9df57c626cb951d540ce23a41780275dbebd192/src/commands/secrets.ts), [retirement checks](https://github.com/hack-dance/hack/blob/d9df57c626cb951d540ce23a41780275dbebd192/src/lib/secret-store-retire.ts) | | Hygiene report, eligible mode tightening, project ignore entries, removal guards and fresh configuration checks | [secrets-hygiene.ts](https://github.com/hack-dance/hack/blob/d9df57c626cb951d540ce23a41780275dbebd192/src/lib/secrets-hygiene.ts), [scope regression tests](https://github.com/hack-dance/hack/blob/d9df57c626cb951d540ce23a41780275dbebd192/tests/secrets-hygiene-scope.test.ts) | | Ten-minute staging and terminal-payload age | [private-staging.ts](https://github.com/hack-dance/hack/blob/d9df57c626cb951d540ce23a41780275dbebd192/src/lib/private-staging.ts), [private-environment.ts](https://github.com/hack-dance/hack/blob/d9df57c626cb951d540ce23a41780275dbebd192/src/mux/private-environment.ts) | | Tracked cleanup consent and truthful outcomes | [doctor.ts](https://github.com/hack-dance/hack/blob/d9df57c626cb951d540ce23a41780275dbebd192/src/commands/doctor.ts) | The hygiene repair removes group/other permission bits from eligible own files; it does not promise to force every mode to exactly 0600. Removal protects live stores, keys, config and YAML by path and resolved path, keeps retired stores, and rechecks configuration before removing anything. It never untracks files. Retirement remains a deliberate separate operation, preserving the encrypted entries and explaining how to put them back. Validation at **`e5a88ea6af096c9fb12cffae3257975fa26b530b`**: - Persistent reviewer: clean at the exact merge head. - Only four docs differ from `next`; all runtime, test and script files are byte-identical to `d9df57c6`. - Bun 1.4.4: docs prepare/check/typecheck and production build pass. Normal hooks pass with six existing complexity warnings in imported code. - Production HTTP smoke: 95 docs, 37 diagram blocks/74 SVGs and 184 local links/anchors pass. The rendered guide returns 200 with hygiene, live-input protection and retirement guidance. - Privacy/diff checks and complete reachable-history Gitleaks pass (1,299 commits). - Obsolete tracked-file cleanup quotation remains absent. No live key/store, migration, daemon or native runtime was exercised. No pin, snapshot, workflow or client changes. Lead owns batch merge and deployment. --------- Co-authored-by: Kit <344842+roodboi@users.noreply.github.com>
Give v5 a short start-here path, with the current first-run messages and a cause/fix lookup for Doctor. Stable remains v4; v5 installs beside it. The pages keep Compose selection and the shared/private home boundary explicit. | Page route (preview/local build until deployment) | What it covers | Diagram | | --- | --- | --- | | `/docs/v5/install` | Channels, install/check/remove, select Compose, routing setup | Install flow | | `/docs/v5/getting-started` | Init or manual Compose adoption, review files, up/open/logs/down | First-run sequence | | `/docs/v5/upgrade` | Backup first, numbered trial steps and rollback | Upgrade flow | | `/docs/v5/native/start` | Setup consent, completed preflight, start/stop and back to Compose | Native state chart | | `/docs/v5/troubleshooting` | Finding/message → cause → next action | Lookup table | The index/sidebar expose the path. Existing URLs and legacy fragment links remain valid. The long references remain, with repeated first-run prose trimmed from the native guide. Contributor guidance now requires behavior PRs to update the affected short page. Correct an inherited claim that init automatically adopts Compose: it discovers app packages; existing Compose services need a reviewed manual scaffold/copy path. This head normally merges `next` `2c1f665157` and includes the requested #791 messages: - Compose `open` keeps the URL and adds the DNS hint: confirmed `unresolved`, or macOS `unconfigured` when Hack's resolver is missing and the lookup is unknown. The pages explain the older-suffix trap and the same-CLI routing/domain remedies. - `init --auto` warns when it generated the Bun `app` placeholder; edit its image/command before starting. Discovery successes and explicit manual/no-discovery choices do not get that notice. - #764's hygiene report replaces the old “separate change” note, including live-input/retired-store protection and configuration rechecks. **Release pins, immutable snapshots and diagram sources are unchanged by the merge.** Newer behavior is marked as next.17 source, not retroactive to next.16. The setup line remains isolated for HACK-2193, and manual upgrade is marked for replacement by HACK-2189/HACK-2191. Sources at merged base `2c1f665157e8645f79fe09812aca84448552e07a`: [generated CLI reference](https://github.com/hack-dance/hack/blob/2c1f665157e8645f79fe09812aca84448552e07a/docs/reference/cli.md), [init/open implementation](https://github.com/hack-dance/hack/blob/2c1f665157e8645f79fe09812aca84448552e07a/src/commands/project.ts), [DNS classification](https://github.com/hack-dance/hack/blob/2c1f665157e8645f79fe09812aca84448552e07a/src/lib/proxy-loopback.ts), [hygiene rules](https://github.com/hack-dance/hack/blob/2c1f665157e8645f79fe09812aca84448552e07a/src/lib/secrets-hygiene.ts), [channel manager CLI](https://github.com/hack-dance/hack/blob/2c1f665157e8645f79fe09812aca84448552e07a/scripts/install-prerelease.ts), [native setup CLI](https://github.com/hack-dance/hack/blob/2c1f665157e8645f79fe09812aca84448552e07a/packages/runtime-core/src/runtime_setup_cli.rs). The source DNS reference now distinguishes definite misses from unknown lookups accurately. Validation at **`095b740bfd56405eed8699745d45373ab2a43328`**: - Persistent reviewer clean at the exact merge head. All runtime and test files match `next`; only docs/contributor guidance/docs tooling differ. - Bun 1.4.4, frozen dependencies: docs prepare/check/typecheck/build, changed-script lint, site tests (2 tests/25 assertions), privacy and diff checks pass. Normal merge hooks passed with seven existing imported-code complexity warnings. - Production-mode HTTP smoke: 97 docs, version isolation/refusals, 41 diagram blocks/82 SVGs and 214 local links/anchors pass. New first-run and hygiene messages render on both updated pages. - 16 command families and flags checked against the generated CLI reference; native setup and manager commands checked against their separate CLI contracts. - Four Pele 1.9.0 house-theme diagrams inspected in both themes (366–563 px wide). Static image evidence only; the merge leaves them unchanged. - Complete reachable-history Gitleaks: 1,300 commits, no findings. No live install, DNS change, migration, key/store or native VM was exercised. **Lead's Mac walkthrough of the first two pages remains the user acceptance step.** Lead owns batch integration, merge and deployment. HACK-2195 stays open for those notes and the pending setup/upgrade commands. --------- Co-authored-by: Kit <344842+roodboi@users.noreply.github.com>
…HACK-2190) (#793) ## Problem and behavior No CI workflow previously exercised the documented upgrade from a v4 home. Add a reusable historical-byte fixture and compiled-CLI regression for Doctor, tracked-file consent, migration, env resolution and legacy store retirement. The fixture covers live/dead registry entries, healthy/lost global store keys, a project store reusing its live project key, tracked/untracked Git files and a linked worktree. It checks the exact changed-file inventory, every declared value, live-key preservation and sentinel-free output/journals. The same command/snapshot helpers can drive the upgrade assistant as it lands. The stable updater now verifies the release inventory and selected version before installation, streams bounded downloads and retries transient failures from fresh files. It stages full assets, preserves extra installed assets, installs the matching compiler and replaces the CLI last. Caught publication failures restore previous files; successful updates retain previous files with a private manifest containing paths and hashes. Native prerelease transfers use the same bounded retry/cancellation implementation, preserve their existing hashes/signatures, reclaim recognized private abandoned stages and gain reversible uninstall with read-only preview. Uninstall retains the whole channel and its user homes; it never recursively deletes candidate data.  Sources: [diagram](docs/reference/update-publication.mmd), [upgrade/recovery contract](docs/guides/upgrading-from-v4.md). ## Validation - Pinned Bun: **142 tests pass, 1,199 assertions, eight focused files**, including existing updater/manager/download/shard regressions. - Root `bun run typecheck`, `bun run check`, explicit changed-test/script lint, and production `bun run build` pass. The updater's version parser also runs against the real compiled current CLI output. - **#769 negative control:** the exact reverse patch no longer applies after subsequent cleanup receipt changes. Locally disabled its shared live-input predicate instead: the new compiled upgrade test failed **both cases**, because migration removed `.hack.secret.key` (ENOENT at the preservation assertion). Restored the source byte-for-byte; both positive cases pass. No mutation is included. - Loopback server cases cover interrupted/truncated transfer, HTTP 503 retry, offline, checksum/wrong-version refusal, stalled body and uncertain cancellation. Four thrown publication faults roll back. Two real child-process SIGKILL cases, after asset and compiler publication, leave the previous built CLI able to rerun `update --yes` successfully against the fixture server; compiler tripwire verifies the rerun does not need it. - Release-layout fixture calls the **actual release archive producer**, then consumes it through the current updater and the v4-compatible directory contract. - Both new test files are explicitly in the normal Linux and macOS pools; shard coverage verifies all 761 files. Hosted macOS execution remains external evidence. ## Hosted integration correction The first hosted run exercised the merge with #764, whose private-write staging landed after the original local base. The upgrade snapshot correctly caught four new self-ignoring staging markers per case. Merge current next and name those exact paths; assert their contents, Git ignore behavior and empty staging inventory. The remaining file-for-file, key, value and sentinel assertions stay intact. The merged tree passes the 142-test qualification and the #769 negative control still fails both cases before byte-identical restoration. ## Boundaries and release signal `fix`: updater integrity and recovery corrections; no CLI migration or required-check change. The ordinary light PR policy still reports selected macOS files as deferred; this PR changes protected CI planning inputs, so it requests full hosted coverage automatically. Stable origin trust remains official GitHub HTTPS plus checksums, not a publisher signature. The swap across several directories is not power-loss atomic; the process-kill rerun tests do not prove filesystem durability or hostile external-writer safety. Completed backups remain until the user disposes of them, and docs give their location and safe disposal point. Older installed v4 updater code retains its old behavior; preserving the release layout protects its compatibility independently. Native runtime applications and published downloads are not exercised by hermetic fixtures. The existing installer model coverage gap is recorded, not presented as formal verification. HACK-2190 Co-authored-by: Kit <344842+roodboi@users.noreply.github.com>
The next.17 section omitted the tmux breaking-change warning that already existed at the page tail. Move it into the release section and put its v4 stop procedure before the v5 trial. The env breaking entry was already correct; keep its scoped single-key/terminal/stdin migration guidance. Audit all **71 commits** from `v5.0.0-next.16` (`b21c3b1898`) through candidate **`5002cf87bb50686b17ceae8a4c835f524ee1b3a5`** against merged code and PR text. Add missing upgrade-assistant, activity, observe/plan/version, interactive exec, recovery, background-command and host/secret-custody notes. Preserve the complete native env-file behavior table and mark the four new JSON contracts **shape may change before 5.0.0**, with the planned HACK-2238 envelope migration. Correct stale native interactive-exec/network/metadata/Ctrl-C claims and the short upgrade assistant wording. Credit the publisher-shutdown fix to #719, already in next.16; keep next.17 lifecycle-command retirement separate. Retake a private stopped-state backup after v4 stops zellij, keeping the first copy too. Keep next.16 warnings scoped to that bundle. Keep original-key backups before older Doctor migrations and distinguish file rollback from runtime/data recovery. Only eight Markdown files change. Runtime, tests, workflows, generated CLI reference, diagrams, immutable snapshots and the site pin are unchanged. No diagram changed, so a new visual would add nothing. The site re-pin remains a separate release follow-up. Merge timing: respect the lead's candidate freeze; intended for the batch immediately after next.17 publication and the site re-pin. The moved tmux breaking-change notice is called out for the lead's pre-cut decision. This PR does not merge or publish anything. Validation at **`d95cfc554fabc4a0d70e3ba6caeb6746f63a198c`**: - Bun 1.4.4, frozen dependencies. Docs prepare/check/typecheck/build and site tests (2 passed, 25 assertions) pass. Production-mode HTTP smoke: 97 docs, 82 SVGs, 217 local links/anchors; task server stopped. - All 50 Hack commands named anywhere in the notes exist in the current generated CLI reference; 19 option contracts checked. CLI-reference regeneration has no diff. - All 71 commits have one row below, including the test commit and merge for #786. All 70 source evidence paths exist at the fixed candidate. Source release-note local links/anchors pass. - Privacy and complete reachable-history Gitleaks pass (1,330 commits, no findings). Persistent Claude Opus second-family review is CLEAN at this exact head. Hosted run 43585059152 passed docs site, secret scan and every planned Linux unit shard (4–8), plus the required test fan-in. Typecheck/privacy/quality ran on shard 8. Focus had no selected tests. Compiler, native core, runtime images/models, process-lifetime and Docker execution were out of scope; a green Docker fan-in is not Docker execution evidence. All bot comments were read; CLEAR at d95cfc5, zero unresolved threads/change requests. Codex code/security reviews found no issues. - No real install, migration, daemon/DNS/trust change, Docker or native VM run was performed for this documentation audit. Native acceptance and the candidate's hosted release qualification remain separate. ## Candidate commit coverage `entry present` means the behavior already had an entry within the next.17 section (some now have fuller detail). `added` means missing behavior or migration guidance was added there; #824 moves the existing warning into that section. `not user-visible` means no shipped CLI/runtime change: documentation, test/CI/repository housekeeping or the internal desktop preview. Source links pin the candidate, rather than a moving branch. | Commit / PR | Coverage | Entry or reason | Audited source | | --- | --- | --- | --- | | [70d328e](70d328e) [#743](#743) | added | Host setup: privileged/NSS safeguards | [src/lib/linux-trust-setup.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/linux-trust-setup.ts) | | [51f15c8](51f15c8) [#746](#746) | not user-visible | Docs-only upgrade checklist and site generation; no installed behavior | [scripts/docs/prepare.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/scripts/docs/prepare.ts) | | [c14f3f5](c14f3f5) [#744](#744) | added | Native setup JSON accounting | [packages/runtime-core/src/provider/setup.rs](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/packages/runtime-core/src/provider/setup.rs) | | [b0c6bcd](b0c6bcd) [#705](#705) | added | Retained background exec/run and cursor tools | [src/commands/background-command-start.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/background-command-start.ts) | | [c89f4fd](c89f4fd) [#745](#745) | added | Linux daemon query/home refusals | [src/commands/daemon-systemd.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/daemon-systemd.ts) | | [cce4b59](cce4b59) [#752](#752) | not user-visible | Site pin/snapshots and editorial pages only | [scripts/docs/versions.json](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/scripts/docs/versions.json) | | [56676fc](56676fc) [#754](#754) | added | Setup reuse/offline accounting; pin-watch changes are internal | [packages/runtime-core/src/provider/setup.rs](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/packages/runtime-core/src/provider/setup.rs) | | [7a496f1](7a496f1) [#755](#755) | added | MCP registered selectors and background tool guidance | [src/mcp/server.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/mcp/server.ts) | | [e7a7039](e7a7039) [#747](#747) | entry present | Native follow text shape; added session ends/restart recovery | [src/backends/native-log-follow.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/backends/native-log-follow.ts) | | [87a6df5](87a6df5) [#758](#758) | added | Compose short one-shot startup | [src/lib/compose-startup-state.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/compose-startup-state.ts) | | [2afb5c4](2afb5c4) [#761](#761) | added | Native Hack networks and inert generated labels | [src/lib/native-hack-compose-conventions.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/native-hack-compose-conventions.ts) | | [342a585](342a585) [#771](#771) | not user-visible | Docs-only next.16 trial record | [docs/versions/v5/guides/upgrade-from-v4.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/versions/v5/guides/upgrade-from-v4.md) | | [6f0acf1](6f0acf1) [#769](#769) | entry present | Migration live-key/alias preservation | [src/lib/project-env-config.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/project-env-config.ts) | | [c96c444](c96c444) [#756](#756) | added | Child key filtering, fixed diagnostics, legacy ignore/YAML API refusals | [src/lib/child-environment.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/child-environment.ts) | | [e2c73c6](e2c73c6) [#748](#748) | not user-visible | Contributor CI selection/coalescing, outside product release notes | [scripts/ci-change-scope.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/scripts/ci-change-scope.ts) | | [ebf794e](ebf794e) [#760](#760) | added | Agent/output custody warning; runtime unchanged | [src/agents/instruction-source.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/agents/instruction-source.ts) | | [021b16b](021b16b) [#763](#763) | added | One-pass background redaction scan; no public benchmark claim | [src/lib/background-command/output-scanner.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/background-command/output-scanner.ts) | | [8564ec4](8564ec4) [#765](#765) | added | Shared preflight/start admission and detached failure reporting | [src/backends/native-project-review.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/backends/native-project-review.ts) | | [0c0fba2](0c0fba2) [#767](#767) | entry present | Breaking env exposure/protect/stdin/scope/API guidance | [src/commands/env.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/env.ts) | | [9435da9](9435da9) [#762](#762) | added | Local Git/link refusals and no-follow dotenv | [src/lib/project-env-config.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/project-env-config.ts) | | [edf23ae](edf23ae) [#753](#753) | added | Daemon stop proves the live Hack home | [src/commands/daemon-systemd.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/daemon-systemd.ts) | | [573ceec](573ceec) [#766](#766) | entry present | Doctor layer/integrity error; added store/key write refusals | [src/lib/secret-store.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/secret-store.ts) | | [a0e9760](a0e9760) [#757](#757) | added | Orphan output truncation and final-sync evidence | [src/lib/background-command/recovery.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/background-command/recovery.ts) | | [10e1958](10e1958) [#759](#759) | added | Private lifecycle logs/FIFO and expiring mux payloads | [src/lib/private-file.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/private-file.ts) | | [bd899ee](bd899ee) [#775](#775) | not user-visible | Portable test fixtures only | [tests/single-file-tar.test.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/tests/single-file-tar.test.ts) | | [80dae3d](80dae3d) [#776](#776) | added | Candidate missing-daemon diagnosis is optional/healthy | [src/commands/doctor.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/doctor.ts) | | [5b2a2d0](5b2a2d0) [#772](#772) | added | Bounded attaching-network retry; strict saved reads remain | [src/lib/native-compose-ownership.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/native-compose-ownership.ts) | | [ab29d49](ab29d49) [#777](#777) | not user-visible | CI scheduling only | [docs/reference/ci-test-selection.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/reference/ci-test-selection.md) | | [31339c7](31339c7) [#770](#770) | entry present | Native inferred readiness, 240 s, HTTP/service_healthy limits | [packages/runtime-core/src/project/compose/service.rs](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/packages/runtime-core/src/project/compose/service.rs) | | [156ee7f](156ee7f) [#773](#773) | entry present | Loopback proxy port/Doctor/open checks | [src/lib/proxy-loopback.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/proxy-loopback.ts) | | [a7ec3c7](a7ec3c7) [#768](#768) | entry present | Cleanup receipts/partial outcomes and tracked-file wording | [src/lib/project-env-config.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/project-env-config.ts) | | [ceb3e23](ceb3e23) [#778](#778) | entry present | Native bridge socket readiness | [packages/runtime-core/src/provider/bridge.rs](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/packages/runtime-core/src/provider/bridge.rs) | | [af91049](af91049) [#783](#783) | entry present | Pointer reconciliation after partial cleanup | [src/commands/doctor.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/doctor.ts) | | [0a0bfdb](0a0bfdb) [#780](#780) | not user-visible | Site-only Linux guide publication; no CLI behavior | [scripts/docs/versions.json](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/scripts/docs/versions.json) | | [d0cf767](d0cf767) [#786](#786) | not user-visible | Consent test wording only (both commits) | [tests/env-migration-tracked-consent.test.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/tests/env-migration-tracked-consent.test.ts) | | [7e2e630](7e2e630) [#786](#786) | not user-visible | Consent test wording only (both commits) | [tests/env-migration-tracked-consent.test.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/tests/env-migration-tracked-consent.test.ts) | | [91c311e](91c311e) [#779](#779) | entry present | Restore or reversible retire; missing store keys scoped to readers | [src/lib/secret-store-retire.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/secret-store-retire.ts) | | [6ab1ace](6ab1ace) [#785](#785) | not user-visible | Docs-only release/upgrade/env notes | [docs/guides/v5-release-notes.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/guides/v5-release-notes.md) | | [25bd63c](25bd63c) [#764](#764) | entry present | Doctor hygiene, local modes, ignored staging and live-input protection | [src/lib/secrets-hygiene.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/secrets-hygiene.ts) | | [d9df57c](d9df57c) [#784](#784) | not user-visible | Resolver/proxy and consent test corrections only | [tests/project-open-loopback.test.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/tests/project-open-loopback.test.ts) | | [2c1f665](2c1f665) [#791](#791) | added | Detached failure names, open DNS hint, init placeholder; prune guidance | [src/commands/project.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/project.ts) | | [f6fe55f](f6fe55f) [#787](#787) | not user-visible | Docs-only retirement/hygiene follow-up | [docs/guides/v5-release-notes.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/guides/v5-release-notes.md) | | [7f9548c](7f9548c) [#792](#792) | not user-visible | Start-here docs, navigation and contributor rule only | [docs/versions/v5/install.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/versions/v5/install.md) | | [a0cfc73](a0cfc73) [#793](#793) | added | Verified updater publication, backups and reversible candidate removal | [src/lib/self-update.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/self-update.ts) | | [292d312](292d312) [#782](#782) | added | Lock-free native ps and proved failed-start down | [src/backends/native-project-observe.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/backends/native-project-observe.ts) | | [b1e123b](b1e123b) [#796](#796) | added | Doctor reader count/worktree grouping in store recovery | [src/lib/doctor-secret-integrity.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/doctor-secret-integrity.ts) | | [286d00f](286d00f) [#789](#789) | added | Foreground command-before-wrapper retirement | [src/lib/project-lifecycle-processes.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/project-lifecycle-processes.ts) | | [bb6a7d1](bb6a7d1) [#788](#788) | not user-visible | Linux qualification runbook only | [docs/guides/linux-host-qualification.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/guides/linux-host-qualification.md) | | [a262d42](a262d42) [#800](#800) | not user-visible | Internal desktop design; outside supported CLI release scope | [apps/desktop/DESIGN.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/apps/desktop/DESIGN.md) | | [6b161ba](6b161ba) [#774](#774) | added | Native interactive exec, finite fallback and receipt recovery | [src/backends/native-project-exec.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/backends/native-project-exec.ts) | | [1249272](1249272) [#799](#799) | not user-visible | Portable output-contract CI selection only | [scripts/test-shard-plan.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/scripts/test-shard-plan.ts) | | [fa3f03d](fa3f03d) [#790](#790) | added | Read-only upgrade check, snapshot and rollback | [src/commands/upgrade.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/upgrade.ts) | | [c3b79bc](c3b79bc) [#807](#807) | added | Observe-only global status and unknown evidence | [src/commands/global-status-observe.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/global-status-observe.ts) | | [29be043](29be043) [#812](#812) | added | Read-only local CA trust diagnosis | [src/lib/ca-trust-status.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/ca-trust-status.ts) | | [f0102fd](f0102fd) [#814](#814) | not user-visible | Prepared-base verifier test fixture only | [tests/qualify-provider-pin.test.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/tests/qualify-provider-pin.test.ts) | | [b4ebfec](b4ebfec) [#815](#815) | added | Compact upgrade plan, snapshot-backed apply/resume | [src/lib/upgrade-apply.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/upgrade-apply.ts) | | [c44b266](c44b266) [#801](#801) | not user-visible | Internal optional desktop preview; not shipped CLI behavior | [apps/desktop/Cargo.toml](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/apps/desktop/Cargo.toml) | | [56d1d0f](56d1d0f) [#804](#804) | added | Automatic mux sweep preserves live/retired config inputs | [src/lib/live-inputs.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/live-inputs.ts) | | [1958363](1958363) [#805](#805) | added | MCP timedOut result and Codex installer timeout | [src/mcp/server.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/mcp/server.ts) | | [e6207e8](e6207e8) [#810](#810) | added | Lifecycle activity writes including handler refusals; activity JSON | [src/commands/lifecycle-activity.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/lifecycle-activity.ts) | | [23fe08f](23fe08f) [#825](#825) | added | Read-only batch review and permission-only key repair | [src/lib/upgrade-review.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/upgrade-review.ts) | | [cab596c](cab596c) [#781](#781) | entry present | Full native env-file behavior table; added support/precedence summary | [src/backends/native-compose-environment.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/backends/native-compose-environment.ts) | | [1e84684](1e84684) [#798](#798) | not user-visible | Rust test process isolation/nextest; internal qualification only | [scripts/test-runtime-core.sh](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/scripts/test-runtime-core.sh) | | [518af29](518af29) [#817](#817) | not user-visible | Remove accidental empty checkout files; no installed CLI change | [.gitignore](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/.gitignore) | | [07192f7](07192f7) [#824](#824) | added | BREAKING warning moved from page tail into next.17; v4 stop procedure retained | [src/mux/mux-config.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/mux/mux-config.ts) | | [fe09a5b](fe09a5b) [#816](#816) | added | Read-only install/trust admin plans and exits | [src/commands/global.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/global.ts) | | [8977676](8977676) [#827](#827) | added | Registry-preserving project observe, runtime opt-in | [src/commands/projects.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/projects.ts) | | [5965b23](5965b23) [#828](#828) | added | Running CLI version identity JSON | [src/lib/version-report.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/version-report.ts) | | [2922210](2922210) [#830](#830) | added | Upgrade safe/admin/manual action kinds | [src/lib/upgrade-action-kind.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/upgrade-action-kind.ts) | | [51b55c0](51b55c0) [#820](#820) | not user-visible | Archive/plan/shared-helper verification fixtures only | [tests/python-free-download.test.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/tests/python-free-download.test.ts) | | [5002cf8](5002cf8) [#809](#809) | added | Retirement read retry, second Ctrl-C and native cancellation cleanup | [src/lib/project-lifecycle-processes.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/project-lifecycle-processes.ts) | --------- Co-authored-by: Kit <344842+roodboi@users.noreply.github.com>
Second of two PRs for HACK-2165 (umbrella HACK-2163): audit findings F1 and S1, lead items 1, 2, 3 and 5, and the
hack doctor"secrets hygiene" section as the migration path. The first PR is #762 (F3, F4, F5); please merge this one after it. Item 4 (encrypted-file backend links and key cache) moved to HACK-2169 and is not here.F1 and item 2: no committable copies of keys or env files
.hack/.envfiles,.hack.secret.key, the encrypted store and its key) staged their contents in a.<name>.<uuid>.tmpsibling that no ignore entry matched, so a crash could leave a copy forgit add -A. They now stage in.hack-staging/next to the target. That directory is private (0700), and it holds a.gitignoreof*that exists before any staging file, so git never lists anything in it, without changing any project ignore file. The rename stays on the same filesystem. The next write there removes leftovers older than ten minutes, plus older versions' siblings for the same target. A linked or shared staging directory is refused. Writers whose directories must hold only their own files (background commands, shared-host claims, the.internalcompose override) keep sibling staging..hack-staging/stays in the directory afterwards, holding only its.gitignore.mv .hack.secret.key .hack.secret.key.old(an unignored name). It now says to keep a 0600 copy outside the worktree (~/.hack/retired-keys/) until every secret is re-added, and to re-add with--value-stdinor the hidden prompt, never as argv. One other doctor hint that suggested--secret KEY VALUEis fixed too.S1 and item 1: loose machine-local layers
env, the up and run paths,session) warn once per file on stderr about a loose machine-local file. The warning names the file and its mode, and is printed after a successful read, so refusals stay one line.Item 3: terminal-session env payloads
Payloads in
$TMPDIR/hack-mux-env-*/env.jsonnow expire after ten minutes. The pane refuses and removes an expired one. The staging process removes its payload when the time limit passes, if it is still running, and the next staging sweeps this user's older payloads.Item 5 and the migration path:
hack doctor"secrets hygiene"This section covers the project and the global Hack home, and names files, never values. It reports:
hack doctor --fixtightens modes (through a no-follow handle, only while the file is still the one found), adds missing ignore entries, and removes Hack's own leftovers. It prints each change. It never deletes a store, a key or a user's file, and it never untracks a file.docs/guides/upgrade-to-v5.mdgains an "after upgrading, check secrets at rest" step;docs/env.mdand the threat model describe the behaviour.Merge ordering and overlap
writeProjectEnvConfigFileinsrc/lib/project-env-config.ts. fix(env): refuse machine-local writes git could collect; no-follow legacy dotenv reads (HACK-2165) #762 adds the destination guard and this PR addstightenExisting. The conflict is a small merge in one object literal; after fix(env): refuse machine-local writes git could collect; no-follow legacy dotenv reads (HACK-2165) #762 lands I will mergenextinto this branch.src/lib/shell.ts, the env parse errors,src/templates.ts,src/daemon/routes/env.ts).src/lib/secret-store.tsonly gains a config-only export at the end of the file (resolveFileSecretStorePaths).Validation
--fixnever deletes a store.privacy:check,docs:checkand gitleaks pass. 162 test files that import the changed modules ran.🤖 Generated with Claude Code
Open in [code]smith · Need help on this PR? Tag
@codesmith-botwith what you need.