mix precompiled.bundle (precompiled v0.2.1)

Copy Markdown View Source

Writes a bundle a device installs from with no network: Precompiled.install(:recon, source: "file:///media/usb/precompiled"). It plans on this host exactly as the device would, from the device's facts, and copies only what that plan needs.

mix precompiled.bundle PKG[@REQ]... --out DIR (--system NAME@VSN | --pure) \
  --otp N --elixir V [--cpu C] [--source URL] [--root FILE]
mix precompiled.bundle PKG[@REQ]... --out DIR --device-report FILE \
  [--source URL] [--root FILE]

DIR (new, or empty) gets the API's own layout:

  • root.json - the root the batch verified under: the source's served root when it chains from the trusted one, else the trusted root itself (--root, or the root this library ships);
  • batch.json - the signed batch, byte for byte as verified;
  • v2/manifests/<pkg>.json - for each planned package, the exact bytes the batch's hash names (manifests/<pkg>.json for a format-1 one);
  • files/<sha256> - every file of every planned build.

Every byte is checked against its signed hash before it is written, and the bundle appears in DIR only once all of it has been. No key, and nothing that is not in the plan, is ever written.

The device facts come from the flags: --system (or --pure for a device with no Nerves system, which takes pure_elixir builds only), --otp, --elixir and --cpu (default aarch64-unknown-linux-gnu), with kernel, stdlib, elixir, logger and crypto present. Or they come from --device-report FILE, the JSON that Precompiled.install(..., dry_run: true, report: path) writes on the device: its system, OTP, Elixir, CPU and present apps, so the bundle holds what that device would fetch. With it, --system, --pure, --otp, --elixir and --cpu are ignored. Apps the device has, by name and exact version, are not bundled. The device checks everything again when it installs.

--source is the API root (default the official one) and --root the trust anchor (default the shipped root.json).

A bundle's batch.json expires 24 hours after it was issued. For a device that stays offline longer, the holder of the root's offline key signs the bundle with mix portal.precompiled.sign_offline, within a day of the batch's issue, passing the current production root.json as --root: the bundle's root.json must be that root.