Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
console-runner-image / build-runner-image (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
87 lines
3.1 KiB
Bash
87 lines
3.1 KiB
Bash
#!/usr/bin/env bash
|
|
# Build console container image with SBOM and optional attestations
|
|
# Usage: ./build-console-image.sh [tag] [registry]
|
|
# Example: ./build-console-image.sh 2025.10.0-edge ghcr.io/stellaops
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
|
|
|
TAG="${1:-$(date +%Y%m%dT%H%M%S)}"
|
|
REGISTRY="${2:-registry.stella-ops.org/stellaops}"
|
|
IMAGE_NAME="console"
|
|
FULL_IMAGE="${REGISTRY}/${IMAGE_NAME}:${TAG}"
|
|
|
|
# Freeze timestamps for reproducibility
|
|
export SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH:-1704067200}
|
|
|
|
echo "==> Building console image: ${FULL_IMAGE}"
|
|
|
|
# Build using the existing Dockerfile.console
|
|
docker build \
|
|
--file "${REPO_ROOT}/ops/devops/docker/Dockerfile.console" \
|
|
--build-arg APP_DIR=src/Web/StellaOps.Web \
|
|
--build-arg APP_PORT=8080 \
|
|
--tag "${FULL_IMAGE}" \
|
|
--label "org.opencontainers.image.created=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
--label "org.opencontainers.image.revision=$(git -C "${REPO_ROOT}" rev-parse HEAD 2>/dev/null || echo 'unknown')" \
|
|
--label "org.opencontainers.image.source=https://github.com/stellaops/stellaops" \
|
|
--label "org.opencontainers.image.title=StellaOps Console" \
|
|
--label "org.opencontainers.image.description=StellaOps Angular Console (non-root nginx)" \
|
|
"${REPO_ROOT}"
|
|
|
|
# Get digest
|
|
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "${FULL_IMAGE}" 2>/dev/null || echo "${FULL_IMAGE}")
|
|
|
|
echo "==> Image built: ${FULL_IMAGE}"
|
|
echo "==> Digest: ${DIGEST}"
|
|
|
|
# Output metadata for CI
|
|
mkdir -p "${SCRIPT_DIR}/../artifacts/console"
|
|
cat > "${SCRIPT_DIR}/../artifacts/console/build-metadata.json" <<EOF
|
|
{
|
|
"image": "${FULL_IMAGE}",
|
|
"digest": "${DIGEST}",
|
|
"tag": "${TAG}",
|
|
"registry": "${REGISTRY}",
|
|
"buildTime": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
"gitCommit": "$(git -C "${REPO_ROOT}" rev-parse HEAD 2>/dev/null || echo 'unknown')",
|
|
"sourceDateEpoch": "${SOURCE_DATE_EPOCH}"
|
|
}
|
|
EOF
|
|
|
|
echo "==> Build metadata written to ops/devops/artifacts/console/build-metadata.json"
|
|
|
|
# Generate SBOM if syft is available
|
|
if command -v syft &>/dev/null; then
|
|
echo "==> Generating SBOM..."
|
|
syft "${FULL_IMAGE}" -o spdx-json > "${SCRIPT_DIR}/../artifacts/console/console.spdx.json"
|
|
syft "${FULL_IMAGE}" -o cyclonedx-json > "${SCRIPT_DIR}/../artifacts/console/console.cdx.json"
|
|
echo "==> SBOMs written to ops/devops/artifacts/console/"
|
|
else
|
|
echo "==> Skipping SBOM generation (syft not found)"
|
|
fi
|
|
|
|
# Sign and attest if cosign is available and key is set
|
|
if command -v cosign &>/dev/null; then
|
|
if [[ -n "${COSIGN_KEY:-}" ]]; then
|
|
echo "==> Signing image with cosign..."
|
|
cosign sign --key "${COSIGN_KEY}" "${FULL_IMAGE}"
|
|
|
|
if [[ -f "${SCRIPT_DIR}/../artifacts/console/console.spdx.json" ]]; then
|
|
echo "==> Attesting SBOM..."
|
|
cosign attest --predicate "${SCRIPT_DIR}/../artifacts/console/console.spdx.json" \
|
|
--type spdx --key "${COSIGN_KEY}" "${FULL_IMAGE}"
|
|
fi
|
|
echo "==> Image signed and attested"
|
|
else
|
|
echo "==> Skipping signing (COSIGN_KEY not set)"
|
|
fi
|
|
else
|
|
echo "==> Skipping signing (cosign not found)"
|
|
fi
|
|
|
|
echo "==> Console image build complete"
|
|
echo " Image: ${FULL_IMAGE}"
|