Files
git.stella-ops.org/ops/deployment/advisory-ai/package-advisory-feeds.sh
StellaOps Bot 2e70c9fdb6
Some checks failed
LNM Migration CI / build-runner (push) Has been cancelled
Ledger OpenAPI CI / deprecation-check (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Airgap Sealed CI Smoke / sealed-smoke (push) Has been cancelled
Ledger Packs CI / build-pack (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Ledger OpenAPI CI / validate-oas (push) Has been cancelled
Ledger OpenAPI CI / check-wellknown (push) Has been cancelled
Ledger Packs CI / verify-pack (push) Has been cancelled
LNM Migration CI / validate-metrics (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
up
2025-12-14 18:33:02 +02:00

166 lines
4.5 KiB
Bash

#!/usr/bin/env bash
# Package advisory feeds (SBOM pointers + provenance) for release/offline kit
# Usage: ./package-advisory-feeds.sh
# Dev mode: COSIGN_ALLOW_DEV_KEY=1 COSIGN_PASSWORD=stellaops-dev ./package-advisory-feeds.sh
set -euo pipefail
ROOT=$(cd "$(dirname "$0")/../../.." && pwd)
OUT_DIR="${OUT_DIR:-$ROOT/out/advisory-ai/feeds}"
CREATED="${CREATED:-$(date -u +%Y-%m-%dT%H:%M:%SZ)}"
mkdir -p "$OUT_DIR"
# Key resolution (same pattern as tools/cosign/sign-signals.sh)
resolve_key() {
if [[ -n "${COSIGN_KEY_FILE:-}" && -f "$COSIGN_KEY_FILE" ]]; then
echo "$COSIGN_KEY_FILE"
elif [[ -n "${COSIGN_PRIVATE_KEY_B64:-}" ]]; then
local tmp_key="$OUT_DIR/.cosign.key"
echo "$COSIGN_PRIVATE_KEY_B64" | base64 -d > "$tmp_key"
chmod 600 "$tmp_key"
echo "$tmp_key"
elif [[ -f "$ROOT/tools/cosign/cosign.key" ]]; then
echo "$ROOT/tools/cosign/cosign.key"
elif [[ "${COSIGN_ALLOW_DEV_KEY:-0}" == "1" && -f "$ROOT/tools/cosign/cosign.dev.key" ]]; then
echo "[info] Using development key (non-production)" >&2
echo "$ROOT/tools/cosign/cosign.dev.key"
else
echo "[error] No signing key available. Set COSIGN_PRIVATE_KEY_B64 or COSIGN_ALLOW_DEV_KEY=1" >&2
return 1
fi
}
KEY_FILE=$(resolve_key)
# Collect advisory feed sources
FEED_SOURCES=(
"$ROOT/docs/samples/advisory-feeds"
"$ROOT/src/AdvisoryAI/feeds"
"$ROOT/out/feeds"
)
echo "==> Collecting advisory feeds..."
STAGE_DIR="$OUT_DIR/stage"
mkdir -p "$STAGE_DIR"
for src in "${FEED_SOURCES[@]}"; do
if [[ -d "$src" ]]; then
echo " Adding feeds from $src"
cp -r "$src"/* "$STAGE_DIR/" 2>/dev/null || true
fi
done
# Create placeholder if no feeds found (dev mode)
if [[ -z "$(ls -A "$STAGE_DIR" 2>/dev/null)" ]]; then
echo "[info] No feed sources found; creating placeholder for dev mode"
cat > "$STAGE_DIR/placeholder.json" <<EOF
{
"type": "advisory-feed-placeholder",
"created": "$CREATED",
"note": "Placeholder for development; replace with real feeds in production"
}
EOF
fi
# Create feed bundle
echo "==> Creating feed bundle..."
BUNDLE_TAR="$OUT_DIR/advisory-feeds.tar.gz"
tar -czf "$BUNDLE_TAR" -C "$STAGE_DIR" .
# Compute hashes
sha256() {
sha256sum "$1" | awk '{print $1}'
}
BUNDLE_HASH=$(sha256 "$BUNDLE_TAR")
# Generate manifest with SBOM pointers
echo "==> Generating manifest..."
MANIFEST="$OUT_DIR/advisory-feeds.manifest.json"
cat > "$MANIFEST" <<EOF
{
"schemaVersion": "1.0.0",
"created": "$CREATED",
"bundle": {
"path": "advisory-feeds.tar.gz",
"sha256": "$BUNDLE_HASH",
"size": $(stat -c%s "$BUNDLE_TAR" 2>/dev/null || stat -f%z "$BUNDLE_TAR")
},
"sbom": {
"format": "spdx-json",
"path": "advisory-feeds.sbom.json",
"note": "SBOM generated during CI; pointer only in manifest"
},
"provenance": {
"path": "provenance.json",
"builder": "stellaops-advisory-ai-release"
}
}
EOF
# Sign manifest with DSSE
echo "==> Signing manifest..."
DSSE_OUT="$OUT_DIR/advisory-feeds.manifest.dsse.json"
# Check for cosign
COSIGN="${COSIGN:-$ROOT/tools/cosign/cosign}"
if ! command -v cosign &>/dev/null && [[ ! -x "$COSIGN" ]]; then
echo "[warn] cosign not found; skipping DSSE signing" >&2
else
COSIGN_CMD="${COSIGN:-cosign}"
if command -v cosign &>/dev/null; then
COSIGN_CMD="cosign"
fi
COSIGN_PASSWORD="${COSIGN_PASSWORD:-}" "$COSIGN_CMD" sign-blob \
--key "$KEY_FILE" \
--bundle "$DSSE_OUT" \
--tlog-upload=false \
--yes \
"$MANIFEST" 2>/dev/null || echo "[warn] DSSE signing skipped (cosign error)"
fi
# Generate provenance
echo "==> Generating provenance..."
PROVENANCE="$OUT_DIR/provenance.json"
cat > "$PROVENANCE" <<EOF
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
{
"name": "advisory-feeds.tar.gz",
"digest": {"sha256": "$BUNDLE_HASH"}
}
],
"predicateType": "https://slsa.dev/provenance/v1",
"predicate": {
"buildDefinition": {
"buildType": "https://stella-ops.org/advisory-ai-release/v1",
"externalParameters": {},
"internalParameters": {
"created": "$CREATED"
}
},
"runDetails": {
"builder": {
"id": "https://stella-ops.org/advisory-ai-release"
},
"metadata": {
"invocationId": "$(uuidgen 2>/dev/null || echo "dev-$(date +%s)")",
"startedOn": "$CREATED"
}
}
}
}
EOF
# Cleanup temp key
[[ -f "$OUT_DIR/.cosign.key" ]] && rm -f "$OUT_DIR/.cosign.key"
echo "==> Advisory feed packaging complete"
echo " Bundle: $BUNDLE_TAR"
echo " Manifest: $MANIFEST"
echo " DSSE: $DSSE_OUT"
echo " Provenance: $PROVENANCE"