Skip to content

fix(image): sandbox build and CI hardening fixes - #16

Merged
kadinsayani merged 6 commits into
canonical:mainfrom
kadinsayani:feat/sandbox-image-pipeline
Jul 21, 2026
Merged

fix(image): sandbox build and CI hardening fixes#16
kadinsayani merged 6 commits into
canonical:mainfrom
kadinsayani:feat/sandbox-image-pipeline

Conversation

@kadinsayani

@kadinsayani kadinsayani commented Jul 21, 2026

Copy link
Copy Markdown
Member

Summary

A handful of fixes to the sandbox container image build pipeline and CI, discovered while exercising it end-to-end against a real LXD daemon:

  • Build openshell-sandbox from source instead of a pinned release tarball (rockcraft.yaml), pointed at a specific upstream commit (v0.0.86) rather than an older release build.
  • Pin lxc publish to uncompressed output (scripts/build-sandbox-image.sh) for deterministic image fingerprints across builds.
  • Trim apt installs to --no-install-recommends in both CI workflows to keep runners lean.
  • Simplify the /sandbox chown in the container-adapted init wrapper — the previous error-swallowing wrapper masked genuine failures (e.g. a read-only filesystem) that should abort under set -euo pipefail instead.
  • Fix scripts/setup-lxd-test-env.sh's image-alias checklxc image alias show isn't a real lxc subcommand and always failed, silently forcing a redundant lxc image copy on every run. Switched to lxc image info, explicitly targeting local: so a non-default remote can't cause it to silently skip staging the test image.
  • Extend the DHCP acquisition poll from 5s to 20s in the container-adapted init wrapper — dhcpcd measured ~8s to acquire a lease on lxdbr0 in testing, so the previous 5s timeout was cutting it close enough to intermittently leave the supervisor starting before the lease landed (Network is unreachable, then a fatal exit since it's PID 1).

Test plan

  • make sandbox-image builds and publishes the image locally end-to-end (verified: image builds successfully, ~158 MiB, publishes under the openshell-sandbox alias).
  • cargo build --workspace, cargo clippy --workspace --all-targets -- -D warnings, cargo fmt --all -- --check, shellcheck scripts/*.sh all clean.
  • CI (build, static-checks, lxd-client-tests, container-image, driver-tests, cla-check).

…e tarball

Replace the openshell-sandbox part's prebuilt-tarball download with a
source build: clone NVIDIA/OpenShell at the v0.0.86 release tag and
build crates/openshell-sandbox with the rust plugin, matching how the
gateway is built. This tracks upstream releases directly instead of
depending on prebuilt release binaries being published, and drops the
need to keep a sha256/architecture checksum table in sync with each
release.

craftctl set version now uses v0.0.86 to match the pinned tag, rather
than the old, now-unrelated v0.0.66 release the tarball approach used.

Signed-off-by: Kadin Sayani <kadin.sayani@canonical.com>
lxc publish's --compression flag was unset, so the published image's
compression fell back to whatever the LXD server's
images.compression_algorithm config happened to be. In CI that's
"none" only because canonical/setup-lxd's init step sets it as a side
effect — a different action's config, not something this script
controls. Pass --compression none explicitly so lxc image export
produces a consistent output shape regardless of the server's default.

Signed-off-by: Kadin Sayani <kadin.sayani@canonical.com>
Add --no-install-recommends to every apt-get install call site in CI
(protobuf-compiler/libprotobuf-dev in three jobs, umoci in
container-image) so runners don't pull in unnecessary recommended
packages.

Signed-off-by: Kadin Sayani <kadin.sayani@canonical.com>
chown with numeric UID:GID sets the inode's owner/group bits directly
and never consults /etc/passwd or /etc/group, so it can't fail because
"the user may not exist yet" — that wasn't a real failure mode this
could hit. The if/WARN wrapper also silently swallowed genuine
failures (e.g. a read-only filesystem) that the script's existing
set -euo pipefail should instead abort on.

Signed-off-by: Kadin Sayani <kadin.sayani@canonical.com>
Signed-off-by: Kadin Sayani <kadin.sayani@canonical.com>
The 5s (10x0.5s) poll timeout was shorter than dhcpcd actually needed
to acquire a lease on lxdbr0 (~8s, measured against a real LXD host
during e2e smoke testing), so eth0 never got an IPv4 address in time.
The supervisor then started with the container's kernel-assigned
IPv6-only route, immediately failed to reach the gateway (Network is
unreachable), exhausted its own policy-fetch retry budget, and exited
- fatal since it's PID 1, killing the container with a "Stopped"
error. Reproduced 3/3 times.

Bump the poll loop to 40x0.5s (20s), well above the measured
acquisition time, so the supervisor doesn't start before the lease
lands.

Signed-off-by: Kadin Sayani <kadin.sayani@canonical.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the OpenShell sandbox container image build pipeline and CI workflows, improving determinism and reliability when building/publishing the LXD image and bootstrapping LXD-based integration tests.

Changes:

  • Build openshell-sandbox from upstream source (pinned to v0.0.86) via Rockcraft’s rust plugin instead of downloading release tarballs.
  • Make published LXD image output deterministic by forcing lxc publish to use uncompressed output.
  • Improve CI and test environment setup: apt-get install --no-install-recommends, fix LXD image alias existence check, and extend DHCP acquisition polling in the container init wrapper.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
scripts/setup-lxd-test-env.sh Fixes the local image/alias existence check to avoid redundant staging work.
scripts/openshell-container-init.sh Removes error-swallowing chown and increases DHCP polling window for more reliable startup.
scripts/build-sandbox-image.sh Publishes with --compression none to stabilize image fingerprints across builds.
rockcraft.yaml Switches sandbox supervisor build to pinned upstream git commit using the Rust plugin and organizes the installed binary.
.github/workflows/tests.yaml Uses --no-install-recommends for leaner CI installs in test/image jobs.
.github/workflows/static-checks.yaml Uses --no-install-recommends for leaner CI installs in static checks.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@simondeziel simondeziel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, thanks

@kadinsayani
kadinsayani merged commit 3fdf9c8 into canonical:main Jul 21, 2026
6 checks passed
@kadinsayani
kadinsayani deleted the feat/sandbox-image-pipeline branch July 21, 2026 18:39
kadinsayani added a commit to kadinsayani/openshell-driver-lxd that referenced this pull request Jul 21, 2026
…ipeline

fix(image): sandbox build and CI hardening fixes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants