Skip to content

Commit 2502b28

Browse files
Adding v3-test-layer
1 parent 0f610dc commit 2502b28

File tree

1 file changed

+239
-0
lines changed

1 file changed

+239
-0
lines changed

.github/workflows/release-test.yml

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
name: Release Test Environment
2+
3+
# THIS PIPELINE DEPLOY PyPi in dev mode (v3.x.x.devx) and layer in the test account
4+
# For this pipeline we don't need to create tag and create docs
5+
6+
# RELEASE PROCESS
7+
#
8+
# === Automated activities ===
9+
#
10+
# 1. [Seal] Bump to release version and export source code with integrity hash
11+
# 2. [Quality check] Restore sealed source code, run tests, linting, security and complexity base line
12+
# 3. [Build] Restore sealed source code, create and export hashed build artifact for PyPi release (wheel, tarball)
13+
# 4. [Provenance] Generates provenance for build, signs attestation with GitHub OIDC claims to confirm it came from this release pipeline, commit, org, repo, branch, hash, etc.
14+
# 5. [Release] Restore built artifact, and publish package to PyPi prod repository
15+
# 7. [PR to bump version] Restore sealed source code, and create a PR to update trunk with latest released project metadata
16+
# 8. [Publish Layer v3 - test] Compile Layer in multiple Python versions and kick off pipeline for beta, prod, and canary releases
17+
# 9. [Publish Layer v3 - test] Update docs with latest Layer ARNs and Changelog
18+
# 10. [Publish Layer v3 - test] Create PR to update trunk so staged docs also point to the latest Layer ARN, when merged
19+
# 12. [Post release] Close all issues labeled "pending-release" and notify customers about the release
20+
#
21+
# === Manual activities ===
22+
#
23+
# 1. Kick off this workflow with the intended version
24+
# 2. Update draft release notes after this workflow completes
25+
# 3. If not already set, use `v<new version>` as a tag, e.g., v3.0.0, and select develop as target branch
26+
27+
# NOTE
28+
#
29+
# See MAINTAINERS.md "Releasing a new version" for release mechanisms
30+
#
31+
# Every job is isolated and starts a new fresh container.
32+
33+
env:
34+
RELEASE_COMMIT: ${{ github.sha }}
35+
RELEASE_TAG_VERSION: ${{ inputs.version_to_publish }}
36+
37+
on:
38+
workflow_dispatch:
39+
inputs:
40+
version_to_publish:
41+
description: "Version to be released in PyPi, Docs, and Lambda Layer, e.g. v3.0.0.dev1 (development release)"
42+
default: v3.0.0
43+
required: true
44+
skip_pypi:
45+
description: "Skip publishing to PyPi as it can't publish more than once. Useful for semi-failed releases"
46+
default: false
47+
type: boolean
48+
required: false
49+
50+
permissions:
51+
contents: read
52+
53+
jobs:
54+
55+
# This job bumps the package version to the release version
56+
# creates an integrity hash from the source code
57+
# uploads the artifact with the integrity hash as the key name
58+
# so subsequent jobs can restore from a trusted point in time to prevent tampering
59+
seal:
60+
runs-on: ubuntu-latest
61+
permissions:
62+
contents: read
63+
outputs:
64+
integrity_hash: ${{ steps.seal_source_code.outputs.integrity_hash }}
65+
artifact_name: ${{ steps.seal_source_code.outputs.artifact_name }}
66+
RELEASE_VERSION: ${{ steps.release_version.outputs.RELEASE_VERSION }}
67+
steps:
68+
- name: Export release version
69+
id: release_version
70+
# transform tag format `v<version` to `<version>`
71+
run: |
72+
RELEASE_VERSION="${RELEASE_TAG_VERSION:1}"
73+
echo "RELEASE_VERSION=${RELEASE_VERSION}" >> "$GITHUB_OUTPUT"
74+
75+
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
76+
with:
77+
ref: ${{ env.RELEASE_COMMIT }}
78+
79+
# We use a pinned version of Poetry to be certain it won't modify source code before we create a hash
80+
- name: Install poetry
81+
run: |
82+
pipx install git+https://github.com/python-poetry/poetry@68b88e5390720a3dd84f02940ec5200bfce39ac6 # v1.5.0
83+
pipx inject poetry git+https://github.com/monim67/poetry-bumpversion@315fe3324a699fa12ec20e202eb7375d4327d1c4 # v0.3.1
84+
85+
- name: Bump package version
86+
id: versioning
87+
run: poetry version "${RELEASE_VERSION}"
88+
env:
89+
RELEASE_VERSION: ${{ steps.release_version.outputs.RELEASE_VERSION}}
90+
91+
- name: Seal and upload
92+
id: seal_source_code
93+
uses: ./.github/actions/seal
94+
with:
95+
artifact_name_prefix: "source"
96+
97+
# This job runs our automated test suite, complexity and security baselines
98+
# it ensures previously merged have been tested as part of the pull request process
99+
#
100+
# NOTE
101+
#
102+
# we don't upload the artifact after testing to prevent any tampering of our source code dependencies
103+
quality_check:
104+
needs: seal
105+
runs-on: ubuntu-latest
106+
permissions:
107+
contents: read
108+
steps:
109+
# NOTE: we need actions/checkout to configure git first (pre-commit hooks in make dev)
110+
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
111+
with:
112+
ref: ${{ env.RELEASE_COMMIT }}
113+
114+
- name: Restore sealed source code
115+
uses: ./.github/actions/seal-restore
116+
with:
117+
integrity_hash: ${{ needs.seal.outputs.integrity_hash }}
118+
artifact_name: ${{ needs.seal.outputs.artifact_name }}
119+
120+
- name: Debug cache restore
121+
run: cat pyproject.toml
122+
123+
- name: Install poetry
124+
run: pipx install git+https://github.com/python-poetry/poetry@68b88e5390720a3dd84f02940ec5200bfce39ac6 # v1.5.0
125+
- name: Set up Python
126+
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
127+
with:
128+
python-version: "3.12"
129+
cache: "poetry"
130+
- name: Install dependencies
131+
run: make dev
132+
- name: Run all tests, linting and baselines
133+
run: make pr
134+
135+
# This job creates a release artifact (tar.gz, wheel)
136+
# it checks out code from release commit for custom actions to work
137+
# then restores the sealed source code (overwrites any potential tampering)
138+
# it's done separately from release job to enforce least privilege.
139+
# We export just the final build artifact for release
140+
build:
141+
runs-on: ubuntu-latest
142+
needs: [quality_check, seal]
143+
permissions:
144+
contents: read
145+
outputs:
146+
integrity_hash: ${{ steps.seal_build.outputs.integrity_hash }}
147+
artifact_name: ${{ steps.seal_build.outputs.artifact_name }}
148+
attestation_hashes: ${{ steps.encoded_hash.outputs.attestation_hashes }}
149+
steps:
150+
# NOTE: we need actions/checkout to configure git first (pre-commit hooks in make dev)
151+
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
152+
with:
153+
ref: ${{ env.RELEASE_COMMIT }}
154+
155+
- name: Restore sealed source code
156+
uses: ./.github/actions/seal-restore
157+
with:
158+
integrity_hash: ${{ needs.seal.outputs.integrity_hash }}
159+
artifact_name: ${{ needs.seal.outputs.artifact_name }}
160+
161+
- name: Install poetry
162+
run: pipx install git+https://github.com/python-poetry/poetry@68b88e5390720a3dd84f02940ec5200bfce39ac6 # v1.5.0
163+
- name: Set up Python
164+
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
165+
with:
166+
python-version: "3.12"
167+
cache: "poetry"
168+
169+
- name: Build python package and wheel
170+
run: poetry build
171+
172+
- name: Seal and upload
173+
id: seal_build
174+
uses: ./.github/actions/seal
175+
with:
176+
artifact_name_prefix: "build"
177+
files: "dist/"
178+
179+
# NOTE: SLSA retraces our build to its artifact to ensure it wasn't tampered
180+
# coupled with GitHub OIDC, SLSA can then confidently sign it came from this release pipeline+commit+branch+org+repo+actor+integrity hash
181+
- name: Create attestation encoded hash for provenance
182+
id: encoded_hash
183+
working-directory: dist
184+
run: echo "attestation_hashes=$(sha256sum ./* | base64 -w0)" >> "$GITHUB_OUTPUT"
185+
186+
# This job creates a provenance file that describes how our release was built (all steps)
187+
# after it verifies our build is reproducible within the same pipeline
188+
# it confirms that its own software and the CI build haven't been tampered with (Trust but verify)
189+
# lastly, it creates and sign an attestation (multiple.intoto.jsonl) that confirms
190+
# this build artifact came from this GitHub org, branch, actor, commit ID, inputs that triggered this pipeline, and matches its integrity hash
191+
# NOTE: supply chain threats review (we protect against all of them now): https://slsa.dev/spec/v1.0/threats-overview
192+
provenance:
193+
needs: [seal, build]
194+
permissions:
195+
contents: write # nested job explicitly require despite upload assets being set to false
196+
actions: read # To read the workflow path.
197+
id-token: write # To sign the provenance.
198+
# NOTE: provenance fails if we use action pinning... it's a Github limitation
199+
# because SLSA needs to trace & attest it came from a given branch; pinning doesn't expose that information
200+
# https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md#referencing-the-slsa-generator
201+
uses: slsa-framework/slsa-github-generator/.github/workflows/[email protected]
202+
with:
203+
base64-subjects: ${{ needs.build.outputs.attestation_hashes }}
204+
upload-assets: false # we upload its attestation in create_tag job, otherwise it creates a new release
205+
206+
# This job uses release artifact to publish to PyPi
207+
# it exchanges JWT tokens with GitHub to obtain PyPi credentials
208+
# since it's already registered as a Trusted Publisher.
209+
# It uses the sealed build artifact (.whl, .tar.gz) to release it
210+
release:
211+
needs: [build, seal, provenance]
212+
environment: release
213+
runs-on: ubuntu-latest
214+
permissions:
215+
id-token: write # OIDC for PyPi Trusted Publisher feature
216+
env:
217+
RELEASE_VERSION: ${{ needs.seal.outputs.RELEASE_VERSION }}
218+
steps:
219+
# NOTE: we need actions/checkout in order to use our local actions (e.g., ./.github/actions)
220+
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
221+
with:
222+
ref: ${{ env.RELEASE_COMMIT }}
223+
224+
- name: Restore sealed source code
225+
uses: ./.github/actions/seal-restore
226+
with:
227+
integrity_hash: ${{ needs.build.outputs.integrity_hash }}
228+
artifact_name: ${{ needs.build.outputs.artifact_name }}
229+
230+
# - name: Upload to PyPi prod
231+
# if: ${{ !inputs.skip_pypi }}
232+
# uses: pypa/gh-action-pypi-publish@81e9d935c883d0b210363ab89cf05f3894778450 # v1.8.14
233+
234+
# PyPi test maintenance affected us numerous times, leaving for history purposes
235+
# - name: Upload to PyPi test
236+
# if: ${{ !inputs.skip_pypi }}
237+
# uses: pypa/gh-action-pypi-publish@81e9d935c883d0b210363ab89cf05f3894778450 # v1.8.14
238+
# with:
239+
# repository-url: https://test.pypi.org/legacy/

0 commit comments

Comments
 (0)