Audit log
Comentario keeps a record of who did what, when, and to which object
The audit log is a record of administrative and security-relevant actions taken on a Comentario instance: who signed in, who changed a domain’s settings, who moderated a comment, who banned a user, and so on.
Every entry answers the same questions: what was done, by whom, to which object, when, and how it ended. It’s meant to help you investigate an incident (“who deleted that page?”), keep an eye on your account’s security (“was that sign-in me?”), and hold several administrators of a domain accountable to each other.
The audit log is append-only: entries can’t be edited or deleted through the Administration UI or the API. They’re removed automatically once they’ve reached the retention period, and the personal data of a user is scrubbed from them when their account is deleted.
What gets recorded
Comentario records actions that change something of consequence, as well as authentication activity. Routine content activity — posting, voting on, or editing one’s own comment — isn’t recorded: there are webhooks for reacting to that.
Sign-in and account security
| Action | Recorded when |
|---|---|
auth.login | A user signs in, to the Administration UI or on a website with comments. Details tell the authentication method (local, sso, or federated, with the provider). |
auth.loginFailed | A sign-in attempt fails or is refused. Details tell the reason, for instance unknownUser or wrongPassword (along with the number of failed attempts so far). |
auth.logout | A user signs out. |
auth.forgotPwd | Someone requests a password reset, whether or not an account with that email exists. |
user.create | A new account is registered, locally or via a federated identity provider or SSO. |
user.confirm | A user confirms their email address. |
user.lock | An account gets locked after too many failed sign-in attempts (see Max. failed login attempts). |
user.password.change | A user changes their password. |
user.password.reset | A user sets a new password using a reset link. |
user.email.change | A user changes their email address. |
User management
| Action | Recorded when |
|---|---|
user.update | A superuser edits a user’s properties, including granting or revoking the superuser privilege. |
user.attrs | A superuser edits a user’s attributes. |
user.ban, user.unban | A superuser bans or unbans a user, optionally deleting their comments. |
user.unlock | A superuser unlocks a locked account. |
user.sessions.expire | A superuser expires all sessions of a user, signing them out everywhere. |
user.delete | A user is deleted by a superuser, or deletes their own account. |
Domains
| Action | Recorded when |
|---|---|
domain.create, domain.update, domain.delete | A domain is created, its settings are saved, or it’s deleted. |
domain.readonly | A domain is frozen or unfrozen. |
domain.ssoSecret.new | A new SSO secret is generated. |
domain.export, domain.import | Domain data is exported or imported. An import entry also tells how many users, pages, and comments were added, and the error if it stopped halfway. |
domain.clear | All pages and comments of a domain are removed. |
domain.purge | Deleted comments are purged; the entry tells how many. |
domain.attrs | A superuser edits a domain’s attributes. |
domain.user.update, domain.user.remove | A domain user’s role or notification settings are changed, or the user is removed from the domain. |
page.update, page.move, page.delete | A domain page’s properties are edited, its comments are moved to another page, or it’s deleted. |
webhook.create, webhook.update, webhook.delete | A webhook is registered, changed, or removed. A token embedded in the webhook URL is never recorded. |
webhook.secret.new | A new webhook signing secret is generated. |
Moderation
| Action | Recorded when |
|---|---|
comment.approve, comment.reject, comment.pending | A moderator approves or rejects a comment, or returns it to the moderation queue. |
comment.edit, comment.delete | A moderator edits or deletes someone else’s comment. An author editing or deleting their own comment isn’t moderation, and isn’t recorded. |
comment.sticky, comment.unsticky | A comment is made sticky or non-sticky. |
System configuration
| Action | Recorded when |
|---|---|
config.dynamic.update | A superuser changes the dynamic configuration; the entry lists every changed setting with its old and new value. |
config.dynamic.reset | A superuser resets the dynamic configuration to defaults. |
Plugins may record actions of their own, in addition to the above.
Anatomy of an entry
Each entry shows a short, translated message (such as Banned user or Moved 12 comments to /blog/new-post) along with the time it was recorded. Clicking the message expands the entry’s details.
- Actor — who performed the action:
- a user, shown with their name and email as they were at the time;
- Anonymous — someone not signed in, for example a person registering a new account or failing to sign in;
- System — Comentario itself, for example when the
--superusercommand-line option turns a user into a superuser on startup.
- Object — what the action was done to, with its type (User, Domain, Page, Comment, Webhook, or Configuration) and a label as it was at the time: an email, a host, a page path.
- Outcome — entries for actions that went through carry no badge. The others are marked:
- Denied — the action was refused by policy: the account is banned or locked, signups are disabled, and so on;
- Failed — the action didn’t succeed for another reason: a wrong password, an unknown email, an identity provider error.
- Changes — for edits, a table of the fields that actually changed, with their old and new values. A secret, such as a password, is listed as changed, not recorded: the entry tells it was changed, but never contains the value.
- Action — the action’s technical name, such as
user.ban, which you can use to filter the log. - Other details — anything else the action is about, for example the number of comments deleted along with a banned user, or the host of the website a user signed in on.
- IP — the IP address of the request. Unless the server runs with the
--log.full-ipsoption, only the first two bytes are stored (172.16.x.x).
Because an entry is a snapshot, it stays intact, and readable, after the domain, page, or comment it names has been deleted or renamed; a deleted user is the exception, see below. While an object still exists, its name in the entry is a link to it; once it’s gone, the name is shown as plain text.
Correlation ID
All entries recorded while handling a single request share a correlation ID, which superusers see in the entry details. For example, the failed sign-in attempt that locks an account out records both the attempt and the lockout, under the same correlation ID.
- To see every entry of the same request, click the Related entries link next to the correlation ID in the entry details. This opens the log filtered by that correlation ID alone.
- Every API response carries the correlation ID in the
X-Comentario-Correlation-Idheader. To find out what a particular request recorded, copy the header’s value from the browser’s developer tools, and filter the log by it.
Who sees what
Not every entry is meant for everyone. Each entry is recorded for an audience, which decides who can read it:
| Who | What they see | Where |
|---|---|---|
| Superusers | Every entry of the instance, with all details, including the IP, the audience, and the correlation ID. | Audit log in the sidebar; Activity in a domain’s and in a user’s properties |
| Domain owners | Entries about their domain: its settings, pages, comment moderation, domain users, webhooks, import and export. The IP address of the requester is never shown to them. | Activity in the domain’s properties |
| Every user | Entries about their own account: sign-ins, sign-outs, failed attempts to sign in, password and email changes. | Security section of their Profile |
A few consequences worth noting:
- Moderators don’t have access to the log. Their moderation actions are visible to the domain owners, which is what makes the log useful for overseeing a moderation team.
- Domain owners don’t see sign-ins of their domain’s users, nor the actions superusers take on user accounts (bans, deletions, edits): those concern the account, which spans all domains, not a particular domain.
- Users don’t see actions a superuser took on their account, such as editing it. They do see all security-related activity on it, including failed sign-in attempts, so they can spot someone trying to break in.
- Entries of a domain remain after the domain is deleted, but only superusers can see them then.
- Failed attempts to sign in, or to reset the password, with an email that matches no account are visible to superusers only.
Using the log
Instance-wide log (superusers)
The Audit log item in the sidebar opens the log of the entire instance, newest entries first. Scroll down and click Load more to see older ones.
Filtering the log
Click Filter to narrow the log down by one or more criteria. Each criterion you add is shown as a tag above the list; click its to remove it, or Clear filter to remove them all.
- Source — Comentario itself, or a specific plugin.
- Action — an exact action name, such as
auth.login, or a prefix ending with a dot, such asuser., to match a whole group of actions. - Correlation ID — the entries recorded within a single request.
- Object type — users, domains, pages, comments, webhooks, or configuration.
- Outcome — succeeded, denied, or failed.
- Authentication — the authentication method of sign-ins and sign-ups: local, Single Sign-On, or federated.
- From, To — a date range, inclusive, in your local time.
A few recipes:
- All failed sign-in attempts this week: Action
auth.loginFailed, From set to Monday. - Who’s been changing the system configuration: Object type Configuration.
- Everything denied: Outcome Denied, which reveals banned or locked users trying to sign in, and federated or SSO signups attempted while signups are disabled.
Activity of a user
A user’s properties page shows the latest entries about that user under Activity about user, with two buttons opening the full log:
- About user — actions done to the user: sign-ins, edits, bans, failed attempts to sign in to their account.
- By user — actions done by the user: their moderation, domain management, configuration changes, and so on.
Domain activity (owners and superusers)
The domain’s properties page shows its five most recent entries in the Activity section; Show all opens the whole list.
Your own account
The Security section of your Profile lists recent sign-ins and changes to your account, including failed sign-in attempts. If you see a sign-in you don’t recognise, change your password right away, and consider asking a superuser to expire all your sessions.
Bursts of failed attempts
Anybody can try signing in with a wrong password, or request password resets, over and over. To keep a flood of such requests — whether a brute-force attack or a misbehaving script — from bloating the database, failed sign-ins and password reset requests are throttled: within each 15-minute window, only the first 10 of them per IP address, and the first 100 in total, are recorded individually.
The ones beyond that aren’t lost: they’re counted, and every 15 minutes Comentario records a single summary entry per action and outcome, such as 37 more failed sign-in attempts not recorded individually, on behalf of System. Summaries are visible to superusers only.
The cap applies per Comentario process: if you run several instances, each records up to that many entries.
Successful sign-ins, and the locking of an account after too many wrong passwords, are always recorded individually.
Retention
Entries are kept for 365 days, after which a background job removes them. The job runs every 12 hours.
Plugin entries
If your instance runs plugins, they may record entries of their own. These appear alongside Comentario’s with a badge showing the plugin ID, and can be selected with the Source filter.
A plugin provides the messages for its entries. If the plugin is later removed, its entries remain, but are shown by their action name instead of a message.
Reliability
With PostgreSQL, an action and its audit entry are saved together, in one transaction: if the entry can’t be recorded, the action is rolled back and the request fails. Thus, every successful action has an entry.
With SQLite, which Comentario runs without transactions, the audit log is best-effort: an action may succeed without its entry if recording it fails, in which case Comentario logs an error. See Requirements for details.
Privacy considerations
The audit log contains personal data: names, email addresses, and (masked) IP addresses of the users involved. As an instance owner, keep in mind that:
- Entries outlive the accounts they mention, but not the personal data: when a user is deleted, their name, email, and IP addresses are removed from the entries, which remain until they reach the retention period.
- The audit log isn’t included in a domain export, so it doesn’t travel with the domain’s data.
- IP addresses are stored masked unless you pass
--log.full-ips. Storing full addresses makes it easier to trace an attack, but they’re more sensitive personal data.
Deleted users
When a user account is deleted, whether by the user themselves or by a superuser, Comentario removes the user’s personal data from the audit log, in the same go:
- their name and email, from the entries they made, and from those about them, the deletion’s own entry included;
- the name and email from attempts made with their email address before the account existed, such as failed sign-ins;
- the old and new values of their email, name, website, remarks, and custom names in domains from recorded changes, which then show as changed, not recorded;
- the IP addresses of the requests they made.
The entries themselves stay, as does the ID of the account, so the log still tells what the account did and what was done to it, and which entries are about the same account; the Administration UI shows it as Deleted user. The IP of somebody else acting on the account, such as the superuser who deleted it, is kept.
Entries recorded by plugins are scrubbed of the user’s name and IP as well, but not their details, which only the plugin knows.
Disabling the audit log
Running Comentario with the --no-audit command-line option (or NO_AUDIT=true in the environment) stops recording entries, by Comentario and by plugins alike.
Entries recorded before are kept, can still be viewed, and are removed once they reach the retention period, just as they would be otherwise.
