Wire breadlock to the bread event bus (app id lock)
Emit bread.lock.locked when ext-session-lock-v1 is accepted and bread.lock.unlocked after PAM success. Fail-silent if breadd is down. No command verbs (no pin/blur stubs). breadgreet is not on the bus. Note that Forgejo Arch registry packages are unsigned (SigLevel=Never on BOS) without changing the package.yml registry.
This commit is contained in:
parent
0937c3b05c
commit
2a541ca5e9
9 changed files with 105 additions and 0 deletions
|
|
@ -7,6 +7,10 @@ on:
|
|||
jobs:
|
||||
package:
|
||||
runs-on: [self-hosted, hestia]
|
||||
# Forgejo's Arch package registry does not GPG-sign packages for pacman.
|
||||
# BOS therefore uses SigLevel=Never on [Breadway.os.git.breadway.dev]
|
||||
# until a signed repo exists. Keep publishing here — do not flip this
|
||||
# job to a different registry just to get signatures.
|
||||
container:
|
||||
image: archlinux:latest
|
||||
steps:
|
||||
|
|
|
|||
24
Cargo.lock
generated
24
Cargo.lock
generated
|
|
@ -64,6 +64,17 @@ dependencies = [
|
|||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bread-shared"
|
||||
version = "0.7.0"
|
||||
source = "git+https://git.breadway.dev/Breadway/bread?tag=v0.7.0#22e34e2cf2202305d7960759dfccb54dc79f948b"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"toml 0.8.23",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bread-theme"
|
||||
version = "0.3.1"
|
||||
|
|
@ -75,6 +86,17 @@ dependencies = [
|
|||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bread-utils"
|
||||
version = "0.3.1"
|
||||
source = "git+https://git.breadway.dev/Breadway/bread-ecosystem?tag=v0.7.1#db2fa3c4b4c1e6933bc5cf62a236d05972fdc886"
|
||||
dependencies = [
|
||||
"bread-shared",
|
||||
"dirs",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "breadgreet"
|
||||
version = "0.2.0"
|
||||
|
|
@ -97,10 +119,12 @@ dependencies = [
|
|||
name = "breadlock"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"bread-utils",
|
||||
"breadlock-ui",
|
||||
"chrono",
|
||||
"pam-client2",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smithay-client-toolkit",
|
||||
"thiserror 2.0.18",
|
||||
"tiny-skia",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ resolver = "2"
|
|||
|
||||
[workspace.dependencies]
|
||||
bread-theme = { git = "https://git.breadway.dev/Breadway/bread-ecosystem", tag = "v0.7.1" }
|
||||
bread-utils = { git = "https://git.breadway.dev/Breadway/bread-ecosystem", tag = "v0.7.1" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
toml = "0.8"
|
||||
|
|
|
|||
44
EVENTS.md
Normal file
44
EVENTS.md
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# breadlock — bread event integration
|
||||
|
||||
breadlock is a standalone session locker: it works exactly the same with
|
||||
or without `breadd` running. When breadd *is* present, `breadlock`
|
||||
publishes events into the shared bread automation fabric. See the parent
|
||||
`bread` repo's `Documentation.md` — specifically its "Namespaces" and
|
||||
"Integrating a bread\* app" sections — for the general convention this
|
||||
follows.
|
||||
|
||||
App id: **`lock`**. Transport: `bread-utils`'s `bread_client` module
|
||||
(feature `bread-client`) — `breadlock` links it directly. Each `emit` is
|
||||
its own short-lived connection (`BreadClient::emit` is fire-and-forget);
|
||||
there is no long-running subscription half because breadlock has no
|
||||
command verbs (see below).
|
||||
|
||||
`breadgreet` is not wired to the bus. It runs under greetd (typically as
|
||||
the dedicated greeter user, before a user session exists), so breadd is
|
||||
usually not there to receive anything, and login is a different lifecycle
|
||||
from session lock/unlock.
|
||||
|
||||
## Events published (`bread.lock.*`)
|
||||
|
||||
| Event | Data | When |
|
||||
|-------|------|------|
|
||||
| `bread.lock.locked` | `{}` | The compositor accepted the `ext-session-lock-v1` request (`SessionLockHandler::locked`). Not emitted merely because breadlock started or asked to lock. |
|
||||
| `bread.lock.unlocked` | `{}` | PAM authenticated successfully and breadlock sent `unlock` to the compositor. Not emitted on a compositor-ended lock (`finished`), a dispatch-error exit (fail-secure: the session stays locked), or a failed/typo password. |
|
||||
|
||||
## Commands honored (`bread.command.lock.*`)
|
||||
|
||||
None. breadlock is started by hypridle / `loginctl lock-session` (or
|
||||
directly) and unlocks only via PAM on this process. There is no
|
||||
`lock`/`unlock`/`pin`/`blur` verb, and none is stubbed as a no-op.
|
||||
|
||||
`background.blur` in `breadlock.toml` remains a documented locker no-op
|
||||
(accepted, warned, surface drawn unblurred). That is appearance config,
|
||||
not a bus command — do not invent `bread.command.lock.blur` for it.
|
||||
|
||||
## Fail-safe behavior
|
||||
|
||||
- If breadd isn't installed or isn't running, `emit` is a silent no-op
|
||||
(`BreadClient::emit` never blocks or errors the caller) — breadlock's
|
||||
actual lock/unlock path is entirely unaffected either way.
|
||||
- There is no command subscription, so a breadd restart while the lock
|
||||
screen is up changes nothing on this side.
|
||||
|
|
@ -9,6 +9,13 @@ Two binaries, one workspace:
|
|||
|
||||
Both use [`bread-theme`](https://git.breadway.dev/Breadway/bread-ecosystem) for palette loading, matching the rest of the bread* ecosystem (breadbar, breadbox, bos-settings).
|
||||
|
||||
## bread event integration
|
||||
|
||||
`breadlock` works the same with or without `breadd`. When `breadd` is
|
||||
running, it publishes `bread.lock.locked` / `bread.lock.unlocked`. See
|
||||
[EVENTS.md](EVENTS.md) for the bus contract. `breadgreet` is not on the
|
||||
bus. There is no `bakery.toml` (PAM / pacman exception).
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ path = "src/bin/breadlock-auth-check.rs"
|
|||
|
||||
[dependencies]
|
||||
breadlock-ui = { path = "../breadlock-ui", features = ["paint"] }
|
||||
bread-utils = { workspace = true, features = ["bread-client"] }
|
||||
smithay-client-toolkit = "0.20"
|
||||
wayland-client = "0.31"
|
||||
tiny-skia = "0.12"
|
||||
|
|
@ -26,6 +27,7 @@ chrono = "0.4"
|
|||
pam-client2 = { version = "0.5", default-features = false }
|
||||
zeroize = { version = "1", features = ["std"] }
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
toml.workspace = true
|
||||
tracing.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
|
|
|
|||
20
breadlock/src/bread_events.rs
Normal file
20
breadlock/src/bread_events.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
//! `bread.lock.*` event integration — optional, non-blocking. See
|
||||
//! `EVENTS.md` at the repo root for the full contract. breadlock works
|
||||
//! identically with or without breadd running; every call here is
|
||||
//! fire-and-forget (`BreadClient::emit` never blocks or errors this
|
||||
//! process) so a missing or restarting breadd never affects locking
|
||||
//! itself.
|
||||
|
||||
use bread_utils::bread_client::BreadClient;
|
||||
|
||||
/// This app's id in bread's sibling-app namespace registry
|
||||
/// (`bread_shared::apps::KNOWN_APPS`) — events publish as `bread.lock.*`.
|
||||
pub const APP_ID: &str = "lock";
|
||||
|
||||
pub fn emit_locked() {
|
||||
BreadClient::connect(APP_ID).emit("bread.lock.locked", serde_json::json!({}));
|
||||
}
|
||||
|
||||
pub fn emit_unlocked() {
|
||||
BreadClient::connect(APP_ID).emit("bread.lock.unlocked", serde_json::json!({}));
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ impl SessionLockHandler for AppState {
|
|||
fn locked(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, session_lock: SessionLock) {
|
||||
tracing::info!("session locked");
|
||||
self.session_lock = Some(session_lock);
|
||||
crate::bread_events::emit_locked();
|
||||
}
|
||||
|
||||
/// The compositor denied the lock request, or ended an active lock out
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
mod auth;
|
||||
mod background;
|
||||
mod bread_events;
|
||||
mod config;
|
||||
mod input;
|
||||
mod lock;
|
||||
|
|
@ -53,6 +54,7 @@ fn main() {
|
|||
tracing::info!("authenticated, unlocking");
|
||||
if let Some(lock) = state.session_lock.take() {
|
||||
lock.unlock();
|
||||
bread_events::emit_unlocked();
|
||||
}
|
||||
state.exit = true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue