Repository navigation
Conversation
…ls, null platform and external volumes
The native Compose-backend classifier reserved a hand-written, incomplete
set of ownership label namespaces, treated `platform: null` as a foreign
platform, and did not classify external volumes, which the native runtime
refuses as `external_volume`.
- Add `HACK_OWNERSHIP_LABEL_NAMESPACES` as the single source of truth for
the label namespaces Hack writes (io.hack-local, io.hack.native-config,
io.hack.native-file, io.hack.storage-witness) and derive the reserved set
and its refusal phrase from it. A test scans the TypeScript and Rust
runtime-core sources so every io.hack label key is covered and no
namespace is stale.
- Treat an absent or null `platform` as unset, as Compose and native review do.
- Classify `volumes.<v>.external` (true or the legacy {name} form) as the
new closed feature `external_volume` in the refusal, doctor output and docs.
- Document that only `.hack/docker-compose.yml` and the explicit `platform`
field are classified; overrides, `extends` and `include` are not followed.
- Move `checkComposeBackendFeatures` so `checkProjectEnvKey` keeps its JSDoc.
Refs HACK-1337
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every file in `bun test` shares one Bun process. A test that changed PATH, HOME, HACK_HOME or cwd and then failed before its restore leaked that change into every later file, which then failed with "Executable not found in $PATH: git/bun" and hid the first failure (HACK-1327). - Preload tests/helpers/global-state-guard-preload.ts from bunfig.toml. It snapshots the environment, cwd, umask, exit code, guarded global functions and process listeners around every test and at every file boundary, fails the leaking test or the run with a value-free message naming the file, and restores the environment, cwd, umask and exit code so later files run clean. Replaced functions and listeners are reported but kept, because they may still sandbox a timed-out test's unsettled work. - Fix leaks it and a review found: fzf replaced the process.env object; the VM-file, retained-build and retained-source-bind helpers could fail setup after changing PATH/HOME with no restore registered; the retained routing and retained-file fixtures kept HACK_HOME/PATH on the fixture when their lifetime was unknown; the protected-files negative left a process.kill spy for later files. Refs HACK-1327 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d exclude only carrier proofs - A carrier boundary now keeps a refusal's own observed reason (an issued helper policy boundary or a classified command cause) even when it is caught after the carrier deadline. `storage-budget` is reported only for a deadline-shaped refusal (timeout, budget, lifetime mark or no observed cause) whose carrier deadline expired and was not cancelled. - A recorded storage command that replaces an admission refusal with its fixed command refusal now carries the source's issued boundary, so a helper policy refusal observed during admission is no longer relabeled `storage-budget` at `storage-helper-start`. - The start deadline's storage exclusion now wraps only each carrier proof (carrier creation and witness verification). The guard's freshness checks and saved-state reads consume the start budget. - The exclusion-cap comment states that the uncapped sum is finite, (5B+3) x V x S, but can reach hours. Refs HACK-1361 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…chctl shim per test The M3 full suite at the first guard commit failed 16 shared-host-lifecycle cases (helpers reported as foreign listeners or never ready) and flagged tests/e2e-launchd-guard.test.ts for a process exit listener. - Root cause of the shared-host cascade: the engine-identity ambient-proxy test set HTTP(S)_PROXY and their lower-case forms, then restored them with a delete. Bun 1.4 copies assignments to proxy keys into the environment that fetch and Bun.spawn (without env) use, but never a delete, so every later loopback fetch in the process went through the dead proxy while process.env looked clean. restoreEnv now assigns "" before deleting. - The guard now also compares Bun's native environment at each file boundary (one /usr/bin/env child per file), names the file, and turns proxies off natively with NO_PROXY=* because Bun cannot take a deleted key back. Restores of deleted keys assign "" first as well. - The e2e harness's launchctl shim registered a process exit listener that lived for the whole Bun process; releaseLaunchctlGuard removes the shim and listener, and e2e-launchd-guard calls it after each test. Refs HACK-1327 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs HACK-1337 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-catalog denylist A dashed `git-<sub>--helper` binary (also by an absolute git-core path or with `.exe`) and a `<sub>--helper` argument to `git` are now read as `git <sub>`, so `git-bisect--helper --bisect-run cmd` meets the `bisect` rule and `git-submodule--helper foreach cmd` the `foreach` rule. Only a whole `<sub>--helper` word is rewritten, so no existing refusal is lost. The reference now names file-loaded code (pickle, marshal, an evaluated config file) as a known limit beside stdin SQL, and records that a helper's own options, such as the old `rebase--helper --add-exec-commands`, are not modeled. Refs HACK-1373 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve bunfig.toml: keep both test preloads, this branch's global-state guard (HACK-1327) and next's checkout-write guard (HACK-1343, #390). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ike .hack/.gitignore `ensureHackGitInfoExclude` decided writability with `access(W_OK)` alone, so root (or a user an ACL grants write) replaced a 0444 `info/exclude`, while `.hack/.gitignore` already treats a file with no write permission bit as read-only for every user. Check the mode bits first, then the injectable access probe, and document the ACL consequence in docs/env.md. docs/cli.md now describes the missing-project refusal as one closed `E_PROJECT_NOT_FOUND: <message>` line and shows each logger's prefix instead of only the console logger's `ERROR:` form. The short-spelling parse test now also covers `up` from the #370 differential table. Refs HACK-1378 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`hack env unset KEY` with a piped stdin and no HACK_NO_INTERACTIVE never returned and burned a full CPU: `confirmSafe` only consulted the explicit opt-out, so a TTY-less run entered the clack confirm, whose readline loop cannot settle on a non-TTY stdin (HACK-1385). - `confirmSafe` now gates on `canPrompt()` (TTY on both streams plus the opt-outs) and resolves every TTY-less run by its declared policy within milliseconds; `doctorConfirm` notes skipped destructive steps on the same condition. - Raw clack prompts without a guard are routed through the convention: `secrets` (name, value, delete), the `session` picker and attached-workspace choice, `mcp` target selection, `update` (stdin as well as stdout), and the `agent` client picker. - Regression tests: unit cases for each policy without a TTY, and an e2e spawn of `env unset` and `secrets delete` with piped stdin under a 5 s kill bound asserting exit, bounded CPU and wall time, and no value echo. - docs/cli.md documents the non-TTY behavior. Refs HACK-1385 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… pending adoption pins After a refused `hack config adopt --recover --stop` (HACK-1318, journaled switch), `hack doctor` told the user to run `hack down` and plain `hack config adopt --rollback`, both of which that pending state refuses. The compose-env-at-rest report now carries `adoptionPending`, and the check and `--fix` note name `hack config adopt --recover --rollback` while the adoption is pending; the settled wording is unchanged. Deadline-guard follow-ups from #397 (HACK-1391): - prove the keep-CHANGED branch of the `mutateRetainedContainers` catch with a drift reported after the caller deadline (mutation: dropping the exclusion fails only this test) - prove `requireMutationDeadline`'s expiry branch directly through the callback revocation fence (mutation: issuing CHANGED fails only this test) - correct the retained-routing helper comment (deadline expiry is E_LEGACY_ADOPTION_DEADLINE) and the HACK-1283 comment (HACK-1340) - document that a second `--recover --stop` after the refusal gets the generic E_LEGACY_ADOPTION_BUSY refusal, and assert it in the HACK-1318 test Refs HACK-1391 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`lokiTail` registered a `process.once("SIGINT")` handler and never removed
it, so every follow that ended by socket close (the normal path) left a
stale handler in the process. In the shared `bun test` process the next
`process.emit("SIGINT")`, in tests/native-authored-project-oneoff.test.ts,
consumed those `once` handlers and the global-state guard blamed that test
for a listener change it did not cause. `runAuthoredCommand` in
src/lib/native-authored-command.ts is symmetric; the one-off file passes on
its own.
The handler is now installed only while the tail is open and removed in a
`finally`, so a SIGINT-fired (self-removing) handler and a normal close both
leave the listener list as it was. Two regression tests cover both paths
and fail without the fix. The guard now reports listener counts
(`2 -> 0`) so a consumed handler from an earlier file is distinguishable
from one added by the test it names.
Refs HACK-1392, HACK-1327
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nput access refusals Target inspector follow-ups after #379 (HACK-1390). - Classify input presence faults through an exported seam, projectInputAccessFault(), so EPERM is covered by a test (a mode-000 directory only produces EACCES). - ProjectInputAccessError keeps a value-free class/code diagnostic (for example Error:ENOTDIR) as a non-enumerable property, read with projectInputAccessDiagnostic(). Envelopes, printed errors and JSON stay unchanged and carry no path, OS message or cause. - input_permission_denied now names the permission fix first. The contract doc no longer says an unsearchable .hack or .hack/.internal is adoption_state_unsafe; it is input_permission_denied even on a project that never used adoption. Refs HACK-1390 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Integration gate for merge batch b50: origin/next + #404 (HACK-1337) + #446 (HACK-1385) + #430 (HACK-1373) + #439 (HACK-1378) + #421 (HACK-1361) + #448 (HACK-1391) + #452 (HACK-1390) + #405 (HACK-1327, HACK-1392). Tree 5f938772. Closed after the batch squashes.
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.