strapi-cms-audit-log 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +212 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1026 -0
  4. package/dist/admin/App-BLt4lqEM.js +1284 -0
  5. package/dist/admin/App-ou5hy99f.mjs +1266 -0
  6. package/dist/admin/en-B0rPiE2W.mjs +87 -0
  7. package/dist/admin/en-BMlJxq3g.js +87 -0
  8. package/dist/admin/index-BYi8OPTw.js +80 -0
  9. package/dist/admin/index-DdmY-p3Q.mjs +81 -0
  10. package/dist/admin/index.js +4 -0
  11. package/dist/admin/index.mjs +4 -0
  12. package/dist/admin/src/components/AuditLogFilters.d.ts +18 -0
  13. package/dist/admin/src/components/AuditLogTable.d.ts +19 -0
  14. package/dist/admin/src/components/ChangeViewer.d.ts +14 -0
  15. package/dist/admin/src/components/JsonViewer.d.ts +20 -0
  16. package/dist/admin/src/components/PluginIcon.d.ts +3 -0
  17. package/dist/admin/src/components/WidgetDiff.d.ts +19 -0
  18. package/dist/admin/src/hooks/useAuditLogs.d.ts +36 -0
  19. package/dist/admin/src/index.d.ts +3 -0
  20. package/dist/admin/src/pages/App.d.ts +11 -0
  21. package/dist/admin/src/pages/AuditLogDetails.d.ts +10 -0
  22. package/dist/admin/src/pages/AuditLogs.d.ts +3 -0
  23. package/dist/admin/src/permissions.d.ts +26 -0
  24. package/dist/admin/src/pluginId.d.ts +2 -0
  25. package/dist/admin/src/types.d.ts +91 -0
  26. package/dist/admin/src/utils/format.d.ts +41 -0
  27. package/dist/admin/src/utils/getTranslation.d.ts +2 -0
  28. package/dist/admin/src/utils/widgets.d.ts +85 -0
  29. package/dist/server/index.js +1856 -0
  30. package/dist/server/index.mjs +1856 -0
  31. package/dist/server/src/bootstrap.d.ts +14 -0
  32. package/dist/server/src/config/index.d.ts +52 -0
  33. package/dist/server/src/constants.d.ts +140 -0
  34. package/dist/server/src/content-types/audit-log/index.d.ts +86 -0
  35. package/dist/server/src/content-types/audit-log/schema.d.ts +141 -0
  36. package/dist/server/src/content-types/index.d.ts +88 -0
  37. package/dist/server/src/controllers/audit-log.d.ts +31 -0
  38. package/dist/server/src/controllers/index.d.ts +42 -0
  39. package/dist/server/src/destroy.d.ts +19 -0
  40. package/dist/server/src/index.d.ts +328 -0
  41. package/dist/server/src/register.d.ts +31 -0
  42. package/dist/server/src/routes/admin.d.ts +26 -0
  43. package/dist/server/src/routes/index.d.ts +19 -0
  44. package/dist/server/src/services/access.d.ts +51 -0
  45. package/dist/server/src/services/audit.d.ts +25 -0
  46. package/dist/server/src/services/config.d.ts +30 -0
  47. package/dist/server/src/services/context.d.ts +33 -0
  48. package/dist/server/src/services/diff.d.ts +48 -0
  49. package/dist/server/src/services/immutability.d.ts +30 -0
  50. package/dist/server/src/services/index.d.ts +137 -0
  51. package/dist/server/src/services/retention.d.ts +22 -0
  52. package/dist/server/src/services/security.d.ts +54 -0
  53. package/dist/server/src/services/snapshot.d.ts +46 -0
  54. package/dist/server/src/services/tracker.d.ts +39 -0
  55. package/dist/server/src/types/index.d.ts +214 -0
  56. package/dist/server/src/utils/json.d.ts +17 -0
  57. package/dist/server/src/utils/paths.d.ts +34 -0
  58. package/dist/server/src/utils/sanitize.d.ts +16 -0
  59. package/package.json +112 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,212 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
6
+ the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.1.0] — 2026-09-03
9
+
10
+ Adds the half of an audit trail that is not about content — authentication,
11
+ authorisation and the admin domain — plus a per-widget before/after view of
12
+ dynamic zones and optional structured-log forwarding.
13
+
14
+ ### Added
15
+
16
+ **Security events**
17
+ - Logins, failed logins and logouts, from Strapi's `admin.auth.success`,
18
+ `admin.auth.error` and `admin.logout` events. All available in **Community
19
+ Edition**; no Enterprise licence and no patching of Strapi's own code.
20
+ - A failed login records the **attempted email**, read off the live request body
21
+ because Strapi's event carries no identity at all. Only `email` is read; the
22
+ password is never touched.
23
+ - Denied requests (`access.denied`) for every 401 and 403, with the method, path,
24
+ status and the reason Strapi gave. Recorded by a Koa middleware registered from
25
+ the plugin's `register` lifecycle, which is the only phase that lands it ahead
26
+ of the router.
27
+ - Admin user, role and permission changes (`admin.user.*`, `admin.role.*`,
28
+ `admin.permission.*`) and media library operations (`media.*`,
29
+ `media-folder.*`).
30
+ - Admin-domain records keep an **allow-list** of identifying fields, so a
31
+ `user.update` payload cannot carry a password hash, reset token or registration
32
+ token into the audit table.
33
+ - New `securityEvents` option — `'*'`, a subset, or `[]` to register no listeners
34
+ and add no middleware at all.
35
+ - A listener can never fail the operation that emitted it. `eventHub.emit` awaits
36
+ its subscribers inside that operation, so every handler is wrapped and
37
+ `failOnAuditError` is deliberately not honoured on this side.
38
+
39
+ **Per-widget before/after**
40
+ - The detail page reassembles dynamic zones and renders each changed widget
41
+ **twice** — the whole widget as it was, then the whole widget as it now is —
42
+ with the differing fields highlighted in both copies.
43
+ - Zones are detected structurally (an array whose members carry `__component`),
44
+ so this covers `widgets`, `blocks` and any zone added later, on any content
45
+ type, with nothing to register.
46
+ - Slots are paired by position rather than component id, because Strapi
47
+ regenerates component row ids on every save; pairing by id would report every
48
+ widget as removed-and-re-added.
49
+ - Added, removed and replaced slots are distinguished; unchanged widgets collapse
50
+ behind a toggle.
51
+ - Computed in the browser from `before`/`after`, so it needs no new column, costs
52
+ no extra query, and works retroactively on records already in the table.
53
+
54
+ **Centralized logging / SIEM**
55
+ - New `forwardToLogger` and `forwardLogLevel` options mirror each record to
56
+ `strapi.log` as one line of structured JSON, for a collector to pick up off
57
+ container stdout. Snapshots are excluded; only the changed field paths are
58
+ emitted.
59
+
60
+ **Schema**
61
+ - `outcome` (`success` / `failure`) and `metadata` (JSON) columns, plus an
62
+ `audit_logs_outcome_idx` index, so "show me every failure" is one indexed
63
+ query. Both are filterable from the admin list and the API.
64
+
65
+ ### Changed
66
+
67
+ - The list page's filter dropdowns now offer **everything filterable**, not only
68
+ the values that already appear in the table. Previously a fresh install listed
69
+ two or three content types and one user, so there was no way to ask 'has anyone
70
+ touched Insights?' until somebody already had — which is exactly when the
71
+ question matters. Content types come from the content-type registry (respecting
72
+ `contentTypes`, and excluding the plugin's own type), users from `admin::user`,
73
+ locales from i18n, and actions, sources and outcomes from their full value sets. Values found only in stored rows — a deleted content type, a
74
+ removed administrator — are merged in, since those are what an investigation
75
+ goes looking for and they exist nowhere else. The content type and user filters
76
+ became searchable comboboxes, because both lists are now long.
77
+
78
+ - `auditSystemOperations` is now actually honoured. It was declared and resolved
79
+ but never consulted. Events emitted outside any request — chiefly Strapi's
80
+ boot-time permission reconciliation — are labelled `source: "system"` rather
81
+ than `admin`, and `auditSystemOperations: false` drops them instead of storing
82
+ them.
83
+ - The admin list gains an Outcome column and an Outcome filter; `outcome` is also
84
+ a sortable column and an accepted query parameter.
85
+ - `AuditEntryInput.action` widens from `AuditAction` to `AuditAnyAction`.
86
+ `AuditFilterOptions` gains `outcomes`, and `AuditLog` gains `outcome` and
87
+ `metadata`. Consumers reading those types may need to widen their own.
88
+
89
+ ### Fixed
90
+
91
+ - **Installing from a local path could make the plugin page unreachable.** With
92
+ `"strapi-plugin-audit-log": "file:../strapi-plugin-audit-log"`, yarn 1 copies
93
+ the directory wholesale — `files` is not honoured and `node_modules` is not
94
+ skipped — so the plugin's *dev* dependencies land at
95
+ `node_modules/strapi-plugin-audit-log/node_modules/`, including `@strapi/strapi`,
96
+ `@strapi/admin`, `react` and `react-router-dom`. Node and Vite resolve from the
97
+ importing file upward, so those nested copies win and the plugin's admin code
98
+ binds to a *second* instance of the admin runtime with its own React context.
99
+
100
+ The result is silent and very hard to attribute: `addMenuLink` still works
101
+ (it hands a plain object to the app's router, so the sidebar entry appears),
102
+ but `Page.Protect` calls `useAuth('Protect', s => s.permissions)` **without**
103
+ the `shouldThrowOnMissingContext` flag, so the missing context yields
104
+ `undefined` instead of an error, `(userPermissions || [])` makes it `[]`, and a
105
+ Super Admin who holds the permission is shown "You don't have the permissions
106
+ to access that content".
107
+
108
+ Nothing in the database, the RBAC registration or the API response is wrong in
109
+ this state, which is what makes it so misleading. See the "Installing from a
110
+ local path" note in the README; consuming projects should strip the nested
111
+ `node_modules` after install.
112
+
113
+ - The admin permission constants now declare the full permission entity
114
+ (`id`, `actionParameters`, `properties`, `conditions` alongside `action` and
115
+ `subject`), matching what `GET /admin/users/me/permissions` returns and what
116
+ Strapi's own first-party plugins declare. Housekeeping rather than a bug fix —
117
+ `{ action, subject: null }` already satisfied both of the admin's permission
118
+ checks.
119
+ - Media library and admin-domain operations are no longer invisible. Both write
120
+ through `strapi.db.query`, below the Document Service, so the tracker could
121
+ never see them; they are covered by the event listeners instead. The
122
+ Limitations section has been corrected accordingly.
123
+
124
+ ## [1.0.0] — 2026-09-02
125
+
126
+ First release.
127
+
128
+ ### Added
129
+
130
+ **Automatic tracking**
131
+ - A single Document Service middleware (`strapi.documents.use`) covering every
132
+ content type, present and future, with no per-content-type code.
133
+ - `create`, `update`, `delete`, `publish` and `unpublish`, across the admin
134
+ panel, the REST and GraphQL content APIs and custom server code.
135
+ - A create or update that also publishes records both actions, since Strapi's
136
+ repository publishes internally without re-entering the middleware.
137
+ - One record per affected locale, so a bulk publish is attributable per
138
+ translation.
139
+
140
+ **Diffs**
141
+ - Generic, schema-agnostic diff engine producing dotted paths with indexed array
142
+ members (`seo.metaTitle`, `blocks[2].heading`).
143
+ - Handles primitives, nested objects, components, repeatable components, dynamic
144
+ zones, relations, media, arrays and localized fields.
145
+ - `Date` and its ISO string compare equal, as do `null` and `undefined`, so a
146
+ re-save does not report spurious changes.
147
+ - Depth budget and a 500-change cap, both with explicit markers when hit.
148
+
149
+ **Redaction**
150
+ - Case-insensitive, wildcard-capable ignore patterns matched at any depth.
151
+ - Built-in defaults covering password, token, secret, apiKey, privateKey,
152
+ credential, accessKey, salt and otp variants.
153
+ - `additionalIgnoredFields` to extend the defaults, `ignoredFields` to replace
154
+ them, `ignoredChangeFields` to exclude from the diff only.
155
+ - Redacted values are removed rather than masked, and stripped before the diff
156
+ runs.
157
+
158
+ **Performance**
159
+ - Snapshot queries scoped to the attributes a write actually touched.
160
+ - Relations and media reduced to identifying fields.
161
+ - Dynamic zones populated so that only the component types present in the data
162
+ are queried — five widgets used out of 173 declared costs five queries.
163
+ - Optional data-driven second pass for nested dynamic-zone content, gated on
164
+ `maxPopulateDepth`.
165
+ - One `findMany` across all affected locales rather than one per locale.
166
+ - Six database indexes, declared in the schema and created by Strapi's schema
167
+ sync on every supported database.
168
+
169
+ **Admin UI**
170
+ - `Audit Logs` sidebar entry at `/admin/audit-logs`, filtered by RBAC.
171
+ - Server-side pagination, search, sorting and filtering by action, content type,
172
+ user, locale, source, document id and date range, all reflected in the URL.
173
+ - Detail page with full metadata, a readable before/after diff and collapsible
174
+ JSON viewers.
175
+ - Delete, shown only to roles holding `plugin::audit-log.delete`.
176
+
177
+ **Security**
178
+ - `plugin::audit-log.read`, `.delete` and `.settings` registered with Strapi's
179
+ admin RBAC; read and delete deliberately separate.
180
+ - Admin-only routes, each guarded by `admin::isAuthenticatedAdmin` plus an
181
+ explicit `admin::hasPermissions`; no content-api route exists.
182
+ - Records are immutable: the collection type is hidden from the Content Manager,
183
+ which is what withholds write permissions, plus a Document Service guard for
184
+ server code.
185
+ - Query parameters are whitelisted and object-valued filters rejected, so a
186
+ client cannot author query operators; `sort` accepts only known columns.
187
+ - Actor and request metadata come from the server-side request context, never
188
+ from a request body.
189
+
190
+ **Operations**
191
+ - Retention on `strapi.cron`, off the request path; `retentionDays: 0` registers
192
+ no job.
193
+ - `writeMode` (`sync` by default) with pending writes drained on shutdown.
194
+ - `failOnAuditError` (`false` by default) with the trade-off documented.
195
+ - `context.runAs()` for labelling migrations, cron tasks and other work with no
196
+ request behind it.
197
+
198
+ **Types**
199
+ - Strict TypeScript throughout, with `AuditAction`, `AuditLog`, `AuditChange`,
200
+ `AuditContext`, `AuditConfig` and others exported from
201
+ `strapi-plugin-audit-log/strapi-server`.
202
+
203
+ ### Notes
204
+
205
+ - The audited document's id is stored as `contentDocumentId`, not `documentId`:
206
+ Strapi v5 reserves the latter as an attribute name and throws at boot if a
207
+ schema declares one. Each audit row still carries its own framework
208
+ `documentId`.
209
+ - Collection-valued configuration options default to `null` internally, because
210
+ Strapi merges plugin config with lodash's `defaultsDeep`, which merges arrays
211
+ element-wise. The real defaults are applied afterwards, so a user-supplied
212
+ array replaces ours cleanly.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Latheefwac
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.