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

@ -23,7 +23,7 @@ const base: ShipConfig = {
apple: { bundleId: 'com.example.game' },
play: { packageName: 'com.example.game' },
dataSafety: {
collectsData: true, encryptedInTransit: true, deletionRequest: false,
collectsData: true, encryptedInTransit: true,
data: {
PSL_DEVICE_ID: { shared: true, collect: ['advertising', 'analytics'], share: ['advertising'] },
PSL_APPROX_LOCATION: { shared: true, collect: ['advertising', 'analytics'], share: ['advertising'] },
@ -144,16 +144,19 @@ describe('check: appPrivacy.types against the iOS project', () => {
try {
writeFileSync(join(dir, '.gitignore'), '.storebound/\n');
const c = { app: base.app, languages: base.languages, accounts: { enabled: true, signUp: ['username'] },
dataSafety: { collectsData: true, encryptedInTransit: true, deletionRequest: true, accountCreation: ['PSL_ACM_USER_ID_OTHER_AUTH'], partialDeletion: false,
dataSafety: { collectsData: true, encryptedInTransit: true, deletionRequest: true, accountCreation: ['PSL_ACM_USER_ID_OTHER_AUTH'], partialDeletion: false, // deletionRequest: deprecated, a note
data: { PSL_USER_ACCOUNT: { shared: false, collect: ['account'] } } } } as ShipConfig;
const out: string[] = [];
const orig = console.log;
console.log = (s: string) => { out.push(s); };
try { await check({ loaded: { config: c, root: dir, path: join(dir, 'storebound.config.ts'), resolve: p => join(dir, p) }, args: parseArgs(['--json']) }); }
finally { console.log = orig; process.exitCode = 0; }
const problems = (JSON.parse(out.at(-1)!).problems as string[]).join('\n');
const res = JSON.parse(out.at(-1)!) as { problems: string[]; warnings: string[] };
const problems = res.problems.join('\n');
expect(problems).toContain('data safety: missing: PSL_ACCOUNT_DELETION_URL');
expect(problems).toContain('set accounts.deletionUrl');
expect(problems).not.toContain('PSL_SUPPORT_DATA_DELETION_BY_USER');
expect(res.warnings.join('\n')).toContain('dataSafety.deletionRequest is no longer used: Play removed that question');
} finally { rmSync(dir, { recursive: true, force: true }); }
});