diff --git a/mobile-uni/androidPrivacy.json.example b/mobile-uni/androidPrivacy.json.example index 10c74d8f..02098ea7 100644 --- a/mobile-uni/androidPrivacy.json.example +++ b/mobile-uni/androidPrivacy.json.example @@ -1,35 +1,4 @@ { - "version": "20260728", - "prompt": "template", - "title": "服务协议和隐私政策", - "message": "  请你审慎阅读并充分理解《服务协议》和《隐私政策》。为了提供登录、录音转写、图片/视频/文件上传和故障排查服务,本应用会在你使用相应功能时请求必要的设备和文件访问权限。你可阅读《服务协议》和《隐私政策》了解详细信息。点击“同意并继续”即表示你同意上述协议。", - "buttonAccept": "同意并继续", - "buttonRefuse": "暂不同意", - "hrefLoader": "system", - "backToExit": "false", - "second": { - "title": "确认提示", - "message": "  进入应用前,请先阅读并同意《服务协议》和《隐私政策》。", - "buttonAccept": "同意并继续", - "buttonRefuse": "退出应用" - }, - "disagreeMode": { - "support": false, - "loadNativePlugins": false, - "visitorEntry": false, - "showAlways": false - }, - "styles": { - "backgroundColor": "#FFFFFF", - "borderRadius": "12px", - "title": { - "color": "#1F2329" - }, - "buttonAccept": { - "color": "#E60012" - }, - "buttonRefuse": { - "color": "#6B7280" - } - } + "version": "20260729", + "prompt": "none" } diff --git a/mobile-uni/package-lock.json b/mobile-uni/package-lock.json index 01f3db97..30595a66 100644 --- a/mobile-uni/package-lock.json +++ b/mobile-uni/package-lock.json @@ -1,12 +1,12 @@ { "name": "aihr-mobile-uni", - "version": "0.1.10", + "version": "0.1.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "aihr-mobile-uni", - "version": "0.1.10", + "version": "0.1.11", "dependencies": { "@dcloudio/uni-app": "3.0.0-alpha-5020220260725001", "@dcloudio/uni-app-plus": "3.0.0-alpha-5020220260725001", diff --git a/mobile-uni/package.json b/mobile-uni/package.json index c836f8b5..e8564770 100644 --- a/mobile-uni/package.json +++ b/mobile-uni/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "aihr-mobile-uni", - "version": "0.1.10", + "version": "0.1.11", "private": true, "type": "module", "scripts": { @@ -10,10 +10,11 @@ "build:h5": "uni build -p h5", "build:app": "uni build -p app && node scripts/sync-app-native-resources.mjs", "generate:app-assets": "sh scripts/generate-app-assets.sh", - "configure:app-privacy": "node scripts/configure-android-privacy.mjs", + "configure:app-legal": "node scripts/configure-android-privacy.mjs", + "configure:app-privacy": "npm run configure:app-legal", "verify:app-assets": "node scripts/verify-app-assets.mjs", "verify:android-apk": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/verify-android-apk.ps1", - "verify:app-release": "node scripts/verify-app-assets.mjs --require-privacy --check-legal-urls", + "verify:app-release": "node scripts/verify-app-assets.mjs --require-legal-consent --check-legal-urls", "test:unit": "node --test tests/*.test.mjs", "typecheck": "vue-tsc --noEmit" }, diff --git a/mobile-uni/scripts/app-legal-config.mjs b/mobile-uni/scripts/app-legal-config.mjs index 010953e5..8f9c1c55 100644 --- a/mobile-uni/scripts/app-legal-config.mjs +++ b/mobile-uni/scripts/app-legal-config.mjs @@ -74,43 +74,39 @@ export const validateLegalUrlPair = (termsValue, privacyValue) => { return { termsUrl, privacyUrl }; }; -const extractLinks = (message) => - [...String(message || '').matchAll(/href="([^"]+)"/g)].map((match) => match[1]); - export const validateAndroidPrivacyDocument = (privacy) => { if (!privacy || typeof privacy !== 'object') { throw new Error('androidPrivacy.json must contain a JSON object'); } - if (privacy.prompt !== 'template') { - throw new Error('androidPrivacy.json must use prompt=template'); + if (privacy.prompt !== 'none') { + throw new Error('androidPrivacy.json must use prompt=none for the controlled internal App'); } if (!/^[1-9]\d*$/.test(String(privacy.version || ''))) { - throw new Error('androidPrivacy.json version must be a positive numeric policy version'); + throw new Error('androidPrivacy.json version must be a positive numeric configuration version'); } - if (privacy.hrefLoader !== 'system') { - throw new Error('androidPrivacy.json must open legal links with hrefLoader=system'); + for (const templateOnlyField of [ + 'title', + 'message', + 'buttonAccept', + 'buttonRefuse', + 'hrefLoader', + 'second', + 'disagreeMode', + 'styles' + ]) { + if (Object.hasOwn(privacy, templateOnlyField)) { + throw new Error(`androidPrivacy.json prompt=none must not contain ${templateOnlyField}`); + } } - - const primaryLinks = extractLinks(privacy.message); - const secondaryLinks = extractLinks(privacy.second?.message); - if (primaryLinks.length !== 2 || secondaryLinks.length !== 2) { - throw new Error('androidPrivacy.json must contain two legal links in both prompts'); - } - - const primary = validateLegalUrlPair(primaryLinks[0], primaryLinks[1]); - const secondary = validateLegalUrlPair(secondaryLinks[0], secondaryLinks[1]); - if (primary.termsUrl !== secondary.termsUrl || primary.privacyUrl !== secondary.privacyUrl) { - throw new Error('androidPrivacy.json primary and secondary prompts must use the same legal links'); - } - return primary; + return { + prompt: privacy.prompt, + version: String(privacy.version) + }; }; export const renderAndroidPrivacy = (templateText, termsValue, privacyValue) => { - const { termsUrl, privacyUrl } = validateLegalUrlPair(termsValue, privacyValue); - const rendered = String(templateText) - .replaceAll('__TERMS_URL__', termsUrl) - .replaceAll('__PRIVACY_URL__', privacyUrl); - const privacy = JSON.parse(rendered); + validateLegalUrlPair(termsValue, privacyValue); + const privacy = JSON.parse(String(templateText)); validateAndroidPrivacyDocument(privacy); return `${JSON.stringify(privacy, null, 2)}\n`; }; diff --git a/mobile-uni/scripts/configure-android-privacy.mjs b/mobile-uni/scripts/configure-android-privacy.mjs index 42415697..ba6c853c 100644 --- a/mobile-uni/scripts/configure-android-privacy.mjs +++ b/mobile-uni/scripts/configure-android-privacy.mjs @@ -23,7 +23,7 @@ try { privacyUrl ); writeFileSync(outputPath, rendered, 'utf8'); - console.log('src/androidPrivacy.json configured from final public legal URLs.'); + console.log('src/androidPrivacy.json configured with prompt=none; final public legal URLs validated for the login page.'); } catch (error) { console.error(`Android privacy configuration failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); diff --git a/mobile-uni/scripts/verify-android-apk.ps1 b/mobile-uni/scripts/verify-android-apk.ps1 index 349f902a..129445b4 100644 --- a/mobile-uni/scripts/verify-android-apk.ps1 +++ b/mobile-uni/scripts/verify-android-apk.ps1 @@ -107,37 +107,71 @@ try { throw "APK versionName mismatch: got $versionName, expected $($sourceManifest.versionName)" } - if (-not [string]::IsNullOrWhiteSpace($ExpectedTermsUrl)) { - if ($BuildKind -eq 'custom-base') { - # A DCloud custom base APK contains only the native debug runtime. HBuilderX - # syncs the compiled www resources separately when it runs the app on a - # device, so the legal links cannot truthfully be asserted from the APK. - $compiledPrivacyPath = Join-Path $projectRoot 'dist\build\app\androidPrivacy.json' - if (-not (Test-Path -LiteralPath $compiledPrivacyPath)) { - throw 'Compiled App resources are missing androidPrivacy.json; run build:app first.' - } - $privacyJson = Get-Content -Raw -Encoding UTF8 -LiteralPath $compiledPrivacyPath + if ($BuildKind -eq 'custom-base') { + # A DCloud custom base APK contains only the native debug runtime. HBuilderX + # syncs the compiled www resources separately when it runs the app on a + # device, so both no-prompt and login-link checks use the compiled App files. + $compiledPrivacyPath = Join-Path $projectRoot 'dist\build\app\androidPrivacy.json' + if (-not (Test-Path -LiteralPath $compiledPrivacyPath)) { + throw 'Compiled App resources are missing androidPrivacy.json; run build:app first.' } - else { - $bundledPrivacyFiles = @( - Get-ChildItem -LiteralPath (Join-Path $decodePath 'assets\apps') ` - -Recurse -File -Filter 'androidPrivacy.json' - ) - if ($bundledPrivacyFiles.Count -ne 1) { - throw "Expected exactly one bundled androidPrivacy.json, found $($bundledPrivacyFiles.Count)." - } - $privacyJson = Get-Content -Raw -Encoding UTF8 -LiteralPath $bundledPrivacyFiles[0].FullName + $privacyJson = Get-Content -Raw -Encoding UTF8 -LiteralPath $compiledPrivacyPath + $legalAppServiceFiles = @( + @( + (Join-Path $projectRoot 'dist\build\app\app-service.js'), + (Join-Path $projectRoot 'dist\build\app-plus\app-service.js') + ) | + Where-Object { Test-Path -LiteralPath $_ } | + Select-Object -First 1 + ) + } + else { + $bundledPrivacyFiles = @( + Get-ChildItem -LiteralPath (Join-Path $decodePath 'assets\apps') ` + -Recurse -File -Filter 'androidPrivacy.json' + ) + if ($bundledPrivacyFiles.Count -ne 1) { + throw "Expected exactly one bundled androidPrivacy.json, found $($bundledPrivacyFiles.Count)." } + $privacyJson = Get-Content -Raw -Encoding UTF8 -LiteralPath $bundledPrivacyFiles[0].FullName + $legalAppServiceFiles = @( + Get-ChildItem -LiteralPath (Join-Path $decodePath 'assets\apps') ` + -Recurse -File -Filter 'app-service.js' + ) + } - if (-not $privacyJson.Contains($ExpectedTermsUrl)) { - throw 'Packaged privacy configuration is missing the expected service agreement URL.' + $privacyConfig = $privacyJson | ConvertFrom-Json + if ($privacyConfig.prompt -ne 'none') { + throw 'Packaged privacy configuration must disable the DCloud native prompt with prompt=none.' + } + foreach ($templateOnlyField in @( + 'title', + 'message', + 'buttonAccept', + 'buttonRefuse', + 'hrefLoader', + 'second', + 'disagreeMode', + 'styles' + )) { + if ($privacyConfig.PSObject.Properties.Name -contains $templateOnlyField) { + throw "Packaged prompt=none privacy configuration must not contain $templateOnlyField." } - if (-not $privacyJson.Contains($ExpectedPrivacyUrl)) { - throw 'Packaged privacy configuration is missing the expected privacy policy URL.' + } + + if (-not [string]::IsNullOrWhiteSpace($ExpectedTermsUrl)) { + if ($legalAppServiceFiles.Count -ne 1) { + throw "Expected exactly one App service for login legal-link verification, found $($legalAppServiceFiles.Count)." } - $privacyConfig = $privacyJson | ConvertFrom-Json - if ($privacyConfig.prompt -ne 'template') { - throw 'Packaged privacy configuration must enable the DCloud native template prompt.' + $legalAppService = Get-Content -Raw -Encoding UTF8 -LiteralPath $legalAppServiceFiles[0] + if (-not $legalAppService.Contains($ExpectedTermsUrl)) { + throw 'Packaged login flow is missing the expected service agreement URL.' + } + if (-not $legalAppService.Contains($ExpectedPrivacyUrl)) { + throw 'Packaged login flow is missing the expected privacy policy URL.' + } + if (-not $legalAppService.Contains('请先阅读并勾选同意')) { + throw 'Packaged login flow is missing the unchecked-consent failure message.' } } diff --git a/mobile-uni/scripts/verify-app-assets.mjs b/mobile-uni/scripts/verify-app-assets.mjs index 12dd9d04..d29615fb 100644 --- a/mobile-uni/scripts/verify-app-assets.mjs +++ b/mobile-uni/scripts/verify-app-assets.mjs @@ -8,13 +8,16 @@ import { const projectRoot = resolve(import.meta.dirname, '..'); const manifestPath = resolve(projectRoot, 'src/manifest.json'); const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')); -const requirePrivacy = process.argv.includes('--require-privacy'); +const requireLegalConsent = process.argv.includes('--require-legal-consent'); const checkLegalUrls = process.argv.includes('--check-legal-urls'); const failures = []; let releaseLegalUrls; const fail = (message) => failures.push(message); const compiledAppRoot = resolve(projectRoot, 'dist/build/app'); +const compiledManifestPath = resolve(compiledAppRoot, 'manifest.json'); +const compiledAppServicePath = resolve(compiledAppRoot, 'app-service.js'); +const loginPagePath = resolve(projectRoot, 'src/pages/auth/login/index.vue'); const sourceAndroidManifestPath = resolve(projectRoot, 'AndroidManifest.xml'); const compiledAndroidManifestPath = resolve(compiledAppRoot, 'AndroidManifest.xml'); const sourceNetworkSecurityPath = resolve( @@ -129,8 +132,8 @@ const modules = app?.modules; if (!Array.isArray(app?.screenOrientation) || !app.screenOrientation.includes('portrait-primary')) { fail('app-plus.screenOrientation must include portrait-primary'); } -if (splashscreen?.useOriginalMsgbox !== true) { - fail('app-plus.distribute.splashscreen.useOriginalMsgbox must enable the native privacy prompt'); +if (splashscreen?.useOriginalMsgbox !== false) { + fail('app-plus.distribute.splashscreen.useOriginalMsgbox must disable the native privacy prompt'); } if (app?.ssl?.untrustedca !== 'refuse') { fail('app-plus.ssl.untrustedca must remain refuse'); @@ -248,7 +251,7 @@ for (const [relativePath, width, height] of splashPaths) expectPng(relativePath, const privacyPath = resolve(projectRoot, 'src/androidPrivacy.json'); const compiledPrivacyPath = resolve(projectRoot, 'dist/build/app/androidPrivacy.json'); -if (requirePrivacy) { +if (requireLegalConsent) { if (String(process.env.VITE_DEV_SMS_HINT_ENABLED || '').toLowerCase() === 'true') { fail('VITE_DEV_SMS_HINT_ENABLED must be disabled for release builds'); } @@ -265,45 +268,78 @@ if (requirePrivacy) { } if (!existsSync(privacyPath)) { - fail('src/androidPrivacy.json is required for release; run configure:app-privacy with final legal URLs'); + fail('src/androidPrivacy.json is required for release; run configure:app-legal with final legal URLs'); } else { try { const privacy = JSON.parse(readFileSync(privacyPath, 'utf8')); - const privacyLegalUrls = validateAndroidPrivacyDocument(privacy); - if ( - releaseLegalUrls - && ( - privacyLegalUrls.termsUrl !== releaseLegalUrls.termsUrl - || privacyLegalUrls.privacyUrl !== releaseLegalUrls.privacyUrl - ) - ) { - fail('androidPrivacy.json legal links must match VITE_APP_TERMS_URL and VITE_APP_PRIVACY_URL'); - } - releaseLegalUrls = privacyLegalUrls; + validateAndroidPrivacyDocument(privacy); } catch (error) { fail(`androidPrivacy.json is invalid: ${error instanceof Error ? error.message : String(error)}`); } } if (!existsSync(compiledPrivacyPath)) { - fail('compiled App resource is missing androidPrivacy.json; run build:app after configure:app-privacy'); + fail('compiled App resource is missing androidPrivacy.json; run build:app after configure:app-legal'); } else { try { const compiledPrivacy = JSON.parse(readFileSync(compiledPrivacyPath, 'utf8')); - const compiledLegalUrls = validateAndroidPrivacyDocument(compiledPrivacy); + validateAndroidPrivacyDocument(compiledPrivacy); if ( - releaseLegalUrls - && ( - compiledLegalUrls.termsUrl !== releaseLegalUrls.termsUrl - || compiledLegalUrls.privacyUrl !== releaseLegalUrls.privacyUrl - ) + existsSync(privacyPath) + && JSON.stringify(compiledPrivacy) !== JSON.stringify(JSON.parse(readFileSync(privacyPath, 'utf8'))) ) { - fail('compiled App androidPrivacy.json must match the source privacy configuration'); + fail('compiled App androidPrivacy.json must match the source prompt=none configuration'); } } catch (error) { fail(`compiled App androidPrivacy.json is invalid: ${error instanceof Error ? error.message : String(error)}`); } } + + if (!existsSync(compiledManifestPath)) { + fail('compiled App resource is missing manifest.json; run build:app'); + } else { + try { + const compiledManifest = JSON.parse(readFileSync(compiledManifestPath, 'utf8')); + if (compiledManifest.plus?.distribute?.splashscreen?.useOriginalMsgbox !== false) { + fail('compiled App manifest must disable the DCloud native privacy prompt'); + } + } catch (error) { + fail(`compiled App manifest is invalid: ${error instanceof Error ? error.message : String(error)}`); + } + } + + if (!existsSync(loginPagePath)) { + fail('login page is missing'); + } else { + const loginSource = readFileSync(loginPagePath, 'utf8'); + for (const [label, pattern] of [ + ['default unchecked consent', /const agreed = ref\(false\)/], + ['shared legal consent gate', /const ensureLegalConsent = \(\) =>/], + ['terms link', /openLegalDocument\('terms'\)/], + ['privacy link', /openLegalDocument\('privacy'\)/], + ['SMS legal gate', /const sendCode = async \(\) => \{[\s\S]*?if \(!ensureLegalConsent\(\)\) return;/], + ['login legal gate', /const login = async \(\) => \{[\s\S]*?if \(!ensureLegalConsent\(\)\) return;/] + ]) { + if (!pattern.test(loginSource)) { + fail(`login page is missing ${label}`); + } + } + } + + if (!existsSync(compiledAppServicePath)) { + fail('compiled App resource is missing app-service.js; run build:app'); + } else if (releaseLegalUrls) { + const appService = readFileSync(compiledAppServicePath, 'utf8'); + if (!appService.includes(releaseLegalUrls.termsUrl)) { + fail('compiled App login flow is missing VITE_APP_TERMS_URL'); + } + if (!appService.includes(releaseLegalUrls.privacyUrl)) { + fail('compiled App login flow is missing VITE_APP_PRIVACY_URL'); + } + if (!appService.includes('请先阅读并勾选同意')) { + fail('compiled App login flow is missing the unchecked-consent failure message'); + } + } verifyAndroidNetworkSecurity( compiledAndroidManifestPath, compiledNetworkSecurityPath, @@ -342,7 +378,7 @@ const checkRemoteLegalPage = async (url, label, expectedText) => { } }; -if (requirePrivacy && checkLegalUrls && releaseLegalUrls) { +if (requireLegalConsent && checkLegalUrls && releaseLegalUrls) { await Promise.all([ checkRemoteLegalPage(releaseLegalUrls.termsUrl, 'service agreement URL', /服务协议|用户协议/), checkRemoteLegalPage(releaseLegalUrls.privacyUrl, 'privacy policy URL', /隐私政策|个人信息保护/) diff --git a/mobile-uni/src/manifest.json b/mobile-uni/src/manifest.json index c9ab0963..3745199a 100644 --- a/mobile-uni/src/manifest.json +++ b/mobile-uni/src/manifest.json @@ -3,8 +3,8 @@ "appid" : "__UNI__B36D8BE", "description" : "帮道员工端", "vueVersion" : "3", - "versionName" : "0.1.10", - "versionCode" : "110", + "versionName" : "0.1.11", + "versionCode" : "111", "uniStatistics" : { "enable" : false }, @@ -59,7 +59,7 @@ }, "splashscreen" : { "iosStyle" : "default", - "useOriginalMsgbox" : true, + "useOriginalMsgbox" : false, "ios" : { "iphone" : { "retina40" : "src/static/app/splash/ios-iphone-retina40.png", diff --git a/mobile-uni/tests/app-packaging.test.mjs b/mobile-uni/tests/app-packaging.test.mjs index f16c9f24..297ea280 100644 --- a/mobile-uni/tests/app-packaging.test.mjs +++ b/mobile-uni/tests/app-packaging.test.mjs @@ -94,7 +94,11 @@ test('Android 启动阶段不主动索取设备信息或外部存储权限', asy const android = manifest['app-plus']?.distribute?.android; const modules = manifest['app-plus']?.modules; - assert.equal(manifest['app-plus']?.distribute?.splashscreen?.useOriginalMsgbox, true); + assert.equal( + manifest['app-plus']?.distribute?.splashscreen?.useOriginalMsgbox, + false, + '受控企业内测不展示 DCloud 原生隐私弹窗,协议同意统一放在登录页' + ); assert.equal(android?.permissionPhoneState?.request, 'none'); assert.equal(android?.permissionExternalStorage?.request, 'none'); assert.ok(Object.hasOwn(modules || {}, 'Camera'), '媒体功能仍需按用户操作动态申请相机权限'); @@ -133,7 +137,7 @@ test('正式法务地址必须使用不同的公网 HTTPS 页面', () => { )); }); -test('Android 隐私模板的首次与二次弹窗使用同一组最终链接', async () => { +test('Android 原生隐私配置明确关闭弹窗,法务地址仍须通过登录页构建校验', async () => { const template = await readFile(new URL('../androidPrivacy.json.example', import.meta.url), 'utf8'); const rendered = renderAndroidPrivacy( template, @@ -143,13 +147,18 @@ test('Android 隐私模板的首次与二次弹窗使用同一组最终链接', const privacy = JSON.parse(rendered); assert.deepEqual(validateAndroidPrivacyDocument(privacy), { - termsUrl: 'https://legal.company.cn/bangdao/terms', - privacyUrl: 'https://legal.company.cn/bangdao/privacy' + prompt: 'none', + version: '20260729' }); - assert.doesNotMatch(rendered, /__TERMS_URL__|__PRIVACY_URL__/); - - privacy.second.message = privacy.second.message.replace('/privacy', '/other-privacy'); - assert.throws(() => validateAndroidPrivacyDocument(privacy), /must use the same legal links/); + assert.doesNotMatch(rendered, /服务协议|隐私政策|buttonAccept|buttonRefuse|second/); + assert.throws( + () => validateAndroidPrivacyDocument({ ...privacy, prompt: 'template' }), + /prompt=none/ + ); + assert.throws( + () => validateAndroidPrivacyDocument({ ...privacy, message: 'unexpected native prompt' }), + /must not contain message/ + ); }); test('Android 隐私配置写入 uni-app CLI 输入目录并校验编译产物', async () => { @@ -164,6 +173,7 @@ test('Android 隐私配置写入 uni-app CLI 输入目录并校验编译产物', assert.match(configureScript, /resolve\(projectRoot, 'src', 'androidPrivacy\.json'\)/); assert.match(verifier, /dist\/build\/app\/androidPrivacy\.json/); + assert.match(verifier, /compiledManifest\.plus\?\.distribute\?\.splashscreen\?\.useOriginalMsgbox !== false/); }); test('App 登录页法务地址校验不依赖浏览器 URL 构造器', async () => { @@ -187,6 +197,10 @@ test('APK 门禁区分自定义调试基座与内置业务资源的测试包', a assert.match(verifier, /assets\\apps/); assert.match(verifier, /bundled androidPrivacy\.json/); assert.match(verifier, /DCloud custom base APK contains only the native debug runtime/); + assert.match(verifier, /prompt=none/); + assert.match(verifier, /Packaged login flow is missing the expected service agreement URL/); + assert.match(verifier, /Packaged login flow is missing the expected privacy policy URL/); + assert.match(verifier, /Packaged login flow is missing the unchecked-consent failure message/); assert.match(verifier, /dist\\build\\app\\app-service\.js/); assert.match(verifier, /dist\\build\\app-plus\\app-service\.js/); assert.match(verifier, /fixed test SMS code/); @@ -209,5 +223,5 @@ test('8 月 1 日 RC 脚本默认拒绝脏工作区且记录完整构建证据', assert.match(script, /AllowDirtyRehearsal/); assert.match(script, /RC build changed the previously clean worktree/); assert.match(script, /releaseEligible = \$releaseEligible/); - assert.match(script, /APK metadata, legal links, signature, content match and sensitive-value scan/); + assert.match(script, /APK metadata, login legal links, no native privacy prompt, signature, content match and sensitive-value scan/); }); diff --git a/scripts/prepare-aug1-rc.ps1 b/scripts/prepare-aug1-rc.ps1 index b69e4a35..f5cb40ea 100644 --- a/scripts/prepare-aug1-rc.ps1 +++ b/scripts/prepare-aug1-rc.ps1 @@ -72,7 +72,7 @@ Remove-Item Env:VITE_DEV_SMS_HINT_VALUE -ErrorAction SilentlyContinue if (-not $SkipBuild) { Invoke-Checked -FilePath 'npm' -Arguments @('--prefix', 'mobile-uni', 'run', 'test:unit') Invoke-Checked -FilePath 'npm' -Arguments @('--prefix', 'mobile-uni', 'run', 'typecheck') - Invoke-Checked -FilePath 'npm' -Arguments @('--prefix', 'mobile-uni', 'run', 'configure:app-privacy') + Invoke-Checked -FilePath 'npm' -Arguments @('--prefix', 'mobile-uni', 'run', 'configure:app-legal') Invoke-Checked -FilePath 'npm' -Arguments @('--prefix', 'mobile-uni', 'run', 'build:h5') Invoke-Checked -FilePath 'npm' -Arguments @('--prefix', 'mobile-uni', 'run', 'build:app') Invoke-Checked -FilePath 'npm' -Arguments @('--prefix', 'mobile-uni', 'run', 'verify:app-release') @@ -212,11 +212,11 @@ $evidence = [ordered]@{ 'frontend production build', 'ruoyi-aihr full test suite', 'backend package', - 'APK metadata, legal links, signature, content match and sensitive-value scan' + 'APK metadata, login legal links, no native privacy prompt, signature, content match and sensitive-value scan' ) } manualGatesRemaining = @( - 'privacy reject and consent choices', + 'login legal links and unchecked-consent failure on Android', 'login error and re-login', 'microphone allow and deny', 'media cancellation',