Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions controller/cmd/exporter-set-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
_ "k8s.io/client-go/plugin/pkg/client/auth"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
Expand All @@ -38,6 +39,7 @@ import (
"github.com/jumpstarter-dev/jumpstarter/controller/internal/exporterset"
"github.com/jumpstarter-dev/jumpstarter/controller/internal/exporterset/provisioners/cuttlefish"
"github.com/jumpstarter-dev/jumpstarter/controller/internal/exporterset/provisioners/qemu"
qemussh "github.com/jumpstarter-dev/jumpstarter/controller/internal/exporterset/provisioners/qemu-ssh"
)

var (
Expand Down Expand Up @@ -102,13 +104,6 @@ func main() {
os.Exit(1)
}

// Select the provisioner implementation based on the flag
prov, err := selectProvisioner(provisioner)
if err != nil {
setupLog.Error(err, "unsupported provisioner", "provisioner", provisioner)
os.Exit(1)
}

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
Cache: cache.Options{
Expand All @@ -129,6 +124,16 @@ func main() {
os.Exit(1)
}

// Select the provisioner implementation based on the flag.
// Some provisioners (e.g. qemu-ssh) need a Kubernetes client for
// reading Secrets and updating annotations, so we create them after
// the manager is initialized.
prov, err := selectProvisioner(provisioner, mgr.GetClient())
if err != nil {
setupLog.Error(err, "unsupported provisioner", "provisioner", provisioner)
os.Exit(1)
}

if err = (&exporterset.ExporterSetReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Expand Down Expand Up @@ -158,16 +163,18 @@ func main() {

// selectProvisioner returns the Provisioner implementation for the given name.
// Add new provisioners here as they are implemented.
func selectProvisioner(name string) (exporterset.Provisioner, error) {
func selectProvisioner(name string, c client.Client) (exporterset.Provisioner, error) {
switch name {
case cuttlefish.ProvisionerName:
return cuttlefish.New(version), nil
case qemu.ProvisionerName:
return qemu.New(version), nil
case qemussh.ProvisionerName:
return qemussh.New(version, c), nil
default:
return nil, fmt.Errorf(
"unknown provisioner %q; supported: %s, %s",
name, qemu.ProvisionerName, cuttlefish.ProvisionerName,
"unknown provisioner %q; supported: %s, %s, %s",
name, qemu.ProvisionerName, cuttlefish.ProvisionerName, qemussh.ProvisionerName,
)
}
}
23 changes: 23 additions & 0 deletions controller/config/samples/operator_jumpstarter_with_qemu_ssh.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Jumpstarter operator CR — enabling both in-cluster QEMU and off-cluster
# QEMU-SSH provisioners.
#
# Apply with: kubectl apply -f operator_jumpstarter_with_qemu_ssh.yaml
apiVersion: operator.jumpstarter.dev/v1alpha1
kind: Jumpstarter
metadata:
name: jumpstarter
namespace: jumpstarter
spec:
exporterSets:
# Container image for the exporter-set controller binary.
# All provisioners share the same binary; --provisioner selects
# the backend at startup.
image: quay.io/jumpstarter-dev/exporter-set-controller:latest
provisioners:
# In-cluster QEMU provisioner (creates Pods with QEMU sidecar)
- name: qemu.jumpstarter.dev
enabled: true
# Off-cluster QEMU provisioner (deploys containers on remote
# hosts via SSH using Podman quadlets)
- name: qemu-ssh.jumpstarter.dev
enabled: true
26 changes: 26 additions & 0 deletions controller/config/samples/secret_ssh_credentials.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# SSH credentials Secret — required by the qemu-ssh.jumpstarter.dev
# provisioner for authenticating to remote lab hosts.
#
# The credentialsSecretRef in the VirtualTargetClass points to this
# Secret. It uses the standard kubernetes.io/ssh-auth type.
#
# Note: kubernetes.io/ssh-auth only carries the private key. The SSH
# username is configured in the VirtualTargetClass parameters
# (parameters.ssh.user or parameters.host.user), not in this Secret.
#
# Create from a file (preferred):
# kubectl create secret generic lab-ssh-key \
# --from-file=ssh-privatekey=$HOME/.ssh/id_ed25519 \
# -n jumpstarter
#
# Or apply this manifest after base64-encoding your key:
# cat ~/.ssh/id_ed25519 | base64 -w0
apiVersion: v1
kind: Secret
metadata:
name: lab-ssh-key
namespace: jumpstarter
type: kubernetes.io/ssh-auth
data:
# Replace with your base64-encoded SSH private key

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.

is there a standard way to pass the username here as well?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

kubernetes.io/ssh-auth only defines ssh-privatekey, so the username should stay in the VTC parameters. I added a comment to the secret sample to make that clearer, and also updated the VTC sample to the new single-host model.

ssh-privatekey: <BASE64_ENCODED_SSH_PRIVATE_KEY>
44 changes: 44 additions & 0 deletions controller/config/samples/v1alpha1_exporterset_qemu_ssh.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# ExporterSet — off-cluster QEMU aarch64 pool via SSH
#
# This example creates a scalable pool of aarch64 virtual targets
# running as Podman containers on remote lab hosts. The
# exporter-set controller manages the lifecycle via SSH.
#
# Uses the qemu-ssh-aarch64 VirtualTargetClass (see
# v1alpha1_virtualtargetclass_qemu_ssh.yaml).
apiVersion: virtualtarget.jumpstarter.dev/v1alpha1
kind: ExporterSet
metadata:
name: aarch64-ssh-pool
namespace: jumpstarter
spec:
minReplicas: 0
maxReplicas: 4
minAvailableReplicas: 1
scaleDownCooldown: 5m
recycleStrategy: ExitAndReplace
virtualTargetClassName: qemu-ssh-aarch64
# Override class-level resource defaults (deep-merged)
parameters:
resources:
memory: 8Gi
selector:
matchLabels:
board: aarch64-qemu
virtual: "true"
template:
metadata:
labels:
board: aarch64-qemu
arch: aarch64
virtual: "true"
spec:
drivers:
- name: qemu
type: jumpstarter_driver_qemu.driver.Qemu
- name: power
type: jumpstarter_driver_power.driver.QemuPower
- name: serial
type: jumpstarter_driver_serial.driver.QemuSerial
# tcp driver is auto-injected by the provisioner (ssh
# hostfwd on port 2222) — no need to specify it explicitly
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# VirtualTargetClass — off-cluster QEMU via SSH
#
# This example defines a virtual target profile for aarch64 targets
# running on a remote lab host (bare metal or VM with KVM). The
# exporter-set controller connects via SSH and deploys Podman
# containers (quadlets) on the host.
#
# Each ExporterSet manages one host. To use multiple hosts, create
# additional ExporterSets under this same VirtualTargetClass.
#
# Prerequisites:
# 1. Create the SSH credentials Secret:
# kubectl create secret generic lab-ssh-key \
# --from-file=ssh-privatekey=$HOME/.ssh/id_ed25519 \
# -n jumpstarter
# 2. Ensure the remote host has Podman and systemd installed.
# 3. Enable qemu-ssh.jumpstarter.dev provisioner in the Jumpstarter CR.
apiVersion: virtualtarget.jumpstarter.dev/v1alpha1
kind: VirtualTargetClass
metadata:
name: qemu-ssh-aarch64
namespace: jumpstarter
spec:
provisioner: qemu-ssh.jumpstarter.dev
credentialsSecretRef:
name: lab-ssh-key
bindingMode: Immediate
reclaimPolicy: Delete
parameters:
# SSH connection defaults (per-host overrides available in host)
ssh:
user: root
port: 22
# Remote lab host for this ExporterSet
host:
name: lab-host-01.example.com
# Runtime container configuration
runtime:
kvm: true # pass /dev/kvm into the QEMU runtime container
# Default resource allocation per virtual target
arch: aarch64
resources:
cpu: 4
memory: 4Gi
storage:
size: 16Gi
18 changes: 9 additions & 9 deletions controller/deploy/operator/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ go 1.26.3

require (
github.com/cert-manager/cert-manager v1.18.6
github.com/go-logr/logr v1.4.3
github.com/google/uuid v1.6.0
github.com/jumpstarter-dev/jumpstarter/controller v0.7.1
github.com/onsi/ginkgo/v2 v2.22.2
Expand All @@ -15,7 +14,6 @@ require (
k8s.io/apimachinery v0.34.1
k8s.io/apiserver v0.34.1
k8s.io/client-go v0.34.1
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d
sigs.k8s.io/controller-runtime v0.22.3
sigs.k8s.io/yaml v1.6.0
)
Expand Down Expand Up @@ -48,6 +46,7 @@ require (
github.com/gin-gonic/gin v1.10.0 // indirect
github.com/go-chi/chi/v5 v5.2.0 // indirect
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.22.1 // indirect
Expand Down Expand Up @@ -111,16 +110,16 @@ require (
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.47.0 // indirect
golang.org/x/crypto v0.57.0 // indirect
golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 // indirect
golang.org/x/net v0.49.0 // indirect
golang.org/x/net v0.58.0 // indirect
golang.org/x/oauth2 v0.34.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/term v0.39.0 // indirect
golang.org/x/text v0.33.0 // indirect
golang.org/x/sync v0.23.0 // indirect
golang.org/x/sys v0.48.0 // indirect
golang.org/x/term v0.46.0 // indirect
golang.org/x/text v0.42.0 // indirect
golang.org/x/time v0.13.0 // indirect
golang.org/x/tools v0.40.0 // indirect
golang.org/x/tools v0.49.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260120221211-b8f7ae30c516 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
Expand All @@ -134,6 +133,7 @@ require (
k8s.io/component-base v0.34.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0 // indirect
sigs.k8s.io/gateway-api v1.4.0 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
Expand Down
28 changes: 14 additions & 14 deletions controller/deploy/operator/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,8 @@ golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M=
golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA=
golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 h1:R9PFI6EUdfVKgwKjZef7QIwGcBKu86OEFpJ9nUEP2l4=
golang.org/x/exp v0.0.0-20250718183923-645b1fa84792/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
Expand All @@ -261,37 +261,37 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk=
golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
golang.org/x/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE=
golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI=
golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E=
golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI=
golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
18 changes: 10 additions & 8 deletions controller/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0
github.com/onsi/ginkgo/v2 v2.22.2
github.com/onsi/gomega v1.36.2
github.com/pkg/sftp v1.13.11
github.com/prometheus/client_golang v1.22.0
github.com/prometheus/client_model v0.6.1
github.com/prometheus/common v0.62.0
github.com/zitadel/oidc/v3 v3.34.1
golang.org/x/crypto v0.57.0
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
golang.org/x/sync v0.19.0
golang.org/x/sync v0.23.0
google.golang.org/genproto/googleapis/api v0.0.0-20260120221211-b8f7ae30c516
google.golang.org/grpc v1.80.0
google.golang.org/protobuf v1.36.11
Expand Down Expand Up @@ -66,13 +68,14 @@ require (
github.com/google/btree v1.1.3 // indirect
github.com/google/cel-go v0.23.2 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-cmp v0.7.0
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
Expand Down Expand Up @@ -102,14 +105,13 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.47.0 // indirect
golang.org/x/net v0.49.0 // indirect
golang.org/x/net v0.58.0 // indirect
golang.org/x/oauth2 v0.34.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/term v0.39.0 // indirect
golang.org/x/text v0.33.0 // indirect
golang.org/x/sys v0.48.0 // indirect
golang.org/x/term v0.46.0 // indirect
golang.org/x/text v0.42.0 // indirect
golang.org/x/time v0.9.0 // indirect
golang.org/x/tools v0.40.0 // indirect
golang.org/x/tools v0.49.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
Expand Down
Loading
Loading