Skip to content

feat(swift): release-pipeline publishing to baml-swift (Go-mirror pattern) - #4149

Merged
ATX24 merged 5 commits into
canaryfrom
dhilan/swift-release-pipeline
Jul 23, 2026
Merged

ATX24 merged 5 commits into
canaryfrom
dhilan/swift-release-pipeline

Conversation

@ATX24

@ATX24 ATX24 commented Jul 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Retires the standalone baml-swift dev-channel poller and moves Swift package publishing into the canary release pipeline, following the Go SDK mirror pattern exactly. baml-swift becomes a passive git mirror (no CI, no polling); the monorepo builds the XCFramework once per release as a release artifact (like bridge_cffi) and pushes the mirror.

New jobs in release-baml-language.yml

  • build-swift-sdk (macos-14) — builds all 5 Apple slices via build-xcframework.sh --all (bitcode-stripped), zips + checksums with shasum (SwiftPM checksum == sha256, no Swift toolchain needed on this path), and assembles the mirror tree via scripts/assemble-swift-sdk-mirror.
  • verify-swift-sdk (macos-15) — pre-publish gate in all-builds.needs, parallel to verify-{cpp,csharp,rust}-sdk: links the release-form binary from a clean SwiftPM project. Catches release-only breakage the debug host-slice sdk-test gate can't (the BamlThrownValue Sendable failure was exactly this class).
  • publish-swift-sdk (gated dry_run==false && canary) — uploads the XCFramework as an immutable asset on the baml-language-<version> release, then clones baml-swift via BAML_SWIFT_DEPLOY_KEY, rsyncs the mirror, pushes an immutable v<version> tag. Mirrors publish-go-sdk.
  • smoke-swift-release (macos-15, post-publish) — resolves the actually published baml-swift package by URL+checksum at the v<version> tag and runs it. Mirrors smoke-go-release.

New files

  • baml_language/sdks/swift/mirror/ — source of truth for the passive repo's Package.swift (release-asset binaryTarget) + README.
  • scripts/assemble-swift-sdk-mirror — analog of assemble-go-sdk-mirror; stamps url/checksum/version/sha.

The monorepo builds the 5-slice binary once per release; the host-slice test build stays in the sdk-test gate ("only build what's needed for testing" everywhere else).

Not included / follow-up

  • Prerequisite before this can publish: a BAML_SWIFT_DEPLOY_KEY secret — an SSH deploy key with write access to BoundaryML/baml-swift, parallel to BAML_GO_DEPLOY_KEY. publish-swift-sdk fails fast (test -n) without it.
  • baml-swift passivation (deleting its current polling workflow) is intentionally NOT in this PR — the poller stays as a bridge until this pipeline lands one real release, to avoid a publishing gap.

Safety

  • Bridge sources are byte-identical to canary — this PR is purely additive release plumbing (5 files, +400 lines, 0 deletions).
  • Secret handling matches the vetted BAML_GO_DEPLOY_KEY pattern (env → file → chmod 600 → GIT_SSH_COMMAND, never logged); pipeline is workflow_dispatch/workflow_run-only (not PR-reachable); all interpolated values come from trusted sources (GitHub context, release.toml-derived plan outputs).
  • actionlint clean (incl. shellcheck on run blocks); mirror/Package.swift (unstamped placeholders in-repo) is inert to the real sdks/swift package and never built in CI.
  • gitleaks clean; no secrets, keys, or personal paths.

Test plan

  • The release jobs run only on canary releases (workflow_dispatch/workflow_run), so this PR's CI exercises the normal suite; the Swift sdk-test gate + cargo tests pass unchanged (bridge untouched).
  • End-to-end validation happens on the first real release once BAML_SWIFT_DEPLOY_KEY exists — verify-swift-sdk gates it pre-publish, smoke-swift-release confirms the published package post-publish.

Summary by CodeRabbit

  • New Features
    • Added an end-to-end Swift SDK release flow using XCFramework binaries distributed via immutable, checksum-verified Swift Package artifacts.
    • Introduced a versioned Swift package mirror with platform configuration for iOS and Apple platforms.
    • Added a README with installation and consumption guidance for the mirrored SDK.
  • Quality Improvements
    • Added automated build, integrity verification, and end-to-end smoke testing for the published Swift release chain.
    • Publishing now guards against accidental asset/tag changes by enforcing byte-for-byte immutability.

ATX24 added 3 commits July 23, 2026 09:42
Follows the Go SDK mirror pattern so the standalone dev-channel poller
can be retired. Adds to the canary release pipeline:

- build-swift-sdk (macos-14): builds all 5 Apple slices via
  build-xcframework.sh --all (bitcode-stripped), zips + checksums with
  shasum (SwiftPM checksum == sha256, no Swift toolchain needed), and
  assembles the baml-swift mirror tree via assemble-swift-sdk-mirror.
- publish-swift-sdk (gated dry_run==false && canary): uploads the
  XCFramework as an immutable asset on the baml-language-<version>
  release, then clones BoundaryML/baml-swift via BAML_SWIFT_DEPLOY_KEY,
  rsyncs the mirror, and pushes an immutable v<version> tag.
- baml_language/sdks/swift/mirror/: source of truth for the passive
  repo's Package.swift (release-asset binaryTarget) + README.
- scripts/assemble-swift-sdk-mirror: stamps url/checksum/version/sha.

The monorepo builds the 5-slice binary once per release as a release
artifact (like bridge_cffi); baml-swift becomes a passive git mirror
with no CI. The host-slice test build stays in the sdk-test gate.

Prereq: BAML_SWIFT_DEPLOY_KEY secret (write deploy key on baml-swift),
parallel to BAML_GO_DEPLOY_KEY.
Parity with verify-{cpp,csharp,rust}-sdk: consume the RELEASE-form
XCFramework (5 slices, release-bridge-swift profile) that build-swift-sdk
produced from a clean SwiftPM project — link + run on macos-15. Catches
release-only breakage the debug host-slice sdk-test gate misses (the
BamlThrownValue Sendable failure was exactly this class). Added to
all-builds.needs so a broken release artifact blocks publishing.
Parity with smoke-go-release: after publish-swift-sdk, resolve the
actually-published baml-swift package by URL at the v<version> tag
(downloading the release-asset xcframework by checksum) from a clean
SwiftPM project, link, and run — proving the full mirror-push +
release-asset chain, not just the pre-publish artifact. macos-15,
gated dry_run==false && canary.
@vercel

vercel Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
beps Ready Ready Preview, Comment Jul 23, 2026 6:29pm
promptfiddle Ready Ready Preview, Comment Jul 23, 2026 6:29pm
promptfiddle2 Ready Ready Preview, Comment Jul 23, 2026 6:29pm

Request Review

@github-actions

Copy link
Copy Markdown

⏭️ Performance benchmarks were skipped

Perf benchmarks (CodSpeed) are opt-in on pull requests — they no longer run on every push. They always run automatically after merge to canary/main.

To run them on this PR, do any of the following, then push a commit (or re-run CI):

  • Add RUN_CODSPEED=1 to the PR description, or
  • Include run-perf or /perf in the PR title or any commit message.

@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 July 23, 2026 17:40 Inactive
@coderabbitai

coderabbitai Bot commented Jul 23, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a545695-1173-430a-8bde-22bad1080537

📥 Commits

Reviewing files that changed from the base of the PR and between 34da3b3 and cb0ddee.

📒 Files selected for processing (2)
  • .github/workflows/release-baml-language.yml
  • scripts/assemble-swift-sdk-mirror
🚧 Files skipped from review as they are similar to previous changes (2)
  • scripts/assemble-swift-sdk-mirror
  • .github/workflows/release-baml-language.yml

📝 Walkthrough

Walkthrough

The release workflow now builds and verifies a multi-slice Swift XCFramework, assembles a checksum- and source-pinned SwiftPM mirror, publishes immutable release artifacts and tags, and smoke-tests the published package with a clean SwiftPM consumer.

Changes

Swift SDK release

Layer / File(s) Summary
Swift mirror package contract
baml_language/sdks/swift/mirror/*
Adds the SwiftPM manifest, package documentation, and ignored build artifacts for the BamlBridge mirror package.
Version-pinned mirror assembly
scripts/assemble-swift-sdk-mirror
Copies mirror sources, stamps release metadata and binary artifact details, writes SOURCE_SHA, and validates the assembled package.
Swift artifact build and verification
.github/workflows/release-baml-language.yml
Builds the multi-platform XCFramework and mirror artifact, verifies them in a clean SwiftPM consumer, and adds both jobs to the release gate.
Swift publication and smoke test
.github/workflows/release-baml-language.yml
Publishes the XCFramework and immutable mirror tag, then builds and runs a consumer against the published Swift package.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ReleaseWorkflow
  participant GitHubRelease
  participant BamlSwiftRepository
  participant SwiftPMConsumer
  ReleaseWorkflow->>GitHubRelease: upload XCFramework zip with immutable checksum validation
  ReleaseWorkflow->>BamlSwiftRepository: publish immutable version tag
  SwiftPMConsumer->>BamlSwiftRepository: resolve exact release version
  SwiftPMConsumer->>GitHubRelease: download checksum-pinned XCFramework
  SwiftPMConsumer->>SwiftPMConsumer: build and run release executable
Loading

Possibly related PRs

  • BoundaryML/baml#4124: Modifies shared release workflow inputs and source metadata used by the Swift release chain.

Poem

A rabbit zips Swift slices with care,
Checksums sparkle in the air.
Tags stand firm, builds hop along,
Clean consumers sing their song.
“Binky!” says the release, strong!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the Swift release-pipeline publishing work and the baml-swift mirror pattern.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dhilan/swift-release-pipeline

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

Binary size checks passed

✅ 7 passed

Artifact Platform File Gzip Gated on Baseline Delta Status
✅ baml-cli Linux 🔒 26.7 MB 11.4 MB file 26.2 MB +544.9 KB (+2.1%) OK
✅ packed-program Linux 🔒 17.3 MB 7.2 MB file 17.0 MB +287.7 KB (+1.7%) OK
✅ baml-cli macOS 🔒 20.7 MB 9.9 MB file 20.3 MB +430.5 KB (+2.1%) OK
✅ packed-program macOS 🔒 13.5 MB 6.3 MB file 13.2 MB +297.6 KB (+2.3%) OK
✅ baml-cli Windows 🔒 22.4 MB 10.1 MB file 21.9 MB +472.6 KB (+2.2%) OK
✅ packed-program Windows 🔒 14.4 MB 6.4 MB file 14.2 MB +247.8 KB (+1.8%) OK
✅ bridge_wasm WASM 16.4 MB 🔒 4.5 MB gzip 4.4 MB +62.0 KB (+1.4%) OK

🔒 = the size this artifact is GATED on (ceiling + delta). Binaries gate on file size (installed binary); WASM gates on gzip (download size). The other size is shown for information only.


Generated by cargo size-gate · workflow run

@vercel
vercel Bot temporarily deployed to Preview – promptfiddle July 23, 2026 17:53 Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
.github/workflows/release-baml-language.yml (3)

445-556: 🩺 Stability & Availability | 🔵 Trivial

No timeout-minutes on the new Swift jobs.

build-swift-sdk, verify-swift-sdk, publish-swift-sdk, and smoke-swift-release all invoke network-dependent operations (SwiftPM resolution, git clone/push, gh calls) without a job-level timeout-minutes, so a hang (e.g., stuck package resolution) would run until the default multi-hour GitHub Actions timeout instead of failing fast.

Also applies to: 1189-1273, 1513-1549

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-baml-language.yml around lines 445 - 556, Add an
appropriate job-level timeout-minutes to build-swift-sdk, verify-swift-sdk,
publish-swift-sdk, and smoke-swift-release. Choose a limit that accommodates
normal XCFramework builds, SwiftPM resolution, git operations, and gh calls
while ensuring hung network-dependent steps fail promptly.

467-477: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reimplements zip/checksum packaging the build script already provides.

build-xcframework.sh supports --zip <path> and computes the SwiftPM checksum via swift package compute-checksum in one step (see build-xcframework.sh:124-137). This step instead duplicates that logic with ditto + shasum -a 256, creating two places that must stay in sync if the packaging/checksum method ever changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-baml-language.yml around lines 467 - 477, The “Zip
+ checksum” step duplicates packaging logic already implemented by
build-xcframework.sh. Update the pack step to invoke build-xcframework.sh with
its --zip option and reuse the script’s computed SwiftPM checksum output,
removing the direct ditto and shasum commands while preserving the existing zip
and checksum GitHub outputs.

1230-1244: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

ssh-keyscan trusts whatever host key GitHub returns without pinning.

ssh-keyscan github.com >> ~/.ssh/known_hosts accepts the returned host key on first use (TOFU) rather than verifying it against GitHub's published SSH key fingerprints, which is a minor MITM exposure for a step that pushes to a repo using a write-capable deploy key.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-baml-language.yml around lines 1230 - 1244, Update
the “Clone BoundaryML/baml-swift” step to pin GitHub’s SSH host key instead of
trusting arbitrary output from ssh-keyscan. Verify the scanned key against
GitHub’s published fingerprint before writing it to ~/.ssh/known_hosts, and fail
the step if verification does not match; keep the existing deploy-key clone flow
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release-baml-language.yml:
- Around line 467-491: Replace the inline workflow expressions in the “Zip +
checksum” and “Assemble baml-swift mirror” run scripts with shell environment
variables: use the existing VERSION environment variable instead of `${{
needs.plan.outputs.version }}`, and use the runner-provided GITHUB_REPOSITORY
when constructing url instead of `${{ github.repository }}`. Preserve the
current ZIP and release URL behavior without adding an extra env entry for
GITHUB_REPOSITORY.

In `@scripts/assemble-swift-sdk-mirror`:
- Around line 47-48: Update the assembly flow around the runtime_sources copy
and create destination / "Sources" before calling shutil.copytree, while
preserving the existing Sources/BamlBridge destination layout.
- Around line 33-38: Update the destination handling in the script around
destination and the existing shutil.rmtree call so an already-existing --out
path is rejected rather than recursively deleted. Preserve the repository
containment guard and allow the workflow’s expected fresh temporary-directory
path to proceed without any unconditional removal.

---

Nitpick comments:
In @.github/workflows/release-baml-language.yml:
- Around line 445-556: Add an appropriate job-level timeout-minutes to
build-swift-sdk, verify-swift-sdk, publish-swift-sdk, and smoke-swift-release.
Choose a limit that accommodates normal XCFramework builds, SwiftPM resolution,
git operations, and gh calls while ensuring hung network-dependent steps fail
promptly.
- Around line 467-477: The “Zip + checksum” step duplicates packaging logic
already implemented by build-xcframework.sh. Update the pack step to invoke
build-xcframework.sh with its --zip option and reuse the script’s computed
SwiftPM checksum output, removing the direct ditto and shasum commands while
preserving the existing zip and checksum GitHub outputs.
- Around line 1230-1244: Update the “Clone BoundaryML/baml-swift” step to pin
GitHub’s SSH host key instead of trusting arbitrary output from ssh-keyscan.
Verify the scanned key against GitHub’s published fingerprint before writing it
to ~/.ssh/known_hosts, and fail the step if verification does not match; keep
the existing deploy-key clone flow unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9f3d748d-1986-4542-8e47-a2cbeb7e973c

📥 Commits

Reviewing files that changed from the base of the PR and between ceae8ea and 34da3b3.

📒 Files selected for processing (5)
  • .github/workflows/release-baml-language.yml
  • baml_language/sdks/swift/mirror/.gitignore
  • baml_language/sdks/swift/mirror/Package.swift
  • baml_language/sdks/swift/mirror/README.md
  • scripts/assemble-swift-sdk-mirror

Comment thread scripts/assemble-swift-sdk-mirror Resolved
Comment thread scripts/assemble-swift-sdk-mirror Resolved
- release workflow: pass version + repo via env/$GITHUB_REPOSITORY
  instead of splicing ${{ }} into the run script text (zizmor; matches
  the file's env-var convention).
- assemble-swift-sdk-mirror: never rmtree an arbitrary --out — refuse
  roots/$HOME and only clear a pre-existing destination when it is
  empty or a prior mirror (SOURCE_SHA marker).
@vercel
vercel Bot temporarily deployed to Preview – beps July 23, 2026 18:08 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 July 23, 2026 18:16 Inactive
@ATX24
ATX24 added this pull request to the merge queue Jul 23, 2026
Merged via the queue into canary with commit 6939724 Jul 23, 2026
66 checks passed
@ATX24
ATX24 deleted the dhilan/swift-release-pipeline branch July 23, 2026 19:04
meefs pushed a commit to meefs/baml that referenced this pull request Jul 23, 2026
…4158)

## Summary

- make the eight-RID C# product an explicit release contract backed by
the shared CFFI artifacts, with platform-neutral preparation running in
parallel and per-RID verification fanning out afterward
- freeze registry identities, timestamps, and native provenance in the
release plan; stamp NuGet/Maven/Gradle consistently; make NuGet retries
content-aware; and bind manifests to the exact verified package
- gate channel advancement on all enabled publishers, rehearse the
production manifest in dry runs, and replace the registry ceiling with a
measured C# package-size policy
- preserve Dhilan's Swift build-once/passive-mirror/immutable-publish
design while adding SwiftPM to the frozen plan, release completion,
production and dry-run manifests, and the post-publish nightly gate
- make both Swift consumer gates invoke `BamlRuntime.nativeVersion()` so
the native binary cannot be dead-stripped, and make the mirror assembler
refuse every pre-existing output path instead of treating a forgeable
`SOURCE_SHA` marker as recursive-delete authority

## Swift review

Dhilan's merged PR BoundaryML#4149 chose the right overall direction: one
XCFramework build, verification before publication, an immutable GitHub
release asset, and a passive `baml-swift` mirror consumed from a clean
project. I kept that architecture.

It did not yet fully adhere to the shared release plan: the Swift
publisher was outside the final publisher fan-in, Swift was absent from
the frozen registry plan and manifests, nightly dispatch did not wait
for the Swift smoke, and both Swift checks only imported/printed without
calling native code. Its normal CI passed, but the release-dispatch job
was skipped, so those edges were not exercised end to end. This PR
closes those correctness gaps. Explicit Swift package-size history and
broader generated/simulator coverage should remain measured follow-ups
rather than an invented policy in this change.

## Validation

- 13 focused Python release-contract tests pass
- 45 `baml_release` Rust tests pass
- C# managed tests and the CFFI/C# ABI/lifetime probe pass
- a nightly C# package was produced locally with the planned NuGet
version
- a representative remapped Linux release cdylib compiled and passed the
shipping-path scan
- NuGet normalizer self-tests pass
- changed release workflows pass `actionlint` and YAML parsing
- commit hooks pass except `cargo-hawk`, which was skipped after its
environment failed because `gofmt` is unavailable; cargo fmt, clippy,
and YAML hooks pass independently

## Release readiness

No production release was triggered. NuGet package
ownership/trusted-publisher configuration still needs an administrative
confirmation before declaring the production publisher ready.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added contract-driven C# SDK preparation and platform-aware native
staging, with per-target native asset sizing and package digest
validation.
* Enriched release planning with registry-specific versions and
`released_at`, plus verified package digests in generated manifests.
* **Bug Fixes**
* Improved NuGet publishing safety by compare-then-allow republishing
based on normalized payload equality.
* Strengthened fail-closed platform and SDK contract validation
(including C#↔native dependency rules).
* **Tests**
* Expanded CI with additional unit tests and stricter version/gating
assertions; added new release-contract and manifest/version test suites.
* **Documentation**
* Updated C# SDK release pipeline docs and NuGet normalizer usage
(including new comparison mode).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant