@intutic/cli 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/dist/cli.d.ts +0 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +481 -19
- package/dist/cli.js.map +1 -1
- package/dist/commands/apiCommand.d.ts +40 -0
- package/dist/commands/apiCommand.d.ts.map +1 -0
- package/dist/commands/apiCommand.js +88 -0
- package/dist/commands/apiCommand.js.map +1 -0
- package/dist/commands/budget.d.ts +4 -0
- package/dist/commands/budget.d.ts.map +1 -1
- package/dist/commands/budget.js +8 -0
- package/dist/commands/budget.js.map +1 -1
- package/dist/commands/compliance.d.ts +122 -0
- package/dist/commands/compliance.d.ts.map +1 -0
- package/dist/commands/compliance.js +278 -0
- package/dist/commands/compliance.js.map +1 -0
- package/dist/commands/connect.d.ts +26 -1
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +109 -51
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/credentials.d.ts +1 -1
- package/dist/commands/credentials.js +1 -1
- package/dist/commands/decision.d.ts +4 -4
- package/dist/commands/decision.js +4 -4
- package/dist/commands/disconnect.d.ts +4 -0
- package/dist/commands/disconnect.d.ts.map +1 -1
- package/dist/commands/disconnect.js +17 -3
- package/dist/commands/disconnect.js.map +1 -1
- package/dist/commands/doctor.d.ts +0 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +0 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/enforce.d.ts +1 -1
- package/dist/commands/enforce.js +1 -1
- package/dist/commands/enterprise.d.ts +3 -2
- package/dist/commands/enterprise.d.ts.map +1 -1
- package/dist/commands/enterprise.js +11 -3
- package/dist/commands/enterprise.js.map +1 -1
- package/dist/commands/env.js +1 -1
- package/dist/commands/exec.d.ts +2 -3
- package/dist/commands/exec.d.ts.map +1 -1
- package/dist/commands/exec.js +4 -5
- package/dist/commands/exec.js.map +1 -1
- package/dist/commands/gateLiveness.d.ts +15 -0
- package/dist/commands/gateLiveness.d.ts.map +1 -0
- package/dist/commands/gateLiveness.js +34 -0
- package/dist/commands/gateLiveness.js.map +1 -0
- package/dist/commands/gateway.d.ts +14 -4
- package/dist/commands/gateway.d.ts.map +1 -1
- package/dist/commands/gateway.js +34 -4
- package/dist/commands/gateway.js.map +1 -1
- package/dist/commands/github.d.ts +20 -0
- package/dist/commands/github.d.ts.map +1 -0
- package/dist/commands/github.js +41 -0
- package/dist/commands/github.js.map +1 -0
- package/dist/commands/guardrails.d.ts +28 -2
- package/dist/commands/guardrails.d.ts.map +1 -1
- package/dist/commands/guardrails.js +233 -24
- package/dist/commands/guardrails.js.map +1 -1
- package/dist/commands/init.d.ts +1 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +1 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install-daemon.d.ts +1 -1
- package/dist/commands/install-daemon.js +2 -2
- package/dist/commands/integrity.d.ts +10 -2
- package/dist/commands/integrity.d.ts.map +1 -1
- package/dist/commands/integrity.js +3 -3
- package/dist/commands/integrity.js.map +1 -1
- package/dist/commands/inventory.d.ts +60 -0
- package/dist/commands/inventory.d.ts.map +1 -0
- package/dist/commands/inventory.js +141 -0
- package/dist/commands/inventory.js.map +1 -0
- package/dist/commands/judge.d.ts +1 -1
- package/dist/commands/judge.js +2 -2
- package/dist/commands/judge.js.map +1 -1
- package/dist/commands/login.d.ts +0 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +0 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts +0 -1
- package/dist/commands/logout.d.ts.map +1 -1
- package/dist/commands/logout.js +0 -1
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/mcp.d.ts +31 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +65 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/notifications.d.ts +54 -0
- package/dist/commands/notifications.d.ts.map +1 -0
- package/dist/commands/notifications.js +151 -0
- package/dist/commands/notifications.js.map +1 -0
- package/dist/commands/org.d.ts +3 -3
- package/dist/commands/org.js +3 -3
- package/dist/commands/policy.d.ts +6 -1
- package/dist/commands/policy.d.ts.map +1 -1
- package/dist/commands/policy.js +77 -37
- package/dist/commands/policy.js.map +1 -1
- package/dist/commands/rollback.d.ts.map +1 -1
- package/dist/commands/rollback.js +3 -1
- package/dist/commands/rollback.js.map +1 -1
- package/dist/commands/routing.d.ts +1 -1
- package/dist/commands/routing.js +1 -1
- package/dist/commands/rules.d.ts +74 -0
- package/dist/commands/rules.d.ts.map +1 -0
- package/dist/commands/rules.js +283 -0
- package/dist/commands/rules.js.map +1 -0
- package/dist/commands/settings.d.ts +43 -0
- package/dist/commands/settings.d.ts.map +1 -0
- package/dist/commands/settings.js +108 -0
- package/dist/commands/settings.js.map +1 -0
- package/dist/commands/setup.d.ts +1 -1
- package/dist/commands/setup.js +1 -1
- package/dist/commands/siem.d.ts +53 -0
- package/dist/commands/siem.d.ts.map +1 -0
- package/dist/commands/siem.js +132 -0
- package/dist/commands/siem.js.map +1 -0
- package/dist/commands/skill.d.ts +5 -5
- package/dist/commands/skill.js +7 -7
- package/dist/commands/skill.js.map +1 -1
- package/dist/commands/status.d.ts +0 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +2 -3
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/syncContext.d.ts +0 -1
- package/dist/commands/syncContext.d.ts.map +1 -1
- package/dist/commands/syncContext.js +0 -1
- package/dist/commands/syncContext.js.map +1 -1
- package/dist/commands/team.d.ts +2 -2
- package/dist/commands/team.js +2 -2
- package/dist/commands/traces.d.ts +0 -3
- package/dist/commands/traces.d.ts.map +1 -1
- package/dist/commands/traces.js +0 -3
- package/dist/commands/traces.js.map +1 -1
- package/dist/commands/usage.d.ts +41 -0
- package/dist/commands/usage.d.ts.map +1 -0
- package/dist/commands/usage.js +129 -0
- package/dist/commands/usage.js.map +1 -0
- package/dist/commands/whoami.d.ts +0 -1
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +0 -1
- package/dist/commands/whoami.js.map +1 -1
- package/dist/config/keychain.d.ts +0 -1
- package/dist/config/keychain.d.ts.map +1 -1
- package/dist/config/keychain.js +0 -1
- package/dist/config/keychain.js.map +1 -1
- package/dist/config/paths.d.ts +0 -1
- package/dist/config/paths.d.ts.map +1 -1
- package/dist/config/paths.js +0 -1
- package/dist/config/paths.js.map +1 -1
- package/dist/config/store.d.ts +0 -1
- package/dist/config/store.d.ts.map +1 -1
- package/dist/config/store.js +0 -1
- package/dist/config/store.js.map +1 -1
- package/dist/harness/ag2.d.ts +1 -1
- package/dist/harness/ag2.js +1 -1
- package/dist/harness/agentFramework.d.ts +1 -1
- package/dist/harness/agentFramework.js +1 -1
- package/dist/harness/agenticOrchestrator.d.ts +1 -1
- package/dist/harness/agenticOrchestrator.js +2 -2
- package/dist/harness/agenticOrchestrator.js.map +1 -1
- package/dist/harness/agentsMd.d.ts +24 -0
- package/dist/harness/agentsMd.d.ts.map +1 -0
- package/dist/harness/agentsMd.js +28 -0
- package/dist/harness/agentsMd.js.map +1 -0
- package/dist/harness/aider.d.ts +3 -1
- package/dist/harness/aider.d.ts.map +1 -1
- package/dist/harness/aider.js +9 -7
- package/dist/harness/aider.js.map +1 -1
- package/dist/harness/antigravity.d.ts +23 -5
- package/dist/harness/antigravity.d.ts.map +1 -1
- package/dist/harness/antigravity.js +45 -55
- package/dist/harness/antigravity.js.map +1 -1
- package/dist/harness/autogen.d.ts +1 -1
- package/dist/harness/autogen.js +2 -2
- package/dist/harness/autogen.js.map +1 -1
- package/dist/harness/claudeCode.d.ts +22 -1
- package/dist/harness/claudeCode.d.ts.map +1 -1
- package/dist/harness/claudeCode.js +47 -3
- package/dist/harness/claudeCode.js.map +1 -1
- package/dist/harness/cline.d.ts.map +1 -1
- package/dist/harness/cline.js +14 -23
- package/dist/harness/cline.js.map +1 -1
- package/dist/harness/codex.d.ts +6 -1
- package/dist/harness/codex.d.ts.map +1 -1
- package/dist/harness/codex.js +23 -21
- package/dist/harness/codex.js.map +1 -1
- package/dist/harness/continue.d.ts +10 -4
- package/dist/harness/continue.d.ts.map +1 -1
- package/dist/harness/continue.js +22 -22
- package/dist/harness/continue.js.map +1 -1
- package/dist/harness/cursor.d.ts +5 -2
- package/dist/harness/cursor.d.ts.map +1 -1
- package/dist/harness/cursor.js +19 -23
- package/dist/harness/cursor.js.map +1 -1
- package/dist/harness/detector.d.ts +0 -1
- package/dist/harness/detector.d.ts.map +1 -1
- package/dist/harness/detector.js +0 -1
- package/dist/harness/detector.js.map +1 -1
- package/dist/harness/dsh.d.ts +5 -3
- package/dist/harness/dsh.d.ts.map +1 -1
- package/dist/harness/dsh.js +17 -29
- package/dist/harness/dsh.js.map +1 -1
- package/dist/harness/eve.d.ts +3 -4
- package/dist/harness/eve.d.ts.map +1 -1
- package/dist/harness/eve.js +3 -4
- package/dist/harness/eve.js.map +1 -1
- package/dist/harness/githubCopilot.d.ts +4 -1
- package/dist/harness/githubCopilot.d.ts.map +1 -1
- package/dist/harness/githubCopilot.js +12 -20
- package/dist/harness/githubCopilot.js.map +1 -1
- package/dist/harness/goose.d.ts +7 -3
- package/dist/harness/goose.d.ts.map +1 -1
- package/dist/harness/goose.js +18 -21
- package/dist/harness/goose.js.map +1 -1
- package/dist/harness/grok.d.ts +2 -2
- package/dist/harness/grok.d.ts.map +1 -1
- package/dist/harness/grok.js +13 -24
- package/dist/harness/grok.js.map +1 -1
- package/dist/harness/hermes.d.ts +6 -0
- package/dist/harness/hermes.d.ts.map +1 -1
- package/dist/harness/hermes.js +17 -16
- package/dist/harness/hermes.js.map +1 -1
- package/dist/harness/muse.d.ts +3 -7
- package/dist/harness/muse.d.ts.map +1 -1
- package/dist/harness/muse.js +15 -35
- package/dist/harness/muse.js.map +1 -1
- package/dist/harness/n8n.d.ts +13 -14
- package/dist/harness/n8n.d.ts.map +1 -1
- package/dist/harness/n8n.js +21 -181
- package/dist/harness/n8n.js.map +1 -1
- package/dist/harness/openWebUI.d.ts.map +1 -1
- package/dist/harness/openWebUI.js +5 -4
- package/dist/harness/openWebUI.js.map +1 -1
- package/dist/harness/openaiAgents.d.ts +1 -1
- package/dist/harness/openaiAgents.js +2 -2
- package/dist/harness/openaiAgents.js.map +1 -1
- package/dist/harness/openclaw.d.ts +8 -0
- package/dist/harness/openclaw.d.ts.map +1 -1
- package/dist/harness/openclaw.js +27 -12
- package/dist/harness/openclaw.js.map +1 -1
- package/dist/harness/opencode.d.ts +4 -5
- package/dist/harness/opencode.d.ts.map +1 -1
- package/dist/harness/opencode.js +15 -30
- package/dist/harness/opencode.js.map +1 -1
- package/dist/harness/openhands.d.ts +9 -3
- package/dist/harness/openhands.d.ts.map +1 -1
- package/dist/harness/openhands.js +30 -24
- package/dist/harness/openhands.js.map +1 -1
- package/dist/harness/pi.d.ts +7 -2
- package/dist/harness/pi.d.ts.map +1 -1
- package/dist/harness/pi.js +19 -18
- package/dist/harness/pi.js.map +1 -1
- package/dist/harness/rooCode.d.ts +12 -5
- package/dist/harness/rooCode.d.ts.map +1 -1
- package/dist/harness/rooCode.js +23 -39
- package/dist/harness/rooCode.js.map +1 -1
- package/dist/harness/rulesFiles.d.ts +53 -0
- package/dist/harness/rulesFiles.d.ts.map +1 -0
- package/dist/harness/rulesFiles.js +106 -0
- package/dist/harness/rulesFiles.js.map +1 -0
- package/dist/harness/smolagents.d.ts +2 -2
- package/dist/harness/smolagents.js +3 -3
- package/dist/harness/smolagents.js.map +1 -1
- package/dist/harness/types.d.ts +20 -6
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js +1 -95
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/windsurf.d.ts +6 -1
- package/dist/harness/windsurf.d.ts.map +1 -1
- package/dist/harness/windsurf.js +21 -24
- package/dist/harness/windsurf.js.map +1 -1
- package/dist/harness/xirp.d.ts +1 -2
- package/dist/harness/xirp.d.ts.map +1 -1
- package/dist/harness/xirp.js +2 -3
- package/dist/harness/xirp.js.map +1 -1
- package/dist/lib/api.d.ts +27 -1
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +55 -18
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/ciscoScanner.d.ts +1 -1
- package/dist/lib/ciscoScanner.js +1 -1
- package/dist/lib/decisionsLogRefresh.d.ts.map +1 -1
- package/dist/lib/decisionsLogRefresh.js +6 -7
- package/dist/lib/decisionsLogRefresh.js.map +1 -1
- package/dist/lib/deviceReport.d.ts +15 -0
- package/dist/lib/deviceReport.d.ts.map +1 -1
- package/dist/lib/deviceReport.js +30 -0
- package/dist/lib/deviceReport.js.map +1 -1
- package/dist/lib/gitHooks.d.ts +0 -1
- package/dist/lib/gitHooks.d.ts.map +1 -1
- package/dist/lib/gitHooks.js +8 -9
- package/dist/lib/gitHooks.js.map +1 -1
- package/dist/lib/gracefulShutdown.d.ts +1 -1
- package/dist/lib/gracefulShutdown.js +1 -1
- package/dist/lib/hash.d.ts +0 -1
- package/dist/lib/hash.d.ts.map +1 -1
- package/dist/lib/hash.js +0 -1
- package/dist/lib/hash.js.map +1 -1
- package/dist/lib/inventory.d.ts +47 -0
- package/dist/lib/inventory.d.ts.map +1 -0
- package/dist/lib/inventory.js +106 -0
- package/dist/lib/inventory.js.map +1 -0
- package/dist/lib/logger.d.ts +0 -1
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +0 -1
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/mdmManifest.d.ts +30 -2
- package/dist/lib/mdmManifest.d.ts.map +1 -1
- package/dist/lib/mdmManifest.js +50 -2
- package/dist/lib/mdmManifest.js.map +1 -1
- package/dist/lib/onboarding.d.ts +0 -1
- package/dist/lib/onboarding.d.ts.map +1 -1
- package/dist/lib/onboarding.js +1 -2
- package/dist/lib/onboarding.js.map +1 -1
- package/dist/lib/policySnapshot.d.ts +3 -2
- package/dist/lib/policySnapshot.d.ts.map +1 -1
- package/dist/lib/policySnapshot.js +6 -3
- package/dist/lib/policySnapshot.js.map +1 -1
- package/dist/lib/process.d.ts +5 -1
- package/dist/lib/process.d.ts.map +1 -1
- package/dist/lib/process.js +13 -4
- package/dist/lib/process.js.map +1 -1
- package/dist/lib/providerProbe.d.ts +2 -2
- package/dist/lib/providerProbe.js +2 -2
- package/dist/lib/sandbox/firecracker.d.ts +3 -3
- package/dist/lib/sandbox/firecracker.js +3 -3
- package/dist/lib/sandbox/index.d.ts +2 -2
- package/dist/lib/sandbox/index.js +2 -2
- package/dist/lib/sandbox/oci.d.ts +1 -1
- package/dist/lib/sandbox/oci.js +1 -1
- package/dist/lib/sandbox/types.d.ts +1 -1
- package/dist/lib/sandbox/types.js +1 -1
- package/dist/lib/sopFrontMatter.d.ts +1 -1
- package/dist/lib/sopFrontMatter.js +1 -1
- package/package.json +6 -5
- package/resources/sandbox/Dockerfile +1 -1
- package/resources/sandbox/entrypoint.sh +4 -4
- package/resources/sandbox/firecracker-launch.sh +1 -1
- package/dist/harness/base.d.ts +0 -24
- package/dist/harness/base.d.ts.map +0 -1
- package/dist/harness/base.js +0 -74
- package/dist/harness/base.js.map +0 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `intutic mcp` — the workspace's MCP server registry and the decisions every
|
|
3
|
+
* MCP proxy enforces on it.
|
|
4
|
+
*
|
|
5
|
+
* Subcommands:
|
|
6
|
+
* - `intutic mcp list [--json]`
|
|
7
|
+
* - `intutic mcp approve|block|reset <server_id> [--json]`
|
|
8
|
+
* - `intutic mcp enable-tool|disable-tool <server_id> <tool> [--json]`
|
|
9
|
+
*
|
|
10
|
+
* Server side: services/control-plane/src/routes/mcpServers.ts. Approving,
|
|
11
|
+
* blocking, resetting and switching tools need OWNER or ADMIN; listing needs
|
|
12
|
+
* any member. The registry-wide settings (`mcpDefaultPolicy`,
|
|
13
|
+
* `mcpHighRiskToolChange`, `mcpBudgets`) are workspace settings, changed with
|
|
14
|
+
* `intutic settings set`.
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import pc from 'picocolors';
|
|
19
|
+
import { log } from '../lib/logger.js';
|
|
20
|
+
import { runApiCommand } from './apiCommand.js';
|
|
21
|
+
const STATUS_FOR = { approve: 'approved', block: 'blocked', reset: 'candidate' };
|
|
22
|
+
function statusLabel(s) {
|
|
23
|
+
const label = s.status === 'approved' ? pc.green(s.status) : s.status === 'blocked' ? pc.red(s.status) : pc.yellow(s.status);
|
|
24
|
+
return s.heldForReview ? `${label} (held: high-risk tool change)` : label;
|
|
25
|
+
}
|
|
26
|
+
/** `intutic mcp list` */
|
|
27
|
+
export async function runMcpList(opts) {
|
|
28
|
+
await runApiCommand(opts, 'Failed to list MCP servers', (client) => client.get('/api/v1/mcp/servers'), (res) => {
|
|
29
|
+
log.header('Intutic — MCP Servers');
|
|
30
|
+
log.field('Default policy', res.defaultPolicy);
|
|
31
|
+
log.field('High-risk tool change', res.highRiskToolChange);
|
|
32
|
+
log.field('Awaiting a decision', String(res.pendingCount));
|
|
33
|
+
if (res.servers.length === 0) {
|
|
34
|
+
log.dim(' No MCP servers seen yet.');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
for (const s of res.servers) {
|
|
38
|
+
console.log('');
|
|
39
|
+
log.field('Server ID', s.serverId);
|
|
40
|
+
log.field('Name', s.serverName);
|
|
41
|
+
log.field('Status', statusLabel(s));
|
|
42
|
+
log.field('Tools', `${s.tools.length}${s.disabledTools.length > 0 ? ` (disabled: ${s.disabledTools.join(', ')})` : ''}`);
|
|
43
|
+
log.field('Last seen', s.lastSeenAt);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** `intutic mcp approve|block|reset <server_id>` */
|
|
48
|
+
export async function runMcpDecide(action, serverId, opts) {
|
|
49
|
+
await runApiCommand(opts, `Failed to ${action} MCP server ${serverId}`, (client) => client.post(`/api/v1/mcp/servers/${encodeURIComponent(serverId)}/status`, {
|
|
50
|
+
status: STATUS_FOR[action],
|
|
51
|
+
}), (res) => {
|
|
52
|
+
if (action === 'reset')
|
|
53
|
+
log.success(`${res.server.serverName} is back in the approval queue.`);
|
|
54
|
+
else
|
|
55
|
+
log.success(`${res.server.serverName} ${STATUS_FOR[action]}.`);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/** `intutic mcp enable-tool|disable-tool <server_id> <tool>` */
|
|
59
|
+
export async function runMcpTool(serverId, tool, enabled, opts) {
|
|
60
|
+
await runApiCommand(opts, `Failed to ${enabled ? 'enable' : 'disable'} ${tool}`, (client) => client.post(`/api/v1/mcp/servers/${encodeURIComponent(serverId)}/tools`, {
|
|
61
|
+
tool,
|
|
62
|
+
enabled,
|
|
63
|
+
}), (res) => log.success(`${tool} on ${res.server.serverName} ${enabled ? 'enabled' : 'disabled'}.`));
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `intutic notifications` — notification rules: which events go to which
|
|
3
|
+
* Slack channel, email addresses, webhook or PagerDuty service.
|
|
4
|
+
*
|
|
5
|
+
* Subcommands:
|
|
6
|
+
* - `intutic notifications list [--json]`
|
|
7
|
+
* - `intutic notifications create --event <type> --channel <channel> <target flag> [filters] [--json]`
|
|
8
|
+
* - `intutic notifications update <rule_id> [fields] [--json]`
|
|
9
|
+
* - `intutic notifications delete <rule_id> [--json]`
|
|
10
|
+
* - `intutic notifications rotate-secret <rule_id> [--json]`
|
|
11
|
+
*
|
|
12
|
+
* Server side: services/control-plane/src/routes/notifications.ts. A webhook
|
|
13
|
+
* rule's signing secret is generated by the server and returned once — in the
|
|
14
|
+
* response that created it (create, a switch to the webhook channel, or a
|
|
15
|
+
* rotation) — so this prints it once, with a warning to copy it.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import { type ApiCommandOpts } from './apiCommand.js';
|
|
20
|
+
/** The flags `create` and `update` share. */
|
|
21
|
+
export interface RuleFlags {
|
|
22
|
+
event?: string;
|
|
23
|
+
channel?: string;
|
|
24
|
+
slackChannel?: string;
|
|
25
|
+
email?: string;
|
|
26
|
+
webhookUrl?: string;
|
|
27
|
+
pagerdutyKey?: string;
|
|
28
|
+
severity?: string;
|
|
29
|
+
harness?: string;
|
|
30
|
+
user?: string;
|
|
31
|
+
cooldown?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The request body for the given flags: only the fields a flag set, so an
|
|
35
|
+
* update leaves everything else as it is. Channel config and filters are each
|
|
36
|
+
* replaced whole when any of their flags is given, as the route stores them.
|
|
37
|
+
*/
|
|
38
|
+
export declare function ruleBody(flags: RuleFlags): Record<string, unknown>;
|
|
39
|
+
/** `intutic notifications list` */
|
|
40
|
+
export declare function runNotificationsList(opts: ApiCommandOpts): Promise<void>;
|
|
41
|
+
/** `intutic notifications create` */
|
|
42
|
+
export declare function runNotificationsCreate(opts: ApiCommandOpts & RuleFlags & {
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
}): Promise<void>;
|
|
45
|
+
/** `intutic notifications update <rule_id>` */
|
|
46
|
+
export declare function runNotificationsUpdate(ruleId: string, opts: ApiCommandOpts & RuleFlags & {
|
|
47
|
+
enable?: boolean;
|
|
48
|
+
disable?: boolean;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
/** `intutic notifications delete <rule_id>` */
|
|
51
|
+
export declare function runNotificationsDelete(ruleId: string, opts: ApiCommandOpts): Promise<void>;
|
|
52
|
+
/** `intutic notifications rotate-secret <rule_id>` */
|
|
53
|
+
export declare function runNotificationsRotateSecret(ruleId: string, opts: ApiCommandOpts): Promise<void>;
|
|
54
|
+
//# sourceMappingURL=notifications.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../../src/commands/notifications.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,EAA8D,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAwBjH,6CAA6C;AAC7C,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAkBD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA4BlE;AAsBD,mCAAmC;AACnC,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9E;AAED,qCAAqC;AACrC,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,cAAc,GAAG,SAAS,GAAG;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAarH;AAED,+CAA+C;AAC/C,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,cAAc,GAAG,SAAS,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACzE,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,+CAA+C;AAC/C,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhG;AAED,sDAAsD;AACtD,wBAAsB,4BAA4B,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAatG"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `intutic notifications` — notification rules: which events go to which
|
|
3
|
+
* Slack channel, email addresses, webhook or PagerDuty service.
|
|
4
|
+
*
|
|
5
|
+
* Subcommands:
|
|
6
|
+
* - `intutic notifications list [--json]`
|
|
7
|
+
* - `intutic notifications create --event <type> --channel <channel> <target flag> [filters] [--json]`
|
|
8
|
+
* - `intutic notifications update <rule_id> [fields] [--json]`
|
|
9
|
+
* - `intutic notifications delete <rule_id> [--json]`
|
|
10
|
+
* - `intutic notifications rotate-secret <rule_id> [--json]`
|
|
11
|
+
*
|
|
12
|
+
* Server side: services/control-plane/src/routes/notifications.ts. A webhook
|
|
13
|
+
* rule's signing secret is generated by the server and returned once — in the
|
|
14
|
+
* response that created it (create, a switch to the webhook channel, or a
|
|
15
|
+
* rotation) — so this prints it once, with a warning to copy it.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import pc from 'picocolors';
|
|
20
|
+
import { NOTIFICATION_EVENT_TYPES } from '@intutic/shared-types';
|
|
21
|
+
import { log } from '../lib/logger.js';
|
|
22
|
+
import { fail, list, positiveInt, printSigningSecret, runApiCommand } from './apiCommand.js';
|
|
23
|
+
const CHANNELS = ['slack', 'email', 'webhook', 'pagerduty'];
|
|
24
|
+
/**
|
|
25
|
+
* Fails on an event type the API would refuse, suggesting the ones in the
|
|
26
|
+
* same family (`decision.pend` → `decision.pending`, …), or all of them when
|
|
27
|
+
* none share its first segment.
|
|
28
|
+
*/
|
|
29
|
+
function checkEventType(event) {
|
|
30
|
+
if (NOTIFICATION_EVENT_TYPES.includes(event))
|
|
31
|
+
return;
|
|
32
|
+
const family = event.split('.')[0];
|
|
33
|
+
const near = NOTIFICATION_EVENT_TYPES.filter((t) => t.split('.')[0] === family);
|
|
34
|
+
fail(`--event "${event}" is not a notification event type. ` +
|
|
35
|
+
(near.length > 0 ? `Did you mean ${near.join(', ')}?` : `Valid types: ${NOTIFICATION_EVENT_TYPES.join(', ')}.`) +
|
|
36
|
+
' Every type is described at https://docs.intutic.ai/guide/settings#notifications');
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The request body for the given flags: only the fields a flag set, so an
|
|
40
|
+
* update leaves everything else as it is. Channel config and filters are each
|
|
41
|
+
* replaced whole when any of their flags is given, as the route stores them.
|
|
42
|
+
*/
|
|
43
|
+
export function ruleBody(flags) {
|
|
44
|
+
const body = {};
|
|
45
|
+
if (flags.event !== undefined) {
|
|
46
|
+
checkEventType(flags.event);
|
|
47
|
+
body.eventType = flags.event;
|
|
48
|
+
}
|
|
49
|
+
if (flags.channel !== undefined) {
|
|
50
|
+
if (!CHANNELS.includes(flags.channel)) {
|
|
51
|
+
fail(`--channel must be one of ${CHANNELS.join(', ')}, got "${flags.channel}"`);
|
|
52
|
+
}
|
|
53
|
+
body.channel = flags.channel;
|
|
54
|
+
}
|
|
55
|
+
const config = {};
|
|
56
|
+
if (flags.slackChannel !== undefined)
|
|
57
|
+
config.slackChannelId = flags.slackChannel;
|
|
58
|
+
if (flags.email !== undefined)
|
|
59
|
+
config.emailRecipients = list(flags.email);
|
|
60
|
+
if (flags.webhookUrl !== undefined)
|
|
61
|
+
config.webhookUrl = flags.webhookUrl;
|
|
62
|
+
if (flags.pagerdutyKey !== undefined)
|
|
63
|
+
config.pagerdutyRoutingKey = flags.pagerdutyKey;
|
|
64
|
+
if (Object.keys(config).length > 0)
|
|
65
|
+
body.channelConfig = config;
|
|
66
|
+
const filters = {};
|
|
67
|
+
if (flags.severity !== undefined)
|
|
68
|
+
filters.severity = list(flags.severity);
|
|
69
|
+
if (flags.harness !== undefined)
|
|
70
|
+
filters.harnessType = list(flags.harness);
|
|
71
|
+
if (flags.user !== undefined)
|
|
72
|
+
filters.userId = list(flags.user);
|
|
73
|
+
if (Object.keys(filters).length > 0)
|
|
74
|
+
body.filters = filters;
|
|
75
|
+
if (flags.cooldown !== undefined)
|
|
76
|
+
body.cooldownMinutes = positiveInt(flags.cooldown, '--cooldown');
|
|
77
|
+
return body;
|
|
78
|
+
}
|
|
79
|
+
function target(rule) {
|
|
80
|
+
const c = rule.channelConfig;
|
|
81
|
+
switch (rule.channel) {
|
|
82
|
+
case 'slack': return c.slackChannelName ?? c.slackChannelId ?? '—';
|
|
83
|
+
case 'email': return c.emailRecipients?.join(', ') ?? '—';
|
|
84
|
+
case 'webhook': return c.webhookUrl ?? '—';
|
|
85
|
+
case 'pagerduty': return 'routing key set';
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function printRule(rule) {
|
|
89
|
+
log.field('Rule ID', rule.ruleId);
|
|
90
|
+
log.field('Event', rule.eventType);
|
|
91
|
+
log.field('Channel', `${rule.channel} → ${target(rule)}`);
|
|
92
|
+
const filters = Object.entries(rule.filters).filter(([, v]) => v && v.length > 0);
|
|
93
|
+
if (filters.length > 0)
|
|
94
|
+
log.field('Filters', filters.map(([k, v]) => `${k}=${v.join(',')}`).join('; '));
|
|
95
|
+
log.field('Cooldown', `${rule.cooldownMinutes} min`);
|
|
96
|
+
log.field('Enabled', rule.enabled ? pc.green('yes') : pc.dim('no'));
|
|
97
|
+
}
|
|
98
|
+
/** `intutic notifications list` */
|
|
99
|
+
export async function runNotificationsList(opts) {
|
|
100
|
+
await runApiCommand(opts, 'Failed to list notification rules', (client) => client.get('/api/v1/notifications/rules'), (res) => {
|
|
101
|
+
log.header('Intutic — Notification Rules');
|
|
102
|
+
if (res.rules.length === 0) {
|
|
103
|
+
log.dim(' No notification rules.');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
for (const rule of res.rules) {
|
|
107
|
+
console.log('');
|
|
108
|
+
printRule(rule);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/** `intutic notifications create` */
|
|
113
|
+
export async function runNotificationsCreate(opts) {
|
|
114
|
+
const body = ruleBody(opts);
|
|
115
|
+
if (opts.disabled)
|
|
116
|
+
body.enabled = false;
|
|
117
|
+
await runApiCommand(opts, 'Failed to create notification rule', (client) => client.post('/api/v1/notifications/rules', body), (rule) => {
|
|
118
|
+
log.success('Notification rule created.');
|
|
119
|
+
printRule(rule);
|
|
120
|
+
printSigningSecret(rule.signingSecret);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/** `intutic notifications update <rule_id>` */
|
|
124
|
+
export async function runNotificationsUpdate(ruleId, opts) {
|
|
125
|
+
if (opts.enable && opts.disable)
|
|
126
|
+
fail('Pass --enable or --disable, not both.');
|
|
127
|
+
const body = ruleBody(opts);
|
|
128
|
+
if (opts.enable)
|
|
129
|
+
body.enabled = true;
|
|
130
|
+
if (opts.disable)
|
|
131
|
+
body.enabled = false;
|
|
132
|
+
if (Object.keys(body).length === 0)
|
|
133
|
+
fail('Nothing to update: pass at least one field to change.');
|
|
134
|
+
await runApiCommand(opts, `Failed to update notification rule ${ruleId}`, (client) => client.put(`/api/v1/notifications/rules/${encodeURIComponent(ruleId)}`, body), (rule) => {
|
|
135
|
+
log.success('Notification rule updated.');
|
|
136
|
+
printRule(rule);
|
|
137
|
+
printSigningSecret(rule.signingSecret);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/** `intutic notifications delete <rule_id>` */
|
|
141
|
+
export async function runNotificationsDelete(ruleId, opts) {
|
|
142
|
+
await runApiCommand(opts, `Failed to delete notification rule ${ruleId}`, (client) => client.del(`/api/v1/notifications/rules/${encodeURIComponent(ruleId)}`), () => log.success(`Notification rule ${ruleId} deleted.`));
|
|
143
|
+
}
|
|
144
|
+
/** `intutic notifications rotate-secret <rule_id>` */
|
|
145
|
+
export async function runNotificationsRotateSecret(ruleId, opts) {
|
|
146
|
+
await runApiCommand(opts, `Failed to replace the signing secret of ${ruleId}`, (client) => client.post(`/api/v1/notifications/rules/${encodeURIComponent(ruleId)}/signing-secret`), (res) => {
|
|
147
|
+
log.success(`New signing secret for ${res.ruleId}; deliveries are signed with it from now on.`);
|
|
148
|
+
printSigningSecret(res.signingSecret);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=notifications.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../src/commands/notifications.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/org.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `intutic org create` — create a real org from an already-authenticated
|
|
3
|
-
* session
|
|
3
|
+
* session.
|
|
4
4
|
*
|
|
5
|
-
* Real org creation now requires DNS domain-ownership verification
|
|
6
|
-
*
|
|
5
|
+
* Real org creation now requires DNS domain-ownership verification:
|
|
6
|
+
* creating an org auto-provisions a real managed gateway cell,
|
|
7
7
|
* so an org's claimed domain must be proven before `POST /api/v1/orgs` will
|
|
8
8
|
* create it. There's no anonymous-compatible verification flow (no session
|
|
9
9
|
* exists yet to own a verification attempt against), so the old anonymous
|
package/dist/commands/org.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `intutic org create` — create a real org from an already-authenticated
|
|
3
|
-
* session
|
|
3
|
+
* session.
|
|
4
4
|
*
|
|
5
|
-
* Real org creation now requires DNS domain-ownership verification
|
|
6
|
-
*
|
|
5
|
+
* Real org creation now requires DNS domain-ownership verification:
|
|
6
|
+
* creating an org auto-provisions a real managed gateway cell,
|
|
7
7
|
* so an org's claimed domain must be proven before `POST /api/v1/orgs` will
|
|
8
8
|
* create it. There's no anonymous-compatible verification flow (no session
|
|
9
9
|
* exists yet to own a verification attempt against), so the old anonymous
|
|
@@ -113,11 +113,16 @@ export declare const explainUnsupportedImport: typeof explainWasmImport;
|
|
|
113
113
|
* Instantiates a compiled rule with the proxy's host imports and evaluates it
|
|
114
114
|
* against one mock context, returning the raw verdict code.
|
|
115
115
|
*
|
|
116
|
+
* The rule is metered as the MCP proxy meters it, against the proxies'
|
|
117
|
+
* budget (`DEFAULT_FUEL_BUDGET`, the Rust proxy's `limits::NATIVE`): a rule
|
|
118
|
+
* that runs out of instructions there throws here, saying so. `budget` is
|
|
119
|
+
* for tests.
|
|
120
|
+
*
|
|
116
121
|
* The import set here is the proxy's, not a convenient superset: a rule that
|
|
117
122
|
* links in this sandbox must link in the proxy, or install validation passes
|
|
118
123
|
* something the proxy then silently bypasses.
|
|
119
124
|
*/
|
|
120
|
-
export declare function instantiateAndEvaluate(wasmBuffer: Uint8Array, mockStr: string): Promise<number>;
|
|
125
|
+
export declare function instantiateAndEvaluate(wasmBuffer: Uint8Array, mockStr: string, budget?: number): Promise<number>;
|
|
121
126
|
export declare function runPolicyTest(opts: {
|
|
122
127
|
wasm: string;
|
|
123
128
|
mock: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/commands/policy.ts"],"names":[],"mappings":"AAOA,OAAO,
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/commands/policy.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/policy.js
CHANGED
|
@@ -5,7 +5,8 @@ import { createHash } from 'node:crypto';
|
|
|
5
5
|
import { spawn } from 'node:child_process';
|
|
6
6
|
import { log } from '../lib/logger.js';
|
|
7
7
|
import { NOT_AUTHENTICATED } from '../lib/authMessages.js';
|
|
8
|
-
import { WASM_HOST_IMPORTS, unsupportedWasmImports, explainWasmImport, } from '@intutic/shared-types';
|
|
8
|
+
import { DEFAULT_FUEL_BUDGET, FUEL_EXPORT, WASM_HOST_IMPORTS, unsupportedWasmImports, explainWasmImport, isOpaModule, meterFuel, } from '@intutic/shared-types';
|
|
9
|
+
import { decideCase, loadMeteredRegoRule } from './rules.js';
|
|
9
10
|
import { loadCredentials, loadConfig } from '../config/store.js';
|
|
10
11
|
import { resolveControlPlaneUrl } from '../config/paths.js';
|
|
11
12
|
import { createApiClient } from '../lib/api.js';
|
|
@@ -230,7 +231,8 @@ function resolveGuestAbi(instance) {
|
|
|
230
231
|
}
|
|
231
232
|
// Accept exactly the allocator exports the proxy runner accepts
|
|
232
233
|
// (packages/proxy/src/wasm/runner.rs: `allocate`, then `__new`) — anything
|
|
233
|
-
// looser would validate rules the proxy then
|
|
234
|
+
// looser would validate rules the proxy then cannot run: they reach no
|
|
235
|
+
// verdict on every call, so every call is refused.
|
|
234
236
|
let allocate;
|
|
235
237
|
const allocateExport = exportedFunction(exports, 'allocate');
|
|
236
238
|
if (allocateExport) {
|
|
@@ -301,11 +303,16 @@ export const explainUnsupportedImport = explainWasmImport;
|
|
|
301
303
|
* Instantiates a compiled rule with the proxy's host imports and evaluates it
|
|
302
304
|
* against one mock context, returning the raw verdict code.
|
|
303
305
|
*
|
|
306
|
+
* The rule is metered as the MCP proxy meters it, against the proxies'
|
|
307
|
+
* budget (`DEFAULT_FUEL_BUDGET`, the Rust proxy's `limits::NATIVE`): a rule
|
|
308
|
+
* that runs out of instructions there throws here, saying so. `budget` is
|
|
309
|
+
* for tests.
|
|
310
|
+
*
|
|
304
311
|
* The import set here is the proxy's, not a convenient superset: a rule that
|
|
305
312
|
* links in this sandbox must link in the proxy, or install validation passes
|
|
306
313
|
* something the proxy then silently bypasses.
|
|
307
314
|
*/
|
|
308
|
-
export async function instantiateAndEvaluate(wasmBuffer, mockStr) {
|
|
315
|
+
export async function instantiateAndEvaluate(wasmBuffer, mockStr, budget = DEFAULT_FUEL_BUDGET) {
|
|
309
316
|
let instanceRef = null;
|
|
310
317
|
/**
|
|
311
318
|
* Guest memory, or null before `WebAssembly.instantiate` has resolved.
|
|
@@ -426,7 +433,7 @@ export async function instantiateAndEvaluate(wasmBuffer, mockStr) {
|
|
|
426
433
|
// error: function import requires a callable". Same outcome either way — the
|
|
427
434
|
// instantiate below would throw — but a rule author needs to know it was
|
|
428
435
|
// `Math.random()`.
|
|
429
|
-
const compiled = await WebAssembly.compile(new Uint8Array(wasmBuffer));
|
|
436
|
+
const compiled = await WebAssembly.compile(meterFuel(new Uint8Array(wasmBuffer), budget));
|
|
430
437
|
const unsupported = unsupportedImports(compiled);
|
|
431
438
|
if (unsupported.length > 0) {
|
|
432
439
|
throw new Error(`rule imports ${unsupported.length} function(s) the proxy sandbox does not provide:\n` +
|
|
@@ -436,13 +443,22 @@ export async function instantiateAndEvaluate(wasmBuffer, mockStr) {
|
|
|
436
443
|
const instance = await WebAssembly.instantiate(compiled, imports);
|
|
437
444
|
instanceRef = instance;
|
|
438
445
|
const abi = resolveGuestAbi(instance);
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
+
const fuel = instance.exports[FUEL_EXPORT];
|
|
447
|
+
try {
|
|
448
|
+
const jsonBytes = Buffer.from(mockStr);
|
|
449
|
+
const offset = abi.allocate(jsonBytes.length);
|
|
450
|
+
// Re-read `abi.memory.buffer` here rather than caching a view: `allocate` can
|
|
451
|
+
// grow the memory, which detaches every ArrayBuffer taken before the call.
|
|
452
|
+
const memView = new Uint8Array(abi.memory.buffer, offset, jsonBytes.length);
|
|
453
|
+
memView.set(jsonBytes);
|
|
454
|
+
return abi.evaluate(offset, jsonBytes.length);
|
|
455
|
+
}
|
|
456
|
+
catch (err) {
|
|
457
|
+
if (fuel instanceof WebAssembly.Global && fuel.value < 0) {
|
|
458
|
+
throw new Error(`WASM rule ran out of its ${budget}-instruction budget; a proxy reaches no verdict and refuses the call as GOVERNANCE_UNAVAILABLE`, { cause: err });
|
|
459
|
+
}
|
|
460
|
+
throw err;
|
|
461
|
+
}
|
|
446
462
|
}
|
|
447
463
|
export async function runPolicyTest(opts) {
|
|
448
464
|
log.header('Intutic — Test Local WASM Policy Rule');
|
|
@@ -463,6 +479,10 @@ export async function runPolicyTest(opts) {
|
|
|
463
479
|
log.error(`Failed to read or parse mock context JSON at "${opts.mock}": ${errMessage(err)}`);
|
|
464
480
|
process.exit(1);
|
|
465
481
|
}
|
|
482
|
+
if (isOpaModule(new WebAssembly.Module(new Uint8Array(wasmBuffer)))) {
|
|
483
|
+
log.error(`"${opts.wasm}" is a Rego rule. Test it with: intutic rules test ${opts.wasm} --input <cases.json>`);
|
|
484
|
+
process.exit(1);
|
|
485
|
+
}
|
|
466
486
|
try {
|
|
467
487
|
const verdict = await instantiateAndEvaluate(wasmBuffer, mockStr);
|
|
468
488
|
log.info(`Dry-run evaluation executed successfully.`);
|
|
@@ -484,8 +504,8 @@ export async function runPolicyTest(opts) {
|
|
|
484
504
|
}
|
|
485
505
|
else {
|
|
486
506
|
log.error(`Result: unmapped verdict code ${verdict}`);
|
|
487
|
-
log.info(' Valid codes are 0 (allow), 1 (block) and 3 (reask).
|
|
488
|
-
log.info('
|
|
507
|
+
log.info(' Valid codes are 0 (allow), 1 (block) and 3 (reask). Anything else is');
|
|
508
|
+
log.info(' no verdict: the proxy refuses the call with GOVERNANCE_UNAVAILABLE.');
|
|
489
509
|
}
|
|
490
510
|
}
|
|
491
511
|
catch (err) {
|
|
@@ -609,7 +629,7 @@ export async function uploadCandidateBundle(client, candidateId, wasmPath, sourc
|
|
|
609
629
|
log.error(`Rule candidate "${candidateId}" was not found in this workspace.`);
|
|
610
630
|
process.exit(1);
|
|
611
631
|
}
|
|
612
|
-
if (status === 400 || status === 409) {
|
|
632
|
+
if (status === 400 || status === 403 || status === 409) {
|
|
613
633
|
log.error(`Refused: ${body.error ?? `HTTP ${status}`}${body.detail ? ` — ${body.detail}` : ''}`);
|
|
614
634
|
process.exit(1);
|
|
615
635
|
}
|
|
@@ -698,33 +718,46 @@ export async function runPolicyInstall(opts) {
|
|
|
698
718
|
log.error(`Failed to read WASM file at "${opts.wasm}": ${errMessage(err)}`);
|
|
699
719
|
process.exit(1);
|
|
700
720
|
}
|
|
701
|
-
//
|
|
702
|
-
//
|
|
721
|
+
// A Rego rule is validated by the Rego host: it must load (a builtin the
|
|
722
|
+
// host lacks is refused here, by name) and evaluate an input.
|
|
723
|
+
let rego;
|
|
703
724
|
try {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
// clean and then enforces nothing — the same silent shape as a rule that
|
|
708
|
-
// cannot link. 2 is accepted here because already-installed rules use it,
|
|
709
|
-
// but it is deprecated and reported as such.
|
|
710
|
-
if (validationVerdict === 2) {
|
|
711
|
-
// Accepted, because refusing it would break reinstalling a rule that
|
|
712
|
-
// already shipped — but never silently. The guest never receives the
|
|
713
|
-
// request body, so redaction was never expressible, and the proxy maps 2
|
|
714
|
-
// to a block. An author who believes they are redacting is blocking.
|
|
715
|
-
log.warn('Rule returned verdict code 2 (REDACT), which is deprecated. The proxy treats it ' +
|
|
716
|
-
'as a block. Return 1 to block, or 3 to reask.');
|
|
717
|
-
}
|
|
718
|
-
if (![0, 1, 2, 3].includes(validationVerdict)) {
|
|
719
|
-
log.error(`Rule returned verdict code ${validationVerdict}, which the proxy does not map — ` +
|
|
720
|
-
'it would be allowed on every request. Valid codes: 0 allow, 1 block, 3 reask.');
|
|
721
|
-
process.exit(1);
|
|
722
|
-
}
|
|
725
|
+
rego = loadMeteredRegoRule(wasmBuffer);
|
|
726
|
+
if (rego)
|
|
727
|
+
decideCase(rego, { tool: null, args: null });
|
|
723
728
|
}
|
|
724
729
|
catch (err) {
|
|
725
|
-
log.error(`
|
|
730
|
+
log.error(`Rego rule failed validation and was NOT installed: ${errMessage(err)}`);
|
|
726
731
|
process.exit(1);
|
|
727
732
|
}
|
|
733
|
+
// Refuse to install a rule that cannot instantiate or evaluate — a broken
|
|
734
|
+
// rule reaches no verdict on any call, so every call would be refused.
|
|
735
|
+
if (!rego) {
|
|
736
|
+
try {
|
|
737
|
+
const validationVerdict = await instantiateAndEvaluate(wasmBuffer, DEFAULT_ALLOW_MOCK);
|
|
738
|
+
// Refuse a code the proxy does not map. Everything outside {0,1,2,3} is
|
|
739
|
+
// no verdict at runtime, so a rule inventing a rung would install clean
|
|
740
|
+
// and then refuse every call. 2 is accepted here because already-installed rules use it,
|
|
741
|
+
// but it is deprecated and reported as such.
|
|
742
|
+
if (validationVerdict === 2) {
|
|
743
|
+
// Accepted, because refusing it would break reinstalling a rule that
|
|
744
|
+
// already shipped — but never silently. The guest never receives the
|
|
745
|
+
// request body, so redaction was never expressible, and the proxy maps 2
|
|
746
|
+
// to a block. An author who believes they are redacting is blocking.
|
|
747
|
+
log.warn('Rule returned verdict code 2 (REDACT), which is deprecated. The proxy treats it ' +
|
|
748
|
+
'as a block. Return 1 to block, or 3 to reask.');
|
|
749
|
+
}
|
|
750
|
+
if (![0, 1, 2, 3].includes(validationVerdict)) {
|
|
751
|
+
log.error(`Rule returned verdict code ${validationVerdict}, which is not a verdict — ` +
|
|
752
|
+
'the proxy would refuse every such call with GOVERNANCE_UNAVAILABLE. Valid codes: 0 allow, 1 block, 3 reask.');
|
|
753
|
+
process.exit(1);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
catch (err) {
|
|
757
|
+
log.error(`Rule failed validation and was NOT installed: ${errMessage(err)}`);
|
|
758
|
+
process.exit(1);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
728
761
|
const priority = parseInt(opts.priority ?? '100', 10);
|
|
729
762
|
if (isNaN(priority) || priority < 0) {
|
|
730
763
|
log.error(`Invalid priority "${opts.priority}". Must be a non-negative integer.`);
|
|
@@ -743,7 +776,9 @@ export async function runPolicyInstall(opts) {
|
|
|
743
776
|
process.exit(1);
|
|
744
777
|
}
|
|
745
778
|
const sha256 = createHash('sha256').update(wasmBuffer).digest('hex');
|
|
746
|
-
log.success(`Installed rule "${name}"`);
|
|
779
|
+
log.success(`Installed ${rego ? 'Rego ' : ''}rule "${name}"`);
|
|
780
|
+
if (rego)
|
|
781
|
+
log.field('Entrypoint', rego.entrypoint);
|
|
747
782
|
log.field('Path', dest);
|
|
748
783
|
log.field('Priority', String(priority));
|
|
749
784
|
log.field('SHA-256', sha256);
|
|
@@ -800,6 +835,11 @@ export async function runPolicyReplay(ruleId, opts) {
|
|
|
800
835
|
}
|
|
801
836
|
process.exit(1);
|
|
802
837
|
}
|
|
838
|
+
if (status === 403) {
|
|
839
|
+
const detail = result.detail;
|
|
840
|
+
log.error(`Replay refused: ${detail ?? 'your role cannot replay rules'}`);
|
|
841
|
+
process.exit(1);
|
|
842
|
+
}
|
|
803
843
|
if (status !== 200) {
|
|
804
844
|
log.error(`Replay failed (${status}): ${JSON.stringify(result)}`);
|
|
805
845
|
process.exit(1);
|