mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-10-21 23:28:19 +00:00
c6fc094c93
The Perl tests of the OpenEmbedded Genesis image ran its shell scripts
and C programs through system(), qx, pipes and fork, wrote fake
commands through copied read_file and write_file helpers, and matched
regexes against shell and C source. Many rejections checked only a
non-zero exit, so an earlier, unrelated failure also passed. The
quality gate judged 91% of their 762 checks bad.
The shell and C checks move to bats in xCAT-test/bats. The C programs
are compiled there and run: the plain console, test drivers for the
shared status view and the shell launcher, and genesis-udp-send against
a loopback listener. Each rejection now matches the message of its own
guard. The .t files keep the artifact checks (kas, recipes, kernel
fragments, units, README), read with XCAT::Test::File. Test files left
with no checks are deleted.
Claim map (file -> where its claims went):
- go_xcat_uninstall_installed_only.t -> go_xcat_uninstall_installed_only.bats
- genesis_readme_paths.t, genesis_base_sources_staged.t -> kept in the
.t (README read by slurp_repo_file, tarball read by Archive::Tar)
- genesis_openembedded_{export,hardware,runtime}.t -> the bats file of
the same name
- genesis_openembedded_{bmcsetup,metrics,extensions,qeth,actions,
discovery}.t -> scripts to the bats file of the same name, recipes
and units kept in the .t
- genesis_openembedded_console.t -> built and run checks, state.c,
plain_ui.c and shell.c to genesis_openembedded_console.bats; Newt
source checks kept in the .t
- genesis_openembedded.t -> oe/build to genesis_openembedded_build.bats;
shell matches to the runtime, hardware and extensions bats; console
matches to the console bats or the console .t; artifacts kept
Red proof: every moved or new test was run against a mutated copy of
the code it covers and went red, for example: rpm -q not checked,
tar without --mtime, VEX report not exported, support dir after PATH,
digest check off, layer2 forced, wildcard device allowed, arguments
eval'd, tcp probe skipped, SOURCE_PORT 302, AF_INET only, stage timer
compared, launch error ignored, kas run twice, status written in place.
One mutation stayed green: tar without --owner=0 when the test runs as
root.
Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
155 lines
6.4 KiB
Bash
155 lines
6.4 KiB
Bash
#!/usr/bin/env bats
|
|
#
|
|
# Genesis extensions are signed squashfs images. oe/scripts/sign-extension signs a manifest,
|
|
# oe/export-extension exports a signed bundle, and genesis-sysext verifies and installs an
|
|
# extension in the running image. systemd-sysext and genesis-status are shell functions
|
|
# written to a scratch PATH; they log their arguments.
|
|
|
|
load 'helpers/shell_source'
|
|
|
|
EXT_FILES='xCAT-genesis-base/oe/meta-xcat-genesis/recipes-core/xcat-genesis-extensions/files'
|
|
|
|
setup()
|
|
{
|
|
command -v openssl >/dev/null || skip 'openssl is required'
|
|
command -v jq >/dev/null || skip 'jq is required'
|
|
LOADER="$(require_repo_file "$EXT_FILES/genesis-sysext")"
|
|
SIGNER="$(require_repo_file 'xCAT-genesis-base/oe/scripts/sign-extension')"
|
|
EXPORTER="$(require_repo_file 'xCAT-genesis-base/oe/export-extension')"
|
|
|
|
root="$BATS_TEST_TMPDIR"
|
|
mkdir -p "$root/bin" "$root/keys" "$root/run"
|
|
image="$root/xcat-smoke.squashfs-zst"
|
|
manifest="$root/xcat-smoke.manifest.json"
|
|
signature="$root/xcat-smoke.sig"
|
|
private_key="$root/private.pem"
|
|
public_key="$root/keys/xcat-release.pem"
|
|
printf 'extension payload\n' >"$image"
|
|
printf 'ID=xcat-genesis\nVERSION_ID=0.1\n' >"$root/os-release"
|
|
: >"$root/commands.log"
|
|
: >"$root/status.log"
|
|
printf '#!/bin/sh\nprintf "systemd-sysext %%s\\n" "$*" >>"$XCAT_TEST_LOG"\n' >"$root/bin/systemd-sysext"
|
|
printf '#!/bin/sh\nprintf "%%s\\n" "$*" >>"$XCAT_STATUS_LOG"\n' >"$root/bin/genesis-status"
|
|
chmod 0755 "$root/bin/systemd-sysext" "$root/bin/genesis-status"
|
|
|
|
openssl genpkey -algorithm ED25519 -out "$private_key" 2>/dev/null
|
|
openssl pkey -in "$private_key" -pubout -out "$public_key"
|
|
hash="$(sha256sum -- "$image" | cut -c1-64)"
|
|
write_manifest "$manifest" '.'
|
|
"$SIGNER" "$manifest" "$private_key" "$signature"
|
|
|
|
export PATH="$root/bin:$PATH"
|
|
export XCAT_GENESIS_EXTENSION_KEY_DIR="$root/keys"
|
|
export XCAT_GENESIS_EXTENSION_RUN_DIR="$root/run"
|
|
export XCAT_GENESIS_OS_RELEASE="$root/os-release"
|
|
export XCAT_GENESIS_STATUS_COMMAND="$root/bin/genesis-status"
|
|
export XCAT_GENESIS_UNAME_M=x86_64
|
|
export XCAT_GENESIS_UNAME_R=6.18.24-test
|
|
export XCAT_TEST_LOG="$root/commands.log"
|
|
export XCAT_STATUS_LOG="$root/status.log"
|
|
}
|
|
|
|
# Write a manifest for $image, changed by a jq filter.
|
|
write_manifest()
|
|
{
|
|
local path="$1" filter="$2"
|
|
jq -n --arg sha "$hash" '{
|
|
architecture: "x86_64", capabilities: ["diagnostic.smoke"], genesis_release: "0.1",
|
|
kernel_modules: false, kernel_release: null, key_id: "xcat-release",
|
|
license_class: "open", name: "xcat-smoke", pci_ids: [], schema: 1,
|
|
sha256: $sha, version: "1.0"
|
|
}' | jq -S "$filter" >"$path"
|
|
}
|
|
|
|
# Write and sign a changed manifest, then verify it against $image.
|
|
verify_changed()
|
|
{
|
|
local name="$1" filter="$2"
|
|
write_manifest "$root/$name.json" "$filter"
|
|
"$SIGNER" "$root/$name.json" "$private_key" "$root/$name.sig"
|
|
/bin/bash "$LOADER" verify "$root/$name.json" "$image" "$root/$name.sig"
|
|
}
|
|
|
|
@test "the extension manifest is signed" {
|
|
[ -s "$signature" ]
|
|
}
|
|
|
|
@test "the built extension exports as a signed bundle with its key and checksums" {
|
|
stem=xcat-genesis-extension-smoke-xcat-genesis-x86-64
|
|
machine_dir="$root/deploy/images/xcat-genesis-x86-64"
|
|
mkdir -p "$machine_dir"
|
|
cp "$image" "$machine_dir/$stem.sysext.squashfs-zst"
|
|
cp "$manifest" "$machine_dir/$stem.sysext.manifest.json"
|
|
run "$EXPORTER" x86_64 xcat-genesis-extension-smoke "$root/deploy" \
|
|
"$private_key" "$public_key" "$root/bundle"
|
|
[ "$status" -eq 0 ]
|
|
[ -f "$root/bundle/extensions/$stem.squashfs-zst" ]
|
|
[ -f "$root/bundle/extensions/$stem.manifest.json" ]
|
|
[ -f "$root/bundle/extensions/$stem.sig" ]
|
|
[ -f "$root/bundle/extension-keys/xcat-release.pem" ]
|
|
(cd "$root/bundle" && sha256sum -c SHA256SUMS >/dev/null)
|
|
}
|
|
|
|
@test "a valid extension is accepted" {
|
|
run /bin/bash "$LOADER" verify "$manifest" "$image" "$signature"
|
|
[ "$status" -eq 0 ]
|
|
}
|
|
|
|
@test "i586, armv7l and s390x runtimes use their extension identities" {
|
|
XCAT_GENESIS_UNAME_M=i586 verify_changed x86 '.architecture = "x86"'
|
|
XCAT_GENESIS_UNAME_M=armv7l verify_changed armv7hf '.architecture = "armv7hf"'
|
|
XCAT_GENESIS_UNAME_M=s390x verify_changed s390x '.architecture = "s390x"'
|
|
}
|
|
|
|
@test "a valid extension is installed under its manifest name, and extensions are refreshed" {
|
|
run /bin/bash "$LOADER" install "$manifest" "$image" "$signature"
|
|
[ "$status" -eq 0 ]
|
|
[ -f "$root/run/xcat-smoke.raw" ]
|
|
grep -qx 'systemd-sysext refresh' "$root/commands.log"
|
|
}
|
|
|
|
@test "loading a valid extension directory publishes the active and ready states" {
|
|
run /bin/bash "$LOADER" load-all "$root"
|
|
[ "$status" -eq 0 ]
|
|
grep -qx 'extensions RUNNING Verifying Genesis extensions' "$root/status.log"
|
|
grep -qx 'extensions READY Genesis extensions loaded' "$root/status.log"
|
|
}
|
|
|
|
@test "an invalid signature is rejected" {
|
|
printf '%064d' 0 | tr 0 x >"$root/bad.sig"
|
|
run /bin/bash "$LOADER" verify "$manifest" "$image" "$root/bad.sig"
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *'extension signature verification failed'* ]]
|
|
}
|
|
|
|
@test "a wrong architecture, release, digest or kernel ABI is rejected" {
|
|
run verify_changed arch '.architecture = "riscv64"'
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *'extension architecture riscv64 does not match x86_64'* ]]
|
|
run verify_changed release '.genesis_release = "9.9"'
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *'extension release 9.9 does not match 0.1'* ]]
|
|
run verify_changed digest ".sha256 = \"$(printf '%064d' 0)\""
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *'extension digest does not match'* ]]
|
|
run verify_changed abi '.kernel_modules = true | .kernel_release = "0.0-wrong"'
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *'extension kernel release does not match'* ]]
|
|
}
|
|
|
|
@test "a linked manifest is rejected" {
|
|
ln -s "$manifest" "$root/linked.json"
|
|
run /bin/bash "$LOADER" verify "$root/linked.json" "$image" "$signature"
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *"invalid extension input: $root/linked.json"* ]]
|
|
}
|
|
|
|
@test "an empty extension directory is rejected, with a structured recovery status" {
|
|
mkdir -p "$root/empty"
|
|
run /bin/bash "$LOADER" load-all "$root/empty"
|
|
[ "$status" -ne 0 ]
|
|
grep -q '^extensions FAILED no extension manifests found in:' "$root/status.log"
|
|
grep -q 'CODE=EXTENSION_VERIFICATION_FAILED .*RECOVERY=Check extension images, manifests, signatures, and trusted keys' \
|
|
"$root/status.log"
|
|
}
|