Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
The format is based on [Keep a Changelog](http://keepachangelog.com/).

## Version 0.7.0 - tbd
## Version 0.8.0 - TBD

### Added

- Default kind `audit-log-to-restv2` for profile `hybrid`
- Support for @sap/cds^8

## Version 0.7.0 - 2024-05-15

### Added

Expand Down
33 changes: 20 additions & 13 deletions cds-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ const { hasPersonalData } = require('./lib/utils')

const WRITE = ['CREATE', 'UPDATE', 'DELETE']

const _get_ancestry_of = (entity, service, ancestors = []) => {
for (const each of service.entities) {
for (const k in each.compositions) {
if (each.compositions[k].target === entity.name && k !== 'SiblingEntity') {
ancestors.push(each)
_get_ancestry_of(each, service, ancestors)
}
}
}
return ancestors
}

/*
* Add generic audit logging handlers
*/
Expand All @@ -15,24 +27,19 @@ cds.on('served', services => {
for (const service of services) {
if (!(service instanceof cds.ApplicationService)) continue

const relevantEntities = []
for (const entity of service.entities) if (hasPersonalData(entity)) relevantEntities.push(entity)
if (!relevantEntities.length) continue

// automatically promote entities that are associated with data subjects
for (const entity of relevantEntities) {
for (const entity of service.entities) {
if (entity['@PersonalData.EntitySemantics'] !== 'DataSubject') continue
for (const e of service.entities) {
for (const k in e.associations) {
if (e.associations[k].target === entity.name && k !== 'SiblingEntity') {
e['@PersonalData.EntitySemantics'] ??= 'Other'
e.associations[k]['@PersonalData.FieldSemantics'] ??= 'DataSubjectID'
if (!relevantEntities.includes(e)) relevantEntities.push(e)
}
}
const ancestors = _get_ancestry_of(entity, service)
for (const each of ancestors) {
each['@PersonalData.EntitySemantics'] ??= 'Other'
}
}

const relevantEntities = []
for (const entity of service.entities) if (hasPersonalData(entity)) relevantEntities.push(entity)
if (!relevantEntities.length) continue

for (const entity of relevantEntities) {
/*
* data access
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cap-js/audit-logging",
"version": "0.7.0",
"version": "0.8.0",
"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.",
"repository": "cap-js/audit-logging",
"author": "SAP SE (https://www.sap.com)",
Expand Down Expand Up @@ -44,6 +44,9 @@
"[development]": {
"kind": "audit-log-to-console"
},
"[hybrid]": {
"kind": "audit-log-to-restv2"
},
"[production]": {
"kind": "audit-log-to-restv2"
}
Expand Down
10 changes: 10 additions & 0 deletions test/personal-data/deep.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const cds = require('@sap/cds')

cds.test('serve', 'srv/deep-service.cds').in(__dirname)

describe('personal data audit logging for deep operations', () => {
test('promotions', async () => {
const { DeepService } = cds.services
debugger
})
})
41 changes: 41 additions & 0 deletions test/personal-data/srv/deep-service.cds
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
service DeepService {

entity Foo {
key ID : UUID;
bars : Composition of many Bar
on bars.foo = $self;
moos : Composition of many {
key ID : UUID;
descr : String;
shus : Composition of many {
key ID : UUID;
descr : String;
};
};
};

entity Bar {
key ID : UUID;
foo : Association to Foo;
descr : String;
bazs : Composition of many Baz
on bazs.bar = $self;
};

entity Baz {
key ID : UUID;
bar : Association to Bar;
descr : String;
};

annotate Baz with @PersonalData: {EntitySemantics: 'DataSubject'} {
ID @PersonalData : {FieldSemantics: 'DataSubjectID', };
descr @PersonalData.IsPotentiallyPersonal;
};

annotate Foo.moos.shus with @PersonalData: {EntitySemantics: 'DataSubject'} {
ID @PersonalData : {FieldSemantics: 'DataSubjectID', };
descr @PersonalData.IsPotentiallyPersonal;
};

}