@cap-js/audit-logging 0.2.0 → 0.3.1

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 (3) hide show
  1. package/README.md +2 -1
  2. package/lib/utils.js +17 -18
  3. package/package.json +19 -18
package/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # Welcome to @cap-js/audit-logging
2
+ [![REUSE status](https://api.reuse.software/badge/github.com/cap-js/audit-logging)](https://api.reuse.software/info/github.com/cap-js/audit-logging)
2
3
 
3
4
  ## About this project
4
5
 
@@ -10,7 +11,7 @@ Documentation can be found at [cap.cloud.sap](https://cap.cloud.sap/docs/guides/
10
11
 
11
12
  See [Getting Started](https://cap.cloud.sap/docs/get-started) on how to jumpstart your development and grow as you go with SAP Cloud Application Programming Model.
12
13
 
13
- The end-to-end out-of-the-box functionality provided by this plugin requires a paid-for instance of the [SAP Audit Logging Service for SAP BTP]([url](https://help.sap.com/docs/application-logging-service?locale=en-US)). However, it is possible to provide an own implementation that writes the audit logs to a custom store.
14
+ The end-to-end out-of-the-box functionality provided by this plugin requires a paid-for instance of the [SAP Audit Log service for customers](https://help.sap.com/docs/btp/sap-business-technology-platform/audit-log-write-api-for-customers?locale=en-US). However, it is possible to provide an own implementation that writes the audit logs to a custom store.
14
15
 
15
16
  ## Support, Feedback, Contributing
16
17
 
package/lib/utils.js CHANGED
@@ -1,8 +1,10 @@
1
1
  const WRITE = { CREATE: 1, UPDATE: 1, DELETE: 1 }
2
2
 
3
3
  const hasPersonalData = entity => {
4
- if (!entity['@PersonalData.DataSubjectRole']) return
5
4
  if (!entity['@PersonalData.EntitySemantics']) return
5
+ // default role to entity name
6
+ if (entity['@PersonalData.EntitySemantics'] === 'DataSubject' && !entity['@PersonalData.DataSubjectRole'])
7
+ entity['@PersonalData.DataSubjectRole'] = entity.name.match(/\w+/g).pop()
6
8
  return !!Object.values(entity.elements).some(
7
9
  element =>
8
10
  element['@PersonalData.IsPotentiallyPersonal'] ||
@@ -148,31 +150,27 @@ const _getUps = (entity, model) => {
148
150
  return entity.set('__parents', ups)
149
151
  }
150
152
 
151
- const _ifDataSubject = (entity, role) => {
152
- return entity['@PersonalData.EntitySemantics'] === 'DataSubject' && entity['@PersonalData.DataSubjectRole'] === role
153
- }
154
-
155
- const _getDataSubjectUp = (role, model, entity, prev, next, result) => {
153
+ const _getDataSubjectUp = (model, entity, prev, next, result) => {
156
154
  for (const element of _getUps(entity, model)) {
157
155
  const me = { entity, relative: element.parent, element }
158
156
  if (prev) prev.next = me
159
- if (_ifDataSubject(element.parent, role)) {
157
+ if (element.parent['@PersonalData.EntitySemantics'] === 'DataSubject') {
160
158
  if (!result) result = { dataSubjectEntity: element.parent, subs: [] }
161
159
  result.subs.push(next || me)
162
160
  return result
163
161
  } else {
164
162
  // dfs is a must here
165
- result = _getDataSubjectUp(role, model, element.parent, me, next || me, result)
163
+ result = _getDataSubjectUp(model, element.parent, me, next || me, result)
166
164
  }
167
165
  }
168
166
  return result
169
167
  }
170
168
 
171
- const _getDataSubjectDown = (role, entity, prev, next) => {
169
+ const _getDataSubjectDown = (entity, prev, next) => {
172
170
  const associations = Object.values(entity.associations || {}).filter(e => !e._isBacklink)
173
171
  for (const element of associations) {
174
172
  const me = { entity, relative: entity, element }
175
- if (_ifDataSubject(element._target, role)) {
173
+ if (element._target['@PersonalData.EntitySemantics'] === 'DataSubject') {
176
174
  if (prev) prev.next = me
177
175
  return { dataSubjectEntity: element._target, subs: [next || me] }
178
176
  }
@@ -181,24 +179,25 @@ const _getDataSubjectDown = (role, entity, prev, next) => {
181
179
  for (const element of associations) {
182
180
  const me = { entity, relative: entity, element }
183
181
  if (prev) prev.next = me
184
- const dataSubject = _getDataSubjectDown(role, element._target, me, next || me)
182
+ const dataSubject = _getDataSubjectDown(element._target, me, next || me)
185
183
  if (dataSubject) return dataSubject
186
184
  }
187
185
  }
188
186
 
189
- const getDataSubject = (entity, model, role) => {
190
- const hash = '__dataSubject4' + role
187
+ const getDataSubject = (entity, model) => {
188
+ const hash = '__dataSubject'
191
189
  if (entity.own(hash)) return entity[hash]
192
190
  // entities with EntitySemantics 'DataSubjectDetails' or 'Other' must not necessarily
193
191
  // be always below or always above 'DataSubject' entity in CSN tree
194
- let dataSubject = _getDataSubjectUp(role, model, entity)
195
- if (!dataSubject) dataSubject = _getDataSubjectDown(role, entity)
196
- return entity.set(hash, dataSubject)
192
+ let dataSubjectInfo = _getDataSubjectUp(model, entity)
193
+ if (!dataSubjectInfo) dataSubjectInfo = _getDataSubjectDown(entity)
194
+ return entity.set(hash, dataSubjectInfo)
197
195
  }
198
196
 
199
197
  const addDataSubjectForDetailsEntity = (row, log, req, entity, model) => {
200
- const role = entity['@PersonalData.DataSubjectRole']
201
- const dataSubjectInfo = getDataSubject(entity, model, role)
198
+ const dataSubjectInfo = getDataSubject(entity, model)
199
+ const role = dataSubjectInfo.dataSubjectEntity['@PersonalData.DataSubjectRole']
200
+ log.data_subject.role ??= role
202
201
  log.data_subject.type = dataSubjectInfo.dataSubjectEntity.name
203
202
  /*
204
203
  * for each req (cf. $batch with atomicity) and data subject role (e.g., customer vs supplier),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cap-js/audit-logging",
3
- "version": "0.2.0",
4
- "description": "CDS plugin providing integration to the SAP BTP Audit Logging Service as well as out-of-the-box personal data-related audit logging based on annotations.",
3
+ "version": "0.3.1",
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)",
7
7
  "homepage": "https://cap.cloud.sap/",
@@ -19,27 +19,28 @@
19
19
  "@sap/cds": "^7"
20
20
  },
21
21
  "devDependencies": {
22
- "@cap-js/sqlite": "^1.0.1",
23
- "axios": "^1.4.0",
22
+ "@cap-js/sqlite": "^1",
23
+ "axios": "^1",
24
+ "better-sqlite3": "8.5.2",
24
25
  "eslint": "^8",
25
- "express": "^4.18.2",
26
- "jest": "^29.5.0"
26
+ "express": "^4",
27
+ "jest": "^29"
27
28
  },
28
29
  "cds": {
29
30
  "requires": {
30
- "audit-log": true,
31
- "kinds": {
32
- "audit-log": {
33
- "handle": [
34
- "WRITE"
35
- ],
36
- "[development]": {
37
- "kind": "audit-log-to-console"
38
- },
39
- "[production]": {
40
- "kind": "audit-log-to-restv2"
41
- }
31
+ "audit-log": {
32
+ "handle": [
33
+ "READ",
34
+ "WRITE"
35
+ ],
36
+ "[development]": {
37
+ "kind": "audit-log-to-console"
42
38
  },
39
+ "[production]": {
40
+ "kind": "audit-log-to-restv2"
41
+ }
42
+ },
43
+ "kinds": {
43
44
  "audit-log-to-console": {
44
45
  "impl": "@cap-js/audit-logging/srv/log2console",
45
46
  "outbox": false