diff --git a/cds-plugin.js b/cds-plugin.js index 84ffcdb..04cf1e1 100644 --- a/cds-plugin.js +++ b/cds-plugin.js @@ -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 */ @@ -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 diff --git a/test/personal-data/deep.test.js b/test/personal-data/deep.test.js new file mode 100644 index 0000000..222b995 --- /dev/null +++ b/test/personal-data/deep.test.js @@ -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 + }) +}) diff --git a/test/personal-data/srv/deep-service.cds b/test/personal-data/srv/deep-service.cds new file mode 100644 index 0000000..b8943a1 --- /dev/null +++ b/test/personal-data/srv/deep-service.cds @@ -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; + }; + +}