Harden auth/vault path sanitization and clean WeKnora docs
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
const { loginViaAuthForm, withAdminBrowserSession } = require('./lib/browser-auth-login');
|
||||
const assert = require("node:assert");
|
||||
const fs = require("node:fs");
|
||||
const os = require("node:os");
|
||||
@@ -33,13 +34,30 @@ function mkdirp(dir) {
|
||||
}
|
||||
|
||||
async function quickLogin(page) {
|
||||
await page.goto(`${BASE}/auth`, { waitUntil: "commit", timeout: TIMEOUT });
|
||||
const quickLoginButton = page.getByRole("button", { name: "测试账号快速登录" });
|
||||
await quickLoginButton.waitFor({ state: "visible", timeout: TIMEOUT });
|
||||
await Promise.all([
|
||||
page.waitForURL((url) => !url.toString().includes("/auth"), { timeout: TIMEOUT }).catch(() => null),
|
||||
quickLoginButton.click(),
|
||||
]);
|
||||
// 7-76 P0: 标准表单登录(无测试快速登录按钮)
|
||||
const base =
|
||||
(typeof BASE_URL !== "undefined" && BASE_URL) ||
|
||||
(typeof baseUrl !== "undefined" && baseUrl) ||
|
||||
process.env.MNOTE_UI_BASE_URL ||
|
||||
"http://127.0.0.1:3000";
|
||||
const timeout =
|
||||
(typeof UI_TIMEOUT_MS !== "undefined" && UI_TIMEOUT_MS) ||
|
||||
(typeof TIMEOUT !== "undefined" && TIMEOUT) ||
|
||||
30_000;
|
||||
if (!String(page.url() || "").includes("/auth")) {
|
||||
await page.goto(String(base).replace(/\/+$/, "") + "/auth", {
|
||||
waitUntil: "commit",
|
||||
timeout,
|
||||
});
|
||||
}
|
||||
await loginViaAuthForm(page, {
|
||||
baseUrl: base,
|
||||
timeoutMs: timeout,
|
||||
gotoAuth: false,
|
||||
});
|
||||
await page
|
||||
.waitForURL((url) => !String(url).includes("/auth"), { timeout })
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
async function requestJson(page, url, options = {}) {
|
||||
@@ -133,46 +151,51 @@ function policyForAllSkillsAndMcp() {
|
||||
};
|
||||
}
|
||||
|
||||
async function ensureDirectoryGrant(page) {
|
||||
const response = await page.request.fetch(`${BASE}/api/admin/access-policy/grants`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
accept: "application/json",
|
||||
"content-type": "application/json",
|
||||
},
|
||||
data: {
|
||||
userId: ACTOR_ID,
|
||||
rootUri: ROOT_URI,
|
||||
rootPath: ROOT_PATH,
|
||||
permission: "write",
|
||||
recursive: true,
|
||||
capabilities: ["ai"],
|
||||
},
|
||||
timeout: TIMEOUT,
|
||||
});
|
||||
const text = await response.text();
|
||||
let body = {};
|
||||
try {
|
||||
body = text ? JSON.parse(text) : {};
|
||||
} catch {
|
||||
body = { raw: text };
|
||||
}
|
||||
if (response.ok()) return body;
|
||||
if (body && body.code === "local_access_policy_grant_duplicate") return body;
|
||||
throw new Error(`POST /api/admin/access-policy/grants failed: ${response.status()} ${text.slice(0, 800)}`);
|
||||
async function ensureDirectoryGrant(browser) {
|
||||
// 方案 A:admin 能力仅 mnote-admin;e2e 为 AI 主体,不可调 /api/admin/*
|
||||
return withAdminBrowserSession(browser, async (adminPage) => {
|
||||
const response = await adminPage.request.fetch(`${BASE}/api/admin/access-policy/grants`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
accept: "application/json",
|
||||
"content-type": "application/json",
|
||||
},
|
||||
data: {
|
||||
userId: ACTOR_ID,
|
||||
rootUri: ROOT_URI,
|
||||
rootPath: ROOT_PATH,
|
||||
permission: "write",
|
||||
recursive: true,
|
||||
capabilities: ["ai"],
|
||||
},
|
||||
timeout: TIMEOUT,
|
||||
});
|
||||
const text = await response.text();
|
||||
let body = {};
|
||||
try {
|
||||
body = text ? JSON.parse(text) : {};
|
||||
} catch {
|
||||
body = { raw: text };
|
||||
}
|
||||
if (response.ok()) return body;
|
||||
if (body && body.code === "local_access_policy_grant_duplicate") return body;
|
||||
throw new Error(`POST /api/admin/access-policy/grants failed: ${response.status()} ${text.slice(0, 800)}`);
|
||||
}, { baseUrl: BASE, timeoutMs: TIMEOUT });
|
||||
}
|
||||
|
||||
async function seedRuntimePolicy(page) {
|
||||
async function seedRuntimePolicy(browser) {
|
||||
mkdirp(ROOT_PATH);
|
||||
await ensureDirectoryGrant(page);
|
||||
await ensureDirectoryGrant(browser);
|
||||
const policy = policyForAllSkillsAndMcp();
|
||||
await requestJson(page, "/api/ai-admin/settings", {
|
||||
method: "PUT",
|
||||
data: {
|
||||
...policy,
|
||||
quota: { daily: 200 },
|
||||
},
|
||||
});
|
||||
await withAdminBrowserSession(browser, async (adminPage) => {
|
||||
await requestJson(adminPage, "/api/ai-admin/settings", {
|
||||
method: "PUT",
|
||||
data: {
|
||||
...policy,
|
||||
quota: { daily: 200 },
|
||||
},
|
||||
});
|
||||
}, { baseUrl: BASE, timeoutMs: TIMEOUT });
|
||||
}
|
||||
|
||||
async function abortExistingSession(page) {
|
||||
@@ -373,7 +396,7 @@ async function main() {
|
||||
|
||||
try {
|
||||
await quickLogin(page);
|
||||
await seedRuntimePolicy(page);
|
||||
await seedRuntimePolicy(browser);
|
||||
result.seededEffective = await requestJson(page, "/api/ai-settings/effective");
|
||||
result.checks.allSkillsEnabled = ["VPN", "Chrome Bridge", "Context7", "SearXNG Search", "Global Search", "MemPalace", "CodeGraph"]
|
||||
.every((name) => (result.seededEffective.skills || []).some((skill) => skill.name === name && skill.enabled !== false));
|
||||
|
||||
Reference in New Issue
Block a user