From 893c7c60cd4cf89dc9270c3c62b488f68691dfbc Mon Sep 17 00:00:00 2001 From: pavlov346346-source Date: Tue, 8 Sep 2026 16:36:47 +0300 Subject: [PATCH] Add v17.7.1 password security release patcher --- .../scripts/patch-v1771-password-security.mjs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/scripts/patch-v1771-password-security.mjs diff --git a/.github/scripts/patch-v1771-password-security.mjs b/.github/scripts/patch-v1771-password-security.mjs new file mode 100644 index 0000000..a87898d --- /dev/null +++ b/.github/scripts/patch-v1771-password-security.mjs @@ -0,0 +1,24 @@ +import fs from 'node:fs'; +const VERSION='17.7.1',RELEASE='20260908-v17-7-1-password-security'; +const read=f=>fs.readFileSync(f,'utf8'),write=(f,s)=>fs.writeFileSync(f,s); +const once=(s,a,b,label)=>{const n=s.split(a).length-1;if(n!==1)throw new Error(`${label}: expected 1 match, got ${n}`);return s.replace(a,b)}; +let perf=read('public/core/performance.js'); +perf=once(perf," const VERSION='17.7.0';\n const RELEASE='20260908-v17-7-0-architecture-foundation';",` const VERSION='${VERSION}';\n const RELEASE='${RELEASE}';`,'performance version'); +perf=once(perf," function loadOfferWorkspace(){\n if(window.SunOfferWorkspaceV1769||document.getElementById('sunOfferWorkspaceV1769Script'))return;\n const script=document.createElement('script');script.id='sunOfferWorkspaceV1769Script';script.src=`core/offer-workspace-v1769.js?v=${RELEASE}`;script.async=true;script.onerror=()=>console.error('[Caterium] Не загрузился модуль offer-workspace-v1769.js');document.head.appendChild(script);\n }"," function loadOfferWorkspace(){\n if(window.SunOfferWorkspaceV1769||document.getElementById('sunOfferWorkspaceV1769Script'))return;\n const script=document.createElement('script');script.id='sunOfferWorkspaceV1769Script';script.src=`core/offer-workspace-v1769.js?v=${RELEASE}`;script.async=true;script.onerror=()=>console.error('[Caterium] Не загрузился модуль offer-workspace-v1769.js');document.head.appendChild(script);\n }\n function loadAccountSecurity(){\n if(window.CateriumAccountSecurityV1771||document.getElementById('cateriumAccountSecurityV1771Script'))return;\n const script=document.createElement('script');script.id='cateriumAccountSecurityV1771Script';script.src=`core/account-security-v1771.js?v=${RELEASE}`;script.async=true;script.onerror=()=>console.error('[Caterium] Не загрузился модуль account-security-v1771.js');document.head.appendChild(script);\n }",'security loader'); +perf=once(perf," loadDataLayer();loadServerAutomation();loadHotfix();loadOpsUX();loadUXFix();loadDeveloperUX();loadOfferWorkspace();scan(document);startMemoryTimer();"," loadDataLayer();loadServerAutomation();loadHotfix();loadOpsUX();loadUXFix();loadDeveloperUX();loadOfferWorkspace();loadAccountSecurity();scan(document);startMemoryTimer();",'security startup'); +perf=once(perf,"loadDataLayer,loadServerAutomation,loadHotfix,loadOpsUX,loadUXFix,loadDeveloperUX,loadOfferWorkspace,disconnect","loadDataLayer,loadServerAutomation,loadHotfix,loadOpsUX,loadUXFix,loadDeveloperUX,loadOfferWorkspace,loadAccountSecurity,disconnect",'security export'); +write('public/core/performance.js',perf); + +let pkg=JSON.parse(read('package.json'));pkg.version=VERSION;pkg.scripts['check:syntax']=pkg.scripts['check:syntax'].replace('public/core/server-automation-v1770.js','public/core/server-automation-v1770.js && node --check public/core/account-security-v1771.js');write('package.json',JSON.stringify(pkg,null,2)+'\n'); +let lock=JSON.parse(read('package-lock.json'));lock.version=VERSION;if(lock.packages?.[''])lock.packages[''].version=VERSION;write('package-lock.json',JSON.stringify(lock,null,2)+'\n'); + +let index=read('public/index.html');index=index.split('20260908-v17-7-0-architecture-foundation').join(RELEASE);write('public/index.html',index); +let sw=read('public/service-worker.js');sw=sw.replace(/const CACHE='sun-catering-pwa-v\d+-[^']+';\nconst VERSION='[^']+';/,`const CACHE='sun-catering-pwa-v76-${RELEASE}';\nconst VERSION='${RELEASE}';`);if(!sw.includes("'core/account-security-v1771.js'"))sw=sw.replace("'core/server-automation-v1770.js',","'core/server-automation-v1770.js',\n 'core/account-security-v1771.js',");write('public/service-worker.js',sw); + +let manifest=JSON.parse(read('docs/release-manifest.json'));Object.assign(manifest,{version:'v17.7.1',release:RELEASE,pwaCache:`v76-${RELEASE}`,forcedTemporaryPasswordChange:true,passwordChangeInEveryAccount:true,passwordMinimumLength:8,passwordChangeRequiresCurrentPassword:true,notes:'Account security: temporary-password employees are blocked by an independent mandatory password-change gate that survives workspace loading; every signed-in account gets Change password in Profile.'});write('docs/release-manifest.json',JSON.stringify(manifest,null,2)+'\n'); +write('docs/releases/V17.7.1-CHANGES.txt',`Caterium v17.7.1 — Account password security\nDate: 2026-09-08\n\n1. First login with an employee temporary password opens an independent mandatory password-change security gate.\n2. The mandatory gate is not owned by the workspace/auth loading DOM, so workspace loading cannot make it disappear.\n3. Until a new password is saved, the user cannot continue into the application; only Sign out is available.\n4. Every signed-in account gets Profile → Security → Change password.\n5. Normal password change verifies the current password, requires a minimum of 8 characters and confirmation.\n6. Successful first-login change clears user_metadata.must_change_password and refreshes the session.\n7. PWA cache v76 / ${RELEASE}.\n`); + +let release=read('tests/release-check.mjs');release+=`\ncheck(pkg.version==='17.7.1','package version is v17.7.1');\ncheck(index.includes('${RELEASE}'),'index cache token is v17.7.1');\ncheck(sw.includes('v76-${RELEASE}')&&sw.includes('account-security-v1771.js'),'service worker contains account security v17.7.1');\nconst accountSecurity=fs.readFileSync(path.join(root,'public/core/account-security-v1771.js'),'utf8');\ncheck(accountSecurity.includes('must_change_password')&&accountSecurity.includes('cat-password-required-v1771')&&accountSecurity.includes('Сменить пароль'),'account security includes mandatory temporary-password gate and profile password change');\ncheck(accountSecurity.includes('signInWithPassword')&&accountSecurity.includes('auth.updateUser')&&accountSecurity.includes('минимум 8 символов'),'password change verifies current password and updates Supabase Auth');\ncheck(performance.includes('loadAccountSecurity')&&performance.includes('account-security-v1771.js'),'performance loader installs account security');\n`;write('tests/release-check.mjs',release); + +let spec=read('tests/app.spec.mjs');spec+=`\n\ntest('v17.7.1 temporary-password account gets persistent mandatory password gate', async ({ page }) => {\n await page.goto('/index.html',{waitUntil:'domcontentloaded'});\n await page.evaluate(()=>{\n window.CateriumAccountSecurityV1771=undefined;\n window.SunCloudV2={getSession:()=>({user:{id:'u1',email:'employee@example.com',user_metadata:{must_change_password:true},app_metadata:{}}}),getClient:()=>({auth:{getUser:async()=>({data:{user:{id:'u1',email:'employee@example.com',user_metadata:{must_change_password:true},app_metadata:{}}}}),updateUser:async()=>({data:{user:{}},error:null}),refreshSession:async()=>({})}})};\n });\n const src=fs.readFileSync(path.join(process.cwd(),'public/core/account-security-v1771.js'),'utf8');await page.addScriptTag({content:src});\n await page.waitForSelector('#cateriumPasswordGateV1771');\n expect(await page.locator('#cateriumPasswordGateV1771').isVisible()).toBe(true);\n expect(await page.locator('#catPasswordCancelV1771').count()).toBe(0);\n await page.evaluate(()=>{document.body.insertAdjacentHTML('beforeend','
')});\n await page.waitForTimeout(120);\n expect(await page.locator('#cateriumPasswordGateV1771').isVisible()).toBe(true);\n});\n\ntest('v17.7.1 every signed-in account gets Change password in Profile', async ({ page }) => {\n await page.goto('/index.html',{waitUntil:'domcontentloaded'});\n await page.evaluate(()=>{\n window.CateriumAccountSecurityV1771=undefined;\n document.body.insertAdjacentHTML('beforeend','

Профиль

user@example.com
');\n window.SunCloudV2={getSession:()=>({user:{id:'u2',email:'user@example.com',user_metadata:{},app_metadata:{}}}),getClient:()=>({auth:{getUser:async()=>({data:{user:{id:'u2',email:'user@example.com',user_metadata:{},app_metadata:{}}}}),signInWithPassword:async()=>({error:null}),updateUser:async()=>({data:{user:{}},error:null}),refreshSession:async()=>({})}})};\n });\n const src=fs.readFileSync(path.join(process.cwd(),'public/core/account-security-v1771.js'),'utf8');await page.addScriptTag({content:src});\n await page.waitForSelector('#catProfilePasswordV1771');\n expect(await page.locator('#catProfilePasswordV1771').textContent()).toContain('Сменить пароль');\n await page.locator('#catProfilePasswordV1771').click();\n await expect(page.locator('#catCurrentPasswordV1771')).toBeVisible();\n});\n`;write('tests/app.spec.mjs',spec); +console.log('Applied Caterium v17.7.1 password-security release patch');