enlace_auth.appmeta#
Editable app-metadata overlay: the write surface for the launcher.
enlace core owns the read model for launcher metadata (title / description /
keywords / icon) — it harvests app-declared values and serves /_apps and the
icon endpoint. But the editable layer — an owner-curated overlay of added
keywords and icon/title/description overrides, mutated live from the launcher UI
— needs authentication, CSRF, an admin allowlist, and durable per-app storage.
Those are exactly the concerns enlace core delegates to this plugin, so the
overlay lives here, mirroring the runtime-grants pattern
(enlace_auth.auth.grants).
The contract with core is two dependency-injection slots on the parent app’s
state (read by core, written here):
app_meta_overlay— aMutableMapping[str, dict]of per-app overlay records; core reads it when resolving/_appsand the icon.app_meta_can_edit—Callable[[Optional[str]], bool]deciding whether an email may edit; core surfaces the result ascan_edit_meta.
Without this plugin (or on an older enlace_auth), those slots default in core to an empty overlay and “nobody can edit”, so the launcher still works read-only.
Overlay record schema (one JSON file per app under <store>/app_meta/{name}):
{
"keywords": ["owner", "added", "tags"], # additive; unioned by core
"icon": "emoji:🎸" | "assets/x.png" | null,
"display_name": "Override Title" | null,
"description": "Override blurb" | null
}
Empty records are deleted, so “no overlay” and “empty overlay” coincide.
Functions
|
Build the |
|
Build the |
- enlace_auth.appmeta.make_appmeta_can_edit(editors, *, widen=True)[source]#
Build the
app_meta_can_editclosure over a normalized editor set.Case-insensitive, and with widen each editor admits both canonical spellings of its address (
account_spellings()). Passwiden=Falsefor the admin list, which is compared as written everywhere else. An empty editor set means nobody can edit (safe default, so a misconfigured deploy fails closed rather than open).
- enlace_auth.appmeta.make_appmeta_router(*, apps, config, overlay_store, can_edit)[source]#
Build the
PATCH/DELETE /_apps/{name}/metarouter (CSRF-gated by the plugin’s middleware, since/_apps/*is not in the CSRF-exempt list).Editor authz is enforced per request via
can_edit. The app name is validated against the known-apps set (unknown ⇒ 404), which also keeps the store key confined to a real app name — defense-in-depth over the[^/]+path convertor that already blocks traversal.- Return type:
APIRouter