Add capability-scoped module API (Workstream D)
ModuleManifest gains a structured [[permissions]] field (bread-shared's
new ModulePermission/PermissionKind, shared between bread-cli and breadd
so the two never drift on what a permission "type" string means).
breadd now gives every third-party module's Lua chunk a scoped _ENV
instead of the shared global table: load_scoped_lua_file builds a fresh
`bread` table containing only baseline bindings (event subscription,
timers, json, module/store, logging, and the pure-Lua sugar built on top
of those) plus whatever the manifest's permissions grant, with a
metatable __index falling back to the real globals for everything else
(stdlib, require/package - so require("bread.devices") keeps working,
since builtins load unscoped and their closures capture that environment
lexically regardless of the caller's). _G is explicitly rebound to the
scoped table itself to close the obvious escape hatch. A module with no
manifest, or a manifest with no permissions key, keeps full ambient
access unchanged (today's behavior) but is now tracked as `ungated` in
module status and surfaced by `bread doctor`. An explicit `permissions =
[]` is scoped for real but not flagged, since that's a deliberate
declaration.
Adds `bread modules audit <name>`: a best-effort text scan of a module's
.lua files suggesting a [[permissions]] block to paste into its manifest.
Converts examples/modules/cpu-temp-widget.lua into a directory module
with a worked bread.module.toml (fs.read + widget) as the reference
example. Documentation.md gets a new "Capability-scoped modules" section
covering the taxonomy, the require()/closure mechanism, and an explicit
note that path/bin scoping is recorded but not yet enforced per-call -
that's the out-of-process module sandboxing workstream this manifest
schema is laid down for. API_VERSION bumped 1.4.0 -> 1.5.0.
This commit is contained in:
parent
96639516b1
commit
6841163620
13 changed files with 1329 additions and 14 deletions
21
examples/modules/cpu-temp-widget/bread.module.toml
Normal file
21
examples/modules/cpu-temp-widget/bread.module.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
name = "cpu-temp-widget"
|
||||
version = "1.0.0"
|
||||
description = "Live CPU package temperature widget, read from hwmon sysfs"
|
||||
author = "bread"
|
||||
source = "local"
|
||||
installed_at = ""
|
||||
|
||||
# This module only ever calls bread.fs.read (never .write) and
|
||||
# bread.widget.register/update — declaring exactly that is what makes
|
||||
# bread.exec, bread.bluetooth, bread.hyprland, bread.machine, bread.notify,
|
||||
# and bread.state all genuinely absent (nil) from its `bread` table at
|
||||
# runtime, rather than merely unused. `source`/`installed_at` above get
|
||||
# overwritten by `bread modules install`; they're placeholders for the
|
||||
# drop-in/copy-paste path.
|
||||
|
||||
[[permissions]]
|
||||
type = "fs.read"
|
||||
path = "/sys/class/hwmon"
|
||||
|
||||
[[permissions]]
|
||||
type = "widget"
|
||||
73
examples/modules/cpu-temp-widget/init.lua
Normal file
73
examples/modules/cpu-temp-widget/init.lua
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
-- cpu-temp-widget — live CPU package temperature, read straight from the
|
||||
-- k10temp hwmon sysfs node via bread.fs.read.
|
||||
--
|
||||
-- Demonstrates: WidgetPlacement "left_of_stats", a bread.every-polled
|
||||
-- widget reading real hardware state (the same category of readout
|
||||
-- breadbar's native CPU%/RAM stats already do in Rust — this shows it's
|
||||
-- just as easy from a drop-in Lua module), and the typed `style` vocabulary
|
||||
-- (color + weight) swapping based on a threshold so the widget visually
|
||||
-- flags when something's hot — no CSS, no guessing which class names the
|
||||
-- rendering app happens to define.
|
||||
--
|
||||
-- Drop-in: copy the whole cpu-temp-widget/ directory into
|
||||
-- ~/.config/bread/modules/ (or `bread modules install path/to/this/dir`).
|
||||
-- TEMP_PATH is specific to this machine (AMD, k10temp) — find yours with:
|
||||
-- grep -l k10temp /sys/class/hwmon/hwmon*/name
|
||||
-- and adjust below; a missing/unreadable path just shows "—" rather than
|
||||
-- erroring, since bread.fs.read returns nil (not an error) for that case.
|
||||
--
|
||||
-- This is also the worked example for the capability-manifest permission
|
||||
-- system (Documentation.md's "Capability-scoped modules" section): see the
|
||||
-- sibling bread.module.toml. It declares exactly the two permissions this
|
||||
-- module actually uses — `fs.read` (bread.fs.read, read-only) and `widget`
|
||||
-- (bread.widget.register/update) — nothing else. If you install it that
|
||||
-- way, bread.exec/bread.bluetooth/bread.hyprland/etc. are all genuinely
|
||||
-- absent (nil) from this module's `bread` table, not just unused.
|
||||
|
||||
local M = bread.module({ name = "cpu-temp-widget", version = "1.0.0" })
|
||||
|
||||
local TEMP_PATH = "/sys/class/hwmon/hwmon6/temp1_input"
|
||||
local HOT_THRESHOLD_C = 80
|
||||
|
||||
local function read_temp_c()
|
||||
local raw = bread.fs.read(TEMP_PATH)
|
||||
if not raw then
|
||||
return nil
|
||||
end
|
||||
return tonumber(raw) / 1000
|
||||
end
|
||||
|
||||
local function widget_root(temp_c)
|
||||
local text = temp_c and string.format("%.0f°C", temp_c) or "—"
|
||||
local hot = temp_c ~= nil and temp_c >= HOT_THRESHOLD_C
|
||||
return {
|
||||
type = "box",
|
||||
children = {
|
||||
{
|
||||
type = "label",
|
||||
text = text,
|
||||
style = hot and { color = "red", weight = "bold" } or { color = "dim" },
|
||||
},
|
||||
{
|
||||
type = "progress",
|
||||
value = temp_c and math.min(temp_c / 100, 1.0) or 0,
|
||||
style = hot and { color = "red" } or nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
function M.on_load()
|
||||
bread.widget.register({
|
||||
id = "cpu-temp",
|
||||
placement = "left_of_stats",
|
||||
tooltip = "CPU package temperature (Tctl)",
|
||||
root = widget_root(read_temp_c()),
|
||||
})
|
||||
|
||||
bread.every(5000, function()
|
||||
bread.widget.update("cpu-temp", { root = widget_root(read_temp_c()) })
|
||||
end)
|
||||
end
|
||||
|
||||
return M
|
||||
Loading…
Add table
Add a link
Reference in a new issue