feat(mindspace): enforce PostgreSQL user data delivery
This commit is contained in:
@@ -40,6 +40,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(
|
||||
@@ -76,20 +103,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');
|
||||
@@ -98,6 +118,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,
|
||||
@@ -111,7 +146,7 @@ export async function assessPageDataHtmlBinding({
|
||||
return { bound: true, reasons: [], pageId: null };
|
||||
}
|
||||
|
||||
const workspace = assessWorkspacePageDataReadiness({ publishDir, relativePath, html });
|
||||
const workspace = await assessWorkspacePageDataReadiness({ userId, publishDir, relativePath, html });
|
||||
const reasons = [...workspace.reasons];
|
||||
|
||||
let pageId = null;
|
||||
@@ -139,6 +174,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