Files
git.stella-ops.org/.gitea/workflows/release-keyless-sign.yml
StellaOps Bot 907783f625 Add property-based tests for SBOM/VEX document ordering and Unicode normalization determinism
- Implement `SbomVexOrderingDeterminismProperties` for testing component list and vulnerability metadata hash consistency.
- Create `UnicodeNormalizationDeterminismProperties` to validate NFC normalization and Unicode string handling.
- Add project file for `StellaOps.Testing.Determinism.Properties` with necessary dependencies.
- Introduce CI/CD template validation tests including YAML syntax checks and documentation content verification.
- Create validation script for CI/CD templates ensuring all required files and structures are present.
2025-12-26 15:17:58 +02:00

400 lines
13 KiB
YAML

# .gitea/workflows/release-keyless-sign.yml
# Keyless signing for StellaOps release artifacts
#
# This workflow signs release artifacts using keyless signing (Fulcio).
# It demonstrates dogfooding of the keyless signing feature.
#
# Triggers:
# - After release bundle is published
# - Manual trigger for re-signing
#
# Artifacts signed:
# - Container images
# - CLI binaries
# - SBOM documents
# - Release manifest
name: Release Keyless Signing
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: 'Release version to sign (e.g., 2025.12.0)'
required: true
type: string
dry_run:
description: 'Dry run (skip actual signing)'
required: false
default: false
type: boolean
env:
STELLAOPS_URL: "https://api.stella-ops.internal"
REGISTRY: registry.stella-ops.org
jobs:
sign-images:
runs-on: ubuntu-22.04
permissions:
id-token: write
contents: read
packages: write
outputs:
scanner-attestation: ${{ steps.sign-scanner.outputs.attestation-digest }}
cli-attestation: ${{ steps.sign-cli.outputs.attestation-digest }}
gateway-attestation: ${{ steps.sign-gateway.outputs.attestation-digest }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Determine Version
id: version
run: |
if [[ -n "${{ github.event.inputs.version }}" ]]; then
VERSION="${{ github.event.inputs.version }}"
else
VERSION="${{ github.event.release.tag_name }}"
VERSION="${VERSION#v}"
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Release version: ${VERSION}"
- name: Install StellaOps CLI
run: |
curl -sL https://get.stella-ops.org/cli | sh
echo "$HOME/.stellaops/bin" >> $GITHUB_PATH
- name: Log in to Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Get OIDC Token
id: oidc
run: |
OIDC_TOKEN="${ACTIONS_ID_TOKEN}"
if [[ -z "$OIDC_TOKEN" ]]; then
echo "::error::OIDC token not available"
exit 1
fi
echo "::add-mask::${OIDC_TOKEN}"
echo "token=${OIDC_TOKEN}" >> $GITHUB_OUTPUT
- name: Sign Scanner Image
id: sign-scanner
if: ${{ github.event.inputs.dry_run != 'true' }}
env:
STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
run: |
VERSION="${{ steps.version.outputs.version }}"
IMAGE="${REGISTRY}/stellaops/scanner:${VERSION}"
echo "Signing scanner image: ${IMAGE}"
DIGEST=$(docker manifest inspect "${IMAGE}" -v | jq -r '.Descriptor.digest')
RESULT=$(stella attest sign \
--keyless \
--artifact "${DIGEST}" \
--type image \
--rekor \
--output json)
ATTESTATION=$(echo "$RESULT" | jq -r '.attestationDigest')
REKOR=$(echo "$RESULT" | jq -r '.rekorUuid')
echo "attestation-digest=${ATTESTATION}" >> $GITHUB_OUTPUT
echo "rekor-uuid=${REKOR}" >> $GITHUB_OUTPUT
# Push attestation to registry
stella attest push \
--attestation "${ATTESTATION}" \
--registry "stellaops/scanner"
- name: Sign CLI Image
id: sign-cli
if: ${{ github.event.inputs.dry_run != 'true' }}
env:
STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
run: |
VERSION="${{ steps.version.outputs.version }}"
IMAGE="${REGISTRY}/stellaops/cli:${VERSION}"
echo "Signing CLI image: ${IMAGE}"
DIGEST=$(docker manifest inspect "${IMAGE}" -v | jq -r '.Descriptor.digest')
RESULT=$(stella attest sign \
--keyless \
--artifact "${DIGEST}" \
--type image \
--rekor \
--output json)
ATTESTATION=$(echo "$RESULT" | jq -r '.attestationDigest')
echo "attestation-digest=${ATTESTATION}" >> $GITHUB_OUTPUT
stella attest push \
--attestation "${ATTESTATION}" \
--registry "stellaops/cli"
- name: Sign Gateway Image
id: sign-gateway
if: ${{ github.event.inputs.dry_run != 'true' }}
env:
STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
run: |
VERSION="${{ steps.version.outputs.version }}"
IMAGE="${REGISTRY}/stellaops/gateway:${VERSION}"
echo "Signing gateway image: ${IMAGE}"
DIGEST=$(docker manifest inspect "${IMAGE}" -v | jq -r '.Descriptor.digest')
RESULT=$(stella attest sign \
--keyless \
--artifact "${DIGEST}" \
--type image \
--rekor \
--output json)
ATTESTATION=$(echo "$RESULT" | jq -r '.attestationDigest')
echo "attestation-digest=${ATTESTATION}" >> $GITHUB_OUTPUT
stella attest push \
--attestation "${ATTESTATION}" \
--registry "stellaops/gateway"
sign-binaries:
runs-on: ubuntu-22.04
permissions:
id-token: write
contents: read
outputs:
cli-linux-x64: ${{ steps.sign-cli-linux-x64.outputs.attestation-digest }}
cli-linux-arm64: ${{ steps.sign-cli-linux-arm64.outputs.attestation-digest }}
cli-darwin-x64: ${{ steps.sign-cli-darwin-x64.outputs.attestation-digest }}
cli-darwin-arm64: ${{ steps.sign-cli-darwin-arm64.outputs.attestation-digest }}
cli-windows-x64: ${{ steps.sign-cli-windows-x64.outputs.attestation-digest }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Determine Version
id: version
run: |
if [[ -n "${{ github.event.inputs.version }}" ]]; then
VERSION="${{ github.event.inputs.version }}"
else
VERSION="${{ github.event.release.tag_name }}"
VERSION="${VERSION#v}"
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Install StellaOps CLI
run: |
curl -sL https://get.stella-ops.org/cli | sh
echo "$HOME/.stellaops/bin" >> $GITHUB_PATH
- name: Download Release Artifacts
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ steps.version.outputs.version }}"
mkdir -p artifacts
# Download CLI binaries
gh release download "v${VERSION}" \
--pattern "stellaops-cli-*" \
--dir artifacts \
|| echo "No CLI binaries found"
- name: Get OIDC Token
id: oidc
run: |
OIDC_TOKEN="${ACTIONS_ID_TOKEN}"
echo "::add-mask::${OIDC_TOKEN}"
echo "token=${OIDC_TOKEN}" >> $GITHUB_OUTPUT
- name: Sign CLI Binary (linux-x64)
id: sign-cli-linux-x64
if: ${{ github.event.inputs.dry_run != 'true' }}
env:
STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
run: |
BINARY="artifacts/stellaops-cli-linux-x64"
if [[ -f "$BINARY" ]]; then
DIGEST="sha256:$(sha256sum "$BINARY" | cut -d' ' -f1)"
RESULT=$(stella attest sign \
--keyless \
--artifact "${DIGEST}" \
--type binary \
--rekor \
--output json)
ATTESTATION=$(echo "$RESULT" | jq -r '.attestationDigest')
echo "attestation-digest=${ATTESTATION}" >> $GITHUB_OUTPUT
fi
- name: Sign CLI Binary (linux-arm64)
id: sign-cli-linux-arm64
if: ${{ github.event.inputs.dry_run != 'true' }}
env:
STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
run: |
BINARY="artifacts/stellaops-cli-linux-arm64"
if [[ -f "$BINARY" ]]; then
DIGEST="sha256:$(sha256sum "$BINARY" | cut -d' ' -f1)"
RESULT=$(stella attest sign \
--keyless \
--artifact "${DIGEST}" \
--type binary \
--rekor \
--output json)
ATTESTATION=$(echo "$RESULT" | jq -r '.attestationDigest')
echo "attestation-digest=${ATTESTATION}" >> $GITHUB_OUTPUT
fi
- name: Sign CLI Binary (darwin-x64)
id: sign-cli-darwin-x64
if: ${{ github.event.inputs.dry_run != 'true' }}
env:
STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
run: |
BINARY="artifacts/stellaops-cli-darwin-x64"
if [[ -f "$BINARY" ]]; then
DIGEST="sha256:$(sha256sum "$BINARY" | cut -d' ' -f1)"
RESULT=$(stella attest sign \
--keyless \
--artifact "${DIGEST}" \
--type binary \
--rekor \
--output json)
ATTESTATION=$(echo "$RESULT" | jq -r '.attestationDigest')
echo "attestation-digest=${ATTESTATION}" >> $GITHUB_OUTPUT
fi
- name: Sign CLI Binary (darwin-arm64)
id: sign-cli-darwin-arm64
if: ${{ github.event.inputs.dry_run != 'true' }}
env:
STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
run: |
BINARY="artifacts/stellaops-cli-darwin-arm64"
if [[ -f "$BINARY" ]]; then
DIGEST="sha256:$(sha256sum "$BINARY" | cut -d' ' -f1)"
RESULT=$(stella attest sign \
--keyless \
--artifact "${DIGEST}" \
--type binary \
--rekor \
--output json)
ATTESTATION=$(echo "$RESULT" | jq -r '.attestationDigest')
echo "attestation-digest=${ATTESTATION}" >> $GITHUB_OUTPUT
fi
- name: Sign CLI Binary (windows-x64)
id: sign-cli-windows-x64
if: ${{ github.event.inputs.dry_run != 'true' }}
env:
STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
run: |
BINARY="artifacts/stellaops-cli-windows-x64.exe"
if [[ -f "$BINARY" ]]; then
DIGEST="sha256:$(sha256sum "$BINARY" | cut -d' ' -f1)"
RESULT=$(stella attest sign \
--keyless \
--artifact "${DIGEST}" \
--type binary \
--rekor \
--output json)
ATTESTATION=$(echo "$RESULT" | jq -r '.attestationDigest')
echo "attestation-digest=${ATTESTATION}" >> $GITHUB_OUTPUT
fi
verify-signatures:
needs: [sign-images, sign-binaries]
runs-on: ubuntu-22.04
permissions:
contents: read
packages: read
steps:
- name: Install StellaOps CLI
run: |
curl -sL https://get.stella-ops.org/cli | sh
echo "$HOME/.stellaops/bin" >> $GITHUB_PATH
- name: Determine Version
id: version
run: |
if [[ -n "${{ github.event.inputs.version }}" ]]; then
VERSION="${{ github.event.inputs.version }}"
else
VERSION="${{ github.event.release.tag_name }}"
VERSION="${VERSION#v}"
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Verify Scanner Image
if: ${{ github.event.inputs.dry_run != 'true' }}
run: |
VERSION="${{ steps.version.outputs.version }}"
IMAGE="${REGISTRY}/stellaops/scanner:${VERSION}"
DIGEST=$(docker manifest inspect "${IMAGE}" -v | jq -r '.Descriptor.digest')
stella attest verify \
--artifact "${DIGEST}" \
--certificate-identity "stella-ops.org/git.stella-ops.org:ref:refs/tags/v${VERSION}" \
--certificate-oidc-issuer "https://git.stella-ops.org" \
--require-rekor
- name: Summary
run: |
VERSION="${{ steps.version.outputs.version }}"
cat >> $GITHUB_STEP_SUMMARY << EOF
## Release v${VERSION} Signed
### Container Images
| Image | Attestation |
|-------|-------------|
| scanner | \`${{ needs.sign-images.outputs.scanner-attestation }}\` |
| cli | \`${{ needs.sign-images.outputs.cli-attestation }}\` |
| gateway | \`${{ needs.sign-images.outputs.gateway-attestation }}\` |
### CLI Binaries
| Platform | Attestation |
|----------|-------------|
| linux-x64 | \`${{ needs.sign-binaries.outputs.cli-linux-x64 }}\` |
| linux-arm64 | \`${{ needs.sign-binaries.outputs.cli-linux-arm64 }}\` |
| darwin-x64 | \`${{ needs.sign-binaries.outputs.cli-darwin-x64 }}\` |
| darwin-arm64 | \`${{ needs.sign-binaries.outputs.cli-darwin-arm64 }}\` |
| windows-x64 | \`${{ needs.sign-binaries.outputs.cli-windows-x64 }}\` |
### Verification
\`\`\`bash
stella attest verify \\
--artifact "sha256:..." \\
--certificate-identity "stella-ops.org/git.stella-ops.org:ref:refs/tags/v${VERSION}" \\
--certificate-oidc-issuer "https://git.stella-ops.org"
\`\`\`
EOF