play data-safety: PSL_SUPPORT_DATA_DELETION_BY_USER as Play's single choice (partialDeletion true | false | 'auto90'), drop the removed PSL_DATA_COLLECTION_USER_REQUEST_DELETE (deletionRequest deprecated, check notes it); ship Google's empty form (cli/data/play-data-safety-form.csv, exported 2026-10-12), take every Answer requirement from it and report pairs not in it (formPairIssues) in check, declarations and play data-safety. Pitfall 21

This commit is contained in:
CRTkafa 2026-10-12 09:33:56 +08:00
parent dfc28c15f8
commit b5b8f2da9d
35 changed files with 1824 additions and 859 deletions

View file

@ -24,7 +24,7 @@ describe('declarations', () => {
});
test('Data safety answers become App Privacy suggestions; linked / tracking stay questions', () => {
const cfg = base({
dataSafety: { collectsData: true, encryptedInTransit: true, deletionRequest: true, data: {
dataSafety: { collectsData: true, encryptedInTransit: true, data: {
PSL_DEVICE_ID: { shared: true, collect: ['analytics'], share: ['advertising'] }, PSL_CRASH_LOGS: { shared: false, collect: ['analytics'] } } },
apple: { bundleId: 'com.example.demo', usesNonExemptEncryption: false, info: { categories: { primary: 'UTILITIES' }, ageRating: {}, contentRights: 'DOES_NOT_USE_THIRD_PARTY_CONTENT' } },
reviewAccess: { signInRequired: false },
@ -39,12 +39,12 @@ describe('declarations', () => {
expect(applePurpose('communications')).toBe('App Functionality');
});
test('changes since the last upload compare answers, not labels', () => {
const ds = { collectsData: true, encryptedInTransit: true, deletionRequest: false, data: { PSL_CRASH_LOGS: { shared: false, collect: ['analytics' as const] } } };
const ds = { collectsData: true, encryptedInTransit: false, data: { PSL_CRASH_LOGS: { shared: false, collect: ['analytics' as const] } } };
const before = dataSafetyCsv(ds);
expect(dataSafetyChanges(before, before)).toEqual([]);
const after = dataSafetyCsv({ ...ds, deletionRequest: true });
expect(dataSafetyChanges(before, after)).toEqual([{ question: 'PSL_DATA_COLLECTION_USER_REQUEST_DELETE', response: '', from: 'FALSE', to: 'TRUE' }]);
const d = declarations(base({ dataSafety: { ...ds, deletionRequest: true } }), { ...none, uploaded: { csv: before, at: '2026-10-01T00:00:00Z' } });
const after = dataSafetyCsv({ ...ds, encryptedInTransit: true });
expect(dataSafetyChanges(before, after)).toEqual([{ question: 'PSL_DATA_COLLECTION_ENCRYPTED_IN_TRANSIT', response: '', from: 'FALSE', to: 'TRUE' }]);
const d = declarations(base({ dataSafety: { ...ds, encryptedInTransit: true } }), { ...none, uploaded: { csv: before, at: '2026-10-01T00:00:00Z' } });
expect(d.dataSafety!.uploaded!.changes.length).toBe(1);
});
});