forked from ChelseaKR/olive-bark-logger
-
Notifications
You must be signed in to change notification settings - Fork 0
200 lines (186 loc) · 8.63 KB
/
Copy pathrelease.yml
File metadata and controls
200 lines (186 loc) · 8.63 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
name: release
# Trusted-main release (REL-14; see docs/GAP-LEDGER.md#gap-rel-1 for the wider
# supply-chain gap this is a slice of). Never trust the PR's green check for a
# release: this re-runs the literal `make verify` gate set (lint, types,
# coverage >=85%, security, accessibility, PWA tests, i18n) at the exact tagged
# commit, then builds sdist + wheel, generates a CycloneDX SBOM, attests build
# provenance via GitHub's native (keyless, no stored signing key) attestation,
# and publishes a GitHub Release with the CHANGELOG section as notes.
#
# Deliberately NOT in scope here (see GAP-REL-1 — these are live, externally
# visible actions with real infrastructure/registry decisions this remediation
# pass does not make on the maintainer's behalf):
# - PyPI publishing (no trusted-publisher project configured yet)
# - GHCR / container registry push of the Dockerfile image (no registry
# decision made yet; ci.yml already CVE-scans the image build on every PR)
# - cosign key-based signing (would require provisioning/protecting a
# long-lived signing key; native attestation below needs no key at all)
#
# NOT YET USED: no `v*` tag exists in this repo yet (CHANGELOG.md's own header:
# "No version of this project has been tagged or released yet"). This workflow
# is prepared ahead of the first tag so cutting `v0.1.0` doesn't also require
# writing a release pipeline from scratch under time pressure.
on:
workflow_dispatch:
inputs:
tag:
description: "Existing signed stable SemVer tag (vX.Y.Z)"
required: true
type: string
permissions:
contents: read
concurrency:
group: release
cancel-in-progress: false
jobs:
authorize:
uses: ChelseaKR/.github/.github/workflows/release-authorize.yml@315a513ff3b4e7c5c0628428909052d947f4f1ab
permissions:
contents: read
with:
tag: ${{ inputs.tag }}
# Re-verify at the tagged commit — the exact same gate a contributor runs
# locally via `make verify` (CICD-27: no local/CI/release drift).
verify-at-tag:
name: re-verify at tagged commit (make verify)
needs: authorize
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: ${{ needs.authorize.outputs.release-commit }}
fetch-depth: 0 # gitleaks (inside `make verify`) needs full history
persist-credentials: false
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
with:
version: "0.11.28"
enable-cache: false
# This action has no input to disable its own Node-distribution tool-cache
# (unlike ci.yml's other caches); zizmor itself notes Low confidence for
# this instance — this job only runs the verify gate, it builds/publishes
# nothing, so there's no cached artifact for a poisoned cache to ride into.
- name: Set up Node (for the pa11y/axe a11y and pwa-test targets in `make verify`)
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 # zizmor: ignore[cache-poisoning] no per-action toggle for the Node tool-cache; low-confidence finding
with:
node-version: "20"
- name: Install gitleaks (pinned, matches .pre-commit-config.yaml)
run: |
GL=8.21.2
archive="gitleaks_${GL}_linux_x64.tar.gz"
curl -sSfL -o "/tmp/${archive}" \
"https://github.com/gitleaks/gitleaks/releases/download/v${GL}/${archive}"
echo "5bc41815076e6ed6ef8fbecc9d9b75bcae31f39029ceb55da08086315316e3ba /tmp/${archive}" \
| sha256sum --check --strict
tar -xzf "/tmp/${archive}" -C /usr/local/bin gitleaks
chmod +x /usr/local/bin/gitleaks
- name: Install
run: uv sync --locked --group dev --python 3.12
- name: make verify
run: make verify
build:
name: build sdist/wheel · SBOM · provenance
needs: [authorize, verify-at-tag]
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # keyless OIDC identity for build provenance attestation
attestations: write # publish the attestation to the repo's attestation store
steps:
- uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: ${{ needs.authorize.outputs.release-commit }}
persist-credentials: false
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
# REL-14: the tag must match the package version — no drifting-version releases.
- name: Tag matches pyproject.toml version
env:
TAG: ${{ needs.authorize.outputs.release-tag }}
run: |
tag_version="${TAG#v}"
pkg_version="$(python3 -c 'import tomllib; print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])')"
echo "tag=$tag_version pyproject=$pkg_version"
if [ "$tag_version" != "$pkg_version" ]; then
echo "::error::tag $TAG does not match pyproject version $pkg_version"
exit 1
fi
# REL-13 / CQ-10: a real wheel + sdist build via the repo's own setuptools backend.
- name: Build sdist + wheel
run: |
python -m pip install --upgrade pip build
python -m build
# SEC-27: CycloneDX SBOM of the exact installed (zero-runtime-dependency)
# package closure, built from a clean venv rather than the build-tool venv.
- name: Generate CycloneDX SBOM
run: |
python -m venv /tmp/sbom-venv
/tmp/sbom-venv/bin/pip install --upgrade pip
/tmp/sbom-venv/bin/pip install dist/*.whl
python -m pip install --upgrade cyclonedx-bom
cyclonedx-py environment /tmp/sbom-venv --output-format json --output-file dist/sbom.cdx.json
# SEC-29 (keyless variant): OIDC-backed GitHub attestation binding this
# workflow run to the built artifacts, verifiable with `gh attestation
# verify` — no signing key is stored anywhere.
- name: Attest build provenance for the built artifacts (keyless OIDC)
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: "dist/*.whl,dist/*.tar.gz,dist/sbom.cdx.json"
# REL-10: the tag must have a matching CHANGELOG section, extracted
# verbatim into the GitHub Release body — a missing section fails the release.
- name: Extract this version's CHANGELOG section
env:
TAG: ${{ needs.authorize.outputs.release-tag }}
run: |
version="${TAG#v}"
awk -v ver="$version" '
index($0, "## [" ver "]") == 1 { found=1; print; next }
found && /^## \[/ { exit }
found { print }
' CHANGELOG.md > release-notes.md
if [ ! -s release-notes.md ]; then
echo "::error::CHANGELOG.md has no '## [$version]' section (REL-10) — add one before tagging" >&2
exit 1
fi
- name: Upload verified release assets
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-assets
path: |
dist/*
release-notes.md
if-no-files-found: error
publish-release:
needs: [authorize, build]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-assets
path: release-assets
- name: Recheck immutable tag object and create the release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
TAG: ${{ needs.authorize.outputs.release-tag }}
TAG_OBJECT_SHA: ${{ needs.authorize.outputs.tag-object-sha }}
run: |
set -euo pipefail
LIVE_TAG_OBJECT="$(gh api "repos/${GITHUB_REPOSITORY}/git/ref/tags/${TAG}" --jq .object.sha)"
test "${LIVE_TAG_OBJECT}" = "${TAG_OBJECT_SHA}"
gh release create "${TAG}" \
--title "${TAG}" \
--notes-file release-assets/release-notes.md \
\
release-assets/dist/*.whl release-assets/dist/*.tar.gz release-assets/dist/sbom.cdx.json