@goodandready/dsh-approval-gate 0.1.16 → 0.1.18
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/CHANGELOG.md +162 -146
- package/lib/classifier.js +392 -0
- package/lib/contract-guard.js +147 -0
- package/lib/dispatcher.js +209 -207
- package/lib/engine.js +512 -407
- package/lib/index.js +57 -1
- package/lib/inspect.js +573 -520
- package/lib/messages.js +57 -0
- package/lib/overengineering.js +97 -0
- package/lib/paths.js +378 -320
- package/package.json +55 -55
package/lib/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { SecurityEngine } from "./engine.js";
|
|
|
2
2
|
import { BandsEngine } from "./bands.js";
|
|
3
3
|
import { AuditLogger } from "./audit-log.js";
|
|
4
4
|
import { DeclarativeRulesEngine } from "./rules-loader.js";
|
|
5
|
+
import { LlmClassifier } from "./classifier.js";
|
|
5
6
|
import Schema from "@deepseek-ai/schemastery";
|
|
6
7
|
|
|
7
8
|
if (typeof Schema.prototype?.volatile !== "function") {
|
|
@@ -217,6 +218,26 @@ export const Config = Schema.object({
|
|
|
217
218
|
auditFailClosed: Schema.boolean().default(false).volatile(),
|
|
218
219
|
/** Optional custom declarative rules YAML file path (#38). */
|
|
219
220
|
rulesFile: Schema.string().default("").volatile(),
|
|
221
|
+
/** Semantic LLM classifier endpoint URL (#127). */
|
|
222
|
+
classifierEndpoint: Schema.string().default("").volatile(),
|
|
223
|
+
/** API key for classifier endpoint (#115). */
|
|
224
|
+
classifierApiKey: Schema.string().default("").volatile(),
|
|
225
|
+
/** Model name for semantic classification. */
|
|
226
|
+
classifierModel: Schema.string().default("gpt-4o-mini").volatile(),
|
|
227
|
+
/** Request timeout in ms for classifier (#118). */
|
|
228
|
+
classifierTimeout: Schema.number().default(3000).volatile(),
|
|
229
|
+
/** Policy on classifier timeout: 'strict' or 'permissive' (#118). */
|
|
230
|
+
classifierTimeoutPolicy: Schema.union(["strict", "permissive"]).default("strict").volatile(),
|
|
231
|
+
/** Maximum context characters for classifier prompt (#117). */
|
|
232
|
+
classifierMaxContext: Schema.number().default(1000).volatile(),
|
|
233
|
+
/** Maximum payload bytes for tool arguments (#71). */
|
|
234
|
+
maxPayloadBytes: Schema.number().default(65536).volatile(),
|
|
235
|
+
/** Isolate temporary directories to workspace/.dsh/tmp (#102). */
|
|
236
|
+
isolateTempRoots: Schema.boolean().default(true).volatile(),
|
|
237
|
+
/** Maximum allowed created files per session to prevent overengineering (#89). */
|
|
238
|
+
maxFilesPerSession: Schema.number().default(10).volatile(),
|
|
239
|
+
/** Task contract boundary rules (#87). */
|
|
240
|
+
taskContract: Schema.any().volatile(),
|
|
220
241
|
/** Security engine instance (internal/testing). */
|
|
221
242
|
engine: Schema.any().hidden(),
|
|
222
243
|
});
|
|
@@ -256,9 +277,30 @@ export function apply(ctx, config) {
|
|
|
256
277
|
};
|
|
257
278
|
const unattendedPolicies = cfg.unattendedPolicies || DEFAULT_UNATTENDED_POLICIES.slice();
|
|
258
279
|
const forcedUnattended = cfg.unattended === true;
|
|
280
|
+
const classifier = cfg.classifierEndpoint
|
|
281
|
+
? new LlmClassifier({
|
|
282
|
+
endpoint: cfg.classifierEndpoint,
|
|
283
|
+
apiKey: cfg.classifierApiKey,
|
|
284
|
+
model: cfg.classifierModel,
|
|
285
|
+
timeoutMs: cfg.classifierTimeout,
|
|
286
|
+
timeoutPolicy: cfg.classifierTimeoutPolicy,
|
|
287
|
+
maxContextChars: cfg.classifierMaxContext,
|
|
288
|
+
})
|
|
289
|
+
: null;
|
|
290
|
+
|
|
259
291
|
const engine = (config && config.engine) || cfg.engine || new SecurityEngine({
|
|
260
|
-
inspectConfig: {
|
|
292
|
+
inspectConfig: {
|
|
293
|
+
toolName: toolName,
|
|
294
|
+
fileWriteTools: fileWriteTools,
|
|
295
|
+
workspaceDir: cfg.workspaceDir || "",
|
|
296
|
+
maxPayloadBytes: cfg.maxPayloadBytes !== undefined ? cfg.maxPayloadBytes : 65536,
|
|
297
|
+
isolateTempRoots: cfg.isolateTempRoots !== false,
|
|
298
|
+
},
|
|
299
|
+
taskContract: cfg.taskContract || undefined,
|
|
300
|
+
maxFilesPerSession: cfg.maxFilesPerSession !== undefined ? cfg.maxFilesPerSession : 10,
|
|
261
301
|
bands: new BandsEngine({ toolRegistry: ctx && ctx.tools }),
|
|
302
|
+
classifier,
|
|
303
|
+
timeoutPolicy: cfg.classifierTimeoutPolicy || "strict",
|
|
262
304
|
defaultVerdict: cfg.defaultVerdict || "allow",
|
|
263
305
|
dryRun: Boolean(cfg.dryRun || cfg.shadowMode),
|
|
264
306
|
auditFailClosed: Boolean(cfg.auditFailClosed),
|
|
@@ -288,6 +330,8 @@ export function apply(ctx, config) {
|
|
|
288
330
|
active: true,
|
|
289
331
|
dryRun: Boolean(cfg.dryRun || cfg.shadowMode),
|
|
290
332
|
auditFailClosed: Boolean(cfg.auditFailClosed),
|
|
333
|
+
classifierActive: Boolean(classifier || engine.classifier),
|
|
334
|
+
timeoutPolicy: engine.timeoutPolicy || "strict",
|
|
291
335
|
counters: engine.getCounters(),
|
|
292
336
|
rulesCount: engine.declarativeRules ? engine.declarativeRules.count() : 0,
|
|
293
337
|
cacheStats: engine.cache ? engine.cache.stats() : null,
|
|
@@ -519,3 +563,15 @@ export {
|
|
|
519
563
|
WORKSPACE_RULES_REL,
|
|
520
564
|
USER_RULES_REL,
|
|
521
565
|
} from "./rules-loader.js";
|
|
566
|
+
export {
|
|
567
|
+
normalizeChatCompletionsUrl,
|
|
568
|
+
withLlmRetry,
|
|
569
|
+
sanitizeClassifierInput,
|
|
570
|
+
truncateClassifierContext,
|
|
571
|
+
isLowRiskExecution,
|
|
572
|
+
LlmClassifier,
|
|
573
|
+
} from "./classifier.js";
|
|
574
|
+
export { ContractGuard } from "./contract-guard.js";
|
|
575
|
+
export { OverengineeringGuard, DEFAULT_MAX_FILES_PER_SESSION } from "./overengineering.js";
|
|
576
|
+
export { resolveTempRoot, isGlobalTempPath, checkTempIsolation } from "./paths.js";
|
|
577
|
+
export { computePayloadSize, scanPromptInjection } from "./inspect.js";
|