Repository navigation
0.7.7
Security
-
Every platform uses a private distribution cookie per app;
mob_secret
is only a fallback for old apps (MOB-49). The Mac-side node and every
development app used the public cookiemob_secret, so anyone who could
reach a dist port could run code on the phone or the Mac. mob_dev now keeps
a random 256-bit cookie per app in~/.mob/dist_cookies/(owner-only) and
hands it over at deploy/connect time: iOS in the launch environment, Android
as a file in the app's private storage (sent over adb's stdin, never on a
command line). An app built against a mob from before MOB-49 still answers
only tomob_secret;mob.connect,mob.deploy,mob.push,mob.watch,
mob.attest,mob.smoke,mob.trace_otpand the battery benches fall back
to it with a warning.mob.deployrestarts such an app instead of
hot-loading it, so updatingmoband deploying (--nativefor iOS) moves
it to the private cookie.--cookienow means "only this cookie". To attach
by hand, load the cookie inside the VM
(Node.set_cookie(MobDev.DistCookie.for_project!())) rather than passing
it as--cookie, which would put it in the process arguments. See
decisions/2026-09-30-private-dist-cookie-for-every-platform.md.Upgrade note: update mob_dev together with mob. mob 0.9.8 accepts only
the private cookie this release hands over, so mob_dev 0.7.6 or older can't
mix mob.connect(or deploy, push, watch) to an app built on mob 0.9.8.
mob_dev 0.7.7 still reaches apps built on older mob through the
mob_secretfallback; the firstmix mob.deployafter updating mob
(--nativefor iOS) moves the app to its private cookie.
Fixed
- Tasks that pick devices on their own leave another agent's leased
device alone (MOB-330). A baremix mob.deployinstalled and launched an
app on an emulator another agent held throughagent-device. When
agent-deviceis on PATH, every selection the user did not name now skips
devices another session has claimed (read fromagent-device device status --json) and prints each one with the session holding it: single-device
auto-selection and--all-devices/--all-physicalinmix mob.deploy,
mix mob.uninstallandmix mob.smoke,mix mob.connectwithout
--device,mix mob.push/mix mob.watch, and the battery benches'
device auto-detection.mix mob.connectalso leaves the app running on a
claimed simulator when it kills stale simulator apps, andmix mob.watch
stops pushing to a device another session claims while it runs. An iPhone
found only over the LAN is known by its IP while a claim names a UDID, so
it is skipped whenever another session claims a device that could be an
iPhone; name it with--deviceto use it. A claim is yours when its
session equalsAGENT_DEVICE_SESSION; with that unset, every claim is
someone else's. A claimed device named with--deviceis still used, after
a loud warning: naming it is the same consent--devicegives for a phone.
The device auto-selection picks is always printed. Withoutagent-device,
selection is unchanged. SeeMobDev.DeviceLeases. mix mob.pluginssays when a plugin's signature doesn't verify (MOB-332).
Such a plugin was listed astier 0 … no manifest (regular dep)after a
separateskipping <name>: invalid_signatureline, or not at all when not
activated. Its row now showstier ?, what is wrong (not signed, invalid,
no public key, legacy v1) and the fix: re-sign a local checkout, reinstall,
ask the author, or acknowledge an unsigned plugin for development.mix mob.plugin.trustwrites one trusted plugin per line and shows a path
dependency's real version (MOB-334).config :mob, :trusted_pluginswas
rewritten as one long line; it is now laid out asmix formatwould, sorted
by name, so a trust change is a one-line diff. An existing one-line stanza
is converted in place. The review showedversion: (unset)for a path
dependency; it now shows the version from the plugin'smix.exs(read, not
evaluated) and the dependency's path.mix mob.deploy's documentation matches what it does (MOB-333). The
fast deploy hot-loads over Erlang distribution without a restart and only
restarts when it has to write the BEAMs to the device;--dist-port
defaults to the port derived from the device serial and app name, not
9100 + index; the "Under the hood" commands are the ones the task runs.- The crypto shim no longer breaks concurrent deploys and test runs
(MOB-339).Deployer.generate_crypto_shimwrote one shared
$TMPDIR/mob_crypto_shimin place, so two runs on one machine could delete
or truncate each other'scrypto.beammid-compile ("error writing file").
It now compiles in a private staging directory and renames it into a
directory named for the shim's content. Tests that timed out only under
machine load wait on their work instead of a 5 s clock, or carry an
explicit timeout for legitimately heavy work. mix mob.smokeexplains why a flow recorded on an iOS simulator fails
its identity check (MOB-343). Such flows failed at their first tap with
REPLAY_DIVERGENCE … nothing in the current tree carries the recorded identity. agent-device (seen on 0.21.1 and 0.21.19) records each step's
identity (the# agent-device:target-v1line) from its simulator
accessibility bridge, but replay checks it against an XCTest snapshot. Inside
a SwiftUIScrollView, XCTest labels the content container with its first
child's text and keeps it, so the recorded ancestry (scrollview) never
matches the replayed one (other "☀️"). A plain SwiftUI app fails the same
way, so it is not a mob bug. On an iOS simulator, anIDENTITY_MISMATCH
failure now carries a hint with thesedcommand that deletes the flow's
identity lines; replay then resolves the step by its selector. The README
("Smoke flows on devices") says to strip them after recording on a
simulator.