Skip to content

Review plan: LavaMoat stack (#1642, #1646, #1652) and ADR zingo-mobile/0021 #1653

Open

Description

@juanky201271

Review plan for the LavaMoat stack (#1641). Three PRs stacked on feat/lavamoat, each based on the previous one, plus one ADR. Review in this order; each PR's diff shows only its own changes.

1. #1642 — allow-scripts

What to look at:

  • .yarnrc (ignore-scripts true), .yarnrc.yml, package.json (setup script, lavamoat.allowScripts, two dev deps), .depcheckrc.yml.
  • The 16 CI install steps now run yarn setup. Check none was missed: grep -rn "run: yarn$" .github/workflows should return nothing.
  • The allowlist is all false. The claim to verify: esbuild, unrs-resolver and @parcel/watcher work without their install scripts because the binaries arrive as optional deps. Reproduce: rm -rf node_modules && yarn setup && yarn tsx --version.

Decision for the reviewer: keep or drop .yarnrc.yml. It only matters for Yarn 2+, which the repo pins out with packageManager.

2. #1646 — SES lockdown

What to look at:

  • metro.config.js: lockdownSerializer as serializer, with RN's default getPolyfills. withStorybook does not touch the serializer.
  • babel.config.js: the ignore pattern accepts \ as well as /; the README's pattern does not match on Windows.
  • The lockdown options are the package's and not configurable (node_modules/@lavamoat/react-native-lockdown/src/repair.js): console and error taming off. Confirm the release console.log silencing in index.js (Audit Issue K) is unaffected.

What a failure looks like: TypeError: Cannot assign to read only property … at startup, naming the module.

3. #1652 — pinned host globals

What to look at:

  • app/utils/pinGlobals.ts: the 21 names against react-native/Libraries/Core/setUpXHR.js and setUpTimers.js. Bindings only, prototypes untouched, on purpose.
  • app/hardenRuntime.ts is the first import of index.js.
  • react-native-worklets reassigns timers inside executeOnUIRuntimeSync, on the UI runtime. Confirm that reading node_modules/react-native-worklets/src/initializers.ts around line 246.
  • __tests__/pinGlobals.unit.ts. Note: the RN Babel preset emits sloppy-mode modules, so a reassignment is ignored, not thrown.

What a failure looks like: Cannot redefine property: <name> or RN's Failed to set polyfill. <name> is not configurable.

4. ADR

zingolabs/zingo-adrs#44, zingo-mobile/0021. One decision, three rules, with what it does not cover. Review it against the three PRs; the submodule pointer in zingo-mobile moves after it lands.

Evidence so far

  • Full CI green on the three PRs, including andr-ubu-integra-test-ci / offline device tests (the app runs on an Android emulator with lockdown and the pinned globals) and ios-integration-test / build-for-testing.
  • Maestro flows dispatched on lavamoat/3-pin-globals: https://github.com/zingolabs/zingo-mobile/actions/runs/38935961419
  • Release bundle built offline and compiled with hermesc -O; SES shim first, hardenIntrinsics();__r(0) after InitializeCore.
  • Not done: a debug or release build on a physical device, iOS at runtime, the visual and gesture paths (bottom sheets, QR scanner, gestures).

Device run, if the reviewer has one

Build lavamoat/3-pin-globals in debug. Cold boot, then bottom sheets, gestures, the QR scanner, toasts, charts. Any lockdown failure is at startup and names the culprit.

Merge order

#1642 → #1646 → #1652, then feat/lavamoat → dev.

🤖 Generated with Claude Code

Activity

  1. added
    documentationImprovements or additions to documentation
    dependenciesPull requests that update a dependency file
    on Oct 16, 2026
  2. juanky201271 commented on Oct 16, 2026

    @juanky201271
    ContributorAuthor

    Device run, 2026-10-16: lavamoat/3-pin-globals at f7ca6e417 (rebased on dev, zingolib stable v7.0.0), Android debug build from Android Studio on a physical device. Cold boot and normal use, nothing odd. No lockdown or pinned-global failure at startup.

    Still open: iOS at runtime, release build.

  3. juanky201271 commented on Oct 16, 2026

    @juanky201271
    ContributorAuthor

    Device run, 2026-10-16: same branch and tip (f7ca6e417), iOS debug build on a physical device. Nothing odd.

    Still open: release build on a device. Note that the Maestro Android job installs the prod release APK, so the Maestro runs cover release on the emulator.

  4. juanky201271 commented on Oct 16, 2026

    @juanky201271
    ContributorAuthor

    Maestro on the rebased tip f7ca6e417: https://github.com/zingolabs/zingo-mobile/actions/runs/38946975410 (Android installs the prod release APK).

    flow dev nightly 2026-10-16 (run 38843445039) lavamoat/3-pin-globals
    Android 01–03, 05–08 pass pass
    Android 04_address_book fail (addressbook.button.new) fail, same
    iOS 01–03, 05, 07, 08 pass pass
    iOS 04_address_book fail (addressbook.button.new) fail, same
    iOS 06_custom_server fail (keyboard) fail, same

    Identical to dev. Logcat of the branch run: no FATAL EXCEPTION, no app death, no lockdown signature (read only property, Cannot redefine, Failed to set polyfill).

    An earlier dispatch on the pre-rebase tip (run 38935961419, base 25 commits behind dev) had three extra failures. For the record: Android 01 died with a Fabric addViewAt: failed to insert view … IndexOutOfBoundsException index=4 count=3 in release 57 s after launch; Android 06 missed server.custom.log.final.ok (the server fixes in dev were missing from that base); iOS 05 typed into an unfocused field (the YAML already notes the simulator flake). None reproduced on the rebased tip.

  5. juanky201271 commented on Oct 20, 2026

    @juanky201271
    ContributorAuthor

    Stack rebased onto dev ba7f43064 (2026-10-20): feat/lavamoat = dev, heads 90e317c5d (#1642), be07a3c83 (#1646), 5a1368d34 (#1652). Conflicts were only package.json/yarn.lock (dependency bumps on dev); resolved by taking dev's files and re-adding the LavaMoat entries, lockfile regenerated, allowlist regenerated (unchanged). Verified again on the new base: frozen install + patch, typecheck, pinGlobals test, prettier, depcheck, offline release bundle (SES first, hardenIntrinsics();__r(0), pinGlobals wired) compiled by hermesc -O. CI re-running.

    The earlier "failed" checks on the three PRs were cancelled runs, not failures.

  6. juanky201271 commented on Nov 2, 2026

    @juanky201271
    ContributorAuthor

    Re-evaluation against dev 5fd3662f3 (zingo 3.0.0), 2026-11-02. dev merged down the stack (no force push): feat/lavamoat = dev, heads e620b5d96 (#1642), 4b61a52f6 (#1646), 5c8ccf218 (#1652). No conflicts.

    What changed on dev since the stack was written, as far as these PRs care:

    • No new runtime dependency. FontAwesome (4 packages) and @react-navigation/stack left; zingolib-bundle-pin arrived as a dev dependency, with no install script. The allowlist is unchanged (allow-scripts auto: nothing to add).
    • React Native stays 0.81.6 on Hermes, so @lavamoat/react-native-lockdown 3.0.0 still applies; the Static Hermes question only arrives with 0.82.
    • index.js, metro.config.js, babel.config.js, jest.config.js: untouched by dev; the only diffs are the stack's own.
    • No new polyfill or global.X = in app code. Rescan of every runtime dependency for intrinsic patching or reassignment of a pinned global: nothing new (js-base64 opt-in, recyclerlistview and react-native-svg's PEG parser patch their own classes).
    • postinstall is now patch-package && node scripts/generate-swapkit-secrets.js; it runs through allow-scripts as the root script, verified.
    • Every install step in the workflows is yarn setup (17 of them on dev, none left as plain yarn).

    Verified on the merged tip: yarn setup from a clean tree (patch applied, lockdown resolvable), typecheck, pinGlobals test, prettier:check, depcheck, lint:check (0 errors), offline release bundle (SES first and untransformed, hardenIntrinsics();__r(0), pinGlobals wired) compiled by hermesc -O.

    The red checks visible since 2026-10-26 were cancelled runs (two pushes a minute apart), not failures; CI is running again on the new heads.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    dependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions