Skip to content

ci: add mac-build-smoke job — catch submodule-side breakage on every PR#806

Merged
buremba merged 2 commits into
mainfrom
ci/mac-build-smoke
May 17, 2026
Merged

ci: add mac-build-smoke job — catch submodule-side breakage on every PR#806
buremba merged 2 commits into
mainfrom
ci/mac-build-smoke

Conversation

@buremba
Copy link
Copy Markdown
Member

@buremba buremba commented May 17, 2026

Summary

Adds a mac-build-smoke job to .github/workflows/ci.yml that runs xcodebuild build (unsigned, no archive) against the pinned packages/web submodule SHA on PRs that could affect the Mac build.

Closes #793.

What triggers it

The job only runs when the diff touches a path that can break the Mac release pipeline:

  • packages/web — the submodule pointer (Mac source lives at packages/web/apps/mac/)
  • .github/workflows/mac-release.yml — the release workflow whose contract this smokes
  • .github/actions/setup-submodule — the composite action both workflows depend on

Everything else short-circuits with a notice and uses zero macOS-runner minutes.

What it does

  • Re-uses the existing setup-submodule composite action.
  • Fails fast on same-repo PRs if the submodule got stubbed (means OWLETTO_WEB_DEPLOY_KEY is missing/invalid — same posture as mac-release.yml's release contract).
  • On fork PRs without the deploy key it logs a notice and skips the build (forks legitimately can't access the private submodule).
  • Runs xcodebuild ... -scheme Lobu -configuration Release build CODE_SIGNING_ALLOWED=NO. No archive, no signing, no notarization, no DMG.

Note on the path filter

The issue's snippet uses contains(github.event.pull_request.changed_files || '', ...). That expression doesn't work — changed_files in the PR webhook payload is an integer (the count of changed files), not a list of paths, so contains() over it never matches and the job would run on every PR.

This implementation computes the changed-file list via git diff "$BASE_SHA"...HEAD in a setup step and gates the rest of the job on its output. Push events (no PR base SHA) default to running the job.

Runner cost

macos-15 is the most expensive runner tier, but the filter keeps it to PRs that actually touch the relevant paths — likely a handful per month, in line with how often the submodule pointer bumps.

Test plan

  • Verify the filter skips this CI run itself (this PR only touches .github/workflows/ci.yml, not the three trigger paths) — should see the mac-build-smoke job exist but log "No paths affecting the Mac build changed — skipping" and pass with no xcodebuild invocation.
  • On a follow-up PR that bumps the packages/web submodule pointer, confirm the smoke build actually runs and passes against the current owletto SHA.
  • Confirm a fork PR (no OWLETTO_WEB_DEPLOY_KEY) hits the "submodule stubbed on fork PR" notice rather than failing.

Summary by CodeRabbit

  • Chores
    • Added a path-filtered, lightweight macOS "smoke" build to CI that runs only when Mac app–related files change.
    • CI now skips or adjusts the mac build for forked PRs and situations where the mac submodule is unavailable, reducing unnecessary mac build runs and failing fast on genuine mac build problems.

Review Change Stack

`mac-release.yml` is workflow_dispatch only, so a rename or path move
inside the owletto submodule (Mac source lives at packages/web/apps/mac/)
can silently break the release pipeline and only surface the next time
someone triggers a release. This job runs xcodebuild build (unsigned,
no archive) against the pinned submodule SHA on PRs that touch:

  - packages/web (the submodule pointer)
  - .github/workflows/mac-release.yml
  - .github/actions/setup-submodule

Closes #793.

Note: `github.event.pull_request.changed_files` from the issue's snippet
is an integer in the webhook payload (a count, not a list), so the
`contains()` filter there would never match. This implementation uses a
git diff against the PR base to compute changed paths instead.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 17, 2026

Caution

Review failed

Pull request was closed or merged during review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 98ba572a-6f13-400e-abac-602ec292ed11

📥 Commits

Reviewing files that changed from the base of the PR and between cc20610 and bcc94e7.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml

📝 Walkthrough

Walkthrough

Adds a path-filtered mac-build-smoke CI job that gates an owletto submodule setup and an unsigned Xcode build for packages/web/apps/mac/Lobu.xcodeproj, with logic to skip or fail fast when the submodule is stubbed on forks or same-repo PRs.

Changes

Mac Build Smoke Test

Layer / File(s) Summary
Path filter and run decision
.github/workflows/ci.yml
Adds mac-build-smoke-filter job that computes PR base SHA (or defaults to run), diffs changed paths against Mac-related regex, and outputs run=true/false.
Submodule setup and control flow
.github/workflows/ci.yml
Adds mac-build-smoke job wiring: checkout with full history, runs ./.github/actions/setup-submodule, fails fast on same-repo PRs when submodule is stubbed, and skips on fork PRs without deploy key.
Unsigned Xcode build execution
.github/workflows/ci.yml
When enabled and submodule present, runs xcodebuild (Release, scheme Lobu) against packages/web/apps/mac/Lobu.xcodeproj with CODE_SIGNING_ALLOWED=NO.

Sequence Diagram

sequenceDiagram
  participant GitHub as GitHub Actions
  participant Filter as mac-build-smoke-filter
  participant Smoke as mac-build-smoke
  participant Submodule as setup-submodule
  participant Xcode as xcodebuild

  GitHub->>Filter: checkout history\ncompute PR base SHA\ndiff paths -> run=true/false
  Filter->>Smoke: emit run flag
  Smoke->>Submodule: setup owletto submodule (with deploy key)
  Submodule->>Smoke: submodule present / stubbed info
  Smoke->>Xcode: run unsigned xcodebuild on Lobu.xcodeproj\n(CODE_SIGNING_ALLOWED=NO)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit nudged the CI gate,
To build a Mac app small and straight,
It checks the paths, then sets the submodule,
Skips the forks, or fails if stubbed — so useful,
A tiny test to keep releases great.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a mac-build-smoke job to catch submodule-related breakage in CI.
Description check ✅ Passed The PR description provides a thorough summary of what was added, how it works, and what triggers it, though the Test plan section uses unchecked boxes without completion status.
Linked Issues check ✅ Passed The implementation fulfills all requirements from #793: adds mac-build-smoke job, runs on macos-15, checks submodule-affecting paths, uses setup-submodule action, runs unsigned xcodebuild, and properly handles fork/stub cases.
Out of Scope Changes check ✅ Passed All changes in .github/workflows/ci.yml are directly scoped to implementing the mac-build-smoke job and its path-filter dependency as specified in #793; no extraneous modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/mac-build-smoke

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

Comment thread .github/workflows/ci.yml Fixed
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

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 @.github/workflows/ci.yml:
- Around line 406-409: The mac-build-smoke job is inheriting default
GITHUB_TOKEN scopes; add an explicit least-privilege permissions block to the
job (or at the workflow root) to limit token capabilities—for example add a
permissions entry that sets contents: read (and any other minimal permissions
needed by mac-build-smoke) so the GITHUB_TOKEN scope is restricted for the
mac-build-smoke job.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c024be43-7cfe-45fa-8f49-aab26b5235c3

📥 Commits

Reviewing files that changed from the base of the PR and between 32920c8 and cc20610.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml

Comment thread .github/workflows/ci.yml Outdated
Comment on lines +406 to +409
mac-build-smoke:
runs-on: macos-15
timeout-minutes: 15
steps:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Set explicit least-privilege GITHUB_TOKEN permissions for this job.

mac-build-smoke currently inherits default token scopes. Please add an explicit permissions block (at workflow or job level), e.g. contents: read, to reduce CI token blast radius.

Suggested hardening change
 jobs:
+  mac-build-smoke:
+    permissions:
+      contents: read
-  mac-build-smoke:
     runs-on: macos-15
     timeout-minutes: 15
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
mac-build-smoke:
runs-on: macos-15
timeout-minutes: 15
steps:
mac-build-smoke:
permissions:
contents: read
runs-on: macos-15
timeout-minutes: 15
steps:
🤖 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/ci.yml around lines 406 - 409, The mac-build-smoke job is
inheriting default GITHUB_TOKEN scopes; add an explicit least-privilege
permissions block to the job (or at the workflow root) to limit token
capabilities—for example add a permissions entry that sets contents: read (and
any other minimal permissions needed by mac-build-smoke) so the GITHUB_TOKEN
scope is restricted for the mac-build-smoke job.

@codecov-commenter
Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cc206102bb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/ci.yml Outdated
# when the submodule pointer, the release workflow, or the submodule
# setup action changes.
mac-build-smoke:
runs-on: macos-15
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid scheduling macOS runners before filtering paths

Because the path gate runs as the first step inside mac-build-smoke, GitHub still schedules a macos-15 runner and performs checkout for every PR before this script can decide to skip. In this CI workflow, pull_request triggers all PRs, so backend/docs-only changes still consume scarce macOS runner startup time and can wait on macOS capacity; move the path decision to a job/workflow-level gate or a cheap Linux prefilter job before starting the macOS build job.

Useful? React with 👍 / 👎.

Comment thread .github/workflows/ci.yml Outdated
# there, so skip the rest gracefully rather than fail. Same-repo PRs
# have the key, so a stub here means the secret is misconfigured.
- name: Fail fast if submodule is stubbed (same-repo PRs only)
if: steps.filter.outputs.run == 'true' && steps.submodule.outputs.stubbed == 'true' && github.event.pull_request.head.repo.full_name == github.repository
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Treat push runs as same-repo when the submodule is stubbed

When this job runs on push to main, the filter defaults to run=true but github.event.pull_request is absent. If OWLETTO_WEB_DEPLOY_KEY is accidentally missing, setup-submodule writes the stub and this same-repo guard does not fire, so the build is skipped and CI can stay green until mac-release.yml fails later; make non-PR events fail on stubbed == 'true' and reserve the graceful skip only for actual fork PRs.

Useful? React with 👍 / 👎.

…tighten push stub-check

pi review findings on the mac-build-smoke job:

1. Skipped PRs allocated a macOS runner just to evaluate the diff. Split
   into a cheap ubuntu `mac-build-smoke-filter` job + the macOS
   `mac-build-smoke` job gated on `needs.mac-build-smoke-filter.outputs.run`.
   The macOS runner is now only allocated when the filter says run.

2. `.gitmodules` was missing from the path filter — changes there can
   break submodule resolution without touching `packages/web`. Added.

3. The fork-skip condition used a bare `pull_request.head.repo.full_name`
   compare, which on push events (where the PR object is absent) silently
   landed in the wrong branch. Tightened both stub-handling steps to gate
   on `github.event_name == 'pull_request'` first, so push events with a
   stubbed submodule now fail loudly as intended.
Comment thread .github/workflows/ci.yml
Comment on lines +403 to +442
runs-on: ubuntu-latest
outputs:
run: ${{ steps.filter.outputs.run }}
steps:
- uses: actions/checkout@v4
with:
# Need the PR base commit so we can diff against it. The default
# fetch-depth=1 only has HEAD.
fetch-depth: 0

- name: Decide whether to run the Mac smoke build
id: filter
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
set -euo pipefail
if [ -z "${BASE_SHA:-}" ]; then
# push to main (or any non-PR trigger) — always run.
echo "run=true" >> "$GITHUB_OUTPUT"
exit 0
fi
changed=$(git diff --name-only "$BASE_SHA"...HEAD)
if echo "$changed" | grep -E '^(packages/web($|/)|\.github/workflows/mac-release\.yml$|\.github/actions/setup-submodule(/|$)|\.gitmodules$)' >/dev/null; then
echo "run=true" >> "$GITHUB_OUTPUT"
else
echo "run=false" >> "$GITHUB_OUTPUT"
echo "::notice::No paths affecting the Mac build changed — skipping mac-build-smoke."
fi

# Cheap end-to-end Xcode build for the Mac app. `mac-release.yml` is
# workflow_dispatch only, so a rename or path move inside the owletto
# submodule (Mac source lives at `packages/web/apps/mac/`) can silently
# break the release pipeline and only surface the next time someone
# triggers a release. Build-only (no archive, no signing, no notarize)
# is enough to prove the Xcode project + submodule layout still compose.
#
# Runner cost is bounded by the filter job above — the macOS runner is
# only allocated when the submodule pointer, the release workflow, the
# submodule setup action, or `.gitmodules` changes.
mac-build-smoke:
Comment thread .github/workflows/ci.yml
Comment on lines +443 to +476
needs: mac-build-smoke-filter
if: needs.mac-build-smoke-filter.outputs.run == 'true'
runs-on: macos-15
timeout-minutes: 15
steps:
- uses: actions/checkout@v4

- id: submodule
uses: ./.github/actions/setup-submodule
with:
deploy-key: ${{ secrets.OWLETTO_WEB_DEPLOY_KEY }}

# Forks (and any run where the secret isn't available) get a stub
# package.json from setup-submodule. There's no Mac source to build
# there, so skip the rest gracefully rather than fail. Same-repo PRs
# and push events both have the key, so a stub there means the secret
# is misconfigured — fail loudly.
- name: Fail fast if submodule is stubbed (same-repo PRs and push)
if: steps.submodule.outputs.stubbed == 'true' && !(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository)
run: |
echo "::error::Mac source unreachable — OWLETTO_WEB_DEPLOY_KEY missing or invalid."
exit 1

- name: Skip on fork PRs without submodule access
if: steps.submodule.outputs.stubbed == 'true' && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
run: echo "::notice::Submodule stubbed on fork PR — skipping Mac smoke build."

- name: Build (unsigned, no archive)
if: steps.submodule.outputs.stubbed != 'true'
run: |
xcodebuild \
-project packages/web/apps/mac/Lobu.xcodeproj \
-scheme Lobu -configuration Release build \
CODE_SIGNING_ALLOWED=NO
@buremba buremba merged commit bed6e1d into main May 17, 2026
25 of 27 checks passed
@buremba buremba deleted the ci/mac-build-smoke branch May 17, 2026 04:10
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.

Add CI Mac-build smoke job (catches submodule path/scheme breakages on every PR)

3 participants