- 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.
400 lines
13 KiB
YAML
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
|