@cap-js/audit-logging 1.0.0 → 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.
- package/package.json +6 -8
- package/srv/log2alsng.js +53 -17
- package/CHANGELOG.md +0 -164
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cap-js/audit-logging",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "CDS plugin providing integration to the SAP Audit Log service as well as out-of-the-box personal data-related audit logging based on annotations.",
|
|
5
5
|
"repository": "cap-js/audit-logging",
|
|
6
6
|
"author": "SAP SE (https://www.sap.com)",
|
|
@@ -9,11 +9,10 @@
|
|
|
9
9
|
"main": "cds-plugin.js",
|
|
10
10
|
"files": [
|
|
11
11
|
"lib",
|
|
12
|
-
"srv"
|
|
13
|
-
"CHANGELOG.md"
|
|
12
|
+
"srv"
|
|
14
13
|
],
|
|
15
14
|
"scripts": {
|
|
16
|
-
"lint": "npx eslint .",
|
|
15
|
+
"lint": "npx eslint . --max-warnings=0",
|
|
17
16
|
"test": "npx jest --silent"
|
|
18
17
|
},
|
|
19
18
|
"peerDependencies": {
|
|
@@ -26,13 +25,12 @@
|
|
|
26
25
|
"axios": "^1",
|
|
27
26
|
"eslint": "^9",
|
|
28
27
|
"express": "^4",
|
|
29
|
-
"jest": "^29"
|
|
28
|
+
"jest": "^29",
|
|
29
|
+
"pretty-quick": "^4.2.2",
|
|
30
|
+
"simple-git-hooks": "^2.13.1"
|
|
30
31
|
},
|
|
31
32
|
"cds": {
|
|
32
33
|
"requires": {
|
|
33
|
-
"[test]": {
|
|
34
|
-
"outbox": "persistent-outbox"
|
|
35
|
-
},
|
|
36
34
|
"audit-log": {
|
|
37
35
|
"handle": [
|
|
38
36
|
"READ",
|
package/srv/log2alsng.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const cds = require('@sap/cds')
|
|
2
|
-
|
|
3
2
|
const LOG = cds.log('audit-log')
|
|
4
3
|
|
|
5
4
|
const https = require('https')
|
|
@@ -12,7 +11,7 @@ module.exports = class AuditLog2ALSNG extends AuditLogService {
|
|
|
12
11
|
this._vcap = JSON.parse(process.env.VCAP_SERVICES || '{}')
|
|
13
12
|
this._userProvided = this._vcap['user-provided']?.find(obj => obj.tags.includes('auditlog-ng')) || {}
|
|
14
13
|
if (!this._userProvided.credentials) throw new Error('No credentials found for SAP Audit Log Service NG')
|
|
15
|
-
this._vcapApplication =
|
|
14
|
+
this._vcapApplication = JSON.parse(process.env.VCAP_APPLICATION || '{}')
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
async init() {
|
|
@@ -24,12 +23,22 @@ module.exports = class AuditLog2ALSNG extends AuditLogService {
|
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
eventMapper(event, data) {
|
|
27
|
-
|
|
26
|
+
const known = {
|
|
28
27
|
PersonalDataModified: () => this.logEvent('dppDataModification', data),
|
|
29
28
|
SensitiveDataRead: () => this.logEvent('dppDataAccess', data),
|
|
30
29
|
ConfigurationModified: () => this.logEvent('configurationChange', data),
|
|
31
30
|
SecurityEvent: () => this.logEvent('legacySecurityWrapper', data)
|
|
32
|
-
}
|
|
31
|
+
}
|
|
32
|
+
const dfault = () => this.logEvent(event, data)
|
|
33
|
+
return (known[event] ?? dfault)()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
flattenAndSortIdObject(id) {
|
|
37
|
+
if (!id || !Object.keys(id).length) return 'not provided'
|
|
38
|
+
|
|
39
|
+
let s = ''
|
|
40
|
+
for (const k of Object.keys(id).sort()) s += `${k}:${id[k]} `
|
|
41
|
+
return s.trim()
|
|
33
42
|
}
|
|
34
43
|
|
|
35
44
|
eventDataPayload(event, data) {
|
|
@@ -37,11 +46,12 @@ module.exports = class AuditLog2ALSNG extends AuditLogService {
|
|
|
37
46
|
const channel = data['channel'] || { type: 'not specified', id: 'not specified' }
|
|
38
47
|
const subject = data['data_subject'] || { type: 'not provided', id: { ID: 'not provided' } }
|
|
39
48
|
const attributes = data['attributes'] || [{ name: 'not provided', old: 'not provided', new: 'not provided' }]
|
|
40
|
-
const objectId = object['id']
|
|
49
|
+
const objectId = this.flattenAndSortIdObject(object['id'])
|
|
41
50
|
const oldValue = attributes[0]['old'] ?? ''
|
|
42
51
|
const newValue = attributes[0]['new'] ?? ''
|
|
43
|
-
const dataSubjectId = subject['id']
|
|
44
|
-
|
|
52
|
+
const dataSubjectId = this.flattenAndSortIdObject(subject['id'])
|
|
53
|
+
|
|
54
|
+
const known = {
|
|
45
55
|
dppDataModification: {
|
|
46
56
|
objectType: object['type'],
|
|
47
57
|
objectId: objectId,
|
|
@@ -76,7 +86,26 @@ module.exports = class AuditLog2ALSNG extends AuditLogService {
|
|
|
76
86
|
: data.data
|
|
77
87
|
})
|
|
78
88
|
}
|
|
79
|
-
}
|
|
89
|
+
}
|
|
90
|
+
if (event in known) return known[event]
|
|
91
|
+
|
|
92
|
+
// For unknown events, remove common audit log entry fields from the event payload
|
|
93
|
+
if (typeof data === 'object' && data !== null) {
|
|
94
|
+
const rest = this.removeCommonAuditLogFields(data)
|
|
95
|
+
return rest
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return data
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
removeCommonAuditLogFields(obj) {
|
|
102
|
+
if (typeof obj !== 'object' || obj === null) return obj
|
|
103
|
+
const { ...rest } = obj
|
|
104
|
+
delete rest.uuid
|
|
105
|
+
delete rest.user
|
|
106
|
+
delete rest.time
|
|
107
|
+
delete rest.tenant
|
|
108
|
+
return rest
|
|
80
109
|
}
|
|
81
110
|
|
|
82
111
|
eventPayload(event, data) {
|
|
@@ -113,23 +142,30 @@ module.exports = class AuditLog2ALSNG extends AuditLogService {
|
|
|
113
142
|
return eventData
|
|
114
143
|
}
|
|
115
144
|
|
|
116
|
-
|
|
117
|
-
const passphrase = this._userProvided.credentials?.keyPassphrase
|
|
118
|
-
const url = new URL(`${this._userProvided.credentials?.url}/ingestion/v1/events`)
|
|
119
|
-
let eventData = []
|
|
120
|
-
|
|
145
|
+
formatEventData(event, data) {
|
|
121
146
|
if (event === 'legacySecurityWrapper') {
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
147
|
+
return JSON.stringify([this.eventPayload(event, data)])
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (event in { dppDataModification: 1, dppDataAccess: 1, configurationChange: 1 }) {
|
|
151
|
+
const eventData = data['attributes']?.map(attr => {
|
|
125
152
|
return this.eventPayload(event, {
|
|
126
153
|
...data,
|
|
127
154
|
attributes: [attr]
|
|
128
155
|
})
|
|
129
156
|
})
|
|
130
|
-
|
|
157
|
+
return JSON.stringify(eventData || [])
|
|
131
158
|
}
|
|
132
159
|
|
|
160
|
+
// Always wrap event in an envelope for custom events
|
|
161
|
+
return JSON.stringify([this.eventPayload(event, data)])
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
logEvent(event, data) {
|
|
165
|
+
const passphrase = this._userProvided.credentials?.keyPassphrase
|
|
166
|
+
const url = new URL(`${this._userProvided.credentials?.url}/ingestion/v1/events`)
|
|
167
|
+
const eventData = this.formatEventData(event, data)
|
|
168
|
+
|
|
133
169
|
const options = {
|
|
134
170
|
method: 'POST',
|
|
135
171
|
headers: {
|
package/CHANGELOG.md
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
# Change Log
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
5
|
-
The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
6
|
-
|
|
7
|
-
## Version 1.0.0 - 2025-07-11
|
|
8
|
-
|
|
9
|
-
### Added
|
|
10
|
-
|
|
11
|
-
- Beta support for next generation SAP Audit Log Service
|
|
12
|
-
- Use explicit kind `audit-log-to-alsng` or alpha auto-detect kind `audit-log-to-als`
|
|
13
|
-
|
|
14
|
-
## Version 0.9.0 - 2025-06-05
|
|
15
|
-
|
|
16
|
-
### Added
|
|
17
|
-
|
|
18
|
-
- Support for `@sap/cds^9`
|
|
19
|
-
|
|
20
|
-
## Version 0.8.3 - 2025-04-09
|
|
21
|
-
|
|
22
|
-
### Fixed
|
|
23
|
-
|
|
24
|
-
- Preperation for `@sap/cds^9`
|
|
25
|
-
|
|
26
|
-
## Version 0.8.2 - 2024-11-27
|
|
27
|
-
|
|
28
|
-
### Fixed
|
|
29
|
-
|
|
30
|
-
- Erroneous modification log for non-updated key properties
|
|
31
|
-
- Error during non-modifying queries on database level
|
|
32
|
-
- Specify charset UTF-8 for requests to SAP Audit Log Service
|
|
33
|
-
|
|
34
|
-
## Version 0.8.1 - 2024-09-13
|
|
35
|
-
|
|
36
|
-
### Fixed
|
|
37
|
-
|
|
38
|
-
- Support for `@sap/cds^8.2`
|
|
39
|
-
- Reduce clutter in error raised for outbound requests
|
|
40
|
-
|
|
41
|
-
## Version 0.8.0 - 2024-05-24
|
|
42
|
-
|
|
43
|
-
### Added
|
|
44
|
-
|
|
45
|
-
- Allow to specify undefined tenant in order to log to provider account in multi-tenant scenarios
|
|
46
|
-
|
|
47
|
-
### Changed
|
|
48
|
-
|
|
49
|
-
- Use kind `audit-log-to-restv2` in profile `hybrid`
|
|
50
|
-
|
|
51
|
-
## Version 0.7.0 - 2024-05-15
|
|
52
|
-
|
|
53
|
-
### Added
|
|
54
|
-
|
|
55
|
-
- Automatically promote entities that are associated with data subjects
|
|
56
|
-
|
|
57
|
-
## Version 0.6.0 - 2024-02-05
|
|
58
|
-
|
|
59
|
-
### Added
|
|
60
|
-
|
|
61
|
-
- Support for `@sap/cds^7.5`
|
|
62
|
-
|
|
63
|
-
### Fixed
|
|
64
|
-
|
|
65
|
-
- Automatic personal data modification logging for data subject details with renamed keys
|
|
66
|
-
- Data subject resolution in circular models
|
|
67
|
-
|
|
68
|
-
## Version 0.5.2 - 2023-12-08
|
|
69
|
-
|
|
70
|
-
### Fixed
|
|
71
|
-
|
|
72
|
-
- Automatic personal data modification logging for deep data structures with renamings
|
|
73
|
-
|
|
74
|
-
## Version 0.5.1 - 2023-11-30
|
|
75
|
-
|
|
76
|
-
### Fixed
|
|
77
|
-
|
|
78
|
-
- Falsy early exit during bootstrapping in case a service does not contain personal data
|
|
79
|
-
|
|
80
|
-
## Version 0.5.0 - 2023-11-22
|
|
81
|
-
|
|
82
|
-
### Added
|
|
83
|
-
|
|
84
|
-
- Common log entry fields `uuid`, `tenant`, `user` and `time` can be provided manually
|
|
85
|
-
|
|
86
|
-
## Version 0.4.0 - 2023-10-24
|
|
87
|
-
|
|
88
|
-
### Added
|
|
89
|
-
|
|
90
|
-
- Support for Premium plan of SAP Audit Log Service
|
|
91
|
-
- Support for XSUAA credential type `x509`
|
|
92
|
-
- Support for generic outbox
|
|
93
|
-
|
|
94
|
-
### Changed
|
|
95
|
-
|
|
96
|
-
- Always use outbox (as configured in project)
|
|
97
|
-
|
|
98
|
-
### Fixed
|
|
99
|
-
|
|
100
|
-
- Avoid dangling `SELECT`s to resolve data subject IDs, which resulted in "Transaction already closed" errors
|
|
101
|
-
|
|
102
|
-
## Version 0.3.2 - 2023-10-11
|
|
103
|
-
|
|
104
|
-
### Fixed
|
|
105
|
-
|
|
106
|
-
- If the request has no tenant (e.g., Unauthorized), the audit log shall be sent to the provider account
|
|
107
|
-
|
|
108
|
-
## Version 0.3.1 - 2023-09-25
|
|
109
|
-
|
|
110
|
-
### Fixed
|
|
111
|
-
|
|
112
|
-
- Defaulting of `@PersonalData.DataSubjectRole` to entity name
|
|
113
|
-
- Overriding service configuration
|
|
114
|
-
|
|
115
|
-
## Version 0.3.0 - 2023-09-05
|
|
116
|
-
|
|
117
|
-
### Changed
|
|
118
|
-
|
|
119
|
-
- Default value for `cds.requires['audit-log'].handle` changed to `['READ', 'WRITE']`, i.e., accessing sensitive data is now logged by default.
|
|
120
|
-
|
|
121
|
-
## Version 0.2.0 - 2023-09-01
|
|
122
|
-
|
|
123
|
-
### Added
|
|
124
|
-
|
|
125
|
-
- Export class `AuditLogService` for extending in custom implementations as follows:
|
|
126
|
-
```js
|
|
127
|
-
const { AuditLogService } = require('@cap-js/audit-logging')
|
|
128
|
-
class MyAuditLogService extends AuditLogService {
|
|
129
|
-
async init() {
|
|
130
|
-
[...]
|
|
131
|
-
// call AuditLogService's init
|
|
132
|
-
await super.init()
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
module.exports = MyAuditLogService
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## Version 0.1.0 - 2023-08-18
|
|
139
|
-
|
|
140
|
-
### Added
|
|
141
|
-
|
|
142
|
-
- New API:
|
|
143
|
-
- `await audit.log('<event>', <data>)` for asynchronous logs (cf. `emit`)
|
|
144
|
-
- `await audit.logSync('<event>', <data>)` for synchronous logs (cf. `send`)
|
|
145
|
-
- New REST API-based schema with auto-filled `LogEntry` aspect
|
|
146
|
-
- New events `SensitiveDataRead`, `PersonalDataModified`, `ConfigurationModified`, and `SecurityEvent`
|
|
147
|
-
- Full support for OAuth2 plan of SAP Audit Log Service
|
|
148
|
-
|
|
149
|
-
### Changed
|
|
150
|
-
|
|
151
|
-
- Whether reading sensitive data and modifying personal data is logged is determined by `cds.requires['audit-log'].handle: [...]`.
|
|
152
|
-
Possible values in the array are `READ` and/ or `WRITE`, with `WRITE` as the sole default entry.
|
|
153
|
-
Hence, accessing sensitive data is not logged by default.
|
|
154
|
-
- Integration with SAP Audit Log Service via REST API instead of client library (`@sap/audit-logging`)
|
|
155
|
-
|
|
156
|
-
### Fixed
|
|
157
|
-
|
|
158
|
-
- Various glitches in log calculation
|
|
159
|
-
|
|
160
|
-
### Removed
|
|
161
|
-
|
|
162
|
-
- Old events `dataAccessLog`, `dataModificationLog`, `configChangeLog`, and `securityLog`
|
|
163
|
-
- `@AuditLog.Operation` annotations are ignored. Having the plugin as dependency signals the intent to audit log.
|
|
164
|
-
- `cds.features.audit_personal_data: true` is no longer necessary. Instead, simply add the plugin as a dependency.
|