-
Notifications
You must be signed in to change notification settings - Fork 0
205 lines (185 loc) · 8.03 KB
/
Copy pathrelease.yml
File metadata and controls
205 lines (185 loc) · 8.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
name: Release
# release-please drives versioning: pushes to main accumulate into a release PR; merging it
# tags vX.Y.Z, cuts the GitHub Release, and (gated on releases_created) builds + signs + publishes
# every artifact in the SAME run (no PAT / tag-trigger recursion needed).
#
# workflow_dispatch is a manual (re)publish path for an already-tagged version — used to retry a
# failed/partial publish without deleting and re-cutting the release. Give it the version (e.g.
# 0.3.0) or leave blank to use the current manifest version.
on:
push:
branches: [main]
workflow_dispatch:
inputs:
version:
description: "Version to (re)publish, no leading v (e.g. 0.3.0). Blank = current manifest version."
required: false
default: ""
permissions: {}
env:
REGISTRY: ghcr.io
IMAGE_NAMESPACE: ${{ github.repository_owner }}
jobs:
release-please:
name: Release PR / tag
if: github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
outputs:
releases_created: ${{ steps.rp.outputs.releases_created }}
steps:
- uses: googleapis/release-please-action@v4
id: rp
with:
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
images:
name: Build, sign & publish images
needs: release-please
# Run when release-please cut a release (push flow) OR on a manual republish dispatch.
if: always() && (needs.release-please.outputs.releases_created == 'true' || github.event_name == 'workflow_dispatch')
runs-on: ubuntu-latest
permissions:
contents: write # attach SBOMs to the release
packages: write # push to GHCR
id-token: write # cosign keyless (OIDC)
strategy:
fail-fast: false
matrix:
include:
- name: truss-api
context: apps/api
dockerfile: apps/api/Dockerfile
- name: truss-dashboard
context: .
dockerfile: selfhosted/Dockerfile.dashboard
- name: truss-mcp
context: apps/mcp
dockerfile: apps/mcp/Dockerfile
- name: truss-operator
context: operator
dockerfile: operator/Dockerfile
steps:
# On a manual republish with an explicit version, check out that tag; otherwise the ref
# we're running on (the release commit on push, or main on a blank-version dispatch).
- uses: actions/checkout@v4
with:
ref: ${{ (github.event_name == 'workflow_dispatch' && inputs.version != '') && format('v{0}', inputs.version) || github.ref }}
- name: Resolve version
id: ver
run: |
V="${{ inputs.version }}"
[ -z "$V" ] && V="$(jq -r '.["."]' .release-please-manifest.json)"
echo "version=$V" >> "$GITHUB_OUTPUT"
- uses: docker/setup-buildx-action@v3
- uses: sigstore/cosign-installer@v3
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build & push ${{ matrix.name }}
id: build
uses: docker/build-push-action@v6
with:
context: ${{ matrix.context }}
file: ${{ matrix.dockerfile }}
# amd64-only: Node crashes (SIGILL) under QEMU arm64 emulation on amd64 runners.
# arm64 self-hosters build locally (see hack/e2e-compose.sh); native arm64 runners later.
platforms: linux/amd64
push: true
provenance: mode=max # SLSA build provenance attestation, pushed alongside the image
sbom: true # SBOM attestation, pushed alongside the image
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/${{ matrix.name }}:${{ steps.ver.outputs.version }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/${{ matrix.name }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Sign the image (cosign keyless)
env:
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/${{ matrix.name }}
DIGEST: ${{ steps.build.outputs.digest }}
run: cosign sign --yes "${IMAGE}@${DIGEST}"
- name: Generate SBOM (syft, SPDX)
uses: anchore/sbom-action@v0
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/${{ matrix.name }}@${{ steps.build.outputs.digest }}
format: spdx-json
output-file: sbom-${{ matrix.name }}.spdx.json
- name: Attach SBOM to the release
# Best-effort: the SBOM is also pushed as an OCI attestation (sbom: true above), so a
# failed release-asset upload (e.g. on a workflow_dispatch republish) must not fail the
# publish/sign path, which is what gates the chart job.
continue-on-error: true
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.ver.outputs.version }}
files: sbom-${{ matrix.name }}.spdx.json
chart:
name: Package, sign & publish Helm chart
needs: [release-please, images]
if: always() && needs.images.result == 'success' && (needs.release-please.outputs.releases_created == 'true' || github.event_name == 'workflow_dispatch')
runs-on: ubuntu-latest
permissions:
packages: write
id-token: write # cosign keyless
steps:
- uses: actions/checkout@v4
with:
ref: ${{ (github.event_name == 'workflow_dispatch' && inputs.version != '') && format('v{0}', inputs.version) || github.ref }}
- name: Resolve version
id: ver
run: |
V="${{ inputs.version }}"
[ -z "$V" ] && V="$(jq -r '.["."]' .release-please-manifest.json)"
echo "version=$V" >> "$GITHUB_OUTPUT"
- uses: azure/setup-helm@v4
- uses: sigstore/cosign-installer@v3
# cosign reads Docker's config for registry auth, so a docker login is required in addition
# to `helm registry login` (which only configures the helm CLI) — else signing 401s.
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Package, push & sign chart
env:
VERSION: ${{ steps.ver.outputs.version }}
run: |
helm package charts/truss --version "$VERSION" --app-version "$VERSION"
# helm push prints the pushed Digest: capture it so cosign signs the exact artifact.
helm push "truss-${VERSION}.tgz" "oci://${REGISTRY}/${IMAGE_NAMESPACE}/charts" 2>&1 | tee push.log
DIGEST="$(grep -oE 'sha256:[0-9a-f]{64}' push.log | head -1)"
test -n "$DIGEST"
cosign sign --yes "${REGISTRY}/${IMAGE_NAMESPACE}/charts/truss@${DIGEST}"
operator-installer:
name: Publish operator install bundle
needs: release-please
if: always() && (needs.release-please.outputs.releases_created == 'true' || github.event_name == 'workflow_dispatch')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ (github.event_name == 'workflow_dispatch' && inputs.version != '') && format('v{0}', inputs.version) || github.ref }}
- name: Resolve version
id: ver
run: |
V="${{ inputs.version }}"
[ -z "$V" ] && V="$(jq -r '.["."]' .release-please-manifest.json)"
echo "version=$V" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@v5
with:
go-version-file: operator/go.mod
- name: Build consolidated installer (CRDs + RBAC + manager)
working-directory: operator
run: make build-installer IMG="${REGISTRY}/${IMAGE_NAMESPACE}/truss-operator:${{ steps.ver.outputs.version }}"
- name: Attach install.yaml to the release
continue-on-error: true # best-effort asset upload; must not fail the publish path
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.ver.outputs.version }}
files: operator/dist/install.yaml