* feat(kubernetes): bootstrap experimental gateway supervisor topology
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* docs: move the experimental supervisor topology under an Experimental section
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* feat(supervisor): report experimental bootstrap health over TCP
experimental-bootstrap now takes --health-port instead of a Unix health
socket. It binds the dedicated supervisor's wildcard readiness listener,
reachable at the Pod IP, and accepts and closes connections while the
process runs. The chart probes the named container port health (5502)
with native kubelet tcpSocket checks and drops the health-only emptyDir.
No filesystem state remains to clean up after an unclean exit.
Dedicated supervisors keep --health-socket-path and health --socket.
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* docs: defer public experimental supervisor docs
Remove the experimental supervisor topology additions from the published gateway configuration page and the public debug-openshell-cluster skill. Public documentation will be added once the experimental stack settles.
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* refactor(supervisor): replace bootstrap with shared host stub
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* refactor(supervisor): name shared supervisor subcommand shared
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* refactor(supervisor): select shared mode with explicit endpoint flags
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* refactor(supervisor): name the shared host module after its mode
Rename the shared-mode host module from experimental to shared to match
the --mode=shared flag. No behavior changes.
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* refactor(kubernetes): drop the experimental prefix from the supervisor topology
Rename the Helm template to supervisor.yaml, its Kubernetes names and
labels to the -supervisor suffix and supervisor component, and the
driver setting to supervisor_topology. The setting remains opt-in and
workspace remains reserved.
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
---------
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* refactor(tests): move tmachine support files under tests/tmachine
Ansible, cloud-init, and the tmachine Nix config belong to tmachine, so
they now live in tests/tmachine/ alongside the crate, which moves to
tests/tmachine/cli/. tests/suites/ and tests/support/ are unchanged.
tmachine still runs from the directory holding ansible/, so playbook
paths stay the same; only inputs outside that directory gain a ../
prefix. The Nix build of tmachine and the base images are identical to
before.
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
* refactor(tests): name the tmachine crate directory orchestrator
The crate boots VMs, provisions them with Ansible, runs suites, and
caches disks; the other entries in tests/tmachine/ are its config.
Name the directory for that role rather than for the command-line
entry point.
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
* refactor(tests): keep the tmachine crate at tests/tmachine
Put the crate back at tests/tmachine/, next to the Ansible and Nix config
it uses, instead of in a subdirectory. Build tmachine from a fileset of
Cargo.toml, Cargo.lock, and src/ so edits to that config do not rebuild
the binary.
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
---------
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
OCI images commonly ship an empty /etc/hosts and rely on the container runtime to bind-mount a generated one. The VM driver does not, and guest init wrote /etc/hostname and /etc/resolv.conf but never /etc/hosts, so localhost did not resolve: the guest resolver is the loopback relay, which has no record for it.
Add configure_hosts to guest init, called after configure_hostname. It writes IPv4 and IPv6 localhost entries when the file is missing or empty, keeps a non-empty file and leaves a symlink alone, because an absolute link target would resolve against init's own root. A write failure logs a warning and boot continues.
Cover the file states and the boot-path call site with tests that run the shipped init function under bash.
Closes#3934
Signed-off-by: Shiju <shiju@nvidia.com>
Go resolves the sdk/go submodule version from sdk/go/vX.Y.Z tags, so
without one pkg.go.dev only shows v0.0.0 pseudo-versions from main. Add
a Release Tag job that creates the prefixed tag at the release commit
and asks the Go module proxy to fetch it.
Signed-off-by: Jim Meyer <jimeyer@nvidia.com>
* docs(providers): close stdin in the openrouter smoke test
The sandbox main process keeps stdin open so attach and detach work,
and opencode run reads stdin until EOF, so the documented smoke test
never printed a result. Run it through sh -c with stdin redirected from
/dev/null and note why.
Closes#3883
Signed-off-by: fede-kamel <fkamelhar@gmail.com>
* Remove verbose comment in providers/openrouter.yaml
---------
Signed-off-by: fede-kamel <fkamelhar@gmail.com>
Co-authored-by: Taylor Mutch <taylormutch@gmail.com>
When a gateway replica accepts a credential for the first time, it now
emits an Informational OCSF Authentication event with status Success.
The caller's request proceeds exactly as before. The event records:
- Who: the principal (user, mTLS operator, sandbox, or gateway peer),
with the same user types as authorization denials.
- How: the authentication protocol (OpenID, mtls, sandbox_jwt,
compute_driver, or k8s_service_account).
- Where: the gRPC method of the request that logged on.
- Correlation: the caller's address and request ID, the same fields the
failure and denial events carry.
Every gRPC request authenticates, and an idle sandbox's supervisor polls
the gateway several times a minute, so an event per request would bury
user logons. Each credential therefore logs on once: later requests with
the same bearer token or client certificate emit nothing until the
credential has been in use for an hour, when it logs on again. The
replica's connections share this record, which holds up to 16,384
credentials and forgets the oldest early when a new one arrives while
full. It keys on a SHA-256
digest of the credential that authenticated the caller (the bearer
token or the client certificate's fingerprint), so headers the
authenticator ignored cannot force new logons, and a renewed certificate
for the same subject logs on again. Digests stay in memory.
Requests admitted by allow_unauthenticated_users, or by a gateway with
no authentication configured, emit no success event, since no credential
was verified.
Refs #2912
Signed-off-by: Kris Hicks <khicks@nvidia.com>
* ci(release): reuse the promoted prerelease's release notes preview
Stable releases now publish the selected prerelease's release-notes
artifact with the prerelease tag replaced by the stable tag. Release
falls back to generating notes when the preview is missing, expired, or
malformed, or when dispatched with regenerate-notes=true. The selection
script exposes the qualified Pre-release run ID for the download.
Closes#4753
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
* ci(release): reuse release notes from the promotion job
Download and retag the preview in Select Qualified Prerelease, which
already knows the qualified Pre-release run, instead of a separate job.
Drop the regenerate-notes input and preview format checks.
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
* ci(release): name the publish notes input after the caller's result
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
---------
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
* feat(sandbox): support sandbox-initiated supervisor connections
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* refactor(sandbox): consolidate control transport setup
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* test(sandbox): remove prototype-specific unit tests
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* feat(kubernetes): migrate legacy control flow on restart
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* docs: remove prototype changes from published docs
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* fix(sandbox): adapt reverse control to published backend protocol
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* feat(sandbox): initiate supervisor connections across compute drivers
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* fix(docker): stage reverse control socket for the supervisor identity
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* refactor(sandbox): keep runtime transports behind the backend
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* fix(docker): mount the runtime control volume read-only
The sandbox runtime only dials the supervisor-owned control socket, so
it does not need write access to the control volume. Mount it read-only
in the runtime container and stop staging the control directory through
the runtime bundle; the supervisor stager already initializes it through
its own writable mount.
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* fix(kubernetes): separate legacy and runtime-initiated control services
Keep os-boundary selecting the workload and add os-supervisor for runtime-initiated connections. Bind the mode marker to its runtime generation so a restart by an older gateway does not inherit stale mode metadata. Preserve the legacy Service across creation and restart, validate the active endpoint, and drop the Service patch permission.
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
---------
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
When the gateway refuses a caller that has already authenticated, it
now emits an OCSF API Activity event. The caller gets exactly the same
error as before. The event records:
- Who: the principal (user, mTLS operator, sandbox, or gateway peer).
- What: the gRPC method, plus the sandbox or workspace that was
refused when there is one.
- Why: a reason such as cross_sandbox, missing_role or
not_workspace_member.
- Correlation: the caller's address and request ID, the same fields
the authentication events carry.
That covers the denials made centrally by the router and the shared
guards, plus the checks inside handlers that have no shared guard: a
sandbox naming another sandbox (in either sandbox-name resolver), a
non-user caller refused by mutation admission, a sandbox sending a
config update it isn't allowed to, and a non-admin granting the
workspace admin role. Denials raised in the mutation admission worker,
which runs in a spawned task, keep the request's context.
When a sandbox credential is refused for calling a method it may not
call, touching another sandbox, or acting across workspaces, the
gateway also emits a High-severity Detection Finding. It carries the
same correlation_uid as the denial event. A real supervisor never makes
these requests, so a finding means the credential is probably being
misused. Two cases are recorded without a finding: a method the
gateway doesn't recognize (unknown_method), so a newer supervisor
doesn't look like a compromised one, and a supervisor whose own sandbox
was deleted mid-request, which is refused but isn't misuse.
The shorthand line names the refused sandbox or workspace, for example
sandbox:<id>, so operators reading console logs can see the target
without JSONL or OTLP export.
To support this, the OCSF crate's Actor can now hold a user instead of
a process, and the API Activity builder gained the fields gateway
events need. Supervisor inference events come out unchanged. Gateway
events declare the container profile only when they concern a sandbox,
as MXC findings do. The OCSF
1.8.0 resource_details schema is vendored so the refused sandbox or
workspace goes in the standard resources field.
Refs #2912
Signed-off-by: Kris Hicks <khicks@nvidia.com>
* fix(vm): flush guest filesystem before a planned sandbox stop
A planned stop of a MicroVM sandbox ended the VM before the guest wrote its dirty pages to disk, so files written shortly before the stop were missing after the next start.
The driver closed the host supervisor's parent-liveness pipe before it sent SIGTERM. The supervisor exits at once on that end-of-file, so it never ran its orderly shutdown: terminate the workload, then ask the guest to terminate. Signal the supervisor first, keep the pipe open until it has exited, and give it a grace period derived from the supervisor's own bounds and kept below the gateway's reclaim deadline.
In the guest runtime, syncfs the root filesystem after the process tree is terminated and before the termination is acknowledged, bounded to 3 seconds and best effort. Only the VM backend, which uses a vsock boundary listener, flushes; the container drivers share this runtime and are unchanged.
A sandbox whose main process has already exited is not covered.
Closes#4185
Signed-off-by: Shiju <shiju@nvidia.com>
* fix(vm): warn about unconfirmed flush after supervisor kill
Preserve the supervisor exit status so a planned stop warns when a signal
killed the supervisor and guest writeback was not confirmed. Keep normal
workload exit codes quiet, including 143 after a handled SIGTERM.
Extend the existing process tests to check the warning after a forced kill
and its absence after an orderly shutdown.
Refs #4185
Signed-off-by: Shiju <shiju@nvidia.com>
* fix(vm): satisfy shutdown timeout control-flow lint
Use if let for the single successful timeout pattern while preserving
the supervisor exit status and forced-kill error handling.
Signed-off-by: Shiju <shiju@nvidia.com>
* fix(vm): preserve shutdown merge resolutions during rebase
Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>
* docs(vm): explain planned stop durability and flush limits
Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>
---------
Signed-off-by: Shiju <shiju@nvidia.com>
Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>
Co-authored-by: John Myers <9696606+johntmyers@users.noreply.github.com>
* fix(snap): only enable gateway user service for one user
Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
* docs(snap): correct snap docs for the gateway user service
Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
* fix(snap): add documentation of global to per-user enablement migration
Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
---------
Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
* fix(ocsf): report https scheme for TLS-terminated requests
Closes#4562
Signed-off-by: Eric Curtin <eric.curtin@docker.com>
* fix(ocsf): use transport scheme on passthrough relay
Signed-off-by: Eric Curtin <eric.curtin@docker.com>
---------
Signed-off-by: Eric Curtin <eric.curtin@docker.com>
* fix(server): warn on dangling provider refs at startup
Signed-off-by: Eric Curtin <eric.curtin@docker.com>
* fix(server): load providers concurrently at startup
Signed-off-by: Eric Curtin <eric.curtin@docker.com>
---------
Signed-off-by: Eric Curtin <eric.curtin@docker.com>
helm push uploads the chart manifest by digest, then fetches it back to
apply the version tag. GHCR sometimes returns 404 for a manifest it just
accepted, failing the push with 'failed to perform "Tag" on
destination: <digest>: not found'. This failed Release Dev on Oct 5 and
the v0.1.5-pre.2 Release Tag run after qualification passed.
Retry each chart push up to four times with a short backoff. A retry
finds the blobs and manifest already present and only applies the tag.
Closes#4577
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
* ci(release): name the failed stage and failing jobs in pre-release failure notices
The pre-release failure notification said only that the run failed.
Name the failed stage (build, publication, or release qualification),
link the tag, and list each failing job of the run attempt with a link.
Skip the aggregate Release Qualification job unless it is the only
failure, and still send the message if the jobs lookup fails.
Closes#4718
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
* ci(release): simplify the failure notice to a list of failed jobs
Drop the stage headline and the aggregate-job filtering. Keep the
existing message and append a link to each failed job.
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
---------
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
* ci(release): promote qualified prereleases to stable
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
* fix(release): preserve qualified images during stable publication
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
* ci(release): run shared release jobs with Nix
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
* fix(release): recheck latest before publishing shared channels
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
---------
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
* fix(tmachine): link libstdc++ statically and verify static musl binaries
On macOS hosts, the aarch64 musl openshell-prover that
build-artifacts-binaries produced was not static. z3-sys asks for a
dynamic libstdc++ (-Wl,-Bdynamic -lstdc++), and the musl cross compiler
wrapper resolved libstdc++.so. The result was a static executable with a
DT_NEEDED entry for libstdc++.so.6 and no interpreter, which crashed
during C++ static initialization. The local Debian package from #4598
ships this prover without running it.
Build the musl binaries with CXXSTDLIB=static:-bundle=stdc++ so z3-sys
requests a static libstdc++. CXXSTDLIB applies to every target and
Darwin has no libstdc++, so set it only on this musl build rather than in
the shared toolchain environment. The bundled form, static=stdc++, fails
because rustc cannot find libstdc++.a on its own search path.
Run tasks/scripts/verify-static-binary.sh on the musl CLI, sandbox and
prover, as the release does, so a binary that is not fully static fails
the local build.
Signed-off-by: Evan Lezar <elezar@nvidia.com>
* feat(tmachine): build local RPM artifacts
Add build-artifacts-rpm, which builds the CLI and gateway RPMs that
tmachine's rpm installer expects at artifacts/packages/rpm/openshell.rpm
and artifacts/packages/rpm/openshell-gateway.rpm. It runs
`packit build locally` with openshell.spec in the Fedora 44 image that
build-rpm.yml uses, for the host's Linux architecture, and packages the
binaries staged by build-artifacts-binaries. The package version defaults
to the development version that branch E2E CI computes.
The aggregate build-artifacts app runs the RPM step after the DEB step.
Signed-off-by: Evan Lezar <elezar@nvidia.com>
---------
Signed-off-by: Evan Lezar <elezar@nvidia.com>
OCSF 1.8 requires type_id on the os object, but device.os carried only
a name. Events now report Linux (200), Windows (100), macOS (300), or
Other (99) with the platform name as the type label. The os object
schema is vendored so tests validate it.
Refs #2912
Signed-off-by: Kris Hicks <khicks@nvidia.com>
Authentication events now carry the connection's immediate peer as
src_endpoint, or edge-tunnel for WebSocket-tunneled requests, and the
request's x-request-id as metadata.correlation_uid when it is a UUID.
Refs #2912
Signed-off-by: Kris Hicks <khicks@nvidia.com>
Supervisors poll the gateway for configuration every 10 seconds. This PR adds an opt-in push mode (config_delivery_mode = "push"): supervisors still start by polling, and once their ConnectSupervisor session is accepted, the gateway delivers every later change over it and supervisors apply it and report the result. poll stays the default, and older supervisors and gateways keep polling.
---------
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
Signed-off-by: divesh <dgude@nvidia.com>
Co-authored-by: divesh <dgude@nvidia.com>
Authenticators now return the mechanism and a reason category with the
status they reject a request with, and the gateway router records both
in the Authentication event. Callers still receive the original status.
Refs #2912
Signed-off-by: Kris Hicks <khicks@nvidia.com>
* perf(server): drop async_trait from mutation replay
Mutation is never used as a trait object, so the boxed futures from
#[tonic::async_trait] buy nothing. Declare its methods as
-> impl Future + Send instead. This keeps the Send guarantee, removes a
heap allocation per call, and cuts a cold openshell-server lib build from
~60s to ~36s.
Box the approve_all_draft_chunks future at its call sites, since it is no
longer boxed implicitly and trips clippy::large_futures.
Closes#4618
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
* perf(supervisor): drop async_trait from generic-only gateway traits
StartupGateway, PolicyGatewayClient, and ReportClient are only used
through generic parameters, never as trait objects. Declare their methods
as -> impl Future + Send instead of boxing each future.
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
---------
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
* fix(ci): make conformance-only e2e selection explicit
Signed-off-by: Evan Lezar <elezar@nvidia.com>
* fix(ci): use mapped NodePort for kind gateway sessions
Signed-off-by: Evan Lezar <elezar@nvidia.com>
* fix(ci): waive SSH transport recovery only on Kubernetes
Signed-off-by: Evan Lezar <elezar@nvidia.com>
* fix(e2e): log a notice when runners skip Rust e2e tests
Emit a GitHub Actions notice from the Docker, Podman, Kubernetes, and VM
runners when e2e-conformance-only skips the Rust tests, so a narrowed lane
is visible in the job summary instead of silently reporting success.
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
* docs(testing): move e2e conformance-only selector to shared section
The selector applies to all four driver runners, so document it with the
Rust CLI e2e suites instead of under the Kubernetes task variants.
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
---------
Signed-off-by: Evan Lezar <elezar@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Co-authored-by: Matthew Grossman <mgrossman@nvidia.com>
The endpoint-status startup sweep ran before the gateway installed its
Prometheus recorder, so the lock waits, timeouts, errors and hold times
it recorded went to the no-op recorder and only its warnings reached
the log. The sweep retries lock timeouts for up to three lock waits
before startup fails, and a slow sweep that still succeeds is what
operators want to see in the lock metrics.
When metrics are enabled, the recorder is now installed before startup
reconciliation, and the metrics listener still binds with the other
listeners. A new pod's first scrape therefore already holds the sweep's
samples, so they show in the raw counter and histogram count values,
not in rate() or increase(). A sweep that fails still exits before any
listener binds, so its timeouts remain log-only.
The startup lock-timeout test now waits for the sweep's timeout counter
instead of a fixed sleep and checks its timeout and wait samples, and
the debug skill says which startup timeouts reach the metrics and how
to read them.
Part of #4307Closes#4523
Signed-off-by: Emilien Macchi <emacchi@redhat.com>
Requests the gateway rejects before consulting any authenticator now emit
an OCSF Authentication [3002] event: no credential presented, mTLS
required without a client certificate, or an operator certificate
combined with an authorization header. Each event carries a reason
category in status_detail and never the presented credential. The
response returned to the caller is unchanged.
openshell-ocsf gains the Authentication class with user and service
objects, and a shared OcsfCapture test layer. Schema validation now
rejects attributes the class does not define and profile attributes
whose profile the event does not declare.
Refs #2912
Signed-off-by: Kris Hicks <khicks@nvidia.com>
* feat(vm): add host bind mount support via virtiofs (libkrun)
Introduce host directory bind mounts for libkrun VM sandboxes using
the virtiofs4 API with simplified permission semantics. The gateway
accepts `enable_bind_mounts` in the `[openshell.drivers.vm]` TOML
table and forwards it to the VM driver subprocess.
Mounts are specified per-sandbox in driver_config.mounts[] with
source, target, optional read_only (default: read-only), and an
optional `type` that must be `bind`, so Docker and Podman bind entries
(without `selinux_label`) parse unchanged.
At sandbox validation the driver rejects mounts unless bind mounts
are enabled and resource admission is disabled. It rejects GPU and
other QEMU launches, sources with control characters, and more mounts
than libkrun has interrupt lines for (32 on aarch64, 3 on x86_64), and
checks targets against reserved VM-internal directories and each other
(no nested targets). The QEMU check runs again once the launch backend
is resolved.
Host source directories are checked at provisioning, before image
preparation, so a briefly missing source fails provisioning visibly
instead of denying recovery of a persisted sandbox. Missing,
inaccessible, symlinked, non-directory, and unreadable sources are
rejected: libkrun does not follow a final symlink, and on macOS it
panics during guest boot when it cannot open the share root.
The driver generates virtiofs tags and always writes a guest-side
manifest into the overlay disk, together with the init drop-ins, so an
image-supplied manifest can never drive guest mounts. The launcher
parses its tab-separated --vm-mount arguments from the right, so a
source can never shift the tag or mode, and the driver logs each
shared directory at launch.
Guest init mounts the shares after every /sandbox ownership fixup
and the init drop-ins, so recursive chowns never reach host files.
It refuses targets that traverse symlinks in the image, hands newly
created mount point parents under /sandbox to the sandbox user, and
skips an empty manifest.
krun_add_virtiofs4 is resolved optionally, so older libkrun runtimes
still boot sandboxes without mounts.
The kernel config lists CONFIG_FUSE_FS and CONFIG_VIRTIO_FS
explicitly; the pinned libkrunfw base config already enables both.
A vm_bind_mount e2e test checks a read-write share round-trips data
with the host, accepts a new file, directory, and nested file that the
host then sees, and that a read-only share rejects writes. libkrun on
rootless Linux refuses file creation by a guest user whose UID/GID
differ from its own, so the VM e2e gateway runs the sandbox as the
gateway user there. It enables bind mounts like the Docker and Podman
e2e gateways.
The runtimes docs cover the mount limit, the symlink restriction, the
guest-kernel exposure, and the rootless Linux UID/GID note. The
debug-openshell-cluster skill lists VM bind mount checks.
Signed-off-by: Florent Benoit <fbenoit@redhat.com>
* fix(nix): refresh vm-runtime hashes to the libkrun v1.19.4 runtime
The Nix vm-runtime package fetches the rolling vm-runtime release with
fixed hashes pinned on 2026-09-16. The release was rebuilt on
2026-09-21 after the libkrun v1.19.4 / libkrunfw v5.6.1 bump (#3451),
but the hashes were not updated, so CI kept substituting the
2026-09-15 runtime (libkrun v1.17.4) from the binary cache.
That libkrun lacks krun_add_virtiofs4, which VM bind mounts need.
Point the hashes at the current release assets.
Signed-off-by: Florent Benoit <fbenoit@redhat.com>
---------
Signed-off-by: Florent Benoit <fbenoit@redhat.com>
* feat(sdk/go)!: replace positional labels with functional Create options
Move labels and annotations from separate parameter positions into
functional options (WithLabels, WithAnnotations) on Create() and
CreateFromTemplate().
Before: Create(ctx, ws, name, spec, labels, CreateOptions{Annotations: ann})
After: Create(ctx, ws, name, spec, WithLabels(labels), WithAnnotations(ann))
This unifies two resource metadata fields that were inconsistently
placed (labels as positional, annotations in a struct) into a single
extensible options pattern matching the existing LogOption convention.
BREAKING CHANGE: Create() and CreateFromTemplate() signatures changed.
All callers must use WithLabels() and WithAnnotations() functional
options instead of positional labels and CreateOptions struct.
Closes#2807
Signed-off-by: Roland Huß <rhuss@redhat.com>
* fix(sdk/go): ignore nil Create options
Callers of the previous signature passed nil for the positional labels
parameter to create an unlabeled sandbox:
Create(ctx, ws, name, spec, nil)
That call still compiles against the new variadic signature, because an
untyped nil converts to CreateOption. ApplyCreateOptions then invoked it
and panicked with a nil pointer dereference, so the migration was unsafe
for existing consumers.
Skip nil options in ApplyCreateOptions and cover the legacy trailing-nil
call with regression tests against ApplyCreateOptions directly, the fake
client (Create and CreateFromTemplate), and the gRPC client.
Signed-off-by: Roland Huß <rhuss@redhat.com>
* refactor(sdk/go): apply Create options through the shared options helper
Signed-off-by: Roland Huß <rhuss@redhat.com>
* docs(sdk/go): use WithLabels in CreateSandboxFromTemplate examples
Signed-off-by: Roland Huß <rhuss@redhat.com>
---------
Signed-off-by: Roland Huß <rhuss@redhat.com>