Skip to content

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}], plus GET /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:

curl -X PATCH /api/projects/{id} -d '{"file_backend":"external_module"}'

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_KEY is 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_tasks payload (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 the Authorization header, 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.