Skip to content

Commit 3cbd1f0

Browse files
fix(mdm): update release flow
1 parent f25dcc1 commit 3cbd1f0

3 files changed

Lines changed: 93 additions & 87 deletions

File tree

.github/workflows/release.yml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,21 @@ jobs:
6868
- name: Install cosign
6969
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
7070

71+
- name: Locate binary
72+
id: binary
73+
run: |
74+
BINARY=$(find dist -type f -name '*darwin_unnotarized' | head -1)
75+
if [ -z "$BINARY" ] || [ ! -f "$BINARY" ]; then
76+
echo "::error::Binary not found"
77+
find dist -type f
78+
exit 1
79+
fi
80+
echo "path=$BINARY" >> "$GITHUB_OUTPUT"
81+
7182
- name: Sign artifacts with Sigstore
7283
run: |
73-
ARCHIVE=$(find dist -name 'stepsecurity-dev-machine-guard-*-darwin.tar.gz' | head -1)
74-
cosign sign-blob "$ARCHIVE" --bundle "${ARCHIVE}.bundle" --yes
84+
cosign sign-blob "${{ steps.binary.outputs.path }}" \
85+
--bundle "${{ steps.binary.outputs.path }}.bundle" --yes
7586
cosign sign-blob stepsecurity-dev-machine-guard.sh \
7687
--bundle dist/stepsecurity-dev-machine-guard.sh.bundle --yes
7788
@@ -80,13 +91,13 @@ jobs:
8091
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
8192
run: |
8293
gh release upload "${{ steps.version.outputs.tag }}" \
83-
dist/stepsecurity-dev-machine-guard-*-darwin.tar.gz.bundle \
94+
"${{ steps.binary.outputs.path }}.bundle" \
8495
dist/stepsecurity-dev-machine-guard.sh.bundle \
8596
--clobber
8697
8798
- name: Attest build provenance
8899
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
89100
with:
90101
subject-path: |
91-
dist/stepsecurity-dev-machine-guard-*-darwin.tar.gz
102+
${{ steps.binary.outputs.path }}
92103
stepsecurity-dev-machine-guard.sh

.goreleaser.yml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,14 @@ universal_binaries:
2626
ids:
2727
- stepsecurity-dev-machine-guard
2828
replace: true
29-
name_template: stepsecurity-dev-machine-guard
29+
name_template: "stepsecurity-dev-machine-guard-{{ .Version }}-darwin_unnotarized"
3030

3131
archives:
32-
- id: archive
33-
ids:
32+
- ids:
3433
- universal
3534
formats:
36-
- tar.gz
37-
strip_binary_directory: true
38-
name_template: "stepsecurity-dev-machine-guard-{{ .Version }}-darwin"
35+
- binary
36+
name_template: "stepsecurity-dev-machine-guard-{{ .Version }}-darwin_unnotarized"
3937

4038
release:
4139
draft: true

docs/release-process.md

Lines changed: 74 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
11
# StepSecurity Dev Machine Guard — Release Process
22

3-
This document describes how releases are created, signed, and verified.
3+
This document describes how releases are created, signed, notarized, and verified.
44

55
> Back to [README](../README.md) | See also: [CHANGELOG](../CHANGELOG.md) | [Versioning](../VERSIONING.md)
66
77
---
88

99
## Overview
1010

11-
Releases are created via a manually triggered GitHub Actions workflow (`workflow_dispatch`) that requires approval from the `release` environment. The workflow uses [GoReleaser](https://goreleaser.com/) to:
11+
Releases are a two-phase process:
1212

13-
1. Read the version from `internal/buildinfo/version.go` (`const Version = "1.9.0"`)
14-
2. Verify the tag does not already exist (immutability)
15-
3. Build platform-specific binaries with GoReleaser
16-
4. Sign the binaries with [Sigstore](https://www.sigstore.dev/) cosign (keyless)
17-
5. Generate SHA256 checksums
18-
6. Create a Git tag and GitHub Release
19-
7. Attach binaries, Sigstore bundles, and checksums as release assets
20-
8. Generate SLSA build provenance attestation
13+
1. **CI (automated)** — GitHub Actions builds the universal macOS binary, signs it with Sigstore, and creates a **draft** release with the binary named `stepsecurity-dev-machine-guard-VERSION-darwin_unnotarized`.
14+
2. **Apple notarization (manual)** — Download the binary, sign and notarize it with an Apple Developer account, upload the notarized binary to the draft release, and publish.
15+
16+
---
2117

2218
## How to Create a Release
2319

@@ -26,109 +22,110 @@ Releases are created via a manually triggered GitHub Actions workflow (`workflow
2622
Update `Version` in `internal/buildinfo/version.go`:
2723

2824
```go
29-
const Version = "1.9.0"
25+
const Version = "1.9.1"
3026
```
3127

32-
Update the [CHANGELOG.md](../CHANGELOG.md) with a new section for the version.
33-
34-
Commit and push to `main`.
28+
Update [CHANGELOG.md](../CHANGELOG.md). Commit and push to `main`.
3529

3630
### 2. Trigger the release workflow
3731

3832
1. Go to [Actions > Release](https://github.com/step-security/dev-machine-guard/actions/workflows/release.yml)
39-
2. Click **Run workflow**
40-
3. Select the `main` branch
41-
4. Click **Run workflow**
33+
2. Click **Run workflow** on the `main` branch
4234

43-
### 3. Approve the release
35+
The workflow will:
36+
- Create a git tag (`v1.9.1`)
37+
- Build a universal macOS binary (amd64 + arm64) via GoReleaser
38+
- Sign with Sigstore cosign (keyless)
39+
- Upload as `stepsecurity-dev-machine-guard-VERSION-darwin_unnotarized` to a **draft** release
40+
- Record the SHA256 of the unnotarized binary in the release notes
41+
- Generate SLSA build provenance attestation
4442

45-
The workflow uses a GitHub Environment called `release` that requires approval. A designated reviewer must approve the run before it proceeds.
43+
### 3. Apple notarization (manual)
4644

47-
### 4. Verify the release
45+
On a Mac with the Apple Developer certificate installed:
4846

49-
Once approved, the workflow will create the tag, build the binaries, sign them, create the GitHub Release, and upload the artifacts. Check the [Releases page](https://github.com/step-security/dev-machine-guard/releases) to confirm.
47+
```bash
48+
VERSION="1.9.1"
5049

51-
---
50+
# Download the unnotarized binary
51+
gh release download "v${VERSION}" --repo step-security/dev-machine-guard \
52+
--pattern "stepsecurity-dev-machine-guard-${VERSION}-darwin_unnotarized"
5253

53-
## Release Artifacts
54+
# Rename for signing
55+
cp "stepsecurity-dev-machine-guard-${VERSION}-darwin_unnotarized" \
56+
"stepsecurity-dev-machine-guard-${VERSION}-darwin"
5457

55-
Each release includes the following artifacts:
58+
# Sign with Apple Developer ID
59+
codesign --sign "Developer ID Application: <COMPANY> (<TEAM_ID>)" \
60+
--options runtime --timestamp "stepsecurity-dev-machine-guard-${VERSION}-darwin"
5661

57-
| Artifact | Description |
58-
|----------|-------------|
59-
| `stepsecurity-dev-machine-guard_darwin_amd64` | macOS Intel binary |
60-
| `stepsecurity-dev-machine-guard_darwin_arm64` | macOS Apple Silicon binary |
61-
| `checksums.txt` | SHA256 checksums of all release artifacts |
62-
| `*.bundle` | Sigstore cosign bundles (signature, certificate, and Rekor transparency log entry) |
62+
# Notarize with Apple (~5 min)
63+
xcrun notarytool submit "stepsecurity-dev-machine-guard-${VERSION}-darwin" \
64+
--apple-id <APPLE_ID_EMAIL> --team-id <TEAM_ID> \
65+
--password <APP_SPECIFIC_PASSWORD> --wait
6366

64-
---
65-
66-
## Verifying a Release
67-
68-
Anyone can verify the authenticity of a release artifact using [cosign](https://docs.sigstore.dev/cosign/system_config/installation/).
67+
# Upload the notarized binary to the draft release
68+
gh release upload "v${VERSION}" "stepsecurity-dev-machine-guard-${VERSION}-darwin" \
69+
--repo step-security/dev-machine-guard
70+
```
6971

70-
### Install cosign
72+
### 4. Publish the release
7173

7274
```bash
73-
# macOS
74-
brew install cosign
75-
76-
# Other platforms: https://docs.sigstore.dev/cosign/system_config/installation/
75+
gh release edit "v${VERSION}" --repo step-security/dev-machine-guard \
76+
--draft=false --latest
7777
```
7878

79-
### Verify the binary signature
79+
---
8080

81-
```bash
82-
# Download the release artifacts
83-
gh release download v1.9.0 --repo step-security/dev-machine-guard
84-
85-
# Verify the Sigstore signature (example for Apple Silicon)
86-
cosign verify-blob stepsecurity-dev-machine-guard_darwin_arm64 \
87-
--bundle stepsecurity-dev-machine-guard_darwin_arm64.bundle \
88-
--certificate-identity-regexp "github.com/step-security/dev-machine-guard" \
89-
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
90-
```
81+
## Release Artifacts
9182

92-
A successful verification confirms:
83+
Each release includes:
9384

94-
- The binary was signed by the `step-security/dev-machine-guard` GitHub Actions workflow
95-
- The signature is recorded in the [Rekor transparency log](https://search.sigstore.dev/)
96-
- The binary has not been tampered with since signing
85+
| Artifact | Description |
86+
|----------|-------------|
87+
| `stepsecurity-dev-machine-guard-VERSION-darwin` | Notarized universal macOS binary (amd64 + arm64) |
88+
| `stepsecurity-dev-machine-guard-VERSION-darwin_unnotarized` | Original CI-built binary (for provenance verification) |
89+
| `stepsecurity-dev-machine-guard-VERSION-darwin_unnotarized.bundle` | Sigstore cosign bundle for the unnotarized binary |
90+
| `stepsecurity-dev-machine-guard.sh` | Legacy shell script |
91+
| `stepsecurity-dev-machine-guard.sh.bundle` | Sigstore cosign bundle for the shell script |
9792

98-
### Verify the checksum
93+
---
9994

100-
```bash
101-
sha256sum -c checksums.txt
102-
```
95+
## Verifying a Release
10396

104-
### Verify build provenance
97+
### Verify a release
10598

10699
```bash
107-
gh attestation verify stepsecurity-dev-machine-guard_darwin_arm64 \
108-
--repo step-security/dev-machine-guard
109-
```
100+
VERSION="1.9.1"
110101

111-
---
102+
# Download release artifacts
103+
gh release download "v${VERSION}" --repo step-security/dev-machine-guard \
104+
--pattern "stepsecurity-dev-machine-guard-${VERSION}-darwin*"
112105

113-
## Immutability Guarantees
106+
# Verify Apple signature and notarization
107+
codesign --verify --deep --strict "stepsecurity-dev-machine-guard-${VERSION}-darwin"
108+
spctl --assess --type execute "stepsecurity-dev-machine-guard-${VERSION}-darwin"
114109

115-
Releases are designed to be immutable through multiple layers:
110+
# Verify Sigstore signature on the unnotarized binary
111+
cosign verify-blob "stepsecurity-dev-machine-guard-${VERSION}-darwin_unnotarized" \
112+
--bundle "stepsecurity-dev-machine-guard-${VERSION}-darwin_unnotarized.bundle" \
113+
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
114+
--certificate-identity-regexp "github.com/.*/dev-machine-guard"
116115

117-
1. **Tag protection** — configure [tag protection rules](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/configuring-tag-protection-rules) in repository settings to prevent tag deletion or overwriting.
118-
2. **Duplicate tag check** — the release workflow fails if the tag already exists, preventing accidental re-releases of the same version.
119-
3. **Sigstore transparency log** — every signature is recorded in the public [Rekor](https://rekor.sigstore.dev/) transparency log. Even if an artifact were replaced, verification against the original log entry would fail.
120-
4. **SLSA build provenance** — the attestation links the artifact to the exact workflow run, commit SHA, and build environment.
116+
# Verify build provenance
117+
gh attestation verify "stepsecurity-dev-machine-guard-${VERSION}-darwin_unnotarized" \
118+
--repo step-security/dev-machine-guard
119+
```
121120

122121
---
123122

124-
## Environment Setup
125-
126-
The release workflow requires a GitHub Environment named `release` with required reviewers. To configure:
123+
## Immutability Guarantees
127124

128-
1. Go to **Settings > Environments** in the repository
129-
2. Create an environment named `release`
130-
3. Enable **Required reviewers** and add the appropriate team members
131-
4. Optionally restrict to the `main` branch under **Deployment branches**
125+
1. **Draft → publish flow** — binaries are uploaded to a draft release, notarized manually, then published. Once published, the release is immutable.
126+
2. **Sigstore transparency log** — the unnotarized binary signature is recorded in the public [Rekor](https://rekor.sigstore.dev/) transparency log.
127+
3. **SLSA build provenance** — attestation links the artifact to the exact workflow run, commit SHA, and build environment.
128+
4. **Duplicate tag check**the release workflow fails if the tag already exists.
132129

133130
---
134131

0 commit comments

Comments
 (0)