Public Access
generated from Philipp/template-git
feat: support dynamic multi-architecture discovery and iteration
This commit is contained in:
3 files changed
+135
-49
No files matched your search
+106
-39
@@ -12,6 +12,10 @@ inputs:
|
||||
description: Target branch name for delta heading (e.g. main)
|
||||
required: false
|
||||
default: main
|
||||
architectures:
|
||||
description: Comma-separated list of architectures or platforms to scan (e.g. 'amd64,arm64' or 'linux/amd64,linux/arm64'). If empty, scans all architectures found in the container image.
|
||||
required: false
|
||||
default: ''
|
||||
output-delta:
|
||||
description: Output markdown file for CVE delta report
|
||||
required: false
|
||||
@@ -95,56 +99,112 @@ runs:
|
||||
fi
|
||||
}
|
||||
|
||||
# Extract platform SBOMs for head image
|
||||
echo "Extracting platform SBOMs for head image: ${{ inputs.head-image }}..."
|
||||
docker buildx imagetools inspect "${{ inputs.head-image }}" \
|
||||
--format '{{ json (index .SBOM "linux/amd64").SPDX }}' > sboms/head/sbom-amd64.spdx.json 2>/dev/null || true
|
||||
cleanup_file sboms/head/sbom-amd64.spdx.json
|
||||
# Determine target platforms / architectures
|
||||
PLATFORMS=()
|
||||
if [ -n "${{ inputs.architectures }}" ]; then
|
||||
IFS=',' read -ra RAW_ARCHS <<< "${{ inputs.architectures }}"
|
||||
for a in "${RAW_ARCHS[@]}"; do
|
||||
clean_a=$(echo "$a" | xargs)
|
||||
[ -z "$clean_a" ] && continue
|
||||
if [[ "$clean_a" != *"/"* ]]; then
|
||||
PLATFORMS+=("linux/${clean_a}")
|
||||
else
|
||||
PLATFORMS+=("$clean_a")
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "Auto-discovering architectures from images..."
|
||||
raw_head=$(docker buildx imagetools inspect --raw "${{ inputs.head-image }}" 2>/dev/null || true)
|
||||
raw_target=$(docker buildx imagetools inspect --raw "${{ inputs.target-image }}" 2>/dev/null || true)
|
||||
|
||||
docker buildx imagetools inspect "${{ inputs.head-image }}" \
|
||||
--format '{{ json (index .SBOM "linux/arm64").SPDX }}' > sboms/head/sbom-arm64.spdx.json 2>/dev/null || true
|
||||
cleanup_file sboms/head/sbom-arm64.spdx.json
|
||||
discovered=$(node -e '
|
||||
const raw1 = process.argv[1];
|
||||
const raw2 = process.argv[2];
|
||||
const set = new Set();
|
||||
for (const raw of [raw1, raw2]) {
|
||||
if (!raw) continue;
|
||||
try {
|
||||
const data = JSON.parse(raw);
|
||||
const manifests = data.manifests || [];
|
||||
for (const m of manifests) {
|
||||
if (m.platform && m.platform.architecture && m.platform.architecture !== "unknown") {
|
||||
const os = m.platform.os || "linux";
|
||||
const variant = m.platform.variant ? "/" + m.platform.variant : "";
|
||||
set.add(`${os}/${m.platform.architecture}${variant}`);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
console.log(Array.from(set).sort().join("\n"));
|
||||
' "$raw_head" "$raw_target")
|
||||
|
||||
# If single-arch, extract root .SPDX
|
||||
if [ ! -f sboms/head/sbom-amd64.spdx.json ] && [ ! -f sboms/head/sbom-arm64.spdx.json ]; then
|
||||
if [ -n "$discovered" ]; then
|
||||
while IFS= read -r line; do
|
||||
[ -n "$line" ] && PLATFORMS+=("$line")
|
||||
done <<< "$discovered"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Configured platforms: ${PLATFORMS[*]:-(single platform fallback)}"
|
||||
|
||||
for platform in "${PLATFORMS[@]}"; do
|
||||
arch_tag=$(echo "$platform" | sed -e 's#^[a-zA-Z0-9_-]*/##' -e 's#/#-#g')
|
||||
|
||||
# Head image extraction & fallback
|
||||
echo "Extracting SBOM for head image ($platform)..."
|
||||
docker buildx imagetools inspect "${{ inputs.head-image }}" \
|
||||
--format '{{ json .SBOM.SPDX }}' > sboms/head/sbom-amd64.spdx.json 2>/dev/null || true
|
||||
cleanup_file sboms/head/sbom-amd64.spdx.json
|
||||
fi
|
||||
--format "{{ json (index .SBOM \"${platform}\").SPDX }}" > "sboms/head/sbom-${arch_tag}.spdx.json" 2>/dev/null || true
|
||||
cleanup_file "sboms/head/sbom-${arch_tag}.spdx.json"
|
||||
|
||||
# Fallback to generating head SBOM with Trivy if attestation missing
|
||||
if [ ! -f sboms/head/sbom-amd64.spdx.json ] && [ ! -f sboms/head/sbom-arm64.spdx.json ]; then
|
||||
echo "Head image lacks SBOM attestation; generating with Trivy..."
|
||||
trivy image --format spdx-json --output sboms/head/sbom-amd64.spdx.json "${{ inputs.head-image }}" || true
|
||||
cleanup_file sboms/head/sbom-amd64.spdx.json
|
||||
fi
|
||||
if [ ! -f "sboms/head/sbom-${arch_tag}.spdx.json" ]; then
|
||||
echo "Head image lacks SBOM attestation for $platform; generating with Trivy..."
|
||||
trivy image --platform "$platform" --format spdx-json --output "sboms/head/sbom-${arch_tag}.spdx.json" "${{ inputs.head-image }}" || true
|
||||
cleanup_file "sboms/head/sbom-${arch_tag}.spdx.json"
|
||||
fi
|
||||
|
||||
# Extract platform SBOMs for target image
|
||||
echo "Extracting platform SBOMs for target image: ${{ inputs.target-image }}..."
|
||||
docker buildx imagetools inspect "${{ inputs.target-image }}" \
|
||||
--format '{{ json (index .SBOM "linux/amd64").SPDX }}' > sboms/target/sbom-amd64.spdx.json 2>/dev/null || true
|
||||
cleanup_file sboms/target/sbom-amd64.spdx.json
|
||||
|
||||
docker buildx imagetools inspect "${{ inputs.target-image }}" \
|
||||
--format '{{ json (index .SBOM "linux/arm64").SPDX }}' > sboms/target/sbom-arm64.spdx.json 2>/dev/null || true
|
||||
cleanup_file sboms/target/sbom-arm64.spdx.json
|
||||
|
||||
if [ ! -f sboms/target/sbom-amd64.spdx.json ] && [ ! -f sboms/target/sbom-arm64.spdx.json ]; then
|
||||
# Target image extraction & fallback
|
||||
echo "Extracting SBOM for target image ($platform)..."
|
||||
docker buildx imagetools inspect "${{ inputs.target-image }}" \
|
||||
--format '{{ json .SBOM.SPDX }}' > sboms/target/sbom-amd64.spdx.json 2>/dev/null || true
|
||||
cleanup_file sboms/target/sbom-amd64.spdx.json
|
||||
--format "{{ json (index .SBOM \"${platform}\").SPDX }}" > "sboms/target/sbom-${arch_tag}.spdx.json" 2>/dev/null || true
|
||||
cleanup_file "sboms/target/sbom-${arch_tag}.spdx.json"
|
||||
|
||||
if [ ! -f "sboms/target/sbom-${arch_tag}.spdx.json" ]; then
|
||||
echo "Target image lacks SBOM attestation for $platform; generating with Trivy..."
|
||||
trivy image --platform "$platform" --format spdx-json --output "sboms/target/sbom-${arch_tag}.spdx.json" "${{ inputs.target-image }}" || true
|
||||
cleanup_file "sboms/target/sbom-${arch_tag}.spdx.json"
|
||||
fi
|
||||
done
|
||||
|
||||
# Fallbacks if no platform-specific SBOMs were extracted (e.g. single-arch image without index)
|
||||
if [ -z "$(find sboms/head -type f -name 'sbom-*.spdx.json' 2>/dev/null)" ]; then
|
||||
echo "Extracting root SBOM or scanning head image directly..."
|
||||
docker buildx imagetools inspect "${{ inputs.head-image }}" \
|
||||
--format '{{ json .SBOM.SPDX }}' > sboms/head/sbom-default.spdx.json 2>/dev/null || true
|
||||
cleanup_file sboms/head/sbom-default.spdx.json
|
||||
|
||||
if [ ! -f sboms/head/sbom-default.spdx.json ]; then
|
||||
trivy image --format spdx-json --output sboms/head/sbom-default.spdx.json "${{ inputs.head-image }}" || true
|
||||
cleanup_file sboms/head/sbom-default.spdx.json
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fallback to generating target SBOM with Trivy if attestation missing
|
||||
if [ ! -f sboms/target/sbom-amd64.spdx.json ] && [ ! -f sboms/target/sbom-arm64.spdx.json ]; then
|
||||
echo "Target image lacks SBOM attestation; attempting to generate with Trivy..."
|
||||
trivy image --format spdx-json --output sboms/target/sbom-amd64.spdx.json "${{ inputs.target-image }}" || true
|
||||
cleanup_file sboms/target/sbom-amd64.spdx.json
|
||||
if [ -z "$(find sboms/target -type f -name 'sbom-*.spdx.json' 2>/dev/null)" ]; then
|
||||
echo "Extracting root SBOM or scanning target image directly..."
|
||||
docker buildx imagetools inspect "${{ inputs.target-image }}" \
|
||||
--format '{{ json .SBOM.SPDX }}' > sboms/target/sbom-default.spdx.json 2>/dev/null || true
|
||||
cleanup_file sboms/target/sbom-default.spdx.json
|
||||
|
||||
if [ ! -f sboms/target/sbom-default.spdx.json ]; then
|
||||
trivy image --format spdx-json --output sboms/target/sbom-default.spdx.json "${{ inputs.target-image }}" || true
|
||||
cleanup_file sboms/target/sbom-default.spdx.json
|
||||
fi
|
||||
fi
|
||||
|
||||
# Expose extracted head SBOMs to workspace root for workflow artifact uploads
|
||||
[ -f sboms/head/sbom-amd64.spdx.json ] && cp sboms/head/sbom-amd64.spdx.json sbom-amd64.spdx.json || true
|
||||
[ -f sboms/head/sbom-arm64.spdx.json ] && cp sboms/head/sbom-arm64.spdx.json sbom-arm64.spdx.json || true
|
||||
for f in sboms/head/sbom-*.spdx.json; do
|
||||
[ -f "$f" ] || continue
|
||||
cp "$f" "$(basename "$f")" || true
|
||||
done
|
||||
|
||||
- name: Scan Multi-Platform SBOMs and Generate Delta
|
||||
shell: bash
|
||||
@@ -180,6 +240,13 @@ runs:
|
||||
primary_sbom="sboms/head/sbom-amd64.spdx.json"
|
||||
elif [ -f sboms/head/sbom-arm64.spdx.json ]; then
|
||||
primary_sbom="sboms/head/sbom-arm64.spdx.json"
|
||||
else
|
||||
for f in sboms/head/sbom-*.spdx.json; do
|
||||
if [ -f "$f" ]; then
|
||||
primary_sbom="$f"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -n "$primary_sbom" ]; then
|
||||
|
||||
Reference in new issue
Block a user