Repository navigation
Tags
Tags
T23 — Check type constraints last, and let a derived type only narrow (… …#3292) * feat(mfile): check Box Type constraints last, and only narrow A type's constraints are a check, never a layer. check_constraints reads a finished expansion, after the override layer, and fails with exit 3 naming the type, the key and the layer that set the value (BOX-061). It never changes the spec, so a constraint never adds a package, a port or an egress entry (BOX-062). Type resolution fails with exit 3 naming the type, the key and the parent when a derived type's constraint admits a value its parent's excludes (BOX-156). * fix(mfile): name the type that holds the broken constraint check_constraints named the entry's own type for every failure, even when the failing constraint came from a parent type. Check the entry's type first and name the type whose constraints table failed. * fix(mfile): seed built-in constraints and check section keys Each built-in Box Type now ships its constraints, so a project type cannot loosen them and an entry of the type is checked against them. A constrained setting is checked at its flat key and under its section, with the section map taken from spec.rs. * docs(mfile): note that no create path calls check_constraints yet #3295 adds the call after each expand on the create path. * fix(mfile): keep both forms of a constrained key when narrowing A type that set a key flat and under its section was checked against itself, and only its last form reached the types that extend it. Check each type only against the types before it, and keep every form. --------- Co-authored-by: minimal-foundry[bot] <327719912+minimal-foundry[bot]@users.noreply.github.com>
T21 — One minimal.toml for every box, end to end (#3244) * feat(boxes): compose the project from the expanded entry The contribution carries the expanded minimal.toml entry, and the daemon composer applies each list it carries. A list the entry leaves out keeps the daemon's own project items of that kind (BOX-068). * feat(minimal): send the expanded entry when a box starts Session and task starts expand their minimal.toml entry over [defaults] and [defaults.<type>], with a legacy [session] table read as [defaults.session], and send it on the contribution. The daemon composes the project's part of each box from it (BOX-068). * fix(minimald): compose an entry box without reading [session] When the client sends an expanded entry, build_composables no longer reads the project's [session] table, so a task box gets none of it. Entry packages join the closure walk, so their env_state_wiring and fs mappings compose. The wire docs state that the entry carries only the five composed lists, and name #3257 for the full expanded spec. * style(minimald): format the entry wiring test * fix(minimal): refuse a start whose session entry is undecided session_box_entry now returns the SessionEntryUndecided refusal in place of sending no entry, so the start never falls back to [session]. The end-to-end test also starts a task entry in a legacy [session] project and checks that the task gets no vars, and checks the refusal. * docs(minimal): say a task entry's vars and patches do not reach the box The box_entry doc comment claimed that min task run applies a task entry's vars and patches. It reads only the [tasks.<name>] table, so the [defaults] layers are dropped. Name issue #3266 for that gap. --------- Co-authored-by: minimal-foundry[bot] <327719912+minimal-foundry[bot]@users.noreply.github.com>
T67 — Restart an until_stopped box from its stored spec, under the sa… …me id and name (#3228) * feat(minimald): restart an until_stopped box from its stored spec Add the RestartBox RPC with a typed RestartRefusal reply. The box's actor checks the lifetime, the name, the stored spec and the volumes before it stops anything, stops a running box as a stop does, and starts it again from its stored spec with no client attached, under the same id and name. A start that fails leaves the box stopped. The restart records the stop's exited event and a started event, and runs only the hooks a resume runs (BOX-176, BOX-177, BOX-178). * test(minimald): pin restart refusals, start failure, hooks and events Cover BOX-176, BOX-177 and BOX-178: a restart from the stored spec under the same id and name, its refusals before any stop, a failed start that leaves the box stopped, the hooks it runs, and the events it records. * fix(minimald): fail a restart whose entrypoint sits behind a hook shell An argv box that holds a host-side row and keeps its hook-launched shell never starts its entrypoint. The restart now fails as ensure_host does, so the box stays stopped and no started event is written. * docs(minimald): name the restart hook-shell gap and its flip condition The refusal in restart_launch fails closed for an argv box that holds a host-side row. Name the tracking issue (#3231) and the condition that lifts it (#3042) at the refusal itself. --------- Co-authored-by: minimal-foundry[bot] <327719912+minimal-foundry[bot]@users.noreply.github.com>
feat(minvmd): look for the guest images under the system data directo… …ries too (#2975) * feat(minvmd): look for the guest images under the system data directories too After the user's own data directory, minvmd looks for the kernel, root filesystem and initramfs under each system data directory: $XDG_DATA_DIRS, else /usr/local/share:/usr/share, as the XDG base directory specification says, relative entries ignored. A machine-wide install (the macOS package, a Linux package) puts the images there; a user's own copy still wins. A daemon with no data directory of its own (no HOME: a service account, a scrubbed environment) uses the machine's copy. The MissingImage error names every directory looked in. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(minvmd): take every guest image of a boot from one data directory Each image used to fall back on its own, so a user directory missing one file (an interrupted or older install) booted its kernel and rootfs with the machine's initramfs. The lookup now picks the first data directory, the user's then the system ones, that holds every image whose override is unset, as regular files: a directory named like an image no longer counts. MissingImage replaces MissingEnv for the no-HOME case. It names each directory looked in with the files it lacked, says when there was none, and ends with what to do: reinstall, or set the overrides. The missing-image test now points XDG_DATA_DIRS at an empty directory, so a machine-wide install cannot satisfy it. New tests cover the mixed install, an override, a directory named like an image, a relative XDG_DATA_DIRS entry and the no-data-directory path. The resolver docs describe the new lookup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(minvmd): select a boot's image directory once for all three images resolve_boot_images and the VMM child called the three resolvers one after another, and each chose the image directory again. An install finishing the user's copy between two calls could still boot the system kernel with the user's initramfs. resolve_boot_images now reads the overrides once, chooses the directory once (select_image_dir) and joins each unset image's file to it; an image with its override set is used verbatim, as before, and a boot with all three overrides needs no data directory. The VMM child and `minvmd boot` use it; the single-image resolvers keep their behaviour. VmError::MissingEnv had no constructor left, so it is removed. The XDG_DATA_DIRS test uses the set_env/unset_env helpers. New tests: one selection per boot (a probe whose user initramfs appears after the first look), every override set with no data directory, and an override beside defaulted images. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
T23 — Show the disk a stopped box holds (#3141) * feat(minimal): report the disk a stopped box holds in show and prune min box show prints a Disk line for a stopped or exited box. min box prune --dry-run lists each box it would remove with the disk it holds, prints the total, and removes nothing (BCLI-006). * fix(minimal): leave out the Disk row when show has no figure min box show printed "Disk: -" for a stopped box the daemon did not measure. The row told the person nothing, and it broke the pinned show output in box_list_and_show_render_retained_records. * fix(minimal): keep the dry run from claiming no match on a failed host min box prune --dry-run printed that nothing matched even when a host was not checked. It now prints that line only when every host answered. min box show again prints a Disk row for every stopped or exited box, with - when the daemon gave no figure, and the list.rs pin includes it. * fix(minimal): pick the disk unit from the rounded value format_disk printed 1048575 bytes as 1024.0 KiB. It now moves up a unit while the value rounded to one decimal is 1024.0 or more. --------- Co-authored-by: minimal-foundry[bot] <327719912+minimal-foundry[bot]@users.noreply.github.com>
feat(diag): send a suspected vulnerability with --security (#3102) * feat(diag): send a suspected vulnerability with --security The diag portal is gaining a security mark on its create request: only portal owners can read the report, its description is never public, and it is never filed to public GitHub. Add --security to the arguments `min bug --upload` and `min diag upload` share, and send it on the create body as a JSON boolean. The ordinary receipt calls the URL a report a person can start a diagnosis from, which is wrong for a report the uploader cannot read. A security upload prints that it was received privately and that the page only confirms receipt. The ordinary lines are unchanged. `min bug --security` without --upload is refused before collecting. Nothing would be sent, and a reporter must not read that as a report made. SECURITY.md keeps email as the route and adds this one for reports that come with a bundle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(diag): send a security bundle only when the portal confirms the mark The receipt said "received privately" from the local flag alone, so a portal that ignored the mark would leave a report public under that promise. The create answer now has to echo security: true, or the bundle is not sent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(diag): delete an unconfirmed security record and say what reached the portal Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(diag): keep a security note until the portal confirms the mark Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(diag): keep the delete doc comment on delete Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
test(minimald): prove a task box exits after its client drops (#3085) A task run's client goes away mid-task. The task box ends by itself as exited with the task's code 3, keeps its exited event, and a new client reads its whole output over ReadLog. The daemon log names the box's end and its code. Co-authored-by: minimal-foundry[bot] <327719912+minimal-foundry[bot]@users.noreply.github.com>
T12 — Attach to a box's terminal, with or without an address (#3018) * feat(minimald-rpc,minimald): carry pty_enabled on box listings The listing and the read of a box now say whether its stored spec sets io.pty_enabled, so min box attach can tell a terminal box from one with none. A daemon that predates the field reads as no terminal. * feat(minimal): add min box attach with and without an address min box attach <box> hands the terminal to a box that has one. With no box named it picks the project's running terminal box, else its only retained one. Refusals exit 2, 4 or 7. An attach the host ends prints one line that names why and exits 254. * test(minimal): classify the read after min box attach ends * refactor(minimald): read the resume PTY check from record_has_pty The resume's PTY check and the listing's record_has_pty were two copies of one rule. The resume now calls record_has_pty. * fix(minimal): wait for the record before min box attach names a cause The daemon closes the attach's channel before it writes the stopped record, so one read after ssh exits could see the box still running. The read now polls under a bound until the box leaves running. A stopped box ends with 254 whatever exit code its entrypoint recorded. The host and exited lines now say what can happen in plain words. * fix(minimal): wait out a stop's grace before min box attach says takeover After a 254 the read now polls for STOP_GRACE plus HOST_PROBE_TIMEOUT, shared from minimald-rpc, so a stop that waits on a process ignoring SIGTERM still prints the stop line. An OOM record carries exit code 137, so its reason is matched before the exit code. * style(minimal): format the 254 settle bound * fix(minimal): say why min box attach waits after a takeover A 254 against a box that still runs waits the stop's grace period to read why. After one quiet second, the terminal now says the attach ended and how long the check can take. * fix(minimal): drop the wait line before a 254 attach notice The design allows one notice line before exit 254. This reverts 1385327 and restores the single DAEMON_END_SETTLE read. * fix(minimal): end min box attach with 0, 7 or 254 only Every ssh 255 is now a lost connection, exit 7. A 254 against a box that reads exited ends with 0 and keeps its line. A 254 with an unread record prints one line that names the host. * fix(minimald): list a box with an unreadable spec by its box type A spec read error listed the box with no terminal, so a bare min box attach could skip a real session. The listing now falls back to the Box Type, as for a box with no stored spec, and logs a warning. --------- Co-authored-by: minimal-foundry[bot] <327719912+minimal-foundry[bot]@users.noreply.github.com>
fix: admit a bundled bep.app proxy in keychain read-backs (#3023) * fix(bep): admit a bundled proxy in keychain read-backs security -T records a bundled proxy as its app bundle, and dump-keychain -a prints that bundle path rather than the inner binary the resolver hands to set and list. entry_admits compared the two literally, so every secret read back from a keychain refused its own proxy. Admit the dump path when it is the bundle that contains the resolved proxy binary: the proxy path, stripped of the dump path, must continue with /Contents/MacOS/. * fix(bep): admit only a bundle's main program in keychain read-backs security -T records a bundle's main program as the bundle, and any other program in it under its own path. An entry naming bep.app therefore says nothing about a helper beside it, so matching on the Contents/MacOS prefix was too wide. Match <name>.app/Contents/MacOS/<name> and nothing else. --------- Co-authored-by: gominimal-aw-bot[bot] <281738952+gominimal-aw-bot[bot]@users.noreply.github.com> Co-authored-by: Norrie Taylor <norrie@minimal.dev>
test(minimal): box addresses and -o json output, end to end (#3006) Address one box over a harness daemon by its id, its name and provider/host/name from min box show, stop and rm. An address that names no box ends with exit 4. An unqualified name while the selected host does not answer ends with exit 7. Each -o json box object carries min/v1/box, and a secret renders only as its reference. Each step logs one resolution in its own span, with the host it reached. Co-authored-by: minimal-foundry[bot] <327719912+minimal-foundry[bot]@users.noreply.github.com>
PreviousNext