Secure Sharing (RBAC Web Server)

The problem this solves: a contractor needs the media division’s runbooks, and nothing else. Sending a folder export means the moment it lands in their inbox you have lost control of it. Sharing the whole vault is worse.

The three roles

RoleCan readCan writeCan delete
viewerdepartments its ACL allowsnono
editordepartments its ACL allowsyes, same departmentsno
admineverythingeverythingyes, with guards

Roles are not hierarchical shortcuts — editor is governed by the same access_control list as viewer, so an editor cannot reach a department it was not granted.

How access is actually decided

Every request passes through one authorisation chokepoint before it is dispatched. There is no route that answers before that check runs, and the allowlist of unauthenticated routes (login, logout, health) is explicit.

This matters because the original design checked permissions inside each handler, and the static-file route simply forgot to. It served any file in the repo to anyone who asked, unauthenticated, while the API beside it correctly returned 401 for the same path. The regression guard for that is a test asserting the raw file route and /api/read return identical status for the same path.

Nested folders do not leak

Access is resolved through hierarchical gates, not by looking at a path’s first segment. A restricted container stays restricted for everything beneath it, even when a subfolder’s name matches an open department. That bug was real: a restricted client folder was reachable because a nested path resolved to an open department name.

What it is not

  • Not internet-facing. Sessions are in memory (a restart logs everyone out) and it ships without TLS. Run it on localhost or a LAN, or behind your own reverse proxy.
  • Not a password vault. Credentials come from environment variables or a hashed store created by --init-users. There are no default passwords.

Running it

python3 pro-pack/web-server/_server.py --init-users   # first time; prints passwords once
python3 -u pro-pack/web-server/_server.py . 8766

Configuration is read from company-config.yaml at startup — restart after editing it.

See also: GUIDE-document-control for how controlled documents are numbered and approved once people can reach them.