Files
Jarvis/scripts/build-webview.sh
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

106 lines
4.7 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# build-webview.sh — Xcode pre-build phase (Plan 03-05).
#
# Produces webview/packages/hud/dist/ and rsyncs the output into
# App/Resources/webview/ so the R3F bundle is covered by the app bundle
# codesign pass.
#
# Order invariant (see project.yml preBuildScripts + postBuildScripts):
# preBuildScripts:
# 1. check-bus-harness-parity.sh
# 2. check-bus-protocol-version.sh
# 3. check-no-evaluate-javascript.sh
# 4. check-single-writer-hudstate.sh
# 5. build-webview.sh (this script) ← produces Resources/webview/assets/*.js
# postBuildScripts:
# 6. verify-entitlements.sh --pre-codesign
# 7. codesign.sh ← signs Jarvis.app INCLUDING
# Contents/Resources/webview/
# 8. verify-entitlements.sh --post-codesign
# 9. verify-codesign-settings.sh
#
# Caching: this script pnpm-installs only when the lockfile sha changed
# (content-hash sentinel). On clean repos the first run is slow (~30s);
# subsequent incremental Xcode builds are ~3-5s through the pnpm cache.
#
# The rsync explicitly EXCLUDES `bus-harness.html` and the webview's own
# `.gitignore` so we never trample 02-03's committed bus-harness.html (which
# the `check-bus-harness-parity.sh` pre-build phase requires to exist + stay
# byte-identical with `webview/bus-harness.html`).
#
# Usage:
# scripts/build-webview.sh # invoked by Xcode pre-build
# bash scripts/build-webview.sh # manual from repo root
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
# Xcode IDE GUI doesn't inherit the user's shell PATH (only `xcodebuild` from
# a terminal does). Homebrew + corepack-managed pnpm live outside the default
# /usr/bin:/bin minimal env Xcode uses for build phases. Prepend the common
# locations so this script works identically from CLI and from Xcode IDE.
# Nix profile paths are included so users on nix-darwin / home-manager /
# multi-user nix find pnpm regardless of which profile owns the symlink.
export PATH="/opt/homebrew/bin:/usr/local/bin:$HOME/.local/bin:$HOME/.nvm/versions/node:$HOME/.nix-profile/bin:/etc/profiles/per-user/$USER/bin:/run/current-system/sw/bin:${PATH:-/usr/bin:/bin}"
if ! command -v pnpm >/dev/null 2>&1; then
echo "[build-webview] FATAL: pnpm not found on PATH ($PATH)" >&2
echo "[build-webview] Install: brew install pnpm" >&2
echo "[build-webview] OR npm i -g pnpm" >&2
echo "[build-webview] OR Nix: add 'pkgs.pnpm' to environment.systemPackages / home.packages" >&2
exit 1
fi
cd "$REPO_ROOT/webview"
# Content-hash sentinel: only pnpm install when pnpm-lock.yaml changed.
LOCKFILE_SHA=$(shasum -a 256 pnpm-lock.yaml | cut -d' ' -f1)
STAMP_FILE="node_modules/.jarvis-lock-sha256"
if [ ! -d node_modules ] || [ ! -f "$STAMP_FILE" ] \
|| [ "$(cat "$STAMP_FILE" 2>/dev/null)" != "$LOCKFILE_SHA" ]; then
echo "[build-webview] pnpm install (lockfile changed or fresh tree)..."
pnpm install --frozen-lockfile
echo "$LOCKFILE_SHA" > "$STAMP_FILE"
else
echo "[build-webview] pnpm install skipped (lockfile unchanged)"
fi
echo "[build-webview] building @jarvis/bus..."
pnpm --filter @jarvis/bus build
echo "[build-webview] building @jarvis/hud..."
pnpm --filter @jarvis/hud build
DEST="$REPO_ROOT/App/Resources/webview"
mkdir -p "$DEST"
mkdir -p "$DEST/assets"
# Issue #46: Vite emits content-hashed asset names (e.g. `index-CXPb0I5z.js`),
# so the active bundle filename changes on every dependency or source edit.
# Without explicit cleanup, stale chunks accumulate in `assets/` because we
# don't pass `--delete` to rsync below. Sweep the asset glob (JS + maps + CSS)
# before the rsync drops the fresh bundle. `bus-harness.html`, `index.html`,
# and the directory's `.gitignore` live one level up (in $DEST), not in
# $DEST/assets, so they are not at risk from this rm.
rm -f "$DEST"/assets/*.js "$DEST"/assets/*.js.map "$DEST"/assets/*.css "$DEST"/assets/*.css.map
echo "[build-webview] rsync dist/ -> $DEST"
# --exclude bus-harness.html: keep 02-03's committed copy intact (parity
# script enforces byte-equality between webview/bus-harness.html and
# App/Resources/webview/bus-harness.html).
# --exclude .gitignore: preserve the App/Resources/webview/.gitignore that
# lets index.html stay source-committed while assets/ regenerates.
# We do NOT pass --delete: other vendored assets coexist in this dir.
# (The explicit `rm -f` above handles stale `assets/` chunks; see #46.)
rsync -a \
--exclude=bus-harness.html \
--exclude=.gitignore \
"$REPO_ROOT/webview/packages/hud/dist/" \
"$DEST/"
echo "[build-webview] done — $DEST populated"