Skip to content

Commit 325aedb

Browse files
committed
fix: flatten MSI directory structure to match binaries job
GoReleaser Pro puts MSI files in dist/msi/<name>/ subdirectory. Instead of adding complexity to handle subdirectories, copy all files to dist root right after GoReleaser runs. This matches the binaries job pattern. Changes: - Add flatten step after GoReleaser to copy MSI files to dist root - Simplify provenance generation to single loop for zip and msi - Simplify SBOM signing to use dist root glob (no recursive search) - Simplify manifest generator to use Glob instead of Walk - Update docs with complete S3 file structure for all attestations
1 parent 673c9da commit 325aedb

3 files changed

Lines changed: 45 additions & 34 deletions

File tree

.github/workflows/release.yaml

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,20 @@ jobs:
454454
GITHUB_TOKEN: ${{ secrets.RELENG_GITHUB_TOKEN }}
455455
GORELEASER_KEY: ${{ secrets.GORELEASER_PRO_KEY }}
456456

457+
- name: Flatten MSI directory structure
458+
shell: pwsh
459+
run: |
460+
# GoReleaser Pro puts MSI files in dist/msi/<name>/ subdirectory
461+
# Copy all files to dist root to match binaries job pattern
462+
$msiDir = "_caller/dist/msi"
463+
if (Test-Path $msiDir) {
464+
Get-ChildItem $msiDir -Recurse -File | ForEach-Object {
465+
Write-Host "Copying $($_.Name) to dist root"
466+
Copy-Item $_.FullName -Destination "_caller/dist/"
467+
}
468+
Write-Host "✅ Flattened MSI directory structure"
469+
}
470+
457471
- name: Generate SLSA provenance for Windows artifacts
458472
working-directory: _workflows
459473
shell: bash
@@ -464,8 +478,9 @@ jobs:
464478
465479
PROVENANCE_COUNT=0
466480
467-
# Find all downloadable archives (zip files)
468-
for artifact in "${CALLER_DIST}"/*.zip; do
481+
# Find all downloadable archives (zip and msi files)
482+
# MSI files are flattened to dist root by previous step
483+
for artifact in "${CALLER_DIST}"/*.zip "${CALLER_DIST}"/*.msi; do
469484
[ -f "$artifact" ] || continue
470485
[[ "$artifact" == *checksums* ]] && continue
471486
@@ -481,20 +496,6 @@ jobs:
481496
((PROVENANCE_COUNT++)) || true
482497
done
483498
484-
# Find MSI files (in dist/msi/<name>/<name>.msi subdirectory)
485-
while IFS= read -r -d '' artifact; do
486-
BASENAME=$(basename "$artifact")
487-
echo "Generating provenance for: $BASENAME"
488-
cosign attest-blob \
489-
--yes \
490-
--predicate "_generated/predicate.json" \
491-
--type slsaprovenance1 \
492-
--bundle "${CALLER_DIST}/${BASENAME}.provenance.sigstore.json" \
493-
"$artifact" > /dev/null
494-
echo "✅ Created ${BASENAME}.provenance.sigstore.json"
495-
((PROVENANCE_COUNT++)) || true
496-
done < <(find "${CALLER_DIST}" -name "*.msi" -print0)
497-
498499
echo "Generated provenance bundles: ${PROVENANCE_COUNT}"
499500
if [ "$PROVENANCE_COUNT" -eq 0 ]; then
500501
echo "::error::No provenance bundles were generated - this indicates a build problem"
@@ -513,6 +514,7 @@ jobs:
513514
SIGNED_COUNT=0
514515
515516
# Find all SBOM files generated by GoReleaser (syft)
517+
# All files are in dist root (MSI files flattened by previous step)
516518
for sbom in "${CALLER_DIST}"/*.sbom.json; do
517519
[ -f "$sbom" ] || continue
518520

cmd/generate-windows-manifest/main.go

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -69,30 +69,26 @@ func main() {
6969
fmt.Fprintf(os.Stderr, "✅ Added zip asset: windows-amd64 -> %s\n", filename)
7070
}
7171

72-
// Find and process MSI files (GoReleaser puts these in dist/msi/<name>/<name>.msi)
73-
err = filepath.Walk(distDir, func(path string, info os.FileInfo, err error) error {
74-
if err != nil {
75-
return err
76-
}
77-
if info.IsDir() || !strings.HasSuffix(info.Name(), ".msi") {
78-
return nil
79-
}
72+
// Find and process MSI files (flattened to dist root by workflow)
73+
msiFiles, err := filepath.Glob(filepath.Join(distDir, "*.msi"))
74+
if err != nil {
75+
fmt.Fprintf(os.Stderr, "generate-windows-manifest: error finding MSI files: %v\n", err)
76+
os.Exit(1)
77+
}
8078

81-
filename := info.Name()
82-
asset, err := buildAsset(path, filename, "application/x-msi", baseURL, distDir)
79+
for _, msiPath := range msiFiles {
80+
filename := filepath.Base(msiPath)
81+
82+
asset, err := buildAsset(msiPath, filename, "application/x-msi", baseURL, distDir)
8383
if err != nil {
84-
return fmt.Errorf("processing %s: %w", filename, err)
84+
fmt.Fprintf(os.Stderr, "generate-windows-manifest: error processing %s: %v\n", filename, err)
85+
os.Exit(1)
8586
}
8687

8788
// MSI uses key "windows-amd64-msi"
8889
// MSI has cosign signatures and attestations; Azure Trusted Signing (Windows code signing) planned for Stage 2
8990
assets["windows-amd64-msi"] = asset
9091
fmt.Fprintf(os.Stderr, "✅ Added MSI asset: windows-amd64-msi -> %s\n", filename)
91-
return nil
92-
})
93-
if err != nil {
94-
fmt.Fprintf(os.Stderr, "generate-windows-manifest: error walking dist directory: %v\n", err)
95-
os.Exit(1)
9692
}
9793

9894
// Marshal assets map to JSON
@@ -138,7 +134,7 @@ func buildAsset(filePath, filename, mediaType, baseURL, distDir string) (*pb.Ass
138134
sizeBytes := info.Size()
139135
href := fmt.Sprintf("%s/%s", baseURL, filename)
140136

141-
// Check for signature and certificate files
137+
// Check for signature and certificate files (all in dist root after flatten step)
142138
var signatureHref, certificateHref *string
143139
sigPath := filepath.Join(distDir, filename+".sig")
144140
if _, err := os.Stat(sigPath); err == nil {

docs/release-workflow.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,25 @@ releases/{org}/{repo}/{tag}/
186186
├── baton-foo_1.0.0_checksums.txt.sig
187187
├── baton-foo_1.0.0_checksums.txt.cert
188188
├── baton-foo-v1.0.0-darwin-arm64.zip
189+
├── baton-foo-v1.0.0-darwin-arm64.zip.sig
190+
├── baton-foo-v1.0.0-darwin-arm64.zip.cert
189191
├── baton-foo-v1.0.0-darwin-arm64.zip.provenance.sigstore.json
190192
├── baton-foo-v1.0.0-darwin-arm64.zip.sbom.sigstore.json
191193
├── baton-foo-v1.0.0-linux-amd64.tar.gz
194+
├── baton-foo-v1.0.0-linux-amd64.tar.gz.sig
195+
├── baton-foo-v1.0.0-linux-amd64.tar.gz.cert
192196
├── baton-foo-v1.0.0-linux-amd64.tar.gz.provenance.sigstore.json
197+
├── baton-foo-v1.0.0-linux-amd64.tar.gz.sbom.sigstore.json
193198
├── baton-foo-v1.0.0-windows-amd64.zip
199+
├── baton-foo-v1.0.0-windows-amd64.zip.sig
200+
├── baton-foo-v1.0.0-windows-amd64.zip.cert
194201
├── baton-foo-v1.0.0-windows-amd64.zip.provenance.sigstore.json
202+
├── baton-foo-v1.0.0-windows-amd64.zip.sbom.sigstore.json
195203
├── baton-foo_v1.0.0_windows_amd64.msi
204+
├── baton-foo_v1.0.0_windows_amd64.msi.sig
205+
├── baton-foo_v1.0.0_windows_amd64.msi.cert
206+
├── baton-foo_v1.0.0_windows_amd64.msi.provenance.sigstore.json
207+
├── baton-foo_v1.0.0_windows_amd64.msi.sbom.sigstore.json
196208
└── ...
197209
```
198210

@@ -202,7 +214,8 @@ releases/{org}/{repo}/{tag}/
202214

203215
Use test connectors for validation:
204216

205-
- `ConductorOne/baton-github-test` - Full release testing
217+
- `ConductorOne/baton-runner` - Default WXS template testing
218+
- `ConductorOne/baton-github-test` - Custom WXS template testing (via `msi_wxs_path`)
206219

207220
### Testing Process
208221

0 commit comments

Comments
 (0)