154 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			YAML
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			YAML
		
	
	
	
	
	
name: Buildx SBOM Demo
 | 
						|
on:
 | 
						|
  workflow_dispatch:
 | 
						|
  push:
 | 
						|
    branches: [ demo/buildx ]
 | 
						|
 | 
						|
jobs:
 | 
						|
  buildx-sbom:
 | 
						|
    runs-on: ubuntu-latest
 | 
						|
    steps:
 | 
						|
      - uses: actions/checkout@v4
 | 
						|
 | 
						|
      - name: Set up Docker Buildx
 | 
						|
        uses: docker/setup-buildx-action@v3
 | 
						|
 | 
						|
      - name: Set up .NET 10 preview
 | 
						|
        uses: actions/setup-dotnet@v4
 | 
						|
        with:
 | 
						|
          dotnet-version: '10.0.x'
 | 
						|
 | 
						|
      - name: Publish StellaOps BuildX generator
 | 
						|
        run: |
 | 
						|
          dotnet publish src/Scanner/StellaOps.Scanner.Sbomer.BuildXPlugin/StellaOps.Scanner.Sbomer.BuildXPlugin.csproj \
 | 
						|
            -c Release \
 | 
						|
            -o out/buildx
 | 
						|
 | 
						|
      - name: Handshake CAS
 | 
						|
        run: |
 | 
						|
          dotnet out/buildx/StellaOps.Scanner.Sbomer.BuildXPlugin.dll handshake \
 | 
						|
            --manifest out/buildx \
 | 
						|
            --cas out/cas
 | 
						|
 | 
						|
      - name: Build demo container image
 | 
						|
        run: |
 | 
						|
          docker buildx build --load -t stellaops/buildx-demo:ci samples/ci/buildx-demo
 | 
						|
 | 
						|
      - name: Capture image digest
 | 
						|
        id: digest
 | 
						|
        run: |
 | 
						|
          DIGEST=$(docker image inspect stellaops/buildx-demo:ci --format '{{index .RepoDigests 0}}')
 | 
						|
          echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"
 | 
						|
 | 
						|
      - name: Generate SBOM from built image
 | 
						|
        run: |
 | 
						|
          mkdir -p out
 | 
						|
          docker sbom stellaops/buildx-demo:ci --format cyclonedx-json > out/buildx-sbom.cdx.json
 | 
						|
 | 
						|
      - name: Start mock Attestor
 | 
						|
        id: attestor
 | 
						|
        run: |
 | 
						|
          mkdir -p out
 | 
						|
          cat <<'PY' > out/mock-attestor.py
 | 
						|
import json
 | 
						|
import os
 | 
						|
from http.server import BaseHTTPRequestHandler, HTTPServer
 | 
						|
 | 
						|
class Handler(BaseHTTPRequestHandler):
 | 
						|
    def do_POST(self):
 | 
						|
        length = int(self.headers.get('Content-Length') or 0)
 | 
						|
        body = self.rfile.read(length)
 | 
						|
        with open(os.path.join('out', 'provenance-request.json'), 'wb') as fp:
 | 
						|
            fp.write(body)
 | 
						|
        self.send_response(202)
 | 
						|
        self.end_headers()
 | 
						|
        self.wfile.write(b'accepted')
 | 
						|
 | 
						|
    def log_message(self, format, *args):
 | 
						|
        return
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    server = HTTPServer(('127.0.0.1', 8085), Handler)
 | 
						|
    try:
 | 
						|
        server.serve_forever()
 | 
						|
    except KeyboardInterrupt:
 | 
						|
        pass
 | 
						|
    finally:
 | 
						|
        server.server_close()
 | 
						|
PY
 | 
						|
          touch out/provenance-request.json
 | 
						|
          python3 out/mock-attestor.py &
 | 
						|
          echo $! > out/mock-attestor.pid
 | 
						|
 | 
						|
      - name: Emit descriptor with provenance placeholder
 | 
						|
        env:
 | 
						|
          IMAGE_DIGEST: ${{ steps.digest.outputs.digest }}
 | 
						|
          # Uncomment the next line and remove the mock Attestor block to hit a real service.
 | 
						|
          # STELLAOPS_ATTESTOR_TOKEN: ${{ secrets.STELLAOPS_ATTESTOR_TOKEN }}
 | 
						|
        run: |
 | 
						|
          dotnet out/buildx/StellaOps.Scanner.Sbomer.BuildXPlugin.dll descriptor \
 | 
						|
            --manifest out/buildx \
 | 
						|
            --image "$IMAGE_DIGEST" \
 | 
						|
            --sbom out/buildx-sbom.cdx.json \
 | 
						|
            --sbom-name buildx-sbom.cdx.json \
 | 
						|
            --artifact-type application/vnd.stellaops.sbom.layer+json \
 | 
						|
            --sbom-format cyclonedx-json \
 | 
						|
            --sbom-kind inventory \
 | 
						|
            --repository ${{ github.repository }} \
 | 
						|
            --build-ref ${{ github.sha }} \
 | 
						|
            --attestor http://127.0.0.1:8085/provenance \
 | 
						|
            > out/buildx-descriptor.json
 | 
						|
 | 
						|
      - name: Verify descriptor determinism
 | 
						|
        env:
 | 
						|
          IMAGE_DIGEST: ${{ steps.digest.outputs.digest }}
 | 
						|
        run: |
 | 
						|
          dotnet out/buildx/StellaOps.Scanner.Sbomer.BuildXPlugin.dll descriptor \
 | 
						|
            --manifest out/buildx \
 | 
						|
            --image "$IMAGE_DIGEST" \
 | 
						|
            --sbom out/buildx-sbom.cdx.json \
 | 
						|
            --sbom-name buildx-sbom.cdx.json \
 | 
						|
            --artifact-type application/vnd.stellaops.sbom.layer+json \
 | 
						|
            --sbom-format cyclonedx-json \
 | 
						|
            --sbom-kind inventory \
 | 
						|
            --repository ${{ github.repository }} \
 | 
						|
            --build-ref ${{ github.sha }} \
 | 
						|
            > out/buildx-descriptor-repeat.json
 | 
						|
 | 
						|
          python - <<'PY'
 | 
						|
import json
 | 
						|
 | 
						|
def normalize(path: str) -> dict:
 | 
						|
    with open(path, 'r', encoding='utf-8') as handle:
 | 
						|
        data = json.load(handle)
 | 
						|
    data.pop('generatedAt', None)
 | 
						|
    return data
 | 
						|
 | 
						|
baseline = normalize('out/buildx-descriptor.json')
 | 
						|
repeat = normalize('out/buildx-descriptor-repeat.json')
 | 
						|
 | 
						|
if baseline != repeat:
 | 
						|
    raise SystemExit('Descriptor output changed between runs.')
 | 
						|
PY
 | 
						|
 | 
						|
      - name: Stop mock Attestor
 | 
						|
        if: always()
 | 
						|
        run: |
 | 
						|
          if [ -f out/mock-attestor.pid ]; then
 | 
						|
            kill $(cat out/mock-attestor.pid)
 | 
						|
          fi
 | 
						|
 | 
						|
      - name: Upload artifacts
 | 
						|
        uses: actions/upload-artifact@v4
 | 
						|
        with:
 | 
						|
          name: stellaops-buildx-demo
 | 
						|
          path: |
 | 
						|
            out/buildx-descriptor.json
 | 
						|
            out/buildx-sbom.cdx.json
 | 
						|
            out/provenance-request.json
 | 
						|
            out/buildx-descriptor-repeat.json
 | 
						|
 | 
						|
      - name: Show descriptor summary
 | 
						|
        run: |
 | 
						|
          cat out/buildx-descriptor.json
 |