Skip to content

Add GitHub Action and Azure DevOps templates for building packages - #27

Merged
jordancalhoun merged 5 commits into
codecarton:nextfrom
rodchristiansen:feat/ci-templates
Aug 2, 2026
Merged

Add GitHub Action and Azure DevOps templates for building packages#27
jordancalhoun merged 5 commits into
codecarton:nextfrom
rodchristiansen:feat/ci-templates

Conversation

@rodchristiansen

@rodchristiansen rodchristiansen commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Two ready-to-use CI integrations for building packages with the tool:

  • A GitHub composite action (action.yml) plus README usage.
  • An Azure DevOps steps template.

No source changes.


Part of a 9-PR series splitting a batch of features into small, themed, independently reviewable PRs. Each applies cleanly to main on its own; the ordering below only minimizes rebases as they land:

  1. Process and exit-code correctness: pipe drain, notarization failure, distinct exit codes #19 — process & exit-code correctness
  2. Version resolution: --pkg-version/--output-dir overrides and dynamic version tokens #20 — version resolution · munki-pkg drop-in compatibility: name handling, keychain paths, --skip-import, receipt-only, notarization deferral #21 — munki-pkg compatibility
  3. Add --output-format json build manifest #22 — json manifest · Add --lint to validate a project without building #23 — lint · Add --verify to check the built package against build-info #24 — verify · Add --provenance attestation sidecar #25 — provenance · Add .env build-time variable substitution for scripts #26 — .env substitution
  4. Add GitHub Action and Azure DevOps templates for building packages #27 — CI templates

Happy to squash, split, or reorder any of these to suit your review preferences.

Summary by CodeRabbit

  • New Features
    • Enhanced the macOS build workflow to securely install the required installer and build packages with JSON output.
    • Added options to pin the installer SHA-256 and require a specific signing Team ID, plus stronger integrity and signature checks.
    • Supports optional linting, verify, and provenance, while exposing built package path, version, and SHA-256 as outputs.
    • Added/updated an Azure DevOps pipeline template with matching build controls and outputs.
  • Documentation
    • Documented the new workflow action inputs, outputs, verification behavior, and an example usage workflow.

action.yml lets any repo build a swiftpkg project on a macOS runner with
`uses: codecarton/swiftpkg@v1` instead of hand-rolling install + invoke. It
installs the swiftpkg release (Universal .pkg via `gh release download` +
installer), optionally lints, builds with --output-format json (+ optional
--verify/--provenance/--pkg-version/--output-dir), and exposes pkg-path,
version, and sha256 as step outputs.

Adapted from munki-pkg's action to swiftpkg's CLI: no --build/--no-import
(swiftpkg builds by default), and the binary is installed from the release
package rather than downloaded bare. README documents inputs/outputs.

Requires a swiftpkg release carrying the CI flags (PRs for --output-format,
--output-dir, --pkg-version, --lint, --verify).
azure-pipelines/swiftpkg-build.yml is the ADO equivalent of action.yml: a
steps template another pipeline can include to install swiftpkg, optionally
lint, build with --output-format json (+ optional --verify/--provenance/
--pkg-version/--output-dir), and expose pkgPath/version/sha256 as output
variables on the 'build' step. Runs on a macOS agent.

Adapted from munki-pkg's template to swiftpkg's CLI: installs the release
Universal .pkg (asset URL resolved from the GitHub release API since the
filename embeds the version) instead of a bare binary, and drops
--build/--no-import.
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 903f1771-fc6b-488b-98a6-8e03d2897817

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds GitHub Actions and Azure DevOps integrations that securely install swiftpkg, optionally lint projects, build Apple installer packages, and expose package path, version, and SHA-256 outputs. README documentation covers inputs, outputs, verification, and workflow usage.

Changes

CI build integrations

Layer / File(s) Summary
CI contracts and documentation
action.yml, azure-pipelines/swiftpkg-build.yml, README.md
Defines action and pipeline parameters, installer verification inputs, build outputs, defaults, and GitHub Action workflow documentation.
GitHub Action installation and build
action.yml
Downloads and verifies the swiftpkg package, optionally lints, builds with required JSON/output flags, and publishes package metadata outputs.
Azure pipeline installation and build
azure-pipelines/swiftpkg-build.yml
Resolves and verifies the selected release, optionally lints, builds with controlled arguments, and publishes validated pipeline output variables.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CIrunner
  participant GitHubReleases
  participant Installer
  participant Swiftpkg
  participant Jq
  CIrunner->>GitHubReleases: Resolve and download swiftpkg package and SHA256SUMS
  CIrunner->>Installer: Verify and install swiftpkg
  CIrunner->>Swiftpkg: Optionally lint and build project
  Swiftpkg-->>CIrunner: Return JSON build result
  CIrunner->>Jq: Extract package path, version, and SHA-256
  Jq-->>CIrunner: Publish CI outputs
Loading

Possibly related PRs

Suggested labels: enhancement

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the addition of GitHub Action and Azure DevOps templates for building packages.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@rodchristiansen

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@rodchristiansen

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 56 minutes.

@rodchristiansen

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@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: 6

🤖 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 `@action.yml`:
- Around line 63-70: Update the SwiftPkg download/install block to create and
use a unique per-invocation directory under RUNNER_TEMP instead of the shared
runner_tmp path. After downloading, resolve the matching package into a
variable, validate that exactly one asset was found, and pass that exact path to
installer; reject zero or multiple matches.
- Around line 17-20: Update the swiftpkg-version input default so the action
does not implicitly install the moving latest release; require an explicit
version or use a specific known release. In the installation flow, verify the
exact downloaded release asset with a trusted checksum or signature before
passing it to sudo installer, rather than relying on --verify.

In `@azure-pipelines/swiftpkg-build.yml`:
- Around line 38-40: Update the swiftpkgVersion parameter in the pipeline
configuration to use a fixed immutable release instead of latest, and add
verification of the downloaded GitHub asset’s digest or signature before the
sudo installation step proceeds. Ensure installation is blocked when
verification fails.
- Line 69: Update the asset URL assignment to select only the first matching
asset within the jq expression, removing the external head -n1 pipeline stage.
Preserve the existing swiftpkg universal package filter and browser_download_url
output while ensuring pipefail cannot treat jq’s SIGPIPE as a failure.
- Around line 110-112: Update the output-variable assignments for pkgPath,
version, and sha256 to extract required non-null values with jq -er, ensure jq
failures propagate instead of being masked by echo, and escape each value
according to Azure logging-command requirements before publishing it with
task.setvariable.

In `@README.md`:
- Around line 246-250: Update the swiftpkg CI flags list in the README
documentation to include --provenance alongside the existing required flags,
matching the provenance input passed by action.yml.
🪄 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: 140d4057-3470-4c3b-9340-70805c99fea5

📥 Commits

Reviewing files that changed from the base of the PR and between 25f222d and 90b7eb1.

📒 Files selected for processing (3)
  • README.md
  • action.yml
  • azure-pipelines/swiftpkg-build.yml

Comment thread action.yml Outdated
Comment thread action.yml Outdated
Comment thread azure-pipelines/swiftpkg-build.yml Outdated
Comment thread azure-pipelines/swiftpkg-build.yml Outdated
Comment thread azure-pipelines/swiftpkg-build.yml Outdated
Comment thread README.md Outdated
…outputs

Both the GitHub action and the Azure template now verify the downloaded
swiftpkg installer's Developer ID signature and notarization (pkgutil
--check-signature + spctl) before running it as root, and note that pinning the
version is preferred over 'latest'. The action downloads into a fresh directory
and requires exactly one matching asset. The Azure template selects the asset
inside jq instead of piping to head (which could SIGPIPE under pipefail),
extracts outputs with jq -er so a null fails the step, and strips CR/LF from
output values so they can't inject a second logging command. Documented
--provenance in the README.
@rodchristiansen

Copy link
Copy Markdown
Contributor Author

All six addressed in the latest commit:

  • Unpinned/unverified install (both templates) — the installer's Developer ID signature and notarization are now verified (pkgutil --check-signature + spctl --assess --type install) before running as root; both note that pinning the version is preferred over latest.
  • Ambiguous match (action) — downloads into a fresh mktemp -d and requires exactly one matching asset, failing otherwise.
  • head + pipefail SIGPIPE (azure) — the asset is now selected with jq -er 'first(...)' instead of piping to head.
  • Azure output values — extracted with jq -er (a null/missing field now fails the step) and stripped of CR/LF so a value can't inject a second logging command.
  • README--provenance documented in the CI flags list.
    Both templates validate as YAML.

Both templates downloaded 'swiftpkg-*-universal.pkg'. No release has ever
published that asset. A release ships swiftpkg-<version>-cli.pkg,
swiftpkg-<version>-combined.pkg, SHA256SUMS, a universal .tar.gz and the
Swiftpkgr zip, so `gh release download` answered "no assets match the file
pattern" and the install step could never have succeeded. Ask for the CLI
package, which is what CI needs.

With the right asset selected, harden what happens to it. It is installed as
root, so three checks now stand between the download and `sudo installer`, each
covering what the others cannot:

  - The caller's own swiftpkg-sha256, when set. GitHub release assets can be
    replaced without moving the tag, so this is the only check that pins the
    bytes; a build that must be reproducible should set it.
  - SHA256SUMS from the release. It ships alongside the asset, so it moves with
    a replaced release -- it catches a truncated or corrupted download, not a
    substituted one.
  - Developer ID Team ID plus spctl. spctl establishes that Apple notarized the
    package; the Team ID establishes who signed it, which notarization alone
    does not. Forging this requires the publisher's certificate.

Default swiftpkg-version to a pinned tag instead of 'latest', so a build does
not silently change when the next release ships. 'latest' still works for anyone
who wants it.

Verified against the real v0.3.1 release on macOS: the install step runs green
end to end (with sudo stubbed), and fails closed on a mismatched checksum and on
an unexpected Team ID.
@rodchristiansen

Copy link
Copy Markdown
Contributor Author

Addressed, and the review turned up a bigger problem alongside it.

The asset never existed. Both templates downloaded swiftpkg-*-universal.pkg. No release has ever published that name — v0.3.1 ships swiftpkg-0.3.1-cli.pkg, swiftpkg-0.3.1-combined.pkg, SHA256SUMS, swiftpkg-0.3.1-universal.tar.gz and Swiftpkgr-0.3.1.zip. Run against a real release, gh release download answers no assets match the file pattern, so the install step could never have succeeded. Both templates now ask for the CLI package.

On the security finding: three checks now stand between the download and sudo installer, each covering what the others cannot.

  • swiftpkg-sha256 / swiftpkgSha256, when the caller sets it. Release assets can be replaced without moving the tag, so this is the only check that actually pins the bytes.
  • SHA256SUMS from the release. It ships alongside the asset and moves with a replaced release, so it catches a truncated or corrupted download — not a substituted one. Worth being precise about, since it would otherwise read as more than it is.
  • Developer ID Team ID (expected-team-id, default DPXY7JLK67) plus spctl. spctl establishes that Apple notarized the package; the Team ID establishes who signed it, which notarization alone does not. This is the check a substituted asset cannot pass.

swiftpkg-version now defaults to a pinned v0.3.1 rather than latest, so a build does not silently change when the next release ships. latest still works for anyone who wants it.

Verified against the real v0.3.1 release on macOS with sudo stubbed: both install steps run green end to end, and fail closed on a mismatched checksum and on an unexpected Team ID.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
azure-pipelines/swiftpkg-build.yml (1)

67-94: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Authenticate the GitHub release metadata request
Unlike action.yml, this template has no token-backed GitHub API call. Unauthenticated curl requests to api.github.com can hit the 60/hour REST limit on shared Azure-hosted agents, making this install step fail with a generic asset lookup error. Accept an optional token here and send Authorization: Bearer ...; adding --retry/--retry-delay to the metadata request would also reduce transient failures.

🤖 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 `@azure-pipelines/swiftpkg-build.yml` around lines 67 - 94, The GitHub release
metadata request in the swiftpkg install step lacks optional authentication and
retry handling. Update the metadata curl for api to accept the available
optional GitHub token, send it as an Authorization Bearer header when present,
and add retry with delay options while preserving unauthenticated operation when
no token is configured.
🤖 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.

Outside diff comments:
In `@azure-pipelines/swiftpkg-build.yml`:
- Around line 67-94: The GitHub release metadata request in the swiftpkg install
step lacks optional authentication and retry handling. Update the metadata curl
for api to accept the available optional GitHub token, send it as an
Authorization Bearer header when present, and add retry with delay options while
preserving unauthenticated operation when no token is configured.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7a5174a6-07c3-4084-8229-6f3d80f2af41

📥 Commits

Reviewing files that changed from the base of the PR and between 90b7eb1 and 00b1754.

📒 Files selected for processing (3)
  • README.md
  • action.yml
  • azure-pipelines/swiftpkg-build.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • README.md

@jordancalhoun
jordancalhoun changed the base branch from main to next August 2, 2026 14:05
@jordancalhoun
jordancalhoun merged commit e64b034 into codecarton:next Aug 2, 2026
2 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Aug 11, 2026
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.

2 participants