munki-pkg drop-in compatibility: name handling, keychain paths, --skip-import, receipt-only, notarization deferral - #21
Conversation
The output package path is build/<name> (and build/Dist-<name> for
distribution builds), with name coming from build-info after ${version}
substitution. A name containing a path separator or ".." wrote the
artifact outside build/ — a path traversal driven by untrusted build-info.
Validate the resolved name is a single, safe path component before the
build starts, throwing invalidConfiguration otherwise.
Add PackageNameValidationTests covering unsafe/safe names and an
end-to-end build that must throw before pkgbuild is ever invoked.
Build-info files commonly set signing_info.keychain to
${HOME}/Library/Keychains/signing.keychain. swiftpkg passed that value
to productbuild verbatim, so signing failed with "Could not find
appropriate signing identity ... in keychain at ${HOME}/...". Expand
${HOME} to the user home directory and resolve a leading tilde before
handing the path to productbuild/productsign, matching munki-pkg.
munki-pkg prompts to import the built package into a Munki repo and offers --skip-import to suppress that prompt; CI pipelines pass it routinely. swiftpkg never prompts, so it previously rejected the flag as unknown and any pipeline passing --skip-import failed. Accept it as a documented no-op so those invocations work unchanged.
A project that has build-info but neither a payload folder nor a scripts folder is valid: pkgbuild --nopayload produces a receipt-only package that installs no files but records a receipt Munki conditions can key off. swiftpkg rejected these outright; munki-pkg builds them. The component builder already emits --nopayload with no --scripts, so only the up-front guard needed to go.
Loading a project with a present-but-incomplete notarization_info (e.g. a bare password with no apple_id/team_id/keychain_profile) threw at load time, so even --skip-notarization builds failed. munki-pkg tolerates the incomplete block at load and only errors when notarization is actually attempted. Parse it into a new .invalid(reason:) authentication case; notarize() rejects .invalid, while skipped builds proceed unaffected.
build-info may set name without a .pkg suffix (e.g. MunkiBootstrap).
munki-pkg writes the artifact as <name>.pkg; swiftpkg used the name
verbatim, producing an extensionless file that find '*.pkg' and
munkiimport miss. Normalize the resolved name to end in .pkg after
${version} substitution, matching munki-pkg.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe changes add receipt-only package verification, normalize and validate package names, defer invalid notarization errors until notarization, expand signing keychain paths, and support the ignored ChangesPackage Build Updates
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@swiftpkg/PackageBuilder.swift`:
- Around line 89-92: Add targeted Swift compatibility coverage for the
receipt-only behavior in PackageBuilder: create a project without payload or
scripts using TemporaryDirectory and RecordingRunner, build it, and assert the
generated command uses the pkgbuild --nopayload path. Keep the test hermetic and
focused on payload-free package behavior.
🪄 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: f6a05848-c43c-492a-b125-7c564980db8c
📒 Files selected for processing (10)
scripts/verify-loop.shswiftpkg/BuildInfo.swiftswiftpkg/PackageBuilder.swiftswiftpkg/PackageSettingsDraft.swiftswiftpkgCLI/CLI.swiftswiftpkgTests/CLITests.swiftswiftpkgTests/KeychainPathTests.swiftswiftpkgTests/NotarizationDeferTests.swiftswiftpkgTests/PackageNameExtensionTests.swiftswiftpkgTests/PackageNameValidationTests.swift
| // A project with neither payload nor scripts is valid: it builds a | ||
| // receipt-only package (pkgbuild --nopayload) that installs no files but | ||
| // records a receipt, which Munki conditions can key off. munki-pkg | ||
| // allows this, so swiftpkg does too. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Add hermetic receipt-only compatibility coverage.
Add a Swift test that builds a project with neither payload nor scripts using TemporaryDirectory and RecordingRunner, and asserts the generated command uses the receipt-only path.
As per coding guidelines, behavior changes affecting “payload-free packages” require targeted compatibility tests, and unit tests must use TemporaryDirectory and RecordingRunner.
🤖 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 `@swiftpkg/PackageBuilder.swift` around lines 89 - 92, Add targeted Swift
compatibility coverage for the receipt-only behavior in PackageBuilder: create a
project without payload or scripts using TemporaryDirectory and RecordingRunner,
build it, and assert the generated command uses the pkgbuild --nopayload path.
Keep the test hermetic and focused on payload-free package behavior.
Source: Coding guidelines
Assert that a project with neither payload nor scripts invokes pkgbuild with --nopayload and no --root, using TemporaryDirectory and RecordingRunner per the repo's unit-test conventions.
|
Added a hermetic receipt-only unit test in |
39a691d to
568e647
Compare
A set of small behaviors that let the tool stand in for munki-pkg against real-world build-info without surprises. Each is independent; they're grouped because they share the "faithful drop-in" theme and are individually tiny.
${HOME}and~in signing keychain paths — munki-pkg expands these; a literal${HOME}otherwise fails signing.--skip-importas an ignored no-op for pipelines that pass it.notarization_infovalidation until notarization actually runs, so--skip-notarizationbuilds with incomplete notary config still succeed..pkgto the resolved name when it lacks the extension, matching munki-pkg — otherwise the artifact is extensionless andfind '*.pkg'/ munkiimport miss it.Tests:
PackageNameValidationTests,KeychainPathTests,CLITests,NotarizationDeferTests,PackageNameExtensionTests; full suite green (33 tests).Part of a 9-PR series splitting a batch of features into small, themed, independently reviewable PRs. Each applies cleanly to
mainon its own; the ordering below only minimizes rebases as they land:Happy to squash, split, or reorder any of these to suit your review preferences.
Summary by CodeRabbit
--skip-importoption (parsed/accepted without changing the normal build workflow)..pkgafter version substitution.pkgbuild.--skip-notarization; errors surface only when notarization is attempted.