Repository navigation
feat(swift): release-pipeline publishing to baml-swift (Go-mirror pattern) - #4149
Conversation
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.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
⏭️ Performance benchmarks were skippedPerf benchmarks (CodSpeed) are opt-in on pull requests — they no longer run on every push. They always run automatically after merge to To run them on this PR, do any of the following, then push a commit (or re-run CI):
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThe 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. ChangesSwift SDK release
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
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Binary size checks passed✅ 7 passed
Generated by |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
.github/workflows/release-baml-language.yml (3)
445-556: 🩺 Stability & Availability | 🔵 TrivialNo
timeout-minuteson the new Swift jobs.
build-swift-sdk,verify-swift-sdk,publish-swift-sdk, andsmoke-swift-releaseall invoke network-dependent operations (SwiftPM resolution,git clone/push,ghcalls) without a job-leveltimeout-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 winReimplements zip/checksum packaging the build script already provides.
build-xcframework.shsupports--zip <path>and computes the SwiftPM checksum viaswift package compute-checksumin one step (see build-xcframework.sh:124-137). This step instead duplicates that logic withditto+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-keyscantrusts whatever host key GitHub returns without pinning.
ssh-keyscan github.com >> ~/.ssh/known_hostsaccepts 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
📒 Files selected for processing (5)
.github/workflows/release-baml-language.ymlbaml_language/sdks/swift/mirror/.gitignorebaml_language/sdks/swift/mirror/Package.swiftbaml_language/sdks/swift/mirror/README.mdscripts/assemble-swift-sdk-mirror
- 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).
…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 -->
Summary
Retires the standalone
baml-swiftdev-channel poller and moves Swift package publishing into the canary release pipeline, following the Go SDK mirror pattern exactly.baml-swiftbecomes a passive git mirror (no CI, no polling); the monorepo builds the XCFramework once per release as a release artifact (likebridge_cffi) and pushes the mirror.New jobs in
release-baml-language.ymlbuild-swift-sdk(macos-14) — builds all 5 Apple slices viabuild-xcframework.sh --all(bitcode-stripped), zips + checksums withshasum(SwiftPM checksum == sha256, no Swift toolchain needed on this path), and assembles the mirror tree viascripts/assemble-swift-sdk-mirror.verify-swift-sdk(macos-15) — pre-publish gate inall-builds.needs, parallel toverify-{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 (theBamlThrownValueSendable failure was exactly this class).publish-swift-sdk(gateddry_run==false && canary) — uploads the XCFramework as an immutable asset on thebaml-language-<version>release, then clonesbaml-swiftviaBAML_SWIFT_DEPLOY_KEY, rsyncs the mirror, pushes an immutablev<version>tag. Mirrorspublish-go-sdk.smoke-swift-release(macos-15, post-publish) — resolves the actually publishedbaml-swiftpackage by URL+checksum at thev<version>tag and runs it. Mirrorssmoke-go-release.New files
baml_language/sdks/swift/mirror/— source of truth for the passive repo'sPackage.swift(release-assetbinaryTarget) + README.scripts/assemble-swift-sdk-mirror— analog ofassemble-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
BAML_SWIFT_DEPLOY_KEYsecret — an SSH deploy key with write access toBoundaryML/baml-swift, parallel toBAML_GO_DEPLOY_KEY.publish-swift-sdkfails fast (test -n) without it.baml-swiftpassivation (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
BAML_GO_DEPLOY_KEYpattern (env → file → chmod 600 →GIT_SSH_COMMAND, never logged); pipeline isworkflow_dispatch/workflow_run-only (not PR-reachable); all interpolated values come from trusted sources (GitHub context,release.toml-derived plan outputs).actionlintclean (incl. shellcheck on run blocks);mirror/Package.swift(unstamped placeholders in-repo) is inert to the realsdks/swiftpackage and never built in CI.Test plan
workflow_dispatch/workflow_run), so this PR's CI exercises the normal suite; the Swift sdk-test gate + cargo tests pass unchanged (bridge untouched).BAML_SWIFT_DEPLOY_KEYexists —verify-swift-sdkgates it pre-publish,smoke-swift-releaseconfirms the published package post-publish.Summary by CodeRabbit