51 documented changes.

Version
1.0.0
Released
Oct 9, 2026
Product
vpctl
vpctl changelog

vpctl 1.0.0

Official notes

Added

  1. Feature

    The `shdctl secret export` command rebuilds a secrets import file from the secrets already deployed in a cluster, for when the file you deployed with is gone. The result goes straight back into `shdctl secret generate --import` . For the flags and the values it exports, refer to Recover the import file from a cluster.

  2. Feature

    Anything the cluster has no usable value for is listed at the end. Supply those values by hand before you run `secret generate` , or it generates new values, and deploying them breaks whatever still uses the old ones.

  3. Feature

    The command needs a kubeconfig with the `list` verb on secrets in the namespace, which is more than a deployment pipeline needs. Run it as an operator rather than widening a CI role.

  4. Feature

    The file it writes holds your secrets in the clear (mode `0600` ): keep it in your secret store, not in Git.

  5. Feature

    `configuration.overrides..values` is now a documented, supported manifest field: a per-chart layer of extra Helm values, applied after every layer the release ships, for when a chart needs a setting the manifest doesn't expose. The field is unchanged since 0.13.0, and nothing in your manifest needs to move; what's new is that its behavior is specified and supported. For the merge semantics and the list-patching form, refer to Per-chart Helm value overrides.

  6. Feature

    The `_arrayMerge` key mentioned in 0.10.0 is no longer accepted. `shdctl release generate` stops and points at the list-patching form that replaces it.

  7. Feature

    A chart name the release doesn't contain now fails generation with the release's chart names listed.

  8. Feature

    It stays a last resort: `shdctl manifest validate` can't catch a key you misspelled under `values:` , and a chart's value keys can move between releases. Read the generated `values.yaml` before you deploy, check your overrides again after each upgrade, and tell Unity what you had to override, so that the setting can become a manifest field of its own.

  9. Feature

    The `configuration.objectStore` manifest field selects where S3-compatible object storage comes from. `provider: garage` is the default, and what every existing manifest gets: the in-cluster store, unchanged. `provider: s3` points transformation step logs, MongoDB backups, and Unity Studio publications at an endpoint you own, and stops deploying the in-cluster store. For the endpoint grammar, the behavior of each bucket, and the warnings that shdctl emits for a partial configuration, refer to Bringing your own object storage.

  10. Feature

    With `s3` , `endpoint` , `region` , and the three bucket names are required, and `shdctl manifest validate` names the one you left out. `buckets.postgresBackups` is optional: setting it moves the pgBackRest repository off its persistent volume, and requires an `https` endpoint.

  11. Feature

    `buckets.studioAssets` needs a CORS rule and an `https` endpoint, and shdctl checks neither: both fail only in the browser, while the server reports success.

  12. Feature

    `shdctl secret generate` prompts for the object store's access key pair instead of generating one. That pair must be able to read, write, and delete in every bucket you name. `--use-defaults` without `--import` leaves it at the `TBD` placeholder, so don't deploy that snapshot.

  13. Feature

    `shdctl artifact sync images` stops mirroring the in-cluster store's images with `s3` , so if you switch back, run the sync again before you deploy.

  14. Feature

    `artifact sync images` now also mirrors the Docker images that a release manifest's artifacts run, not just the artifacts themselves. There's nothing to do beyond the sync you already run, but expect more images to be copied, and `--dry-run` to contact the source registry.

  15. Feature

    The `shdctl artifact sync verify` command reports what a target registry holds against what your manifest requires, without writing to it. Missing images make it exit with a non-zero code, so a pipeline can gate a deployment on it. It reads release manifests from the target registry, so it works air-gapped. For the flags, refer to Verify the target registry.

  16. Feature

    A probe can't tell "not found" from "not authorized", so an expired credential looks exactly like an empty registry. When every required image comes back missing, `verify` says so, and points you at `shdctl artifact sync preflight` : run that first.

  17. Feature

    "Present but not required" covers only the images this release defines. Tags left by earlier releases aren't reported.

  18. Feature

    The `configuration.infrastructure.components.postgresql.backupStorage` manifest field sizes the volume that the pgBackRest repository sits on, independently of `storage` . If you leave it out, the sizing profile's default applies (100Gi on `small` , 800Gi on `medium` , 1600Gi on `large` ). When `configuration.objectStore.buckets.postgresBackups` is set, no backup volume is provisioned at all, and `release generate` warns that this field is ignored. A persistent volume can't shrink, so a value below what a deployed cluster already has is refused, and the volume stays as it was.

  19. Feature

    The `configuration.kubernetes.podAnnotations` manifest field holds annotations that `release generate` adds to every pod the release creates, for example `kubernetes.azure.com/no-http-proxy-vars: "true"` on AKS with an HTTP proxy. A chart's `configuration.overrides` can change or remove one for that chart. For the field, refer to the annotated example.

Changed

  1. Change

    The `vpctl` command is now `shdctl` . The tool was named for "Virtual Private Cloud", which the product is no longer called: it's a Self-Hosted Deployment, so the tool is `shdctl` . Install it with `install-shdctl.sh` , which also leaves a `vpctl` symlink so that your existing scripts keep running; they print a notice that names the new command. Install the new version, and at your convenience, switch your scripts to `shdctl` , `SHDCTL_USERNAME` and `SHDCTL_PASSWORD` , and `install-shdctl.sh` . Everything in the following table keeps working throughout shdctl 1.x, and stops working in shdctl 2.0.0: You have Still works in 1.x Replace with The `vpctl` command Yes, with a notice `shdctl` `VPCTL_USERNAME` and `VPCTL_PASSWORD` Yes, with a notice `SHDCTL_USERNAME` and `SHDCTL_PASSWORD` Credentials in `~/.vpctl/config.json` Yes, read in place Run `shdctl configure ` to move them `install-vpctl.sh` run from a checkout or a release tarball Yes, it forwards `install-shdctl.sh` Two things aren't on that schedule. The old download path ( `releases/cli/vpctl__` ) is still published until Unity announces otherwise, because a vendored installer fails there with an unclear registry error that upgrading can't fix. And `compatibility.yaml` keeps carrying `minVpctlVersion` alongside the new `minShdctlVersion` , so a 0.13.0 or earlier binary pointed at this release still enforces a minimum version rather than silently accepting it.

  2. Change

    Breaking: `shdctl release generate` now refuses `--clean-output` together with `--name` , before it deletes anything. Run a full `shdctl release generate` instead; `--name` on its own is unchanged.

  3. Change

    Breaking: a manifest whose `configuration.kubernetes.docker.repository` is `artifactSync.sourceRepository` can no longer set `docker.namespace` : every command that reads the manifest refuses it, `shdctl manifest validate` and `cluster check` included. Remove `docker.namespace` when you pull straight from Unity's registry.

  4. Change

    Breaking: deleting the top-level `asset-solutions` application no longer tears down the deployment. It now leaves the child applications and their workloads running, and reapplying `app-of-apps-application.yaml` adopts them again. To remove a deployment, delete the top-level application first, then the child applications: while it exists, it recreates any child you delete.

  5. Change

    `shdctl artifact sync` now checks the release package's minimum shdctl version, like `release generate` , `secret generate` , and `secret export` already did. To bypass the check, pass `--skip-version-check` .

  6. Change

    The chart index that `shdctl release generate` writes is now `charts-metadata.yaml` , previously `vpctl-metadata.yaml` . `shdctl release deploy` reads either, so a tree that an earlier version generated still deploys. If your GitOps repository has the old file committed, regenerating drops it.

  7. Change

    Logs now go to stderr rather than stdout, so a command's own output, such as a `--dry-run` command list, the `cluster check` results, or a `verify` report, no longer risks a warning landing in the middle of it. If you redirected `shdctl ... > file` to capture log output, redirect stderr instead.

  8. Change

    `configuration.overrides` now honors `null` on any key, not only on keys that hold a single value: setting a key whose value is a map or a list to `null` now removes it. If a manifest of yours sets a map or a list to `null` , read the generated `values.yaml` once before your next deployment. Setting a key to `{}` or `[]` is unchanged.

  9. Change

    `shdctl cluster check` now requires Kubernetes 1.34 or later: a cluster on 1.33 fails the version check instead of passing it. Kubernetes 1.33 is past its upstream end of life, and past Amazon EKS standard support.

  10. Change

    `shdctl cluster check` now fails when the cluster has no default storage class, even if the manifest sets `configuration.kubernetes.storage.defaultStorageClass` , and warns when that class isn't the cluster default. The field applies only to Garage and the licensing server; every other `ReadWriteOnce` volume uses the cluster's default storage class. If the check fails, mark a storage class as the cluster default before you deploy. `--probe-storage` now probes the cluster default, plus the manifest's class when it's different.

  11. Change

    `shdctl secret generate` now also generates the image pull secret named by `configuration.kubernetes.imagePullSecret` , into the same file as the release secrets, so `shdctl secret deploy` creates it along with everything else, and you no longer need the separate `kubectl create secret docker-registry` step. It carries the container registry credentials you already supply for `acr-oras-credentials` , for the registry your manifest pulls images from ( `configuration.kubernetes.docker.repository` , or `artifactSync.sourceRepository` when no mirror is configured). If anything other than shdctl creates that secret in your cluster, such as a refresher for a registry that issues short-lived credentials (ECR tokens expire after 12 hours), turn generation off in your manifest before your next `secret generate` , so that the generated snapshot doesn't overwrite the live credential when you deploy: `configuration: kubernetes: imagePullSecret: name: ecr-regcred generate: false` Nothing is generated, and the reason is logged, when generation is off, the manifest names no pull secret, the name collides with another secret in the release, no registry resolves, or the registry credentials weren't supplied.

  12. Change

    `shdctl secret generate` now warns about every value in your import file that it doesn't read, naming the file and the entry: a secret name that the release's schema doesn't define, a key that the secret doesn't declare, or a key that names a field the schema derives from a default. Read the warnings before you deploy: where the schema generates a field you meant to supply, generation creates a new random value in place of yours, and nothing says so until something fails to authenticate with it. The usual cause is a value filed under the wrong secret. Generation still succeeds either way.

  13. Change

    `shdctl release deploy --format helm` and `shdctl release uninstall` now stop with a message that names the problem when the directory they're pointed at wasn't produced by `shdctl release generate` , or is missing a chart the release contains, instead of deploying a subset of the release and reporting success.

  14. Change

    `shdctl release deploy` starts each wave's largest charts first, so a wave deployed with `--concurrency` above 1 finishes sooner. The dry run lists the charts in the order they deploy.

  15. Change

    You can now list IPv6 CIDRs in `configuration.networking.allowedIngressCIDRs` , so a cluster whose traffic leaves over IPv6 can allow its own egress prefix in. The two families mix freely in one list, entries are still validated by position, and nothing in an existing manifest needs to move.

shdctl follows the release package's rename from "onprem" to "shd", and can still pull every previously published release.

  1. Change

    Generate a release earlier than SHD 2.0.0 with the vpctl version it shipped with. shdctl stops on the `_arrayMerge` key those releases use, and names it.

  2. Change

    Pass `--clean-output` when you pull into an extraction directory that already holds a release. Without it, extraction stops at the first file that already exists. If a directory ends up holding both package directories, the next command that reads the release ( `release generate` , `secret generate` , `secret export` , or `artifact sync` ) stops with an error that names both, instead of letting the stale one shadow the fresh one.

Breaking:

  1. Change

    Turning a feature on now means running `shdctl artifact sync images` again before you deploy: on an air-gapped registry, a missing image can't be fetched at deployment time. `shdctl artifact sync verify` tells you whether a registry already holds what a manifest needs.

  2. Change

    To mirror the full image set as before, pass `--all` . Use it for a registry that deployments with different feature sets share. `artifact sync preflight` and `oras` aren't affected.

Deprecated

  1. Deprecation

    `configuration.kubernetes.imagePullSecret` written as a plain string (the secret name) is deprecated in favor of the block form, which keeps the name and the new `generate` switch under one key. There's nothing to do now: the string form still works, means `generate: true` , and keeps working until a release announces its removal. shdctl logs a notice that names the replacement when it reads one.

  2. Deprecation

    `platform:` is deprecated and ignored. There's nothing to do now: a manifest that still carries the key validates and deploys exactly as before, the rendered charts are identical either way, and the tool logs a notice. Delete the line at your convenience. `shdctl manifest init` no longer asks for it, and a future release will reject it. The value is no longer checked, so a manifest that says something other than `onprem` also stops failing validation.

Fixed

  1. Fix

    `--manifest ` now stops with an error when the file is missing or doesn't parse. It used to warn and carry on without a manifest, so the command then failed on something unrelated ( `version is required` ) or, for a command that needs nothing else, ran without the manifest you named. Without `--manifest` , a `manifest.yaml` found by searching upward is still used on a best-effort basis, as before.

  2. Fix

    `shdctl manifest validate --manifest ` now validates the file you name, instead of ignoring the flag and exiting with code 0 against whatever `manifest.yaml` it found by searching upward. A pipeline step that gated on this command passed regardless of the manifest: check yours again.

  3. Fix

    `shdctl manifest schema` now prints the schema to stdout, so `shdctl manifest schema > manifest.cue` captures it instead of writing an empty file. `--export` is unchanged.

  4. Fix

    `shdctl secret generate` now reuses the RSA key your import file carries ( `asset-cloud-storage-abstraction` 's `storage-key.pem` ), instead of creating a new one on every run and rotating it when you deploy. A `--persist` file written by an earlier version doesn't carry the key: the first run after you upgrade creates one and persists it. To keep the key a cluster already runs with, rebuild the file from that cluster with `shdctl secret export` before you generate: refer to Rebuild a secrets file that vpctl persisted.

  5. Fix

    A value supplied for a `keyType: rsa` field is now rejected at generation time, naming the field, unless it's a PKCS#1 key ( `-----BEGIN RSA PRIVATE KEY-----` ). The PKCS#8 form previously deployed, and then made the services that read it crash-loop, with nothing pointing at the key. To convert one, run `openssl rsa -traditional -in key.pem -out key-pkcs1.pem` . Keys that shdctl generates aren't affected.

  6. Fix

    `shdctl secret generate --use-defaults` now names the secret in its placeholder warning ( `field pixyz-license-3dds.pixyz.lic is required ...` ). `pixyz-license` and `pixyz-license-3dds` both have a `pixyz.lic` field, so the two warnings used to read identically.

  7. Fix

    `shdctl release generate --format argocd` no longer renders the top-level `asset-solutions` application as one of its own children, which could cascade-delete every application in the deployment and all their workloads on a later regeneration. Before you upgrade, check whether `/asset-solutions/templates/asset-solutions.yaml` exists in your GitOps repository. If it does, the live top-level application is tracking itself: remove the `resources-finalizer.argocd.argoproj.io` finalizer from it first, then regenerate and commit. With no finalizer, the worst case is ArgoCD deleting that one application while the child applications keep running, and reapplying `app-of-apps-application.yaml` adopts them again.

  8. Fix

    A full `shdctl release generate --format argocd` now removes the application of a chart that's no longer in the release, or that your manifest disables, instead of leaving it in the deployment's desired state. Expect ArgoCD to delete such an application and its workloads on the next sync after you commit. If you disabled a chart in an earlier release and rely on its workloads still being there, enable it again before you regenerate.

  9. Fix

    `shdctl release generate --name ` no longer drops the other charts' registry details from the generated output, which left a later `shdctl release deploy --format helm` pointing Helm at a directory that held only values. If you ran `release generate --name` since 0.13.0, run a full `shdctl release generate` before your next deployment.

  10. Fix

    `shdctl secret generate --clean-output` now removes only the output file; nothing else in its directory is touched.

  11. Fix

    `shdctl secret generate --name ` now writes only that secret. Every generated value must come from `--import` or `--persist` : a run that would create one from scratch is refused, naming it, and so is a name the release doesn't produce.

Pick your Unity version

Unity Releases compares releases against the version your project is on. Picking it now keeps Compare versions focused on what changes between where you are and where you might be going.