`listInstances` passed the stderr of `limactl list --json` through to the
terminal. On a fresh installation it printed "No instance found. Run
`limactl create` to create an instance." before the TUI started. The
warning stayed hidden behind the TUI and reappeared when the menu
suspended to run `limactl create`, which was confusing.
Buffer the stderr and only include it in the error when the command fails.
Also fix the error from `cmd.Start()` being discarded.
Fixes#5681
Assisted-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
Press `c` or F7 in the instance list (or "Create Instance" in the
empty state) to open a form for the instance name, template, CPUs,
memory, disk, VM type, and whether to start the instance after
creation. Empty fields fall back to the template defaults.
The other `limactl create` flags (mounts, networks, port forwards,
`--set`, `--param`, etc.) are available in the "Details" section, which
is hidden by default. Its fields are generated from the flag
definitions of `limactl create`, and the description of the focused
field is shown below the form.
To minimize free-text input, the values are chosen from dropdowns
whenever the choices are known: the shell completion values of the
flags, the drivers, and the image variants of the selected template.
"Other..." in a dropdown allows entering a value that is not in the
list.
"Create" runs `limactl start` (or `limactl create`) with the
corresponding flags. "Edit" opens an editor for the template YAML with
the form values applied, and then creates the instance from the edited
YAML. In both cases, the menu is suspended while limactl is running, and
the new instance is selected when returning to the menu.
The form can be navigated with the arrow keys as well as with Tab:
Up/Down move between the fields and the buttons (except in an open
dropdown list, and except between the lines of a text area), and
Left/Right move between the buttons.
The single-key shortcuts of the instance list are now only handled
while the list has the focus, so that they do not interfere with typing
into the form.
Fixes#5595
Assisted-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
Merge the windows-plain-wsl2 and windows-plain-qemu jobs into a
windows-plain matrix job, and add HCS to the matrix, running the
plain-Windows smoke test against templates/experimental/hcs.yaml.
The full test suite is not run for HCS, as the HCS driver still lacks
several features (mounts, port forwarding, ...).
Fixes#5465
Assisted-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
golangci-lint v2.14.0 (revive v1.17.0) reports `unexported-return`
for Manager, ManagerWith, and DaemonManager returning the unexported
autoStartManager type.
Assisted-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
Add the `macos-27` template for macOS 27 "Golden Gate" (27.0, build 26A428),
and repoint the `macos` aliases (`templates/macos.yaml` and
`templates/_images/macos.yaml`) from `macos-26` to `macos-27`.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
Apple changed the IPSW path layout for macOS 27.0; the URL no longer
contains the `fullrestores` path component:
https://updates.cdn-apple.com/2026FallFCS/<uuid>/UniversalMac_27.0_26A428_Restore.ipsw
The regex in `hack/update-template-macos.sh` did not match this layout, and
`macos_url_spec_from_location` just returns non-zero on a mismatch, so the
script would silently skip such a template rather than fail. Relax the path
part of the regex to accept any depth.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
For a recursive copy whose destination is an existing directory, the rsync
backend copied the *contents* of the source directory, while the scp backend
copied the directory itself, like `cp -r` and `scp -r` do. Since `--backend=auto`
prefers rsync and only falls back to scp when the guest has no rsync, the
outcome of the very same command depended on the guest image.
The rsync backend appended a trailing slash to every path of a recursive copy,
and a trailing slash on the source is what tells rsync to copy the contents.
Derive the form to pass to rsync from the destination instead, so that a
trailing slash spelled by the user is no longer significant:
- the destination is an existing directory: `SRC DST`, copying SRC into DST;
- the destination does not exist yet: `SRC/ DST`, making DST a copy of SRC.
A destination that can neither be confirmed nor ruled out to be a directory
fails the copy, instead of being assumed to be missing, which would put the
files in the wrong place again.
This also fixes two related defects of the previous code: `copy -r` of a
non-directory into a destination that does not exist made rsync fail on the
appended slash, and multiple sources were merged into the destination instead
of being copied by name.
Add the missing case to copy.bats (both backends, both directions), which only
covered a plain `SRC DST` copy into a destination that does not exist yet, plus
unit tests for the path rewriting, which needs no VM.
`limactl shell --sync` does want the form that copies the contents, so let it
spell its own paths with a trailing slash and stop setting Options.Recursive,
which for rsync only added a `-r` that `-a` already implies.
Fixes#5500
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
gomodjail v2 moves the focus to static analysis: `gomodjail analyze`
verifies that the modules annotated `gomodjail:confined` in go.mod cannot
reach a denied capability (filesystem, network, process execution, raw
syscalls, OS state modification, or cgo).
Add gomodjail to ./hack/tools, add a `gomodjail` lint target, and wire it
into `make lint` and the "Lints" job. Unlike the legacy dynamic mode, this
gate is blocking.
The verdicts are platform-dependent, so the gate is pinned to linux/amd64
and linux/arm64. These are the only platforms that can be analyzed from any
host: analyzing darwin needs a macOS host, as the "vz" driver requires cgo.
The linux verdicts are a superset of the darwin ones anyway. Windows is
deliberately left out, as it would unconfine 18 more modules (go-yaml,
containerd/log, go-runewidth, ...) and weaken the gate for the other
platforms.
`gomodjail fix` downgraded 36 modules to `gomodjail:unconfined` to make the
gate pass. 65 modules remain confined: 37 clean, 28 warning-only.
`make gomodjail-fix` is added for redoing this on dependency bumps, so that
the decision stays visible and reviewable in go.mod.
The macOS job that exercises the legacy dynamic mode (`gomodjail run`) is
kept as an experiment, with its checkout pinned to v2.0.1 instead of HEAD.
Assisted-by: Claude Code (Opus 5)
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
Add hack/bats/tests/port-forwarding.bats, covering the same portForwards
rule matrix as hack/test-port-forwarding.pl, with one @test per
forward/ignore scenario, and run it in CI on every host platform:
- Linux: the existing "bats" job
- macOS: the "qemu" job (QEMU driver) and the "vz" job (vz driver)
- Windows: the "windows" job (WSL2 driver) and the "windows-qemu" job
Instead of grepping hostagent log strings and sleeping for a fixed time
(issue 4388), the test records `limactl watch --json` events and waits
for the "forwarding"/"not-forwarding" event of each guest listener
before connecting.
The test honors LIMACTL_CREATE_ARGS (e.g. --vm-type), allows overriding
the base template via LIMA_BATS_PORT_FORWARDING_BASE_TEMPLATE (the WSL2
job uses template:experimental/wsl2), and installs socat in the guest
with whatever package manager the guest image provides.
Notable differences from the Perl script:
- Uses socat on both the host and the guest (the nc/socat choice is
dropped; CI was already running the socat mode).
- The tests for the `guestPortRange: [305, 309]` rule now actually use
ports 305-309; the Perl script tested ports 325-329 by mistake, which
are not covered by any rule.
- Test names are ASCII-only ("->" instead of a Unicode arrow): the MSYS2
bash mangles multibyte characters inconsistently between bats' test
registration and dispatch, making every such test fail with
"bats: unknown test name".
- Guest paths passed to `limactl shell` are embedded in an `sh -c`
command string instead of being passed as arguments, because MSYS2
path conversion would rewrite a bare /tmp/... argument to
C:/msys64/tmp/... before limactl.exe sees it.
hack/test-port-forwarding.pl is removed. The only piece of it that
test-templates.sh still needs is the `guestPort: 8888` rule for the
"CONTAINER_ENGINE run" test, which is now injected with `limactl yq`.
The injected rule replaces any portForwards rules from the template, as
the Perl script did: all instances share the host port namespace, so
e.g. test-misc.yaml's own rules would collide with a concurrently
running instance created from the same template. The modified template
is round-tripped through `limactl tmpl copy --embed` so that it still
passes the template-embedding check (`limactl yq` indents sequences
differently than the embed encoder).
The perl/nc/socat host requirements and the guest netcat/socat installs
are gone; the external host IP is now looked up with getent instead of
perl.
The test passed 56/56 (16 skipped as designed on a Linux host) against
the QEMU driver without KVM.
Fix#4389
Assisted-by: Claude Fable 5 <noreply@anthropic.com>
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
Docsy < 0.12 loaded "Open Sans" from Google Fonts by default
($td-enable-google-fonts: true); newer Docsy flipped the default to
false, so the site silently fell back to system fonts. Re-enable it.
Assisted-by: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
Docsy >= 0.12 pre-declares Bootstrap color variables in
_variables_forward.scss before importing the project's
_variables_project.scss, so our `!default` assignments of $primary,
$secondary, and $dark were silently ignored, and the site fell back
to the stock Bootstrap palette (blue primary, gray secondary).
Turn them into plain assignments.
Also pin $link-color to $blue: Docsy < 0.12 set it explicitly, but
newer Docsy lets Bootstrap derive it from $primary, which is white
here, making links invisible.
Assisted-by: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
- hugo-extended 0.133.1 -> 0.164.0 (via `npm run update:pkg:hugo`;
0.164.0 is the latest on npm)
- docsy 0.11.0 -> 0.17.0, as docsy 0.11.0 is incompatible with
Hugo >= 0.141 (Resource.Err removal):
- The Hugo module path is now `github.com/google/docsy/theme`; the
`github.com/google/docsy/dependencies` module is retired.
Bootstrap and Font Awesome (now v7) come from npm instead, via
`hugo mod npm pack` (packages/hugoautogen)
- docsy 0.17 requires Dart Sass >= 1.95 (LibSass is no longer
supported); add `sass-embedded` to devDependencies, which `npm run`
puts on PATH for hugo (locally, on Netlify, and in CI)
- hugo.toml: allow HTML content files (`security.allowContent`,
default-deny since Hugo 0.162) and Node.js parent-directory reads
for PostCSS/browserslist (`security.node.permissions.allowRead`,
sandboxed since Hugo 0.161)
- hugo.toml: rename deprecated `includeFiles` -> `files`,
`languageName` -> `label`; bump min Hugo version to 0.162.0
- Refresh caniuse-lite via `npx update-browserslist-db`
Assisted-by: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>