Skip to content

fix(start): recover from the broken states left by an unclean shutdown - #5088

Merged
AkihiroSuda merged 3 commits into
lima-vm:masterfrom
resker:feature/vz-shutdown-recovery
Sep 30, 2026
Merged

AkihiroSuda merged 3 commits into
lima-vm:masterfrom
resker:feature/vz-shutdown-recovery

Conversation

@resker

@resker resker commented Jun 6, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Filed as #5087. A KeepAlive-enabled LaunchDaemon crash-loops after an unclean shutdown, because the host agent can exit before the VM is stopped and limactl start then refuses to start from the state that leaves behind.

#5436 has since fixed the first of the two bugs of #5087 — the vz driver now asks the guest to stop over SSH when CanRequestStop is false, and removes vz.pid when it stops. This PR is rebased onto that and now covers the rest: recovering an instance that is already in one of the two broken states.

Changes

One commit per topic:

fix(store) — name the recoverable broken states, and only when provable
Sentinel errors (ErrDriverRunningHostAgentStopped, ErrHostAgentUnreachable) so callers match with errors.Is rather than on message strings. The second is reported only on ECONNREFUSED, the one outcome proving nothing is listening on ha.sock; a timeout, a protocol error, or a socket not yet bound can all come from a live host agent and must not be auto-recovered, or the caller would delete a live agent's files and start a second one. (On Windows WSAECONNREFUSED is not mapped to ECONNREFUSED, so the sentinel never fires there — reported but not recovered, which is the safe direction.)

fix(start) — recover from the broken states left by an unclean shutdown
An orphaned driver is force-stopped; an unreachable host agent has its files removed without signaling any process, since the recorded PID may since belong to an unrelated one. Only ha.pid/ha.sock are removed — a driver running as its own process may still be alive, and hiding it from the next inspection would allow a second driver for the same instance; a driver that runs in the host agent process (vz) records the same PID and is removed with them. The two run in sequence, not as alternatives, because clearing a departed host agent can reveal a driver that still needs stopping — and doing that after ha.pid is gone means the force stop cannot signal a reused PID.

docs(autostart) — documents both states, when they occur, and what limactl start does about each.

What is left after e529ce0 and #5436

Both narrowed how these states arise; neither closes them.

Still reachable, and what this PR recovers from:

  • a driver that runs as its own process (qemu, and the other out-of-process drivers) outliving a host agent that died within the same boot — no reboot and no PID reuse needed, and nothing stops that VM or clears its PID file;
  • PID reuse within a single boot;
  • instances whose directory carries no boot session marker, because they were started by an older version of Lima — i.e. every existing autostart instance, until it is started once by a build that has e529ce0;
  • platforms that expose no boot session ID (osutil.ErrBootSessionNotSupported), where PID files are handled as they were before the marker.

Testing

Unit tests for both halves: the socket cases drive the real host agent client against a unix socket rather than synthetic errors, and the cleanup cases cover in-process vs. separate driver.

Validated on Apple Silicon (macOS 26, arm64) with a --condition=boot LaunchDaemon running k3s — hard reboot auto-starts cleanly, both broken states recover, k3s and its workloads healthy afterwards. @CFBancroft independently validated the orphaned-driver recovery on a 2018 Intel Mac mini.

Closes #5087

Also fixes the problem reported in #5075, which is the stale-ha.sock state above; leaving that issue open for @lonlundgren to confirm against their setup rather than closing it from here.

Assisted-by: Claude Code

@resker
resker force-pushed the feature/vz-shutdown-recovery branch from d2298fa to 933ac53 Compare June 6, 2026 04:08
@resker resker changed the title fix(vz): recover from orphaned driver and CanRequestStop=false on unclean shutdown fix(vz): self-healing LaunchDaemon restart after unclean shutdown Jun 6, 2026
@resker
resker force-pushed the feature/vz-shutdown-recovery branch from 933ac53 to 6f12be4 Compare June 6, 2026 13:00
@lonlundgren

Copy link
Copy Markdown
Contributor

Nice job.

This needs additional testing on Intel. HVF has reliability issues that don't show up on VZ that are especially exacerbated by launching a Lima VM closer to boot time.

See: #84 , #2252 , #5074

We have custom launchdaemon scripts running across stably Intel and Apple Silicon that encompass these fixes and the #5075 fix you included.

@resker

resker commented Jun 6, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @loncharles — noted wrt Intel systems... alas I don't have any accessible to validate w/. I'd had a look at some of your comments and wonder if you'd considered vzNAT as alternative to socket_vmnet - might sidestep the XPC timing issue and hew closer to what macOS is layering in.

@lonlundgren

Copy link
Copy Markdown
Contributor

We absolutely need bridged network in our setup and it is the reason why we chose Lima instead of an alternative and so that we'd have one deployment surface area over Intel and Apple Silicon.

The XPC timing issue is less of a problem in practice, but socket_vmnet has several other repeatable ways it fails when you try to start a VM at boot. And much more reproducible on a machine that has a two-step boot when FileVault is enabled, than one that doesn't. So net net, the better ordering when wanting to boot a VM with a luanchscript is to have the script own start/retry on socket_vmnet creation and then only start Lima after.

The APIC timer kernel panic is independent of networking choice and is highly repeatable on Intel. Many people will hit this. And Lima made a change in their CI to fix it but never shipped any fixes in any of their VM template files.

@resker

resker commented Jun 6, 2026

Copy link
Copy Markdown
Contributor Author

fyi, just tested this with socket_vmnet bridged networking on Apple Silicon (most of my use is k3s w/ NAT) — both the LaunchDaemon boot and keep-alive restart work w/o any observed issues.

@lonlundgren

Copy link
Copy Markdown
Contributor

Good stuff. I should have been clear that these are primarily Intel issues and both are intermittent, but real and regular.

This should get some Intel coverage, if not include the other fixes, before merge.

@resker

resker commented Jun 7, 2026

Copy link
Copy Markdown
Contributor Author

FYI, #5091 should improve the silent hang described

@AkihiroSuda AkihiroSuda added this to the v2.2.0 milestone Jun 8, 2026
@resker

resker commented Jun 10, 2026 •

Copy link
Copy Markdown
Contributor Author

loncharles — since you've Intel + FileVault setups running, could you give this a spin? I don't have Intel hw accessible.

EDIT: tagged the wrong person on these originally... removing the "@" to spare them further noise.

@resker

resker commented Jun 13, 2026 •

Copy link
Copy Markdown
Contributor Author

loncharles — thanks again for the detailed notes. I believe this PR should be scoped to the LaunchDaemon restart behavior, with the two issues you raised handled separately, since they're really independent of the self-healing change here:

EDIT: tagged the wrong person on these originally... removing the "@" to spare them further noise.

Comment thread .gitignore Outdated
default-template.yaml
schema-limayaml.json
.config
/limactl

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Irrelevant change

Comment thread cmd/limactl/start.go Outdated
// after an unclean shutdown (e.g. launchd SIGTERM before the host agent could stop the VM).
func isOrphanedDriverError(errs []error) bool {
for _, err := range errs {
if strings.Contains(err.Error(), "driver is running but host agent is not") {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use errors.Is or errors.As

Comment thread cmd/limactl/autostart_darwin.go Outdated
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
logrus.Debugf("running: sudo %v", args)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case of sudo, this should be explicitly printed

@AkihiroSuda

Copy link
Copy Markdown
Member

Note: this PR stacks on #5086 (keep-alive flag) which stacks on #4984 (LaunchDaemon support). The diff includes those commits as context; the new changes are the four commits on top. Target base will move to master once those merge.

Let me mark this PR as a draft

@AkihiroSuda
AkihiroSuda marked this pull request as draft June 13, 2026 16:08
@resker
resker force-pushed the feature/vz-shutdown-recovery branch from 017a37a to 3286232 Compare June 16, 2026 02:03
@resker

resker commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

@AkihiroSuda — addressed:

  • dropped the .gitignore change
  • recovery detection now matches sentinel errors in pkg/store (ErrDriverRunningHostAgentStopped, ErrHostAgentUnreachable) via errors.Is instead of string-matching
  • runSudo now logs at info level and notes it may prompt for a password

Also re-stacked on the updated #5086.

@resker

resker commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

@AkihiroSuda — I tested this directly. Two clarifications:

  1. launchd isn't restarting a separate host-agent process of its own — the LaunchDaemon just runs limactl start <instance> --foreground, and KeepAlive re-runs that same command. So "restarting the host agent" really just means "re-running limactl start", the normal start path.
  2. With vz the VM runs in-process in the host agent, so an unclean exit doesn't leave a separate VM process behind — the broken states this PR handles come from stale PID files after a reboot (a persisted PID that's since been reused by another process).

I reproduced both broken states on a test instance and confirmed limactl start recovers each one:

  • orphaned driver ("driver is running but host agent is not") → force-stops the orphan, then starts cleanly → Running.
  • stale host agent (ha.pid live but socket unreachable) → removes the stale files and starts cleanly → Running, without signaling the possibly-unrelated PID.

@resker
resker force-pushed the feature/vz-shutdown-recovery branch from 3286232 to 27f0abf Compare June 16, 2026 05:22
@resker
resker force-pushed the feature/vz-shutdown-recovery branch from 27f0abf to f14b343 Compare July 2, 2026 23:13
@AkihiroSuda AkihiroSuda modified the milestones: v2.2.0, v2.3.0 Jul 15, 2026
@AkihiroSuda
AkihiroSuda changed the base branch from master to release/0.20 July 18, 2026 22:36
@CFBancroft

Copy link
Copy Markdown

Intel Mac test result for Pull Request #5088

I am a regular Mac mini user, not a Lima developer. I performed this testing step-by-step with help from ChatGPT.

Test hardware

2018 Intel Mac mini (Macmini8,1)
Intel Core i7, 6-core 3.2 GHz
64 GB RAM
macOS Sequoia 15.7.9 (24G830)
Lima/Colima using Apple VZ
Lima VM architecture: x86_64
Separate Mac Studio used as the remote test/control machine

How the headless test was performed

This was intended to be a real unattended server test, not a GUI-login test.

I enabled Remote Login on the Intel Mac mini and then rebooted it while the Lima/Colima VM was running.

After reboot, I did not log into any macOS GUI account on the Intel Mac mini. The Mac mini remained at the macOS login screen.

From a separate Mac Studio, I attempted to access my Docker-hosted DokuWiki service on host port 5555. The connection was refused, showing that the container stack had not started.

I then connected from the Mac Studio to the Intel Mac mini using SSH, while the Intel Mac mini was still sitting at its macOS login screen.

All subsequent launchctl, Unified Log, filesystem, and Lima checks were performed through that SSH session. This allowed me to inspect the failed boot without first logging into the Mac mini GUI and changing the headless test conditions.

Build result: PASS

I built the current #5088 branch locally on the Intel Mac. The resulting limactl was a native x86_64 Mach-O executable.

Manual #5088 recovery test: PASS

Before the headless reboot test, I reproduced the broken/orphaned Lima state:

vz driver is running but host agent is not

Running the #5088 limactl start colima manually as my dedicated containerserver account successfully detected the orphaned state, cleaned stale state, restarted VZ, restored the Docker socket, and reached:

READY.

My DokuWiki container on port 5555 then became reachable again.

This confirms that the #5088 recovery logic itself worked on this Intel Mac.

Normal Intel VZ shutdown: PASS

For additional Intel testing, I added a temporary diagnostic to vz_driver_darwin.go to report CanRequestStop().

During a fresh normal start/stop cycle on this Intel Mac, the result was:

CFB Intel test: CanRequestStop=true

The VZ VM shut down normally.

Therefore, the normal Intel shutdown path does not reproduce the CanRequestStop=false condition involved in #5087/#5088.

Headless LaunchDaemon reboot test: BLOCKED before Lima executes

After the real reboot, while the Intel Mac mini remained at the login screen, SSH inspection from the Mac Studio showed that the system LaunchDaemon had attempted to run once and exited with:

last exit code = 78: EX_CONFIG

The macOS Unified Log showed:

Service could not initialize: posix_spawn(.../limactl), error 0xd - Permission denied

Importantly, this occurs before limactl itself starts, so the #5088 recovery code never gets an opportunity to execute during this boot test.

I reproduced the posix_spawn EACCES behavior using multiple executable locations, including:

the Homebrew Lima 2.2.0 binary
my locally built #5088/CFB test binary
a copy of that binary placed under /Users/Shared/Server

The same locally built binary executes successfully when invoked manually as the dedicated containerserver account.

I also unloaded and freshly reloaded the LaunchDaemon after changing the executable location. launchd correctly loaded the new /Users/Shared/Server executable path, but still failed with:

posix_spawn(/Users/Shared/Server/lima-cfb/limactl), error 0xd - Permission denied

Therefore, simply moving the executable does not resolve the LaunchDaemon problem.

Result

On this 2018 Intel Mac mini:

Building #5088 for x86_64: PASS
Running the #5088 build manually: PASS
#5088 recovery from the broken/orphaned VZ state: PASS
Normal Intel VZ shutdown (CanRequestStop=true): PASS
Real reboot with no GUI login: TESTED
Remote verification from a separate Mac Studio over SSH while the Intel Mac remained at the login screen: CONFIRMED
Automatic LaunchDaemon execution after reboot: BLOCKED by macOS posix_spawn EACCES

Therefore, I cannot honestly mark the complete unattended reboot test for #5088 as either PASS or FAIL. The Intel #5088 code works when executed, but my true headless boot test is currently blocked by a separate macOS LaunchDaemon execution problem that occurs before Lima starts.

For Akihiro Suda

I understand that you are in the Tokyo area and mentioned that you do not currently have access to an Intel Mac for testing.

Accessibility note: I am Deaf. I communicate through written English. I also use some Japanese Sign Language (JSL), but I do not use Japanese fingerspelling. If we meet in person, please communicate with me using written English.

I have a train pass between Fujisawa and Ueno on the JR Tokaido Line (Ueno-Tokyo Line), so I can meet you somewhere convenient along that line.

I can bring my 2018 Intel Mac mini, keyboard, mouse, and a very small monitor. We can meet at a café or another place with a power outlet. That way, you can test Lima directly on an actual Intel Mac.

Alternatively, if meeting is unnecessary, please give me the exact commands or test procedure you want me to run. I can run them on the Intel Mac mini and post the complete terminal output here.

@CFBancroft

Copy link
Copy Markdown

Additional Technical Details — Exact Intel Test Code and Commands

Follow-up to my previous Intel Mac test report above.

I realized that my previous post described the hardware, headless reboot/SSH test, results, and the LaunchDaemon failure, but I did not include the actual source-code modification and exact commands I used during the Intel testing.

I am adding those details here so the test can be reproduced and so it is clear exactly what I changed and what I observed.

Important: The source modification below is my local CFB Intel experiment on top of Pull Request #5088. It is not code from Pull Request #5088 itself. I made this modification only to observe the Intel VZ shutdown behavior and experiment with the SSH-failure path.

Local Intel diagnostic modification

In:

pkg/driver/vz/vz_driver_darwin.go

immediately after:

logrus.Info("Shutting down VZ")

I added:

logrus.Infof("CFB Intel test: CanRequestStop=%v", l.machine.CanRequestStop())

I also changed:

logrus.WithError(err).Warn("vz: SSH shutdown failed; VM process may require manual cleanup")
return nil

to:

logrus.WithError(err).Warn("vz: SSH shutdown failed; continuing to observe VM state")

The purpose of this second experimental change was to allow execution to continue into the existing 30-second VM-state polling loop rather than immediately returning when the SSH shutdown request failed.

My resulting local diff was:

@@ -501,6 +501,7 @@
func (l *LimaVzDriver) Stop(ctx context.Context) error {
logrus.Info("Shutting down VZ")

  •    logrus.Infof("CFB Intel test: CanRequestStop=%v", l.machine.CanRequestStop())
       if l.machine.CanRequestStop() {
    

...

  •                    logrus.WithError(err).Warn("vz: SSH shutdown failed; VM process may require manual cleanup")
    
  •                    return nil
    
  •                    logrus.WithError(err).Warn("vz: SSH shutdown failed; continuing to observe VM state")
    

Building on the Intel Mac

I built limactl directly on the 2018 Intel Mac mini:

make limactl

The build completed for:

GOARCH=amd64

and produced a native x86_64 limactl.

The locally built version reported:

limactl version 2.1.2-beta.0-633-g0ba123d4.m

I also built the x86_64 guest agent and templates:

make x86_64-guestagent templates

The guest-agent target produced a gzip-related Error 1, but the resulting compressed x86_64 guest-agent file existed:

_output/share/lima/lima-guestagent.Linux-x86_64.gz

I then ran:

make templates

which completed successfully and populated the required runtime templates.

Starting the existing VM with my modified Intel build

I started my existing Colima VM with the locally compiled binary:

sudo -u containerserver -H env
LIMA_HOME=/Users/containerserver/.colima/_lima
/Users/macmini-clainkawada/Developer/lima-5088/_output/bin/limactl start colima

The VM successfully started and ultimately reported:

READY.

Docker became available again and my DokuWiki container on host port 5555 was reachable.

Intel CanRequestStop() result

I then performed a fresh normal start/stop cycle using the modified build.

My diagnostic produced:

CFB Intel test: CanRequestStop=true

The VZ VM shut down normally.

This shows that on my 2018 Intel Mac mini, a normal VZ shutdown uses the CanRequestStop=true path. I therefore could not reproduce CanRequestStop=false simply by performing a normal Intel start/stop cycle.

Pull Request #5088 recovery test

Separately from my local diagnostic modification, I tested the #5088 recovery behavior.

The instance had reported:

vz driver is running but host agent is not

I started it using the #5088 test build:

sudo -u containerserver -H env
LIMA_HOME=/Users/containerserver/.colima/_lima
/usr/local/bin/limactl-5088-test start colima

The #5088 code detected the orphaned state and attempted recovery.

During that process, the attempt to send SIGKILL to the old VZ driver reported:

operation not permitted

However, recovery continued. Stale state including vz.pid was removed, VZ restarted, the Docker socket was restored, and Lima ultimately reported:

READY.

My DokuWiki service on port 5555 then became reachable again.

Therefore, manual #5088 broken/orphaned-state recovery worked on this Intel Mac despite the SIGKILL operation-not-permitted message.

Attempt to reproduce the abnormal state manually

I also experimented with killing only the host agent after obtaining its PID from ha.pid.

After sending SIGKILL to that host-agent process, this did not reproduce the original orphaned-VZ condition. The VZ process disappeared as well, and limactl list showed the instance as stopped.

Therefore, I do not count that experiment as evidence either for or against #5088.

Relationship to my previous report

These are the source-code and command details that I accidentally omitted from my previous comment.

My previous comment contains the separate real headless reboot test: the Intel Mac mini was rebooted and left at the macOS login screen, I tested the service from a separate Mac Studio, and then connected to the Intel Mac mini from the Mac Studio using SSH without logging into the Intel Mac GUI.

That test remains blocked by the separate macOS LaunchDaemon failure:

Service could not initialize: posix_spawn(.../limactl), error 0xd - Permission denied

Because that error occurs before limactl executes, I do not consider the headless LaunchDaemon result a failure of #5088 itself.

Summary of this follow-up:

#5088 builds natively on my 2018 Intel Mac: PASS
#5088 manual orphaned-state recovery on Intel: PASS
My diagnostic build runs on Intel: PASS
Normal Intel VZ shutdown: CanRequestStop=true
Deliberately killing the host agent did not reproduce the original orphaned state
Full headless reboot testing remains blocked before Lima executes by the separate macOS launchd posix_spawn EACCES issue

I apologize for not including these exact technical details in my first report. I wanted to add them rather than edit the original comment so that the testing history remains clear.

@resker

resker commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

@CFBancroft - A few questions:

  1. How did you create your LaunchDaemon? Was it w/ limactl autostart enable --condition=boot <instance>, or something put together manually? Lima's generated daemon plist sets UserName, so the job runs as that user rather than root — a hand-written one without it will behave quite differently.

  2. If it is running as user other than root, does this work?

    sudo -u containerserver /Users/Shared/Server/lima-cfb/limactl --version

  3. Could you post the output of the following (making sure it doesn't reveal anything sensitive / private beforehand)?

    sudo plutil -p /Library/LaunchDaemons/<the plist for your Lima job>.plist

@resker
resker force-pushed the feature/vz-shutdown-recovery branch from 0ba123d to b9d1e89 Compare September 5, 2026 23:27
@resker

resker commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor Author

Rebased onto latest master (clean, no conflicts) and pushed four commits addressing the Copilot review:

  • vz Stop — a failed SSH shutdown request returned nil, so the host agent exited 0 while the VM was likely still running, and KeepAlive{SuccessfulExit=false} would not restart it. It now falls through to the existing stop poll, as the CanRequestStop() branch already does.
  • ErrHostAgentUnreachable — was attached to every failure to reach the host agent, including a timeout and the startup race where ha.pid is written before the socket is bound. Now only on ECONNREFUSED, the one result proving nothing is listening. Other failures are still recorded and still leave the instance Broken; they're just not auto-recovered. (On Windows WSAECONNREFUSED isn't mapped to ECONNREFUSED by syscall.Errno.Is, so the sentinel never fires there — reported but not recovered, which is the safe direction.)
  • Stale-file cleanup — removed every .pid/.sock/.tmp in the instance dir, which could delete a live driver's PID file and let a second driver start. Now only ha.pid/ha.sock, plus the driver PID file when the driver runs in-process (vz) and records that same PID.
  • The two recovery paths now run in sequence rather than as alternatives, so a driver revealed by clearing the host agent is force-stopped on its own — and since that happens after ha.pid is gone, the force stop can't signal a PID that may have been reused.

Added unit tests for both: the socket cases drive the real host agent client against a unix socket rather than synthetic errors, and the cleanup cases cover in-process vs. separate driver.

@CFBancroft

Copy link
Copy Markdown

@resker Thank you. Here are the answers to your questions.

I powered on the 2018 Intel Mac mini again tonight (September 6). I left the Mac mini at the macOS login screen and did not log into a GUI account. I am currently accessing it remotely from my separate Mac Studio using SSH. This is the same headless arrangement I was trying to test previously.

  1. How was the LaunchDaemon created?

The LaunchDaemon I tested was created manually. I did not create it using:

limactl autostart enable --condition=boot

This may be an important distinction. My previous report should not be interpreted as a test of the LaunchDaemon generated by Lima's own autostart enable --condition=boot command.

I was trying to run the existing Colima/Lima VM under a dedicated macOS service account named containerserver, with no GUI login required.

  1. Can containerserver execute the test binary manually?

Yes.

I previously ran:

sudo -u containerserver /Users/Shared/Server/lima-cfb/limactl --version

and received:

limactl version 2.1.2-beta.0-633-g0ba123d4.m

The same locally built binary also successfully starts the existing Lima/Colima VM when I invoke it manually as containerserver with the appropriate LIMA_HOME.

Therefore, the containerserver account itself can execute this binary.

  1. Current LaunchDaemon plist

I ran the command you requested:

sudo plutil -p /Library/LaunchDaemons/io.lima-vm.daemon.colima.plist

Output:

{
"EnvironmentVariables" => {
"HOME" => "/Users/containerserver"
"LIMA_HOME" => "/Users/containerserver/.colima/_lima"
}
"Label" => "io.lima-vm.daemon.colima"
"ProcessType" => "Background"
"ProgramArguments" => [
0 => "/Users/Shared/Server/lima-cfb/limactl"
1 => "start"
2 => "colima"
3 => "--foreground"
]
"RunAtLoad" => 1
"StandardErrorPath" => "/var/log/colima-boot-error.log"
"StandardOutPath" => "/var/log/colima-boot.log"
"UserName" => "containerserver"
"WorkingDirectory" => "/Users/containerserver/.colima/_lima/colima"
}

This is the manually created plist that produced the posix_spawn(.../limactl), error 0xd - Permission denied behavior I reported earlier.

I also want to correct/clarify my previous report: because this plist was manually created, my LaunchDaemon failure does not demonstrate that Lima's own limactl autostart enable --condition=boot implementation has the same problem.

If you would like me to test the official Lima-generated boot autostart configuration instead, please give me the exact commands/procedure you want me to use. I will run them on this Intel Mac mini and report the complete output.

Likewise, I see that #5088 has changed since the 0ba123d build I tested. If you want me to rebuild and test the current #5088 head on this Intel Mac, please tell me which test sequence you would like me to run, and I will follow that sequence exactly.

@resker

resker commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

@CFBancroft — thanks, that clarifies things.

It also turned up a real gap, so thank you for that: limactl autostart enable generates a plist with no EnvironmentVariables, so LIMA_HOME isn't propagated and the job looks in ~/.lima at boot — which would never find a Colima instance under ~/.colima/_lima. Presumably why you hand-rolled the plist to begin with. Filed as #5488 with a draft fix in #5489 (credited you as reporter).

Independent of this PR, so nothing here changes.

If you're still curious about the EACCES on the manual plist, the one thing I didn't get was:

ls -lde / /Users /Users/Shared /Users/Shared/Server /Users/Shared/Server/lima-cfb

Since sudo -u containerserver ... --version works the mode bits look fine, so an ACL or a mount option is the likelier culprit.

@resker
resker force-pushed the feature/vz-shutdown-recovery branch from b9d1e89 to 2178d8b Compare September 7, 2026 16:45
@CFBancroft

Copy link
Copy Markdown

@resker Thanks. I ran the exact command you requested on the 2018 Intel Mac mini.

The Mac mini is still being accessed remotely from my Mac Studio over SSH.

$ ls -lde / /Users /Users/Shared /Users/Shared/Server /Users/Shared/Server/lima-cfb

drwxr-xr-x 22 root wheel 704 Aug 2 01:31 /
drwxr-xr-x 11 root admin 352 Aug 31 20:26 /Users
drwxrwxrwt 27 root wheel 864 Aug 31 23:06 /Users/Shared
drwxr-xr-x 4 root wheel 128 Sep 1 18:40 /Users/Shared/Server
drwxr-xr-x 3 root wheel 96 Sep 1 18:41 /Users/Shared/Server/lima-cfb

There were no additional ACL entries printed by ls -lde.

I have not changed any permissions, ACLs, mount settings, the LaunchDaemon, Lima, or Colima after running this command.

If you would like another check on this Intel Mac, please give me the exact command(s) and I will run them and post the output.

@resker

resker commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

@CFBancroft — that rules out the path then. I ought to point out that this thread isn't ideal for troubleshooting and isn't really topical to the PR at this point — it's not anything Lima is generating.

I'd suggest keeping an eye on #5488 / #5489 and adopting them if they merge. #5489 makes limactl autostart enable --condition=boot colima work with Colima's LIMA_HOME, which is what your hand-written plist is trying to do today — Lima generates the plist itself (with UserName and KeepAlive). #5088 here is the other half: recovery after an unclean shutdown.

@resker

resker commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

@AkihiroSuda — bumping this... since your review: a few Copilot findings were addressed & it's been rebased. CI indicates green — the one red is a cancelled release job. Most of the thread above is unrelated, but @CFBancroft also validated the recovery on an Intel Mac (I've only access to Apple Silicon based systems).

Anything further needed?

@AkihiroSuda AkihiroSuda left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please tidy up the commits (one commit for one topic)

Comment thread pkg/store/staleagent_test.go Outdated
// SPDX-FileCopyrightText: Copyright The Lima Authors
// SPDX-License-Identifier: Apache-2.0

//go:build !windows

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file should be named *_test_unix.go

@resker
resker force-pushed the feature/vz-shutdown-recovery branch from 2178d8b to 3608c8f Compare September 12, 2026 15:11
@resker

resker commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

@AkihiroSuda - thanks and I've collapsed everything to four commits, one per topic (each builds on its own):

  • fix(vz) (SSH shutdown fallback)
  • fix(store) (the recoverable-state sentinels)
  • fix(start) (the recovery itself)
  • docs(autostart).

But the contributing guide says commits are usually squashed to one before merge — please advise if that's what you meant.

Also renamed the test file to staleagent_unix_test.go, matching pkg/limayaml/defaults_unix_test.go. I read your *_test_unix.go as a typo for that — let me know if you meant something else.

Rebased on master and updated the description to match the new commits.

resker and others added 3 commits September 22, 2026 07:52
An unclean shutdown can leave an instance in one of two broken states that
`limactl start` is able to recover from. Give each a sentinel error so callers
can match it with `errors.Is` rather than comparing message strings:
`ErrDriverRunningHostAgentStopped` when the VM driver outlives the host agent,
and `ErrHostAgentUnreachable` when nothing is listening on the host agent socket.

The second is reported only on ECONNREFUSED, which is the one outcome that
proves the host agent recorded in ha.pid is gone. A timeout, a protocol error,
or a socket that does not exist yet may all come from a live host agent --
including one that has written its PID file but not yet bound its socket -- and
must not be recoverable: a caller acting on the sentinel would remove that
agent's files and start a second host agent for the same instance. Such failures
are still recorded and still leave the instance Broken.

On Windows the sockets layer reports WSAECONNREFUSED, which `syscall.Errno.Is`
does not map to `syscall.ECONNREFUSED`, so the sentinel never fires there. The
state is reported without being recovered from automatically, which is the safe
direction; the recovery exists for launchd-managed instances on macOS.

The tests drive the real host agent client against a unix socket, so they cover
the error chain that Inspect actually sees rather than synthetic values.

Part of lima-vm#5087.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Robert Esker <resker@gmail.com>
A host agent that dies without stopping the VM can leave an instance in one of two
broken states, and `limactl start` then refuses to start it until they are cleared
by hand. Recover from both instead:

- the VM driver is running with no host agent attached, which is force-stopped;
- nothing is listening on the host agent socket, whose files are removed without
  signaling any process, since the recorded PID may since belong to an unrelated
  one.

Only the host agent's own ha.pid and ha.sock are removed. A driver that runs as
its own process may still be alive, and deleting its PID file would hide it from
the next inspection and allow a second driver to be started for the same
instance; the exception is a driver that runs the VM inside the host agent
process, such as vz, which records the same PID and so is removed with them.

The two run in sequence rather than as alternatives, because clearing a departed
host agent can reveal a driver that is still running and has to be stopped on
its own. Doing that after ha.pid is gone also means the force stop cannot signal
a reused PID.

Two upstream changes have since narrowed how these states arise, without closing
them. e529ce0 makes `ReadPIDFile` ignore PID files written during a previous boot,
which covers PID reuse across a reboot. lima-vm#5436 removes `vz.pid` whenever the vz
driver stops, which covers the launchd SIGTERM path for vz. What is left:

- a driver that runs as its own process, such as qemu, outliving a host agent that
  died within the same boot. No reboot and no PID reuse are needed, and nothing
  stops that VM or clears its PID file;
- PID reuse within a single boot;
- instances whose directory carries no boot session marker, because they were
  started by an older version of Lima;
- platforms that expose no boot session ID (`osutil.ErrBootSessionNotSupported`),
  where PID files are handled as they were before the marker.

lima-vm#5436 fixed the first of the two bugs of lima-vm#5087; this is the rest of it.

Fixes lima-vm#5087.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Robert Esker <resker@gmail.com>
Describe the two broken states an instance can be left in when its host agent dies
without stopping the VM, when they are likely to occur, and what `limactl start`
does about each.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Robert Esker <resker@gmail.com>
@resker
resker force-pushed the feature/vz-shutdown-recovery branch from 3608c8f to 8449477 Compare September 22, 2026 13:55
@resker resker changed the title fix(vz): self-healing LaunchDaemon restart after unclean shutdown fix(start): recover from the broken states left by an unclean shutdown Sep 22, 2026
@resker

resker commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

@AkihiroSuda — rebased. #5436 landed yesterday and supersedes my fix(vz) commit, so I dropped it (thanks @ekalinin — yours also removes vz.pid on stop, mine didn't). Three left, still one per topic: fix(store), fix(start), docs(autostart). The docs commit lost its VZ shutdown section for the same reason.

This PR is still applicable even though #5436 and e529ce0 both narrow how these states arise. The description has been rewritten to cover what's left rather than lean on the launchd SIGTERM story those two now cover — mainly an out-of-process driver (qemu) outliving a host agent that died in the same boot, which needs neither a reboot nor PID reuse, and instances with no boot session marker because an older Lima started them. #5075 is that same state, reported independently.

This is on the v2.3.0 milestone and #5436 went in after beta.0, so please advise if anything further is needed to proceed.

  • These are one commit per topic, as requested. The contributing guide does say squash to one before merge — so happy to do that if preferred.

@resker

resker commented Sep 29, 2026

Copy link
Copy Markdown
Contributor Author

Hi @AkihiroSuda — bumping this again. Still green & still clean on master.

@AkihiroSuda
AkihiroSuda merged commit 573bada into lima-vm:master Sep 30, 2026
36 checks passed
@AkihiroSuda

Copy link
Copy Markdown
Member

thanks

@resker
resker deleted the feature/vz-shutdown-recovery branch September 30, 2026 14:47
ChengyuZhu6 added a commit to ChengyuZhu6/lima that referenced this pull request Oct 7, 2026
`limactl info` listed VM types with their location only, so there was no way to
ask what a driver supports. Anything that needed to know had to hardcode a list
of VM types, e.g. the `qemu | krunkit` whitelist in the snapshot bats test.

Add DriverFeatures.CanSnapshot and report each driver's features per VM type
under vmTypesEx. Internal drivers are queried directly; external drivers are
started in a temporary directory, queried, and stopped again, so no instance
is touched. Features are omitted when a driver cannot be queried, so a driver
that fails to start does not break the command.

Signed-off-by: ChengyuZhu6 <hudson@cyzhu.com>

Merge pull request #5508 from olamilekan000/5312-structured-snapshots

driver: return structured snapshot metadata
driver: return structured snapshot metadata

Signed-off-by: olamilekan000 <odukoyaonline@gmail.com>

Merge pull request #5575 from lima-vm/dependabot/go_modules/github.com/foxcpp/go-mockdns-1.3.0

build(deps): bump github.com/foxcpp/go-mockdns from 1.2.0 to 1.3.0
Merge pull request #5576 from lima-vm/dependabot/go_modules/github.com/pb33f/ordered-map/v2-2.3.2

build(deps): bump github.com/pb33f/ordered-map/v2 from 2.3.1 to 2.3.2
Merge pull request #5577 from lima-vm/dependabot/go_modules/github.com/klauspost/compress-1.20.1

build(deps): bump github.com/klauspost/compress from 1.18.5 to 1.20.1
build(deps): bump github.com/klauspost/compress from 1.18.5 to 1.20.1

Bumps [github.com/klauspost/compress](https://github.com/klauspost/compress) from 1.18.5 to 1.20.1.
- [Release notes](https://github.com/klauspost/compress/releases)
- [Commits](https://github.com/klauspost/compress/compare/v1.18.5...v1.20.1)

---
updated-dependencies:
- dependency-name: github.com/klauspost/compress
  dependency-version: 1.20.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
build(deps): bump github.com/pb33f/ordered-map/v2 from 2.3.1 to 2.3.2

Bumps [github.com/pb33f/ordered-map/v2](https://github.com/pb33f/ordered-map) from 2.3.1 to 2.3.2.
- [Changelog](https://github.com/pb33f/ordered-map/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pb33f/ordered-map/compare/v2.3.1...v2.3.2)

---
updated-dependencies:
- dependency-name: github.com/pb33f/ordered-map/v2
  dependency-version: 2.3.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
build(deps): bump github.com/foxcpp/go-mockdns from 1.2.0 to 1.3.0

Bumps [github.com/foxcpp/go-mockdns](https://github.com/foxcpp/go-mockdns) from 1.2.0 to 1.3.0.
- [Release notes](https://github.com/foxcpp/go-mockdns/releases)
- [Commits](https://github.com/foxcpp/go-mockdns/compare/v1.2.0...v1.3.0)

---
updated-dependencies:
- dependency-name: github.com/foxcpp/go-mockdns
  dependency-version: 1.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Merge pull request #5559 from Sarthak-Shreshtha01/fix/issue-5552

templates/k8s: accept an https:// url when joining a node
Merge pull request #5460 from bcollard/fix/additional-disks-label-truncation

Do not identify additional disks by filesystem label
Do not identify additional disks by filesystem label

An `additionalDisks` entry whose name did not fit in the filesystem label
was reformatted on every boot, silently destroying its contents.

`mkfs.ext4` silently truncates the label to 16 bytes, so a name longer
than 11 characters produced a label that could never match the
`/dev/disk/by-label/lima-${DISK_NAME}` node the first-time-setup guard
tested for. The guard was true on every boot and `mkfs` ran again. The
disk still mounted, because the mount uses the device path, so nothing
appeared to be wrong. (`mkfs.xfs` instead rejects a label over 12 bytes,
so an xfs disk with a name over 7 characters was never formatted at all.)

Identify the disk by the presence of a filesystem on its partition
instead: the guard tests whether `blkid -o value -s TYPE` prints anything.
It tests the output rather than the exit status, because util-linux blkid
exits 0 for a bare GPT partition-table entry that has no filesystem yet,
and BusyBox blkid (Alpine) ignores -o and -s and always exits 0. This
removes the length limit and, because a disk formatted by an older Lima
version also carries a filesystem, such disks are recognised rather than
reformatted on upgrade. A partition left without a filesystem by an
interrupted boot or a failed mkfs is formatted on the next boot. The
guard fails closed: if blkid is missing or reports an error, the disk is
left alone, so a disk whose state cannot be determined is never
reformatted.

The labels are kept as a convenience and clamped to what each filesystem
accepts, so that `mkfs.xfs` no longer aborts the boot. A GPT partition
label, which holds 36 characters, now carries the name as well. For an
fsType not listed here, the limit (and even whether mkfs.$FORMAT_FSTYPE
accepts a label at all) is unknown, so no label is set rather than guess
and risk aborting boot. The label is passed without a bash array, since
on Alpine /bin/bash is BusyBox ash, which has none.

Over-long names are reported at info level rather than as an error: the
disk works correctly now that identification does not depend on the
label. The notice is limited to Linux guests and disks Lima formats, the
only case in which a label is written. The `additionalDisks` comment in
the default template now points at the partition label, which keeps
names of up to 31 characters whole.

The disk-mount test regression check used a plain substring match, which
the new long-named disk's mount point ("/mnt/lima-data-with-a-long-name")
also satisfies, silently defeating the original disk's assertion. Anchor
the pattern to end-of-line.

Fixes #5407

Assisted-by: Claude Code
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Baptiste Collard <9626829+bcollard@users.noreply.github.com>

Merge pull request #5514 from lima-vm/fix/5466

driver(hcs): drop dependency on `qemu-img` for VHDX image conversion
templates/k8s: accept an https:// url when joining a node

The documentation and the k3s template pass the control plane as a
URL ("https://<ADDRESS>:6443"), but the k8s template put the url
param into apiServerEndpoint unchanged, and kubeadm expects a bare
host:port there, so the documented command did not work.

Strip the https:// prefix in the template, so both forms work, and
make the template comment and the BATS test use the URL form.

Fixes #5552

Signed-off-by: Sarthak <sarthakshreshtha345@gmail.com>

driver(hcs): drop dependency on qemu-img

Signed-off-by: unsuman <anshumansahoo500@gmail.com>

Merge pull request #5480 from SABITHSAHEB/apfs-gpt-header-bounds

apfs: bound GPT partition entry size and count before use
Merge pull request #5560 from jandubois/wsl2-no-distributions

wsl2: handle a host with no WSL distributions
Merge pull request #5558 from aka-rider/portfwd-current-client

portfwd: dial through the current guest agent client, not the (poissibly stale one) captured at listen time
Merge pull request #5563 from kolyshkin/fix-rawhide-url

limactl-url-fedora-rawhide: don't rely on COMPOSE_ID
Merge pull request #5562 from AkihiroSuda/dev

templates: update
limactl-url-fedora-rawhide: don't rely on COMPOSE_ID

The rawhide/COMPOSE_ID file on dl.fedoraproject.org is sometimes out of
sync with the contents of the images directory. For example, currently
COMPOSE_ID says Fedora-Rawhide-20260929.n.0, while the only image
available is Fedora-Cloud-Base-Generic-Rawhide-20261002.n.0, so
starting an instance from experimental/fedora-rawhide fails with:

	failed to download `https://dl.fedoraproject.org/pub/fedora/linux/development/rawhide/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-Rawhide-20260929.n.0.x86_64.qcow2`: unexpected HTTP status Not Found

Instead, get the image file name from the CHECKSUM file in the images
directory, which describes the images actually present there. As a
bonus, this also gives us the image digest.

While at it, add --retry to curl invocations.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>

Merge pull request #5561 from AkihiroSuda/nerdctl

nerdctl: update from v2.4.0 to v2.4.1
templates: update

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>

Merge pull request #5405 from SABITHSAHEB/wsl2-ssh-address-validate

wsl2: validate guest-reported address in getSSHAddress
nerdctl: update from v2.4.0 to v2.4.1

https://github.com/containerd/nerdctl/releases/tag/v2.4.1

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>

CI: drop the dummy WSL2 distro

CI imported an empty distro because the WSL2 driver failed when WSL had
no distributions. The driver handles that case now, so CI can test it by
running the WSL2 jobs with no distributions installed.

Signed-off-by: Jan Dubois <jan.dubois@suse.com>

Driver: WSL2: Better handle no distributions

This fixes the case where WSL is installed, but no distributions are
installed at all.  In that case, newer versions of WSL no longer prints the
error code `Wsl/WSL_E_DEFAULT_DISTRO_NOT_FOUND` (or indeed, any error code
at all).

Instead of trying to parse error messages, use the WSL API to check if the
distribution exists.  However, the API is very limited and does not allow
us to check the state of the distribution in the case it _does_ exist, so
we still need to parse the text for that.

If WSL is not installed, using the WSL API causes a command prompt window
to appear with a prompt to install WSL.  To avoid showing that, try to
detect whether WSL is installed by opening its registry key.

Signed-off-by: Mark Yen <mark.yen@suse.com>
Signed-off-by: Jan Dubois <jan.dubois@suse.com>

Merge pull request #5342 from jandubois/ci-plain-windows-jobs

CI: factor Windows setup into composite actions; add plain-Windows jobs
Merge pull request #5198 from ekalinin/feat-4065-disk-mountpoint

additionalDisks: support custom mountPoint and optional mounting
Merge pull request #5556 from lima-vm/dependabot/go_modules/hack/tools/github.com/golangci/golangci-lint/v2-2.14.0

build(deps): bump github.com/golangci/golangci-lint/v2 from 2.13.2 to 2.14.0 in /hack/tools
additionalDisks: support custom mountPoint and optional mounting

Additional disks were always mounted at the hardcoded path
/mnt/lima-<name>, with no way to change that location or to attach a disk
without Lima mounting it. Issue #4065 asks for both: a custom mount point
and an attach-only mode so the guest can manage the disk itself (a
flexibility Colima can benefit from).

Add two optional, backwards-compatible fields to each additionalDisks
entry:
- mountPoint: absolute guest path to mount at (default /mnt/lima-<name>)
- mount: whether Lima auto-mounts the disk (default true; false attaches
  the disk without mounting it)

A separate `mount` boolean is used rather than overloading an empty
mountPoint, per the discussion in #4065. nil for either field preserves
the current behavior. Values are passed to the guest via
LIMA_CIDATA_DISK_<i>_MOUNT / _MOUNTPOINT and honored by 05-lima-disks.sh
(non-swap disks only). mountPoint is validated to be an absolute guest
path (path.IsAbs, not the host-dependent filepath.IsAbs) and neither a
critical system path nor the reserved guest home directory.

Fixes #4065

Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>

portfwd: dial through the current guest agent client, not the one captured at listen time

processGuestAgentEvents built one dialer per event stream and the
listeners kept it for their whole lifetime. When the guest agent was
unreachable at the 10 s check, getOrCreateClient closed that client
and opened a new one, so every accepted host connection failed with
"grpc: the client connection is closing". Resolve the client per dial.

Signed-off-by: Iurii Krasnoshchok <github@iurii.net>
Assisted-by: Claude Code

build(deps): bump github.com/golangci/golangci-lint/v2 in /hack/tools

Bumps [github.com/golangci/golangci-lint/v2](https://github.com/golangci/golangci-lint) from 2.13.2 to 2.14.0.
- [Release notes](https://github.com/golangci/golangci-lint/releases)
- [Changelog](https://github.com/golangci/golangci-lint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/golangci/golangci-lint/compare/v2.13.2...v2.14.0)

---
updated-dependencies:
- dependency-name: github.com/golangci/golangci-lint/v2
  dependency-version: 2.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>

autostart: export AutoStartManager interface

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>

Merge pull request #5399 from mvanhorn/fix/5389-disable-llmnr-login-delay

fix: Disable LLMNR to prevent Debian SSH login delay
Merge pull request #5546 from Sarthak-Shreshtha01/fix/issue-5545

guestagent: close the gRPC connection when a write fails
Merge pull request #5528 from trodemaster/feat/vz-guest-os-version-log

feat(vz): record the guest macOS version from the restore image
CI: factor Windows setup into composite actions; add plain-Windows jobs

Lima should run on a Windows host whose only ssh is the native OpenSSH
client, but the existing Windows jobs run with Git for Windows and MSYS2
installed, so a new dependency on their tools would go unnoticed. The
plain-Windows jobs remove both toolchains before testing.

The MSYS2 jobs got a Cygwin ssh from Git for Windows through
_LIMA_WINDOWS_EXTRA_PATH and now install MSYS2's openssh instead. That
was the experimental variable's last use in the repo, so remove it.

The MSYS2 jobs also install rsync, so the integration tests cover the
rsync copy backend on Windows. Because MSYS2 setup now runs before the
unit tests and make, the unit tests that skip without rsync run on
Windows too.

The WSL2 job's id changes from windows to windows-wsl2.

Signed-off-by: Jan Dubois <jan.dubois@suse.com>

copytool: expect converted paths in TestRsyncCommandPaths on Windows

On Windows, Command converts each local path for the rsync it runs,
because a Cygwin or MSYS rsync reads "C:" as a host. The test still
expected the paths as given, but no Windows CI job had rsync on
PATH when the unit tests ran, so it always skipped there.

Convert the expected paths the same way.

Signed-off-by: Jan Dubois <jan.dubois@suse.com>

Merge pull request #5554 from somaz94/krunkit-lock-for-instance

krunkit: auto-unlock disk locked to the same instance on startup
Merge pull request #5555 from lima-vm/fix/5551

CI: tolerate systemd-binfmt failure on wsl2
Merge pull request #5553 from lima-vm/dependabot/github_actions/codeql-action-9d88a12d2b

build(deps): bump the codeql-action group with 3 updates
Merge pull request #5299 from jandubois/copytool-native-windows-openssh

copytool: support native Windows OpenSSH
CI: tolerate systemd-binfmt failure on wsl2

WSL 3.0.1 mounts /proc/sys/fs/binfmt_misc read-only, so systemd-binfmt
cannot flush its rules and exits 1. That leaves the guest "degraded" and
fails the systemd check even though the instance is fully functional.

The behaviour is host-side and reproduces with any rootfs, so add the
unit to the set of failures lima does not control, scoped to vmType wsl2.

Fixes #5551

Signed-off-by: unsuman <anshumansahoo500@gmail.com>

guestagent: close the gRPC connection when a write fails

If the gRPC server fails to write, it stops sending but keeps reading.
The connection then stays half-open: requests reach the guest, but no
response ever comes back, and the host agent never reconnects.

Close the connection on the first write error, so that the read side
fails too and the host agent reconnects.

Fixes #5545

Signed-off-by: Sarthak <sarthakshreshtha345@gmail.com>

krunkit: auto-unlock disk locked to the same instance on startup

Signed-off-by: somaz <genius5711@gmail.com>

build(deps): bump the codeql-action group with 3 updates

Bumps the codeql-action group with 3 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action).

Updates `github/codeql-action/init` from 4.38.1 to 4.38.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/1c5b675653bb5c22dbe9b12b556ec555138e09fd...2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2)

Updates `github/codeql-action/analyze` from 4.38.1 to 4.38.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/1c5b675653bb5c22dbe9b12b556ec555138e09fd...2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2)

Updates `github/codeql-action/upload-sarif` from 4.38.1 to 4.38.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/1c5b675653bb5c22dbe9b12b556ec555138e09fd...2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.38.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.38.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.38.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <support@github.com>
Merge pull request #5548 from jandubois/lint-quick-exclude-deepwiki

CI: lint-quick: ignore deepwiki.com 429
CI: lint-quick: ignore deepwiki.com 429

deepwiki.com now answers non-browser clients with a Vercel bot
challenge that returns 429, so the README's DeepWiki badge has failed
every lint-quick run since 2026-09-28. GitHub's image proxy still
fetches the badge, so readers see it.

Signed-off-by: Jan Dubois <jan.dubois@suse.com>

Merge pull request #5088 from resker/feature/vz-shutdown-recovery

fix(start): recover from the broken states left by an unclean shutdown
Merge pull request #5117 from pirate/secure-vz-block-devices

Secure macOS VZ block-device attachment
Merge pull request #5538 from lima-vm/dependabot/github_actions/codeql-action-97c20ee9f3

build(deps): bump the codeql-action group across 1 directory with 3 updates
build(deps): bump the codeql-action group across 1 directory with 3 updates

Bumps the codeql-action group with 3 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action).

Updates `github/codeql-action/init` from 4.38.0 to 4.38.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/b96794f015dfd88f77b49b1c93e0fa7110f94c63...1c5b675653bb5c22dbe9b12b556ec555138e09fd)

Updates `github/codeql-action/analyze` from 4.38.0 to 4.38.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/b96794f015dfd88f77b49b1c93e0fa7110f94c63...1c5b675653bb5c22dbe9b12b556ec555138e09fd)

Updates `github/codeql-action/upload-sarif` from 4.38.0 to 4.38.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/b96794f015dfd88f77b49b1c93e0fa7110f94c63...1c5b675653bb5c22dbe9b12b556ec555138e09fd)

---
updated-dependencies:
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.38.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/init
  dependency-version: 4.38.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.38.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <support@github.com>
Merge pull request #5544 from unsuman/fix-5511

driver(qemu): disable the TPM PPI on HVF with QEMU >= 11.0
Merge pull request #5542 from unsuman/fix-lima-social-link

fix(docs): replace broken Twitter/X URL in README
driver(qemu): disable the TPM PPI on HVF with QEMU >= 11.0

Signed-off-by: Ansuman Sahoo <anshumansahoo500@gmail.com>

wsl2: validate guest-reported address in getSSHAddress

getSSHAddress reads the instance address from commands run inside the
guest; only the fallback probe checked that the output was an IP, the
first two returned it verbatim. The pipeline in the first probe exits 0
even when hostname does not support -I, so its usage text could become
inst.SSHAddress and end up on the ssh/scp/rsync command line instead of
falling through to the next probe.

Route all three probes through one helper that accepts only global
unicast addresses (private and ULA ranges included), so unspecified,
loopback, link-local and multicast values fall through the same way
127.0.1.1 already did in the fallback.

Signed-off-by: Sabith Saheb <shabi7204192361@gmail.com>

fix: disable LLMNR to prevent Debian SSH login delay

systemd-resolved's LLMNR probe adds a multi-second delay to SSH logins on
Debian. Debian 13's sshd passes an UNKNOWN peer address for vsock connections
to Linux audit, which resolves it via LLMNR; that lookup is the delay.

Set LLMNR=no, gated behind the internal_disableLLMNR param so only the
Debian 13 image template opts in, mirroring the Ubuntu 26.04 workaround
pattern. Other distros keep LLMNR untouched.

Compare the param against the literal "true" rather than testing it for
non-emptiness, so setting it to "false" does not still emit LLMNR=no.
template_test covers "", "false" and "true", so reverting the template
alone fails that subtest.

Record in the debian-13 template why the workaround exists, with the
upstream OpenSSH commit that removes the need for it and the Debian bug
report tracking it downstream.

Fixes #5389

Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>

fix broken X link in README

Signed-off-by: Ansuman Sahoo <anshumansahoo500@gmail.com>

Merge pull request #5537 from lima-vm/dependabot/go_modules/hack/tools/google.golang.org/grpc-1.84.0

build(deps): bump google.golang.org/grpc from 1.83.2 to 1.84.0 in /hack/tools
build(deps): bump google.golang.org/grpc in /hack/tools

Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.83.2 to 1.84.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.83.2...v1.84.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-version: 1.84.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Support secure host block-device attachment on macOS VZ

Attach explicitly allowed host disks through a dedicated root-owned helper,
passing validated file descriptors to unprivileged VZ over an authenticated
Unix socket. Scope sudoers grants to the invoking user and exact device paths,
reject unsafe helper paths and socket symlinks, authenticate both peers, and
validate the received device identity.

Retain descriptors per VM while preserving process-lifetime network wrappers
used by krunkit. Lock whole host disks across instances sharing LIMA_HOME,
including raw/block aliases and partitions. Reject duplicate configuration
entries and external VZ drivers at runtime.

Compose network and block-device sudoers fragments through pkg/sudoers, match
complete generated lines, and warn when regeneration removes existing grants.
Keep integration-test grants in temporary fragments and revoke them before
detaching the test RAM disk. Add security, lifecycle, and real-disk regression
coverage and document installation requirements and remaining grant limits.

Signed-off-by: Nick Sweeting <git@sweeting.me>

feat(vz): record the guest macOS version from the restore image

When creating a macOS guest, the vz driver loads the IPSW as a
VZMacOSRestoreImage and reads only the hardware model from it, then
removes the IPSW after installation. The image also carries the OS
version and build number, which are otherwise lost at that point.

Log both and persist them next to vz-hwmodel as vz-guest-os-version and
vz-guest-os-build-version, written once when the hardware model is
extracted. store.ReadGuestOSVersion reads them back (empty when unknown,
e.g. for instances created before this change), so that host-side steps
such as disk patching and cidata generation can select behavior by guest
macOS version. For macOS guests, cidata also exposes the values to
provisioning scripts as LIMA_CIDATA_GUEST_OS_VERSION and
LIMA_CIDATA_GUEST_OS_BUILD_VERSION, emitted empty when unknown like the
other optional LIMA_CIDATA_* variables.

The values describe the restore image, i.e. the guest at first boot;
they do not track later OS updates.

Signed-off-by: Blake Garner <blake@netjibbing.com>

docs(autostart): document unclean shutdown recovery

Describe the two broken states an instance can be left in when its host agent dies
without stopping the VM, when they are likely to occur, and what `limactl start`
does about each.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Robert Esker <resker@gmail.com>

fix(start): recover from the broken states left by an unclean shutdown

A host agent that dies without stopping the VM can leave an instance in one of two
broken states, and `limactl start` then refuses to start it until they are cleared
by hand. Recover from both instead:

- the VM driver is running with no host agent attached, which is force-stopped;
- nothing is listening on the host agent socket, whose files are removed without
  signaling any process, since the recorded PID may since belong to an unrelated
  one.

Only the host agent's own ha.pid and ha.sock are removed. A driver that runs as
its own process may still be alive, and deleting its PID file would hide it from
the next inspection and allow a second driver to be started for the same
instance; the exception is a driver that runs the VM inside the host agent
process, such as vz, which records the same PID and so is removed with them.

The two run in sequence rather than as alternatives, because clearing a departed
host agent can reveal a driver that is still running and has to be stopped on
its own. Doing that after ha.pid is gone also means the force stop cannot signal
a reused PID.

Two upstream changes have since narrowed how these states arise, without closing
them. e529ce08 makes `ReadPIDFile` ignore PID files written during a previous boot,
which covers PID reuse across a reboot. #5436 removes `vz.pid` whenever the vz
driver stops, which covers the launchd SIGTERM path for vz. What is left:

- a driver that runs as its own process, such as qemu, outliving a host agent that
  died within the same boot. No reboot and no PID reuse are needed, and nothing
  stops that VM or clears its PID file;
- PID reuse within a single boot;
- instances whose directory carries no boot session marker, because they were
  started by an older version of Lima;
- platforms that expose no boot session ID (`osutil.ErrBootSessionNotSupported`),
  where PID files are handled as they were before the marker.

#5436 fixed the first of the two bugs of #5087; this is the rest of it.

Fixes #5087.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Robert Esker <resker@gmail.com>

fix(store): name the recoverable broken states, and only when provable

An unclean shutdown can leave an instance in one of two broken states that
`limactl start` is able to recover from. Give each a sentinel error so callers
can match it with `errors.Is` rather than comparing message strings:
`ErrDriverRunningHostAgentStopped` when the VM driver outlives the host agent,
and `ErrHostAgentUnreachable` when nothing is listening on the host agent socket.

The second is reported only on ECONNREFUSED, which is the one outcome that
proves the host agent recorded in ha.pid is gone. A timeout, a protocol error,
or a socket that does not exist yet may all come from a live host agent --
including one that has written its PID file but not yet bound its socket -- and
must not be recoverable: a caller acting on the sentinel would remove that
agent's files and start a second host agent for the same instance. Such failures
are still recorded and still leave the instance Broken.

On Windows the sockets layer reports WSAECONNREFUSED, which `syscall.Errno.Is`
does not map to `syscall.ECONNREFUSED`, so the sentinel never fires there. The
state is reported without being recovered from automatically, which is the safe
direction; the recovery exists for launchd-managed instances on macOS.

The tests drive the real host agent client against a unix socket, so they cover
the error chain that Inspect actually sees rather than synthetic values.

Part of #5087.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Robert Esker <resker@gmail.com>

Merge pull request #5527 from lima-vm/dependabot/go_modules/github.com/lima-vm/go-qcow2reader-0.8.0

build(deps): bump github.com/lima-vm/go-qcow2reader from 0.7.1 to 0.8.0
build(deps): bump github.com/lima-vm/go-qcow2reader from 0.7.1 to 0.8.0

Bumps [github.com/lima-vm/go-qcow2reader](https://github.com/lima-vm/go-qcow2reader) from 0.7.1 to 0.8.0.
- [Release notes](https://github.com/lima-vm/go-qcow2reader/releases)
- [Commits](https://github.com/lima-vm/go-qcow2reader/compare/v0.7.1...v0.8.0)

---
updated-dependencies:
- dependency-name: github.com/lima-vm/go-qcow2reader
  dependency-version: 0.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Merge pull request #5523 from jandubois/fix-readpidfile

store/instance: Fix finding process by pid file
Merge pull request #5436 from ekalinin/fix/vz-clean-shutdown

fix(vz): stop the VM even when CanRequestStop is false
Merge pull request #5525 from lima-vm/dependabot/go_modules/hack/tools/github.com/AkihiroSuda/gosocialcheck-0.2.0

build(deps): bump github.com/AkihiroSuda/gosocialcheck from 0.1.3 to 0.2.0 in /hack/tools
Merge pull request #5524 from lima-vm/dependabot/go_modules/github.com/mattn/go-shellwords-1.0.15

build(deps): bump github.com/mattn/go-shellwords from 1.0.14 to 1.0.15
build(deps): bump github.com/AkihiroSuda/gosocialcheck in /hack/tools

Bumps [github.com/AkihiroSuda/gosocialcheck](https://github.com/AkihiroSuda/gosocialcheck) from 0.1.3 to 0.2.0.
- [Release notes](https://github.com/AkihiroSuda/gosocialcheck/releases)
- [Commits](https://github.com/AkihiroSuda/gosocialcheck/compare/v0.1.3...v0.2.0)

---
updated-dependencies:
- dependency-name: github.com/AkihiroSuda/gosocialcheck
  dependency-version: 0.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
build(deps): bump github.com/mattn/go-shellwords from 1.0.14 to 1.0.15

Bumps [github.com/mattn/go-shellwords](https://github.com/mattn/go-shellwords) from 1.0.14 to 1.0.15.
- [Release notes](https://github.com/mattn/go-shellwords/releases)
- [Commits](https://github.com/mattn/go-shellwords/compare/v1.0.14...v1.0.15)

---
updated-dependencies:
- dependency-name: github.com/mattn/go-shellwords
  dependency-version: 1.0.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
store/instance: Fix finding process by pid file

On Windows, `os.FindProcess()` returns an error if the pid given does not
correspond to a valid process; this is unlike *nix, where it succeeds, and
the caller must attempt to send a signal to the target process to know if
it is still alive.  Catch that error on Windows and return no error to
match the other cases.

The underlying Win32 call `OpenProcess` returns ERROR_INVALID_PARAMETER on
either invalid pid (e.g. 0), as well as valid pids that do not exist.  So
we can only catch that generic case and swallow the error.

Signed-off-by: Mark Yen <mark.yen@suse.com>
(cherry picked from commit 8a338c8cf5c1ca598cc8a0abe1f5300a2f5c4569)

Merge pull request #5509 from AkihiroSuda/nerdctl

nerdctl: update from v2.3.5 to v2.4.0
nerdctl: update from v2.3.5 to v2.4.0

https://github.com/containerd/nerdctl/releases/tag/v2.4.0

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>

copytool: support native Windows OpenSSH

On Windows, `limactl copy` converted host paths to the Cygwin/MSYS form
no matter which tool would consume them, and it passed ControlMaster
options unconditionally. Native OpenSSH cannot use that path form and
has no multiplexing, so scp failed with "getsockname failed".

The two backends need different path forms. scp takes whatever its own
toolchain uses, while rsync on Windows is always Cygwin-based and reads
a drive letter as a hostspec. So every path now takes the form of the
binary that reads it, operands and ssh options alike, because scp hands
its options to the ssh beside itself while rsync hands them to the ssh
it names.

Both backends now skip multiplexing on Windows, so they stop building
a control socket path they never use.

Signed-off-by: Jan Dubois <jan.dubois@suse.com>

Merge pull request #5503 from AkihiroSuda/macos-27

templates: add macos-27 (Golden Gate)
Merge pull request #5337 from jandubois/copytool-parse-error

copytool: report a bad path instead of a missing tool
Merge pull request #5341 from jandubois/docs-plain-windows-wsl2

docs: document the Windows host SSH toolchain
docs: clarify that macOS guests need the host macOS to be newer

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>

templates: add macos-27 (Golden Gate)

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>

hack: accept IPSW URLs without the "fullrestores" path component

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>

docs: document $SSH and correct the Windows SSH notes

The $SSH environment variable replaces the ssh command Lima runs, and
the environment variables page had no entry for it. Describe it.

The QEMU page said nothing about the Windows host's ssh binaries, and
the WSL2 page claimed Windows ships no ssh.exe.

These pages describe the state after the copytool work lands, so merge
this commit after it.

Signed-off-by: Jan Dubois <jan.dubois@suse.com>

copytool: report a bad path instead of a missing tool

A path naming an instance that does not exist reached the user as
"neither rsync nor scp found on host", because the auto backend
discarded the parse error, skipped rsync, and reported whatever the scp
fallback said. Only a host without scp saw that message; everywhere else
the auto backend built the copy tool without complaint and the real
error surfaced later, from the copy command itself. The explicit rsync
backend reduced the same error to "rsync not available on guest(s)".

The fallback message no longer guesses which tool is missing, since
rsync may well have been found and rejected for another reason.

Signed-off-by: Jan Dubois <jan.dubois@suse.com>

Merge pull request #5512 from AkihiroSuda/fix-5510

hack/tools: go mod tidy
hack/tools: go mod tidy

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>

Merge pull request #5220 from afbjorklund/sbom

Add SBOM artifact using cyclonedx-gomod
Merge pull request #5484 from unsuman/net/pr2-lima-net-daemon

networks: add the `lima-privileged-net` daemon and tap device naming
networks: add the lima-privileged-net daemon and tap device naming

Generalize the daemon handling in pkg/networks, which so far assumed that
socket_vmnet is the only privileged helper, and describe the Linux helper
(lima-privileged-net) next to it:

- RequiredDaemons() returns the helpers needed on the current host, so the
  callers no longer have to hardcode socket_vmnet.
- paths.limaPrivilegedNet holds the path of the Linux helper, mirroring
  paths.socketVMNet.
- StartCmd() renders the lima-privileged-net command line, and TapCmd() the
  command that attaches an instance to the bridge of a network.
- TapName() derives a tap device name that fits into IFNAMSIZ, and
  TapNamePattern() renders the matching sudoers wildcard. IsTapName() and
  IsManagedBridge(), which recognize the names TapName() and BridgeName()
  generate, were added alongside the helper itself in the previous commit.
- DigestSpec() hashes a daemon binary so that the sudoers rules generated by
  the next commit can pin it with a sudo `Digest_Spec`.

Signed-off-by: Ansuman Sahoo <anshumansahoo500@gmail.com>

Merge pull request #5375 from jandubois/apparmor-allow-lima-mount-points

cidata: allow apparmor mounts on every Lima mount point
Merge pull request #5501 from AkihiroSuda/fix-5500

copytool: make `copy -r` into an existing directory consistent across backends
copytool: make `copy -r` into an existing directory consistent across backends

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>

Merge pull request #5506 from lima-vm/dependabot/github_actions/codeql-action-8213001b74

build(deps): bump the codeql-action group with 3 updates
Merge pull request #5505 from lima-vm/dependabot/go_modules/golang-x-7af35257a6

build(deps): bump the golang-x group across 1 directory with 3 updates
Merge pull request #5507 from lima-vm/dependabot/github_actions/zizmorcore/zizmor-action-0.6.4

build(deps): bump zizmorcore/zizmor-action from 0.6.3 to 0.6.4
build(deps): bump zizmorcore/zizmor-action from 0.6.3 to 0.6.4

Bumps [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) from 0.6.3 to 0.6.4.
- [Release notes](https://github.com/zizmorcore/zizmor-action/releases)
- [Commits](https://github.com/zizmorcore/zizmor-action/compare/70fb788f84895a7701f5643d103d587e460b5c99...cc914d7f3750a2d13d75c7f184a1060aa0e9d482)

---
updated-dependencies:
- dependency-name: zizmorcore/zizmor-action
  dependency-version: 0.6.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
build(deps): bump the codeql-action group with 3 updates

Bumps the codeql-action group with 3 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action).

Updates `github/codeql-action/init` from 4.37.9 to 4.38.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/cdf488f595d80d6e07e03d4674febd5ab45fa938...b96794f015dfd88f77b49b1c93e0fa7110f94c63)

Updates `github/codeql-action/analyze` from 4.37.9 to 4.38.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/cdf488f595d80d6e07e03d4674febd5ab45fa938...b96794f015dfd88f77b49b1c93e0fa7110f94c63)

Updates `github/codeql-action/upload-sarif` from 4.37.9 to 4.38.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/cdf488f595d80d6e07e03d4674febd5ab45fa938...b96794f015dfd88f77b49b1c93e0fa7110f94c63)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: codeql-action
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <support@github.com>
build(deps): bump the golang-x group across 1 directory with 3 updates

Bumps the golang-x group with 2 updates in the / directory: [golang.org/x/image](https://github.com/golang/image) and [golang.org/x/net](https://github.com/golang/net).

Updates `golang.org/x/image` from 0.45.0 to 0.46.0
- [Commits](https://github.com/golang/image/compare/v0.45.0...v0.46.0)

Updates `golang.org/x/net` from 0.58.0 to 0.59.0
- [Commits](https://github.com/golang/net/compare/v0.58.0...v0.59.0)

Updates `golang.org/x/text` from 0.41.0 to 0.42.0
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.41.0...v0.42.0)

---
updated-dependencies:
- dependency-name: golang.org/x/image
  dependency-version: 0.46.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang-x
- dependency-name: golang.org/x/net
  dependency-version: 0.59.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang-x
- dependency-name: golang.org/x/text
  dependency-version: 0.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang-x
...

Signed-off-by: dependabot[bot] <support@github.com>
Merge pull request #5443 from sharanrajt/nested-virt-qemu

qemu: support `nestedVirtualization` with HVF (QEMU 11.1 or later)
Merge pull request #5502 from lima-vm/dependabot/go_modules/github.com/modelcontextprotocol/go-sdk-1.8.0

build(deps): bump github.com/modelcontextprotocol/go-sdk from 1.7.0 to 1.8.0
qemu: support `nestedVirtualization`

Add support for `nestedVirtualization` in the QEMU driver:

- On macOS (aarch64, HVF): requires QEMU 11.1.0 or later and macOS 15 or
  later (Apple M3 or later). QEMU 11.1 added nested virtualization support
  to HVF for the aarch64 `virt` machine using `hv_vm_config_set_el2_enabled`
  (https://wiki.qemu.org/ChangeLog/11.1). Enabled by appending
  `virtualization=on` to the `-machine virt` option.
- On Linux (aarch64, KVM): requires QEMU 10.1.0 or later and a host kernel
  (6.16 or later) booted with `kvm-arm.mode=nested`. Enabled by appending
  `virtualization=on` to the `-machine virt` option.
- On Linux (x86_64, KVM): verifies that nested virtualization is enabled
  in the host KVM module (`kvm_intel` or `kvm_amd` parameter `nested`) and
  that CPU type `host` is used.

For unsupported architectures or accelerators, a warning is logged and
the field is ignored.

Tested on Apple M4 / macOS 26.5 with QEMU 11.1.0: the guest kernel
initializes KVM in nVHE mode and a nested KVM VM boots EDK2 to the
UEFI shell.

Fix #5419

Signed-off-by: Sharan Raj T <sharanrajtm@gmail.com>

build(deps): bump github.com/modelcontextprotocol/go-sdk

Bumps [github.com/modelcontextprotocol/go-sdk](https://github.com/modelcontextprotocol/go-sdk) from 1.7.0 to 1.8.0.
- [Release notes](https://github.com/modelcontextprotocol/go-sdk/releases)
- [Commits](https://github.com/modelcontextprotocol/go-sdk/compare/v1.7.0...v1.8.0)

---
updated-dependencies:
- dependency-name: github.com/modelcontextprotocol/go-sdk
  dependency-version: 1.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
apfs: bound GPT partition entry size and count before use

findAPFSPartitionGPT trusted the entry size and count from the GPT
header. An entry size below 16 panics in the type-GUID copy and a large
value sizes a multi-GB allocation, while the count only bounds the scan
loop. Bound the entry size to [128, 4096], a sanity range rather than
the UEFI 128*2^n rule (which sets no maximum; 128 is the only size seen
in practice), and bound the count through the total table size, since
UEFI sets no maximum on it either. Cap nx_block_size at
NX_MAXIMUM_BLOCK_SIZE since it sizes every readBlock allocation.

Signed-off-by: Sabith Saheb <shabi7204192361@gmail.com>

Merge pull request #5418 from chrisanderton/fsync-drop

hostagent: don't fsync every log record
Merge pull request #5498 from lima-vm/dependabot/go_modules/hack/tools/mvdan.cc/sh/v3-3.14.1

build(deps): bump mvdan.cc/sh/v3 from 3.14.0 to 3.14.1 in /hack/tools
build(deps): bump mvdan.cc/sh/v3 from 3.14.0 to 3.14.1 in /hack/tools

Bumps [mvdan.cc/sh/v3](https://github.com/mvdan/sh) from 3.14.0 to 3.14.1.
- [Release notes](https://github.com/mvdan/sh/releases)
- [Changelog](https://github.com/mvdan/sh/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mvdan/sh/compare/v3.14.0...v3.14.1)

---
updated-dependencies:
- dependency-name: mvdan.cc/sh/v3
  dependency-version: 3.14.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
fix(vz): stop the VM even when CanRequestStop is false

`LimaVzDriver.Stop()` returned an error without stopping the VM when
`CanRequestStop()` reported false, and it never removed the driver PID file.

When launchd sends SIGTERM to the host agent of a LaunchDaemon instance, the
host agent exits with `vz: CanRequestStop is not supported` and leaves `vz.pid`
behind. Within the same boot this is harmless, because `ReadPIDFile` removes
the PID file of a dead process, but after a reboot the recorded PID may have
been reused by an unrelated process. The instance then shows up as `Broken`
with "vz driver is running but host agent is not", and launchd with
`KeepAlive` crash-loops `limactl start`.

Ask the guest to shut down over SSH whenever the request could not be made
through the Virtualization framework, not only for the macOS guests that ignore
`RequestStop()`. The VM is never stopped forcibly with `VirtualMachine.Stop()`:
that does not give the guest a chance to stop cleanly, and may corrupt the disk.

Always remove the PID file when the driver stops, as the qemu and krunkit
drivers already do.

Related to #5087

Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>

cidata: allow apparmor mounts on every Lima mount point

Ubuntu 25.04 added an apparmor profile for fusermount3 that only permits
fuse mounts under home, /mnt, /tmp and /media. A Lima mount point mirrors
the host path, so it is /Users/USER from a macOS host and /c/Users/USER
from a Windows one. Reverse-sshfs mounts fail there with
"fusermount3: mount failed: Permission denied". The override added in
#4968 covered @{HOME} alone, which only ever helped a Linux host.

Derive the rules from the cidata mount points instead, and rewrite the
file on every boot. Writing it only when it is missing, as #4968 did,
would keep the home-only rule on instances that already have it, and
would miss later changes to an instance's mounts. The cost is that a
rule added to the file by hand is lost on the next boot.

The Windows QEMU job has skipped its mount-home check since the job was
added. The failure the skip cites predates the default template's move
to Ubuntu 25.04, but the skip hid this bug too. Re-enable it.

Signed-off-by: Jan Dubois <jan.dubois@suse.com>

Merge pull request #5489 from resker/fix/autostart-lima-home

fix(autostart): propagate LIMA_HOME into generated launchd/systemd units
Merge pull request #5376 from SABITHSAHEB/networks-varrun-whitespace

validate paths.varRun against an allowlist before findBaseDirectory trims it
Merge pull request #5192 from AkihiroSuda/fix-4389

Rewrite test-port-forwarding.pl in BATS
Merge pull request #5483 from unsuman/net/pr1-lima-net-helper

`lima-privileged-net`: add the privileged network helper for Linux hosts
Add SBOM artifact to the release notes

Signed-off-by: Anders F Björklund <anders.f.bjorklund@gmail.com>

Add SBOM artifact using cyclonedx-gomod

One for lima as a library, one for each cmd.

https://github.com/CycloneDX/cyclonedx-gomod

Add cyclonedx-gomod to hack/tools dir

Running cyclonedx-gomod vendor fails

Mention SBOM in README.md as required

Signed-off-by: Anders F Björklund <anders.f.bjorklund@gmail.com>

Merge pull request #5491 from AkihiroSuda/gomodjail

gomodjail: update to v2.0.1, enforce `gomodjail analyze` in CI
fix(autostart): propagate LIMA_HOME into generated launchd/systemd units

`limactl autostart enable` rendered a launchd plist or systemd unit that carried
no LIMA_HOME. Neither launchd nor systemd inherits the environment of the shell
that registered the instance, so the autostarted `limactl start <instance>`
resolved LIMA_HOME to its default ~/.lima and could not find an instance kept
anywhere else. Both conditions were affected, `--condition=login` as well as
`--condition=boot`.

Pass the LIMA_HOME in effect at registration time to the templates and emit it:
an EnvironmentVariables dict in the two plists, and an Environment= line in the
systemd unit.

The system LaunchDaemon is rendered by `daemonInstall` rather than by the shared
manager, so it needs the value supplied separately. Its rendering moves to
`renderDaemonPlist` to be testable: a key the template references but the map
omits renders as the literal "<no value>" instead of failing, which would then be
written into /Library/LaunchDaemons.

The render tests pin LIMA_HOME so the generated units do not vary with the host
running the test.

Fixes #5488

Signed-off-by: Robert Esker <resker@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Merge pull request #5494 from alexandear/docs/emeritus-alexandear

MAINTAINERS: move alexandear to emeritus section
MAINTAINERS: remove alexandear

Signed-off-by: Oleksandr Redko <oleksandr.red+github@gmail.com>

Merge pull request #5336 from trodemaster/upstream-pr/b1-fakecloudinit-clean

feat(vz): add osOpts.Darwin.suppressFirstLoginSetup
lima-privileged-net: add the privileged network helper for Linux hosts

Linux has no equivalent of socket_vmnet, so add lima-privileged-net, a small
helper that limactl runs via sudo to set up the "shared", "host" and "bridged"
networks. It is installed into libexec/lima/privileged/, a directory reserved
for helpers that run with elevated privileges, so that they are easy to tell
apart from the unprivileged helpers and easy to audit.

`lima-privileged-net start` creates (for "shared" and "host") the lima-<name>
bridge, assigns the gateway address, spawns dnsmasq for DHCP, and installs the
NAT/forwarding rules of the "shared" mode. `lima-privileged-net tap` creates the
tap device of a single instance, hands it to the calling user, and attaches it
to the bridge. Both take all parameters from the command line rather than
reading the user-writable networks.yaml, because the arguments are what the
sudoers file pins down.

The tap device is created with `ip tuntap`, falling back to the /dev/net/tun
ioctls that iproute2 itself uses, because busybox's `ip` applet does not
implement the tuntap subcommand.

The helper tears the network down again when the last instance leaves, and only
ever touches bridges and tap devices that follow the Lima naming scheme.

networks.IsManagedBridge() and networks.IsTapName() recognize the bridges and
tap devices that lima-privileged-net owns, so it never touches an interface it
did not create itself. Config.Validate() rejects a network name that would make
the derived bridge name exceed IFNAMSIZ-1. A daemon-side commit adds the
matching name generators and the command lines that start the helper and attach
an instance to its bridge.

Signed-off-by: Ansuman Sahoo <anshumansahoo500@gmail.com>

gomodjail: update to v2.0.1, enforce `gomodjail analyze` in CI

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>

Merge pull request #5493 from lima-vm/dependabot/go_modules/al.essio.dev/pkg/shellescape-1.6.1

build(deps): bump al.essio.dev/pkg/shellescape from 1.6.0 to 1.6.1
Merge pull request #5492 from lima-vm/dependabot/go_modules/golang-x-b740b0382b

build(deps): bump the golang-x group across 1 directory with 2 updates
Merge pull request #5454 from SABITHSAHEB/portfwd-event-strip-control-chars

reject guest agent events that report an invalid IP
build(deps): bump al.essio.dev/pkg/shellescape from 1.6.0 to 1.6.1

Bumps [al.essio.dev/pkg/shellescape](https://github.com/alessio/shellescape) from 1.6.0 to 1.6.1.
- [Release notes](https://github.com/alessio/shellescape/releases)
- [Commits](https://github.com/alessio/shellescape/compare/v1.6.0...v1.6.1)

---
updated-dependencies:
- dependency-name: al.essio.dev/pkg/shellescape
  dependency-version: 1.6.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
build(deps): bump the golang-x group across 1 directory with 2 updates

Bumps the golang-x group with 2 updates in the / directory: [golang.org/x/sync](https://github.com/golang/sync) and [golang.org/x/sys](https://github.com/golang/sys).

Updates `golang.org/x/sync` from 0.22.0 to 0.23.0
- [Commits](https://github.com/golang/sync/compare/v0.22.0...v0.23.0)

Updates `golang.org/x/sys` from 0.47.0 to 0.48.0
- [Commits](https://github.com/golang/sys/compare/v0.47.0...v0.48.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-version: 0.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang-x
- dependency-name: golang.org/x/sys
  dependency-version: 0.48.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang-x
...

Signed-off-by: dependabot[bot] <support@github.com>
reject guest agent events that report an invalid IP

IPPort.Ip arrives over the guest agent gRPC stream as an arbitrary
string under the guest's control and ends up in
PortForwardEvent.GuestAddr, which limactl start/watch print to the
operator terminal, so a bogus entry could inject ANSI/OSC escape
sequences. Fail the event stream with an error when an entry does not
parse as an IP, before the forwarders derive GuestAddr and log lines
from it.

Signed-off-by: Sabith Saheb <shabi7204192361@gmail.com>

validate paths.varRun before findBaseDirectory trims it

findBaseDirectory() cuts paths.varRun down to the deepest component that
already exists, and validatePath() only ever sees the trimmed value, so
the components that have not been created yet are never checked. The
untrimmed value is what MkdirCmd/PIDFile/Sock interpolate into the
sudoers file, where a newline in that tail becomes a directive of its
own and a comma ends the command list entry.

Check the whole value before it is trimmed, and require every component
to be an identifier rather than enumerating sudoers metacharacters, the
same rule the network name, mode, interface and group already use. Only
varRun is checked this way; the other paths keep the existing whitespace
check so layouts like /Users/foo/.local keep working.

The check is only reached on darwin, so its tests are built with
!windows and use filepath.IsAbs like the rest of the package.

Signed-off-by: Sabith Saheb <shabi7204192361@gmail.com>

Rewrite test-port-forwarding.pl in BATS

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>

Merge pull request #5462 from iamstarkov/vz-audio-microphone

vz: add audio.microphone to attach a capture stream
Merge pull request #5482 from lima-vm/dependabot/github_actions/zizmorcore/zizmor-action-0.6.3

build(deps): bump zizmorcore/zizmor-action from 0.6.2 to 0.6.3
build(deps): bump zizmorcore/zizmor-action from 0.6.2 to 0.6.3

Bumps [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) from 0.6.2 to 0.6.3.
- [Release notes](https://github.com/zizmorcore/zizmor-action/releases)
- [Commits](https://github.com/zizmorcore/zizmor-action/compare/3dc1ecc9bcb9e94e9b2c709687979e1298497054...70fb788f84895a7701f5643d103d587e460b5c99)

---
updated-dependencies:
- dependency-name: zizmorcore/zizmor-action
  dependency-version: 0.6.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Merge pull request #5487 from unsuman/fix/zizmor

ci(zizmor): use self-repository syntax
ci(zizmor): use self-repository syntax

Signed-off-by: Ansuman Sahoo <anshumansahoo500@gmail.com>

Merge pull request #5481 from lima-vm/dependabot/go_modules/hack/tools/mvdan.cc/sh/v3-3.14.0

build(deps): bump mvdan.cc/sh/v3 from 3.13.1 to 3.14.0 in /hack/tools
Merge pull request #5307 from AkihiroSuda/docs

website: update hugo-extended, docsy
build(deps): bump mvdan.cc/sh/v3 from 3.13.1 to 3.14.0 in /hack/tools

Bumps [mvdan.cc/sh/v3](https://github.com/mvdan/sh) from 3.13.1 to 3.14.0.
- [Release notes](https://github.com/mvdan/sh/releases)
- [Changelog](https://github.com/mvdan/sh/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mvdan/sh/compare/v3.13.1...v3.14.0)

---
updated-dependencies:
- dependency-name: mvdan.cc/sh/v3
  dependency-version: 3.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Merge pull request #5479 from AkihiroSuda/dev

go.mod: golang.org/x/crypto v0.56.0
vz: add audio.microphone to attach a capture stream

The vz driver only creates a host output stream, so a guest with
`audio.device: vz` gets a speaker and no microphone: `/dev/snd` has
`pcmC0D0p` but no capture device, and nothing in the guest can record.

Add an opt-in `audio.microphone` boolean, default false. When it is set,
the driver also creates a host input stream and passes both streams to
SetStreams. It is opt-in because an input stream…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(vz/launchdaemon): VZ driver leaves VM orphaned on shutdown; limactl start fails to recover broken state

5 participants