External project-module (file backend)¶
The project-module (trimus-project-module) is an optional standalone
service that hosts a project's files off the main Trimus server. The server and
remote workers reach it over HTTP through the same internal
file-store interface used for local files, so flipping a project to the module
changes where files live without changing the UI or the API.
Status: SP2.2 — server + remote workers. Remote workers can now read/write a module-backed project's files securely via short-lived, project-scoped tokens (see Security). Still pending for a shared, multi-company module exposed on an untrusted network: replay/nonce hardening and egress-allowlist wiring.
What it does¶
- Stores each project's files under
<data-root>/companies/<companyId>/projects/<projectId>/files, with the exact path-validation and streaming behavior of the built-in local backend. - Exposes a minimal HTTP API the server calls: list / read / write / delete / stat under
/modules/projects/{companyId}/{projectId}/files[/{path}], plusGET /healthz. - Reads still stream through the server (the browser/API never talks to the module directly), so no UI or auth changes are needed.
Running the module¶
Environment variables (the module is database-free):
| Var | Required | Default | Meaning |
|---|---|---|---|
TRIMUS_MODULE_KEY |
yes | — | shared bearer token; the server must present the same value |
TRIMUS_PROJECT_MODULE_PORT |
no | 8090 |
listen port |
TRIMUS_PROJECT_MODULE_TLS_CERT / _TLS_KEY |
no | — | PEM cert+key paths; when both are set the module serves HTTPS |
TRIMUS_PROJECT_MODULE_HOME |
no | TRIMUS_HOME, else /var/lib/trimus-project-module |
data root |
TRIMUS_MODULE_KEY=<shared-secret> \
TRIMUS_PROJECT_MODULE_HOME=/srv/project-files \
TRIMUS_PROJECT_MODULE_PORT=8090 \
trimus-project-module
Pointing the server at it¶
On the server:
| Var | Meaning |
|---|---|
TRIMUS_PROJECT_MODULE_ENDPOINT |
base URL of the module, e.g. http://127.0.0.1:8090 |
TRIMUS_MODULE_KEY |
the shared HMAC secret the module enforces (also the server's raw-key bearer) |
TRIMUS_PROJECT_MODULE_TOKEN_TTL |
lifetime of a minted worker→module token (default 1h; must exceed the max run timeout) |
If the endpoint or key is empty, a project set to external_module degrades to
local-FS with a warning (so a misconfiguration never breaks file access).
Opting a project (or company) in¶
The backend is selected by a file_backend column on projects (and a
per-company default on companies), added by migration 150. Values:
local_fs (default) or external_module; a project's value overrides its
company's default.
Flip a single project via the API:
Switch guard¶
Switching file_backend while files already exist on the current backend is
rejected with HTTP 409 — the module owns the bytes and the server keeps no
mirror, so a silent switch would orphan the existing files. Migrate or remove
them first, then switch. (Automatic copy-on-switch is a planned enhancement.)
Security (read before enabling)¶
TRIMUS_MODULE_KEYis now both the module's raw-key bearer (for the co-located server — full access) and the HMAC signing secret for tokens. It lives only on the server + module; workers never receive it.- For a remote worker, the server mints a short-lived, project-scoped token
(
{company_id, project_id, exp}, HMAC-SHA256) into the task payload. The module verifies the signature, the expiry, and that the request's company/project match the token's claims — so a worker can only reach the one project it was authorized for, for ≤ the token TTL. A leaked token exposes one project's files for a bounded window; a leaked key still exposes the whole module (keep it server-side only). - The token rides in the
remote_taskspayload (DB); it is mitigated by being scoped + short-lived. Never logged. - On an untrusted network, run the module over TLS — set
TRIMUS_PROJECT_MODULE_TLS_CERT/_TLS_KEY(or front it with a TLS-terminating proxy). The bearer key and scoped tokens travel in theAuthorizationheader, so without TLS they can be sniffed. The module audit-logs every authorized request (method, company, project, path, auth kind) for forensics. - Not applicable to this design (documented so they aren't mistaken for gaps): a single-use nonce/replay cache — one scoped token is deliberately reused across a run's many requests (list + reads + writes + deletes), so the replay window is bounded by the TTL + TLS, not by per-request nonces; and the per-company egress allowlist (#79), which gates the agent subprocess's traffic — the worker (not the agent) performs module I/O, so worker→module reachability is a deployment/network concern, not a per-company agent rule.