77 - ' v*'
88
99env :
10- REGISTRY : ghcr.io
10+ GHCR_REGISTRY : ghcr.io
11+ DOCKERHUB_REGISTRY : docker.io
1112 # Using 'cyberchef-mcp_v1' as requested for the package name
12- IMAGE_NAME : ${{ github.repository_owner }}/cyberchef-mcp_v1
13+ GHCR_IMAGE_NAME : ${{ github.repository_owner }}/cyberchef-mcp_v1
14+ # Docker Hub image name (assumes username/repo format - update with your Docker Hub namespace)
15+ # Example: if your Docker Hub username is 'myusername', this becomes 'myusername/cyberchef-mcp'
16+ DOCKERHUB_IMAGE_NAME : ${{ secrets.DOCKERHUB_USERNAME }}/cyberchef-mcp
1317
1418jobs :
1519 build-and-push :
1822 contents : write
1923 packages : write
2024 security-events : write
25+ attestations : write # Required for attestation generation
26+ id-token : write # Required for OIDC token generation (attestation signing)
2127
2228 steps :
2329 - name : Configure git
@@ -29,57 +35,103 @@ jobs:
2935 - name : Set up Docker Buildx
3036 uses : docker/setup-buildx-action@v3
3137
32- - name : Log in to the Container registry
38+ # =============================================================================
39+ # Authentication: Log in to both GHCR and Docker Hub
40+ # =============================================================================
41+ - name : Log in to GitHub Container Registry
3342 uses : docker/login-action@v3
3443 with :
35- registry : ${{ env.REGISTRY }}
44+ registry : ${{ env.GHCR_REGISTRY }}
3645 username : ${{ github.actor }}
3746 password : ${{ secrets.GITHUB_TOKEN }}
3847
39- - name : Extract metadata (tags, labels) for Docker
40- id : meta
48+ - name : Log in to Docker Hub
49+ uses : docker/login-action@v3
50+ with :
51+ registry : ${{ env.DOCKERHUB_REGISTRY }}
52+ username : ${{ secrets.DOCKERHUB_USERNAME }}
53+ password : ${{ secrets.DOCKERHUB_TOKEN }}
54+
55+ # =============================================================================
56+ # Metadata Extraction: Generate tags and labels for both registries
57+ # =============================================================================
58+ - name : Extract metadata for GHCR
59+ id : meta-ghcr
4160 uses : docker/metadata-action@v5
4261 with :
43- images : ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
62+ images : ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}
4463 tags : |
4564 type=semver,pattern={{major}}
4665 type=semver,pattern={{major}}.{{minor}}
4766 type=semver,pattern={{version}}
4867 type=sha
4968
50- - name : Build and push Docker image
69+ - name : Extract metadata for Docker Hub
70+ id : meta-dockerhub
71+ uses : docker/metadata-action@v5
72+ with :
73+ images : ${{ env.DOCKERHUB_REGISTRY }}/${{ env.DOCKERHUB_IMAGE_NAME }}
74+ tags : |
75+ type=semver,pattern={{major}}
76+ type=semver,pattern={{major}}.{{minor}}
77+ type=semver,pattern={{version}}
78+ type=sha
79+ type=raw,value=latest,enable={{is_default_branch}}
80+
81+ # =============================================================================
82+ # Build and Push: Single build, multi-registry push with attestations
83+ # =============================================================================
84+ # CRITICAL: Supply chain attestations for Docker Scout health score compliance
85+ # Docker Hub health scores require BOTH provenance and SBOM attestations.
86+ # These attestations account for 15 points out of 100 in the health score.
87+ # Missing attestations can drop the score from A to C grade.
88+ #
89+ # Dual SBOM Strategy:
90+ # 1. Docker attestation SBOM (below): Attached to image manifest for
91+ # Docker Scout health scores, `docker sbom` command, and registry verification
92+ # 2. Trivy SBOM artifact (separate step): Downloadable CycloneDX file
93+ # for offline audits, compliance reports, and third-party tools
94+ #
95+ # References:
96+ # - Docker Scout Policies: https://docs.docker.com/scout/policy/
97+ # - Health Scores: https://docs.docker.com/scout/policy/scores/
98+ # - GitHub Actions Attestations: https://docs.docker.com/build/ci/github-actions/attestations/
99+ # =============================================================================
100+ - name : Build and push Docker image to both registries
51101 uses : docker/build-push-action@v6
52102 with :
53103 context : .
54104 file : Dockerfile.mcp
55105 push : true
56- tags : ${{ steps.meta.outputs.tags }}
57- labels : ${{ steps.meta.outputs.labels }}
106+ tags : |
107+ ${{ steps.meta-ghcr.outputs.tags }}
108+ ${{ steps.meta-dockerhub.outputs.tags }}
109+ labels : ${{ steps.meta-ghcr.outputs.labels }}
58110 platforms : linux/amd64
59- # Supply chain attestations for Docker Scout compliance (v1.4.5+)
60- # Dual SBOM Strategy:
61- # 1. Docker attestation SBOM (below): Attached to image manifest for
62- # Docker Scout, docker sbom, and registry verification
63- # 2. Trivy SBOM artifact (separate step): Downloadable CycloneDX file
64- # for offline audits, compliance reports, and third-party tools
65- provenance : mode=max # Max-level provenance for build integrity
66- sbom : true # Generate and attach SBOM attestation (in-toto format)
67-
68- # Export Docker image as tarball for offline distribution
69- # Note: metadata-action generates tags without 'v' prefix (e.g., 1.2.0 not v1.2.0)
70- # We use the 'latest' tag which is always generated for releases
71- - name : Pull Docker image for export
111+ # Supply chain attestations (CRITICAL for Docker Hub health score)
112+ provenance : mode=max # Max-level provenance for SLSA Build Level 3 compliance
113+ sbom : true # Generate and attach SBOM attestation (in-toto SPDX format)
114+ # Note: Attestations are automatically pushed with the image to both registries
115+
116+ # =============================================================================
117+ # Export: Create tarball for offline distribution
118+ # =============================================================================
119+ # Note: We pull from Docker Hub since that's the primary distribution channel
120+ - name : Pull Docker image from Docker Hub for export
72121 run : |
73- docker pull "$REGISTRY/$IMAGE_NAME :latest"
122+ docker pull "$DOCKERHUB_REGISTRY/$DOCKERHUB_IMAGE_NAME :latest"
74123
75124 - name : Export Docker image as tarball
76125 env :
77126 TAG_NAME : ${{ github.ref_name }}
78127 run : |
79- docker save "$REGISTRY/$IMAGE_NAME :latest" | gzip > "cyberchef-mcp-${TAG_NAME}-docker-image.tar.gz"
128+ docker save "$DOCKERHUB_REGISTRY/$DOCKERHUB_IMAGE_NAME :latest" | gzip > "cyberchef-mcp-${TAG_NAME}-docker-image.tar.gz"
80129 ls -lh cyberchef-mcp-*.tar.gz
81130
82- # Security: Generate Software Bill of Materials (SBOM) - Part 2 of Dual Strategy
131+ # =============================================================================
132+ # Security: Generate SBOM and Vulnerability Scans
133+ # =============================================================================
134+ # Generate Software Bill of Materials (SBOM) - Part 2 of Dual Strategy
83135 # This Trivy-generated SBOM complements the Docker attestation SBOM above
84136 # Purpose: Provides CycloneDX format for:
85137 # - Offline security audits (no registry access required)
@@ -89,16 +141,16 @@ jobs:
89141 - name : Generate SBOM with Trivy (CycloneDX artifact)
90142 uses : aquasecurity/trivy-action@0.28.0
91143 with :
92- image-ref : ' ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest'
144+ image-ref : ' ${{ env.DOCKERHUB_REGISTRY }}/${{ env.DOCKERHUB_IMAGE_NAME }}:latest'
93145 format : ' cyclonedx'
94146 output : ' sbom.cyclonedx.json'
95147 vuln-type : ' os,library'
96148
97- # Security: Run vulnerability scan on release image
149+ # Security: Run vulnerability scan on release image (scanning Docker Hub image)
98150 - name : Run Trivy vulnerability scanner
99151 uses : aquasecurity/trivy-action@0.28.0
100152 with :
101- image-ref : ' ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest'
153+ image-ref : ' ${{ env.DOCKERHUB_REGISTRY }}/${{ env.DOCKERHUB_IMAGE_NAME }}:latest'
102154 format : ' sarif'
103155 output : ' trivy-release-results.sarif'
104156 severity : ' CRITICAL,HIGH'
0 commit comments