Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
1d0b4b2
build: define cross-platform backend artifact names
Rajioba1 Jul 30, 2026
acfc4f6
build: compile analysis backends for darwin
Rajioba1 Jul 30, 2026
ce03575
fix: harden darwin backend compile verification
Rajioba1 Jul 30, 2026
d470b75
fix: validate darwin compile prerequisites
Rajioba1 Jul 30, 2026
72fca16
build: stage and validate darwin runtime artifacts
Rajioba1 Jul 30, 2026
2278c26
fix: harden darwin runtime validation
Rajioba1 Jul 30, 2026
1dc0579
fix: resolve analysis backends on macos
Rajioba1 Jul 30, 2026
6ecf0a0
ci: add fast macos quality gates
Rajioba1 Jul 30, 2026
4dc9a2d
fix: name Darwin Nuitka launchers
Rajioba1 Jul 30, 2026
5c6994d
fix: harden Darwin release validation
Rajioba1 Jul 31, 2026
f1ca578
chore: disclose Darwin certifi license
Rajioba1 Jul 31, 2026
68c4f10
fix: make license sync check cross-platform
Rajioba1 Jul 31, 2026
b647bff
fix: preserve PowerShell license gate parity
Rajioba1 Jul 31, 2026
74c0c43
fix: allow cold compiled backend startup
Rajioba1 Jul 31, 2026
5e2451a
fix: enforce the Darwin runtime support floor
Rajioba1 Jul 31, 2026
d93d95b
fix: support framework Python on macOS
Rajioba1 Jul 31, 2026
c216917
build: define bundled macos runtime layout
Rajioba1 Aug 1, 2026
e479633
build: provision bundled python on macos
Rajioba1 Aug 1, 2026
bdeea48
fix: harden bundled python provisioning
Rajioba1 Aug 1, 2026
119b866
fix: close bundled python review gaps
Rajioba1 Aug 1, 2026
8fb8530
build: stage and validate bundled macos python
Rajioba1 Aug 2, 2026
610b3b1
fix: require bundled python in macos releases
Rajioba1 Aug 2, 2026
36263e4
ci: pair Apple Silicon with macos-15 and cover bundled mode
Rajioba1 Aug 2, 2026
4711ada
build: standardize on Node.js 24
Rajioba1 Aug 2, 2026
2cc15d1
ci: prove bundled macos runtime on both architectures
Rajioba1 Aug 2, 2026
4fc3cbf
fix: make protected macos validation buildable
Rajioba1 Aug 2, 2026
edb2ed3
fix: export APP_PATH for same-step macos signing
Rajioba1 Aug 2, 2026
99f3691
fix: fail closed bundled macos runtime resolution
Rajioba1 Aug 3, 2026
278f11f
fix: correct macos validation closeout
Rajioba1 Aug 3, 2026
cdff749
fix: test macos validation dispatch boundary
Rajioba1 Aug 3, 2026
b64b28b
fix: bound AppShell grid stability setup timeout
Rajioba1 Aug 3, 2026
f053d5d
fix: distinguish local runtime paths from wheel provenance
Rajioba1 Aug 3, 2026
15f1f80
ci: bound protected macos build heap
Rajioba1 Aug 3, 2026
ff6d7bb
fix: preserve runtime digest through macos packaging
Rajioba1 Aug 3, 2026
7ec6fb1
test: await spreadsheet selection readiness
Rajioba1 Aug 3, 2026
4127cde
test: bound AppShell setup hooks
Rajioba1 Aug 3, 2026
cc1475c
fix: align provisioned runtime digest
Rajioba1 Aug 3, 2026
de9de31
build: harden macos runtime reproducibility
Rajioba1 Aug 3, 2026
b4dff3b
fix: prevent bundled python bytecode writes
Rajioba1 Aug 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 91 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "20"
node-version: "24"
cache: npm

- name: Setup Python
Expand All @@ -41,6 +41,9 @@ jobs:
- name: Install JS dependencies
run: npm ci --legacy-peer-deps --no-audit --no-fund

- name: Launch clean-installed Tauri CLI
run: npm exec -- tauri --version

- name: Bootstrap Python runtime
shell: pwsh
run: ./scripts/bootstrap-python.ps1
Expand Down Expand Up @@ -79,3 +82,90 @@ jobs:
$matches | ForEach-Object { Write-Host "FORBIDDEN: $_" }
throw "Forbidden tracked paths detected in CI"
}

macos-quality-gates:
name: macos-community-quality-gates (${{ matrix.suffix }})
strategy:
fail-fast: false
matrix:
include:
- runner: macos-15-intel
rust_target: x86_64-apple-darwin
suffix: x86_64
- runner: macos-15
rust_target: aarch64-apple-darwin
suffix: aarch64
runs-on: ${{ matrix.runner }}
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
fetch-depth: 1
lfs: false

- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: "24"
cache: npm

- name: Setup Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: "3.12"

- name: Setup Rust
uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7
with:
targets: ${{ matrix.rust_target }}

- name: Install JS dependencies
run: npm ci --legacy-peer-deps --no-audit --no-fund

- name: Launch clean-installed Tauri CLI
run: npm exec -- tauri --version

- name: Typecheck
run: npm run -s typecheck

- name: Run frontend tests
run: npm run -s test:run

- name: Build frontend
env:
NODE_OPTIONS: --max-old-space-size=4096
run: npm run -s build

- name: Runtime naming tests
run: npm run -s test:runtime-platform

- name: Darwin provisioner unit tests
run: npm run -s test:python-runtime:macos

- name: Compiler helper tests
run: npm run -s test:compile-python

- name: Staging and validation contract tests
run: node --test scripts/runtime-artifact-layout.test.mjs scripts/validate-release.test.mjs

- name: Third-party license synchronization
run: |
npm run -s license:check-sync
node --test scripts/check-third-party-license-sync.test.mjs

- name: CI workflow privacy contract
run: node --test scripts/ci-workflow-contract.test.mjs

- name: Focused macOS backend path tests
run: |
cargo test --manifest-path src-tauri/Cargo.toml compiled_backend_names_follow_platform
cargo test --manifest-path src-tauri/Cargo.toml venv_python_paths_follow_platform
cargo test --manifest-path src-tauri/Cargo.toml macos_bundle_python_base_dir_candidate_uses_updater_resources
cargo test --manifest-path src-tauri/Cargo.toml bundled_runtime
cargo test --manifest-path src-tauri/Cargo.toml backend_mode
cargo test --manifest-path src-tauri/Cargo.toml choose_backend_mode

- name: Rust check
run: cargo check --manifest-path src-tauri/Cargo.toml
218 changes: 218 additions & 0 deletions .github/workflows/macos-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
name: macOS Runtime Validation

# Protected dual-architecture proof for M1 closeout candidates.
# Does not publish releases or mutate the public updater channel.
on:
push:
branches:
- "validation/macos/**"
- "validation/ci/**"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: macos-validation-${{ github.ref }}
cancel-in-progress: true

jobs:
bundled-runtime-proof:
name: bundled-runtime (${{ matrix.suffix }})
strategy:
fail-fast: false
matrix:
include:
- runner: macos-15-intel
rust_target: x86_64-apple-darwin
arch: x86_64
suffix: x86_64
- runner: macos-15
rust_target: aarch64-apple-darwin
arch: arm64
suffix: aarch64
runs-on: ${{ matrix.runner }}
timeout-minutes: 360
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 1
lfs: false

- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "24"
cache: npm

- name: Setup host Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"

- name: Setup Rust
uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable
with:
targets: ${{ matrix.rust_target }}

- name: Reject private path leaks
run: |
set -euo pipefail
if git ls-files | grep -E '^(e2e/|_documentation/|_test_data/|_test_validation/|docs/plans/)'; then
echo "Private paths must not be tracked"
exit 1
fi

- name: Install JS dependencies
run: npm ci --legacy-peer-deps --no-audit --no-fund

- name: Typecheck and public unit contracts
run: |
set -euo pipefail
npm run -s typecheck
npm run -s test:runtime-platform
npm run -s test:python-runtime:macos
node --test scripts/runtime-artifact-layout.test.mjs scripts/validate-release.test.mjs
node --test scripts/macos-validation-contract.test.mjs scripts/ci-workflow-contract.test.mjs scripts/node-toolchain-contract.test.mjs
cargo test --manifest-path src-tauri/Cargo.toml bundled_runtime
cargo test --manifest-path src-tauri/Cargo.toml backend_mode

- name: Provision pinned Darwin runtime
env:
EASYCRIS_PROTECTED_VALIDATION: "1"
run: npm run -s provision-python:macos

- name: Stage and validate Darwin runtime
run: |
set -euo pipefail
node scripts/stage_python_runtime.mjs --platform darwin
node scripts/validate_release.js --platform darwin --community

- name: Public GSEApy dependency smoke (staged runtime)
run: |
set -euo pipefail
node scripts/gseapy-dependency-smoke.mjs \
--python bundle_resources/python_embedded/runtime/bin/python3.12

- name: Build unsigned macOS app bundle
env:
CI: "true"
NODE_OPTIONS: --max-old-space-size=4096
run: |
set -euo pipefail
npm run -s build
# Keep the bundle unsigned until its installed runtime and manifests pass validation.
npm exec -- tauri build \
--no-sign \
--bundles app \
--target "${{ matrix.rust_target }}" \
--config src-tauri/tauri.validation.macos.conf.json

- name: Validate unsigned installed runtime and manifests
run: |
set -euo pipefail
APP="src-tauri/target/${{ matrix.rust_target }}/release/bundle/macos/easyCris.app"
if [[ ! -d "$APP" ]]; then
APP="src-tauri/target/release/bundle/macos/easyCris.app"
fi
test -d "$APP"
export APP_PATH="$APP"
echo "APP_PATH=$APP" >> "$GITHUB_ENV"
node scripts/validate_release.js \
--platform darwin \
--community \
--installed-app "$APP_PATH"

- name: Sign nested runtime inside-out (ad-hoc hardened)
run: |
set -euo pipefail
APP="src-tauri/target/${{ matrix.rust_target }}/release/bundle/macos/easyCris.app"
if [[ ! -d "$APP" ]]; then
APP="src-tauri/target/release/bundle/macos/easyCris.app"
fi
test -d "$APP"
# Same-step consumers need a real shell/process env; GITHUB_ENV only applies to later steps.
export APP_PATH="$APP"
echo "APP_PATH=$APP" >> "$GITHUB_ENV"

# Enumerate nested Mach-O payloads under the app and sign deepest paths first.
# Pass the path as argv so the quoted heredoc cannot depend on delayed GITHUB_ENV.
python3 - "$APP_PATH" <<'PY'
import subprocess, sys
from pathlib import Path

app = Path(sys.argv[1])
if not app.is_dir():
raise SystemExit(f"app bundle missing: {app}")
roots = [
app / "Contents" / "Resources",
app / "Contents" / "MacOS",
app / "Contents" / "Frameworks",
]
candidates = []
for root in roots:
if not root.exists():
continue
for path in root.rglob("*"):
if not path.is_file():
continue
try:
with path.open("rb") as handle:
head = handle.read(4)
except OSError:
continue
magic = head.hex()
if magic not in {
"feedface", "cefaedfe", "feedfacf", "cffaedfe",
"cafebabe", "bebafeca", "cafebabf", "bfbafeca",
}:
continue
candidates.append(path)

candidates.sort(key=lambda p: (-len(p.parts), str(p)))
for path in candidates:
cmd = [
"codesign", "--force", "--timestamp=none",
"--options", "runtime", "--sign", "-",
str(path),
]
print("signing", path.relative_to(app))
subprocess.run(cmd, check=True)

app_cmd = [
"codesign", "--force", "--timestamp=none",
"--options", "runtime", "--sign", "-",
str(app),
]
print("signing app", app)
subprocess.run(app_cmd, check=True)
PY

codesign --verify --deep --strict --verbose=2 "$APP_PATH"

- name: Run signed installed execution probes
run: |
set -euo pipefail
node scripts/validate_release.js \
--platform darwin \
--community \
--post-sign-installed-execution \
--installed-app "$APP_PATH"
INSTALLED_PYTHON="$APP_PATH/Contents/Resources/_up_/bundle_resources/python_embedded/runtime/bin/python3.12"
if [[ ! -x "$INSTALLED_PYTHON" ]]; then
INSTALLED_PYTHON="$APP_PATH/Contents/Resources/python_embedded/runtime/bin/python3.12"
fi
test -x "$INSTALLED_PYTHON"
node scripts/gseapy-dependency-smoke.mjs --python "$INSTALLED_PYTHON"

- name: Upload sanitized validation summary
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: macos-runtime-proof-${{ matrix.suffix }}
path: |
python_embedded/runtime/easycris_runtime_manifest.json
bundle_resources/python_embedded/runtime/easycris_runtime_manifest.json
if-no-files-found: warn
retention-days: 7
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
name: build-and-publish-windows
runs-on: windows-latest
env:
NODE_VERSION: "20"
NODE_VERSION: "24"
PYTHON_VERSION: "3.12"
steps:
- name: Enable Git long paths
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ e2e/fixtures/ole/portability_project/
# Hermes — contains real VPS IP, kept local only
docs/SSH-QUICKSTART.md
_tmp
.venv-macos-build/

# Local deployment notes with environment/resource IDs
easycris-remote-signaling/DEPLOYMENT.local.md
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24
Loading
Loading