From 1bf2b5163c6db9436c4afab87506b0f619c2f16d Mon Sep 17 00:00:00 2001 From: scanner Date: Wed, 16 Sep 2026 02:15:51 -0400 Subject: [PATCH 1/2] [scanner] fix(bonedigger-report): derive booted image name from live bootc status image-info.json's image-name field is baked at build time and goes stale after a bootc rebase (e.g. bluefin -> dakota). read_boot_status() already corrected IMAGE_TAG and IMAGE_REF from the live booted ref but left IMAGE_NAME untouched, so route_issue_repo() still routed rebased hosts' reports to the pre-rebase repo. Derive IMAGE_NAME from the booted ref's repository basename, with the same jq/booted-image-snapshot fallback chain already used for tag/ref. Add BATS coverage exercising a rebased bluefin->dakota deployment. Closes #1009 Signed-off-by: scanner --- .../bluefin/usr/libexec/bonedigger-report | 13 +++++++++++ tests/test_bonedigger_report.bats | 23 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/system_files/bluefin/usr/libexec/bonedigger-report b/system_files/bluefin/usr/libexec/bonedigger-report index 5b566d2a..00b1d733 100755 --- a/system_files/bluefin/usr/libexec/bonedigger-report +++ b/system_files/bluefin/usr/libexec/bonedigger-report @@ -108,6 +108,19 @@ read_boot_status() { *@*) ;; # digest-pinned ref, no tag to extract *:*) IMAGE_TAG="${booted_ref##*:}" ;; esac + if [[ -n "$booted_ref" ]]; then + # image-name from image-info.json is baked at build time and is + # equally stale after a rebase (e.g. bluefin -> dakota); derive + # it from the booted ref's repository basename so issue routing + # follows the live deployment, not the original build + # (projectbluefin/common#1009). + local booted_repo="${booted_ref%%@*}" + booted_repo="${booted_repo%%:*}" + local booted_name="${booted_repo##*/}" + if [[ -n "$booted_name" ]]; then + IMAGE_NAME="$booted_name" + fi + fi else BOOTED_DIGEST="unknown" fi diff --git a/tests/test_bonedigger_report.bats b/tests/test_bonedigger_report.bats index b7de0d7f..3b6ca756 100755 --- a/tests/test_bonedigger_report.bats +++ b/tests/test_bonedigger_report.bats @@ -62,6 +62,29 @@ teardown() { [ "$output" = "projectbluefin/common" ] } +@test "read_boot_status derives image name, tag, and ref from a rebased booted deployment" { + cat << 'EOF' > "$WORKDIR/bin/bootc" +#!/usr/bin/bash +if [[ "$1" == "status" && "$2" == "--json" ]]; then + printf '%s' '{"status":{"booted":{"image":{"image":{"image":"ghcr.io/projectbluefin/dakota:stable"},"imageDigest":"sha256:deadbeef"}}}}' + exit 0 +fi +printf 'Booted: ghcr.io/projectbluefin/dakota:stable\n' +EOF + chmod +x "$WORKDIR/bin/bootc" + + run env PATH="$WORKDIR/bin:$PATH" bash -c ' + source "$1" + IMAGE_NAME="bluefin" + IMAGE_TAG="latest" + read_boot_status + printf "%s|%s|%s" "$IMAGE_NAME" "$IMAGE_TAG" "$IMAGE_REF" + ' _ "$BONEDIGGER_SCRIPT" + + [ "$status" -eq 0 ] + [ "$output" = "dakota|stable|ghcr.io/projectbluefin/dakota:stable" ] +} + @test "queue choices map to at most one supported queue label" { run bash -c 'source "$1"; queue_label_for_choice "$2"' _ \ "$BONEDIGGER_SCRIPT" "Submit to the clanker queue for machine analysis" From cb93d436c72bb154745bd41e4dce3e5f99aa469a Mon Sep 17 00:00:00 2001 From: "Jorge O. Castro" Date: Sat, 19 Sep 2026 09:16:11 -0400 Subject: [PATCH 2/2] fix(bonedigger-report): take repo basename before stripping the tag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `${booted_repo%%:*}` cut at the first colon of the whole reference, so a registry port was mistaken for a tag: `localhost:5000/bluefin:latest` yielded `IMAGE_NAME=localhost`. Take the basename first, then strip the tag — in the final path component a colon can only be a tag. Adds two regression cases: a digest-pinned booted ref (which also pins the previously unverified `%%@*` digest strip) and a port-bearing registry ref. Assisted-by: Claude Opus 4.6 via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/skills/bonedigger/SKILL.md | 3 ++ .../bluefin/usr/libexec/bonedigger-report | 5 +- tests/test_bonedigger_report.bats | 46 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/docs/skills/bonedigger/SKILL.md b/docs/skills/bonedigger/SKILL.md index 29dfe974..79ebc50d 100644 --- a/docs/skills/bonedigger/SKILL.md +++ b/docs/skills/bonedigger/SKILL.md @@ -48,6 +48,9 @@ configuration, or lifecycle automation owned by `projectbluefin/actions`. - Applying both queue labels, using `machine-id`, or reviving generic OTel capture. - Falling back to a browser issue form or a QR login flow. +- Parsing a booted OCI ref by cutting at the first colon: that colon may be a + registry port (`localhost:5000/bluefin:latest` → `localhost`). Strip the + digest, take the repository basename, then strip the tag — in that order. ## Verification diff --git a/system_files/bluefin/usr/libexec/bonedigger-report b/system_files/bluefin/usr/libexec/bonedigger-report index 00b1d733..c944dcb9 100755 --- a/system_files/bluefin/usr/libexec/bonedigger-report +++ b/system_files/bluefin/usr/libexec/bonedigger-report @@ -114,9 +114,12 @@ read_boot_status() { # it from the booted ref's repository basename so issue routing # follows the live deployment, not the original build # (projectbluefin/common#1009). + # Take the basename before stripping the tag: the first colon in + # a full reference can belong to a registry port + # (localhost:5000/bluefin:latest), not the tag. local booted_repo="${booted_ref%%@*}" - booted_repo="${booted_repo%%:*}" local booted_name="${booted_repo##*/}" + booted_name="${booted_name%%:*}" if [[ -n "$booted_name" ]]; then IMAGE_NAME="$booted_name" fi diff --git a/tests/test_bonedigger_report.bats b/tests/test_bonedigger_report.bats index 3b6ca756..e9b9fc9f 100755 --- a/tests/test_bonedigger_report.bats +++ b/tests/test_bonedigger_report.bats @@ -85,6 +85,52 @@ EOF [ "$output" = "dakota|stable|ghcr.io/projectbluefin/dakota:stable" ] } +@test "read_boot_status strips the digest from a digest-pinned booted ref" { + cat << 'EOF' > "$WORKDIR/bin/bootc" +#!/usr/bin/bash +if [[ "$1" == "status" && "$2" == "--json" ]]; then + printf '%s' '{"status":{"booted":{"image":{"image":{"image":"ghcr.io/projectbluefin/dakota@sha256:deadbeef"},"imageDigest":"sha256:deadbeef"}}}}' + exit 0 +fi +printf 'Booted: ghcr.io/projectbluefin/dakota@sha256:deadbeef\n' +EOF + chmod +x "$WORKDIR/bin/bootc" + + run env PATH="$WORKDIR/bin:$PATH" bash -c ' + source "$1" + IMAGE_NAME="bluefin" + IMAGE_TAG="latest" + read_boot_status + printf "%s|%s" "$IMAGE_NAME" "$IMAGE_TAG" + ' _ "$BONEDIGGER_SCRIPT" + + [ "$status" -eq 0 ] + [ "$output" = "dakota|latest" ] +} + +@test "read_boot_status keeps the repository basename when the registry has a port" { + cat << 'EOF' > "$WORKDIR/bin/bootc" +#!/usr/bin/bash +if [[ "$1" == "status" && "$2" == "--json" ]]; then + printf '%s' '{"status":{"booted":{"image":{"image":{"image":"localhost:5000/bluefin:latest"},"imageDigest":"sha256:deadbeef"}}}}' + exit 0 +fi +printf 'Booted: localhost:5000/bluefin:latest\n' +EOF + chmod +x "$WORKDIR/bin/bootc" + + run env PATH="$WORKDIR/bin:$PATH" bash -c ' + source "$1" + IMAGE_NAME="dakota" + IMAGE_TAG="stable" + read_boot_status + printf "%s|%s" "$IMAGE_NAME" "$IMAGE_TAG" + ' _ "$BONEDIGGER_SCRIPT" + + [ "$status" -eq 0 ] + [ "$output" = "bluefin|latest" ] +} + @test "queue choices map to at most one supported queue label" { run bash -c 'source "$1"; queue_label_for_choice "$2"' _ \ "$BONEDIGGER_SCRIPT" "Submit to the clanker queue for machine analysis"