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.
This commit is contained in:
399
.gitea/workflows/release-keyless-sign.yml
Normal file
399
.gitea/workflows/release-keyless-sign.yml
Normal file
@@ -0,0 +1,399 @@
|
||||
# .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
|
||||
Reference in New Issue
Block a user