170 lines
9.4 KiB
Markdown
170 lines
9.4 KiB
Markdown
# 03 — The account's own tools: ssh, scripts, mail
|
|
|
|
Three further directions from the operator on 2026-10-04. Each is account-level, like the shell
|
|
([to-be 41](../../03-DESIGN/01-to-be/41-the-shell-and-the-accounts-environment.md)).
|
|
|
|
## `~/.ssh` is one module's
|
|
|
|
*"A module owns `~/.ssh`, so it is its responsibility that every folder is set up consistently and
|
|
correctly."*
|
|
|
|
**Measured:**
|
|
|
|
- The catalogue's `ssh-client` module owns the directory (mode 0700) and one region of
|
|
`~/.ssh/config`: a `Host` block per machine of the mesh. It owns nothing else.
|
|
- On one workstation, a predecessor's header, `Include` and hand-written host block sat **above** the
|
|
mesh's region. ssh takes the first match, so the predecessor's entries were the ones in force, for
|
|
the same machines. Removed on 2026-10-04.
|
|
- On the control machine, two keys of a retired CI system were still in the operator's
|
|
`authorized_keys`, able to log in as the operator. Removed the same day.
|
|
- Permissions differ by file and by machine. Backups of the configuration lie beside it.
|
|
|
|
**Starting position:** `ssh-client` becomes the holder of everything under `~/.ssh`, classified as
|
|
ADR 0182 asks:
|
|
|
|
| path | class | how |
|
|
|---|---|---|
|
|
| `~/.ssh/`, its mode, every file's mode | owned | the directory resource, plus a check verb that reports a file with the wrong mode |
|
|
| `~/.ssh/config` | written into, the mesh's block **at the start** | the mesh's hosts win; the operator's lines after it are kept; an `Include config.d/*` line in the block |
|
|
| `~/.ssh/config.d/<module>` | owned by the contributing module | ssh's own drop-in: a work module adds its forge's host there (research 026 C1) |
|
|
| `~/.ssh/authorized_keys` | written into, the mesh's block | the operator's keys as the mesh records them, and nothing a retired system left. The operator's own lines are kept below the block |
|
|
| `~/.ssh/known_hosts` | written into, the mesh's block | every mesh machine's host key, so the first connection never asks |
|
|
| private keys | found | never read and never written by the mesh; a key the mesh should hand out comes from the vault, through the module's own process (ADR 0182, third class) |
|
|
|
|
The sshd module is the other half: the machine's side. It is already in the catalogue.
|
|
|
|
## Scripts on every machine, shared and machine-specific
|
|
|
|
*"All nodes should get some custom scripts, both node-specific and mesh-specific (shared)."*
|
|
|
|
**Measured:** the operator's script folder holds 64 entries plus 33 in its `bin/`. It is under no
|
|
version control, and exists only where it was copied. It mixes three kinds:
|
|
|
|
1. scripts belonging to a module (the desktop's watchers, lock, menus; a laptop model's brightness);
|
|
2. the operator's own tools;
|
|
3. installers that modules have replaced.
|
|
|
|
**Starting position:**
|
|
|
|
- **The operator's scripts live in a repository of their own,** registered as any application is
|
|
([ADR 0015](../../02-DECISIONS/0015-applications-live-in-their-own-repository.md)), built as archives,
|
|
unpacked into a directory the module owns under the home. `bin/` goes on `PATH` through an
|
|
environment contribution ([ADR 0203](../../02-DECISIONS/0203-the-accounts-environment-is-one-modules-and-every-module-contributes-to-it.md)),
|
|
and small functions go into the shell through a `shell` contribution
|
|
([ADR 0204](../../02-DECISIONS/0204-a-module-contributes-shell-code-to-the-login-shell-in-named-slots.md)).
|
|
- **"Machine-specific" is said by assignment, never by naming a machine**
|
|
([ADR 0112](../../02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md)). One repository
|
|
holds several modules:
|
|
- `scripts` (shared, on every machine);
|
|
- `scripts-workstation`;
|
|
- `scripts-media`;
|
|
- and so on, each assigned where it applies.
|
|
|
|
A script that belongs to a piece of software or hardware moves into that module instead. A flavor
|
|
inside one module is what [research 026/03](../026-the-graphical-session-as-modules/03-what-the-predecessor-taught.md)
|
|
says not to repeat.
|
|
- **A script can also be a tool.** A script with a one-line description is served by the node's
|
|
runtime, so it can be called through the mesh on any machine that has it.
|
|
- A script that needs a secret gets it through question 2's mechanism, never from a file of
|
|
environment secrets.
|
|
|
|
## The keyring
|
|
|
|
*"A keyring is also a good thing to create a module for."*
|
|
|
|
**Measured on the two workstations, which both run GNOME Keyring:**
|
|
|
|
- **On one, the keyring unlocks at login.** The login manager's PAM service includes `login`, which
|
|
carries `pam_gnome_keyring`.
|
|
- **On the other, it does not.** The PAM line is only in the screensaver's service, so at session
|
|
start the window manager runs a script that asks for the password a second time and unlocks the
|
|
keyring with it.
|
|
- **On both, the session's start script starts the daemon again** with the ssh and gpg components,
|
|
and exports the ssh agent's socket. The keyring's current release serves the ssh agent through a
|
|
separate per-user socket unit instead.
|
|
|
|
**Starting position:** a `gnome-keyring` module that holds a node seat, `node-secret-service` (the
|
|
holder of the desktop's secret service; a password manager could hold it instead). It declares:
|
|
|
|
- the package;
|
|
- its lines in the login manager's PAM file, written into, never over (ADR 0102), so login unlocks it
|
|
on every machine;
|
|
- the ssh agent's user socket, once user-scoped units ship;
|
|
- the agent's socket path as an environment contribution, which needs a machine fact for the
|
|
account's runtime directory. ADR 0203 forbids `$` in values, so `$XDG_RUNTIME_DIR` cannot be
|
|
written in one.
|
|
|
|
The second unlock prompt and the second daemon start go away.
|
|
|
|
## Mail as events
|
|
|
|
*"Ideally a mail consumer with all my mail accounts configured, so my mail is recorded in the bus."*
|
|
|
|
**Measured:**
|
|
|
|
- The predecessor polled one work mailbox every minute. It **read an access token out of the mail
|
|
client's process memory**, called a mail API with it, and raised a desktop notification per unread
|
|
message. It worked only while the mail client ran, and stopped silently when the predecessor's units
|
|
were retired.
|
|
- Two further predecessor modules served mail tools, for one provider and for IMAP.
|
|
- The mesh runs a mail server of its own for its domains.
|
|
|
|
**Not decided here; it needs an effort of its own.** The questions it would have to answer:
|
|
|
|
- **Accounts and how each authenticates:**
|
|
- IMAP with an app password;
|
|
- a provider's OAuth with a registered application;
|
|
- the mesh's own mail server, which can publish delivery itself.
|
|
|
|
An employer's tenant may forbid registering an application at all.
|
|
- **What the bus records:**
|
|
- headers and a summary as events;
|
|
- bodies and attachments in an object store the event points at;
|
|
- retention, since mail is the most personal data the mesh would hold.
|
|
- **What consumes it:** a notifier bridge to the desktop (the predecessor's notifications), search,
|
|
an agent's context.
|
|
- **Where it runs:** one long-running module, not per machine (ADR 0198).
|
|
|
|
The obvious first step is the mail server the mesh already runs.
|
|
|
|
## Power management on the laptop
|
|
|
|
*"Power management for the laptop."*
|
|
|
|
**Measured on the laptop** (a gaming model with a hybrid GPU):
|
|
|
|
- **The platform profile is driven by a vendor daemon** (`asusd`) and its CLI. The vendor CLI is
|
|
now in the official repositories; the copy installed came from elsewhere. A predecessor script
|
|
runs as a user unit and switches the profile every five seconds: quiet on battery, balanced on
|
|
mains, performance above 50 % CPU.
|
|
- **The hybrid GPU's mode** (now hybrid) is held by a second vendor daemon (`supergfxd`), which is
|
|
**not** in the official repositories. Kernel-module options for the discrete GPU's power state
|
|
and its suspend, hibernate and resume units are set by hand. Its own power daemon is masked.
|
|
- **The battery charge limit is 80 %,** set by the vendor daemon.
|
|
- **The lid and power key suspend.** The brightness key is ignored by logind and handled by the
|
|
vendor-key path. Both are logind drop-ins.
|
|
- **Memory pressure:** compressed swap in RAM (`zram`) beside a swap file and a partition;
|
|
`systemd-oomd` with drop-ins; a predecessor *memory guard* user unit that notifies before the OOM
|
|
killer acts.
|
|
- `upower` runs. There is no `power-profiles-daemon`, `tlp`, `auto-cpufreq` or `thermald`, so nothing
|
|
competes with the vendor daemon, by design.
|
|
|
|
All of it came from two predecessor modules, one of which was a laptop-model *flavor*. A desktop
|
|
received part of it (research 026/01).
|
|
|
|
**Starting position:**
|
|
|
|
- **A hardware module per machine model** (here, the laptop's model). It holds the vendor daemon and
|
|
its profile configuration, the GPU mode daemon (ADR 0205's case, or the build machine's package
|
|
repository of research 027 question 1), the discrete GPU's module options and suspend units, the
|
|
logind drop-ins, the battery charge limit, and the vendor keys and brightness. It is assigned to
|
|
the one machine of that model, and to any second one later.
|
|
- **The profile switching** moves from a polling script to the module's own long-running code
|
|
(ADR 0198). It reacts to the power-supply change event instead of polling, and its thresholds
|
|
become settings (issue 168).
|
|
- **Memory pressure is not the laptop's alone.** `zram` and `systemd-oomd` with the notifier are a
|
|
`memory-pressure` module, assigned wherever wanted. The swap layout stays the machine's (`kernel`
|
|
module, question 3).
|
|
- A **`node-power-profile`** seat (vendor daemon, or `power-profiles-daemon` on other hardware)
|
|
gives the mesh one verb, `profile`, the same on every machine that has one.
|