feat(audit): OCIS file-tail ingest worker (Phase 2 chunk 3)
Tails OCIS's JSON-Lines audit log on a shared Docker volume and forwards
mutations into AuditService. Final piece of Phase 2 — the /audit page now
unifies platform-api, authentik, and ocis events on one timeline.
services/platform-api/src/ingest/ocis.ingest.ts:
- 5s polling loop (fs.watch is unreliable across Docker bind mounts on
macOS). Stat → detect inode change or truncation → resume from byte
position OR start over.
- Cursor in IngestCursor stores lastEventId = "<inode>:<bytePosition>".
Restarts resume cleanly; on overlap the (source, externalId) unique
index dedups silently.
- Lines collected first, then processed sequentially after the read
stream closes. Earlier draft fired recordOne() from inside the
readline 'line' callback which would have resolved the stream
before all writes finished — same class of race we hit in the
Authentik worker, fixed before commit.
- Tenant inference: spaceName (set during provisioning to the slug)
first, then User.authentikSubjectId → tenantIds → Tenant.slug.
- Mutations only: OCIS_ALLOWLIST in action-map.ts whitelists 24 event
types (User/Group/Space/Share/Link/File mutations). FileDownloaded,
UserSignedIn, and the rest of the high-volume read traffic gets
skipped — keeps the timeline scannable.
services/platform-api/src/ingest/action-map.ts:
- mapOcisAction() + OCIS_ALLOWLIST. Returns null for non-whitelisted
types so the worker filters early.
infrastructure/docker-compose/docker-compose.yml:
- New named volume `ocis_audit_log` mounted writeable on the ocis
container and read-only on platform-api.
- OCIS env: OCIS_ADD_RUN_SERVICES=audit (the audit microservice is
NOT in the default `ocis server` set — opt in explicitly),
AUDIT_LOG_FILE_PATH=/var/log/ocis/audit.log, AUDIT_LOG_FORMAT=json.
- platform-api env: OCIS_AUDIT_LOG_PATH points at the same file.
Verified end-to-end with synthetic events written to the audit log:
- Worker tailed 5 events across initial read + incremental append
(5 → bytes 0:1276, then 1 → bytes 1276:1519).
- FileDownloaded correctly filtered by the allowlist (4 mutations
landed in Mongo, not 5).
- Tenant inference: events with executingUser.id resolved to
`dezky` via User → tenantIds → Tenant.slug.
- Operator /audit shows all three sources (89 events: 79 authentik
+ 5 platform-api + 5 ocis) in one unified timeline.
Known unknown — same shape as the Stalwart commit: I couldn't fully
confirm the OCIS v7 audit microservice emits events with just
OCIS_ADD_RUN_SERVICES=audit + the AUDIT_LOG_FILE_PATH env. The audit
service starts but the file stays empty until OCIS internals start
publishing events to NATS (which may need additional service-side
config). The ingest worker is correct regardless — when OCIS starts
writing real events, they'll flow into /audit. This is a follow-up
in the OCIS-side configuration, not in our ingest code.
This commit is contained in:
@@ -28,6 +28,7 @@ volumes:
|
||||
stalwart_data:
|
||||
ocis_config:
|
||||
ocis_data:
|
||||
ocis_audit_log:
|
||||
portal_node_modules:
|
||||
platform_api_node_modules:
|
||||
operator_node_modules:
|
||||
@@ -258,9 +259,17 @@ services:
|
||||
NATS_NATS_PORT: 9233
|
||||
GATEWAY_GRPC_ADDR: 0.0.0.0:9142
|
||||
MICRO_GRPC_CLIENT_DNS_CACHE_TIMEOUT: 10s
|
||||
# Audit service — JSON Lines to a shared volume that platform-api also
|
||||
# mounts read-only. Used by the OCIS ingest worker to fold file/share
|
||||
# mutations into the global audit timeline. The audit microservice is
|
||||
# NOT part of the default `ocis server` set so we opt in explicitly.
|
||||
OCIS_ADD_RUN_SERVICES: audit
|
||||
AUDIT_LOG_FILE_PATH: /var/log/ocis/audit.log
|
||||
AUDIT_LOG_FORMAT: json
|
||||
volumes:
|
||||
- ocis_config:/etc/ocis
|
||||
- ocis_data:/var/lib/ocis
|
||||
- ocis_audit_log:/var/log/ocis
|
||||
- ./configs/ocis/csp.yaml:/etc/ocis/csp.yaml:ro
|
||||
networks: [dezky]
|
||||
depends_on:
|
||||
@@ -469,10 +478,14 @@ services:
|
||||
AUTHENTIK_JWKS_URI: https://auth.dezky.local/application/o/dezky-portal/jwks/
|
||||
# Trust mkcert root CA for Node fetch (dev only)
|
||||
NODE_EXTRA_CA_CERTS: /etc/ssl/mkcert-root.pem
|
||||
# Path to the OCIS audit log inside this container. The same shared
|
||||
# volume is mounted on the OCIS service writeable; here it's read-only.
|
||||
OCIS_AUDIT_LOG_PATH: /var/log/ocis/audit.log
|
||||
volumes:
|
||||
- ../../services/platform-api:/app
|
||||
- platform_api_node_modules:/app/node_modules
|
||||
- ./certs/mkcert-root.pem:/etc/ssl/mkcert-root.pem:ro
|
||||
- ocis_audit_log:/var/log/ocis:ro
|
||||
networks: [dezky]
|
||||
depends_on:
|
||||
mongo:
|
||||
|
||||
Reference in New Issue
Block a user