Files
oikos/secrets
dtoro 2084a1583e Oikos Week 3: scheduler, drift detectors, signals, classifier, approvals
New kernel modules, all wired into `homelab` CLI + tested against live
production where reachable:

- oikos/scheduler.py — Observe stage: HTTP health probes for every
  service, disk-usage probes on hubris/strong, writes oikos/state.json
  (gitignored — regenerates every run). `homelab service <name> health`
  is now cache-first; `--live` forces a fresh probe. Deploys via
  oikos/systemd/oikos-scheduler.{timer,service} on LXC 105.

- oikos/drift.py — SOPS-recipient-vs-inventory and lifecycle-consistency
  detectors (fully local, no SSH) plus pct-list and Caddy-backend
  detectors (best-effort SSH, degrade to an info finding when
  unreachable rather than a false drift alarm). Found real, currently-
  true drift on first run: republic-laptop's age key granted on every
  secret but missing from inventory.yaml, grimmory missing from
  hello.yaml's recipients, and an undocumented pve_id 131 on hubris —
  recorded in OIKOS.md for the operator, not auto-fixed (each is a
  config_mutation/destructive decision).

- oikos/signal.py — the attention layer: raised -> acknowledged ->
  acting -> resolved|muted lifecycle, severity-based routing, dedup via
  open_signal_for(). `homelab signal list|raise|ack|resolve|mute`.

- oikos/decide.py — the Decide-stage classifier: risk class x blast
  radius x ledger-history confidence -> auto-act/escalate. Adds an
  action-alias layer (oikos/policy.py ACTION_ALIASES) and auto-infers
  service_name from the entity for per-service policy overrides.
  `homelab decide <action> <entity>`.

- oikos/approve.py — the escalate route. No dedicated Matrix bot exists
  in this homelab, so this is the repo-side half only: request/reply/
  grant lifecycle with short-TTL HMAC-signed tokens (new secret
  secrets/oikos-approval-hmac.yaml, recipients apps+hubris). Matrix
  delivery is Hermes's existing @dtoro:avispero send path (documented
  integration contract in the module docstring), not a new bot.
  `homelab restart` now mechanically refuses config_mutation/destructive
  services without a valid --approval-id, regardless of -y/interactivity.

- oikos/report.py — daily brief + weekly report from signal/approval/
  ledger state (no Prometheus yet, so point-in-time counts only).

- plans/2026-07-05-oikos-prometheus-lxc.md — Prometheus is `planned`,
  not provisioned: no pve_id is guessed here since Proxmox assigns real
  IDs at creation time, and drift already found an unclaimed ID (131) to
  investigate first.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 23:29:39 +02:00
..

secrets/

SOPS-encrypted YAML files. The plaintext lives only in transit and in the operator's head — committed files are always ciphertext.

Conventions

  • One file per logical grouping (e.g. gitea-tokens.yaml, webhook-hmacs.yaml, api-keys.yaml).
  • Recipients are declared in ../.sops.yaml by path-regex, not per-file.
  • The plaintext schema inside each file is free-form YAML; the consumer code decides what it expects (e.g. gitea-tokens.yaml contains {"<host>": "ghp_xxx"}).

How to add a secret

# 1. Decide which clients should be able to decrypt it; edit ../.sops.yaml to
#    list their age public keys for the new path_regex.
# 2. Create the plaintext, encrypt in place:
sops -e --in-place secrets/my-thing.yaml
# 3. Commit + push. The 5-min sync propagates to every recipient.

How to consume a secret

# On any client that's a recipient:
homelab secret my-thing               # prints plaintext
# Or programmatically:
sops -d /opt/homelab-context/secrets/my-thing.yaml

The mcp tool list_my_secrets(caller_pubkey) returns the names of secrets the caller can decrypt. The MCP server never reads plaintext — decryption stays client-side.

Granting / revoking access

To grant a new recipient: edit ../.sops.yaml to add their age pubkey, then re-key every affected file:

sops updatekeys -y secrets/my-thing.yaml

To revoke: remove the recipient from ../.sops.yaml and sops updatekeys — but remember this only protects future ciphertext. Past plaintext the client already decrypted is gone from your control. Rotate the underlying credential if compromise is suspected.

homelab client remove <name> does the recipient removal + updatekeys for you, and prints the rotation checklist as a follow-up.

hello.yaml — bootstrap decrypt test

secrets/hello.yaml is encrypted to every enrolled client. Used by Phase 3a verification to confirm the end-to-end decrypt path works on a freshly- bootstrapped machine. Content is intentionally trivial:

greeting: hello from the homelab