@objectstack/plugin-audit 4.0.3 → 4.0.4
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.
- package/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +8 -0
- package/README.md +414 -0
- package/package.json +3 -3
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @objectstack/plugin-audit@4.0.
|
|
2
|
+
> @objectstack/plugin-audit@4.0.4 build /home/runner/work/framework/framework/packages/plugins/plugin-audit
|
|
3
3
|
> tsup --config ../../../tsup.config.ts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
[34mCJS[39m Build start
|
|
13
13
|
[32mCJS[39m [1mdist/index.js [22m[32m4.93 KB[39m
|
|
14
14
|
[32mCJS[39m [1mdist/index.js.map [22m[32m7.55 KB[39m
|
|
15
|
-
[32mCJS[39m ⚡️ Build success in
|
|
15
|
+
[32mCJS[39m ⚡️ Build success in 79ms
|
|
16
16
|
[32mESM[39m [1mdist/index.mjs [22m[32m3.75 KB[39m
|
|
17
17
|
[32mESM[39m [1mdist/index.mjs.map [22m[32m7.10 KB[39m
|
|
18
|
-
[32mESM[39m ⚡️ Build success in
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 82ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 21495ms
|
|
21
21
|
[32mDTS[39m [1mdist/index.d.mts [22m[32m103.78 KB[39m
|
|
22
22
|
[32mDTS[39m [1mdist/index.d.ts [22m[32m103.78 KB[39m
|
package/CHANGELOG.md
CHANGED
package/README.md
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
# @objectstack/plugin-audit
|
|
2
|
+
|
|
3
|
+
Audit Plugin for ObjectStack — System audit log object and audit trail for compliance and security monitoring.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Comprehensive Audit Trail**: Track all CRUD operations across all objects
|
|
8
|
+
- **User Activity Logging**: Record who did what, when, and from where
|
|
9
|
+
- **Field-Level Changes**: Capture before/after values for all field changes
|
|
10
|
+
- **Compliance Ready**: Meet SOC 2, HIPAA, GDPR audit requirements
|
|
11
|
+
- **Query Filtering**: Search audit logs by user, object, action, date range
|
|
12
|
+
- **Retention Policies**: Auto-archive or delete old audit logs
|
|
13
|
+
- **Security Events**: Track authentication, authorization, and security-related events
|
|
14
|
+
- **Immutable Logs**: Audit records cannot be modified or deleted (only archived)
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm add @objectstack/plugin-audit
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Basic Usage
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { defineStack } from '@objectstack/spec';
|
|
26
|
+
import { PluginAudit } from '@objectstack/plugin-audit';
|
|
27
|
+
|
|
28
|
+
const stack = defineStack({
|
|
29
|
+
plugins: [
|
|
30
|
+
PluginAudit.configure({
|
|
31
|
+
enabled: true,
|
|
32
|
+
trackObjects: '*', // Track all objects
|
|
33
|
+
trackFields: '*', // Track all field changes
|
|
34
|
+
}),
|
|
35
|
+
],
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Configuration
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
interface AuditPluginConfig {
|
|
43
|
+
/** Enable audit logging (default: true) */
|
|
44
|
+
enabled?: boolean;
|
|
45
|
+
|
|
46
|
+
/** Objects to track ('*' for all, or array of object names) */
|
|
47
|
+
trackObjects?: '*' | string[];
|
|
48
|
+
|
|
49
|
+
/** Fields to track ('*' for all, or object-specific config) */
|
|
50
|
+
trackFields?: '*' | Record<string, string[]>;
|
|
51
|
+
|
|
52
|
+
/** Track system events (login, logout, failed auth, etc.) */
|
|
53
|
+
trackSystemEvents?: boolean;
|
|
54
|
+
|
|
55
|
+
/** Retention period in days (default: 365) */
|
|
56
|
+
retentionDays?: number;
|
|
57
|
+
|
|
58
|
+
/** Auto-archive after retention period (default: true) */
|
|
59
|
+
autoArchive?: boolean;
|
|
60
|
+
|
|
61
|
+
/** Exclude certain users from audit (e.g., system users) */
|
|
62
|
+
excludeUsers?: string[];
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Audit Log Schema
|
|
67
|
+
|
|
68
|
+
The plugin automatically creates the `audit_log` object:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
{
|
|
72
|
+
id: string; // Unique audit log entry ID
|
|
73
|
+
timestamp: datetime; // When the action occurred
|
|
74
|
+
userId: string; // User who performed the action
|
|
75
|
+
userName: string; // User's name at time of action
|
|
76
|
+
userEmail: string; // User's email at time of action
|
|
77
|
+
action: string; // 'insert', 'update', 'delete', 'read'
|
|
78
|
+
object: string; // Object type (e.g., 'opportunity')
|
|
79
|
+
recordId: string; // Record ID that was affected
|
|
80
|
+
recordName: string; // Record display name
|
|
81
|
+
changes: json; // Field-level changes (before/after)
|
|
82
|
+
metadata: json; // Additional context (IP, user agent, etc.)
|
|
83
|
+
ipAddress: string; // Client IP address
|
|
84
|
+
userAgent: string; // Client user agent
|
|
85
|
+
sessionId: string; // Session ID
|
|
86
|
+
status: string; // 'success' | 'failed'
|
|
87
|
+
errorMessage: string; // Error message if action failed
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Automatic Audit Logging
|
|
92
|
+
|
|
93
|
+
All CRUD operations are automatically audited:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// This operation is automatically audited
|
|
97
|
+
await kernel.getDriver().insert({
|
|
98
|
+
object: 'opportunity',
|
|
99
|
+
data: {
|
|
100
|
+
name: 'Big Deal',
|
|
101
|
+
amount: 100000,
|
|
102
|
+
stage: 'prospecting',
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Audit log entry created:
|
|
107
|
+
// {
|
|
108
|
+
// action: 'insert',
|
|
109
|
+
// object: 'opportunity',
|
|
110
|
+
// recordId: '123',
|
|
111
|
+
// recordName: 'Big Deal',
|
|
112
|
+
// changes: {
|
|
113
|
+
// name: { from: null, to: 'Big Deal' },
|
|
114
|
+
// amount: { from: null, to: 100000 },
|
|
115
|
+
// stage: { from: null, to: 'prospecting' }
|
|
116
|
+
// }
|
|
117
|
+
// }
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Querying Audit Logs
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
// Get audit logs via kernel
|
|
124
|
+
const auditService = kernel.getService('audit');
|
|
125
|
+
|
|
126
|
+
// Get all changes for a specific record
|
|
127
|
+
const recordHistory = await auditService.getRecordHistory({
|
|
128
|
+
object: 'opportunity',
|
|
129
|
+
recordId: '123',
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Get user activity
|
|
133
|
+
const userActivity = await auditService.getUserActivity({
|
|
134
|
+
userId: 'user:456',
|
|
135
|
+
from: '2024-01-01',
|
|
136
|
+
to: '2024-01-31',
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Search audit logs
|
|
140
|
+
const logs = await auditService.searchLogs({
|
|
141
|
+
action: 'delete',
|
|
142
|
+
object: 'account',
|
|
143
|
+
from: '2024-01-01',
|
|
144
|
+
to: '2024-01-31',
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Get failed actions (security monitoring)
|
|
148
|
+
const failures = await auditService.getFailedActions({
|
|
149
|
+
from: '2024-01-01',
|
|
150
|
+
limit: 100,
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Selective Tracking
|
|
155
|
+
|
|
156
|
+
### Track Specific Objects
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
PluginAudit.configure({
|
|
160
|
+
trackObjects: ['opportunity', 'account', 'contact'],
|
|
161
|
+
// Only these objects will be audited
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Track Specific Fields
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
PluginAudit.configure({
|
|
169
|
+
trackFields: {
|
|
170
|
+
opportunity: ['stage', 'amount', 'close_date'], // Only track these fields
|
|
171
|
+
account: '*', // Track all fields for accounts
|
|
172
|
+
contact: ['email', 'phone'], // Only email and phone for contacts
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Exclude System Users
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
PluginAudit.configure({
|
|
181
|
+
excludeUsers: [
|
|
182
|
+
'system:integration',
|
|
183
|
+
'system:cron',
|
|
184
|
+
'service:automation',
|
|
185
|
+
],
|
|
186
|
+
// These users' actions won't be audited
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Advanced Features
|
|
191
|
+
|
|
192
|
+
### Manual Audit Entries
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
// Log custom security event
|
|
196
|
+
await auditService.log({
|
|
197
|
+
action: 'security:password_reset',
|
|
198
|
+
userId: 'user:456',
|
|
199
|
+
metadata: {
|
|
200
|
+
resetMethod: 'email',
|
|
201
|
+
ipAddress: '192.168.1.100',
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Log business process event
|
|
206
|
+
await auditService.log({
|
|
207
|
+
action: 'workflow:approval',
|
|
208
|
+
object: 'opportunity',
|
|
209
|
+
recordId: '123',
|
|
210
|
+
metadata: {
|
|
211
|
+
approver: 'manager:789',
|
|
212
|
+
decision: 'approved',
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Audit Snapshots
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
// Create snapshot of record state at a specific time
|
|
221
|
+
const snapshot = await auditService.getRecordSnapshot({
|
|
222
|
+
object: 'opportunity',
|
|
223
|
+
recordId: '123',
|
|
224
|
+
asOf: '2024-01-15T10:30:00Z',
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// Returns: Record state as it existed on Jan 15, 2024 at 10:30 AM
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Audit Reports
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
// Generate compliance report
|
|
234
|
+
const report = await auditService.generateReport({
|
|
235
|
+
type: 'compliance',
|
|
236
|
+
from: '2024-01-01',
|
|
237
|
+
to: '2024-03-31',
|
|
238
|
+
format: 'pdf',
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Generate user activity report
|
|
242
|
+
const userReport = await auditService.generateReport({
|
|
243
|
+
type: 'user_activity',
|
|
244
|
+
userId: 'user:456',
|
|
245
|
+
from: '2024-01-01',
|
|
246
|
+
to: '2024-01-31',
|
|
247
|
+
includeDetails: true,
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Data Retention & Archival
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
// Archive old audit logs
|
|
255
|
+
await auditService.archiveLogs({
|
|
256
|
+
olderThan: '2023-01-01',
|
|
257
|
+
destination: 's3://audit-archive/2023/',
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Permanently delete archived logs (compliance approved)
|
|
261
|
+
await auditService.purgeLogs({
|
|
262
|
+
olderThan: '2020-01-01',
|
|
263
|
+
confirmed: true, // Safety check
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Security Events
|
|
268
|
+
|
|
269
|
+
The plugin automatically logs security-related events:
|
|
270
|
+
|
|
271
|
+
- **Authentication**: Login, logout, password changes
|
|
272
|
+
- **Authorization**: Permission denied, role changes
|
|
273
|
+
- **Data Access**: Read operations on sensitive fields
|
|
274
|
+
- **Configuration**: System setting changes
|
|
275
|
+
- **API**: API key usage, rate limit violations
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
// Automatically logged:
|
|
279
|
+
// - Login attempts (success/failure)
|
|
280
|
+
// - Permission denied errors
|
|
281
|
+
// - Sensitive field access
|
|
282
|
+
// - API authentication failures
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Compliance Integration
|
|
286
|
+
|
|
287
|
+
### GDPR Compliance
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
// Right to be forgotten - audit trail for deletions
|
|
291
|
+
await auditService.logDataDeletion({
|
|
292
|
+
userId: 'user:456',
|
|
293
|
+
reason: 'gdpr_right_to_be_forgotten',
|
|
294
|
+
deletedRecords: [
|
|
295
|
+
{ object: 'user', recordId: '456' },
|
|
296
|
+
{ object: 'contact', recordId: '789' },
|
|
297
|
+
],
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// Right of access - audit trail for data exports
|
|
301
|
+
await auditService.logDataExport({
|
|
302
|
+
userId: 'user:456',
|
|
303
|
+
reason: 'gdpr_data_access_request',
|
|
304
|
+
exportedObjects: ['user', 'contact', 'activity'],
|
|
305
|
+
});
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### SOC 2 Compliance
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
// Log administrative actions
|
|
312
|
+
await auditService.logAdminAction({
|
|
313
|
+
adminId: 'admin:123',
|
|
314
|
+
action: 'user_role_change',
|
|
315
|
+
targetUserId: 'user:456',
|
|
316
|
+
changes: {
|
|
317
|
+
roles: { from: ['user'], to: ['user', 'admin'] },
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### HIPAA Compliance
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
// Track PHI access
|
|
326
|
+
PluginAudit.configure({
|
|
327
|
+
trackFields: {
|
|
328
|
+
patient: ['ssn', 'medical_record_number', 'diagnosis'], // PHI fields
|
|
329
|
+
},
|
|
330
|
+
trackSystemEvents: true,
|
|
331
|
+
});
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## REST API Endpoints
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
GET /api/v1/audit # List audit logs
|
|
338
|
+
GET /api/v1/audit/:id # Get specific log entry
|
|
339
|
+
GET /api/v1/audit/record/:object/:id # Get record history
|
|
340
|
+
GET /api/v1/audit/user/:userId # Get user activity
|
|
341
|
+
POST /api/v1/audit/report # Generate report
|
|
342
|
+
POST /api/v1/audit/archive # Archive old logs
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Dashboard Integration
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
// Audit dashboard widget
|
|
349
|
+
const auditWidget = {
|
|
350
|
+
title: 'Recent Activity',
|
|
351
|
+
query: {
|
|
352
|
+
object: 'audit_log',
|
|
353
|
+
limit: 50,
|
|
354
|
+
sort: [{ field: 'timestamp', direction: 'desc' }],
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
// Security alerts dashboard
|
|
359
|
+
const securityWidget = {
|
|
360
|
+
title: 'Failed Login Attempts',
|
|
361
|
+
query: {
|
|
362
|
+
object: 'audit_log',
|
|
363
|
+
filters: [
|
|
364
|
+
{ field: 'action', operator: 'eq', value: 'auth:login' },
|
|
365
|
+
{ field: 'status', operator: 'eq', value: 'failed' },
|
|
366
|
+
{ field: 'timestamp', operator: 'gte', value: 'today' },
|
|
367
|
+
],
|
|
368
|
+
},
|
|
369
|
+
};
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## Best Practices
|
|
373
|
+
|
|
374
|
+
1. **Selective Tracking**: Only audit what's necessary for compliance
|
|
375
|
+
2. **Retention Policy**: Set appropriate retention based on regulations
|
|
376
|
+
3. **Performance**: Archive old logs to keep query performance high
|
|
377
|
+
4. **Security**: Restrict access to audit logs (admin only)
|
|
378
|
+
5. **Immutability**: Never allow modification of audit records
|
|
379
|
+
6. **Monitoring**: Set alerts for suspicious activity patterns
|
|
380
|
+
7. **Regular Review**: Periodically review audit logs for anomalies
|
|
381
|
+
|
|
382
|
+
## Performance Considerations
|
|
383
|
+
|
|
384
|
+
- **Async Logging**: Audit writes happen asynchronously (no performance impact)
|
|
385
|
+
- **Indexing**: Automatically indexes `userId`, `object`, `recordId`, `timestamp`
|
|
386
|
+
- **Partitioning**: Consider table partitioning for high-volume deployments
|
|
387
|
+
- **Archival**: Move old logs to cold storage (S3, Glacier)
|
|
388
|
+
|
|
389
|
+
## Contract Implementation
|
|
390
|
+
|
|
391
|
+
Implements audit logging hooks from `@objectstack/spec/contracts`:
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
interface IAuditService {
|
|
395
|
+
log(entry: AuditLogEntry): Promise<void>;
|
|
396
|
+
getRecordHistory(options: RecordHistoryOptions): Promise<AuditLog[]>;
|
|
397
|
+
getUserActivity(options: UserActivityOptions): Promise<AuditLog[]>;
|
|
398
|
+
searchLogs(filter: AuditLogFilter): Promise<AuditLog[]>;
|
|
399
|
+
getRecordSnapshot(options: SnapshotOptions): Promise<any>;
|
|
400
|
+
archiveLogs(options: ArchiveOptions): Promise<void>;
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
## License
|
|
405
|
+
|
|
406
|
+
Apache-2.0
|
|
407
|
+
|
|
408
|
+
## See Also
|
|
409
|
+
|
|
410
|
+
- [SOC 2 Compliance Guide](https://www.aicpa.org/interestareas/frc/assuranceadvisoryservices/sorhome)
|
|
411
|
+
- [GDPR Requirements](https://gdpr.eu/)
|
|
412
|
+
- [HIPAA Compliance](https://www.hhs.gov/hipaa/)
|
|
413
|
+
- [@objectstack/plugin-security](../plugin-security/)
|
|
414
|
+
- [Audit Logging Best Practices](/content/docs/guides/audit/)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/plugin-audit",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.4",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Audit Plugin for ObjectStack — System audit log object and audit trail",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@objectstack/core": "4.0.
|
|
17
|
-
"@objectstack/spec": "4.0.
|
|
16
|
+
"@objectstack/core": "4.0.4",
|
|
17
|
+
"@objectstack/spec": "4.0.4"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@types/node": "^25.6.0",
|