-
Notifications
You must be signed in to change notification settings - Fork 1
Audit Log
Operational audit trail. Every important admin action is recorded with
timestamp, user, IP, result, and an optional JSON detail field. View at
/audit (left nav → "감사 로그").
| Action | Trigger | Result codes | Detail JSON |
|---|---|---|---|
auth.login |
POST /api/auth/login, POST /login (SSR) |
OK / FAIL
|
`{"channel":"web |
auth.setup |
First admin creation | OK |
(none) |
auth.logout |
POST /api/auth/logout, POST /logout
|
OK |
(none) |
auth.password.change |
POST /password |
OK / FAIL
|
(none) |
device.revoke |
POST /devices/{id}/revoke |
OK |
(none) |
project.create |
POST /projects |
OK |
`{"sourceType":"empty |
project.delete |
POST /projects/{id}/delete |
OK / FAIL
|
(none) |
build.enqueue |
POST /projects/{id}/builds |
OK |
(none) |
build.cancel |
POST /projects/{id}/builds/{buildId}/cancel |
OK |
(none) |
console.new |
POST /projects/{id}/console/new |
OK |
(none) |
console.cancel |
POST /api/projects/{id}/claude/console/cancel |
OK |
(none) |
mcp.install |
POST /env-setup/mcp/install |
OK |
{"selected":"id1,id2,..."} |
mcp.unregister |
POST /env-setup/mcp/unregister |
OK |
(none) |
settings.update |
POST /settings |
OK / FAIL
|
{"error":"..."} on failure |
git.token.register |
POST /settings/git-integrations |
OK |
(none) |
git.token.delete |
POST /settings/git-integrations/delete |
OK / FAIL
|
(none) |
REST API hits that don't change state (GETs, console prompt streaming, env
diagnostics) are not in the audit log — they go to the server log
instead (docker compose logs -f vibe-coder-server). The audit log is
strictly IAM-level, not a request log.
CREATE TABLE audit_log (
id VARCHAR(64) PRIMARY KEY,
ts VARCHAR(64) NOT NULL, -- ISO-8601 UTC
user_id VARCHAR(64) , -- nullable (e.g. failed login)
device_id VARCHAR(64) , -- nullable
ip VARCHAR(64) ,
action VARCHAR(64) NOT NULL,
resource_type VARCHAR(64) ,
resource_id VARCHAR(256) ,
result VARCHAR(16) NOT NULL, -- OK / FAIL / DENIED
detail TEXT ,
INDEX (ts), INDEX (action)
);detail is always a JSON object built with kotlinx.serialization (no
string interpolation — quote-safe even when input contains ").
/audit exposes five filters as GET query parameters:
| Param | Example | Notes |
|---|---|---|
action |
auth.login |
dropdown auto-populated from distinct values |
result |
FAIL |
OK / FAIL / DENIED |
user |
<userId> |
the admin's internal id, not username |
from |
2026-05-24T00:00:00Z |
ISO ts; string ≥ comparison |
to |
2026-05-25T00:00:00Z |
ISO ts; string ≤ comparison |
Pagination: 100 rows per page, ?p=<index> (0-based).
ISO-8601 lexicographic ordering means the simple ts text index supports
range queries efficiently even though the column type is varchar.
A JSON API endpoint (GET /api/audit) is on the roadmap — clients
will be able to stream the log into SIEM / monitoring. For now use direct
PostgreSQL access:
docker exec -it vibe-coder-postgres psql -U vibecoder -d vibecoder
\d audit_log
SELECT ts, action, result, ip, resource_id FROM audit_log ORDER BY ts DESC LIMIT 50;Audit writes are wrapped in a try/catch. If the INSERT fails (e.g.,
PostgreSQL momentarily unavailable), the user-facing request still
completes successfully and the failure is logged to stderr. Missing
audit entries are a forensic gap, not a denial-of-service surface.
No automatic rotation. The audit log accumulates indefinitely. For 1-person LAN tools this is fine for years. Manual cleanup when needed:
DELETE FROM audit_log WHERE ts < (now() - interval '180 days')::text;
VACUUM ANALYZE audit_log;Future work: retention configuration in server.yml, optional archive
table.
- No request bodies are recorded — only metadata (action / IDs).
-
Passwords / tokens are never written to
detail. -
IP is the value from
RoutingCall.request.local.remoteHost— for reverse-proxy deployments this may be the proxy's IP unless the proxy strips/setsX-Forwarded-For. Honouring that header is future work.
Useful one-liners — paste into the browser:
/audit?action=auth.login&result=FAIL # all failed logins
/audit?action=project.delete # who deleted what
/audit?user=<userId>&from=2026-05-24T00:00:00Z # one user, one day
/audit?action=git.token.register # PAT lifecycle