feat: add memindadm runtime policy for agent code runs (Phase 1.5)

Persist code-run gates in admin DB and expose them via /auth/status so H5 can honor runtime policy without VITE rebuilds.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-07-23 21:33:27 +08:00
parent 13f5c740a1
commit 239c41f935
12 changed files with 639 additions and 43 deletions
+38 -8
View File
@@ -214,6 +214,7 @@ import { createManagedMemoryV2Runtime } from './memory-v2-runtime.mjs';
import { createMemoryV2AdminConfigService } from './memory-v2-admin-config.mjs';
import { createEpisodicMemoryService } from './episodic-memory.mjs';
import { createSkillRuntimeAdminConfigService } from './skill-runtime-admin-config.mjs';
import { createAgentCodeRunAdminConfigService } from './agent-code-run-admin-config.mjs';
import { createWechatScheduleLlmConfigService } from './wechat-schedule-llm-config.mjs';
import { createExperienceService } from './experience-service.mjs';
import { attachAsrRoutes } from './asr-proxy.mjs';
@@ -384,6 +385,7 @@ let memoryV2 = null;
let episodicMemoryService = null;
let memoryV2ConfigService = null;
let skillRuntimeConfigService = null;
let agentCodeRunPolicyService = null;
let wechatScheduleLlmConfigService = null;
let mindSpace = null;
let mindSpaceAssets = null;
@@ -719,6 +721,7 @@ async function bootstrapUserAuth() {
});
memoryV2ConfigService = createMemoryV2AdminConfigService(pool);
skillRuntimeConfigService = createSkillRuntimeAdminConfigService(pool, { h5Root: __dirname });
agentCodeRunPolicyService = createAgentCodeRunAdminConfigService(pool, { env: process.env });
wechatScheduleLlmConfigService = createWechatScheduleLlmConfigService(pool);
conversationMemoryService = createConversationMemoryService(pool, {
llmProviderService,
@@ -1024,6 +1027,16 @@ async function resolveSkillRuntimeForClient() {
}
}
async function resolveAgentCodeRunForClient(userId) {
if (!agentCodeRunPolicyService?.getPublicClientPolicy) return null;
try {
return await agentCodeRunPolicyService.getPublicClientPolicy(userId);
} catch (err) {
console.warn('[AgentCodeRun] public policy unavailable:', err instanceof Error ? err.message : err);
return null;
}
}
app.get('/auth/status', async (req, res) => {
await userAuthReady;
if (userAuth) {
@@ -1033,6 +1046,7 @@ app.get('/auth/status', async (req, res) => {
const row = await userAuth.getUserById(me.id);
const capabilityState = await userAuth.resolveUserCapabilities(row);
const skillRuntime = await resolveSkillRuntimeForClient();
const agentCodeRun = await resolveAgentCodeRunForClient(me.id);
return res.json({
authenticated: true,
user: me,
@@ -1041,6 +1055,7 @@ app.get('/auth/status', async (req, res) => {
grantedSkills: capabilityState.grantedSkills ?? [],
unrestricted: capabilityState.unrestricted,
skillRuntime,
agentCodeRun,
});
} catch (err) {
console.error('[Auth] status failed:', err instanceof Error ? err.message : err);
@@ -2228,12 +2243,21 @@ function runtimeCsvList(value) {
}
function runtimeCodeRunPolicyStatus() {
return {
enabled: runtimeEnvFlag(process.env.MEMIND_AGENT_CODE_RUNS_ENABLED),
userAllowlist: runtimeCsvList(process.env.MEMIND_AGENT_CODE_RUNS_USER_IDS),
taskTypeAllowlist: runtimeCsvList(process.env.MEMIND_AGENT_CODE_RUN_TASK_TYPES),
requireValidation: runtimeEnvFlag(process.env.MEMIND_AGENT_CODE_RUNS_REQUIRE_VALIDATION),
};
return agentCodeRunPolicyService?.getRuntimeStatusSummary
? agentCodeRunPolicyService.getRuntimeStatusSummary()
: Promise.resolve({
source: 'env',
enabled: runtimeEnvFlag(process.env.MEMIND_AGENT_CODE_RUNS_ENABLED),
clientEnabled: runtimeEnvFlag(process.env.VITE_AGENT_CODE_RUNS_ENABLED),
userAllowlist: runtimeCsvList(process.env.MEMIND_AGENT_CODE_RUNS_USER_IDS),
taskTypeAllowlist: runtimeCsvList(process.env.MEMIND_AGENT_CODE_RUN_TASK_TYPES),
requireValidation: runtimeEnvFlag(process.env.MEMIND_AGENT_CODE_RUNS_REQUIRE_VALIDATION),
pageDataDevAutodetect: runtimeEnvFlag(process.env.VITE_AGENT_PAGE_DATA_DEV_AUTODETECT),
generalAutodetect: runtimeEnvFlag(process.env.VITE_AGENT_CODE_RUNS_AUTODETECT),
envOverrideActive: String(process.env.MEMIND_CODE_RUN_POLICY_SOURCE ?? '').trim().toLowerCase() === 'env',
updatedAt: null,
updatedBy: null,
});
}
api.get('/runtime/status', async (_req, res) => {
@@ -2261,7 +2285,7 @@ api.get('/runtime/status', async (_req, res) => {
if (toolQueue) {
status.toolRuntime = {
...(status.toolRuntime ?? {}),
codeRunPolicy: runtimeCodeRunPolicyStatus(),
codeRunPolicy: await runtimeCodeRunPolicyStatus(),
queue: toolQueue,
};
}
@@ -5081,7 +5105,13 @@ api.post('/agent/runs', async (req, res, next) => {
[
tkmindProxy.requireUser,
tkmindProxy.ensureChatAllowed,
createPostAgentRunsHandler({ userAuth, sessionAccess, agentRunGateway, mindSpaceAssetAgent }),
createPostAgentRunsHandler({
userAuth,
sessionAccess,
agentRunGateway,
mindSpaceAssetAgent,
codeRunPolicyService: agentCodeRunPolicyService,
}),
],
req,
res,