chainlesschain 0.37.12 → 0.40.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.
- package/package.json +3 -2
- package/src/commands/agent.js +7 -1
- package/src/commands/ask.js +24 -9
- package/src/commands/chat.js +7 -1
- package/src/commands/cli-anything.js +266 -0
- package/src/commands/compliance.js +216 -0
- package/src/commands/dao.js +312 -0
- package/src/commands/dlp.js +278 -0
- package/src/commands/evomap.js +558 -0
- package/src/commands/hardening.js +230 -0
- package/src/commands/matrix.js +168 -0
- package/src/commands/nostr.js +185 -0
- package/src/commands/pqc.js +162 -0
- package/src/commands/scim.js +218 -0
- package/src/commands/serve.js +109 -0
- package/src/commands/siem.js +156 -0
- package/src/commands/social.js +480 -0
- package/src/commands/terraform.js +148 -0
- package/src/constants.js +1 -0
- package/src/index.js +60 -0
- package/src/lib/autonomous-agent.js +487 -0
- package/src/lib/cli-anything-bridge.js +379 -0
- package/src/lib/cli-context-engineering.js +472 -0
- package/src/lib/compliance-manager.js +290 -0
- package/src/lib/content-recommender.js +205 -0
- package/src/lib/dao-governance.js +296 -0
- package/src/lib/dlp-engine.js +304 -0
- package/src/lib/evomap-client.js +135 -0
- package/src/lib/evomap-federation.js +240 -0
- package/src/lib/evomap-governance.js +250 -0
- package/src/lib/evomap-manager.js +227 -0
- package/src/lib/git-integration.js +1 -1
- package/src/lib/hardening-manager.js +275 -0
- package/src/lib/llm-providers.js +14 -1
- package/src/lib/matrix-bridge.js +196 -0
- package/src/lib/nostr-bridge.js +195 -0
- package/src/lib/permanent-memory.js +370 -0
- package/src/lib/plan-mode.js +211 -0
- package/src/lib/pqc-manager.js +196 -0
- package/src/lib/scim-manager.js +212 -0
- package/src/lib/session-manager.js +38 -0
- package/src/lib/siem-exporter.js +137 -0
- package/src/lib/social-manager.js +283 -0
- package/src/lib/task-model-selector.js +232 -0
- package/src/lib/terraform-manager.js +201 -0
- package/src/lib/ws-server.js +474 -0
- package/src/repl/agent-repl.js +796 -41
- package/src/repl/chat-repl.js +14 -6
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DAO Governance v2 commands
|
|
3
|
+
* chainlesschain dao propose|vote|delegate|execute|treasury|allocate|stats|configure
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import { logger } from "../lib/logger.js";
|
|
8
|
+
import { bootstrap, shutdown } from "../runtime/bootstrap.js";
|
|
9
|
+
import {
|
|
10
|
+
ensureDAOv2Tables,
|
|
11
|
+
propose,
|
|
12
|
+
vote,
|
|
13
|
+
delegate,
|
|
14
|
+
execute,
|
|
15
|
+
getTreasury,
|
|
16
|
+
allocate,
|
|
17
|
+
depositToTreasury,
|
|
18
|
+
getStats,
|
|
19
|
+
configure,
|
|
20
|
+
} from "../lib/dao-governance.js";
|
|
21
|
+
|
|
22
|
+
export function registerDaoCommand(program) {
|
|
23
|
+
const dao = program
|
|
24
|
+
.command("dao")
|
|
25
|
+
.description("DAO Governance v2 — proposals, voting, delegation, treasury");
|
|
26
|
+
|
|
27
|
+
// dao propose
|
|
28
|
+
dao
|
|
29
|
+
.command("propose <title>")
|
|
30
|
+
.description("Create a governance proposal")
|
|
31
|
+
.option("-d, --description <text>", "Proposal description")
|
|
32
|
+
.option("-p, --proposer <id>", "Proposer identity", "cli-user")
|
|
33
|
+
.option(
|
|
34
|
+
"--voting-type <type>",
|
|
35
|
+
"Voting type: simple or quadratic",
|
|
36
|
+
"simple",
|
|
37
|
+
)
|
|
38
|
+
.action(async (title, options) => {
|
|
39
|
+
try {
|
|
40
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
41
|
+
if (!ctx.db) {
|
|
42
|
+
logger.error("Database not available");
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
const db = ctx.db.getDatabase();
|
|
46
|
+
ensureDAOv2Tables(db);
|
|
47
|
+
|
|
48
|
+
const result = propose(
|
|
49
|
+
db,
|
|
50
|
+
title,
|
|
51
|
+
options.description,
|
|
52
|
+
options.proposer,
|
|
53
|
+
{
|
|
54
|
+
votingType: options.votingType,
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
logger.success("Proposal created");
|
|
58
|
+
logger.log(` ${chalk.bold("ID:")} ${chalk.cyan(result.id)}`);
|
|
59
|
+
logger.log(` ${chalk.bold("Title:")} ${result.title}`);
|
|
60
|
+
logger.log(` ${chalk.bold("Status:")} ${result.status}`);
|
|
61
|
+
logger.log(` ${chalk.bold("Type:")} ${result.votingType}`);
|
|
62
|
+
logger.log(` ${chalk.bold("Ends:")} ${result.endsAt}`);
|
|
63
|
+
|
|
64
|
+
await shutdown();
|
|
65
|
+
} catch (err) {
|
|
66
|
+
logger.error(`Failed: ${err.message}`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// dao vote
|
|
72
|
+
dao
|
|
73
|
+
.command("vote <proposal-id> <direction>")
|
|
74
|
+
.description('Vote on a proposal (direction: "for" or "against")')
|
|
75
|
+
.option("-v, --voter <id>", "Voter identity", "cli-user")
|
|
76
|
+
.option("-w, --weight <n>", "Vote weight", "1")
|
|
77
|
+
.action(async (proposalId, direction, options) => {
|
|
78
|
+
try {
|
|
79
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
80
|
+
if (!ctx.db) {
|
|
81
|
+
logger.error("Database not available");
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
const db = ctx.db.getDatabase();
|
|
85
|
+
ensureDAOv2Tables(db);
|
|
86
|
+
|
|
87
|
+
const result = vote(
|
|
88
|
+
db,
|
|
89
|
+
proposalId,
|
|
90
|
+
options.voter,
|
|
91
|
+
direction,
|
|
92
|
+
parseFloat(options.weight),
|
|
93
|
+
);
|
|
94
|
+
logger.success("Vote recorded");
|
|
95
|
+
logger.log(
|
|
96
|
+
` ${chalk.bold("Vote ID:")} ${chalk.cyan(result.voteId)}`,
|
|
97
|
+
);
|
|
98
|
+
logger.log(` ${chalk.bold("Direction:")} ${result.direction}`);
|
|
99
|
+
logger.log(` ${chalk.bold("Weight:")} ${result.weight}`);
|
|
100
|
+
|
|
101
|
+
await shutdown();
|
|
102
|
+
} catch (err) {
|
|
103
|
+
logger.error(`Failed: ${err.message}`);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// dao delegate
|
|
109
|
+
dao
|
|
110
|
+
.command("delegate <delegator> <delegate-to>")
|
|
111
|
+
.description("Delegate voting power")
|
|
112
|
+
.option("-w, --weight <n>", "Delegation weight", "1")
|
|
113
|
+
.action(async (delegator, delegateTo, options) => {
|
|
114
|
+
try {
|
|
115
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
116
|
+
if (!ctx.db) {
|
|
117
|
+
logger.error("Database not available");
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
const db = ctx.db.getDatabase();
|
|
121
|
+
ensureDAOv2Tables(db);
|
|
122
|
+
|
|
123
|
+
const result = delegate(
|
|
124
|
+
db,
|
|
125
|
+
delegator,
|
|
126
|
+
delegateTo,
|
|
127
|
+
parseFloat(options.weight),
|
|
128
|
+
);
|
|
129
|
+
logger.success("Delegation set");
|
|
130
|
+
logger.log(` ${chalk.bold("From:")} ${result.delegator}`);
|
|
131
|
+
logger.log(` ${chalk.bold("To:")} ${result.delegate}`);
|
|
132
|
+
logger.log(` ${chalk.bold("Weight:")} ${result.weight}`);
|
|
133
|
+
|
|
134
|
+
await shutdown();
|
|
135
|
+
} catch (err) {
|
|
136
|
+
logger.error(`Failed: ${err.message}`);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// dao execute
|
|
142
|
+
dao
|
|
143
|
+
.command("execute <proposal-id>")
|
|
144
|
+
.description("Execute a passed proposal")
|
|
145
|
+
.action(async (proposalId) => {
|
|
146
|
+
try {
|
|
147
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
148
|
+
if (!ctx.db) {
|
|
149
|
+
logger.error("Database not available");
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
const db = ctx.db.getDatabase();
|
|
153
|
+
ensureDAOv2Tables(db);
|
|
154
|
+
|
|
155
|
+
const result = execute(db, proposalId);
|
|
156
|
+
logger.success(`Proposal ${chalk.cyan(result.proposalId)} executed`);
|
|
157
|
+
|
|
158
|
+
await shutdown();
|
|
159
|
+
} catch (err) {
|
|
160
|
+
logger.error(`Failed: ${err.message}`);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// dao treasury
|
|
166
|
+
dao
|
|
167
|
+
.command("treasury")
|
|
168
|
+
.description("Show treasury balance and allocations")
|
|
169
|
+
.option("--json", "Output as JSON")
|
|
170
|
+
.action(async (options) => {
|
|
171
|
+
try {
|
|
172
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
173
|
+
if (!ctx.db) {
|
|
174
|
+
logger.error("Database not available");
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
const db = ctx.db.getDatabase();
|
|
178
|
+
ensureDAOv2Tables(db);
|
|
179
|
+
|
|
180
|
+
const result = getTreasury();
|
|
181
|
+
if (options.json) {
|
|
182
|
+
console.log(JSON.stringify(result, null, 2));
|
|
183
|
+
} else {
|
|
184
|
+
logger.log(` ${chalk.bold("Balance:")} ${result.balance}`);
|
|
185
|
+
logger.log(
|
|
186
|
+
` ${chalk.bold("Allocations:")} ${result.allocations.length}`,
|
|
187
|
+
);
|
|
188
|
+
for (const a of result.allocations) {
|
|
189
|
+
logger.log(
|
|
190
|
+
` ${chalk.cyan(a.id.slice(0, 12))} ${a.amount} — ${a.description || "N/A"}`,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
await shutdown();
|
|
196
|
+
} catch (err) {
|
|
197
|
+
logger.error(`Failed: ${err.message}`);
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// dao allocate
|
|
203
|
+
dao
|
|
204
|
+
.command("allocate <proposal-id> <amount>")
|
|
205
|
+
.description("Allocate treasury funds to a proposal")
|
|
206
|
+
.option("-d, --description <text>", "Allocation description")
|
|
207
|
+
.action(async (proposalId, amount, options) => {
|
|
208
|
+
try {
|
|
209
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
210
|
+
if (!ctx.db) {
|
|
211
|
+
logger.error("Database not available");
|
|
212
|
+
process.exit(1);
|
|
213
|
+
}
|
|
214
|
+
const db = ctx.db.getDatabase();
|
|
215
|
+
ensureDAOv2Tables(db);
|
|
216
|
+
|
|
217
|
+
const result = allocate(
|
|
218
|
+
db,
|
|
219
|
+
proposalId,
|
|
220
|
+
parseFloat(amount),
|
|
221
|
+
options.description,
|
|
222
|
+
);
|
|
223
|
+
logger.success("Funds allocated");
|
|
224
|
+
logger.log(` ${chalk.bold("ID:")} ${chalk.cyan(result.id)}`);
|
|
225
|
+
logger.log(` ${chalk.bold("Amount:")} ${result.amount}`);
|
|
226
|
+
logger.log(` ${chalk.bold("Proposal:")} ${result.proposalId}`);
|
|
227
|
+
|
|
228
|
+
await shutdown();
|
|
229
|
+
} catch (err) {
|
|
230
|
+
logger.error(`Failed: ${err.message}`);
|
|
231
|
+
process.exit(1);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// dao stats
|
|
236
|
+
dao
|
|
237
|
+
.command("stats")
|
|
238
|
+
.description("Show governance statistics")
|
|
239
|
+
.option("--json", "Output as JSON")
|
|
240
|
+
.action(async (options) => {
|
|
241
|
+
try {
|
|
242
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
243
|
+
if (!ctx.db) {
|
|
244
|
+
logger.error("Database not available");
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
const db = ctx.db.getDatabase();
|
|
248
|
+
ensureDAOv2Tables(db);
|
|
249
|
+
|
|
250
|
+
const result = getStats();
|
|
251
|
+
if (options.json) {
|
|
252
|
+
console.log(JSON.stringify(result, null, 2));
|
|
253
|
+
} else {
|
|
254
|
+
logger.log(
|
|
255
|
+
` ${chalk.bold("Total Proposals:")} ${result.totalProposals}`,
|
|
256
|
+
);
|
|
257
|
+
logger.log(` ${chalk.bold("Active:")} ${result.active}`);
|
|
258
|
+
logger.log(` ${chalk.bold("Executed:")} ${result.executed}`);
|
|
259
|
+
logger.log(
|
|
260
|
+
` ${chalk.bold("Delegations:")} ${result.delegations}`,
|
|
261
|
+
);
|
|
262
|
+
logger.log(` ${chalk.bold("Treasury:")} ${result.treasury}`);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
await shutdown();
|
|
266
|
+
} catch (err) {
|
|
267
|
+
logger.error(`Failed: ${err.message}`);
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// dao configure
|
|
273
|
+
dao
|
|
274
|
+
.command("configure")
|
|
275
|
+
.description("Update governance configuration")
|
|
276
|
+
.option("--voting-period <ms>", "Voting period in milliseconds")
|
|
277
|
+
.option("--quorum <ratio>", "Quorum ratio (0-1)")
|
|
278
|
+
.option("--execution-delay <ms>", "Execution delay in milliseconds")
|
|
279
|
+
.action(async (options) => {
|
|
280
|
+
try {
|
|
281
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
282
|
+
if (!ctx.db) {
|
|
283
|
+
logger.error("Database not available");
|
|
284
|
+
process.exit(1);
|
|
285
|
+
}
|
|
286
|
+
const db = ctx.db.getDatabase();
|
|
287
|
+
ensureDAOv2Tables(db);
|
|
288
|
+
|
|
289
|
+
const cfg = {};
|
|
290
|
+
if (options.votingPeriod)
|
|
291
|
+
cfg.votingPeriod = parseInt(options.votingPeriod);
|
|
292
|
+
if (options.quorum) cfg.quorum = parseFloat(options.quorum);
|
|
293
|
+
if (options.executionDelay)
|
|
294
|
+
cfg.executionDelay = parseInt(options.executionDelay);
|
|
295
|
+
|
|
296
|
+
const result = configure(cfg);
|
|
297
|
+
logger.success("Configuration updated");
|
|
298
|
+
logger.log(
|
|
299
|
+
` ${chalk.bold("Voting Period:")} ${result.votingPeriod}ms`,
|
|
300
|
+
);
|
|
301
|
+
logger.log(` ${chalk.bold("Quorum:")} ${result.quorum}`);
|
|
302
|
+
logger.log(
|
|
303
|
+
` ${chalk.bold("Execution Delay:")} ${result.executionDelay}ms`,
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
await shutdown();
|
|
307
|
+
} catch (err) {
|
|
308
|
+
logger.error(`Failed: ${err.message}`);
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DLP commands
|
|
3
|
+
* chainlesschain dlp scan|incidents|resolve|stats|policy
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import { logger } from "../lib/logger.js";
|
|
8
|
+
import { bootstrap, shutdown } from "../runtime/bootstrap.js";
|
|
9
|
+
import {
|
|
10
|
+
ensureDLPTables,
|
|
11
|
+
scanContent,
|
|
12
|
+
listIncidents,
|
|
13
|
+
resolveIncident,
|
|
14
|
+
getDLPStats,
|
|
15
|
+
createPolicy,
|
|
16
|
+
updatePolicy,
|
|
17
|
+
deletePolicy,
|
|
18
|
+
listDLPPolicies,
|
|
19
|
+
} from "../lib/dlp-engine.js";
|
|
20
|
+
|
|
21
|
+
export function registerDlpCommand(program) {
|
|
22
|
+
const dlp = program
|
|
23
|
+
.command("dlp")
|
|
24
|
+
.description("Data Loss Prevention — scanning, incidents, policies");
|
|
25
|
+
|
|
26
|
+
// dlp scan
|
|
27
|
+
dlp
|
|
28
|
+
.command("scan <content>")
|
|
29
|
+
.description("Scan content for DLP violations")
|
|
30
|
+
.option("-c, --channel <channel>", "Content channel", "cli")
|
|
31
|
+
.option("-u, --user <id>", "User ID", "cli-user")
|
|
32
|
+
.option("--json", "Output as JSON")
|
|
33
|
+
.action(async (content, options) => {
|
|
34
|
+
try {
|
|
35
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
36
|
+
if (!ctx.db) {
|
|
37
|
+
logger.error("Database not available");
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
const db = ctx.db.getDatabase();
|
|
41
|
+
ensureDLPTables(db);
|
|
42
|
+
|
|
43
|
+
const result = scanContent(db, content, options.channel, options.user);
|
|
44
|
+
if (options.json) {
|
|
45
|
+
console.log(JSON.stringify(result, null, 2));
|
|
46
|
+
} else {
|
|
47
|
+
logger.log(
|
|
48
|
+
` ${chalk.bold("Allowed:")} ${result.allowed ? chalk.green("Yes") : chalk.red("No")}`,
|
|
49
|
+
);
|
|
50
|
+
logger.log(` ${chalk.bold("Action:")} ${result.action}`);
|
|
51
|
+
logger.log(
|
|
52
|
+
` ${chalk.bold("Matched:")} ${result.matchedPolicies} policy(ies)`,
|
|
53
|
+
);
|
|
54
|
+
logger.log(
|
|
55
|
+
` ${chalk.bold("Incidents:")} ${result.incidents.length}`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
await shutdown();
|
|
60
|
+
} catch (err) {
|
|
61
|
+
logger.error(`Failed: ${err.message}`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// dlp incidents
|
|
67
|
+
dlp
|
|
68
|
+
.command("incidents")
|
|
69
|
+
.description("List DLP incidents")
|
|
70
|
+
.option("-c, --channel <channel>", "Filter by channel")
|
|
71
|
+
.option("-s, --severity <level>", "Filter by severity")
|
|
72
|
+
.option("--json", "Output as JSON")
|
|
73
|
+
.action(async (options) => {
|
|
74
|
+
try {
|
|
75
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
76
|
+
if (!ctx.db) {
|
|
77
|
+
logger.error("Database not available");
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
const db = ctx.db.getDatabase();
|
|
81
|
+
ensureDLPTables(db);
|
|
82
|
+
|
|
83
|
+
const incidents = listIncidents({
|
|
84
|
+
channel: options.channel,
|
|
85
|
+
severity: options.severity,
|
|
86
|
+
});
|
|
87
|
+
if (options.json) {
|
|
88
|
+
console.log(JSON.stringify(incidents, null, 2));
|
|
89
|
+
} else if (incidents.length === 0) {
|
|
90
|
+
logger.info("No incidents found.");
|
|
91
|
+
} else {
|
|
92
|
+
for (const i of incidents) {
|
|
93
|
+
const resolved = i.resolvedAt
|
|
94
|
+
? chalk.green("resolved")
|
|
95
|
+
: chalk.yellow("open");
|
|
96
|
+
logger.log(
|
|
97
|
+
` ${chalk.cyan(i.id.slice(0, 8))} [${i.severity}] ${i.channel} — ${i.actionTaken} ${resolved}`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
await shutdown();
|
|
103
|
+
} catch (err) {
|
|
104
|
+
logger.error(`Failed: ${err.message}`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// dlp resolve
|
|
110
|
+
dlp
|
|
111
|
+
.command("resolve <incident-id>")
|
|
112
|
+
.description("Resolve a DLP incident")
|
|
113
|
+
.option("-r, --resolution <text>", "Resolution details", "resolved")
|
|
114
|
+
.action(async (incidentId, options) => {
|
|
115
|
+
try {
|
|
116
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
117
|
+
if (!ctx.db) {
|
|
118
|
+
logger.error("Database not available");
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
const db = ctx.db.getDatabase();
|
|
122
|
+
ensureDLPTables(db);
|
|
123
|
+
|
|
124
|
+
const result = resolveIncident(db, incidentId, options.resolution);
|
|
125
|
+
logger.success(
|
|
126
|
+
`Incident ${chalk.cyan(incidentId.slice(0, 8))} resolved`,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
await shutdown();
|
|
130
|
+
} catch (err) {
|
|
131
|
+
logger.error(`Failed: ${err.message}`);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// dlp stats
|
|
137
|
+
dlp
|
|
138
|
+
.command("stats")
|
|
139
|
+
.description("Show DLP statistics")
|
|
140
|
+
.option("--json", "Output as JSON")
|
|
141
|
+
.action(async (options) => {
|
|
142
|
+
try {
|
|
143
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
144
|
+
if (!ctx.db) {
|
|
145
|
+
logger.error("Database not available");
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
const db = ctx.db.getDatabase();
|
|
149
|
+
ensureDLPTables(db);
|
|
150
|
+
|
|
151
|
+
const stats = getDLPStats();
|
|
152
|
+
if (options.json) {
|
|
153
|
+
console.log(JSON.stringify(stats, null, 2));
|
|
154
|
+
} else {
|
|
155
|
+
logger.log(` ${chalk.bold("Scanned:")} ${stats.scanned}`);
|
|
156
|
+
logger.log(` ${chalk.bold("Blocked:")} ${stats.blocked}`);
|
|
157
|
+
logger.log(` ${chalk.bold("Alerted:")} ${stats.alerted}`);
|
|
158
|
+
logger.log(` ${chalk.bold("Incidents:")} ${stats.totalIncidents}`);
|
|
159
|
+
logger.log(
|
|
160
|
+
` ${chalk.bold("Unresolved:")} ${stats.unresolvedIncidents}`,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
await shutdown();
|
|
165
|
+
} catch (err) {
|
|
166
|
+
logger.error(`Failed: ${err.message}`);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// dlp policy
|
|
172
|
+
const policy = dlp.command("policy").description("DLP policy management");
|
|
173
|
+
|
|
174
|
+
policy
|
|
175
|
+
.command("create <name>")
|
|
176
|
+
.description("Create a DLP policy")
|
|
177
|
+
.option("-p, --patterns <patterns>", "Regex patterns (comma-separated)")
|
|
178
|
+
.option("-k, --keywords <keywords>", "Keywords (comma-separated)")
|
|
179
|
+
.option(
|
|
180
|
+
"-a, --action <action>",
|
|
181
|
+
"Action: allow, alert, block, quarantine",
|
|
182
|
+
"alert",
|
|
183
|
+
)
|
|
184
|
+
.option("-s, --severity <level>", "Severity: low, medium, high", "medium")
|
|
185
|
+
.action(async (name, options) => {
|
|
186
|
+
try {
|
|
187
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
188
|
+
if (!ctx.db) {
|
|
189
|
+
logger.error("Database not available");
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
const db = ctx.db.getDatabase();
|
|
193
|
+
ensureDLPTables(db);
|
|
194
|
+
|
|
195
|
+
const patterns = options.patterns
|
|
196
|
+
? options.patterns.split(",").map((s) => s.trim())
|
|
197
|
+
: [];
|
|
198
|
+
const keywords = options.keywords
|
|
199
|
+
? options.keywords.split(",").map((s) => s.trim())
|
|
200
|
+
: [];
|
|
201
|
+
const result = createPolicy(
|
|
202
|
+
db,
|
|
203
|
+
name,
|
|
204
|
+
patterns,
|
|
205
|
+
keywords,
|
|
206
|
+
options.action,
|
|
207
|
+
options.severity,
|
|
208
|
+
);
|
|
209
|
+
logger.success("Policy created");
|
|
210
|
+
logger.log(` ${chalk.bold("ID:")} ${chalk.cyan(result.id)}`);
|
|
211
|
+
logger.log(` ${chalk.bold("Name:")} ${result.name}`);
|
|
212
|
+
logger.log(` ${chalk.bold("Action:")} ${result.action}`);
|
|
213
|
+
logger.log(` ${chalk.bold("Severity:")} ${result.severity}`);
|
|
214
|
+
|
|
215
|
+
await shutdown();
|
|
216
|
+
} catch (err) {
|
|
217
|
+
logger.error(`Failed: ${err.message}`);
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
policy
|
|
223
|
+
.command("list")
|
|
224
|
+
.description("List DLP policies")
|
|
225
|
+
.option("--json", "Output as JSON")
|
|
226
|
+
.action(async (options) => {
|
|
227
|
+
try {
|
|
228
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
229
|
+
if (!ctx.db) {
|
|
230
|
+
logger.error("Database not available");
|
|
231
|
+
process.exit(1);
|
|
232
|
+
}
|
|
233
|
+
const db = ctx.db.getDatabase();
|
|
234
|
+
ensureDLPTables(db);
|
|
235
|
+
|
|
236
|
+
const policies = listDLPPolicies();
|
|
237
|
+
if (options.json) {
|
|
238
|
+
console.log(JSON.stringify(policies, null, 2));
|
|
239
|
+
} else if (policies.length === 0) {
|
|
240
|
+
logger.info("No DLP policies configured.");
|
|
241
|
+
} else {
|
|
242
|
+
for (const p of policies) {
|
|
243
|
+
logger.log(
|
|
244
|
+
` ${chalk.cyan(p.id.slice(0, 8))} ${p.name} [${p.action}] severity=${p.severity} enabled=${p.enabled}`,
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
await shutdown();
|
|
250
|
+
} catch (err) {
|
|
251
|
+
logger.error(`Failed: ${err.message}`);
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
policy
|
|
257
|
+
.command("delete <policy-id>")
|
|
258
|
+
.description("Delete a DLP policy")
|
|
259
|
+
.action(async (policyId) => {
|
|
260
|
+
try {
|
|
261
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
262
|
+
if (!ctx.db) {
|
|
263
|
+
logger.error("Database not available");
|
|
264
|
+
process.exit(1);
|
|
265
|
+
}
|
|
266
|
+
const db = ctx.db.getDatabase();
|
|
267
|
+
ensureDLPTables(db);
|
|
268
|
+
|
|
269
|
+
deletePolicy(db, policyId);
|
|
270
|
+
logger.success(`Policy ${chalk.cyan(policyId.slice(0, 8))} deleted`);
|
|
271
|
+
|
|
272
|
+
await shutdown();
|
|
273
|
+
} catch (err) {
|
|
274
|
+
logger.error(`Failed: ${err.message}`);
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|