Skip to content

Commit 0c13cdd

Browse files
committed
tests: Add cstor-dist registry infrastructure to bootc_testlib.nu
Add reusable functions for running cstor-dist, a tool that serves images from containers-storage via an authenticated OCI registry endpoint. This enables testing authenticated logically bound images. The following functions are exported: - start_cstor_dist: Starts cstor-dist container with basic auth - get_cstor_auth: Returns registry address and base64-encoded credentials - setup_insecure_registry: Configures registries.conf.d for non-TLS access - setup_system_auth: Sets up /run/ostree/auth.json with credentials Also update test-logically-bound-switch.nu to: - Import get_cstor_auth from bootc_testlib.nu - Add --with-auth flag to build_image for baking auth.json into images - Fix verify_images to check if image name is IN the Names array (not exact match) to support images with multiple tags Assisted-by: Claude Code (claude-opus-4-5@20251101) Signed-off-by: ckyrouac <ckyrouac@redhat.com>
1 parent 03ab934 commit 0c13cdd

File tree

2 files changed

+107
-14
lines changed

2 files changed

+107
-14
lines changed

tmt/tests/booted/bootc_testlib.nu

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,88 @@ export def have_hostexports [] {
2323
export def parse_cmdline [] {
2424
open /proc/cmdline | str trim | split row " "
2525
}
26+
27+
# cstor-dist configuration for authenticated registry testing
28+
# cstor-dist serves images from containers-storage via an authenticated OCI registry endpoint
29+
# https://github.com/ckyrouac/cstor-dist
30+
const CSTOR_DIST_IMAGE = "ghcr.io/ckyrouac/cstor-dist:latest"
31+
const CSTOR_DIST_USER = "testuser"
32+
const CSTOR_DIST_PASS = "testpass"
33+
const CSTOR_DIST_PORT = 8000
34+
35+
# The registry address for cstor-dist
36+
export const CSTOR_DIST_REGISTRY = $"localhost:($CSTOR_DIST_PORT)"
37+
38+
# Start cstor-dist with basic auth on localhost
39+
# Fails if cstor-dist cannot be started
40+
export def start_cstor_dist [] {
41+
print "Starting cstor-dist with basic auth..."
42+
43+
# Pull test images that cstor-dist will serve
44+
print "Pulling test images for cstor-dist to serve..."
45+
podman pull docker.io/library/alpine:latest
46+
podman pull docker.io/library/busybox:latest
47+
48+
# Run cstor-dist container with auth enabled
49+
# Mount the local containers storage so cstor-dist can serve images from it
50+
let storage_path = if ("/var/lib/containers/storage" | path exists) {
51+
"/var/lib/containers/storage"
52+
} else {
53+
$"($env.HOME)/.local/share/containers/storage"
54+
}
55+
56+
(podman run --privileged --rm -d --name cstor-dist-auth
57+
-p $"($CSTOR_DIST_PORT):8000"
58+
-v $"($storage_path):/var/lib/containers/storage"
59+
$CSTOR_DIST_IMAGE --username $CSTOR_DIST_USER --password $CSTOR_DIST_PASS)
60+
61+
# Wait for cstor-dist to be ready by testing HTTP connection
62+
# Loop for up to 20 seconds
63+
print "Waiting for cstor-dist to be ready..."
64+
let auth_header = $"($CSTOR_DIST_USER):($CSTOR_DIST_PASS)" | encode base64
65+
mut ready = false
66+
for i in 1..20 {
67+
let result = do { curl -sf -H $"Authorization: Basic ($auth_header)" $"http://($CSTOR_DIST_REGISTRY)/v2/" } | complete
68+
if $result.exit_code == 0 {
69+
$ready = true
70+
break
71+
}
72+
print $"Attempt ($i)/20: cstor-dist not ready yet..."
73+
sleep 1sec
74+
}
75+
76+
if not $ready {
77+
# Show container logs for debugging
78+
print "cstor-dist failed to start. Container logs:"
79+
podman logs cstor-dist-auth
80+
error make { msg: "cstor-dist failed to become ready within 20 seconds" }
81+
}
82+
83+
print $"cstor-dist running on ($CSTOR_DIST_REGISTRY)"
84+
}
85+
86+
# Get cstor-dist auth config
87+
export def get_cstor_auth [] {
88+
# Base64 encode the credentials for auth.json
89+
let auth_b64 = $"($CSTOR_DIST_USER):($CSTOR_DIST_PASS)" | encode base64
90+
{
91+
registry: $CSTOR_DIST_REGISTRY,
92+
auth_b64: $auth_b64
93+
}
94+
}
95+
96+
# Configure insecure registry for cstor-dist (no TLS)
97+
export def setup_insecure_registry [] {
98+
mkdir /etc/containers/registries.conf.d
99+
(echo $"[[registry]]\nlocation=\"($CSTOR_DIST_REGISTRY)\"\ninsecure=true"
100+
| save -f /etc/containers/registries.conf.d/99-cstor-dist.conf)
101+
}
102+
103+
# Set up auth.json on the running system with cstor-dist credentials
104+
export def setup_system_auth [] {
105+
mkdir /run/ostree
106+
let cstor = get_cstor_auth
107+
print $"Setting up system auth for cstor-dist at ($cstor.registry)"
108+
let auth_json = $'{"auths": {"($cstor.registry)": {"auth": "($cstor.auth_b64)"}}}'
109+
echo $auth_json | save -f /run/ostree/auth.json
110+
}

tmt/tests/booted/test-logically-bound-switch.nu

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,21 @@
1515

1616
use std assert
1717
use tap.nu
18+
use bootc_testlib.nu [get_cstor_auth]
1819

1920
# This code runs on *each* boot.
2021
bootc status
2122
let st = bootc status --json | from json
2223
let booted = $st.status.booted.image
2324

24-
# The tests here aren't fetching from a registry which requires auth by default,
25-
# but we can replicate the failure in https://github.com/bootc-dev/bootc/pull/1852
26-
# by just injecting any auth file.
27-
echo '{}' | save -f /run/ostree/auth.json
28-
2925
def initial_setup [] {
3026
bootc image copy-to-storage
3127
podman images
3228
podman image inspect localhost/bootc | from json
3329
}
3430

35-
def build_image [name images containers] {
31+
# Build an image with optional auth.json baked in
32+
def build_image [name images containers --with-auth] {
3633
let td = mktemp -d
3734
cd $td
3835
mkdir usr/share/containers/systemd
@@ -59,6 +56,16 @@ RUN echo sanity check > /usr/share/bound-image-sanity-check.txt
5956
}
6057
}
6158

59+
# Optionally bake auth.json into the image
60+
if $with_auth {
61+
let cstor = get_cstor_auth
62+
print "Baking auth.json into the image"
63+
mkdir etc/ostree
64+
let auth_json = $'{"auths": {"($cstor.registry)": {"auth": "($cstor.auth_b64)"}}}'
65+
echo $auth_json | save etc/ostree/auth.json
66+
echo "COPY etc/ /etc/\n" | save Dockerfile --append
67+
}
68+
6269
# Build it
6370
podman build -t $name .
6471
# Just sanity check it
@@ -74,12 +81,13 @@ def verify_images [images containers] {
7481
let image_names = podman --storage-opt=additionalimagestore=/usr/lib/bootc/storage images --format json | from json | select -i Names
7582

7683
for $image in $bound_images {
77-
let found = $image_names | where Names == [$image.image]
84+
# Check if the expected image name is IN the Names array (not exact match)
85+
let found = $image_names | where { |row| $image.image in $row.Names }
7886
assert (($found | length) > 0) $"($image.image) not found"
7987
}
8088

8189
for $container in $bound_containers {
82-
let found = $image_names | where Names == [$container.image]
90+
let found = $image_names | where { |row| $container.image in $row.Names }
8391
assert (($found | length) > 0) $"($container.image) not found"
8492
}
8593
}
@@ -89,14 +97,14 @@ def first_boot [] {
8997

9098
initial_setup
9199

92-
# build a bootc image that includes bound images
100+
# Build a bootc image that includes bound images
93101
let images = [
94102
{ "bound": true, "image": "registry.access.redhat.com/ubi9/ubi-minimal:9.4", "name": "ubi-minimal" },
95103
{ "bound": false, "image": "quay.io/centos-bootc/centos-bootc:stream9", "name": "centos-bootc" }
96104
]
97105

98106
let containers = [{
99-
"bound": true, "image": "docker.io/library/alpine:latest", "name": "alpine"
107+
"bound": true, "image": "docker.io/library/alpine:latest", "name": "alpine"
100108
}]
101109

102110
let image_name = "localhost/bootc-bound"
@@ -111,18 +119,18 @@ def second_boot [] {
111119
assert equal $booted.image.transport containers-storage
112120
assert equal $booted.image.image localhost/bootc-bound
113121

114-
# verify images are still there after boot
122+
# Verify images are still there after boot
115123
let images = [
116124
{ "bound": true, "image": "registry.access.redhat.com/ubi9/ubi-minimal:9.4", "name": "ubi-minimal" },
117125
{ "bound": false, "image": "quay.io/centos-bootc/centos-bootc:stream9", "name": "centos-bootc" }
118126
]
119127

120128
let containers = [{
121-
"bound": true, "image": "docker.io/library/alpine:latest", "name": "alpine"
129+
"bound": true, "image": "docker.io/library/alpine:latest", "name": "alpine"
122130
}]
123131
verify_images $images $containers
124132

125-
# build a new bootc image with an additional bound image
133+
# Build a new bootc image with an additional bound image
126134
print "bootc upgrade with another bound image"
127135
let image_name = "localhost/bootc-bound"
128136
let more_images = $images | append [{ "bound": true, "image": "registry.access.redhat.com/ubi9/ubi-minimal:9.3", "name": "ubi-minimal-9-3" }]
@@ -144,7 +152,7 @@ def third_boot [] {
144152
]
145153

146154
let containers = [{
147-
"bound": true, "image": "docker.io/library/alpine:latest", "name": "alpine"
155+
"bound": true, "image": "docker.io/library/alpine:latest", "name": "alpine"
148156
}]
149157

150158
verify_images $images $containers

0 commit comments

Comments
 (0)