Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.
This commit is contained in:
267
.gitea/workflows/templates/replay-verify.yml
Normal file
267
.gitea/workflows/templates/replay-verify.yml
Normal file
@@ -0,0 +1,267 @@
|
||||
# =============================================================================
|
||||
# replay-verify.yml
|
||||
# Sprint: SPRINT_20251228_001_BE_replay_manifest_ci (T4)
|
||||
# Description: CI workflow template for SBOM hash drift detection
|
||||
# =============================================================================
|
||||
#
|
||||
# This workflow verifies that SBOM generation and verdict computation are
|
||||
# deterministic by comparing replay manifest hashes across builds.
|
||||
#
|
||||
# Usage:
|
||||
# 1. Copy this template to your project's .gitea/workflows/ directory
|
||||
# 2. Adjust the image name and scan parameters as needed
|
||||
# 3. Optionally enable the SBOM attestation step
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 - Verification passed, all hashes match
|
||||
# 1 - Drift detected, hashes differ
|
||||
# 2 - Verification error (missing inputs, invalid manifest)
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
name: SBOM Replay Verification
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
fail_on_drift:
|
||||
description: 'Fail build if hash drift detected'
|
||||
required: false
|
||||
default: 'true'
|
||||
type: boolean
|
||||
strict_mode:
|
||||
description: 'Enable strict verification mode'
|
||||
required: false
|
||||
default: 'false'
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
STELLAOPS_VERSION: '1.0.0'
|
||||
|
||||
jobs:
|
||||
build-and-scan:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write # For OIDC-based signing
|
||||
|
||||
outputs:
|
||||
image_digest: ${{ steps.build.outputs.digest }}
|
||||
sbom_digest: ${{ steps.scan.outputs.sbom_digest }}
|
||||
verdict_digest: ${{ steps.scan.outputs.verdict_digest }}
|
||||
replay_manifest: ${{ steps.scan.outputs.replay_manifest }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to container registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=sha,prefix=
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
|
||||
- name: Build and push image
|
||||
id: build
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
provenance: true
|
||||
sbom: false # We generate our own SBOM
|
||||
|
||||
- name: Install StellaOps CLI
|
||||
run: |
|
||||
curl -sSfL https://stellaops.io/install.sh | sh -s -- -v ${{ env.STELLAOPS_VERSION }}
|
||||
echo "$HOME/.stellaops/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Scan image and generate replay manifest
|
||||
id: scan
|
||||
env:
|
||||
IMAGE_REF: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
|
||||
run: |
|
||||
# Scan image with StellaOps
|
||||
stella scan \
|
||||
--image "${IMAGE_REF}" \
|
||||
--output-sbom sbom.json \
|
||||
--output-findings findings.json \
|
||||
--output-verdict verdict.json \
|
||||
--format cyclonedx-1.6
|
||||
|
||||
# Export replay manifest for CI verification
|
||||
stella replay export \
|
||||
--image "${IMAGE_REF}" \
|
||||
--output replay.json \
|
||||
--include-feeds \
|
||||
--include-reachability \
|
||||
--pretty
|
||||
|
||||
# Extract digests for outputs
|
||||
SBOM_DIGEST=$(sha256sum sbom.json | cut -d' ' -f1)
|
||||
VERDICT_DIGEST=$(sha256sum verdict.json | cut -d' ' -f1)
|
||||
|
||||
echo "sbom_digest=sha256:${SBOM_DIGEST}" >> $GITHUB_OUTPUT
|
||||
echo "verdict_digest=sha256:${VERDICT_DIGEST}" >> $GITHUB_OUTPUT
|
||||
echo "replay_manifest=replay.json" >> $GITHUB_OUTPUT
|
||||
|
||||
# Display summary
|
||||
echo "### Scan Results" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Artifact | Digest |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "|----------|--------|" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Image | \`${{ steps.build.outputs.digest }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| SBOM | \`sha256:${SBOM_DIGEST}\` |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Verdict | \`sha256:${VERDICT_DIGEST}\` |" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Upload scan artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: scan-artifacts-${{ github.sha }}
|
||||
path: |
|
||||
sbom.json
|
||||
findings.json
|
||||
verdict.json
|
||||
replay.json
|
||||
retention-days: 30
|
||||
|
||||
verify-determinism:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-and-scan
|
||||
|
||||
steps:
|
||||
- name: Download scan artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: scan-artifacts-${{ github.sha }}
|
||||
|
||||
- name: Install StellaOps CLI
|
||||
run: |
|
||||
curl -sSfL https://stellaops.io/install.sh | sh -s -- -v ${{ env.STELLAOPS_VERSION }}
|
||||
echo "$HOME/.stellaops/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Verify SBOM determinism
|
||||
id: verify
|
||||
env:
|
||||
FAIL_ON_DRIFT: ${{ inputs.fail_on_drift || 'true' }}
|
||||
STRICT_MODE: ${{ inputs.strict_mode || 'false' }}
|
||||
run: |
|
||||
# Build verification flags
|
||||
VERIFY_FLAGS="--manifest replay.json"
|
||||
if [ "${FAIL_ON_DRIFT}" = "true" ]; then
|
||||
VERIFY_FLAGS="${VERIFY_FLAGS} --fail-on-drift"
|
||||
fi
|
||||
if [ "${STRICT_MODE}" = "true" ]; then
|
||||
VERIFY_FLAGS="${VERIFY_FLAGS} --strict-mode"
|
||||
fi
|
||||
|
||||
# Run verification
|
||||
stella replay export verify ${VERIFY_FLAGS}
|
||||
EXIT_CODE=$?
|
||||
|
||||
# Report results
|
||||
if [ $EXIT_CODE -eq 0 ]; then
|
||||
echo "✅ Verification passed - all hashes match" >> $GITHUB_STEP_SUMMARY
|
||||
echo "status=success" >> $GITHUB_OUTPUT
|
||||
elif [ $EXIT_CODE -eq 1 ]; then
|
||||
echo "⚠️ Drift detected - hashes differ from expected" >> $GITHUB_STEP_SUMMARY
|
||||
echo "status=drift" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "❌ Verification error" >> $GITHUB_STEP_SUMMARY
|
||||
echo "status=error" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
exit $EXIT_CODE
|
||||
|
||||
- name: Comment on PR (on drift)
|
||||
if: failure() && github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: `## ⚠️ SBOM Determinism Check Failed
|
||||
|
||||
Hash drift detected between scan runs. This may indicate non-deterministic build or scan behavior.
|
||||
|
||||
**Expected digests:**
|
||||
- SBOM: \`${{ needs.build-and-scan.outputs.sbom_digest }}\`
|
||||
- Verdict: \`${{ needs.build-and-scan.outputs.verdict_digest }}\`
|
||||
|
||||
**Possible causes:**
|
||||
- Non-deterministic build artifacts (timestamps, random values)
|
||||
- Changed dependencies between runs
|
||||
- Environment differences
|
||||
|
||||
**Next steps:**
|
||||
1. Review the replay manifest in the artifacts
|
||||
2. Check build logs for non-deterministic elements
|
||||
3. Consider using \`--strict-mode\` for detailed drift analysis`
|
||||
})
|
||||
|
||||
# Optional: Attest SBOM to OCI registry
|
||||
attest-sbom:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-and-scan, verify-determinism]
|
||||
if: github.event_name != 'pull_request' && success()
|
||||
permissions:
|
||||
packages: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Download scan artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: scan-artifacts-${{ github.sha }}
|
||||
|
||||
- name: Install StellaOps CLI
|
||||
run: |
|
||||
curl -sSfL https://stellaops.io/install.sh | sh -s -- -v ${{ env.STELLAOPS_VERSION }}
|
||||
echo "$HOME/.stellaops/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Log in to container registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Attach SBOM attestation
|
||||
env:
|
||||
IMAGE_REF: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build-and-scan.outputs.image_digest }}
|
||||
run: |
|
||||
# Sign and attach SBOM as in-toto attestation
|
||||
stella attest attach \
|
||||
--image "${IMAGE_REF}" \
|
||||
--sbom sbom.json \
|
||||
--predicate-type https://cyclonedx.org/bom/v1.6 \
|
||||
--sign keyless
|
||||
|
||||
echo "### SBOM Attestation" >> $GITHUB_STEP_SUMMARY
|
||||
echo "SBOM attached to \`${IMAGE_REF}\`" >> $GITHUB_STEP_SUMMARY
|
||||
Reference in New Issue
Block a user