Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
[1.2.5] - 2026-10-03
Fixed
- Online snapshots failed at the filesystem freeze, and the agent claimed it had frozen.
guestkitdruns aszyvor-agentwith an empty capability set, but the QGA handlersguest-fsfreeze-freeze/-thawranfsfreezethemselves, so every freeze failed withOperation not permittedand KubeVirt failed the snapshot of any VM with PVC-backed disks (measured on Ubuntu 24.04 under KubeVirt 1.9: a freshly installed agent cannot freeze; withCAP_SYS_ADMINit can). The unit file already says privileged operations run inguestkitd-exec; freeze and thaw now do: a newfsfreezeaction in the helper (freeze/thawonly, always/) andexecutor_ipc::fsfreeze()for the agent, falling back to an in-process call only when no helper is running (agent run as root). Also,snapshot_hooks::freeze_filesystems/thaw_filesystemstreated a successfully spawnedfsfreezeas success (status().is_ok()), sosnapshot.preparereportedfs_frozen: truewhile nothing was frozen; they now use the same checked path. Covered by a test that starts the realguestkitd-execwith a fakefsfreeze. Requires the helper service (zyvor-guest-agent-exec.service, enabled by the packages) to be running. - Linux agent never connected to the hypervisor channel on stock distros. The virtio port (
/dev/virtio-ports/org.qemu.guest_agent.0) isroot:root 0600butguestkit-agent.serviceruns aszyvor-agent, so the agent started, loggedfailed to open virtio channel, and KubeVirt reported no guest agent. The DEB, RPM and tarball now ship60-zyvor-guest-agent.rules(groupzyvor-agent, mode 0660 fororg.qemu.guest_agent.0andcom.zyvor.guestkit.0) and reload/trigger udev on install. Verified on Ubuntu 24.04 under KubeVirt 1.9: with the rule the agent connects (agentConnected), without it it does not. - Concurrent NBD allocate+connect —
NbdDevice::connectholds a cross-processflock(/run/lock/guestkit-nbd.lock, fallback/tmp) across free-device selection andqemu-nbd -c, and retries the next free index on failure. Fixes races where two mounts claimed the same/dev/nbdN(fluxvm#104:/dev/nbd0p1 already mounted, wrong guest-agent token).new()no longer claims a device index before connect.
Added
- Offline inject on
run_migrate_repair— optionalinject_jsonappends hostname, network files, users, services, first-boot scripts, cloud-init user-data, Active Directory rejoin, Windows KMS reactivation, and RDP enable to the repair plan. Empty or"null"is a no-op.guestkit migrate-repairhas no inject flag; h2kvm passes the JSON from Python. - Live guest fix helpers —
live_fix_commands()returns shell lines (regenerate initramfs, update GRUB, optionally removeopen-vm-tools).run_live_plan(commands, dry_run=False)runs those lines on the machine where Python is executing. It does not SSH. - Docs: README is now a landing page — the detailed sections moved into
docs/(quick-start,who-does-what,capabilities,oss-vs-enterprise,platform-layout,repository-layout,documentation-map, ...); every earlier README anchor still resolves.
[1.2.4] - 2026-09-18
Changed
- Docs — install instructions use the GitHub Release and
pip install zyvor-guestkit. GHCR examples pinv1.2.4. Serial console withoutgrubbyis documented. crates.ioguestkitis still 0.3.2.
[1.2.3] - 2026-09-18
Fixed
- Serial console without
grubby— Photon and other guests have nogrubby. Kernel console args are written into the bootloader the guest already uses (grub2, BLS, syslinux, extlinux, zipl) instead of failing first-boot with exit 127. - XFS remount — pick a valid remount option set after
norecoveryinspect mounts. - Guest root resolution — path resolve uses the real guest
/, notsda1/sda2. - Windows agent inject — mount the Windows root read-write for offline
guestkitdinject.
Changed
- PyPI — Python distribution is
zyvor-guestkit, owned by pypi.org/user/zyvor.hypersdk-guestkitis retired. Import name staysguestkit. Wheel artifact:zyvor_guestkit-*.whl. - GHCR registry — container images publish/pull from
ghcr.io/zyvorai/{zyvor-ui,zyvor-api,guestkit-worker}(wasghcr.io/hypersdk). - Docs — customer wording is now users; CE vs Enterprise licensing is spelled out; docs site is Docusaurus.
Removed
- Zyvor company terms and the distribution acceptance gate.
[1.2.2] - 2026-09-06
Added
- Web Image Vault TUI parity — OSS
deploy/uirenders inspect inventory tabs, Assurance (doctor / migration plan / passport / repair preview + gated apply), Profiles/Issues, and read-only Files browse (guestkit.explore). Docs: using-the-dashboard.md. POST /api/v1/vms/:id/profileandPOST /api/v1/vms/:id/explore— enqueue existing/new worker ops; repair-plan acceptsdry_runquery (default true).- OpenAPI documents profile, explore, and repair
dry_run.
Changed
- Inspect worker summary — larger package/service samples (200/100) for UI lists.
[1.1.0] - 2026-08-31
Added
- Python assurance bindings (
guestkit.pyi,src/python.rs) — native PyO3 wrappers for the migration assurance engine:run_doctor(image, target="kvm")— bootability score, blockers, evidencerun_boot_inspect(image, target="kvm")— OS release, fstab, bootloader summaryrun_migrate_plan(image, target="kvm")— hypervisor-aware fix planrun_repair_plan(image, dry_run=True)— repair plan with before/after scoresrun_migrate_repair(image, apply=False)— primary offline fix path used by h2kvm
- h2kvm integration —
h2kvm.core.guestkit_clientdelegates to these APIs; VMCraft removed from h2kvm - Documentation: python-bindings.md, hyper2kvm-integration.md
Changed
- Python package remains
hypersdk-guestkiton PyPI; wheel artifact:hypersdk_guestkit-*.whl - Assurance APIs return structured
dictresults matching CLI JSON output - Published: PyPI
hypersdk-guestkit==1.1.0, GitHub Release binaries, crates.io
Fixed
- Python 3.13+ builds: document
PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1for maturin when needed
[1.0.1] - 2026-08-15
Fixed
guestkit-worker's Docker release build failed for every release past the0.xline —crates/guestkit-worker/Cargo.tomlpinned its ownguestkitpath dependency toversion = "0.3.3"; the worker'sDockerfilenever copies aCargo.lockin, so each build freshly resolves dependencies and cargo enforces the version requirement even against apathdependency —1.0.0didn't satisfy^0.3.3and thePublish GHCR Release Imagesjob inv1.0.0's release run failed. Dropped the version pin (path-only, matchingzyvor-apiandzyvor-guest-agent's existing pattern for the same in-workspace dependency).
[1.0.0] - 2026-08-15
Added
- GitHub Action for the Passport CI gate (
action.yml) — reusable composite action wrappingdoctor → migrate-plan → passport emit → passport verifyas a single CI step; installs a checksum-verified release binary, no build step. Dogfooded against a real disk image by.github/workflows/passport-gate-demo.ymlon every change. Seedocs/devops/01-passport-ci-gate.md. - Native OpenAI tool-calling for the AI copilot (
src/ai/rig_tools.rs) — rig-coreAgentBuilder/multi_turnwith real JSON-schema tool definitions, replacing regex/JSON-scraped completion text for OpenAI. xAI/Anthropic/Ollama still use the original text-instructed loop. - Cross-run AI memory (
src/ai/memory.rs) — a repeateddoctor --ai/migrate-plan --airun against the same VM folds a summary of prior findings into the query, capped at the last 20 runs.GUESTKIT_AI_MEMORY_DIR/GUESTKIT_AI_MEMORY=0to relocate/disable. - MCP server for the AI copilot (
src/ai/mcp.rs,--features mcp) —guestkit mcp-serve <disk> [--target <target>]exposes the same 6 read-only evidence tools over stdio to Claude Desktop / other MCP hosts, independent of guestkit's own agent loop. guestkit fleet wave-plan(src/fleet/wave.rs) — orders a fleet's disk images into dependency-aware migration waves (DB-role priority + NFS storage-dependency edges, Kahn's-algorithm topological sort, cycles reported rather than dropped or arbitrarily ordered).guestkit fleet watch(src/fleet/baseline.rs) — scheduled drift monitoring: diffs each VM's current evidence against a stored golden baseline (first run establishes it),--fail-on-driftfor pipeline gating. Includes a KubernetesCronJobtemplate (deploy/helm/zyvor/templates/fleet-drift-watch-cronjob.yaml) as the reference scheduled-invocation path.- Helm chart CI —
ci.yml's newhelm-chartjob runshelm lintandhelm templateagainstdeploy/helm/zyvor, which previously had zero CI coverage, across default values, every optional PVC-backed feature enabled at once, hostPath-backed persistence, and all three real deployment overlays (values-ci.yaml,values-k3s.yaml,values-prod.yaml). - Manual-dispatch workflow for NBD-dependent tests
(
self-hosted-nbd-tests.yml) — runs the full test suite with none ofci.yml's NBD skips, for self-hosted runners with working loop/NBD support.workflow_dispatchonly, deliberately never wired topull_request/push.
Fixed
- k3s E2E's
zyvor-apipod crash-looped on every run — the Helm chart's defaultzyvorApi.agentMtls.enabled: truerequiresAGENT_BOOTSTRAP_TOKEN(zyvor-api refuses to start otherwise: "AGENT_MTLS_BIND_ADDR is set but AGENT_BOOTSTRAP_TOKEN is unset"), but the Deployment template only ever wired that env var — and the Secret holding it — inside thezyvorApi.auth.enabledblock.values-ci.yaml(mTLS on, full auth off) hit exactly that gap;values-prod.yamlmasked it by having both auth and a token on together, andvalues-k3s.yamlworked around it by disabling mTLS outright (its own comment already described the bug). Decoupled thezyvor-api-authSecret andAGENT_BOOTSTRAP_TOKENenv var fromauth.enabled— gated only on the token itself being set, matching whatzyvor-api's own config validation actually requires — and set a CI-only placeholder token invalues-ci.yamlso the E2E job now exercises the mTLS path instead of crash-looping.ci.yml's Helm Chart job now alsohelm templates all three real overlays (values-ci.yaml,values-k3s.yaml,values-prod.yaml) so a rendering break here is caught without needing a live k3s cluster. - k3s E2E multi-round debugging — the job was failing on every run;
fixing it required peeling through several layers, each masking the
next:
poll_job(deploy/scripts/e2e-smoke.sh) only recognized"completed"as terminal, so a"failed"job status looked identical to "still pending" for the full 5-minute poll budget, and the worker's own error message (live_status.error) was never printed. Now treatsfailed/cancelled/timeoutas terminal and prints the error immediately.install-k3s-ubuntu.shnever got the loop/NBD device setupci.ymlneeded earlier this session (guestkit-worker's pod bind-mounts the host's/dev, so the same root:disk-0660-node / EACCES-looks-like-timeout issue applies here too). Added it — confirmed live afterward:inspect/doctorboth complete in one poll with a real bootability score. This specific k3s stack path does not hit the deeper NBD-attach limitationci.yml's plaincargo testjob still has to skip around.curl -sfswallows the response body on any non-2xx status, so the next failure (provision) looked like an empty response (Expecting value: line 1 column 1) instead of a real API error. Added acurl_or_diehelper (splits HTTP status from body via curl's-w, prints both on failure).- That revealed a real HTTP 500:
"No operating system found in disk image"fromprovision(POST /vms/{id}/provision, which mounts the disk synchronously in zyvor-api's own process), on the same imagedoctorhad just inspected successfully. Suspected (and partially fixed) an unawaited asyncmigration-planjob racing provision's own mount viaNbdDevice::find_available_device(src/disk/nbd.rs) — that function does check device availability and connect as two separate, unlocked steps with no cross-process coordination, a real bug now flagged with a code comment — but serializing migration-plan before provision did not fix it, disproving the race as this failure's cause. provision_vm's.map_err(|e| ApiError::internal(e.to_string()))(crates/zyvor-api/src/routes/vms.rs) only shows anyhow's outermost.context()layer via plainDisplay. Changed toformat!("{e:#}")(alternate Display, full chain) forprovision_vm's threeguestkit/export::kubevirt-derivedmap_errcalls — correct and worth keeping, but the next run's error was still byte-identical to before, because there was no chain to reveal:mount_all_ro(src/cli/commands/mod.rs) returnsOption<String>, notResult<String>, and.context("No operating system found in disk image")on aNone(anyhow'sContextimpl forOption) produces an error with no wrapped source at all — the context message genuinely is the entire error. Left the other ~90.map_err(|e| ApiError::internal(e.to_string()))sites in the crate alone; most wrap simple error types (serde_json,std::io) where.to_string()isn't lossy.- The real swallowed information was one layer further down:
mount_all_rocallsg.inspect_os().unwrap_or_default()—inspect_os()failing for any reason (guestfs launch issue, mount error, permission problem) collapses to the identical empty-rootsNoneas "genuinely no OS found," discarding whateverinspect_os's real error was before it could reach any context message. Changed to log the real error (log::warn!) before discarding it. Didn't widenmount_all_ro'sOption<String>return type toResult— it's used across 9 files where callers only ever branch onSome/None, and that ripple is out of scope for this investigation. Widened the defaultEnvFilter(was "nothing enabled" withoutRUST_LOGset, now falls back towarnglobally) somount_all_ro's newlog::warn!— and any otherlog::*!from guestkit's dependency graph — actually reaches the pod's logs. First attempt at this also added an explicittracing_log::LogTracer::init()call, reasoning thatzyvor-apionly sets up atracingsubscriber and guestkit logs through the plainlogfacade — wrong, and a real regression:tracing-subscriber's "tracing-log" feature (on by default) already bridgesloginto the subscriber as part of.init(), so the explicit call double-registered the globalloglogger and panicked at startup withSetLoggerError, crash-loopingzyvor-apiagain. Confirmed viakubectl logsfrom the next E2E run (once the "dump pod logs on failure" step below existed to capture it) and reproduced in an isolated 10-line binary before re-pushing — removed the explicitLogTracer::init()call and the now-unneeded directtracing-logdependency; the isolated repro confirmedlog::warn!still reaches the subscriber correctly without it. - Also: nothing in
k3s-e2e.ymlever captured pod logs on failure — every fix in this list up to this point was diagnosed purely from HTTP response bodies, each requiring a full ~20-40min re-run just to test. Added a failure-only step dumpingkubectl logs(all containers, prefixed by pod) for every deployed component, plusget pods -o wideanddescribe pods. - That finally showed it: no panic, no error, no
mount_all_rowarning —inspect_os()genuinely returned an empty root list.validate_root_partition/validate_initrd_boot_partition(src/guestfs/inspect.rs) treat mount/extraction failures as "not a valid root" by design, not as errors — a real mount failure and "genuinely no OS" are indistinguishable at that layer on purpose (LVM volumes on read-only NBD devices can legitimately fail to mount for benign reasons).validate_initrd_boot_partitionis the cirros-cloud-image path — root filesystem lives inside the initrd, not on a directly-mountable partition — and shells out tozcat <initrd> | cpio -tto look inside it.crates/zyvor-api/Dockerfilenever installedcpio(orgzip), unlikecrates/guestkit-worker/Dockerfile's otherwise-identical package list, which does. That shell command silently failing insidezyvor-api's container is whyprovision(run_migrate_plancalled synchronously in zyvor-api's own process) couldn't find an OS on exactly the imagedoctor/inspect(viaguestkit-worker, which hascpio) found one on every time. Addedcpio/gziptozyvor-api's Dockerfile, matchingguestkit-worker's package list. Confirmed live afterward:provisionsucceeds, generating a real PVC-referencing manifest — this was the fix. The remaining unguardedcurl -sf | python3call sites pastprovision(/config,/kubevirt/vms,/kubevirt/namespaces,/vmtools/coverage,/vmtools/policy,/storage/roots, theE2E_KUBEVIRTcluster-inspect calls) got the samecurl_or_dietreatment for consistency. - One more layer, different in kind from everything above:
/vmtools/coveragenow fails with a real, visible error —kube list virtualmachines: ... 404 page not found.values-ci.yamlsetskubevirt.enabled: true(zyvor-api/worker assume the KubeVirt CRDs exist), but neitherinstall-k3s-ubuntu.shnordeploy-remote-k3s.shever installed the KubeVirt operator that registers them — this repo already has that install (pinnedv1.4.0, operator + CR manifests, tolerant wait) indeploy/scripts/kind-kubevirt-quickstart.sh, just never ported to the script this CI workflow actually uses. Ported it. GitHub-hosted runners have no/dev/kvm(no nested virtualization), sovirt-handlerwon't reach fully healthy and starting a realVirtualMachineInstancestill won't work here — but the CRDs register and thekubevirt.io/v1API group routes real (empty) responses instead of 404 as soon as the operator applies them, which is all this job's default (non-E2E_KUBEVIRT) path needs.
- Main CI (
ci.yml) had been broken for a while —journal-native(a default feature) needslibsystemd-dev, missing from every job exceptrelease.yml's;Code Coverage's--all-featuresalso needslibhivex-dev; the musl release build tried to link glibc'slibsystemdinto a musl target instead of building--no-default-features. Loop/NBD device nodes were root:disk 0660 — unreadable by the unprivileged test process, which read that as "not ready" instead of a permissions error; thenbdkernel module was never loaded inci.ymlat all.guestkit.spec/guestkit-full.specwere two releases stale, breakingrpmbuild. The k3s E2E workflow was missingmusl-tools/gcc-mingw-w64-x86-64for the vmtools cross-builds, and its MinIO upload usedmc's defaultlocalalias credentials instead of this deployment's actual root user/password. Guestfs::launch()didn't transition toErrorstate when failing on the "no drives added" precondition — only later failures did.- Windows cross-compile regression in
agent/rdp.rs— an automated lint pass removed thejsonimport as unused (true when checked on a non-Windows host) but it's real, used code behind#[cfg(target_os = "windows")]. - 6 pre-existing doc-test compile failures (
mem_optimize.rs,cli/parallel.rs,fstab_rewriter.rs) — ambiguous generic return types and stale API usage in doc examples, never caught because CI never previously got far enough to reach the doc-test phase.
[0.3.21] - 2026-08-08
Fixed
rescue -o reset-passwordSEGV —hivex_value_typeFFI declaration was missing its two out-params (*mut c_int,*mut usize); calling it with the wrong signature corrupted the argument registers and crashed. Fixed the binding and the RID-lookup call site.ntfsfixnever actually cleared the NTFS dirty flag — write-mode Windows rescue ops (reset-password,enable-rdp, ...) against a VM disk that wasn't cleanly shut down from inside the guest (the norm, not the exception, for a hypervisor-level stop) silently mounted read-only and no-opped until the final write, which then failed deep in the SAM upload step with a confusing "Read-only file system" error.ntfsfix()is nowntfsfix_opts()with a realclear_dirtyflag that passes--clear-dirty, wired into all three Windows rescue-mount call sites; an interimremove_hiberfilemount-option attempt is superseded by this.- Windows cross-compile broken — offline package/firstboot-stage modules
(
cli::plan::{firstboot_stage,package_fetch,package_stage,preview}) referenced Unix-onlyguestfstypes with nocfggate, breaking builds targetingwindowsfor the in-guest agent. Gated with#[cfg(not(target_os = "windows"))].
[0.3.20] - 2026-08-07
Added
- DevOps runbooks —
docs/devops/Passport CI gate, offline repair worker, air-gap packages/VirtIO, fleet analyze, cutover weekend, failure triage, cloud disk sources (S3/GCS/Azure), forensic IR, SBOM/inventory CI. - GitHub Wiki — operator cheat sheets (Passport, day-0, packages, env, TUI, KubeVirt/GCF/agent) linked from README / docs INDEX.
GUESTKIT_PACKAGE_MIRROR— HTTP fallback viacurl/wgetwhen hostdnf/apt-getis missing or fails (comma-separated bases; optional{name}/{ext}templates). Helps macOS hosts stage PackageInstall.- Domain-leave first-boot RunOnce —
windows-domain-leavestagesGuestKitDomainLeaveRunOnce (Add-Computer -WorkGroupName) in addition to Tcpip/Winlogon markers (DC computer-account delete still needs live AD). - Worker performance + migration profiles —
guestkit.profilejobs run the same CLIInspectionProfileimplementations asguestkit profile. - Offline ServiceOperation / CommandExec staging — enable/disable via
systemd wants Symlink/FileDelete; start/restart and other commands stage
guestkit-firstboot-live.servicewhen chroot cannot run them. - UEFI-aware
fix-grub --force— detects ESP under the guest root and runsgrub-install --target=x86_64-efi|arm64-efi --efi-directory=… --no-nvram --removable(BIOS path unchanged). - Windows AES/RC4 SAM NT-hash write —
rescue -o reset-password --passwordreconstructs the SYSKEY bootkey from SYSTEM LSA class names, derives the hashed bootkey from SAMF, and writes an AES-128-CBC (or legacy RC4) encrypted NT hash into the userVblob. Falls back to SAM blank + RunOncenet userif SYSTEM/bootkey/crypto fails. - PackageInstall host fetch — with
GUESTKIT_PACKAGE_FETCH=1, offlineplan applydownloads missing.rpm/.debon the host (dnf download/yumdownloader/apt-get download) intoGUESTKIT_PACKAGE_CACHEor~/.cache/guestkit/packages, then stages the first-boot oneshot as before. - Offline GRUB repair (
fix-grub) —rescue -o fix-grubbind-mounts proc/sys/dev and runs chrootgrub2-mkconfig/grub-mkconfig/update-grub;--forcealso attemptsgrub-installonto the NBD device (BIOS) or EFI removable path when an ESP is present; if chroot mkconfig fails, stagesguestkit-firstboot-grub.service.--export-planwrites the first-boot FileWrite/Symlink ops.check-grubremains diagnose-only. - System Reserved / ESP detection — offline Windows evidence probes
non-OS NTFS/FAT volumes for
bootmgr+ BCD (legacy System Reserved) or EFI Microsoft Boot (ESP). Surfaces onwindows.system_reserved, promotesbcd_store_found/bootmgr_found, fixesesp_present(no longer aliased to bootmgr). Boot check BOOT-014, migration MIG-W-011, Passport flagssystem_reserved_layout+bcd_store_found. - Windows driver/hotfix migration diagnostics — offline HotFix registry +
$NtUninstall*/$hf_mig$/ CBS.log tail; VirtIO.syspresence onWindowsDriverEntry.sys_present; BCD UTF-16 probe for testsigning / nointegritychecks. Migration MIG-W-012 (hotfixes/servicing), MIG-W-013 (VirtIO files); Passporthotfix_count/hf_mig_present/driver_signature_enforcement. Hive paths resolve via guestfs mount root. - Offline activation / ghost-NIC depth — SOFTWARE ProductId/EditionID/
DigitalProductId +
oeminfo.ini→windows.activation(OEM/Retail/Volume); SYSTEMEnum\PCIremnant/problem NICs →ghost_nics; Tcpip static interfaces →static_nic_configs. Enriches MIG-W-006/007/008; Passportactivation_channel,ghost_nic_count,static_nic_count. - Offline BitLocker / VSS enrichment —
BitLockerStatus\BootStatus(On → hard block), FVE/$BitLocker/fvevol artifacts (offline_uncertainwarning), VSS+swprv services + System Volume Information inference. Fillswindows.bitlocker/windows.vssfor MIG-W-005/009; Passportbitlocker_uncertain. - Day-0 plan/rescue depth —
windows-dhcp/windows-dns/linux-hostnameprofiles; rescueenable-rdp/enable-winrm/set-timezone; Windowsset-hostnameapplies registry day-0 plan (was Linux/etc/hostname). - Cutover Passport signed-enterprise workflows —
passport keygen(Ed25519 seed + pubkey); emit--issuer/--expires-hours; verify--trust-keysallowlist +--max-age-hoursfreshness gate (signing/verify needagent). - Production Helm —
values-prod.yaml: PVC-backed Postgres/Redis/MinIO (eval stillemptyDir); Ingress TLS + cert-manager annotations; pinned GHCRv0.3.19images; nightly image-vault backup CronJob + backup PVC. - Guest Control Fabric poll telemetry — airgap reconciler records per-method
latency + transport attempts; Redis fleet rollup;
GET .../guest/poll-telemetry(VM + fleet);guest/statusexposeslastPoll/telemetryMode. - Fleet analyze performance — parallel
--jobs/GUESTKIT_FLEET_JOBS(default min(4, CPUs)); evidence-cache hit skips remount. - Cloud disk source depth — persistent
~/.cache/guestkit/cloudpulls; S3GUESTKIT_S3_ENDPOINT/AWS_ENDPOINT_URL;azure://URIs; GCSgcloud storagefallback; CI recipescripts/ci-cloud-disk-sources.sh. - Offline heuristic remediations + linux-grub —
systemctl enable/disable→ Symlink/FileDelete; fail2ban/auditd/chrony/apparmor/sshd enable offline; ufw default deny FileEdit; day-0linux-grub(--grub-timeout/--grub-cmdline) for/etc/default/grub. - Offline PackageInstall staging — when
GUESTKIT_PACKAGE_CACHE(orhost_cache) holds matching.rpm/.deb, offlineplan applystages packages + a first-boot systemd oneshot instead of skipping; optionalGUESTKIT_PACKAGE_FETCH=1downloads missing packages on the host first; live install unchanged. - Windows offline password set —
rescue -o reset-password --passwordprefers AES/RC4 SAM NT-hash write via SYSKEY; falls back to SAM blank + HKLM RunOncenet userfor first boot; omit--passwordto blank only.
Changed
- Docs — Roadmap parked list cleared; CLI / quick-reference / feature guide /
fix-plans updated for AES SAM passwords,
fix-grub, andGUESTKIT_PACKAGE_FETCHoffline staging.
[0.3.19] - 2026-08-06
Added
- Cutover Passport —
guestkit passport emit|verify: versioned CI-gateable assurance artifact (evidence digest, boot/migration scores, FixPlan digest, Windows BitLocker hard-block +windows_offline_ready, optional live attestation via agent-proxy, optional Ed25519 sign). Suite handoff points to HyperSDK (export) + hyper2kvm (convert/deploy). Web:POST /vms/:id/passport- dock download. Worker op
guestkit.passport.
- dock download. Worker op
plan generate -p windows-domain-leave— offline domain→workgroup markers (--workgroup, defaultWORKGROUP).plan generate -p windows-timezone— offlineTimeZoneKeyName(--timezone).plan generate -p windows-static-ip— offline static IPv4 on a known interface GUID (--interface-guid --ip --mask [--gateway] [--dns]).
[0.3.18] - 2026-08-06
Added
plan generate --profile windows-hostname— offline ComputerName + Tcpip Hostname / NV Hostname (--hostnamerequired). Apply with--skip-backup.plan generate --profile windows-winrm— WinRM Automatic +WINRM-HTTP-In-TCPfirewall rule. Apply with--skip-backup.Symlink/FileDeleteplan ops — offline guestfsln_sf/rm(used by hardenedlinux-ssh).plan generate -p linux-ssh --user+--key/--key-file— injectauthorized_keysinto the enable plan.- Windows
rescue -o reset-password— offline SAM blank (chntpw-style) viaregistry-write/ libhivex; clears password so interactive logon works. rescue --export-plan PLAN.yaml— emit a reviewable FixPlan for enable-ssh / inject-ssh-key / set-hostname / reset-password / fix-fstab.- Offline
DriverInject— apply useshost_dir/GUESTKIT_VIRTIO_WINinject_windows_driver_dirwhen built withregistry-write,agent.
migrate-repair --virtio-win DIR— wires VirtIO host tree into migration repairDriverInject(same as$GUESTKIT_VIRTIO_WIN).- Heuristic offline remediations — firewalld enable →
Symlink, ufw → conf edit, more sshd FileEdits; preview tags live-only ops as offline-skip.
Fixed
linux-sshplan fidelity — wants enable viaSymlink(notCommandExec ln), removes/etc/ssh/sshd_not_to_be_run, matches rescue enable path.from_security_profilenaming — plan profile/tags follow the inspect profile name (not hardcoded"security").rescue check-grub— diagnose-only rename (fix-grubkept as alias).
[0.3.17] - 2026-08-06
Added
plan generate --profile linux-ssh— offline Linux SSH enablement (systemdssh/sshdwants symlink +/etc/ssh/sshd_config.d/99-guestkit.confwithPubkeyAuthentication yes). Apply with--skip-backup.planFileWriteoperation — create/overwrite a guest file offline.rescue inject-ssh-key—--user+--key/--key-fileappends toauthorized_keys.rescue set-hostname—--hostnamewrites/etc/hostnameand patches/etc/hosts.
Fixed
rescue enable-ssh— actually creates the systemd wants symlink and writes an sshd drop-in (previously only printed a manualsystemctlnote); write drop-in before unit enable; prefer real wants dirs / relative symlinks /ln -sfnwhen guestfsln_sfrejects unit paths.- Windows
guest-fsfreeze-freeze/thaw— route to VSS marker shadows instead of the Linuxfsfreezebinary so KubeVirt quiesced snapshots work on Windows guests.
[0.3.16] - 2026-08-06
Added
plan apply --skip-backup— skip the mandatory full-image qcow2/raw copy before apply. For low-risk registry-only plans (enable RDP, etc.) a 30–40 GiB Windows golden backup is slower than the edit; default remains refuse-without-backup.plan generate --profile windows-rdp— offline Windows Remote Desktop enablement plan (fDenyTSConnections, NLA, TermService/UmRdpService Automatic, port 3389, inbound TCP/UDP firewall Active=TRUE). Apply with--skip-backup.
Fixed
plan applydirty NTFS — runntfsfixon NTFS devices before mount (same path asagent-inject --windows) so force-off / fast-startup disks mount read-write and hive edits are not silently skipped (0 operations).
[0.3.15] - 2026-07-29
Added
- In-guest Windows agent, fully offline install —
guestkit agent-inject --windowsprovisions a Windows guest with no boot required: registers theGuestKitAgentservice in theSYSTEMhive via hivex, and installs the virtio-serial (vioser) driver the QGA channel needs (driver files,DevicePath, service key, andCriticalDeviceDatabaseentries parsed from the INF, including the KMDF binding). - Stock
qemu-guest-agenttakeover — anyQEMU-GA/qemu-ga/QEMUGuestAgentservice found during Windows injection is disabled (Start=4) so GuestKit answers the virtio-serial channel uncontended, while remaining QGA-compatible so KubeVirt/libvirt see no difference. - Converted-image driver fix — deletes the stale cached
SYSTEM\...\Enum\PCI\VEN_1AF4&DEV_1043device key on converted images (e.g. VirtualBox eval → qcow2) so the PCI bus re-detects the virtio-serial device and runs a full driver install on next boot instead of staying stuck on "no driver." - Generic
guestkit-rpcQGA passthrough — every in-guest agent RPC method is now reachable through the standard QGA channel, so host automation only needsvirsh qemu-agent-command. - Windows agent default channel — the Windows service now defaults to the virtio QGA port, matching the Linux agent's channel selection.
- Fall back to
systemctl restartwhen the D-BusRestartUnitcall fails.
Documentation
- Page-by-page user manual (
docs/user/) with per-page PDFs, linked from the README. docs/features/guest-agent.mddocuments the Windows offline install path end-to-end, including the stock-QGA disable step.- README now surfaces the in-guest agent (previously undocumented at the top level) with a dedicated "What's New" section, plus CI/crates.io/PyPI/license badges.
[0.3.14] - 2026-07-11
Added
- Boot-score trend (
guestkit-ux.js) — every boot score is recorded per disk in localStorage; a re-scan after a repair toasts the delta (▲ +N/▼ −N), and a new 📈 Boot-score trend command renders the history as an inline SVG sparkline (CSP-safe, no external assets, reduced-motion aware). - Zyvor brand footer + logo — the web console and login page now carry the
zyvor.devlogo (linked) and azyvor.dev · HyperSDK · © 2026credit line, matching the PacketWolf branding treatment.
Documentation
- Default web console login documented — the seeded
admin/Admin@321(previously only printed at install time bypackage-auth-bootstrap.sh) is now in the remote-deploy guide, getting-started, and README, each with a change-on-first-login warning. Also surfaced as a first-run hint on the login page, shown only when local login/bypass is available. - Run the web stack from GHCR — new
deploy/docker-compose.ghcr.yml(pulls only the publicghcr.io/zyvorai/{zyvor-ui,zyvor-api,guestkit-worker}images) plus a "Published images (GHCR)" guide covering pull, Compose (eval), and Helm (prod), cross-linked from the README and deployment docs.
[0.3.13] - 2026-07-11
Added
- Deep offline inspection panels — the
guestkit.inspectworker handler now collects and surfaces, from a mounted disk: partitions (device/fstype/UUID) + fstab, installed kernels + default, boot-load kernel modules, systemd unit inventory, and user accounts (/etc/passwd→ name/uid/home/shell/login). A second wave adds network detail (DNS servers, default gateway), machine-id, cloud-init presence, VM guest tools (open-vm-tools/vmware/vbox/hyperv/qemu-ga), firewall (ufw/firewalld/iptables) and SSH policy (root-login/password-auth). The web report renders each as a token-driven panel (Storage table, Kernels, Drivers, Systemd units, Users table, Guest platform), all reduced-motion aware. - Premium web-console UX layer (
guestkit-ux.js) — ⌘K fuzzy command palette (with>Ask-Zeus mode), dock cursor-magnify, event-bus rich toasts, activity log, cinematic Zeus scan overlay + verdict burst, ambient aurora, theme wipe, keyboard-driven fleet nav, click-to-copy, shortcut cheat sheet, skeleton loaders, Ask-Zeus starter chips, global drag-to-analyze overlay, first-run coach-mark tour, a canvas verdict share-card (PNG export), synthesized Web Audio cues, a Konami "storm mode", and a client-side fleet compare view. - OVA + cloud-image ingest and multi-node CephFS RWX vault for shared image storage across cluster nodes.
Fixed
- Windows boot doctor — Linux-only checks (BOOT-003 Initramfs, BOOT-004 GRUB) are now gated as N/A on Windows guests instead of failing as false blockers.
- Legacy-BIOS Windows BCD/bootmgr detection — the evidence builder checked
only EFI paths, falsely flagging
BCD store not foundon legacy installs; now also detects/Boot/BCDand/bootmgrat the boot-volume root. - Security: JWT signing key fails closed — with
AUTH_ENABLED=true, the API refuses to start unlessJWT_SECRETis a real value (previously fell back to a hardcoded, globally-knownchange-me-in-productionkey → forgeable tokens). - Security: DB password out of plaintext env —
DATABASE_URLnow comes from thezyvor-secretsSecret viasecretKeyRefinstead of being interpolated into the API Deployment env (visible inkubectl describe). delete_vmno longer 500s on analyzed disks — the handler tears downjob_results → jobs → vm_imagestransactionally instead of hitting thejobs_vm_id_fkeyforeign-key constraint.- Helm multi-tenant collision — the KubeVirt ClusterRole/Binding names are
namespace-scoped (
zyvor-api-kubevirt-<ns>) so a second install doesn't clash.
[0.3.12] - 2026-07-10
Added
- Offline Windows registry writes —
registry-writefeature links libhivex (hand-rolled FFI, LGPL-2.1 dynamic link — no copyleft crate) so fix-planRegistryEditoperations mutate offline SOFTWARE/SYSTEM/SAM/SECURITY hives (HKLM) instead of being skipped; supports REG_SZ/EXPAND_SZ/DWORD/QWORD/MULTI_SZ/BINARY with whole-disk backup. Build with--features registry-write(needslibhivex-dev/hivex-devel)
[0.3.11] - 2026-06-15
Added
- Guest Control Fabric — transport-independent guest control with 7-tier ladder (virtio-serial → QGA exec → QGA builtin → push cache → offline disk)
- New API routes —
guest/status,guest/capabilities,guest/doctor,guest/readiness,guest/install-agent,guest/repair-plan,guest/file/read|write,guest/poll-reconcile - QGA file bootstrap — airgap agent install via
guest-file-write+guest-exec(no guest network) - Agent Doctor — probe tree, readiness score (0–100), live
guestkit.doctorvia transport ladder - Host-mediated polling — background reconciler for
airgap_liveVMs without push telemetry - GuestActionPolicy extensions —
execAllowlist,fileReadAllowlist,fileWriteAllowlist,freezeAllowed,maxExecOutputBytes - UI — Guest Control panel, Agent Doctor tree, control-state chips, host-mediated exec warning banner
- Docs — guest-control-fabric.md
Changed
- Guest intel routes —
/guest/*intel endpoints returnGuestControlEnvelopewith legacy fields indata - Exec policy — when
GuestActionPolicyexists,execAllowlistis required (no raw shell by default) - Repair worker — honors
inject_qga,fix_cloud_init_network,validate_fstab,enable_systemdjob payload fields - Transport ladder — attempts VirtioSerial (daemon + socket) and InGuestSocket before QGA exec RPC
- Offline inject — agent binary path aligned to
/usr/local/bin/zyvor-guest-agentandzyvor-guest-agentsystemd unit - Worker repair — honors
inject_zyvor_agentfrom job payload
[0.3.10] - 2026-06-14
Added
deploy/scripts/e2e-ubuntu-k3s.sh— Ubuntu 22.04 k3s E2E: offline inspect/doctor, CDI VM, live guest intel, cluster offline inspect
Fixed
- Release CI — optional
journal-nativefeature for musl/static builds; installlibsystemd-devfor gnu tarballs; fixApiErrormapping in guest pull; align VM tools.sha256artifact name - KubeVirt QGA transport — virt-launcher pod lookup uses
kubevirt.io/vm(KubeVirt 1.8 labels) with fallbacks - Guest agent install — KubeVirt 1.8+ virtio guestagent disk (
serial: org.qemu.guest_agent.0) instead of rejecteddevices.channels - Per-VM guest pull — install/RPC paths use
/usr/local/bin/zyvor-guest-agent; QGA failures no longer silently fall back to in-clusterAGENT_PROXY_URL
[0.3.9] - 2026-06-13
Fixed
cargo fmtformatting in security profile score calculation- Integration tests treat
unknownOS distro as undetected and fall back to/etc/debian_version - RPM workflow installs binary package when optional Python RPM is absent; verify step uses
command -v - Python wheel CI installs locally built artifacts instead of stale PyPI releases
- PyPI publish uses wheel-only upload with version synced from
Cargo.toml
[0.3.8] - 2026-06-12
Fixed
- CI clippy warnings across agent, AI, guestfs, and assurance modules
- Integration test uses disk-to-disk
guestkit copywith four arguments Cargo.locksynced for RPM--lockedbuilds
[0.3.7] - 2026-06-12
Added
- Abyss web console — GuestKit deploy UI with deep-navy design system (aurora background, indigo/violet accents, frosted-glass cards), local Inter fonts, and GuestKit-branded brain/dock/mission rail
- Console Copilot API — briefing, ask, fleet overview, compare narrative, launch advice, and system status endpoints in
zyvor-api zyvor-guest-agentcrate — in-guest agent daemon for Windows and Linux VM Tools- Windows forensic depth — EVTX parsing, persistence run keys, forensic profile merge in evidence collectors
- QGA helpers — KubeVirt guest-agent transport improvements for live inspection
Changed
- Renamed Abyss UI modules to
guestkit-console.js,guestkit-ai.js,guestkit-features.js - Integration tests use
guestkit copy(replacing removedcpalias) - TUI view registry includes Assurance, SystemdDeep, and AiInsights (21 views)
Fixed
- AI agent tool-call parser accepts JSON embedded in prose lines
- Failed-disk UX in web console (deduped job tracker, disk switch guidance)
- RPM spec
%changelogweekday dates for Fedora builds
[0.3.6] - 2026-05-27
Added
- In-guest agent — optional
agentfeature:guestkit agent(virtio-serial JSON-RPC daemon),guestkit agent-proxy(host HTTP bridge), live evidence + fix-plan execution inside running VMs guestkit-agent-protocol— shared length-prefixed JSON-RPC types for agent and proxyrepair --inject-agent/migrate-plan --export --inject-agent— offline guestfs injection of agent binary + systemd unit- Worker jobs —
guestkit.agent.evidenceandguestkit.agent.fixvia agent-proxy HTTP - TUI LIVE badge — assurance view when
GUESTKIT_AGENT_SOCKETresponds to ping - CI —
agent-release.ymlmusl artifact workflow; integration tests behind--features agent - TUI fix-plan preview — read-only modal of migration plan operations (
pin Assurance,: plan preview) - TUI Assurance shortcuts — dashboard
aopens Assurance; global search indexes boot blockers and migration items - TUI Assurance view — Security-group panel for
doctorboot gate andmigrate-planscoring;d/t/ekeys; palette commandsdoctor,migrate-plan,export plan - TUI config —
[behavior]default_migration_target,assurance_on_startup,show_assurance_hint - TUI UX — scrollable view tab row (
,/.); compact density on Issues list rows; palettegotoaliases for all views
Changed
- Dashboard — boot score line when assurance data is loaded
- Documentation — pruned CLI guide and CHANGELOG; TUI assurance docs updated
[0.3.5] - 2026-05-26
Added
- Migration assurance platform — evidence snapshot model (
EvidenceSnapshot) as the digital twin primitive for scoring engines guestkit doctor— bootability prediction with weighted score, blockers, and--explainroot-cause analysisguestkit migrate-plan— hypervisor-aware migration scoring (KVM/Proxmox/cloud) with driver injections and downtime estimateguestkit migrate-plan --export— write migration guidance as an executable fix plan (YAML/JSON)guestkit policy check— policy-as-code alias with expression DSL over evidence fields (bootability.score >= 80)guestkit fleet analyze— cluster identical VMs, detect snowflakes, flag migration blockersguestkit forensic-diff— security drift scoring between two disk snapshotsguestkit repair --fix boot— transactional boot repair via fix plans with post-apply doctor validation--profile windows-migration— BitLocker, domain join, RDP, hypervisor remnants, driver gaps- Windows registry depth — SAM/SECURITY hive parsing, BitLocker detection, pending reboot, domain/RDP audit
- OSV CVE lookup — offline cache at
~/.cache/guestkit/cve/with static fallback database - Cloud disk sources — optional S3/Azure/GCS backends (
--features cloud-s3, etc.) - AI evidence tools — deterministic bootability and evidence snapshot for the optional AI assistant
- Assurance integration tests — CLI and plan-generation coverage for doctor/migrate-plan/repair workflow
- Documentation — migration-assurance.md; VM migration and fix-plans guides updated
Changed
- TUI navigation — two-tier tabs (group + view rows); scrollable jump menu and help;
{/}switch groups (tui-enhancements.md)
[0.3.4] - 2026-05-25
Added
guestctlbinary — separate crate binary (alias entry point); install viacargo install guestkitor client tarball symlink- GitHub Release user bundles — full install tarball (
guestkit-<version>-linux-amd64.tar.gz) matching remote deploy packaging scripts/package-binary-release.sh— local/CI packaging shared with GitHub Actions- TUI visual polish — shared
widgets.rs(stat chips, severity rail, progress bar, risk donut) - Theme variants —
high-contrastandminimalvia[ui] themeintui.toml - Config —
show_emoji,densityunder[ui]
Changed
- CLI entry split into
guestkit::climodule tree (entry,invocation,commands_list,welcome) - TUI header, stats bar, tabs, footer, loading bar, fleet sidebar, and modal dim layer
- Dashboard and Issues views use carbon gauges, sparklines, and risk summary donut
- GitHub release workflow uploads user bundles (gnu + musl) instead of bare binaries
- Documentation: tui-enhancements.md updated for carbon theme and visual polish
[0.3.3] - 2026-05-22
Added
- Carbon control-plane TUI theme — graphite surfaces (
#0B0E12), orange accent (#FF7A00) on focus and risk states only - Zyvor branding on TUI splash (
zyvor.devwordmark) - Risk-aware header border — subtle red/amber glow from security issue counts
- Documentation hub (
docs/INDEX.md) with pruned user-facing docs
Changed
- TUI footer uses muted key hints; orange reserved for primary actions
- Default TUI theme config:
carbon - README: open-source branding (removed Community Edition wording)
Fixed
- TUI dashboard and issues views use consistent
content_blockpane styling
[0.3.1] - 2026-01-26
Added
- Killer summary view on inspect; Windows registry-based version detection
- Universal fstab/crypttab rewriter for VM migration; loop-device primary path for RAW/IMG/ISO
- LVM volume group cleanup on shutdown
[0.3.0] and earlier
Release notes for v0.3.0 (interactive REPL, expanded inspect), v0.2.0 (extended guestfs API coverage), and v0.1.0 (initial toolkit) are in GitHub Releases and git history.