Commit Graph
13 Commits
Author SHA1 Message Date
dependabot[bot] 412aa1e9ab chore(deps): bump github/codeql-action from 3 to 4
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3 to 4.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-20 04:31:08 +00:00
james.maesandClaude Opus 4.7 439e1ee2f5 ci: build hygiene — webview cleanup + OpenSSF Scorecard (#46, #178) (#194)
* ci(build-webview): sweep stale hashed chunks before rsync (#46)

Vite emits content-hashed asset names (e.g. `index-CXPb0I5z.js`), so the
active bundle filename rotates on every source/dependency edit. The
existing rsync runs without `--delete` (to preserve `bus-harness.html`
and `.gitignore`), so old chunks accumulated in
`App/Resources/webview/assets/` — observed 9 stale `index-*.js` /
`.js.map` pairs locally before this fix.

Add an explicit `rm -f` of the asset glob (JS + JS map + CSS + CSS map)
before the rsync drops the fresh bundle. The preserved files
(`bus-harness.html`, `index.html`, `.gitignore`) live one level up in
`$DEST`, not in `$DEST/assets`, so the rm cannot reach them.

Verified locally: `bash scripts/build-webview.sh` now leaves exactly one
`index-*.js` + `.js.map` in `assets/` (matching the reference in
`index.html`).

Refs #46

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* ci(scorecard): add OpenSSF Scorecard workflow + README badge (#178)

Adds `.github/workflows/scorecard.yml` running `ossf/scorecard-action@v2.4.0`
on:
- Weekly cron (Mondays 06:00 UTC) for posture drift detection
- Push to develop for prompt regression visibility
- workflow_dispatch for ad-hoc runs

Permissions follow the canonical Scorecard set (`id-token: write`,
`contents: read`, `security-events: write`) with top-level `read-all` and
job-scoped writes. Results are published to the OpenSSF public dataset
(powers the README badge URL) and uploaded as SARIF to code-scanning.

The workflow consumes no untrusted user inputs in `run:` blocks, so it is
not exposed to workflow-injection patterns documented in
github.blog/security/.../how-to-catch-github-actions-workflow-injections.

README.md gains the standard Scorecard badge next to the existing
license/platform/swift badges.

Refs #178

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 09:29:48 -05:00
james.maes 774e60a020 ci(actions): create GitHub Release directly in publish-tag job (#187)
The default GITHUB_TOKEN cannot trigger downstream workflows (GitHub
prevents the chain to avoid infinite loops). publish-tag's `git push
origin "$TAG"` therefore never fires release.yml's `push: tags:`
listener — observed on v0.1.0-dev.50, where the tag landed but the
Release object was missing until manually created.

Fold the Release creation into the publish-tag job using `gh release
create` with GH_TOKEN=secrets.GITHUB_TOKEN. Direct API calls work fine
with the default token; only the push→workflow chain is blocked.

- Idempotent: skips if release already exists.
- Notes: auto-generated from `git log $prev..$TAG` plus a Verification
  block linking back to the CI run.
- Prerelease flag respects steps.version.outputs.prerelease (true for
  dev/rc tags, false for vX.Y.Z final tags on main).

release.yml stays untouched as a fallback for manually-pushed tags
(humans pushing tags directly CAN trigger workflows).

Closes #186
2026-05-13 18:28:07 -05:00
james.maes 4cdb3560e9 ci(actions): age-filter zombie reaper (>= 1h) for multi-runner safety (#189)
Grogu will host multiple self-hosted runners simultaneously (planned: 3
runners). Each runner's job-start cleanup step previously killed ANY
xctest/swift-test/swift-driver — meaning sibling runners would nuke
each other's in-flight tests.

Real CI jobs complete in <10 min. Zombies from interactive Xcode use
are typically >hours old. A 1-hour age cutoff cleanly separates the
two populations.

awk filter: ps -o etime formats are `MM:SS` (<1h), `HH:MM:SS` (>=1h),
or `DD-HH:MM:SS` (days). Match the latter two by testing for `-` (days
prefix) or three `:`-separated groups.

Single-runner behavior unchanged. Validated against synthetic ps
output covering all three etime format cases.

Closes #188
2026-05-13 17:33:03 -05:00
james.maes 81ce64c3f7 ci(actions): reap orphan xctest/swift-test on self-hosted before each job (#183)
Grogu is a shared workstation, not an ephemeral VM. Interactive Xcode
test runs, aborted swift test sessions, or debugger crashes can leave
orphan xctest/swift-test/swift-driver processes around for hours,
holding Mach services + sockets + ports that subsequent CI jobs block
on when mounting their own test infrastructure.

Concrete incident: develop run 25824607025 hung in SPM AgentCore for
34 min (0% CPU, sleeping state) while 6 unrelated xctest zombies aged
22-24h were alive from prior interactive use. The runner only executes
one job at a time, so any such process at job start belongs to no live
job and is safe to kill.

Add a first step that runs SIGTERM then SIGKILL on any
xctest/swift-test/swift-driver process. Gated to runner.environment ==
'self-hosted' since github-hosted VMs start clean.

Closes #182
2026-05-13 16:37:27 -05:00
james.maesandClaude Opus 4.7 eef1725292 ci: move swift-packages matrix to self-hosted runner (Grogu) (#181)
* ci(actions): move swift-packages matrix to self-hosted runner (Grogu)

The github-hosted macos-15 pool was the rate-limiting step for v0.1: 13
matrix jobs + 1 app-build job all needed macOS slots, GitHub scheduled
them 1-3 at a time, and total wall-clock was ~1-2h per run versus actual
work of <10m. Grogu is registered with labels [self-hosted, macOS, ARM64,
jarvis] and _work/ symlinked to HD-2 (1.3 TB) for headroom.

Scope:
- swift-packages matrix only — app-build stays on macos-15 for now.
- `if:` clause blocks fork PRs from triggering self-hosted jobs (push,
  workflow_dispatch, and same-repo PRs only).
- Xcode select switches from `sudo xcode-select -s` to a per-process
  DEVELOPER_DIR env so the runner doesn't need passwordless sudo. The
  fallback chain now also accepts /Applications/Xcode.app/Contents/Developer
  so Grogu's local Xcode 26.5 is picked up.

Closes #180

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* ci(actions): fix self-hosted runner env quirks for keychain + cache

Three SPM failures on PR #181's first self-hosted CI run, all
environment-specific:

- SPM Keychain: errSecInteractionNotAllowed (-25308). The LaunchAgent
  has no UI session and the login keychain is locked.
- SPM Voice + SPM Harness: github-hosted actions/cache@v4 entries with
  absolute paths (/Users/runner/work/...) baked into
  .build/artifacts/onnxruntime.xcframework. Cache key only contained
  runner.os (= macOS for both environments), so self-hosted hit the
  poisoned github-hosted cache.

Fixes:

- Restrict actions/cache@v4 to runner.environment == 'github-hosted'.
  Self-hosted's _work/ on HD-2 persists between jobs naturally, so the
  cache action is unnecessary there and prevents path-baked cache
  poisoning between environments.

- Add a "Unlock runner keychain" step gated to runner.environment ==
  'self-hosted'. Unlocks a pre-created jarvis-runner.keychain-db with
  password from the repo secret JARVIS_RUNNER_KEYCHAIN_PASSWORD and
  prepends it to the user search list so SecItemAdd writes there.

Document both in CLAUDE.md "Self-hosted CI runner".

Refs #180

* ci: retrigger after JARVIS_RUNNER_KEYCHAIN_PASSWORD secret fix

Previous run failed all 13 SPM jobs with 'passphrase you entered is not
correct' because the secret value was set to literal '-' (gh secret set
parsed '--body -' as the body value, not as 'read from stdin'). Secret
now contains the correct password. This empty commit triggers a fresh
CI run that will resolve the corrected secret.

Refs #180

* ci(actions): drop set-keychain-settings from unlock step

The Security framework requires user interaction for set-keychain-settings
even when the keychain is unlocked, and the LaunchAgent on Grogu has no
UI. The settings (no-timeout, no-lock-on-sleep) are persistent and were
applied once at keychain-creation time; only the unlock step needs to
run every job.

Refs #180

* ci(actions): also set default-keychain so SecItemAdd targets jarvis-runner

SecItemAdd on the legacy file-based macOS keychain writes to the user's
DEFAULT keychain, not the first writable keychain in the search list.
Changing list-keychains alone left SecItemAdd targeting the locked
login.keychain-db, still returning errSecInteractionNotAllowed (-25308).

Also set the user's default keychain to jarvis-runner.keychain-db in the
unlock step. This is persistent for the runner user (james.maes), so
SecItemAdd from interactive use will also go there — documented as a
side effect in CLAUDE.md with the undo command.

Refs #180

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 15:29:09 -05:00
james.maes 16bed16012 ci(actions): restore pnpm + node setup on app-build for Xcode build phase (#173)
PR #164 stripped pnpm+node setup from app-build expecting the artifact to be sufficient, but Xcode's build-phase script invokes scripts/build-webview.sh which needs pnpm on PATH. Re-adds Setup pnpm + Setup Node.js steps. Surfaced by PR #170's error-visibility improvement.
2026-05-13 10:24:10 -05:00
james.maesandClaude Opus 4.7 bcc55c68be fix(ci): pin Xcode 26.x, drop phantom VoiceLog, harden Batcher timing (#167)
CI run 25799596445 failed on 6 SPM packages + the App target. Root cause
was a toolchain skew between local dev (Swift 6.3.2 / Xcode 26) and CI
(Swift 6.0 / Xcode 16):

- mlx-audio-swift v0.1.2 ships swift-tools-version:6.2 which Swift 6.0
  cannot parse, breaking Voice + Harness + the App target with
  "Dependencies could not be resolved because 'mlx-audio-swift' contains
  incompatible tools version (6.2.0)".
- MCP swift-sdk 0.12.0 uses the new `withThrowingTaskGroup` overload
  (no `of:` parameter) that only exists in Swift 6.2+.
- AgentCore tests use `@MainActor` XCTestCase with `await super.setUp()`,
  a pattern Swift 6.0 rejects but Swift 6.1+ accepts.

The macos-15 runner already ships Xcode 26.3 / 26.2 / 26.1 / 26.0
alongside 16.x, so the fix is to switch the Xcode select. Fallback to
Xcode_26.app preserves robustness against patch-level shuffles.

Also:
- Drop `VoiceLog` from the SPM matrix. No `packages/VoiceLog` directory
  exists; the job failed with `chdir error: No such file or directory`.
  Voice-log work is parked under v1.1.
- Bump BatcherTests `waitForDrain` from 80ms to 250ms. The batcher
  window is 33ms; 80ms was tight enough that macos-15 dropped
  test_tokenDeltaConcat with sendCount=0 because the scheduled drain
  hadn't completed its actor + main-actor hop before the test resumed.
  250ms (~7.5× the window) survives CI jitter; verified locally — all
  five Batcher tests pass in 1.27s.

Refs: CI run 25799596445.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 08:37:47 -05:00
james.maesandClaude Opus 4.7 ae7d8a805e ci(actions): make Typecheck step blocking (#166)
PR #165 fixed the one real strict-undefined error in SegmentedRing.tsx;
the other ~30 errors reported in CI run 25797533005 were downstream of
`TS2307: Cannot find module '@jarvis/bus'` and resolve automatically
once `scripts/build-webview.sh` produces the bus package's
`dist/index.d.ts` (which CI already runs before typecheck).

Removes `continue-on-error: true` from the Typecheck step so typecheck
regressions block CI going forward.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 07:38:39 -05:00
james.maes 5458732546 ci(actions): apply missed webview reorder + rename artifact + non-block typecheck (164)
Three fixes that #161 attempted but only partially landed: webview build-before-typecheck (missed in #161 due to security-hook short-circuit), artifact rename webview-dist→webview-resources (matching the downloads), typecheck continue-on-error:true (~30 pre-existing TS18048 strict-undefined errors in hud src — filed as v0.2 cleanup). After this lands, SPM + app-build + publish-tag chain unblocks.
2026-05-13 07:06:59 -05:00
james.maes 7a22b0513f ci(actions): remove custom CodeQL workflow — default setup now enabled
Default code-scanning setup enabled via API after going public; advanced/custom workflow now redundant + would error with 'default setup is enabled'.
2026-05-13 07:01:03 -05:00
james.maes f6637ec39a ci(actions): fix typecheck/build order + share webview artifact across jobs (#161)
Three surgical fixes to .github/workflows/ci.yml from the first develop-push validation cycle:

1. Webview job: typecheck ran before build, so packages/hud TS imports of @jarvis/bus failed (TS2307). Reordered: install → build → typecheck → test. Build invokes scripts/build-webview.sh, producing App/Resources/webview/ directly.

2. swift-packages job: 6 packages (AgentCore/Bus/Harness/MCP/Voice/VoiceLog) failed with 'bus not mounted' because BusTests mount real WKWebView. Added needs: [webview] + download-artifact for the new webview-resources artifact.

3. app-build job: replaced inline pnpm+node+build-webview.sh with the same artifact download. One webview build serves all consumers.

Artifact renamed webview-dist → webview-resources (production-stamped App/Resources/webview/ tree). Old name was 1 day old, no external consumers.
2026-05-13 06:55:49 -05:00
james.maes 223310aa27 ci(actions): full pipeline — build / test / scan / publish (#154)
Adds five GitHub Actions workflows + CODEOWNERS + BUILDING.md CI section.

- ci.yml: boundary gates (Ubuntu), webview pnpm test+build (Ubuntu), 14-package SPM matrix on macos-15, app target via xcodebuild, optional self-hosted real-hardware lane, semver tag-publish on push to develop/rc/release/main.
- codeql.yml: Swift + JS/TS with security-extended queries, weekly cron.
- semgrep.yml: p/default + p/swift + p/typescript + p/secrets, SARIF upload, optional SEMGREP_APP_TOKEN.
- dependency-review.yml: blocks severity:high on PRs touching manifests/lockfiles.
- release.yml: tag-triggered GitHub Release with auto-generated changelog.

Branch + tag conventions: feature/fix branches run checks only; develop publishes v0.X.Y-dev.<run_number>; rc/release publishes v0.X.Y-rc.N; main publishes v0.X.Y. Conventional-Commits-aware bumping (feat → minor, fix → patch, feat!/BREAKING → major). Seed version v0.1.0.
2026-05-13 06:28:10 -05:00