@pranavp311 tracking this from PR #100 so the remaining production work has one place to live.
PR #100 already works locally for the macOS shell. We verified:
zig build test
zig build cli
zig build native-build -Doptimize=ReleaseSmall
zig build package -Doptimize=ReleaseSmall
- launching
zig-out/MerJS.app
- app window appears as
MerJS
- embedded localhost server responds with
200 OK
This issue is for making mer native production-ready, cross-platform, and testable.
Scope
1. macOS code signing
Current integration points:
build.zig, native package step around the .app bundle creation
cli.zig, cmdPackage
mer.app.zon / src/native/manifest.zig
Requested work:
- add signing config to
mer.app.zon
- support a signing identity / team id / entitlements file
- add a build or CLI path for signing the generated
.app
- likely command shape:
mer package --sign
zig build package-sign
Acceptance tests:
- unsigned package still works by default
- signed package is produced when signing config is present
codesign --verify --deep --strict zig-out/<App>.app passes
- generated
Info.plist remains valid after signing
2. macOS notarization
Current integration points:
build.zig package step
cli.zig package command
Requested work:
- add notarization config to manifest or env-based CLI config
- support
xcrun notarytool submit ... --wait
- support
xcrun stapler staple zig-out/<App>.app
- document expected Apple credentials / keychain profile setup
Acceptance tests:
- notarization can be skipped in local dev
- notarization command fails clearly if credentials are missing
- notarized app has a stapled ticket
spctl --assess --type execute --verbose zig-out/<App>.app passes when configured
3. auto-updater
Current integration points:
src/native/manifest.zig
src/native/bridge.zig
cli.zig package/build metadata
Requested work:
- add update metadata to
mer.app.zon
- support signed update manifests/artifacts
- support checking current version against a feed
- optionally expose update commands through
window.mer.invoke
Possible manifest shape:
.update = .{
.provider = "github-releases",
.feed_url = "https://example.com/mer-native/update.json",
.public_key = "...",
}
Acceptance tests:
- update check returns
no update when current version is latest
- update check returns metadata when a newer version exists
- invalid signature is rejected
- downgrade / rollback is rejected
- malformed feed is rejected without crashing
4. full Linux support
Current state:
src/native/shell.zig returns UnsupportedPlatform for non-macOS
- current backend is
src/native/macos.zig
- current command backend is
src/native/macos_commands.zig
Requested work:
- add
src/native/linux.zig using WebKitGTK
- add
src/native/linux_commands.zig
- add Linux build/link logic in
build.zig
- update generated
native_build_snippet in cli.zig
- document Linux package dependencies
Acceptance tests:
zig build native-build succeeds on Linux with documented deps
- native window opens on Linux
window.mer.invoke("mer.ping", {}) works on Linux
- clipboard/dialog/open/window commands either work or fail with clear unsupported errors
5. full Windows support
Current state:
- no Windows WebView backend yet
Requested work:
- add
src/native/windows.zig using WebView2
- add
src/native/windows_commands.zig
- add Windows build/link logic in
build.zig
- update generated
native_build_snippet in cli.zig
- document WebView2 runtime requirements
Acceptance tests:
- native binary builds on Windows
- native window opens on Windows
window.mer.invoke("mer.ping", {}) works on Windows
- installer/package path is documented, even if full installer support is deferred
6. hardened permission model
Current state:
src/native/bridge.zig has size limit, command registry, permission checks, malformed JSON handling
src/native/macos.zig checks frame origin before dispatch
src/native/manifest.zig has global permissions and global allowed origins
Requested work:
- add per-command permission allowlists
- add per-command origin allowlists
- deny or intercept WebView navigation to non-allowed origins
- add argument schemas per command
- restrict
open.path and open.external
- consider user prompts for clipboard/filesystem/open permissions
Acceptance tests:
- command without permission is denied
- command with broad permission but wrong origin is denied
- hostile iframe cannot call privileged native commands
- oversized payload is denied
- embedded NUL payload is denied
- malformed JSON is denied
- unknown command is denied
open.external rejects disallowed schemes like javascript: and unexpected local file URLs
open.path rejects paths outside allowed roots when roots are configured
7. mature plugin system
Current state:
- command registry is static in
src/native/bridge.zig
- app-level custom command registries are deferred
Requested work:
- define plugin API exported from
src/native/mer.zig
- support app-provided command registries at comptime
- let plugins declare permissions and capabilities
- let manifest enable/disable plugin commands
- add docs and an example plugin
Acceptance tests:
- app can register a custom native command
- plugin command is denied unless enabled in manifest
- plugin command permission is enforced
- plugin command appears in generated docs/debug output if applicable
8. production security audit
Requested deliverable:
- add
docs/native-security.md or similar
- threat model the native shell, loopback server, WebView, bridge, updater, and packaging
- document what is production-ready and what is still experimental
Audit checklist:
- WKWebView navigation policy
- bridge message origin validation
- JSON parsing and schema validation
- file/path/url handling
- update signing and rollback prevention
- macOS entitlements and sandbox assumptions
- CSP interaction with injected
window.mer shim
- local loopback server exposure
- logging of sensitive data
Required test matrix
At minimum, please add or document these checks:
zig build test
zig build cli
zig build native-build -Doptimize=ReleaseSmall
zig build package -Doptimize=ReleaseSmall
Manual macOS smoke test:
Expected:
- app window opens
- embedded server listens on
127.0.0.1:<ephemeral port>
- root route loads with HTTP 200
- closing the final window exits the app
Bridge smoke test:
- create a small page or test fixture that calls:
const result = await window.mer.invoke("mer.ping", {});
Expected:
Security smoke tests:
- unknown command returns an error
- missing permission returns
PermissionDenied
- bad origin returns
OriginNotAllowed
- oversized payload returns
PayloadTooLarge
- malformed JSON returns
ParseError
Cleanup requested from PR #100 before merge
- remove
harness.trajectory.jsonl
- avoid zeroing/changing
codedb.snapshot unless intentional
- rebase or retarget onto
main so the diff contains only native work
The core feature is strong. This issue is the checklist for making it production-grade.
@pranavp311 tracking this from PR #100 so the remaining production work has one place to live.
PR #100 already works locally for the macOS shell. We verified:
zig build testzig build clizig build native-build -Doptimize=ReleaseSmallzig build package -Doptimize=ReleaseSmallzig-out/MerJS.appMerJS200 OKThis issue is for making
mer nativeproduction-ready, cross-platform, and testable.Scope
1. macOS code signing
Current integration points:
build.zig, native package step around the.appbundle creationcli.zig,cmdPackagemer.app.zon/src/native/manifest.zigRequested work:
mer.app.zon.appAcceptance tests:
codesign --verify --deep --strict zig-out/<App>.apppassesInfo.plistremains valid after signing2. macOS notarization
Current integration points:
build.zigpackage stepcli.zigpackage commandRequested work:
xcrun notarytool submit ... --waitxcrun stapler staple zig-out/<App>.appAcceptance tests:
spctl --assess --type execute --verbose zig-out/<App>.apppasses when configured3. auto-updater
Current integration points:
src/native/manifest.zigsrc/native/bridge.zigcli.zigpackage/build metadataRequested work:
mer.app.zonwindow.mer.invokePossible manifest shape:
Acceptance tests:
no updatewhen current version is latest4. full Linux support
Current state:
src/native/shell.zigreturnsUnsupportedPlatformfor non-macOSsrc/native/macos.zigsrc/native/macos_commands.zigRequested work:
src/native/linux.zigusing WebKitGTKsrc/native/linux_commands.zigbuild.zignative_build_snippetincli.zigAcceptance tests:
zig build native-buildsucceeds on Linux with documented depswindow.mer.invoke("mer.ping", {})works on Linux5. full Windows support
Current state:
Requested work:
src/native/windows.zigusing WebView2src/native/windows_commands.zigbuild.zignative_build_snippetincli.zigAcceptance tests:
window.mer.invoke("mer.ping", {})works on Windows6. hardened permission model
Current state:
src/native/bridge.zighas size limit, command registry, permission checks, malformed JSON handlingsrc/native/macos.zigchecks frame origin before dispatchsrc/native/manifest.zighas global permissions and global allowed originsRequested work:
open.pathandopen.externalAcceptance tests:
open.externalrejects disallowed schemes likejavascript:and unexpected local file URLsopen.pathrejects paths outside allowed roots when roots are configured7. mature plugin system
Current state:
src/native/bridge.zigRequested work:
src/native/mer.zigAcceptance tests:
8. production security audit
Requested deliverable:
docs/native-security.mdor similarAudit checklist:
window.mershimRequired test matrix
At minimum, please add or document these checks:
zig build test zig build cli zig build native-build -Doptimize=ReleaseSmall zig build package -Doptimize=ReleaseSmallManual macOS smoke test:
Expected:
127.0.0.1:<ephemeral port>Bridge smoke test:
Expected:
{ "pong": true }Security smoke tests:
PermissionDeniedOriginNotAllowedPayloadTooLargeParseErrorCleanup requested from PR #100 before merge
harness.trajectory.jsonlcodedb.snapshotunless intentionalmainso the diff contains only native workThe core feature is strong. This issue is the checklist for making it production-grade.