@aliou/pi-guardrails 0.11.2 → 0.12.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 +72 -167
- package/extensions/guardrails/commands/examples/index.ts +520 -0
- package/extensions/guardrails/commands/onboarding/config.ts +54 -0
- package/{src/commands/onboarding-command.ts → extensions/guardrails/commands/onboarding/index.ts} +5 -31
- package/extensions/guardrails/commands/settings/add-rule-wizard.ts +267 -0
- package/extensions/guardrails/commands/settings/examples.ts +399 -0
- package/extensions/guardrails/commands/settings/index.ts +596 -0
- package/extensions/guardrails/commands/settings/path-list-editor.ts +158 -0
- package/extensions/guardrails/commands/settings/scope-picker-submenu.ts +69 -0
- package/extensions/guardrails/commands/settings/utils.ts +108 -0
- package/extensions/guardrails/components/onboarding-choice-step.ts +140 -0
- package/extensions/guardrails/components/onboarding-finish-step.ts +50 -0
- package/extensions/guardrails/components/onboarding-intro-step.ts +30 -0
- package/extensions/guardrails/components/onboarding-types.ts +10 -0
- package/extensions/guardrails/components/onboarding-wizard.ts +116 -0
- package/{src → extensions/guardrails}/components/pattern-editor.ts +11 -10
- package/extensions/guardrails/index.ts +106 -0
- package/extensions/guardrails/rules.test.ts +107 -0
- package/extensions/guardrails/rules.ts +119 -0
- package/extensions/guardrails/targets.test.ts +44 -0
- package/extensions/guardrails/targets.ts +66 -0
- package/extensions/path-access/grants.test.ts +47 -0
- package/extensions/path-access/grants.ts +68 -0
- package/extensions/path-access/index.ts +143 -0
- package/extensions/path-access/prompt.ts +196 -0
- package/extensions/path-access/rules.test.ts +46 -0
- package/extensions/path-access/rules.ts +37 -0
- package/extensions/path-access/targets.test.ts +40 -0
- package/extensions/path-access/targets.ts +19 -0
- package/extensions/permission-gate/grants.ts +21 -0
- package/extensions/permission-gate/index.ts +122 -0
- package/extensions/permission-gate/prompt.ts +222 -0
- package/extensions/permission-gate/rules.test.ts +132 -0
- package/extensions/permission-gate/rules.ts +72 -0
- package/package.json +18 -20
- package/schema.json +286 -0
- package/src/core/check.test.ts +169 -0
- package/src/core/check.ts +38 -0
- package/src/{hooks/permission-gate/dangerous-commands.test.ts → core/commands/dangerous.test.ts} +134 -2
- package/src/{hooks/permission-gate/dangerous-commands.ts → core/commands/dangerous.ts} +119 -1
- package/src/core/commands/index.ts +15 -0
- package/src/core/index.ts +13 -0
- package/src/{utils/path-access.test.ts → core/paths/access.test.ts} +1 -5
- package/src/core/paths/index.ts +14 -0
- package/src/core/shell/command-args.test.ts +142 -0
- package/src/{utils → core/shell}/command-args.ts +71 -0
- package/src/core/shell/index.ts +2 -0
- package/src/core/types.ts +55 -0
- package/src/shared/config/defaults.ts +118 -0
- package/src/shared/config/index.ts +17 -0
- package/src/shared/config/loader.ts +64 -0
- package/src/shared/config/migration/001-v0-format-upgrade.ts +107 -0
- package/src/shared/config/migration/002-strip-toolchain-fields.ts +39 -0
- package/src/shared/config/migration/003-strip-command-explainer-fields.ts +42 -0
- package/src/shared/config/migration/004-env-files-to-policies.ts +87 -0
- package/src/shared/config/migration/005-normalize-allowed-paths.ts +43 -0
- package/src/shared/config/migration/006-apply-builtin-defaults.ts +19 -0
- package/src/shared/config/migration/007-mark-onboarding-done.ts +25 -0
- package/src/shared/config/migration/index.ts +44 -0
- package/src/shared/config/migration/version.ts +7 -0
- package/src/shared/config/types.ts +141 -0
- package/src/shared/events.ts +100 -0
- package/src/shared/index.ts +6 -0
- package/src/shared/matching.test.ts +86 -0
- package/src/{utils → shared}/matching.ts +4 -4
- package/src/{utils → shared/paths}/bash-paths.test.ts +32 -2
- package/src/{utils → shared/paths}/bash-paths.ts +4 -4
- package/src/shared/paths/index.ts +1 -0
- package/src/shared/warnings.ts +17 -0
- package/docs/defaults.md +0 -140
- package/docs/examples.md +0 -170
- package/src/commands/onboarding.ts +0 -390
- package/src/commands/settings-command.ts +0 -1616
- package/src/config.ts +0 -392
- package/src/hooks/index.ts +0 -11
- package/src/hooks/path-access.ts +0 -395
- package/src/hooks/permission-gate/index.test.ts +0 -332
- package/src/hooks/permission-gate/index.ts +0 -595
- package/src/hooks/policies.ts +0 -322
- package/src/index.ts +0 -96
- package/src/lib/executor.ts +0 -280
- package/src/lib/index.ts +0 -16
- package/src/lib/model-resolver.ts +0 -47
- package/src/lib/timing.ts +0 -42
- package/src/lib/types.ts +0 -115
- package/src/utils/command-args.test.ts +0 -83
- package/src/utils/events.ts +0 -32
- package/src/utils/migration.test.ts +0 -58
- package/src/utils/migration.ts +0 -340
- package/src/utils/warnings.ts +0 -7
- /package/src/{utils/path-access.ts → core/paths/access.ts} +0 -0
- /package/src/{utils → core/paths}/path.test.ts +0 -0
- /package/src/{utils → core/paths}/path.ts +0 -0
- /package/src/{utils/shell-utils.ts → core/shell/ast.ts} +0 -0
- /package/src/{utils/glob-expander.ts → shared/glob.ts} +0 -0
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Model resolution helper for subagents.
|
|
3
|
-
*
|
|
4
|
-
* Resolves a model by provider + ID from the model registry.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { Model } from "@mariozechner/pi-ai";
|
|
8
|
-
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Find a model by provider and ID.
|
|
12
|
-
*
|
|
13
|
-
* @param provider - Provider name (e.g., "openrouter", "anthropic", "openai-codex")
|
|
14
|
-
* @param modelId - Model ID (e.g., "anthropic/claude-haiku-4.5")
|
|
15
|
-
* @param ctx - Extension context with modelRegistry
|
|
16
|
-
* @returns The resolved model
|
|
17
|
-
* @throws Error if model not found or API key not configured
|
|
18
|
-
*/
|
|
19
|
-
export function resolveModel(
|
|
20
|
-
provider: string,
|
|
21
|
-
modelId: string,
|
|
22
|
-
ctx: ExtensionContext,
|
|
23
|
-
// biome-ignore lint/suspicious/noExplicitAny: Model type requires any for generic API
|
|
24
|
-
): Model<any> {
|
|
25
|
-
const available = ctx.modelRegistry.getAvailable();
|
|
26
|
-
const model = available.find(
|
|
27
|
-
(m) => m.id === modelId && m.provider === provider,
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
if (model) {
|
|
31
|
-
return model;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Check if the model exists but the API key is missing
|
|
35
|
-
const all = ctx.modelRegistry.getAll();
|
|
36
|
-
const existsWithoutKey = all.some(
|
|
37
|
-
(m) => m.id === modelId && m.provider === provider,
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
if (existsWithoutKey) {
|
|
41
|
-
throw new Error(
|
|
42
|
-
`Model "${modelId}" exists on ${provider} but no valid API key is configured.`,
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
throw new Error(`Model "${modelId}" not found on provider "${provider}".`);
|
|
47
|
-
}
|
package/src/lib/timing.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared timing utilities for tool and subagent execution.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/** Minimal shape that supports timing fields. */
|
|
6
|
-
export interface TimedExecution {
|
|
7
|
-
startedAt?: number;
|
|
8
|
-
endedAt?: number;
|
|
9
|
-
durationMs?: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/** Mark execution start time (epoch ms). */
|
|
13
|
-
export function markExecutionStart<T extends TimedExecution>(
|
|
14
|
-
target: T,
|
|
15
|
-
startedAt = Date.now(),
|
|
16
|
-
): T {
|
|
17
|
-
target.startedAt = startedAt;
|
|
18
|
-
return target;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Mark execution end time and compute duration (epoch ms / ms). */
|
|
22
|
-
export function markExecutionEnd<T extends TimedExecution>(
|
|
23
|
-
target: T,
|
|
24
|
-
endedAt = Date.now(),
|
|
25
|
-
): T {
|
|
26
|
-
target.endedAt = endedAt;
|
|
27
|
-
if (target.startedAt !== undefined) {
|
|
28
|
-
target.durationMs = Math.max(0, endedAt - target.startedAt);
|
|
29
|
-
}
|
|
30
|
-
return target;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** Simple wall-clock timer for a full operation (e.g., subagent call). */
|
|
34
|
-
export function createExecutionTimer(startedAt = Date.now()): {
|
|
35
|
-
startedAt: number;
|
|
36
|
-
getDurationMs: (endedAt?: number) => number;
|
|
37
|
-
} {
|
|
38
|
-
return {
|
|
39
|
-
startedAt,
|
|
40
|
-
getDurationMs: (endedAt = Date.now()) => Math.max(0, endedAt - startedAt),
|
|
41
|
-
};
|
|
42
|
-
}
|
package/src/lib/types.ts
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import type { AgentTool, ThinkingLevel } from "@mariozechner/pi-agent-core";
|
|
2
|
-
import type { Model } from "@mariozechner/pi-ai";
|
|
3
|
-
import type { Skill, ToolDefinition } from "@mariozechner/pi-coding-agent";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Configuration for a subagent.
|
|
7
|
-
*/
|
|
8
|
-
export interface SubagentConfig {
|
|
9
|
-
/** Subagent name (for logging and run ID) */
|
|
10
|
-
name: string;
|
|
11
|
-
|
|
12
|
-
/** Model instance to use */
|
|
13
|
-
// biome-ignore lint/suspicious/noExplicitAny: Model type requires any for generic API
|
|
14
|
-
model: Model<any>;
|
|
15
|
-
|
|
16
|
-
/** System prompt for the subagent */
|
|
17
|
-
systemPrompt: string;
|
|
18
|
-
|
|
19
|
-
/** Built-in tools (AgentTool[]) - e.g., from createReadOnlyTools() */
|
|
20
|
-
tools?: AgentTool[];
|
|
21
|
-
|
|
22
|
-
/** Custom tools (ToolDefinition[]) - e.g., GitHub tools */
|
|
23
|
-
customTools?: ToolDefinition[];
|
|
24
|
-
|
|
25
|
-
/** Skills to load into system prompt */
|
|
26
|
-
skills?: Skill[];
|
|
27
|
-
|
|
28
|
-
/** Thinking level. Default: "low" */
|
|
29
|
-
thinkingLevel?: ThinkingLevel;
|
|
30
|
-
|
|
31
|
-
/** Logging options */
|
|
32
|
-
logging?: {
|
|
33
|
-
/** Enable logging. Default: false */
|
|
34
|
-
enabled: boolean;
|
|
35
|
-
/** Include raw events in debug.jsonl. Default: false */
|
|
36
|
-
debug?: boolean;
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Tool call state for tracking subagent tool executions.
|
|
42
|
-
*/
|
|
43
|
-
export interface SubagentToolCall {
|
|
44
|
-
toolCallId: string;
|
|
45
|
-
toolName: string;
|
|
46
|
-
args: Record<string, unknown>;
|
|
47
|
-
status: "running" | "done" | "error";
|
|
48
|
-
/** Epoch ms when tool execution started */
|
|
49
|
-
startedAt?: number;
|
|
50
|
-
/** Epoch ms when tool execution ended */
|
|
51
|
-
endedAt?: number;
|
|
52
|
-
/** Duration in milliseconds (set when ended) */
|
|
53
|
-
durationMs?: number;
|
|
54
|
-
result?: unknown;
|
|
55
|
-
error?: string;
|
|
56
|
-
/** Partial result from tool updates (for progress display) */
|
|
57
|
-
partialResult?: {
|
|
58
|
-
content: Array<{ type: string; text?: string }>;
|
|
59
|
-
details?: unknown;
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Usage/cost information from the model response.
|
|
65
|
-
*/
|
|
66
|
-
export interface SubagentUsage {
|
|
67
|
-
/** Input tokens from API (if available) */
|
|
68
|
-
inputTokens?: number;
|
|
69
|
-
/** Output tokens from API (if available) */
|
|
70
|
-
outputTokens?: number;
|
|
71
|
-
/** Cache read tokens (if available) */
|
|
72
|
-
cacheReadTokens?: number;
|
|
73
|
-
/** Cache write tokens (if available) */
|
|
74
|
-
cacheWriteTokens?: number;
|
|
75
|
-
/** Estimated tokens from response length (chars/4) */
|
|
76
|
-
estimatedTokens: number;
|
|
77
|
-
/** LLM cost in USD (if available) */
|
|
78
|
-
llmCost?: number;
|
|
79
|
-
/** Tool/API cost in USD (e.g., Exa, GitHub) */
|
|
80
|
-
toolCost?: number;
|
|
81
|
-
/** Total cost in USD (llmCost + toolCost) */
|
|
82
|
-
totalCost?: number;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Result from executing a subagent.
|
|
87
|
-
*/
|
|
88
|
-
export interface SubagentResult {
|
|
89
|
-
/** Final text content from the subagent */
|
|
90
|
-
content: string;
|
|
91
|
-
|
|
92
|
-
/** Whether the subagent was aborted */
|
|
93
|
-
aborted: boolean;
|
|
94
|
-
|
|
95
|
-
/** Final tool call states */
|
|
96
|
-
toolCalls: SubagentToolCall[];
|
|
97
|
-
|
|
98
|
-
/** Total subagent execution duration in milliseconds */
|
|
99
|
-
totalDurationMs: number;
|
|
100
|
-
|
|
101
|
-
/** Error message if the subagent failed */
|
|
102
|
-
error?: string;
|
|
103
|
-
|
|
104
|
-
/** Unique run identifier */
|
|
105
|
-
runId: string;
|
|
106
|
-
|
|
107
|
-
/** Usage/cost information */
|
|
108
|
-
usage: SubagentUsage;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/** Callback for text streaming updates */
|
|
112
|
-
export type OnTextUpdate = (delta: string, accumulated: string) => void;
|
|
113
|
-
|
|
114
|
-
/** Callback for tool execution updates */
|
|
115
|
-
export type OnToolUpdate = (toolCalls: SubagentToolCall[]) => void;
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { classifyCommandArgs } from "./command-args";
|
|
3
|
-
|
|
4
|
-
const tokens = (command: string, args: string[]) =>
|
|
5
|
-
classifyCommandArgs(command, args).map((arg) => arg.token);
|
|
6
|
-
|
|
7
|
-
describe("classifyCommandArgs", () => {
|
|
8
|
-
it("keeps unknown command arguments unchanged", () => {
|
|
9
|
-
expect(tokens("cat", ["/etc/hosts", "./file"])).toEqual([
|
|
10
|
-
"/etc/hosts",
|
|
11
|
-
"./file",
|
|
12
|
-
]);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it("ignores awk inline program and keeps file operands", () => {
|
|
16
|
-
expect(tokens("awk", ["/aaa/{print}", "./input"])).toEqual(["./input"]);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it("keeps awk -f program files", () => {
|
|
20
|
-
expect(tokens("awk", ["-f", "./prog.awk", "./input"])).toEqual([
|
|
21
|
-
"./prog.awk",
|
|
22
|
-
"./input",
|
|
23
|
-
]);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("ignores sed inline scripts and keeps file operands", () => {
|
|
27
|
-
expect(tokens("sed", ["s#/old#/new#g", "./file"])).toEqual(["./file"]);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("keeps sed -f script files", () => {
|
|
31
|
-
expect(tokens("sed", ["-f", "./script.sed", "./file"])).toEqual([
|
|
32
|
-
"./script.sed",
|
|
33
|
-
"./file",
|
|
34
|
-
]);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("ignores grep patterns and keeps file operands", () => {
|
|
38
|
-
expect(tokens("grep", ["/api/v1", "./src"])).toEqual(["./src"]);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("keeps grep pattern files", () => {
|
|
42
|
-
expect(tokens("grep", ["-f", "./patterns", "./src"])).toEqual([
|
|
43
|
-
"./patterns",
|
|
44
|
-
"./src",
|
|
45
|
-
]);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it("keeps find roots and ignores expression patterns", () => {
|
|
49
|
-
expect(tokens("find", ["./src", "-regex", ".*/test/.*"])).toEqual([
|
|
50
|
-
"./src",
|
|
51
|
-
]);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("ignores jq filters and keeps file operands", () => {
|
|
55
|
-
expect(tokens("jq", ['.path | test("^/tmp/")', "./data.json"])).toEqual([
|
|
56
|
-
"./data.json",
|
|
57
|
-
]);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it("keeps jq -f filter files", () => {
|
|
61
|
-
expect(tokens("jq", ["-f", "./filter.jq", "./data.json"])).toEqual([
|
|
62
|
-
"./filter.jq",
|
|
63
|
-
"./data.json",
|
|
64
|
-
]);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it("ignores interpreter inline code", () => {
|
|
68
|
-
expect(tokens("python3", ["-c", 'open("/etc/passwd")'])).toEqual([]);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it("keeps interpreter script operands", () => {
|
|
72
|
-
expect(tokens("python3", ["./script.py", "./data.json"])).toEqual([
|
|
73
|
-
"./script.py",
|
|
74
|
-
"./data.json",
|
|
75
|
-
]);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it("ignores delimiter args", () => {
|
|
79
|
-
expect(tokens("cut", ["-d", "/", "./file"])).toEqual(["./file"]);
|
|
80
|
-
expect(tokens("sort", ["-t", "/", "./file"])).toEqual(["./file"]);
|
|
81
|
-
expect(tokens("tr", ["/", ":"])).toEqual([]);
|
|
82
|
-
});
|
|
83
|
-
});
|
package/src/utils/events.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
|
|
3
|
-
export const GUARDRAILS_BLOCKED_EVENT = "guardrails:blocked";
|
|
4
|
-
export const GUARDRAILS_DANGEROUS_EVENT = "guardrails:dangerous";
|
|
5
|
-
|
|
6
|
-
export interface GuardrailsBlockedEvent {
|
|
7
|
-
feature: "policies" | "permissionGate" | "pathAccess";
|
|
8
|
-
toolName: string;
|
|
9
|
-
input: Record<string, unknown>;
|
|
10
|
-
reason: string;
|
|
11
|
-
userDenied?: boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface GuardrailsDangerousEvent {
|
|
15
|
-
command: string;
|
|
16
|
-
description: string;
|
|
17
|
-
pattern: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function emitBlocked(
|
|
21
|
-
pi: ExtensionAPI,
|
|
22
|
-
event: GuardrailsBlockedEvent,
|
|
23
|
-
): void {
|
|
24
|
-
pi.events.emit(GUARDRAILS_BLOCKED_EVENT, event);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function emitDangerous(
|
|
28
|
-
pi: ExtensionAPI,
|
|
29
|
-
event: GuardrailsDangerousEvent,
|
|
30
|
-
): void {
|
|
31
|
-
pi.events.emit(GUARDRAILS_DANGEROUS_EVENT, event);
|
|
32
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import type { GuardrailsConfig } from "../config";
|
|
3
|
-
import {
|
|
4
|
-
migrateAllowedPaths,
|
|
5
|
-
needsAllowedPathsMigration,
|
|
6
|
-
normalizeAllowedPaths,
|
|
7
|
-
} from "./migration";
|
|
8
|
-
|
|
9
|
-
describe("allowedPaths migration", () => {
|
|
10
|
-
it("normalizes strings and legacy pattern objects", () => {
|
|
11
|
-
expect(
|
|
12
|
-
normalizeAllowedPaths([
|
|
13
|
-
"/dev/null",
|
|
14
|
-
{ pattern: "~/Downloads/" },
|
|
15
|
-
{ pattern: " /tmp/file " },
|
|
16
|
-
{ pattern: "" },
|
|
17
|
-
{ regex: true },
|
|
18
|
-
42,
|
|
19
|
-
null,
|
|
20
|
-
"/dev/null",
|
|
21
|
-
]),
|
|
22
|
-
).toEqual(["/dev/null", "~/Downloads/", "/tmp/file"]);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("detects legacy object-shaped allowed paths", () => {
|
|
26
|
-
const config = {
|
|
27
|
-
pathAccess: {
|
|
28
|
-
allowedPaths: [{ pattern: "/dev/null" }],
|
|
29
|
-
},
|
|
30
|
-
} as unknown as GuardrailsConfig;
|
|
31
|
-
|
|
32
|
-
expect(needsAllowedPathsMigration(config)).toBe(true);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("does not migrate valid string allowed paths", () => {
|
|
36
|
-
const config: GuardrailsConfig = {
|
|
37
|
-
pathAccess: {
|
|
38
|
-
allowedPaths: ["/dev/null"],
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
expect(needsAllowedPathsMigration(config)).toBe(false);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("converts legacy object-shaped allowed paths to strings", () => {
|
|
46
|
-
const config = {
|
|
47
|
-
pathAccess: {
|
|
48
|
-
mode: "block",
|
|
49
|
-
allowedPaths: [{ pattern: "/dev/null" }, "~/Downloads/"],
|
|
50
|
-
},
|
|
51
|
-
} as unknown as GuardrailsConfig;
|
|
52
|
-
|
|
53
|
-
expect(migrateAllowedPaths(config).pathAccess?.allowedPaths).toEqual([
|
|
54
|
-
"/dev/null",
|
|
55
|
-
"~/Downloads/",
|
|
56
|
-
]);
|
|
57
|
-
});
|
|
58
|
-
});
|