From e01547f440c5c04bb88547b86171f4393d6d7d96 Mon Sep 17 00:00:00 2001 From: Kit <344842+roodboi@users.noreply.github.com> Date: Fri, 13 Nov 2026 18:52:21 +0000 Subject: [PATCH 1/2] docs: add next.17 secret store retirement guidance --- docs/guides/upgrade-to-v5.md | 21 +++++++++++++++ docs/guides/v5-release-notes.md | 25 +++++++++++++---- docs/versions/v5/guides/upgrade-from-v4.md | 31 ++++++++++++++++------ 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/docs/guides/upgrade-to-v5.md b/docs/guides/upgrade-to-v5.md index 6913afa03..7a345c783 100644 --- a/docs/guides/upgrade-to-v5.md +++ b/docs/guides/upgrade-to-v5.md @@ -114,6 +114,27 @@ See [Env and secrets](../env.md#legacy-repos-and-migration) and the [threat model](../security/env-secrets-threat-model.md). These are manual checks, not evidence that the real-machine upgrade or rollback has passed. +### An old global secret store whose key is gone + +Merged #779, intended for next.17, makes an old store with a missing or wrong +key a Doctor error only where the project's runtime reads it. Other projects +receive a warning. Choose one: restore the original key from a private backup, +or retire the store if the key is gone for good. A new key cannot open the old +entries. + +`hack secrets retire-store --path ` selects the store for that project +and moves it into a timestamped directory beside it. It deletes nothing, leaves +the key file alone and prints how to put the encrypted file back. Retirement +does not decrypt or print entries. Doctor then lists the retired file as +information. + +Retiring requires `--allow-unchecked` because another shell may hold the key in +`HACK_SECRETS_FILE_KEY`, which Hack cannot check. Pass it only after confirming +that no shell for a project selecting the store has that key; it also acknowledges +registered projects Hack could not check. Without a terminal, add `--yes` to +confirm the move. A store that an available key opens is refused. See +[the recovery and retirement details](../env.md#compatibility-notes). + ## The daemon after an upgrade Installing 5.0.0 over a running 4.x does not replace the daemon. On Linux the old diff --git a/docs/guides/v5-release-notes.md b/docs/guides/v5-release-notes.md index 4be82fc3a..ba260b6d8 100644 --- a/docs/guides/v5-release-notes.md +++ b/docs/guides/v5-release-notes.md @@ -26,6 +26,7 @@ its original behavior. | **Env listings hide values by default, including migrated plaintext.** Ordinary `env` / `env list` text and JSON output are metadata. JSON omits `value` and reports `has_value`. | Use `has_value` for availability checks. For a value a script actually needs, call `hack env get KEY` with the same `--env` and `--service`; that command prints plaintext. Bulk `--show-values` requires interactive stdin and stdout; `--show-secrets` remains an alias. | | **Migration cleanup preserves live keys (HACK-2172).** A legacy store's `keyPath` can no longer make the current project/shared key a cleanup target. Current config and YAML inputs are protected too, including filesystem aliases. | Keep key and env backups before migration. On next.16 or an earlier prerelease, do not run `doctor --migrate-env-config` without a private readable copy of `.hack.secret.key`. The fix does not recover a key already removed. | | **Doctor fails when an env layer cannot be used by the runtime.** Unreadable, invalid or undecryptable layers no longer get an apparent all-clear. | Run `hack doctor` after upgrading. Fix the reported layer or recover the original key before starting; keep the encrypted file rather than generating a replacement key over it. | +| **An old global secret store with a lost key no longer fails Doctor in unrelated projects (HACK-2177).** It is an error where the runtime reads it and a warning elsewhere. | Restore the original key, or deliberately retire the store with `hack secrets retire-store --path `. Retirement preserves the encrypted file and prints how to put it back; see the confirmation requirements below. | | **Doctor checks the Compose proxy's loopback ports.** A reachable container address no longer hides a broken published loopback path. | Read the `proxy ports` warning, check competing listeners and DNS/bind settings, then retry. HTTP success on port 80 is not HTTPS success on 443; the check applies no automatic repair. | | **Native route readiness can be inferred.** A complete standard Caddy route with no authored healthcheck gets a reviewed HTTP probe and 240 seconds of initial grace. A complete HTTP 200–499 response establishes endpoint readiness, not application correctness. | Review the route port and startup logs. Explicit healthchecks are not replaced, and inferred readiness does not satisfy `depends_on: condition: service_healthy`. The grace does not extend the whole graph's deadline. | | **Native start waits for bridge sockets after a stopped pool resumes.** An immediate start no longer fails merely because provider readiness preceded the bridge listener. | Use normal native `up`; startup still requires a successful bridge connection within its deadline. Do not replace readiness checks with a fixed sleep. | @@ -77,11 +78,25 @@ proof that nothing changed. See [cleanup and reconciliation](../env.md#legacy-re [#768](https://github.com/hack-dance/hack/pull/768) and [#783](https://github.com/hack-dance/hack/pull/783). -An old global secret store whose key is lost still needs its original key for -recovery. Keep the encrypted store and key backups; do not delete it or provision -a new key just to clear Doctor. A separate retire path is being added in -[#779](https://github.com/hack-dance/hack/pull/779); no retire command is promised -by these notes until it merges. +### An old global store whose key is lost + +Merged [#779](https://github.com/hack-dance/hack/pull/779), intended for next.17, +makes a missing or wrong store key a Doctor error only in projects whose runtime +reads that store. Other projects receive a warning. The finding names registered +projects that read it; without the key, entries cannot be counted or read. + +Choose one: restore the original key, or, if it is gone for good, run +`hack secrets retire-store --path ` for a project that selects the store. +Retirement moves the encrypted file into a timestamped directory beside it, +deletes nothing, leaves the key file alone and prints the command to put it back. +It does not recover the values; a new key cannot decrypt them. + +The command refuses a store that an available key opens. It also needs +`--allow-unchecked`: another shell may set `HACK_SECRETS_FILE_KEY` to the key, +and Hack cannot inspect that shell. Pass the flag only after confirming that no +shell for a project selecting the store has that key; it also acknowledges +registered projects Hack could not check. Without a terminal, add `--yes` for +the move confirmation. See [store recovery and retirement](../env.md#compatibility-notes). ## Highlights diff --git a/docs/versions/v5/guides/upgrade-from-v4.md b/docs/versions/v5/guides/upgrade-from-v4.md index aab246728..9894a3a20 100644 --- a/docs/versions/v5/guides/upgrade-from-v4.md +++ b/docs/versions/v5/guides/upgrade-from-v4.md @@ -387,8 +387,9 @@ output contract or assume the protection command exists in next.16. #### An old global secret store whose key is gone A machine upgraded from v4 may still have an encrypted store such as -`~/.hack/secrets.enc.json` whose key file was lost. From next.17 (HACK-2169, -HACK-2177), Doctor reports that store as a `secret integrity` finding: +`~/.hack/secrets.enc.json` whose key file was lost. Merged +[#779](https://github.com/hack-dance/hack/pull/779), intended for next.17, +changes Doctor's `secret integrity` finding for that store: - an **error** in a project whose legacy env contract reads the store, and a **warning** in any other project; @@ -402,8 +403,9 @@ entries. 600), from a backup or another machine, or set `HACK_SECRETS_FILE_KEY` to the same key. 2. **Retire the store** when the key is gone for good: - `hack secrets retire-store`, run in a project that selects the store or - outside any project for the global one. Without a terminal, add `--yes`. + `hack secrets retire-store --path ` selects that project's store; + outside any project, omitting `--path` selects the global one. Without a + terminal, add `--yes`. - It moves the store into a new directory `.retired-/` beside it, keeping its name. It deletes nothing, reads and prints no entry, and leaves the key file alone. It only retires a file that is a @@ -418,6 +420,20 @@ entries. - Afterwards Doctor lists the retired file as information, and the project check no longer fails. +For example, after those key and project checks, use the selected candidate: + +```sh +"$V5" secrets retire-store --path /absolute/project --allow-unchecked +``` + +Review the store path in the confirmation prompt. Retirement keeps the encrypted +entries for recovery; it does not make them readable with a replacement key. +It is separate from migration cleanup and is not available in next.16. + +Sources: [Doctor's store finding](https://github.com/hack-dance/hack/blob/91c311e4d9/src/lib/doctor-secret-integrity.ts), +[retirement command and confirmation](https://github.com/hack-dance/hack/blob/91c311e4d9/src/commands/secrets.ts), +[retirement checks](https://github.com/hack-dance/hack/blob/91c311e4d9/src/lib/secret-store-retire.ts). + Sources for next.16 behavior: [env list and get](https://github.com/hack-dance/hack/blob/b21c3b189841c1a3cbb8af2b76414fa347dc7057/src/commands/env.ts), [project key checks](https://github.com/hack-dance/hack/blob/b21c3b189841c1a3cbb8af2b76414fa347dc7057/src/lib/doctor-env-key.ts). @@ -444,10 +460,9 @@ With [#783](https://github.com/hack-dance/hack/pull/783), a confirmed store removal drops its legacy config pointer even if a later cleanup step fails. If the store remains, the pointer stays. A config-write failure is reported too, so follow the remaining reconciliation guidance rather than assuming rollback. -An old global store with a missing key should stay intact until its key is -recovered or the separate retirement path in -[#779](https://github.com/hack-dance/hack/pull/779) is available. Do not discard -the store or replace its only key to silence Doctor. +For an old global store with a missing key, use the separate +[restore-or-retire choices](#an-old-global-secret-store-whose-key-is-gone) above. +Do not discard the store or replace its only key to silence Doctor. Source: [current env migration and cleanup guidance](https://github.com/hack-dance/hack/blob/af91049f30d7ec272c461d009253faf6800507bc/docs/env.md#legacy-repos-and-migration). From 354099d70e33b05a5bf03f95360c1c1d94a28ece Mon Sep 17 00:00:00 2001 From: Kit <344842+roodboi@users.noreply.github.com> Date: Fri, 13 Nov 2026 19:07:20 +0000 Subject: [PATCH 2/2] docs: select the shared home for candidate store retirement --- docs/versions/v5/guides/upgrade-from-v4.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/versions/v5/guides/upgrade-from-v4.md b/docs/versions/v5/guides/upgrade-from-v4.md index 9894a3a20..e6fb12cab 100644 --- a/docs/versions/v5/guides/upgrade-from-v4.md +++ b/docs/versions/v5/guides/upgrade-from-v4.md @@ -420,19 +420,20 @@ entries. - Afterwards Doctor lists the retired file as information, and the project check no longer fails. -For example, after those key and project checks, use the selected candidate: +For example, after those key and project checks, use the selected candidate +with the same Compose home as the Doctor finding: ```sh -"$V5" secrets retire-store --path /absolute/project --allow-unchecked +HACK_RUNTIME_BACKEND=compose "$V5" secrets retire-store --path /absolute/project --allow-unchecked ``` Review the store path in the confirmation prompt. Retirement keeps the encrypted entries for recovery; it does not make them readable with a replacement key. It is separate from migration cleanup and is not available in next.16. -Sources: [Doctor's store finding](https://github.com/hack-dance/hack/blob/91c311e4d9/src/lib/doctor-secret-integrity.ts), -[retirement command and confirmation](https://github.com/hack-dance/hack/blob/91c311e4d9/src/commands/secrets.ts), -[retirement checks](https://github.com/hack-dance/hack/blob/91c311e4d9/src/lib/secret-store-retire.ts). +Sources: [Doctor's store finding](https://github.com/hack-dance/hack/blob/91c311e4d9540ea3ca32113a61458a26db90c704/src/lib/doctor-secret-integrity.ts), +[retirement command and confirmation](https://github.com/hack-dance/hack/blob/91c311e4d9540ea3ca32113a61458a26db90c704/src/commands/secrets.ts), +[retirement checks](https://github.com/hack-dance/hack/blob/91c311e4d9540ea3ca32113a61458a26db90c704/src/lib/secret-store-retire.ts). Sources for next.16 behavior: [env list and get](https://github.com/hack-dance/hack/blob/b21c3b189841c1a3cbb8af2b76414fa347dc7057/src/commands/env.ts), [project key checks](https://github.com/hack-dance/hack/blob/b21c3b189841c1a3cbb8af2b76414fa347dc7057/src/lib/doctor-env-key.ts).