name: wine-csp-build on: push: branches: [main, develop] paths: - 'src/__Tools/WineCspService/**' - 'ops/wine-csp/**' - 'third_party/forks/AlexMAS.GostCryptography/**' - '.gitea/workflows/wine-csp-build.yml' pull_request: paths: - 'src/__Tools/WineCspService/**' - 'ops/wine-csp/**' - 'third_party/forks/AlexMAS.GostCryptography/**' workflow_dispatch: inputs: push: description: "Push to registry" required: false default: "false" version: description: "Version tag (e.g., 2025.10.0-edge)" required: false default: "2025.10.0-edge" env: IMAGE_NAME: registry.stella-ops.org/stellaops/wine-csp DOCKERFILE: ops/wine-csp/Dockerfile # Wine CSP only supports linux/amd64 (Wine ARM64 has compatibility issues with Windows x64 apps) PLATFORMS: linux/amd64 jobs: build: name: Build Wine CSP Image runs-on: ubuntu-latest permissions: contents: read packages: write steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: install: true - name: Install syft (SBOM generation) uses: anchore/sbom-action/download-syft@v0 - name: Install cosign (attestation) uses: sigstore/cosign-installer@v3.7.0 - name: Set version tag id: version run: | if [[ -n "${{ github.event.inputs.version }}" ]]; then echo "tag=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT elif [[ "${{ github.ref }}" == "refs/heads/main" ]]; then echo "tag=2025.10.0-edge" >> $GITHUB_OUTPUT else echo "tag=pr-${{ github.event.pull_request.number || github.sha }}" >> $GITHUB_OUTPUT fi - name: Docker metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.IMAGE_NAME }} tags: | type=raw,value=${{ steps.version.outputs.tag }} type=sha,format=short - name: Build image (no push) id: build uses: docker/build-push-action@v6 with: context: . file: ${{ env.DOCKERFILE }} platforms: ${{ env.PLATFORMS }} push: false load: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max - name: Test container startup run: | set -e echo "Starting Wine CSP container for health check test..." # Run container in detached mode docker run -d --name wine-csp-test \ -e WINE_CSP_MODE=limited \ -e WINE_CSP_LOG_LEVEL=Debug \ -p 5099:5099 \ "${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}" # Wait for container startup (Wine takes time to initialize) echo "Waiting for container startup (90s max)..." for i in $(seq 1 18); do sleep 5 if curl -sf http://127.0.0.1:5099/health > /dev/null 2>&1; then echo "Health check passed after $((i * 5))s" break fi echo "Waiting... ($((i * 5))s elapsed)" done # Final health check echo "Final health check:" curl -sf http://127.0.0.1:5099/health || { echo "Health check failed!" docker logs wine-csp-test exit 1 } # Test status endpoint echo "Testing /status endpoint:" curl -sf http://127.0.0.1:5099/status | jq . # Cleanup docker stop wine-csp-test docker rm wine-csp-test echo "Container tests passed!" - name: Generate SBOM (SPDX) run: | mkdir -p out/sbom syft "${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}" \ -o spdx-json=out/sbom/wine-csp.spdx.json - name: Generate SBOM (CycloneDX) run: | syft "${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}" \ -o cyclonedx-json=out/sbom/wine-csp.cdx.json - name: Upload SBOM artifacts uses: actions/upload-artifact@v4 with: name: wine-csp-sbom-${{ steps.version.outputs.tag }} path: out/sbom/ - name: Login to registry if: ${{ github.event.inputs.push == 'true' || (github.event_name == 'push' && github.ref == 'refs/heads/main') }} uses: docker/login-action@v3 with: registry: registry.stella-ops.org username: ${{ secrets.REGISTRY_USER }} password: ${{ secrets.REGISTRY_TOKEN }} - name: Push to registry if: ${{ github.event.inputs.push == 'true' || (github.event_name == 'push' && github.ref == 'refs/heads/main') }} run: | docker push "${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}" docker push "${{ env.IMAGE_NAME }}:sha-${{ github.sha }}" - name: Sign image with cosign if: ${{ github.event.inputs.push == 'true' || (github.event_name == 'push' && github.ref == 'refs/heads/main') }} env: COSIGN_EXPERIMENTAL: "1" run: | # Sign with keyless signing (requires OIDC) cosign sign --yes "${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}" || echo "Signing skipped (no OIDC available)" - name: Build air-gap bundle run: | mkdir -p out/bundles docker save "${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}" | gzip > out/bundles/wine-csp-${{ steps.version.outputs.tag }}.tar.gz # Generate bundle manifest cat > out/bundles/wine-csp-${{ steps.version.outputs.tag }}.manifest.json <