Two related defects in the group-read story (found on openSUSE Tumbleweed, v0.3.2)
1. Unhandled PermissionError crashes views instead of degrading (contract violation)
CONTEXT.md defines Store fault as "the store ... cannot be read ... — degrading every view that depends on it rather than crashing". But open_store_readonly() (status.py:91) calls store_path.exists() before the fault handling — and stat() on a root:fenris 2750 directory by a non-group user raises PermissionError ([Errno 13]), which neither fenris status nor the TUI (tui.py:347) catches. Both crash with a full traceback instead of rendering the degraded view.
_open_store() catches only StoreFault/NewerSchema — PermissionError from stat() slips through before a StoreFault can even be raised.
Fix: catch OSError in open_store_readonly() and raise StoreFault (or make the caller degrade). Add a regression test: non-group user + 2750 dir → status/TUI render the fault view, exit 0.
2. Group members cannot actually read the WAL-mode store — StoreFault "attempt to write a readonly database"
After joining the fenris group, a member still cannot open the store:
tmpfiles.d creates only the directory (2750); the collector (root, umask 022) creates observations.db + WAL sidecars 644 — group has no write.
SQLite in WAL mode requires write access to -shm/-wal (and to create them when absent) even for read-only connections. mode=ro → attempt to write a readonly database → open_store_readonly wraps it into StoreFault.
So every group reader gets the fault view forever, and only root sees data. The 2750 group placement suggests group read was intended.
Fix (packaging + collector):
tmpfiles.d: 2770 for /var/lib/fenris (group create/traverse).
Collector: after init_store(), chmod g+rw the db and sidecars (or run the unit with UMask=002).
Keep open_store_readonly on plain mode=ro — immutable=1 is unsafe with a live collector.
Verified locally on the affected machine: chmod 2770 /var/lib/fenris + group membership → fenris status renders live data for a non-root group member.
Notes for the release-notes matrix
who
2750 (current)
2770 + g+rw sidecars (proposed)
root
ok
ok
group member
crash / permanent fault
ok
other
crash / fault
fault (no traversal)
## Two related defects in the group-read story (found on openSUSE Tumbleweed, v0.3.2)
### 1. Unhandled `PermissionError` crashes views instead of degrading (contract violation)
`CONTEXT.md` defines **Store fault** as "the store ... cannot be read ... — degrading every view that depends on it rather than crashing". But `open_store_readonly()` (`status.py:91`) calls `store_path.exists()` before the fault handling — and `stat()` on a `root:fenris 2750` directory by a non-group user raises `PermissionError` (`[Errno 13]`), which neither `fenris status` nor the TUI (`tui.py:347`) catches. Both crash with a full traceback instead of rendering the degraded view.
`_open_store()` catches only `StoreFault`/`NewerSchema` — `PermissionError` from `stat()` slips through before a `StoreFault` can even be raised.
**Fix:** catch `OSError` in `open_store_readonly()` and raise `StoreFault` (or make the caller degrade). Add a regression test: non-group user + `2750` dir → status/TUI render the fault view, exit 0.
### 2. Group members cannot actually read the WAL-mode store — `StoreFault` "attempt to write a readonly database"
After joining the `fenris` group, a member still cannot open the store:
- `tmpfiles.d` creates only the directory (`2750`); the collector (root, umask 022) creates `observations.db` + WAL sidecars `644` — group has no write.
- SQLite in WAL mode requires **write** access to `-shm`/`-wal` (and to create them when absent) even for read-only connections. `mode=ro` → `attempt to write a readonly database` → `open_store_readonly` wraps it into `StoreFault`.
So every group reader gets the fault view forever, and only root sees data. The `2750` group placement suggests group read was intended.
**Fix (packaging + collector):**
- `tmpfiles.d`: `2770` for `/var/lib/fenris` (group create/traverse).
- Collector: after `init_store()`, `chmod g+rw` the db and sidecars (or run the unit with `UMask=002`).
- Keep `open_store_readonly` on plain `mode=ro` — `immutable=1` is unsafe with a live collector.
Verified locally on the affected machine: `chmod 2770 /var/lib/fenris` + group membership → `fenris status` renders live data for a non-root group member.
### Notes for the release-notes matrix
| who | 2750 (current) | 2770 + g+rw sidecars (proposed) |
|---|---|---|
| root | ok | ok |
| group member | crash / permanent fault | ok |
| other | crash / fault | fault (no traversal) |
Verified end to end on the reporting machine (openSUSE Tumbleweed): upgraded 0.3.2 → 0.3.3, tmpfiles re-applied 2770, collector recreated group-writable sidecars, non-root fenris group member reads live data via status/TUI store path.
Resolved in **v0.3.3** (commits fb683f5 + 4a7661d, [release](https://git.bongbetic.com/xavierk/Fenris/releases/tag/v0.3.3)):
- `open_store_readonly()` maps `OSError` from `stat()` to `StoreFault` — status/TUI degrade instead of crashing (src/fenris/status.py)
- `init_store()` enforces `g+rw` on the db and `-wal`/`-shm` sidecars (src/fenris/store.py)
- Store dir ships `2770` (tmpfiles.d + `make install`); collect unit sets `UMask=002`
- rpm `%post` upgrade path re-runs `systemd-tmpfiles --create` to correct existing machines
- `tests/test_store_group_access.py`: stat-denied → StoreFault, sidecar modes, packaging assertions
Verified end to end on the reporting machine (openSUSE Tumbleweed): upgraded 0.3.2 → 0.3.3, tmpfiles re-applied `2770`, collector recreated group-writable sidecars, non-root `fenris` group member reads live data via status/TUI store path.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Two related defects in the group-read story (found on openSUSE Tumbleweed, v0.3.2)
1. Unhandled
PermissionErrorcrashes views instead of degrading (contract violation)CONTEXT.mddefines Store fault as "the store ... cannot be read ... — degrading every view that depends on it rather than crashing". Butopen_store_readonly()(status.py:91) callsstore_path.exists()before the fault handling — andstat()on aroot:fenris 2750directory by a non-group user raisesPermissionError([Errno 13]), which neitherfenris statusnor the TUI (tui.py:347) catches. Both crash with a full traceback instead of rendering the degraded view._open_store()catches onlyStoreFault/NewerSchema—PermissionErrorfromstat()slips through before aStoreFaultcan even be raised.Fix: catch
OSErrorinopen_store_readonly()and raiseStoreFault(or make the caller degrade). Add a regression test: non-group user +2750dir → status/TUI render the fault view, exit 0.2. Group members cannot actually read the WAL-mode store —
StoreFault"attempt to write a readonly database"After joining the
fenrisgroup, a member still cannot open the store:tmpfiles.dcreates only the directory (2750); the collector (root, umask 022) createsobservations.db+ WAL sidecars644— group has no write.-shm/-wal(and to create them when absent) even for read-only connections.mode=ro→attempt to write a readonly database→open_store_readonlywraps it intoStoreFault.So every group reader gets the fault view forever, and only root sees data. The
2750group placement suggests group read was intended.Fix (packaging + collector):
tmpfiles.d:2770for/var/lib/fenris(group create/traverse).init_store(),chmod g+rwthe db and sidecars (or run the unit withUMask=002).open_store_readonlyon plainmode=ro—immutable=1is unsafe with a live collector.Verified locally on the affected machine:
chmod 2770 /var/lib/fenris+ group membership →fenris statusrenders live data for a non-root group member.Notes for the release-notes matrix
Resolved in v0.3.3 (commits
fb683f5+4a7661d, release):open_store_readonly()mapsOSErrorfromstat()toStoreFault— status/TUI degrade instead of crashing (src/fenris/status.py)init_store()enforcesg+rwon the db and-wal/-shmsidecars (src/fenris/store.py)2770(tmpfiles.d +make install); collect unit setsUMask=002%postupgrade path re-runssystemd-tmpfiles --createto correct existing machinestests/test_store_group_access.py: stat-denied → StoreFault, sidecar modes, packaging assertionsVerified end to end on the reporting machine (openSUSE Tumbleweed): upgraded 0.3.2 → 0.3.3, tmpfiles re-applied
2770, collector recreated group-writable sidecars, non-rootfenrisgroup member reads live data via status/TUI store path.