nexarch 0.6.2 → 0.6.4
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import process from "process";
|
|
2
|
-
import { existsSync, readFileSync
|
|
2
|
+
import { existsSync, readFileSync } from "fs";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import { homedir } from "os";
|
|
5
5
|
import { requireCredentials } from "../lib/credentials.js";
|
|
@@ -35,66 +35,6 @@ function loadIdentity() {
|
|
|
35
35
|
return { agentKey: null, projectKeys: [] };
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
function safeReadText(path, maxChars = 6000) {
|
|
39
|
-
if (!existsSync(path))
|
|
40
|
-
return null;
|
|
41
|
-
try {
|
|
42
|
-
return readFileSync(path, "utf8").slice(0, maxChars);
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
function collectEvidenceFromRepo() {
|
|
49
|
-
const cwd = process.cwd();
|
|
50
|
-
const readme = safeReadText(join(cwd, "README.md"), 8000)
|
|
51
|
-
?? safeReadText(join(cwd, "readme.md"), 8000)
|
|
52
|
-
?? undefined;
|
|
53
|
-
const packageJson = safeReadText(join(cwd, "package.json"), 5000);
|
|
54
|
-
const notes = [];
|
|
55
|
-
if (packageJson)
|
|
56
|
-
notes.push("package.json detected");
|
|
57
|
-
const files = [];
|
|
58
|
-
if (packageJson)
|
|
59
|
-
files.push({ path: "package.json", content: packageJson });
|
|
60
|
-
const srcDir = join(cwd, "src");
|
|
61
|
-
if (existsSync(srcDir)) {
|
|
62
|
-
try {
|
|
63
|
-
const entries = readdirSync(srcDir)
|
|
64
|
-
.filter((name) => /\.(ts|tsx|js|jsx)$/i.test(name))
|
|
65
|
-
.slice(0, 8);
|
|
66
|
-
for (const name of entries) {
|
|
67
|
-
const full = join(srcDir, name);
|
|
68
|
-
try {
|
|
69
|
-
if (!statSync(full).isFile())
|
|
70
|
-
continue;
|
|
71
|
-
const content = safeReadText(full, 4000);
|
|
72
|
-
if (content)
|
|
73
|
-
files.push({ path: `src/${name}`, content });
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
// ignore per-file failures
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
if (entries.length > 0)
|
|
80
|
-
notes.push(`included ${entries.length} source file snippet(s)`);
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
// ignore directory read issues
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
const summary = [
|
|
87
|
-
`cwd=${cwd}`,
|
|
88
|
-
readme ? "README included" : "README missing",
|
|
89
|
-
files.length > 0 ? `evidence files=${files.length}` : "no evidence files collected",
|
|
90
|
-
].join("; ");
|
|
91
|
-
return {
|
|
92
|
-
summary,
|
|
93
|
-
...(readme ? { readme } : {}),
|
|
94
|
-
...(notes.length ? { notes: notes.join("; ") } : {}),
|
|
95
|
-
...(files.length ? { files } : {}),
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
38
|
export async function checkIn(args) {
|
|
99
39
|
const asJson = parseFlag(args, "--json");
|
|
100
40
|
const agentKeyArg = parseOptionValue(args, "--agent-key");
|
|
@@ -102,7 +42,6 @@ export async function checkIn(args) {
|
|
|
102
42
|
const creds = requireCredentials();
|
|
103
43
|
const identity = loadIdentity();
|
|
104
44
|
const agentKey = agentKeyArg ?? identity.agentKey;
|
|
105
|
-
// Use --project flag as a single override, otherwise send all stored keys
|
|
106
45
|
const resolvedProjectKeys = projectKey ? [projectKey] : identity.projectKeys;
|
|
107
46
|
if (!agentKey) {
|
|
108
47
|
if (asJson) {
|
|
@@ -113,46 +52,46 @@ export async function checkIn(args) {
|
|
|
113
52
|
}
|
|
114
53
|
return;
|
|
115
54
|
}
|
|
116
|
-
const mcpOpts = { companyId: creds.companyId };
|
|
117
|
-
const evidence = collectEvidenceFromRepo();
|
|
118
55
|
const raw = await callMcpTool("nexarch_claim_command", {
|
|
119
56
|
agentKey,
|
|
120
57
|
...(resolvedProjectKeys.length > 0 ? { projectKeys: resolvedProjectKeys } : {}),
|
|
121
|
-
evidence,
|
|
122
58
|
companyId: creds.companyId,
|
|
123
|
-
},
|
|
59
|
+
}, { companyId: creds.companyId });
|
|
124
60
|
const result = parseToolText(raw);
|
|
125
61
|
if (asJson) {
|
|
126
62
|
process.stdout.write(JSON.stringify(result) + "\n");
|
|
127
63
|
return;
|
|
128
64
|
}
|
|
129
|
-
|
|
130
|
-
|
|
65
|
+
const commands = result.commands ?? [];
|
|
66
|
+
if (commands.length === 0) {
|
|
67
|
+
console.log("No pending application-target commands found.");
|
|
131
68
|
return;
|
|
132
69
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
70
|
+
console.log("\nPending application-target commands (preview only; nothing claimed):");
|
|
71
|
+
for (const cmd of commands) {
|
|
72
|
+
const claimable = cmd.claimable ? "yes" : "no";
|
|
73
|
+
const reason = cmd.claimReason ?? (cmd.claimable ? "in_project_scope" : "missing_project_scope");
|
|
74
|
+
console.log(`\n- ID : ${cmd.id}`);
|
|
75
|
+
console.log(` Type : ${cmd.command_type}`);
|
|
76
|
+
console.log(` Target : ${cmd.target_entity_key ?? "(none)"}`);
|
|
77
|
+
console.log(` Priority : ${cmd.priority}`);
|
|
78
|
+
console.log(` Claimable : ${claimable} (${reason})`);
|
|
79
|
+
if (cmd.command_type_version != null)
|
|
80
|
+
console.log(` Type ver : ${cmd.command_type_version}`);
|
|
81
|
+
if (cmd.resolved_runtime_handler)
|
|
82
|
+
console.log(` Runtime : ${cmd.resolved_runtime_handler}`);
|
|
83
|
+
if (cmd.claimable) {
|
|
84
|
+
console.log(` Claim cmd : npx nexarch command-claim --id "${cmd.id}"${cmd.target_entity_key ? ` --project "${cmd.target_entity_key}"` : ""}`);
|
|
85
|
+
}
|
|
147
86
|
}
|
|
148
|
-
|
|
149
|
-
|
|
87
|
+
console.log("\nCurrent project scope:");
|
|
88
|
+
if (resolvedProjectKeys.length === 0) {
|
|
89
|
+
console.log(" (none) — use --project <application:key> to scope claims");
|
|
150
90
|
}
|
|
151
|
-
|
|
152
|
-
|
|
91
|
+
else {
|
|
92
|
+
for (const key of resolvedProjectKeys)
|
|
93
|
+
console.log(` - ${key}`);
|
|
153
94
|
}
|
|
154
|
-
console.log(
|
|
155
|
-
console.log(
|
|
156
|
-
console.log(`\nIf it fails, run:`);
|
|
157
|
-
console.log(` npx nexarch command-fail --id "${cmd.id}" --error "..."`);
|
|
95
|
+
console.log("\nTo validate an application target is accessible in Nexarch before claiming:");
|
|
96
|
+
console.log(" npx nexarch policy-controls --entity <application:key> --json");
|
|
158
97
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import process from "process";
|
|
2
|
+
import { existsSync, readFileSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
import { requireCredentials } from "../lib/credentials.js";
|
|
6
|
+
import { callMcpTool } from "../lib/mcp.js";
|
|
7
|
+
function parseFlag(args, flag) {
|
|
8
|
+
return args.includes(flag);
|
|
9
|
+
}
|
|
10
|
+
function parseOptionValue(args, option) {
|
|
11
|
+
const idx = args.indexOf(option);
|
|
12
|
+
if (idx === -1)
|
|
13
|
+
return null;
|
|
14
|
+
const v = args[idx + 1];
|
|
15
|
+
if (!v || v.startsWith("--"))
|
|
16
|
+
return null;
|
|
17
|
+
return v;
|
|
18
|
+
}
|
|
19
|
+
function parseToolText(result) {
|
|
20
|
+
const text = result.content?.[0]?.text ?? "{}";
|
|
21
|
+
return JSON.parse(text);
|
|
22
|
+
}
|
|
23
|
+
function loadIdentity() {
|
|
24
|
+
const identityPath = join(homedir(), ".nexarch", "identity.json");
|
|
25
|
+
if (!existsSync(identityPath))
|
|
26
|
+
return { agentKey: null, projectKeys: [] };
|
|
27
|
+
try {
|
|
28
|
+
const data = JSON.parse(readFileSync(identityPath, "utf8"));
|
|
29
|
+
return {
|
|
30
|
+
agentKey: data.agentKey ?? null,
|
|
31
|
+
projectKeys: Array.isArray(data.projectKeys) ? data.projectKeys : [],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return { agentKey: null, projectKeys: [] };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export async function commandClaim(args) {
|
|
39
|
+
const asJson = parseFlag(args, "--json");
|
|
40
|
+
const id = parseOptionValue(args, "--id");
|
|
41
|
+
const agentKeyArg = parseOptionValue(args, "--agent-key");
|
|
42
|
+
const projectKey = parseOptionValue(args, "--project");
|
|
43
|
+
if (!id) {
|
|
44
|
+
console.error("error: --id <commandId> is required");
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
const creds = requireCredentials();
|
|
48
|
+
const identity = loadIdentity();
|
|
49
|
+
const agentKey = agentKeyArg ?? identity.agentKey;
|
|
50
|
+
const resolvedProjectKeys = projectKey ? [projectKey] : identity.projectKeys;
|
|
51
|
+
if (!agentKey) {
|
|
52
|
+
console.error("error: no agent key found. Pass --agent-key or run nexarch init-agent first.");
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
const raw = await callMcpTool("nexarch_claim_command_by_id", {
|
|
56
|
+
commandId: id,
|
|
57
|
+
agentKey,
|
|
58
|
+
...(resolvedProjectKeys.length > 0 ? { projectKeys: resolvedProjectKeys } : {}),
|
|
59
|
+
companyId: creds.companyId,
|
|
60
|
+
}, { companyId: creds.companyId });
|
|
61
|
+
const result = parseToolText(raw);
|
|
62
|
+
if (asJson) {
|
|
63
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (!result.command) {
|
|
67
|
+
console.log(`Command ${id} was not claimed.`);
|
|
68
|
+
if (result.reason)
|
|
69
|
+
console.log(`Reason: ${result.reason}`);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const cmd = result.command;
|
|
73
|
+
console.log(`\n╔══════════════════════════════════════════════════════════════════╗`);
|
|
74
|
+
console.log(`║ COMMAND CLAIMED — action required ║`);
|
|
75
|
+
console.log(`╚══════════════════════════════════════════════════════════════════╝`);
|
|
76
|
+
console.log(`\nCommand ID : ${cmd.id}`);
|
|
77
|
+
console.log(`Type : ${cmd.command_type}`);
|
|
78
|
+
console.log(`Target : ${cmd.target_entity_key ?? "(any)"}`);
|
|
79
|
+
console.log(`Priority : ${cmd.priority}`);
|
|
80
|
+
if (cmd.resolved_runtime_handler)
|
|
81
|
+
console.log(`Runtime : ${cmd.resolved_runtime_handler}`);
|
|
82
|
+
if (cmd.command_type_version != null)
|
|
83
|
+
console.log(`Type ver : ${cmd.command_type_version}`);
|
|
84
|
+
if (Object.keys(cmd.command_params).length > 0) {
|
|
85
|
+
console.log(`Params : ${JSON.stringify(cmd.command_params)}`);
|
|
86
|
+
}
|
|
87
|
+
if (cmd.resolved_playbook_text?.trim()) {
|
|
88
|
+
console.log(`\nPlaybook:\n${cmd.resolved_playbook_text}`);
|
|
89
|
+
}
|
|
90
|
+
if (cmd.instructions) {
|
|
91
|
+
console.log(`\nInstructions:\n${cmd.instructions}`);
|
|
92
|
+
}
|
|
93
|
+
console.log(`\nWhen done, run:`);
|
|
94
|
+
console.log(` npx nexarch command-done --id "${cmd.id}" --summary "..."`);
|
|
95
|
+
console.log(`\nIf it fails, run:`);
|
|
96
|
+
console.log(` npx nexarch command-fail --id "${cmd.id}" --error "..."`);
|
|
97
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import process from "process";
|
|
2
|
+
import { existsSync, readFileSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
import { requireCredentials } from "../lib/credentials.js";
|
|
6
|
+
import { callMcpTool } from "../lib/mcp.js";
|
|
7
|
+
function parseFlag(args, flag) {
|
|
8
|
+
return args.includes(flag);
|
|
9
|
+
}
|
|
10
|
+
function parseOptionValue(args, option) {
|
|
11
|
+
const idx = args.indexOf(option);
|
|
12
|
+
if (idx === -1)
|
|
13
|
+
return null;
|
|
14
|
+
const v = args[idx + 1];
|
|
15
|
+
if (!v || v.startsWith("--"))
|
|
16
|
+
return null;
|
|
17
|
+
return v;
|
|
18
|
+
}
|
|
19
|
+
function parseMultiOptionValues(args, option) {
|
|
20
|
+
const values = [];
|
|
21
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
22
|
+
if (args[i] !== option)
|
|
23
|
+
continue;
|
|
24
|
+
const v = args[i + 1];
|
|
25
|
+
if (!v || v.startsWith("--"))
|
|
26
|
+
continue;
|
|
27
|
+
values.push(v);
|
|
28
|
+
}
|
|
29
|
+
return values;
|
|
30
|
+
}
|
|
31
|
+
function parseToolText(result) {
|
|
32
|
+
const text = result.content?.[0]?.text ?? "{}";
|
|
33
|
+
return JSON.parse(text);
|
|
34
|
+
}
|
|
35
|
+
function loadIdentityAgentKey() {
|
|
36
|
+
const identityPath = join(homedir(), ".nexarch", "identity.json");
|
|
37
|
+
if (!existsSync(identityPath))
|
|
38
|
+
return null;
|
|
39
|
+
try {
|
|
40
|
+
const data = JSON.parse(readFileSync(identityPath, "utf8"));
|
|
41
|
+
return data.agentKey ?? null;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function parseFindingToken(token) {
|
|
48
|
+
const [policyControlId, policyRuleId, resultRaw, rationaleRaw, missingRaw] = token.split("|");
|
|
49
|
+
const result = (resultRaw ?? "").trim().toLowerCase();
|
|
50
|
+
if (!policyControlId?.trim() || !policyRuleId?.trim() || !result) {
|
|
51
|
+
throw new Error("Each --finding must be: <policyControlId>|<policyRuleId>|<pass|partial|fail>|<rationale>|<missing1;missing2>");
|
|
52
|
+
}
|
|
53
|
+
if (result !== "pass" && result !== "partial" && result !== "fail") {
|
|
54
|
+
throw new Error(`Invalid finding result '${resultRaw}'. Use pass|partial|fail.`);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
policyControlId: policyControlId.trim(),
|
|
58
|
+
policyRuleId: policyRuleId.trim(),
|
|
59
|
+
result,
|
|
60
|
+
...(rationaleRaw?.trim() ? { rationale: rationaleRaw.trim() } : {}),
|
|
61
|
+
...(missingRaw?.trim() ? { missingRequirements: missingRaw.split(";").map((m) => m.trim()).filter(Boolean) } : {}),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function parseFindings(args) {
|
|
65
|
+
const findingsJson = parseOptionValue(args, "--findings-json");
|
|
66
|
+
if (findingsJson) {
|
|
67
|
+
let parsed;
|
|
68
|
+
try {
|
|
69
|
+
parsed = JSON.parse(findingsJson);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
throw new Error("--findings-json must be valid JSON array");
|
|
73
|
+
}
|
|
74
|
+
if (!Array.isArray(parsed) || parsed.length === 0) {
|
|
75
|
+
throw new Error("--findings-json must be a non-empty JSON array");
|
|
76
|
+
}
|
|
77
|
+
return parsed.map((item) => {
|
|
78
|
+
const value = item;
|
|
79
|
+
const result = String(value.result ?? "").toLowerCase();
|
|
80
|
+
if (!value.policyControlId || !value.policyRuleId || !result) {
|
|
81
|
+
throw new Error("Each finding must include policyControlId, policyRuleId, result");
|
|
82
|
+
}
|
|
83
|
+
if (result !== "pass" && result !== "partial" && result !== "fail") {
|
|
84
|
+
throw new Error(`Invalid finding result '${String(value.result)}'. Use pass|partial|fail.`);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
policyControlId: String(value.policyControlId),
|
|
88
|
+
policyRuleId: String(value.policyRuleId),
|
|
89
|
+
result,
|
|
90
|
+
...(value.rationale ? { rationale: String(value.rationale) } : {}),
|
|
91
|
+
...(Array.isArray(value.missingRequirements) ? { missingRequirements: value.missingRequirements.map(String) } : {}),
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const tokens = parseMultiOptionValues(args, "--finding");
|
|
96
|
+
if (tokens.length === 0) {
|
|
97
|
+
throw new Error("Provide findings via --finding (repeatable) or --findings-json '<json-array>'");
|
|
98
|
+
}
|
|
99
|
+
return tokens.map(parseFindingToken);
|
|
100
|
+
}
|
|
101
|
+
export async function policyAuditSubmit(args) {
|
|
102
|
+
const asJson = parseFlag(args, "--json");
|
|
103
|
+
const commandId = parseOptionValue(args, "--command-id") ?? parseOptionValue(args, "--id");
|
|
104
|
+
const applicationEntityKey = parseOptionValue(args, "--application-key") ?? parseOptionValue(args, "--entity");
|
|
105
|
+
const agentKey = parseOptionValue(args, "--agent-key") ?? loadIdentityAgentKey();
|
|
106
|
+
if (!commandId) {
|
|
107
|
+
console.error("error: --command-id <uuid> is required");
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
if (!applicationEntityKey) {
|
|
111
|
+
console.error("error: --application-key <externalKey> is required (e.g. application:bad-driving)");
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
const findings = parseFindings(args);
|
|
115
|
+
const creds = requireCredentials();
|
|
116
|
+
const raw = await callMcpTool("nexarch_submit_policy_audit", {
|
|
117
|
+
commandId,
|
|
118
|
+
applicationEntityKey,
|
|
119
|
+
...(agentKey ? { agentKey } : {}),
|
|
120
|
+
findings,
|
|
121
|
+
companyId: creds.companyId,
|
|
122
|
+
}, { companyId: creds.companyId });
|
|
123
|
+
const result = parseToolText(raw);
|
|
124
|
+
if (asJson) {
|
|
125
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (!result.ok) {
|
|
129
|
+
console.error(`Policy audit submit failed${result.error ? `: ${result.error}` : ""}`);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
console.log(`Policy audit submitted for ${applicationEntityKey}.`);
|
|
133
|
+
if (result.runId)
|
|
134
|
+
console.log(`Run ID: ${result.runId}`);
|
|
135
|
+
if (result.summary) {
|
|
136
|
+
console.log(`Summary: ${result.summary.passCount ?? 0} pass, ${result.summary.partialCount ?? 0} partial, ${result.summary.failCount ?? 0} fail`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import process from "process";
|
|
2
|
+
import { requireCredentials } from "../lib/credentials.js";
|
|
3
|
+
import { callMcpTool } from "../lib/mcp.js";
|
|
4
|
+
function parseFlag(args, flag) {
|
|
5
|
+
return args.includes(flag);
|
|
6
|
+
}
|
|
7
|
+
function parseOptionValue(args, option) {
|
|
8
|
+
const idx = args.indexOf(option);
|
|
9
|
+
if (idx === -1)
|
|
10
|
+
return null;
|
|
11
|
+
const v = args[idx + 1];
|
|
12
|
+
if (!v || v.startsWith("--"))
|
|
13
|
+
return null;
|
|
14
|
+
return v;
|
|
15
|
+
}
|
|
16
|
+
function parseToolText(result) {
|
|
17
|
+
const text = result.content?.[0]?.text ?? "{}";
|
|
18
|
+
return JSON.parse(text);
|
|
19
|
+
}
|
|
20
|
+
export async function policyControls(args) {
|
|
21
|
+
const asJson = parseFlag(args, "--json");
|
|
22
|
+
const entity = parseOptionValue(args, "--entity") ?? parseOptionValue(args, "--application-key");
|
|
23
|
+
if (!entity) {
|
|
24
|
+
console.error("error: --entity <externalKey> is required (e.g. application:bad-driving)");
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
const creds = requireCredentials();
|
|
28
|
+
const raw = await callMcpTool("nexarch_get_entity_policy_controls", { entityExternalKey: entity, companyId: creds.companyId }, { companyId: creds.companyId });
|
|
29
|
+
const result = parseToolText(raw);
|
|
30
|
+
if (asJson) {
|
|
31
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (!result.found) {
|
|
35
|
+
console.log(`Entity not found: ${entity}`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
console.log(`Policy controls for ${result.entityExternalKey ?? entity}`);
|
|
39
|
+
console.log(`Controls: ${result.controlCount ?? 0}`);
|
|
40
|
+
for (const control of result.controls ?? []) {
|
|
41
|
+
const rules = control.rules ?? [];
|
|
42
|
+
console.log(`\n- ${control.name} (${control.id})`);
|
|
43
|
+
if (rules.length === 0) {
|
|
44
|
+
console.log(" (no rules)");
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
for (const rule of rules) {
|
|
48
|
+
const level = rule.requirementLevel ? ` [${rule.requirementLevel}]` : "";
|
|
49
|
+
console.log(` • ${rule.name} (${rule.id})${level}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,9 @@ import { resolveNames } from "./commands/resolve-names.js";
|
|
|
15
15
|
import { checkIn } from "./commands/check-in.js";
|
|
16
16
|
import { commandDone } from "./commands/command-done.js";
|
|
17
17
|
import { commandFail } from "./commands/command-fail.js";
|
|
18
|
+
import { commandClaim } from "./commands/command-claim.js";
|
|
19
|
+
import { policyControls } from "./commands/policy-controls.js";
|
|
20
|
+
import { policyAuditSubmit } from "./commands/policy-audit-submit.js";
|
|
18
21
|
const [, , command, ...args] = process.argv;
|
|
19
22
|
const commands = {
|
|
20
23
|
login,
|
|
@@ -33,6 +36,9 @@ const commands = {
|
|
|
33
36
|
"check-in": checkIn,
|
|
34
37
|
"command-done": commandDone,
|
|
35
38
|
"command-fail": commandFail,
|
|
39
|
+
"command-claim": commandClaim,
|
|
40
|
+
"policy-controls": policyControls,
|
|
41
|
+
"policy-audit-submit": policyAuditSubmit,
|
|
36
42
|
};
|
|
37
43
|
async function main() {
|
|
38
44
|
if (command === "agent") {
|
|
@@ -113,12 +119,18 @@ Usage:
|
|
|
113
119
|
results before calling add-relationship.
|
|
114
120
|
Options: --names <csv> (required, e.g. "vercel,neon")
|
|
115
121
|
--json
|
|
116
|
-
nexarch check-in
|
|
117
|
-
|
|
122
|
+
nexarch check-in Preview pending application-target commands for this agent scope
|
|
123
|
+
without claiming. Reads agent key from ~/.nexarch/identity.json
|
|
118
124
|
(written by init-agent) or via --agent-key.
|
|
119
125
|
Options: --agent-key <key> override stored agent key
|
|
120
126
|
--project <key> application entity key
|
|
121
127
|
--json
|
|
128
|
+
nexarch command-claim
|
|
129
|
+
Explicitly claim a pending command by ID.
|
|
130
|
+
Options: --id <commandId> (required)
|
|
131
|
+
--agent-key <key> override stored agent key
|
|
132
|
+
--project <key> application entity key
|
|
133
|
+
--json
|
|
122
134
|
nexarch command-done
|
|
123
135
|
Mark a claimed command as completed.
|
|
124
136
|
Options: --id <commandId> (required)
|
|
@@ -129,6 +141,18 @@ Usage:
|
|
|
129
141
|
Options: --id <commandId> (required)
|
|
130
142
|
--error <message> (required)
|
|
131
143
|
--json
|
|
144
|
+
nexarch policy-controls
|
|
145
|
+
Fetch policy controls/rules assigned to an entity (for policy audits).
|
|
146
|
+
Options: --entity <externalKey> (required, e.g. application:bad-driving)
|
|
147
|
+
--json
|
|
148
|
+
nexarch policy-audit-submit
|
|
149
|
+
Submit structured policy findings (writes policy_audit_finding rows).
|
|
150
|
+
Options: --command-id <id> (required)
|
|
151
|
+
--application-key <key> (required)
|
|
152
|
+
--agent-key <key> (optional; defaults from identity)
|
|
153
|
+
--finding <controlId|ruleId|result|rationale|missing1;missing2> (repeatable)
|
|
154
|
+
--findings-json <json-array>
|
|
155
|
+
--json
|
|
132
156
|
`);
|
|
133
157
|
process.exit(command ? 1 : 0);
|
|
134
158
|
}
|