MITM configs
The config file each MITM needs, written onto every box in a group.
Installing a MITM is half the job. Aegis, Atlas and GoCheats all read a JSON file next to themselves and do nothing useful until it has the correct parameters.
Youu can fill that file on the device group, in Settings → Device groups → MITM data.
What a group declares
| Field | What it is |
|---|---|
| MITM package | The scanner these boxes run. Also what the MITM column shows. |
| Column header | Shorter name for that column. Defaults to the last dotted segment. |
| Config file path | Where the file goes on the box, eg. /data/local/tmp/aegis_config.json. |
| Config JSON | The file's contents, with placeholders. |
| Install on join | Builds every box joining this group is given, before anybody asks. Empty by default. |
The Fill from buttons put in the real shapes for Aegis, Atlas, GoCheats
and Cosmog, paths and key sets. Aegis (Redroid) and Cosmog (Redroid) are
the same two for a group of containers, with "workers": "{{device.workers}}"
instead of a fixed number, so each container gets the count its machine was
scaled with.
Install on join
A box that has just enrolled is in its group with nothing on it — a container that has only now come up, or hardware somebody has just flashed. Everything else the fleet does assumes the scanner and its MITM are already there, so the first move after every scale-up was a trip to Manual deploy to install the same two builds on the same kind of box again.
Put those builds in the group's Install on join and the box does it itself. A container coming up at four in the morning after a scale-up arrives with the scanner on it.
This is the one control here that installs with nobody watching
It is empty on every group and nothing happens until somebody fills it — the same care the monitoring rules are seeded disabled with. An upgrade that starts installing on its own is the version of this nobody asked for.
What it does, precisely:
- One build per package. Two builds of one package would mean a new box installing one over the other in whichever order the scheduler happened to pick, so the second is refused with the first one named.
- A build, not "the newest". Installing whatever is latest is what a rollout is for, and answering it here would make every new box the first to try a version nobody chose. This answers the narrower question — what does a box need before it is any use — and that is a build somebody picked and has already seen work.
- Cached builds only, because that is what a rollout accepts. One listed by a source and not yet downloaded is refused when you add it, rather than at the one moment nobody is watching.
- Each build is its own rollout, so they appear on Rollouts noted
joined its groupand are followed, retried and cancelled like any other. - One after the other, the MITM last. The builds go in the order they were
added, except the group's MITM package, which always goes last, and each
waits for the one before it to succeed: until then its rollout shows as
pending, after whatever it waits for. The MITM's install is the one that writes its config and starts it, so it wants the game already on the box. - No hooks, but the one that starts the MITM. The game goes in with neither hook: on a new box there is nothing running to stop, and the MITM a post-install hook would start is not installed yet. The MITM's own install runs only the post-install hook, after its config is written.
- A failed game holds the MITM back. It stays
pendingrather than going in without it. Retry on the failed job lets it go once that succeeds, and Start now on the waiting rollout sends it regardless. - Not before the box has settled. Nothing starts until the box has been up
for Settings → Tuning → New boxes settle for (120 s), counted from its
boot. A minute-old Android is still compiling its packages and settling
Magisk, which is a poor moment to push a 170 MB game into. The job says
held 118s while the box settles after booting;0installs on enrolment. - A box that already has one gets nothing for it. The check is what the box
reports installed, not whether it has enrolled before — so a re-enrolment
queues nothing, and a box whose
/datawas wiped gets everything again, which is exactly when it needs to. - Removing a build from the list uninstalls nothing. The boxes that got it keep it; the list only says what the next box gets.
A box that enrolled on a token without auto-approve is skipped, because a rollout cannot target an unapproved box. It gets its builds the moment you approve it.
Putting boxes in a group
One box: the Group select on its device page. Many: pick them on Fleet and press Change group in the bar at the bottom, the same place Rename lives. The dialog says where the selection is now and how many actually move, boxes already in the target group are left alone.
Moving a box changes what it installs, not what is on it: the new group's config, its install hooks and its concurrency cap apply from the next deploy. Nothing is pushed at the moment of the move.
Placeholders
Anything a box has to say about itself is a placeholder, substituted per device before the file is written.
{
"authBearer": "s3cret",
"deviceName": "{{device.name}}",
"rotomUrl": "http://rotom.lan:7072",
"workers": 8
}Available: device.id, device.name, device.serial, device.model,
device.manufacturer, device.androidVersion, device.abi, device.localIp,
device.publicIp, device.rotomOrigin, device.rotomDeviceId,
device.workers, group.name.
device.workers is how many workers a Redroid container is configured for: its
own number, else its machine's, else Settings → Tuning, as set on the
Machines page. It is what makes
a machine's capacity a number the dashboard owns — containers times workers —
rather than one hard-coded into the group's config, where it would be the same
for every machine in the group.
A group that mixes containers and real hardware
Only a container has a worker count, so {{device.workers}} is empty on a TV box — and an empty
known placeholder is refused when the config is rendered, naming the box. That is the refusal
working, and the fix is a group per kind rather than a default nobody chose.
Two things are refused rather than papered over:
- An unknown placeholder.
{{device.nmae}}would otherwise be written through literally, and a scanner started against that is worse off than one never configured. Caught at Save. - A known placeholder with no value on a box. Substituting
""is how a whole site ends up reporting to Rotom under the same blank origin. Caught when the config is rendered for a deploy, naming the box and the field, and logged as a warning on that box's job.
rotomOrigin is empty until Rotom matches the box
So a first deploy on a fresh fleet often refuses it on most boxes. That is the
refusal working. Either use {{device.name}}, which every box has, or deploy
again once the Rotom sync has run.
When it is written
With the install. A rollout of a group's own MITM carries that group's config (if toggled on). The agent writes it after the install verifies and before the post-install hook. A join install is such a rollout, so the MITM in a group's Install on join arrives already configured.
By hand, on one box. The device page's Execute has two buttons built from the box's group:
- Show MITM config —
catof the group's config path, so you see the file as it is on the box right now. - Rewrite MITM config… — the group's config rendered for this box, in an
editor. Write and restart writes it with nothing installed: the box
stops the MITM with the group's pre-install hook, writes the file exactly as
an install does, and starts it again with the post-install hook. A group
without hooks gets
am force-stopand the app's launcher. An edit goes to this box alone; the group keeps its own template.
The restart is the point of the second one, because a running MITM does not
re-read a file it has already read. It needs an agent that knows push_config
(1.0.5 or later); an older one says so instead of offering the button.
When a container's workers change. A Redroid box whose
worker count moves — its own, its
machine's, or the one in Settings — has its config rewritten by the hub, the way
Rewrite config does it, a few boxes at a time. Only a config that says
{{device.workers}} is rewritten; any other is the same file either way.
Saving a group writes to the database and nothing else. An edited config reaches the fleet on the next deploy of that group's MITM (if toggled on), or a box at a time with Rewrite config, and not before.
How it lands
The agent takes the config object off the install job, or off push_config
for a rewrite by hand, and:
- Writes to a temp file and renames it into place, so a scanner reading the file while it is replaced sees the old bytes or the new ones, never a half-written middle.
- Reads the file back and reports its sha256. That answers "what is on the box", where hashing what the hub sent would only answer "what did the hub mean".
A config that cannot be written fails the job, rather than leaving a scanner running on someone else's settings. The downloaded bundle is kept, so the retry costs an attempt and not a second download.
The config holds credentials
authBearer, deviceAuthToken, an email address. It is never written to the hub's log, never
into an audit entry.
Lineage
The paths and the per-box name substitution are both aconf's, which has been doing this on the same hardware for years. Credits to @TechG3n for the original idea.