Dala.Diag (dala v0.0.1)

Copy Markdown View Source

Runtime diagnostics that run inside a Dala app's BEAM. Designed to be invoked via Erlang RPC from a developer's machine to inspect the actual state of a deployed app.

Pairs with dala_dev's tooling — mix dala.verify_strip calls into verify_loaded_modules/0. Kept in the dala library (not dala_dev) so the functions are present in every shipped app, not just at build time on the developer's machine.

Security warnings

This module is a permanent target for remote execution if distribution credentials leak. Any node that can connect to your app's Erlang node can call these functions.

Mitigation strategies

  1. Use strong, unique cookies — generate per-app random cookies:

    cookie = Dala.Dist.cookie_from_env("MY_APP_DIST_COOKIE", "my_app")
  2. Never commit cookies to source control.

  3. Rotate cookies periodically using Node.set_cookie/1.

  4. Limit network exposure — use firewalls/VPC to restrict port 9100 and 4369 access to trusted machines only.

  5. Strip in production — consider removing or disabling this module in release builds by setting dala_RELEASE=1 or using code trimming.

  6. Monitor connections — log and alert on unexpected Node.connect attempts in production.

Don't expand the API surface here without thinking — anything added is permanently shipped to every Dala app and a permanent target for remote-execution if dist credentials leak.

Summary

Functions

Snapshot of what's currently loaded in the running BEAM, plus what's shipped-but-never-loaded (the empirical strip candidates).

Force-load every .beam file under the running app's OTP tree and report any that fail. Used by mix dala.verify_strip to validate that an aggressive strip didn't remove a module something else needed.

Types

load_failure()

@type load_failure() :: %{module: module(), reason: term()}

load_report()

@type load_report() :: %{
  total: non_neg_integer(),
  loaded: non_neg_integer(),
  failed: [load_failure()],
  elapsed_us: non_neg_integer(),
  otp_root: String.t() | nil
}

loaded_snapshot()

@type loaded_snapshot() :: %{
  loaded: [module()],
  loaded_count: non_neg_integer(),
  shipped_count: non_neg_integer(),
  unloaded_in_bundle: [module()],
  otp_root: String.t() | nil,
  captured_at: DateTime.t()
}

Functions

loaded_snapshot()

@spec loaded_snapshot() :: loaded_snapshot()

Snapshot of what's currently loaded in the running BEAM, plus what's shipped-but-never-loaded (the empirical strip candidates).

In interactive mode (Dala's default), a module is loaded only when something calls into it. So the loaded set after a representative user session is "what the app actually needs." Anything in the bundle but not in the loaded set is a strong strip candidate.

Better than tracing for our purposes: zero overhead, no rate-limit worries, no risk of mailbox-overflowing a busy app.

Workflow:

  1. Deploy the app
  2. User exercises every flow they care about
  3. RPC Dala.Diag.loaded_snapshot/0 from a Mix task
  4. Cross-reference :unloaded_in_bundle with the static audit: shipped + statically-reachable + never-loaded = high-confidence strip candidates.

Caveats: a flow that wasn't exercised won't show up. Run after a thorough session, not after just opening the app.

verify_loaded_modules()

@spec verify_loaded_modules() :: load_report()

Force-load every .beam file under the running app's OTP tree and report any that fail. Used by mix dala.verify_strip to validate that an aggressive strip didn't remove a module something else needed.

Walks all entries in :code.get_path/0, finds the OTP root from the first matching .../otp/lib/... path, and enumerates .beam files under it.

Returns load_report/0. Failures usually mean a stripped lib contained a transitive dependency of a kept module.