refactor: modularize portal server and harden session recovery
This commit is contained in:
@@ -63,8 +63,22 @@ assertIncludes(voiceInputButton, 'useVoiceSession({', 'VoiceInputButton.tsx');
|
||||
assertIncludes(voiceInputButton, 'onTranscript?.(transcript)', 'VoiceInputButton.tsx');
|
||||
|
||||
const server = read('server.mjs');
|
||||
assertIncludes(server, 'canUseSnapshotCache', 'server.mjs');
|
||||
assertIncludes(server, 'hintMc != null && hintUa != null', 'server.mjs');
|
||||
assertIncludes(
|
||||
server,
|
||||
'attachPortalSessionRoutes(api, {',
|
||||
'server.mjs session route composition',
|
||||
);
|
||||
const portalSessionRoutes = read('server/portal-session-routes.mjs');
|
||||
assertIncludes(
|
||||
portalSessionRoutes,
|
||||
'canUseSnapshotCache',
|
||||
'portal-session-routes.mjs',
|
||||
);
|
||||
assertIncludes(
|
||||
portalSessionRoutes,
|
||||
'hintMc != null && hintUa != null',
|
||||
'portal-session-routes.mjs',
|
||||
);
|
||||
|
||||
const publicFinishSync = read('mindspace-public-finish-sync.mjs');
|
||||
assertIncludes(publicFinishSync, 'applyPublicHtmlEdit', 'mindspace-public-finish-sync.mjs');
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
import { isLegacyPageDataApiPath } from '../page-data-routes.mjs';
|
||||
import { isPageDataPublicPath } from '../page-data-public-service.mjs';
|
||||
import {
|
||||
assessPortalAccessMigrationReadiness,
|
||||
PORTAL_STATIC_ACCESS_RULES,
|
||||
resolvePortalAccessEnforcementConfig,
|
||||
} from '../server/portal-access-policy.mjs';
|
||||
|
||||
const routeSamples = [
|
||||
{ path: '/status', method: 'GET' },
|
||||
{ path: '/runtime/status', method: 'GET' },
|
||||
{ path: '/config/blocked-words', method: 'GET' },
|
||||
{ path: '/internal/agent/jobs/job-1/claim', method: 'POST' },
|
||||
{ path: '/agent/mindspace_page_patch', method: 'POST' },
|
||||
{ path: '/internal/image-make/runtime-config', method: 'GET' },
|
||||
{ path: '/mindspace/v1/assets/asset-1/download', method: 'GET' },
|
||||
{ path: '/plaza/v1/feed', method: 'GET' },
|
||||
{ path: '/plaza/v1/categories', method: 'GET' },
|
||||
{ path: '/plaza/v1/seo/sitemap', method: 'GET' },
|
||||
{ path: '/plaza/v1/posts/post-1', method: 'GET' },
|
||||
{ path: '/plaza/v1/posts/post-1/comments', method: 'GET' },
|
||||
{ path: '/plaza/v1/users/alice', method: 'GET' },
|
||||
{ path: '/plaza/v1/users/alice/posts', method: 'GET' },
|
||||
{ path: '/plaza/v1/events', method: 'POST' },
|
||||
{ path: '/plaza/v1/posts/post-1/reports', method: 'POST' },
|
||||
{ path: '/public/pages/page-1/data/signups', method: 'GET' },
|
||||
{ path: '/public/pages/page-1/data/signups/rows', method: 'POST' },
|
||||
{ path: '/page-data/signups', method: 'GET' },
|
||||
{ path: '/mindspace/v1/pages', method: 'GET' },
|
||||
];
|
||||
|
||||
const predicates = {
|
||||
isPageDataPublicPath,
|
||||
isLegacyPageDataApiPath,
|
||||
};
|
||||
const knownMismatchPolicyGroups = [
|
||||
'plaza-optional-user',
|
||||
'page-data-public',
|
||||
'legacy-page-data',
|
||||
];
|
||||
|
||||
const staticRuleIds = PORTAL_STATIC_ACCESS_RULES.map((rule) => rule.id);
|
||||
if (new Set(staticRuleIds).size !== staticRuleIds.length) {
|
||||
throw new Error('Portal access policy contains duplicate static rule ids');
|
||||
}
|
||||
if (resolvePortalAccessEnforcementConfig({}).enabled) {
|
||||
throw new Error('Portal access enforcement must default to disabled');
|
||||
}
|
||||
try {
|
||||
resolvePortalAccessEnforcementConfig({
|
||||
MEMIND_PORTAL_ACCESS_POLICY_ENFORCEMENT_ENABLED: '1',
|
||||
MEMIND_PORTAL_ACCESS_POLICY_ENFORCE_GROUPS: 'all',
|
||||
});
|
||||
throw new Error('Portal access enforcement unexpectedly accepted all');
|
||||
} catch (error) {
|
||||
if (!String(error?.message ?? error).includes('Unknown Portal access enforcement group')) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
const noMultiUserReport = assessPortalAccessMigrationReadiness(routeSamples, {
|
||||
...predicates,
|
||||
multiUserEnabled: false,
|
||||
knownMismatchPolicyGroups,
|
||||
});
|
||||
const multiUserReport = assessPortalAccessMigrationReadiness(routeSamples, {
|
||||
...predicates,
|
||||
multiUserEnabled: true,
|
||||
});
|
||||
|
||||
if (!noMultiUserReport.contractReady) {
|
||||
throw new Error(
|
||||
`Portal access policy has ${noMultiUserReport.unexpectedMismatches.length} unexpected no-auth/legacy mismatch(es)`,
|
||||
);
|
||||
}
|
||||
if (!multiUserReport.safeForBehaviorSwitch) {
|
||||
throw new Error(
|
||||
`Portal access policy has ${multiUserReport.knownMismatches.length + multiUserReport.unexpectedMismatches.length} multi-user mismatch(es)`,
|
||||
);
|
||||
}
|
||||
|
||||
console.log(
|
||||
[
|
||||
'portal access policy compatibility ok',
|
||||
`samples=${routeSamples.length}`,
|
||||
`static_rules=${staticRuleIds.length}`,
|
||||
`known_no_auth_mismatches=${noMultiUserReport.knownMismatches.length}`,
|
||||
`unexpected_no_auth_mismatches=${noMultiUserReport.unexpectedMismatches.length}`,
|
||||
`multi_user_mismatches=${multiUserReport.knownMismatches.length + multiUserReport.unexpectedMismatches.length}`,
|
||||
`contract_ready=${noMultiUserReport.contractReady && multiUserReport.contractReady}`,
|
||||
`behavior_switch_ready=${noMultiUserReport.safeForBehaviorSwitch && multiUserReport.safeForBehaviorSwitch}`,
|
||||
].join(' '),
|
||||
);
|
||||
Reference in New Issue
Block a user