merge: integrate feature/0713-dev into main
# Conflicts: # mindspace-page-data-finish-guard.mjs # page-data-delivery-assess.mjs
This commit is contained in:
@@ -41,6 +41,33 @@ export function buildSmokeInsertRow(policy, datasetName) {
|
||||
return row;
|
||||
}
|
||||
|
||||
export function assessPageDataAuthenticationContract({ policy, html } = {}) {
|
||||
const accessMode = String(policy?.accessMode ?? '').trim();
|
||||
const content = String(html ?? '');
|
||||
const usesServerAuthentication = /\.\s*authenticate\s*\(/.test(content);
|
||||
const passwordValue = String.raw`\b(?:pwd|pass(?:word)?|passwordInput|adminPassword)\w*(?:\.value)?`;
|
||||
const passwordComparison = String.raw`(?:===?|!==?)`;
|
||||
const passwordOperand = String.raw`(?:[A-Za-z_$][\w$]*|['"\x60][^'"\x60]*['"\x60])`;
|
||||
const usesClientSidePasswordCheck = new RegExp(
|
||||
`(?:${passwordValue}\\s*${passwordComparison}\\s*${passwordOperand}|${passwordOperand}\\s*${passwordComparison}\\s*${passwordValue})`,
|
||||
'i',
|
||||
).test(content);
|
||||
const reasons = [];
|
||||
if (accessMode === 'password' && !usesServerAuthentication) {
|
||||
reasons.push('password_page_missing_server_authentication');
|
||||
}
|
||||
if (accessMode === 'public' && usesServerAuthentication) {
|
||||
reasons.push('public_page_cannot_use_password_authentication');
|
||||
}
|
||||
if (accessMode === 'public' && usesClientSidePasswordCheck) {
|
||||
reasons.push('public_page_uses_client_side_password_gate');
|
||||
}
|
||||
if (accessMode === 'password' && usesClientSidePasswordCheck) {
|
||||
reasons.push('password_page_uses_client_side_password_gate');
|
||||
}
|
||||
return reasons;
|
||||
}
|
||||
|
||||
export async function queryOnlinePublication(pool, pageId) {
|
||||
if (!pool || !pageId) return null;
|
||||
const [rows] = await pool.query(
|
||||
@@ -77,20 +104,13 @@ function findWorkspacePolicyForHtml({ publishDir, relativePath, html }) {
|
||||
return null;
|
||||
}
|
||||
|
||||
export function assessWorkspacePageDataReadiness({ publishDir, relativePath, html }) {
|
||||
function assessWorkspacePageDataPolicyReadiness({ publishDir, relativePath, html }) {
|
||||
const usage = detectPageDataDatasetUsageFromHtml(html);
|
||||
if (!usage.size) {
|
||||
return { ready: true, reasons: [] };
|
||||
}
|
||||
|
||||
const reasons = [];
|
||||
const dataSpace = createUserDataSpaceService({ workspaceRoot: publishDir });
|
||||
for (const datasetName of usage.keys()) {
|
||||
if (!dataSpace.getDataset(datasetName)) {
|
||||
reasons.push(`dataset_not_registered:${datasetName}`);
|
||||
}
|
||||
}
|
||||
|
||||
const policy = findWorkspacePolicyForHtml({ publishDir, relativePath, html });
|
||||
if (!policy) {
|
||||
reasons.push('missing_workspace_policy');
|
||||
@@ -99,6 +119,21 @@ export function assessWorkspacePageDataReadiness({ publishDir, relativePath, htm
|
||||
return { ready: reasons.length === 0, reasons, policy };
|
||||
}
|
||||
|
||||
export async function assessWorkspacePageDataReadiness({ userId, publishDir, relativePath, html }) {
|
||||
const usage = detectPageDataDatasetUsageFromHtml(html);
|
||||
const policyAssessment = assessWorkspacePageDataPolicyReadiness({ publishDir, relativePath, html });
|
||||
if (!usage.size) return policyAssessment;
|
||||
|
||||
const reasons = [...policyAssessment.reasons];
|
||||
const dataSpace = createUserDataSpaceService({ workspaceRoot: publishDir, userId });
|
||||
for (const datasetName of usage.keys()) {
|
||||
if (!(await dataSpace.getDataset(datasetName))) {
|
||||
reasons.push(`dataset_not_registered:${datasetName}`);
|
||||
}
|
||||
}
|
||||
return { ...policyAssessment, ready: reasons.length === 0, reasons };
|
||||
}
|
||||
|
||||
export async function assessPageDataHtmlBinding({
|
||||
pool,
|
||||
userId,
|
||||
@@ -123,7 +158,7 @@ export async function assessPageDataHtmlBinding({
|
||||
};
|
||||
}
|
||||
|
||||
const workspace = assessWorkspacePageDataReadiness({ publishDir, relativePath, html });
|
||||
const workspace = await assessWorkspacePageDataReadiness({ userId, publishDir, relativePath, html });
|
||||
reasons.push(...workspace.reasons);
|
||||
|
||||
let pageId = null;
|
||||
@@ -151,6 +186,7 @@ export async function assessPageDataHtmlBinding({
|
||||
if (String(policy.accessMode ?? '').trim() !== expectedAccessMode) {
|
||||
reasons.push('policy_access_mode_mismatch');
|
||||
}
|
||||
reasons.push(...assessPageDataAuthenticationContract({ policy, html }));
|
||||
for (const [datasetName, perms] of usage) {
|
||||
const policyDataset = policy.datasets?.[datasetName];
|
||||
if (!policyDataset) continue;
|
||||
|
||||
Reference in New Issue
Block a user