citadel0 1.0.0 → 1.0.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/README.md +188 -75
- package/dist/index.cjs +145 -260
- package/dist/index.d.cts +42 -99
- package/dist/index.d.ts +42 -99
- package/dist/index.js +144 -257
- package/package.json +1 -1
- package/LICENSE +0 -21
package/dist/index.cjs
CHANGED
|
@@ -20,237 +20,22 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
|
|
23
|
+
Citadel_0: () => Citadel_0,
|
|
24
24
|
evaluatePolicies: () => evaluatePolicies,
|
|
25
|
-
|
|
26
|
-
wrapTool: () => wrapTool,
|
|
27
|
-
wrapToolWithReview: () => wrapToolWithReview
|
|
25
|
+
guardTool: () => guardTool
|
|
28
26
|
});
|
|
29
27
|
module.exports = __toCommonJS(index_exports);
|
|
30
28
|
|
|
31
|
-
// src/
|
|
32
|
-
var
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
this.baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
39
|
-
this.agentToken = config.agentToken;
|
|
40
|
-
this.environment = config.environment;
|
|
41
|
-
this.defaultSessionId = config.defaultSessionId;
|
|
42
|
-
}
|
|
43
|
-
async check(action, params = {}, options = {}) {
|
|
44
|
-
const url = `${this.baseUrl}/api/v1/check`;
|
|
45
|
-
const sessionId = options.sessionId ?? this.defaultSessionId ?? `sess_${Math.random().toString(36).slice(2, 11)}`;
|
|
46
|
-
const response = await fetch(url, {
|
|
47
|
-
method: "POST",
|
|
48
|
-
headers: {
|
|
49
|
-
"Content-Type": "application/json",
|
|
50
|
-
Authorization: `Bearer ${this.agentToken}`
|
|
51
|
-
},
|
|
52
|
-
body: JSON.stringify({
|
|
53
|
-
action,
|
|
54
|
-
params,
|
|
55
|
-
sessionId,
|
|
56
|
-
environment: options.environment ?? this.environment,
|
|
57
|
-
metadata: options.metadata
|
|
58
|
-
})
|
|
59
|
-
});
|
|
60
|
-
if (!response.ok) {
|
|
61
|
-
const errorBody = await response.json().catch(() => ({}));
|
|
62
|
-
const errorMessage = typeof errorBody.error === "string" ? errorBody.error : `Citadel gateway error: ${response.status} ${response.statusText}`;
|
|
63
|
-
throw new Error(errorMessage);
|
|
64
|
-
}
|
|
65
|
-
return await response.json();
|
|
66
|
-
}
|
|
67
|
-
async isAllowed(action, params = {}, options = {}) {
|
|
68
|
-
const result = await this.check(action, params, options);
|
|
69
|
-
return result.verdict.decision === "ALLOW";
|
|
70
|
-
}
|
|
71
|
-
async guard(action, params, callback, options = {}) {
|
|
72
|
-
const result = await this.check(action, params, options);
|
|
73
|
-
if (result.verdict.decision !== "ALLOW") {
|
|
74
|
-
throw new Error(
|
|
75
|
-
`Action '${action}' blocked by Citadel: ${result.verdict.reason}`
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
return await callback();
|
|
79
|
-
}
|
|
80
|
-
async getReviewStatus(auditLogId) {
|
|
81
|
-
const url = `${this.baseUrl}/api/v1/review/status?auditLogId=${encodeURIComponent(
|
|
82
|
-
auditLogId
|
|
83
|
-
)}`;
|
|
84
|
-
const response = await fetch(url);
|
|
85
|
-
if (!response.ok) {
|
|
86
|
-
const errorBody = await response.json().catch(() => ({}));
|
|
87
|
-
const errorMessage = typeof errorBody.error === "string" ? errorBody.error : `Review status error: ${response.status}`;
|
|
88
|
-
throw new Error(errorMessage);
|
|
89
|
-
}
|
|
90
|
-
return await response.json();
|
|
91
|
-
}
|
|
92
|
-
async pollReview(auditLogId, options = {}) {
|
|
93
|
-
const timeoutMs = options.timeoutMs ?? 6e4;
|
|
94
|
-
const intervalMs = options.intervalMs ?? 2e3;
|
|
95
|
-
const deadline = Date.now() + timeoutMs;
|
|
96
|
-
while (Date.now() < deadline) {
|
|
97
|
-
const status = await this.getReviewStatus(auditLogId);
|
|
98
|
-
if (status.decision !== "REVIEW") {
|
|
99
|
-
return status;
|
|
100
|
-
}
|
|
101
|
-
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
102
|
-
}
|
|
103
|
-
throw new Error(
|
|
104
|
-
`Review timed out after ${timeoutMs}ms for auditLogId: ${auditLogId}`
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
async guardWithReview(action, params, callback, options = {}) {
|
|
108
|
-
const result = await this.check(action, params, options);
|
|
109
|
-
if (result.verdict.decision === "ALLOW") {
|
|
110
|
-
return await callback();
|
|
111
|
-
}
|
|
112
|
-
if (result.verdict.decision === "BLOCK") {
|
|
113
|
-
throw new Error(
|
|
114
|
-
`Action '${action}' blocked by Citadel: ${result.verdict.reason}`
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
if (options.onReviewPending) {
|
|
118
|
-
options.onReviewPending(result.auditLogId);
|
|
119
|
-
}
|
|
120
|
-
const reviewed = await this.pollReview(result.auditLogId, {
|
|
121
|
-
timeoutMs: options.timeoutMs,
|
|
122
|
-
intervalMs: options.pollIntervalMs
|
|
123
|
-
});
|
|
124
|
-
if (reviewed.decision === "ALLOW") {
|
|
125
|
-
return await callback();
|
|
126
|
-
}
|
|
127
|
-
throw new Error(
|
|
128
|
-
`Action '${action}' rejected during human review: ${reviewed.reviewComment ?? "Rejected"}`
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
// src/sdk/tools.ts
|
|
134
|
-
function wrapTool(client, tool) {
|
|
135
|
-
return {
|
|
136
|
-
...tool,
|
|
137
|
-
execute: async (args) => {
|
|
138
|
-
return await client.guard(
|
|
139
|
-
tool.name,
|
|
140
|
-
args,
|
|
141
|
-
() => tool.execute(args),
|
|
142
|
-
tool.options
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
function wrapToolWithReview(client, tool, reviewOptions) {
|
|
148
|
-
return {
|
|
149
|
-
...tool,
|
|
150
|
-
execute: async (args) => {
|
|
151
|
-
return await client.guardWithReview(
|
|
152
|
-
tool.name,
|
|
153
|
-
args,
|
|
154
|
-
() => tool.execute(args),
|
|
155
|
-
{
|
|
156
|
-
...tool.options,
|
|
157
|
-
...reviewOptions
|
|
158
|
-
}
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// src/engine/semantic.ts
|
|
165
|
-
var INJECTION_PATTERNS = [
|
|
166
|
-
{
|
|
167
|
-
regex: /(?:ignore|disregard|forget|bypass|override)\s+(?:all\s+)?(?:previous|prior|existing|above)\s+(?:instructions|rules|guidelines|directions|constraints)/i,
|
|
168
|
-
description: "Direct prompt instruction override",
|
|
169
|
-
score: 95
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
regex: /(?:you\s+are\s+now|act\s+as|roleplay\s+as)\s+(?:an?\s+)?(?:unfiltered|unrestricted|jailbroken|evil|dan|developer\s+mode)/i,
|
|
173
|
-
description: "Adversarial persona / DAN jailbreak attempt",
|
|
174
|
-
score: 90
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
regex: /(?:reveal|output|print|display|leak)\s+(?:the\s+)?(?:system\s+prompt|initial\s+prompt|core\s+instructions|developer\s+instructions)/i,
|
|
178
|
-
description: "System prompt extraction attempt",
|
|
179
|
-
score: 85
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
regex: /(?:\[INST\]|\[\/INST\]|<<SYS>>|<\/SYS>|<\|im_start\|>|<\|im_end\|>)/i,
|
|
183
|
-
description: "Model token delimiter injection",
|
|
184
|
-
score: 90
|
|
185
|
-
}
|
|
186
|
-
];
|
|
187
|
-
var CREDENTIAL_PATTERNS = [
|
|
188
|
-
{
|
|
189
|
-
regex: /(?:sk-[a-zA-Z0-9-_]{20,}|ghp_[a-zA-Z0-9]{36}|gho_[a-zA-Z0-9]{36})/i,
|
|
190
|
-
description: "Exposed API token (OpenAI / GitHub)",
|
|
191
|
-
score: 95
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
regex: /AKIA[0-9A-Z]{16}/,
|
|
195
|
-
description: "AWS Access Key ID",
|
|
196
|
-
score: 90
|
|
197
|
-
},
|
|
198
|
-
{
|
|
199
|
-
regex: /-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/,
|
|
200
|
-
description: "Exposed Private Key block",
|
|
201
|
-
score: 99
|
|
202
|
-
}
|
|
203
|
-
];
|
|
204
|
-
function extractStrings(obj) {
|
|
205
|
-
const strings = [];
|
|
206
|
-
function recurse(value) {
|
|
207
|
-
if (typeof value === "string") {
|
|
208
|
-
strings.push(value);
|
|
209
|
-
} else if (Array.isArray(value)) {
|
|
210
|
-
for (const item of value) recurse(item);
|
|
211
|
-
} else if (value !== null && typeof value === "object") {
|
|
212
|
-
for (const val of Object.values(value)) {
|
|
213
|
-
recurse(val);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
recurse(obj);
|
|
218
|
-
return strings;
|
|
219
|
-
}
|
|
220
|
-
function scanPayloadSemantics(params) {
|
|
221
|
-
const stringsToScan = extractStrings(params);
|
|
222
|
-
const threats = [];
|
|
223
|
-
for (const text of stringsToScan) {
|
|
224
|
-
for (const rule of INJECTION_PATTERNS) {
|
|
225
|
-
if (rule.regex.test(text)) {
|
|
226
|
-
threats.push({
|
|
227
|
-
type: "PROMPT_INJECTION",
|
|
228
|
-
confidence: rule.score / 100,
|
|
229
|
-
reason: rule.description,
|
|
230
|
-
matchedPattern: rule.regex.source
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
for (const rule of CREDENTIAL_PATTERNS) {
|
|
235
|
-
if (rule.regex.test(text)) {
|
|
236
|
-
threats.push({
|
|
237
|
-
type: "CREDENTIAL_LEAK",
|
|
238
|
-
confidence: rule.score / 100,
|
|
239
|
-
reason: rule.description,
|
|
240
|
-
matchedPattern: rule.regex.source
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
}
|
|
29
|
+
// src/engine/match.ts
|
|
30
|
+
var regexCache = /* @__PURE__ */ new Map();
|
|
31
|
+
function getCompiledRegex(pattern) {
|
|
32
|
+
let re = regexCache.get(pattern);
|
|
33
|
+
if (!re) {
|
|
34
|
+
re = new RegExp(pattern);
|
|
35
|
+
regexCache.set(pattern, re);
|
|
244
36
|
}
|
|
245
|
-
|
|
246
|
-
return {
|
|
247
|
-
flagged: threats.length > 0,
|
|
248
|
-
threats,
|
|
249
|
-
maxRiskScore: Math.round(maxScore)
|
|
250
|
-
};
|
|
37
|
+
return re;
|
|
251
38
|
}
|
|
252
|
-
|
|
253
|
-
// src/engine/match.ts
|
|
254
39
|
function extractField(obj, path) {
|
|
255
40
|
const parts = path.split(".");
|
|
256
41
|
let current = obj;
|
|
@@ -292,7 +77,7 @@ function evaluateCondition(actual, operator, target) {
|
|
|
292
77
|
return false;
|
|
293
78
|
}
|
|
294
79
|
try {
|
|
295
|
-
return
|
|
80
|
+
return getCompiledRegex(target).test(actual);
|
|
296
81
|
} catch {
|
|
297
82
|
return false;
|
|
298
83
|
}
|
|
@@ -305,8 +90,7 @@ function matchesActionPattern(pattern, action) {
|
|
|
305
90
|
return true;
|
|
306
91
|
}
|
|
307
92
|
if (pattern.endsWith("*")) {
|
|
308
|
-
|
|
309
|
-
return action.startsWith(prefix);
|
|
93
|
+
return action.startsWith(pattern.slice(0, -1));
|
|
310
94
|
}
|
|
311
95
|
return false;
|
|
312
96
|
}
|
|
@@ -314,37 +98,35 @@ function evaluateRule(payload, rule) {
|
|
|
314
98
|
const targetObject = {
|
|
315
99
|
action: payload.action,
|
|
316
100
|
params: payload.params,
|
|
317
|
-
context: payload.context,
|
|
318
|
-
timestamp: payload.timestamp,
|
|
101
|
+
context: payload.context ?? {},
|
|
319
102
|
metadata: payload.metadata ?? {}
|
|
320
103
|
};
|
|
321
104
|
const actualValue = extractField(targetObject, rule.field);
|
|
322
105
|
return evaluateCondition(actualValue, rule.operator, rule.value);
|
|
323
106
|
}
|
|
324
|
-
function calculateRisk(decision, matchedCount
|
|
107
|
+
function calculateRisk(decision, matchedCount) {
|
|
325
108
|
if (decision === "BLOCK") {
|
|
326
|
-
return { riskScore:
|
|
109
|
+
return { riskScore: 95, riskLevel: "CRITICAL" };
|
|
327
110
|
}
|
|
328
111
|
if (decision === "REVIEW") {
|
|
329
|
-
return { riskScore:
|
|
112
|
+
return { riskScore: 65, riskLevel: "HIGH" };
|
|
330
113
|
}
|
|
331
114
|
if (matchedCount > 0) {
|
|
332
115
|
return { riskScore: 25, riskLevel: "MEDIUM" };
|
|
333
116
|
}
|
|
334
117
|
return { riskScore: 5, riskLevel: "LOW" };
|
|
335
118
|
}
|
|
336
|
-
function evaluatePolicies(payload,
|
|
337
|
-
const startTime =
|
|
119
|
+
function evaluatePolicies(payload, sortedPolicies) {
|
|
120
|
+
const startTime = performance.now();
|
|
338
121
|
const traces = [];
|
|
339
|
-
const activePolicies = policies.filter((p) => p.isActive && p.tenantId === payload.context.tenantId).sort((a, b) => b.priority - a.priority);
|
|
340
122
|
let finalDecision = "ALLOW";
|
|
341
|
-
let primaryReason = "
|
|
342
|
-
let
|
|
343
|
-
|
|
344
|
-
if (!matchesActionPattern(policy.actionPattern, payload.action)) {
|
|
123
|
+
let primaryReason = "All security policies satisfied";
|
|
124
|
+
for (let i = 0; i < sortedPolicies.length; i++) {
|
|
125
|
+
const policy = sortedPolicies[i];
|
|
126
|
+
if (!policy.isActive || !matchesActionPattern(policy.actionPattern, payload.action)) {
|
|
345
127
|
continue;
|
|
346
128
|
}
|
|
347
|
-
const rulesMatched = policy.rules.length
|
|
129
|
+
const rulesMatched = policy.rules.length === 0 || policy.rules.every((rule) => evaluateRule(payload, rule));
|
|
348
130
|
if (rulesMatched) {
|
|
349
131
|
traces.push({
|
|
350
132
|
policyId: policy.id,
|
|
@@ -363,36 +145,139 @@ function evaluatePolicies(payload, policies) {
|
|
|
363
145
|
}
|
|
364
146
|
}
|
|
365
147
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
const semanticResult = scanPayloadSemantics(payload.params);
|
|
369
|
-
if (semanticResult.flagged) {
|
|
370
|
-
pipeline = traces.length > 0 ? "HYBRID" : "AI_GUARD";
|
|
371
|
-
semanticScore = semanticResult.maxRiskScore;
|
|
372
|
-
finalDecision = "BLOCK";
|
|
373
|
-
const threatReasons = semanticResult.threats.map((t) => t.reason).join(", ");
|
|
374
|
-
primaryReason = `AI Guard blocked threat: ${threatReasons}`;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
const { riskScore, riskLevel } = calculateRisk(finalDecision, traces.length, semanticScore);
|
|
378
|
-
const latencyMs = Date.now() - startTime;
|
|
148
|
+
const { riskScore, riskLevel } = calculateRisk(finalDecision, traces.length);
|
|
149
|
+
const latencyMs = Number((performance.now() - startTime).toFixed(3));
|
|
379
150
|
return {
|
|
380
151
|
verdictId: `vrd_${Math.random().toString(36).slice(2, 11)}`,
|
|
381
152
|
decision: finalDecision,
|
|
382
153
|
reason: primaryReason,
|
|
383
154
|
riskScore,
|
|
384
155
|
riskLevel,
|
|
385
|
-
evaluationPipeline: pipeline,
|
|
386
156
|
matchedPolicies: traces,
|
|
387
|
-
executedAt:
|
|
157
|
+
executedAt: Date.now(),
|
|
388
158
|
latencyMs
|
|
389
159
|
};
|
|
390
160
|
}
|
|
161
|
+
|
|
162
|
+
// src/sdk/client.ts
|
|
163
|
+
var Citadel_0 = class {
|
|
164
|
+
baseUrl;
|
|
165
|
+
agentToken;
|
|
166
|
+
environment;
|
|
167
|
+
defaultSessionId;
|
|
168
|
+
policies = [];
|
|
169
|
+
telemetryQueue = [];
|
|
170
|
+
batchSize;
|
|
171
|
+
flushTimer = null;
|
|
172
|
+
constructor(config) {
|
|
173
|
+
this.baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
174
|
+
this.agentToken = config.agentToken;
|
|
175
|
+
this.environment = config.environment ?? "production";
|
|
176
|
+
this.defaultSessionId = config.defaultSessionId;
|
|
177
|
+
this.batchSize = config.batchSize ?? 50;
|
|
178
|
+
if (config.policies) {
|
|
179
|
+
this.setPolicies(config.policies);
|
|
180
|
+
}
|
|
181
|
+
const interval = config.flushIntervalMs ?? 3e3;
|
|
182
|
+
this.flushTimer = setInterval(() => {
|
|
183
|
+
void this.flush();
|
|
184
|
+
}, interval);
|
|
185
|
+
if (typeof this.flushTimer === "object" && "unref" in this.flushTimer) {
|
|
186
|
+
this.flushTimer.unref();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
setPolicies(policies) {
|
|
190
|
+
this.policies = [...policies].sort((a, b) => b.priority - a.priority);
|
|
191
|
+
}
|
|
192
|
+
async syncPolicies() {
|
|
193
|
+
const res = await fetch(`${this.baseUrl}/api/v1/policies`, {
|
|
194
|
+
headers: { Authorization: `Bearer ${this.agentToken}` }
|
|
195
|
+
});
|
|
196
|
+
if (res.ok) {
|
|
197
|
+
const data = await res.json();
|
|
198
|
+
const list = Array.isArray(data) ? data : data?.policies ?? [];
|
|
199
|
+
this.setPolicies(list);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
check(action, params = {}, options = {}) {
|
|
203
|
+
const payload = {
|
|
204
|
+
action,
|
|
205
|
+
params,
|
|
206
|
+
context: {
|
|
207
|
+
sessionId: options.sessionId ?? this.defaultSessionId,
|
|
208
|
+
environment: options.environment ?? this.environment
|
|
209
|
+
},
|
|
210
|
+
metadata: options.metadata
|
|
211
|
+
};
|
|
212
|
+
const verdict = evaluatePolicies(payload, this.policies);
|
|
213
|
+
this.telemetryQueue.push({
|
|
214
|
+
traceId: verdict.verdictId,
|
|
215
|
+
action,
|
|
216
|
+
params,
|
|
217
|
+
verdict,
|
|
218
|
+
sessionId: payload.context?.sessionId,
|
|
219
|
+
environment: payload.context?.environment ?? this.environment,
|
|
220
|
+
timestamp: verdict.executedAt
|
|
221
|
+
});
|
|
222
|
+
if (this.telemetryQueue.length >= this.batchSize) {
|
|
223
|
+
void this.flush();
|
|
224
|
+
}
|
|
225
|
+
return verdict;
|
|
226
|
+
}
|
|
227
|
+
isAllowed(action, params = {}, options = {}) {
|
|
228
|
+
return this.check(action, params, options).decision === "ALLOW";
|
|
229
|
+
}
|
|
230
|
+
guard(action, params, callback, options = {}) {
|
|
231
|
+
const verdict = this.check(action, params, options);
|
|
232
|
+
if (verdict.decision === "BLOCK") {
|
|
233
|
+
throw new Error(`Action '${action}' blocked by Citadel 0: ${verdict.reason}`);
|
|
234
|
+
}
|
|
235
|
+
if (verdict.decision === "REVIEW") {
|
|
236
|
+
throw new Error(`Action '${action}' halted: requires human review`);
|
|
237
|
+
}
|
|
238
|
+
return callback();
|
|
239
|
+
}
|
|
240
|
+
async flush() {
|
|
241
|
+
if (this.telemetryQueue.length === 0) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const batch = this.telemetryQueue.splice(0, this.batchSize);
|
|
245
|
+
try {
|
|
246
|
+
await fetch(`${this.baseUrl}/api/v1/telemetry`, {
|
|
247
|
+
method: "POST",
|
|
248
|
+
headers: {
|
|
249
|
+
"Content-Type": "application/json",
|
|
250
|
+
Authorization: `Bearer ${this.agentToken}`
|
|
251
|
+
},
|
|
252
|
+
body: JSON.stringify({ traces: batch })
|
|
253
|
+
});
|
|
254
|
+
} catch {
|
|
255
|
+
this.telemetryQueue.unshift(...batch);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
destroy() {
|
|
259
|
+
if (this.flushTimer) {
|
|
260
|
+
clearInterval(this.flushTimer);
|
|
261
|
+
this.flushTimer = null;
|
|
262
|
+
}
|
|
263
|
+
void this.flush();
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// src/sdk/tools.ts
|
|
268
|
+
function guardTool(client, action, fn, options) {
|
|
269
|
+
return async (args) => {
|
|
270
|
+
return client.guard(
|
|
271
|
+
action,
|
|
272
|
+
args,
|
|
273
|
+
() => fn(args),
|
|
274
|
+
options
|
|
275
|
+
);
|
|
276
|
+
};
|
|
277
|
+
}
|
|
391
278
|
// Annotate the CommonJS export names for ESM import in node:
|
|
392
279
|
0 && (module.exports = {
|
|
393
|
-
|
|
280
|
+
Citadel_0,
|
|
394
281
|
evaluatePolicies,
|
|
395
|
-
|
|
396
|
-
wrapTool,
|
|
397
|
-
wrapToolWithReview
|
|
282
|
+
guardTool
|
|
398
283
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
type Decision = 'ALLOW' | 'BLOCK' | 'REVIEW';
|
|
2
2
|
type RiskLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
|
|
3
|
-
type PolicyEffect = 'ALLOW' | 'BLOCK' | 'REVIEW';
|
|
4
|
-
interface SecurityContext {
|
|
5
|
-
tenantId: string;
|
|
6
|
-
agentId: string;
|
|
7
|
-
sessionId: string;
|
|
8
|
-
environment: 'production' | 'staging' | 'development';
|
|
9
|
-
clientIp?: string;
|
|
10
|
-
}
|
|
11
|
-
interface ActionPayload {
|
|
12
|
-
context: SecurityContext;
|
|
13
|
-
action: string;
|
|
14
|
-
params: Record<string, unknown>;
|
|
15
|
-
timestamp: number;
|
|
16
|
-
metadata?: Record<string, unknown>;
|
|
17
|
-
}
|
|
18
3
|
type PolicyConditionOperator = 'EQUALS' | 'NOT_EQUALS' | 'GREATER_THAN' | 'LESS_THAN' | 'IN' | 'NOT_IN' | 'CONTAINS' | 'REGEX_MATCH';
|
|
19
4
|
interface PolicyRule {
|
|
20
5
|
field: string;
|
|
@@ -23,20 +8,28 @@ interface PolicyRule {
|
|
|
23
8
|
}
|
|
24
9
|
interface SecurityPolicy {
|
|
25
10
|
id: string;
|
|
26
|
-
tenantId: string;
|
|
27
11
|
name: string;
|
|
28
|
-
description?: string;
|
|
29
12
|
actionPattern: string;
|
|
30
|
-
|
|
31
|
-
effect: PolicyEffect;
|
|
13
|
+
effect: Decision;
|
|
32
14
|
priority: number;
|
|
33
15
|
isActive: boolean;
|
|
16
|
+
rules: PolicyRule[];
|
|
17
|
+
}
|
|
18
|
+
interface ActionPayload {
|
|
19
|
+
action: string;
|
|
20
|
+
params: Record<string, unknown>;
|
|
21
|
+
context?: {
|
|
22
|
+
tenantId?: string;
|
|
23
|
+
sessionId?: string;
|
|
24
|
+
environment?: string;
|
|
25
|
+
};
|
|
26
|
+
metadata?: Record<string, unknown>;
|
|
34
27
|
}
|
|
35
28
|
interface PolicyEvaluationTrace {
|
|
36
29
|
policyId: string;
|
|
37
30
|
policyName: string;
|
|
38
31
|
matched: boolean;
|
|
39
|
-
effect:
|
|
32
|
+
effect: Decision;
|
|
40
33
|
}
|
|
41
34
|
interface SecurityVerdict {
|
|
42
35
|
verdictId: string;
|
|
@@ -44,108 +37,58 @@ interface SecurityVerdict {
|
|
|
44
37
|
reason: string;
|
|
45
38
|
riskScore: number;
|
|
46
39
|
riskLevel: RiskLevel;
|
|
47
|
-
evaluationPipeline: 'DETERMINISTIC' | 'AI_GUARD' | 'HYBRID';
|
|
48
40
|
matchedPolicies: PolicyEvaluationTrace[];
|
|
49
41
|
executedAt: number;
|
|
50
42
|
latencyMs: number;
|
|
51
43
|
}
|
|
52
|
-
interface
|
|
53
|
-
|
|
54
|
-
tenantId: string;
|
|
55
|
-
agentId: string;
|
|
56
|
-
sessionId: string;
|
|
44
|
+
interface TelemetryTrace {
|
|
45
|
+
traceId: string;
|
|
57
46
|
action: string;
|
|
58
47
|
params: Record<string, unknown>;
|
|
59
48
|
verdict: SecurityVerdict;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
49
|
+
sessionId?: string;
|
|
50
|
+
environment: string;
|
|
51
|
+
timestamp: number;
|
|
63
52
|
}
|
|
64
53
|
|
|
65
|
-
|
|
54
|
+
declare function evaluatePolicies(payload: ActionPayload, sortedPolicies: SecurityPolicy[]): SecurityVerdict;
|
|
55
|
+
|
|
56
|
+
interface Citadel_0_Config {
|
|
66
57
|
baseUrl: string;
|
|
67
58
|
agentToken: string;
|
|
68
59
|
environment?: 'production' | 'staging' | 'development';
|
|
69
60
|
defaultSessionId?: string;
|
|
61
|
+
policies?: SecurityPolicy[];
|
|
62
|
+
flushIntervalMs?: number;
|
|
63
|
+
batchSize?: number;
|
|
70
64
|
}
|
|
71
65
|
interface CheckOptions {
|
|
72
66
|
sessionId?: string;
|
|
73
67
|
environment?: 'production' | 'staging' | 'development';
|
|
74
68
|
metadata?: Record<string, unknown>;
|
|
75
69
|
}
|
|
76
|
-
|
|
77
|
-
verdict: SecurityVerdict;
|
|
78
|
-
auditLogId: string;
|
|
79
|
-
}
|
|
80
|
-
interface ReviewStatus {
|
|
81
|
-
auditLogId: string;
|
|
82
|
-
decision: 'ALLOW' | 'BLOCK' | 'REVIEW';
|
|
83
|
-
reviewedBy?: string;
|
|
84
|
-
reviewComment?: string;
|
|
85
|
-
action: string;
|
|
86
|
-
params: unknown;
|
|
87
|
-
riskScore: number;
|
|
88
|
-
riskLevel: string;
|
|
89
|
-
createdAt: number;
|
|
90
|
-
}
|
|
91
|
-
interface GuardWithReviewOptions extends CheckOptions {
|
|
92
|
-
timeoutMs?: number;
|
|
93
|
-
pollIntervalMs?: number;
|
|
94
|
-
onReviewPending?: (auditLogId: string) => void;
|
|
95
|
-
}
|
|
96
|
-
declare class CitadelClient {
|
|
70
|
+
declare class Citadel_0 {
|
|
97
71
|
private readonly baseUrl;
|
|
98
72
|
private readonly agentToken;
|
|
99
|
-
private readonly environment
|
|
73
|
+
private readonly environment;
|
|
100
74
|
private readonly defaultSessionId?;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
75
|
+
private policies;
|
|
76
|
+
private telemetryQueue;
|
|
77
|
+
private readonly batchSize;
|
|
78
|
+
private flushTimer;
|
|
79
|
+
constructor(config: Citadel_0_Config);
|
|
80
|
+
setPolicies(policies: SecurityPolicy[]): void;
|
|
81
|
+
syncPolicies(): Promise<void>;
|
|
82
|
+
check(action: string, params?: Record<string, unknown>, options?: CheckOptions): SecurityVerdict;
|
|
83
|
+
isAllowed(action: string, params?: Record<string, unknown>, options?: CheckOptions): boolean;
|
|
84
|
+
guard<T>(action: string, params: Record<string, unknown>, callback: () => Promise<T> | T, options?: CheckOptions): Promise<T> | T;
|
|
85
|
+
flush(): Promise<void>;
|
|
86
|
+
destroy(): void;
|
|
111
87
|
}
|
|
112
88
|
|
|
113
|
-
interface
|
|
114
|
-
|
|
115
|
-
description?: string;
|
|
116
|
-
execute: (args: TArgs) => Promise<TResult> | TResult;
|
|
117
|
-
options?: CheckOptions;
|
|
118
|
-
}
|
|
119
|
-
declare function wrapTool<TArgs extends Record<string, unknown>, TResult>(client: CitadelClient, tool: GuardedToolDefinition<TArgs, TResult>): {
|
|
120
|
-
execute: (args: TArgs) => Promise<TResult>;
|
|
121
|
-
name: string;
|
|
122
|
-
description?: string;
|
|
123
|
-
options?: CheckOptions;
|
|
124
|
-
};
|
|
125
|
-
declare function wrapToolWithReview<TArgs extends Record<string, unknown>, TResult>(client: CitadelClient, tool: GuardedToolDefinition<TArgs, TResult>, reviewOptions?: {
|
|
126
|
-
timeoutMs?: number;
|
|
127
|
-
pollIntervalMs?: number;
|
|
128
|
-
onReviewPending?: (auditLogId: string) => void;
|
|
129
|
-
}): {
|
|
130
|
-
execute: (args: TArgs) => Promise<TResult>;
|
|
131
|
-
name: string;
|
|
132
|
-
description?: string;
|
|
133
|
-
options?: CheckOptions;
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
interface ThreatDetection {
|
|
137
|
-
type: 'PROMPT_INJECTION' | 'JAILBREAK_ATTEMPT' | 'CREDENTIAL_LEAK';
|
|
138
|
-
confidence: number;
|
|
139
|
-
reason: string;
|
|
140
|
-
matchedPattern: string;
|
|
89
|
+
interface GuardedToolOptions extends CheckOptions {
|
|
90
|
+
actionName?: string;
|
|
141
91
|
}
|
|
142
|
-
|
|
143
|
-
flagged: boolean;
|
|
144
|
-
threats: ThreatDetection[];
|
|
145
|
-
maxRiskScore: number;
|
|
146
|
-
}
|
|
147
|
-
declare function scanPayloadSemantics(params: Record<string, unknown>): SemanticScanResult;
|
|
148
|
-
|
|
149
|
-
declare function evaluatePolicies(payload: ActionPayload, policies: SecurityPolicy[]): SecurityVerdict;
|
|
92
|
+
declare function guardTool<TArgs extends Record<string, unknown>, TResult>(client: Citadel_0, action: string, fn: (args: TArgs) => Promise<TResult> | TResult, options?: CheckOptions): (args: TArgs) => Promise<TResult>;
|
|
150
93
|
|
|
151
|
-
export { type ActionPayload, type
|
|
94
|
+
export { type ActionPayload, type CheckOptions, Citadel_0, type Citadel_0_Config, type Decision, type GuardedToolOptions, type PolicyConditionOperator, type PolicyEvaluationTrace, type PolicyRule, type RiskLevel, type SecurityPolicy, type SecurityVerdict, type TelemetryTrace, evaluatePolicies, guardTool };
|