diff --git a/cli/lib/scan/index.ts b/cli/lib/scan/index.ts index dbc1e67..5b88cff 100644 --- a/cli/lib/scan/index.ts +++ b/cli/lib/scan/index.ts @@ -1,5 +1,6 @@ // `storebound scan` engine: detect the project, run the rejection-risk rules, propose the declarations. Offline and // read-only (the only write is `--write`, done by the command, never here). +import { pgsFindings, readPgsProject } from '../game-services'; import { withoutTemplate } from '../template-answers'; import { existsSync, readFileSync } from 'node:fs'; import { join, relative, resolve } from 'node:path'; @@ -63,6 +64,15 @@ export async function runScan(dir: string, o: { config?: string } = {}): Promise return { type: d.type, missing: [...new Set(missing)].join(', '), evidence: d.evidence }; }).filter(d => d.missing) : []; const findings = scanRules({ facts, config, configFile, listings, demoAccount: !!reviewDemoAccount(dir), labelGaps: declarations.labelGaps, dataMerges }); + // Play Games Services: the Gradle dependency without the APP_ID meta-data / resource fails sign-in at runtime + if (facts.android) { + try { + const pgs = readPgsProject(dir); + for (const g of pgsFindings(config ?? {}, pgs).filter(x => x.level === 'error' && !(config?.scan?.ignore ?? []).some(i => i.rule === x.id))) + findings.push({ rule: g.id, guideline: 'Play Games Services setup', store: 'play', severity: 'high', title: g.msg, evidence: [{ file: pgs.manifest?.file ?? pgs.gradle[0] ?? 'android', line: 1, text: pgs.manifest?.value ?? 'play-services-games-v2' }], + fix: g.fix ?? '', skill: 'game-services', ref: 'https://developer.android.com/games/pgs/android/android-start' }); + } catch { /* unreadable Android project */ } + } for (const f of findings) { const action = f.accepted ? undefined : scanFixAction(f.rule, { configPath, declarationsChanged: declarations.changed }); if (action) f.action = action;