99 - " v[0-9]+.[0-9]+.[0-9]+"
1010 - " v[0-9]+.[0-9]+.[0-9]+-*"
1111
12+ # ---- Global permissions for Trusted Publishing & attestations ----
13+ # id-token:write is required for OIDC (npm trusted publishing, keyless attestations)
14+ # packages:write for GHCR; attestations:write for GitHub artifact attestations (optional but recommended)
15+ permissions :
16+ contents : read
17+
1218env :
1319 IMAGE_NAME : ${{ github.repository_owner }}/fabric-nodeenv
1420
@@ -19,30 +25,39 @@ jobs:
1925 publishnpm :
2026 runs-on : ubuntu-24.04
2127 needs : test
28+ permissions :
29+ contents : read
30+ id-token : write
2231 steps :
2332 - uses : actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
2433 with :
2534 node-version : " 18.x"
2635 registry-url : " https://registry.npmjs.org"
36+ # Ensure npm 11.5.1 or later for trusted publishing support
37+ - name : Update npm
38+ run : npm install -g npm@latest
2739 - uses : actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
2840 with :
2941 name : node-tgzs
3042 path : build/
31- - run : |
43+ - name : Publish packages with provenance (OIDC)
44+ # No NODE_AUTH_TOKEN needed when Trusted Publishing is enabled.
45+ # --provenance tells npm to attach SLSA provenance to the package. [oai_citation:1‡The GitHub Blog](https://github.blog/security/supply-chain-security/introducing-npm-package-provenance/?utm_source=chatgpt.com)
46+ run : |
3247 set -xev
3348 ls -lart build/
3449 cd build
3550 find . -type f -name 'fabric-*.tgz' -exec npm publish {} \;
36- env:
37- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
3851
52+ # ========= Build & push per-arch images (with provenance/SBOM) =========
3953 docker-build-push :
40- name : Push Docker image
54+ name : Build & Push Docker image (per-arch)
4155 needs : test
4256 runs-on : ${{ matrix.arch.runner }}
4357 permissions :
4458 contents : read
45- packages : write
59+ packages : write # for ghcr.io
60+ id-token : write # for provenance/attestations
4661 strategy :
4762 fail-fast : false
4863 matrix :
@@ -53,50 +68,68 @@ jobs:
5368 runner : ubuntu-24.04-arm
5469 steps :
5570 - uses : actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
71+
5672 - name : Get commit timestamp
5773 run : echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> "${GITHUB_ENV}"
58- - name : Login to GitHub Container Registry
74+
75+ # ---- GHCR login via GITHUB_TOKEN (already short-lived/trusted) ----
76+ - name : Login to GitHub Container Registry (ghcr.io)
5977 uses : docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
6078 with :
6179 registry : ghcr.io
6280 username : ${{ github.actor }}
6381 password : ${{ secrets.GITHUB_TOKEN }}
82+
83+ # ---- Optional: Docker Hub login (kept for now) ----
84+ # If your Docker Hub org enables its own trusted/OIDC flow later, you can
85+ # replace this with that method; until then PAT is required. [oai_citation:2‡Docker Documentation](https://docs.docker.com/docker-hub/image-library/trusted-content/?utm_source=chatgpt.com)
6486 - name : Login to Docker Hub
65- uses : docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
87+ if : ${{ secrets.DOCKERHUB_USERNAME && secrets.DOCKERHUB_TOKEN }}
88+ uses : docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
6689 with :
6790 registry : docker.io
6891 username : ${{ secrets.DOCKERHUB_USERNAME }}
6992 password : ${{ secrets.DOCKERHUB_TOKEN }}
93+
7094 - name : Set up Docker Buildx
7195 uses : docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
72- - name : Build image
96+
97+ - name : Build image (per-arch) with provenance + SBOM
7398 id : build
7499 uses : docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
75100 with :
76101 file : docker/fabric-nodeenv/Dockerfile
77102 context : docker/fabric-nodeenv
103+ platforms : ${{ matrix.arch.platform }}
104+ # Generate and attach provenance/SBOM at build time. [oai_citation:3‡Docker Documentation](https://docs.docker.com/build/metadata/attestations/slsa-provenance/?utm_source=chatgpt.com)
105+ provenance : true
106+ sbom : true
78107 outputs : type=registry,"name=${{ format('ghcr.io/{0},docker.io/{0}', env.IMAGE_NAME) }}",push-by-digest=true,name-canonical=true
79108 env :
80109 SOURCE_DATE_EPOCH : ${{ env.SOURCE_DATE_EPOCH }}
110+
81111 - name : Export digest
82112 run : |
83113 mkdir -p ${{ runner.temp }}/digests
84114 digest="${{ steps.build.outputs.digest }}"
85115 touch "${{ runner.temp }}/digests/${digest#sha256:}"
116+
86117 - name : Upload digest
87118 uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
88119 with :
89120 name : digest-${{ matrix.arch.platform }}
90121 path : ${{ runner.temp }}/digests/*
91122 if-no-files-found : error
92123
124+ # =============== Manifest + tags publishing ==================
93125 docker-meta :
94126 needs : docker-build-push
95127 name : Publish Docker metadata
96128 runs-on : ubuntu-latest
97129 permissions :
98130 contents : read
99131 packages : write
132+ id-token : write
100133 strategy :
101134 fail-fast : false
102135 matrix :
@@ -110,12 +143,14 @@ jobs:
110143 path : ${{ runner.temp }}/digests
111144 pattern : digest-*
112145 merge-multiple : true
146+
113147 - name : Login to ${{ matrix.registry }}
114148 uses : docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
115149 with :
116150 registry : ${{ matrix.registry }}
117151 username : ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_USERNAME || github.actor }}
118152 password : ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_TOKEN || secrets.GITHUB_TOKEN }}
153+
119154 - name : Docker metadata
120155 id : meta
121156 uses : docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
@@ -125,12 +160,15 @@ jobs:
125160 type=semver,pattern={{version}}
126161 type=semver,pattern={{major}}.{{minor}}
127162 type=semver,pattern={{major}}.{{minor}}.{{patch}}
163+
128164 - name : Set up Docker Buildx
129165 uses : docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
166+
130167 - name : Create and push manifest list
131168 working-directory : ${{ runner.temp }}/digests
132169 run : |
133170 docker buildx imagetools create $(jq -cr '.tags | map("--tag " + .) | join(" ")' <<< "${DOCKER_METADATA_OUTPUT_JSON}") \
134171 $(printf '${{ matrix.registry }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
172+
135173 - name : Inspect image
136174 run : docker buildx imagetools inspect '${{ matrix.registry }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}'
0 commit comments