nexarch 0.6.6 → 0.7.1
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,3 +1,4 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "fs";
|
|
1
2
|
import process from "process";
|
|
2
3
|
import { requireCredentials } from "../lib/credentials.js";
|
|
3
4
|
import { callMcpTool } from "../lib/mcp.js";
|
|
@@ -19,7 +20,16 @@ function parseToolText(result) {
|
|
|
19
20
|
export async function commandDone(args) {
|
|
20
21
|
const asJson = parseFlag(args, "--json");
|
|
21
22
|
const id = parseOptionValue(args, "--id");
|
|
22
|
-
const
|
|
23
|
+
const summaryArg = parseOptionValue(args, "--summary");
|
|
24
|
+
const summaryFile = parseOptionValue(args, "--summary-file");
|
|
25
|
+
let summary = summaryArg;
|
|
26
|
+
if (summaryFile) {
|
|
27
|
+
if (!existsSync(summaryFile)) {
|
|
28
|
+
console.error(`error: --summary-file not found: ${summaryFile}`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
summary = readFileSync(summaryFile, "utf8");
|
|
32
|
+
}
|
|
23
33
|
if (!id) {
|
|
24
34
|
console.error("error: --id <commandId> is required");
|
|
25
35
|
process.exit(1);
|
|
@@ -83,18 +83,23 @@ function parseFindings(args) {
|
|
|
83
83
|
}
|
|
84
84
|
return parsed.map((item) => {
|
|
85
85
|
const value = item;
|
|
86
|
+
const policyControlId = String(value.policyControlId ?? value.controlId ?? "").trim();
|
|
87
|
+
const policyRuleId = String(value.policyRuleId ?? value.ruleId ?? "").trim();
|
|
86
88
|
const result = String(value.result ?? "").toLowerCase();
|
|
87
|
-
if (!
|
|
88
|
-
throw new Error("Each finding must include policyControlId, policyRuleId, result");
|
|
89
|
+
if (!policyControlId || !policyRuleId || !result) {
|
|
90
|
+
throw new Error("Each finding must include policyControlId, policyRuleId, result. Tip: run 'nexarch policy-controls --entity <application:key> --json' and use the rule IDs from controls[].rules[].id");
|
|
89
91
|
}
|
|
90
92
|
if (result !== "pass" && result !== "partial" && result !== "fail") {
|
|
91
93
|
throw new Error(`Invalid finding result '${String(value.result)}'. Use pass|partial|fail.`);
|
|
92
94
|
}
|
|
95
|
+
const rationale = value.rationale
|
|
96
|
+
? String(value.rationale)
|
|
97
|
+
: [value.summary, value.evidence].filter(Boolean).map(String).join("\n\n");
|
|
93
98
|
return {
|
|
94
|
-
policyControlId
|
|
95
|
-
policyRuleId
|
|
99
|
+
policyControlId,
|
|
100
|
+
policyRuleId,
|
|
96
101
|
result,
|
|
97
|
-
...(
|
|
102
|
+
...(rationale ? { rationale } : {}),
|
|
98
103
|
...(Array.isArray(value.missingRequirements) ? { missingRequirements: value.missingRequirements.map(String) } : {}),
|
|
99
104
|
};
|
|
100
105
|
});
|
|
@@ -107,6 +112,27 @@ function parseFindings(args) {
|
|
|
107
112
|
}
|
|
108
113
|
export async function policyAuditSubmit(args) {
|
|
109
114
|
const asJson = parseFlag(args, "--json");
|
|
115
|
+
if (parseFlag(args, "--help") || parseFlag(args, "-h")) {
|
|
116
|
+
console.log(`
|
|
117
|
+
Usage:
|
|
118
|
+
nexarch policy-audit-submit --command-id <id> --application-key <key> [options]
|
|
119
|
+
|
|
120
|
+
Options:
|
|
121
|
+
--command-id <id> Required command id
|
|
122
|
+
--application-key <key> Required application key (e.g. application:bad-driving)
|
|
123
|
+
--agent-key <key> Optional agent key (defaults from identity)
|
|
124
|
+
--finding <controlId|ruleId|result|rationale|missing1;missing2> Repeatable
|
|
125
|
+
--findings-json <json> JSON array of findings
|
|
126
|
+
--findings-file <path> Path to JSON array of findings
|
|
127
|
+
--json Print JSON response
|
|
128
|
+
|
|
129
|
+
Notes:
|
|
130
|
+
- Findings are rule-level (policyRuleId is required).
|
|
131
|
+
- You can submit partial findings multiple times for the same command.
|
|
132
|
+
- Get valid rule ids with: nexarch policy-controls --entity <application:key> --json
|
|
133
|
+
`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
110
136
|
const commandId = parseOptionValue(args, "--command-id") ?? parseOptionValue(args, "--id");
|
|
111
137
|
const applicationEntityKey = parseOptionValue(args, "--application-key") ?? parseOptionValue(args, "--entity");
|
|
112
138
|
const agentKey = parseOptionValue(args, "--agent-key") ?? loadIdentityAgentKey();
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import process from "process";
|
|
2
|
+
import { writeFileSync } from "fs";
|
|
3
|
+
import { requireCredentials } from "../lib/credentials.js";
|
|
4
|
+
import { callMcpTool } from "../lib/mcp.js";
|
|
5
|
+
function parseFlag(args, flag) {
|
|
6
|
+
return args.includes(flag);
|
|
7
|
+
}
|
|
8
|
+
function parseOptionValue(args, option) {
|
|
9
|
+
const idx = args.indexOf(option);
|
|
10
|
+
if (idx === -1)
|
|
11
|
+
return null;
|
|
12
|
+
const v = args[idx + 1];
|
|
13
|
+
if (!v || v.startsWith("--"))
|
|
14
|
+
return null;
|
|
15
|
+
return v;
|
|
16
|
+
}
|
|
17
|
+
function parseMultiOptionValues(args, option) {
|
|
18
|
+
const values = [];
|
|
19
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
20
|
+
if (args[i] !== option)
|
|
21
|
+
continue;
|
|
22
|
+
const v = args[i + 1];
|
|
23
|
+
if (!v || v.startsWith("--"))
|
|
24
|
+
continue;
|
|
25
|
+
values.push(v);
|
|
26
|
+
}
|
|
27
|
+
return values;
|
|
28
|
+
}
|
|
29
|
+
function parseToolText(result) {
|
|
30
|
+
const text = result.content?.[0]?.text ?? "{}";
|
|
31
|
+
return JSON.parse(text);
|
|
32
|
+
}
|
|
33
|
+
export async function policyAuditTemplate(args) {
|
|
34
|
+
const asJson = parseFlag(args, "--json");
|
|
35
|
+
const entity = parseOptionValue(args, "--entity") ?? parseOptionValue(args, "--application-key");
|
|
36
|
+
const outputPath = parseOptionValue(args, "--out") ?? parseOptionValue(args, "--output");
|
|
37
|
+
const defaultResult = (parseOptionValue(args, "--default-result") ?? "fail").toLowerCase();
|
|
38
|
+
const selectedControlIds = new Set(parseMultiOptionValues(args, "--control-id"));
|
|
39
|
+
if (parseFlag(args, "--help") || parseFlag(args, "-h")) {
|
|
40
|
+
console.log(`
|
|
41
|
+
Usage:
|
|
42
|
+
nexarch policy-audit-template --entity <application:key> [options]
|
|
43
|
+
|
|
44
|
+
Options:
|
|
45
|
+
--entity <key> Required (e.g. application:bad-driving)
|
|
46
|
+
--control-id <uuid> Optional repeatable filter (selected controls only)
|
|
47
|
+
--default-result <value> pass|partial|fail (default: fail)
|
|
48
|
+
--output, --out <path.json> Write findings array to file
|
|
49
|
+
--json Print JSON to stdout
|
|
50
|
+
|
|
51
|
+
Output shape is ready for:
|
|
52
|
+
nexarch policy-audit-submit --findings-file <path.json>
|
|
53
|
+
`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (!entity) {
|
|
57
|
+
console.error("error: --entity <externalKey> is required (e.g. application:bad-driving)");
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
if (!["pass", "partial", "fail"].includes(defaultResult)) {
|
|
61
|
+
console.error("error: --default-result must be pass|partial|fail");
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
const creds = requireCredentials();
|
|
65
|
+
const raw = await callMcpTool("nexarch_get_entity_policy_controls", { entityExternalKey: entity, companyId: creds.companyId }, { companyId: creds.companyId });
|
|
66
|
+
const result = parseToolText(raw);
|
|
67
|
+
if (!result.found) {
|
|
68
|
+
console.error(`error: entity not found: ${entity}`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
const findings = (result.controls ?? [])
|
|
72
|
+
.filter((control) => selectedControlIds.size === 0 || selectedControlIds.has(control.id))
|
|
73
|
+
.flatMap((control) => (control.rules ?? []).map((rule) => ({
|
|
74
|
+
policyControlId: control.id,
|
|
75
|
+
policyRuleId: rule.id,
|
|
76
|
+
result: defaultResult,
|
|
77
|
+
rationale: "",
|
|
78
|
+
missingRequirements: [],
|
|
79
|
+
})));
|
|
80
|
+
if (findings.length === 0) {
|
|
81
|
+
console.error("error: no rules found for selected controls/entity");
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
const payload = JSON.stringify(findings, null, 2);
|
|
85
|
+
if (outputPath) {
|
|
86
|
+
writeFileSync(outputPath, `${payload}\n`, "utf8");
|
|
87
|
+
if (!asJson) {
|
|
88
|
+
console.log(`Template written: ${outputPath}`);
|
|
89
|
+
console.log(`Findings: ${findings.length}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (asJson || !outputPath) {
|
|
93
|
+
process.stdout.write(`${payload}\n`);
|
|
94
|
+
}
|
|
95
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import { commandDone } from "./commands/command-done.js";
|
|
|
17
17
|
import { commandFail } from "./commands/command-fail.js";
|
|
18
18
|
import { commandClaim } from "./commands/command-claim.js";
|
|
19
19
|
import { policyControls } from "./commands/policy-controls.js";
|
|
20
|
+
import { policyAuditTemplate } from "./commands/policy-audit-template.js";
|
|
20
21
|
import { policyAuditSubmit } from "./commands/policy-audit-submit.js";
|
|
21
22
|
const [, , command, ...args] = process.argv;
|
|
22
23
|
const commands = {
|
|
@@ -38,6 +39,7 @@ const commands = {
|
|
|
38
39
|
"command-fail": commandFail,
|
|
39
40
|
"command-claim": commandClaim,
|
|
40
41
|
"policy-controls": policyControls,
|
|
42
|
+
"policy-audit-template": policyAuditTemplate,
|
|
41
43
|
"policy-audit-submit": policyAuditSubmit,
|
|
42
44
|
};
|
|
43
45
|
async function main() {
|
|
@@ -132,6 +134,7 @@ Usage:
|
|
|
132
134
|
Mark a claimed command as completed.
|
|
133
135
|
Options: --id <commandId> (required)
|
|
134
136
|
--summary <text> short summary of what was done
|
|
137
|
+
--summary-file <path.md|txt>
|
|
135
138
|
--json
|
|
136
139
|
nexarch command-fail
|
|
137
140
|
Mark a claimed command as failed.
|
|
@@ -142,6 +145,13 @@ Usage:
|
|
|
142
145
|
Fetch policy controls/rules assigned to an entity (for policy audits).
|
|
143
146
|
Options: --entity <externalKey> (required, e.g. application:bad-driving)
|
|
144
147
|
--json
|
|
148
|
+
nexarch policy-audit-template
|
|
149
|
+
Generate a findings JSON template from policy controls/rules for an entity.
|
|
150
|
+
Options: --entity <externalKey> (required)
|
|
151
|
+
--control-id <uuid> (repeatable; optional filter)
|
|
152
|
+
--default-result <pass|partial|fail> (default: fail)
|
|
153
|
+
--output <path.json>
|
|
154
|
+
--json
|
|
145
155
|
nexarch policy-audit-submit
|
|
146
156
|
Submit structured policy findings (writes policy_audit_finding rows).
|
|
147
157
|
Options: --command-id <id> (required)
|