nexarch 0.6.7 → 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.
|
@@ -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() {
|
|
@@ -143,6 +145,13 @@ Usage:
|
|
|
143
145
|
Fetch policy controls/rules assigned to an entity (for policy audits).
|
|
144
146
|
Options: --entity <externalKey> (required, e.g. application:bad-driving)
|
|
145
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
|
|
146
155
|
nexarch policy-audit-submit
|
|
147
156
|
Submit structured policy findings (writes policy_audit_finding rows).
|
|
148
157
|
Options: --command-id <id> (required)
|