dsh-permission-rules 0.4.2 → 0.5.2

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.
Files changed (76) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.es.md +160 -117
  3. package/README.hi.md +162 -119
  4. package/README.md +133 -90
  5. package/README.pt.md +161 -118
  6. package/README.zh.md +162 -119
  7. package/docs/rule-test-vectors/README.md +28 -0
  8. package/docs/rule-test-vectors/corpus.json +109 -0
  9. package/lib/client.js +4693 -0
  10. package/lib/client.js.map +1 -0
  11. package/lib/index.js +1530 -179
  12. package/lib/typert.host.js +4305 -0
  13. package/lib/types/client/index.d.ts +28 -0
  14. package/lib/types/client/index.d.ts.map +1 -0
  15. package/lib/types/client/locales.d.ts +9 -0
  16. package/lib/types/client/locales.d.ts.map +1 -0
  17. package/lib/types/client/remote.d.ts +181 -0
  18. package/lib/types/client/remote.d.ts.map +1 -0
  19. package/lib/types/client/section.d.ts +35 -0
  20. package/lib/types/client/section.d.ts.map +1 -0
  21. package/lib/types/config.d.ts +54 -2
  22. package/lib/types/config.d.ts.map +1 -1
  23. package/lib/types/events.d.ts +45 -0
  24. package/lib/types/events.d.ts.map +1 -1
  25. package/lib/types/index.d.ts +8 -6
  26. package/lib/types/index.d.ts.map +1 -1
  27. package/lib/types/network.d.ts +90 -0
  28. package/lib/types/network.d.ts.map +1 -0
  29. package/lib/types/prose.d.ts +15 -0
  30. package/lib/types/prose.d.ts.map +1 -1
  31. package/lib/types/proxy.d.ts +128 -0
  32. package/lib/types/proxy.d.ts.map +1 -0
  33. package/lib/types/remote-service.d.ts +45 -0
  34. package/lib/types/remote-service.d.ts.map +1 -0
  35. package/lib/types/rules.d.ts +131 -0
  36. package/lib/types/rules.d.ts.map +1 -1
  37. package/lib/types/runtime.d.ts +153 -21
  38. package/lib/types/runtime.d.ts.map +1 -1
  39. package/lib/types/settings.d.ts +28 -0
  40. package/lib/types/settings.d.ts.map +1 -0
  41. package/lib/types/typert.host.d.ts +166 -0
  42. package/lib/types/typert.host.d.ts.map +1 -0
  43. package/lib/types/wire.d.ts +421 -0
  44. package/lib/types/wire.d.ts.map +1 -0
  45. package/package.json +182 -144
  46. package/scripts/repair-session-logs.mjs +7 -2
  47. package/src/client/index.ts +111 -0
  48. package/src/client/locales.ts +94 -0
  49. package/src/client/remote.ts +41 -0
  50. package/src/client/section.ts +201 -0
  51. package/src/config.ts +111 -0
  52. package/src/events.ts +46 -0
  53. package/src/index.ts +2 -0
  54. package/src/network.ts +177 -0
  55. package/src/prose.ts +85 -10
  56. package/src/proxy.ts +327 -0
  57. package/src/remote-service.ts +109 -0
  58. package/src/rules.ts +424 -5
  59. package/src/runtime.ts +464 -53
  60. package/src/settings.ts +74 -0
  61. package/src/typert.host.ts +25 -0
  62. package/src/wire.ts +239 -0
  63. package/lib/types/config.js +0 -99
  64. package/lib/types/config.js.map +0 -1
  65. package/lib/types/events.js +0 -44
  66. package/lib/types/events.js.map +0 -1
  67. package/lib/types/glob.js +0 -307
  68. package/lib/types/glob.js.map +0 -1
  69. package/lib/types/index.js +0 -27
  70. package/lib/types/index.js.map +0 -1
  71. package/lib/types/prose.js +0 -173
  72. package/lib/types/prose.js.map +0 -1
  73. package/lib/types/rules.js +0 -610
  74. package/lib/types/rules.js.map +0 -1
  75. package/lib/types/runtime.js +0 -818
  76. package/lib/types/runtime.js.map +0 -1
@@ -0,0 +1,128 @@
1
+ /**
2
+ * The plugin's built-in local HTTP/CONNECT proxy: the process-level
3
+ * network gate for shell subprocess traffic. Bash/pwsh children inherit
4
+ * `HTTP(S)_PROXY`/`ALL_PROXY` environment variables pointing here, and the
5
+ * proxy adjudicates EVERY connection target against the loaded network
6
+ * rules and the active policy mode — the domain decision lives in the
7
+ * proxy layer, not in per-command wrappers.
8
+ *
9
+ * Boundaries (documented in the README): DSH's official `ctx.sandbox`
10
+ * enforces FILE effects only, so network interception is entirely this
11
+ * plugin's job; the proxy has no session context, so an `ask` decision at
12
+ * the proxy layer cannot ride the interactive approval seam — it blocks
13
+ * the connection with a structured message and is audit-logged instead
14
+ * (web tools get the real approval seam at `tools/pre-execute`).
15
+ * @module dsh-permission-rules/proxy
16
+ */
17
+ import type { CallId } from '@deepseek-ai/dsh-llm';
18
+ import type { NetworkDecision, NetworkMode } from './network.js';
19
+ import type { NetworkTarget, SchemeName } from './rules.js';
20
+ /** Proxy environment variable names the injector sets/restores (uppercase + lowercase for mixed-ecosystem CLIs). */
21
+ export declare const PROXY_ENV_NAMES: readonly string[];
22
+ /** NO_PROXY names cleared (or preserved) by the injector. */
23
+ export declare const NO_PROXY_ENV_NAMES: readonly string[];
24
+ /** One recorded proxy-layer block (settings-page list + session audit + logger). */
25
+ export interface NetworkBlockRecord {
26
+ readonly time: number;
27
+ readonly tool: string;
28
+ readonly attributed: boolean;
29
+ readonly callId?: CallId;
30
+ readonly domain: string;
31
+ readonly scheme?: SchemeName;
32
+ readonly port?: number;
33
+ readonly action: 'deny' | 'ask';
34
+ readonly mode: NetworkMode;
35
+ readonly matched: boolean;
36
+ readonly source: string;
37
+ readonly ruleIndex?: number;
38
+ readonly reason?: string;
39
+ }
40
+ /** Cumulative proxy-layer block counters. */
41
+ export interface NetworkStats {
42
+ denied: number;
43
+ askBlocked: number;
44
+ }
45
+ /** The attribution the runtime supplies for one connection (the newest in-flight shell execution). */
46
+ export interface ProxyAttribution {
47
+ readonly tool: string;
48
+ readonly callId?: CallId;
49
+ readonly agent?: {
50
+ readonly session: {
51
+ append(type: 'permissionRules/network', data: unknown, options?: {
52
+ ignorable?: true;
53
+ }): unknown;
54
+ };
55
+ };
56
+ }
57
+ /** Construction options for {@link NetworkProxy}. */
58
+ export interface NetworkProxyOptions {
59
+ /** Bind address (loopback by config). */
60
+ readonly bind: string;
61
+ /** Requested port; `0` binds an ephemeral port. */
62
+ readonly port: number;
63
+ /** Cap on recent-block records kept in memory. */
64
+ readonly maxRecent: number;
65
+ /** Decision function supplied by the runtime (rules + mode). */
66
+ readonly decide: (target: NetworkTarget) => NetworkDecision;
67
+ /** Current attribution (newest in-flight shell execution), or undefined. */
68
+ readonly attribution?: () => ProxyAttribution | undefined;
69
+ /** Called for every blocked connection, after the response is sent. */
70
+ readonly onBlock?: (record: NetworkBlockRecord, attribution: ProxyAttribution | undefined) => void;
71
+ /** Logger sink (proxy failures must never crash the host). */
72
+ readonly logger: {
73
+ warn(message: string): void;
74
+ };
75
+ }
76
+ /**
77
+ * The local HTTP/CONNECT policy proxy. Binds on demand (the plugin calls
78
+ * {@link start} inside an effect and {@link close} from its disposer);
79
+ * every live tunnel socket is tracked and destroyed on close so updates
80
+ * and uninstalls leave no orphaned connections.
81
+ */
82
+ export declare class NetworkProxy {
83
+ private readonly options;
84
+ private server;
85
+ private readonly sockets;
86
+ private readonly recent;
87
+ private readonly stats;
88
+ private actualPort;
89
+ constructor(options: NetworkProxyOptions);
90
+ /** The bound port (valid after {@link start} resolves). */
91
+ get port(): number;
92
+ /** Deny/ask blocks recorded since mount, newest first (settings-page list). */
93
+ recentBlocks(): readonly NetworkBlockRecord[];
94
+ /** Cumulative block counters. */
95
+ blockStats(): NetworkStats;
96
+ /** Bind the server and return the actual port. */
97
+ start(): Promise<number>;
98
+ /** Stop the server and destroy every tunnel; resolves when sockets are closed. */
99
+ close(): Promise<void>;
100
+ /** Plain-HTTP proxying: absolute-form requests are adjudicated and forwarded (or blocked with a structured 403). */
101
+ private handleRequest;
102
+ /** CONNECT tunneling (HTTPS and friends): adjudicate, then either 403 or an established TCP tunnel. */
103
+ private handleConnect;
104
+ /** Adjudicate one plain-HTTP request; deny/ask blocks with a structured 403 before any forwarding. */
105
+ private forwardOrBlock;
106
+ /** Resolve a hostname once so `ips`-scoped rules see the real addresses, then decide. */
107
+ private decideWithResolution;
108
+ /** Record a block: counters, recent ring, and the runtime hook (logger + session audit). */
109
+ private recordBlock;
110
+ }
111
+ /**
112
+ * Inject the proxy environment variables for subprocesses and return a
113
+ * disposer restoring every previous value exactly (so updates and
114
+ * uninstalls leave the host environment untouched). `noProxy: 'clear'`
115
+ * empties NO_PROXY so the policy cannot be bypassed through ambient
116
+ * exclusions; `preserve` keeps ambient values.
117
+ *
118
+ * The snapshot pass covers EVERY name BEFORE any write: on Windows
119
+ * `process.env` is case-insensitive, so the uppercase/lowercase spellings
120
+ * share one variable — writing `HTTP_PROXY` mid-loop would otherwise
121
+ * poison the later snapshot of `http_proxy` and make the restore write
122
+ * the proxy address back over the original.
123
+ * @param port - the bound proxy port.
124
+ * @param noProxy - the configured NO_PROXY handling.
125
+ * @returns the restore disposer.
126
+ */
127
+ export declare function injectProxyEnv(port: number, noProxy: 'clear' | 'preserve'): () => void;
128
+ //# sourceMappingURL=proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/proxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The settings-page Remote service: exposes the `permissionRules` Typert
3
+ * namespace (network snapshot + rule-file read/save/reload) to the
4
+ * browser half. All state lives in the {@link PermissionRulesRuntime}
5
+ * this service delegates to; the service itself only bridges the wire
6
+ * vocabulary. The rule editor only ever touches KNOWN rule sources —
7
+ * arbitrary paths are refused by the runtime.
8
+ * @module dsh-permission-rules/remote-service
9
+ */
10
+ import type { Context } from '@deepseek-ai/cordis';
11
+ import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
12
+ import type { PermissionRulesRuntime } from './runtime.js';
13
+ import type { PermissionRulesSnapshot, RulesReadResult, RulesReloadResult, RulesSaveResult } from './wire.js';
14
+ declare module '@deepseek-ai/cordis' {
15
+ interface Context {
16
+ /** Settings-page snapshot + rule-editor bridge (this package). */
17
+ permissionRules: PermissionRulesRemoteService;
18
+ }
19
+ }
20
+ /** Service config: the runtime instance whose state the wire exposes. */
21
+ export interface PermissionRulesRemoteServiceConfig {
22
+ /** The runtime holding the loaded rules, proxy state, and block records. */
23
+ runtime: PermissionRulesRuntime;
24
+ }
25
+ /**
26
+ * The Typert Remote service behind the settings page. Registered through
27
+ * `ctx.plugin(PermissionRulesRemoteService, { runtime })` in
28
+ * {@link apply}; the typert gateway binds its public methods to the
29
+ * invocation descriptors in `./wire.ts`.
30
+ */
31
+ export declare class PermissionRulesRemoteService extends TypertRemoteService {
32
+ private readonly config;
33
+ static inject: string[];
34
+ constructor(ctx: Context, config: PermissionRulesRemoteServiceConfig);
35
+ /** The settings-page snapshot: mode mapping, proxy liveness, counters, recent blocks, editable rule sources. */
36
+ networkStatus(): PermissionRulesSnapshot;
37
+ /** Read one known rule file for the editor. */
38
+ rulesRead(path: string): RulesReadResult;
39
+ /** Validate and write one known rule file; invalid edits are rejected before anything touches disk. */
40
+ rulesSave(path: string, text: string): RulesSaveResult;
41
+ /** Re-read every cached workspace chain (after an external edit). */
42
+ reload(): RulesReloadResult;
43
+ }
44
+ export default PermissionRulesRemoteService;
45
+ //# sourceMappingURL=remote-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-service.d.ts","sourceRoot":"","sources":["../../src/remote-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AACtE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAC1D,OAAO,KAAK,EAAE,uBAAuB,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAE7G,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,kEAAkE;QAClE,eAAe,EAAE,4BAA4B,CAAA;KAC9C;CACF;AAED,yEAAyE;AACzE,MAAM,WAAW,kCAAkC;IACjD,4EAA4E;IAC5E,OAAO,EAAE,sBAAsB,CAAA;CAChC;AAED;;;;;GAKG;AACH,qBAAa,4BAA6B,SAAQ,mBAAmB;IAGzC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFjD,MAAM,CAAC,MAAM,EAAS,MAAM,EAAE,CAAA;gBAElB,GAAG,EAAE,OAAO,EAAmB,MAAM,EAAE,kCAAkC;IAIrF,gHAAgH;IAChH,aAAa,IAAI,uBAAuB;IAiCxC,+CAA+C;IAC/C,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;IAUxC,uGAAuG;IACvG,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe;IAStD,qEAAqE;IACrE,MAAM,IAAI,iBAAiB;CAQ5B;AAED,eAAe,4BAA4B,CAAA"}
@@ -12,6 +12,12 @@ export type RuleAction = 'allow' | 'deny' | 'ask';
12
12
  export type PatternMode = 'glob' | 'regex';
13
13
  /** Closed action list for runtime normalization of untrusted values. */
14
14
  export declare const RULE_ACTIONS: readonly RuleAction[];
15
+ /** URL schemes a network rule may name (the proxy classifies CONNECT tunnels as `https`). */
16
+ export type SchemeName = 'http' | 'https';
17
+ /** Closed scheme list for runtime normalization of untrusted values. */
18
+ export declare const SCHEMES: readonly SchemeName[];
19
+ /** Hostname characters that make a URL candidate parseable as a network target. */
20
+ export declare const URL_CANDIDATE_KEYS: readonly string[];
15
21
  /** Platform names a `when.platform` entry may name (Node `process.platform` values). */
16
22
  export declare const PLATFORMS: readonly string[];
17
23
  /**
@@ -58,6 +64,11 @@ export interface RuleMatchDoc {
58
64
  agents: string[];
59
65
  /** Environment/platform conditions; every listed env key must be present and match. */
60
66
  when: WhenDoc;
67
+ /**
68
+ * Network scope, when this rule is a network rule; absent means the rule
69
+ * never evaluates URL/connection targets.
70
+ */
71
+ network?: NetworkDoc;
61
72
  }
62
73
  /** The parsed `when` conditions. */
63
74
  export interface WhenDoc {
@@ -66,6 +77,40 @@ export interface WhenDoc {
66
77
  /** Platform names; ANY match satisfies the dimension. */
67
78
  platform: string[];
68
79
  }
80
+ /**
81
+ * The parsed network match dimensions; a rule WITHOUT this block has no
82
+ * network scope (it stays a file/command rule exactly as before). A rule
83
+ * WITH this block is a network rule: it matches a tool call only when the
84
+ * call carries a URL candidate satisfying every listed dimension (AND),
85
+ * and it matches proxy-layer connections (shell subprocess traffic)
86
+ * against the connection target.
87
+ */
88
+ export interface NetworkDoc {
89
+ /**
90
+ * Domain patterns (lowercased; a trailing `.` is stripped). A pattern
91
+ * WITHOUT wildcards is subdomain-inclusive — `example.com` also matches
92
+ * `api.example.com` — while `*.example.com` matches subdomains only and
93
+ * `*`/`**` compile as ordinary globs. ANY pattern matching the target
94
+ * host satisfies the dimension.
95
+ */
96
+ domains: string[];
97
+ /**
98
+ * IP patterns: an exact IPv4/IPv6 literal, a glob (e.g. `10.0.*.*`), or
99
+ * an IPv4 CIDR (`10.0.0.0/8`). A literal IP in the URL is always a
100
+ * candidate; the proxy additionally resolves hostnames and tests their
101
+ * addresses, while `tools/pre-execute` matches literal IPs only (no DNS
102
+ * in the hot path). ANY match satisfies the dimension.
103
+ */
104
+ ips: string[];
105
+ /**
106
+ * Port patterns: `*`, one port (`443`), or an inclusive range
107
+ * (`8000-9000`). Evaluated against the effective port (URL port, else
108
+ * 80/443 by scheme). ANY match satisfies the dimension.
109
+ */
110
+ ports: string[];
111
+ /** Schemes; the target scheme must be one of them (ANY). */
112
+ schemes: SchemeName[];
113
+ }
69
114
  /** One compiled rule, ready for the `tools/pre-execute` hot path. */
70
115
  export interface CompiledRule {
71
116
  /** 0-based position in the merged rule chain. */
@@ -91,9 +136,33 @@ export interface CompiledRule {
91
136
  readonly env: ReadonlyMap<string, readonly RegExp[]>;
92
137
  readonly platform: readonly string[];
93
138
  };
139
+ /** Compiled network dimensions, when this rule has network scope. */
140
+ readonly network?: CompiledNetwork;
94
141
  /** The original source strings, kept for the `/rules` display. */
95
142
  readonly source: RuleDocEntry;
96
143
  }
144
+ /** One compiled port pattern: an inclusive range; `max: Infinity` is the `*` catch-all. */
145
+ export interface CompiledPortRange {
146
+ readonly min: number;
147
+ readonly max: number;
148
+ }
149
+ /** One compiled IP pattern: a glob RegExp, an IPv4 CIDR block, or an exact literal (IPv6/odd shapes). */
150
+ export interface CompiledIpPattern {
151
+ readonly regex?: RegExp;
152
+ readonly cidr?: {
153
+ readonly network: number;
154
+ readonly prefix: number;
155
+ };
156
+ readonly literal?: string;
157
+ }
158
+ /** The compiled network dimensions of one rule (absent block = no network scope). */
159
+ export interface CompiledNetwork {
160
+ /** Subdomain-inclusive exact domains and glob domains, all anchored + case-insensitive. */
161
+ readonly domains: readonly RegExp[];
162
+ readonly ips: readonly CompiledIpPattern[];
163
+ readonly ports: readonly CompiledPortRange[];
164
+ readonly schemes: readonly SchemeName[];
165
+ }
97
166
  /** A compiled, size-capped ruleset. */
98
167
  export interface CompiledRuleset {
99
168
  readonly rules: readonly CompiledRule[];
@@ -213,11 +282,20 @@ export interface DescribeTokens {
213
282
  readonly absent: string;
214
283
  readonly when: string;
215
284
  readonly platform: string;
285
+ readonly network: string;
286
+ readonly domains: string;
287
+ readonly ips: string;
288
+ readonly ports: string;
289
+ readonly schemes: string;
216
290
  readonly disabled: string;
217
291
  readonly tags: string;
218
292
  /** Prefix of the per-rule source-file attribution. */
219
293
  readonly src: string;
220
294
  }
295
+ /** Whether a rule's tools dimension selects the tool. */
296
+ export declare function matchTools(rule: CompiledRule, toolName: string): boolean;
297
+ /** Whether a rule's when dimension holds for the host facts. */
298
+ export declare function matchWhen(rule: CompiledRule, context: MatchContext): boolean;
221
299
  /** Top-level argument keys whose string values are path candidates. */
222
300
  export declare const PATH_CANDIDATE_KEYS: readonly string[];
223
301
  /**
@@ -231,6 +309,59 @@ export declare const PATH_CANDIDATE_KEYS: readonly string[];
231
309
  * @returns candidate strings in argument key order (duplicates kept).
232
310
  */
233
311
  export declare function extractPathCandidates(args: Record<string, unknown>): string[];
312
+ /** One parsed network target (a URL candidate or a proxy connection target). */
313
+ export interface NetworkTarget {
314
+ /** `http` or `https`, or undefined for scheme-less host candidates. */
315
+ readonly scheme: SchemeName | undefined;
316
+ /** Lowercased hostname (brackets stripped for IPv6) or literal IP, trailing dot stripped. */
317
+ readonly host: string;
318
+ /** Effective port: URL port, else 80/443 by scheme; undefined for bare hostnames. */
319
+ readonly port: number | undefined;
320
+ /** Literal IP when `host` is one; the proxy appends resolved addresses here. */
321
+ readonly ips: readonly string[];
322
+ }
323
+ /**
324
+ * Whether the tool is a shell tool: its `command` argument is scanned for
325
+ * embedded URLs. Every other tool contributes URL candidates only through
326
+ * {@link URL_CANDIDATE_KEYS}.
327
+ */
328
+ export declare function isShellTool(toolName: string): boolean;
329
+ /**
330
+ * Collect URL-candidate strings from tool arguments: values under the
331
+ * {@link URL_CANDIDATE_KEYS} at ANY nesting depth (capped like path
332
+ * extraction), plus embedded `http(s)://` substrings of command-shaped
333
+ * arguments (shell command text). Deterministic: own key order, duplicates
334
+ * kept.
335
+ * @param args - the parsed tool arguments.
336
+ * @returns raw candidate strings, each already an http(s) URL or a bare host.
337
+ */
338
+ export declare function extractUrlCandidates(args: Record<string, unknown>): string[];
339
+ /**
340
+ * Parse one raw candidate into a {@link NetworkTarget}. Full `http(s)://`
341
+ * URLs parse through WHATWG URL semantics; a bare `host[:port]` candidate
342
+ * (no spaces, no slashes) becomes a scheme-less target (the `scheme` key
343
+ * is present with value `undefined`). Anything else yields `undefined` —
344
+ * a rule simply cannot match a non-target candidate.
345
+ * @param raw - the candidate string.
346
+ * @returns the parsed target, or undefined.
347
+ */
348
+ export declare function parseUrlTarget(raw: string): NetworkTarget | undefined;
349
+ /** Whether a host string is an IP literal (IPv4 or IPv6). */
350
+ export declare function isIpLiteral(host: string): boolean;
351
+ /**
352
+ * Evaluate one target against one compiled network block (pure; shared by
353
+ * the pre-execute path and the proxy layer). Domain patterns are tested
354
+ * against the host string as-is — including literal-IP hosts, so a
355
+ * catch-all glob like `*` matches `127.0.0.1` too (Codex parity keeps
356
+ * loopback reachable only via the `loopback` short-circuit, never by
357
+ * name matching). Literal-IP hosts are tested against `ips` patterns
358
+ * directly; `target.ips` may carry additional resolved addresses
359
+ * supplied by the proxy.
360
+ * @param target - the parsed target.
361
+ * @param network - the compiled network dimensions.
362
+ * @returns true when EVERY listed dimension holds.
363
+ */
364
+ export declare function targetMatchesNetwork(target: NetworkTarget, network: CompiledNetwork): boolean;
234
365
  /**
235
366
  * Normalize one candidate path against the workspace root: separators
236
367
  * become `/`, `./` prefixes drop, and in-root paths become workspace
@@ -1 +1 @@
1
- {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/rules.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/rules.ts"],"names":[],"mappings":"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"}
@@ -13,9 +13,11 @@
13
13
  import type { Context } from '@deepseek-ai/cordis';
14
14
  import type { CommandInvocation, CommandResult } from '@deepseek-ai/dsh-commands';
15
15
  import type { PreToolDecision, ToolExecution } from '@deepseek-ai/dsh-tools';
16
- import type { Config, ResolvedConfig } from './config.ts';
17
- import type { CompiledRuleset, RuleHit } from './rules.ts';
18
- import type { DecisionOutcome } from './events.ts';
16
+ import type { Config, ResolvedConfig } from './config.js';
17
+ import type { CompiledRuleset, RuleHit } from './rules.js';
18
+ import type { NetworkMode } from './network.js';
19
+ import type { NetworkBlockRecord } from './proxy.js';
20
+ import type { DecisionOutcome } from './events.js';
19
21
  export declare const name = "permission-rules";
20
22
  /** Services required before the plugin mounts. */
21
23
  export declare const inject: string[];
@@ -33,11 +35,10 @@ interface LoadedRules {
33
35
  }
34
36
  /**
35
37
  * State and behavior. One instance per plugin mount; disposals are owned by
36
- * the watcher/timer effects registered in {@link apply}.
38
+ * the watcher/timer/proxy effects registered in {@link apply}.
37
39
  */
38
40
  export declare class PermissionRulesRuntime {
39
41
  private readonly ctx;
40
- readonly config: ResolvedConfig;
41
42
  /** Loaded (or failed) rules per workspace cwd, least-recently-used first for eviction. */
42
43
  private readonly byCwd;
43
44
  /** Live watchers per watched path (rule file or candidate ancestor directory), with the cwds each serves. */
@@ -46,7 +47,19 @@ export declare class PermissionRulesRuntime {
46
47
  private readonly timers;
47
48
  /** Whether the host honors the audit envelope's `ignorable` marker: unknown until the first decision (or peer-version check). */
48
49
  private auditSupport;
50
+ /** In-flight bash/pwsh executions (insertion order = start order), for proxy-block attribution. */
51
+ private readonly inFlight;
52
+ /** The network proxy, when the policy is enabled and mounted. */
53
+ private networkProxy;
54
+ /** Restores the injected proxy environment (set after a successful bind). */
55
+ private envRestore;
56
+ /** The authoritative config source: the composition entry, replaced by the settings scope while attached. */
57
+ private configSource;
49
58
  constructor(ctx: Context, config: ResolvedConfig);
59
+ /** The currently authoritative config (settings scope or composition entry). */
60
+ get config(): ResolvedConfig;
61
+ /** Rebind the config source (the settings section hooks call this on attach/detach/change). */
62
+ setConfigSource(source: () => ResolvedConfig): void;
50
63
  /** The shared compile options derived from config. */
51
64
  private compileOptions;
52
65
  /**
@@ -109,16 +122,28 @@ export declare class PermissionRulesRuntime {
109
122
  * The `tools/pre-execute` listener. A deny/ask hit returns the decision
110
123
  * (first match wins, short-circuiting downstream listeners); an allow hit
111
124
  * and a passthrough MUST delegate via `next()` so later listeners keep
112
- * their say. Under `enforce: false` (dry-run) a deny/ask hit also
113
- * delegates — the record keeps the would-be action with `dryRun: true`
114
- * and the actual downstream outcome. Audit is appended once the final
115
- * outcome is known, so the recorded `outcome` matches what the waterfall
116
- * settled on.
125
+ * their say. Network-scoped rule hits on tool calls carry the structured
126
+ * `[network: …]` marker; when NO rule matches a web tool
127
+ * (`web_fetch`/`web_search`) the network mode default applies (deny-all
128
+ * denies, whitelist asks/denies, allow-all passes) — shell tools are
129
+ * NOT gated here, the proxy enforces their traffic per connection.
130
+ * Under `enforce: false` (dry-run) a deny/ask hit also delegates — the
131
+ * record keeps the would-be action with `dryRun: true` and the actual
132
+ * downstream outcome. Audit is appended once the final outcome is
133
+ * known, so the recorded `outcome` matches what the waterfall settled
134
+ * on.
117
135
  * @param exec - the pending call (name, parsed arguments, caller agent).
118
136
  * @param next - the downstream chain.
119
137
  * @returns the pre-execute decision.
120
138
  */
121
139
  preExecute(exec: ToolExecution, next: () => Promise<PreToolDecision>): Promise<PreToolDecision>;
140
+ /**
141
+ * The mode-default decision for an unlisted web-tool call, or undefined
142
+ * when the policy is disabled, the tool is not a web tool, or the mode
143
+ * allows. Shell tools always yield undefined here (the proxy decides
144
+ * their traffic per connection).
145
+ */
146
+ private webToolFallback;
122
147
  /**
123
148
  * Append the log-only `permissionRules/decision` audit event for every
124
149
  * decision (passthrough included unless `audit: 'hits'`), requesting the
@@ -131,18 +156,120 @@ export declare class PermissionRulesRuntime {
131
156
  * `allowUnmarkedAudit: true` opts back in. `source` names the matched
132
157
  * rule's file, or the nearest effective file on a passthrough; `cwd`
133
158
  * names the workspace the rules were resolved for; `dryRun` marks
134
- * would-be deny/ask hits under `enforce: false`. Agentless calls have no
135
- * session to audit; append failures are contained so an audit hiccup can
136
- * never change a permission decision.
159
+ * would-be deny/ask hits under `enforce: false`; `modeDefault` records a
160
+ * network mode-default decision on a web tool (no rule fired).
161
+ * Agentless calls have no session to audit; append failures are
162
+ * contained so an audit hiccup can never change a permission decision.
137
163
  * @param exec - the pending call.
138
164
  * @param loaded - the rules in effect.
139
165
  * @param hit - the first matching rule, or undefined for passthrough.
140
166
  * @param outcome - the final pre-execute decision.
141
167
  * @param dryRun - mark the record as a would-be decision (dry-run mode).
168
+ * @param modeDefault - the network mode-default action when no rule fired.
142
169
  */
143
- audit(exec: ToolExecution, loaded: LoadedRules, hit: RuleHit | undefined, outcome: DecisionOutcome, dryRun?: boolean): void;
170
+ audit(exec: ToolExecution, loaded: LoadedRules, hit: RuleHit | undefined, outcome: DecisionOutcome, dryRun?: boolean, modeDefault?: 'deny' | 'ask'): void;
171
+ /** After the first append, probe the returned envelope for the ignorable marker (host capability detection). */
172
+ private probeAuditResult;
144
173
  /** Append one audit event through the session surface; the probe seam for host-capability detection. */
145
174
  private appendAudit;
175
+ /**
176
+ * Resolve the network policy mode. An explicit config mode wins; `auto`
177
+ * maps the official sandbox preset (`read-only` → deny-all,
178
+ * `workspace-write` → whitelist, `danger-full-access` → allow-all) with
179
+ * `network.autoFallback` covering hosts without the sandbox-policy
180
+ * service (rc.6 and friends stay permissive until configured). For web
181
+ * tools the SESSION's resolved mode is used; the proxy resolves without
182
+ * a session (its connections carry no session context).
183
+ * @param session - optional session whose override outranks the default.
184
+ * @returns the resolved mode plus the sandbox preset it came from.
185
+ */
186
+ resolveNetworkMode(session?: {
187
+ events?: unknown;
188
+ }): {
189
+ mode: NetworkMode;
190
+ sandboxMode: string | undefined;
191
+ };
192
+ /**
193
+ * The proxy-layer decision for one connection target: first-match
194
+ * network rules across every loaded workspace chain (insertion order),
195
+ * then the mode default. Shell subprocess traffic counts as `bash`/
196
+ * `pwsh` tool candidates; loopback handling follows config.
197
+ */
198
+ private decideProxyTarget;
199
+ /** The loaded rule chains in cache order, nearest workspace first. */
200
+ private proxyChains;
201
+ /** Mark one delegated shell execution as in-flight (newest attribution wins). */
202
+ private markShell;
203
+ /** Drop one shell execution when it settles. */
204
+ unmarkShell(exec: ToolExecution): void;
205
+ /** The newest in-flight shell execution within the TTL, or undefined (best-effort attribution). */
206
+ private proxyAttribution;
207
+ /**
208
+ * Audit one proxy-layer block: the in-memory record is always kept
209
+ * (settings page), the logger always warns, and when the block can be
210
+ * attributed to an agent the `permissionRules/network` event is appended
211
+ * with the same ignorable-marker discipline as the decision audit.
212
+ */
213
+ private auditNetworkBlock;
214
+ /**
215
+ * Mount the network proxy and the subprocess environment injection.
216
+ * Called from {@link apply}; the proxy binds an ephemeral (or
217
+ * configured) loopback port, the env injection only happens after a
218
+ * successful bind, and every side effect is owned by an effect
219
+ * disposer. A bind failure degrades loudly (file rules stay active,
220
+ * the settings page and `/rules network` show the inactive proxy)
221
+ * instead of taking the permission plugin down.
222
+ */
223
+ attachNetworkProxy(): Promise<void>;
224
+ /**
225
+ * Apply a live settings change to the network policy: rebind the proxy
226
+ * when a bind/env-relevant knob changed (old proxy closed, old env
227
+ * restored, new proxy + env installed). Web-tool gating and the decision
228
+ * path read the config per call, so they need no rebind.
229
+ */
230
+ onNetworkConfigChanged(): Promise<void>;
231
+ /** The network snapshot the settings page and `/rules network` render. */
232
+ networkSnapshot(): {
233
+ readonly enabled: boolean;
234
+ readonly mode: NetworkMode;
235
+ readonly configuredMode: 'auto' | NetworkMode;
236
+ readonly sandboxMode: string | undefined;
237
+ readonly proxyPort: number;
238
+ readonly proxyActive: boolean;
239
+ readonly denied: number;
240
+ readonly askBlocked: number;
241
+ readonly recent: readonly NetworkBlockRecord[];
242
+ };
243
+ /**
244
+ * The rule-file paths the settings-page editor may read or write: every
245
+ * currently loaded source plus the per-workspace project files and the
246
+ * configured fallback (so a not-yet-existing project file can be
247
+ * created). The editor never touches arbitrary paths.
248
+ */
249
+ knownRuleSources(): readonly string[];
250
+ /** Read one known rule file for the editor: `{ exists, text, error }`. */
251
+ readRuleFile(path: string): {
252
+ path: string;
253
+ exists: boolean;
254
+ text: string;
255
+ error?: string;
256
+ };
257
+ /** The workspace a rule source belongs to (for the editor's file list), or undefined for the fallback. */
258
+ sourceOwner(path: string): string | undefined;
259
+ /** Re-read every cached workspace chain (the settings-page reload action). */
260
+ reloadAll(): void;
261
+ /**
262
+ * Validate and write one known rule file. The document must parse and
263
+ * compile (same checks as a load) BEFORE anything is written — an
264
+ * invalid edit is rejected with its error and the file stays untouched.
265
+ * After a successful write every cached workspace reloads so the edit
266
+ * is in effect immediately.
267
+ */
268
+ saveRuleFile(path: string, text: string): {
269
+ ok: boolean;
270
+ error?: string;
271
+ reloaded?: number;
272
+ };
146
273
  /** The installed `@deepseek-ai/dsh-session` version, or `null` when unresolvable (falls back to the append probe). */
147
274
  private peerVersion;
148
275
  /** One-time warning that session-log audit was disabled to keep session logs loadable. */
@@ -179,6 +306,8 @@ export declare class PermissionRulesRuntime {
179
306
  private displaySource;
180
307
  /** Render the session's `permissionRules/decision` audit trail, newest last. */
181
308
  private decisionsCommand;
309
+ /** Render the network policy state: mode mapping, proxy liveness, counters, recent blocks. */
310
+ private networkCommand;
182
311
  /**
183
312
  * Validate deployment-level file references at mount — the earliest
184
313
  * resolvable point. An absolute `rulesFile` or a configured
@@ -249,16 +378,19 @@ export declare class PermissionRulesRuntime {
249
378
  * @param ctx - the host context.
250
379
  * @param config - raw plugin config.
251
380
  */
252
- export declare function apply(ctx: Context, config: Config): void;
381
+ export declare function apply(ctx: Context, config: Config): Promise<void>;
253
382
  /**
254
383
  * Whether a `@deepseek-ai/dsh-session` version line predates the
255
- * `ignorable` envelope-marker surface: the `0.1.0-rc.6` line and earlier
256
- * silently drop the marker from `Session.append` options, so audit events
257
- * written by those builds land unmarked and break resume on stricter
258
- * hosts. Non-matching (post-rc.6, stable, or unresolvable) versions are
259
- * treated as possibly-marker-aware and verified by the append probe.
384
+ * `ignorable` envelope-marker surface: every released rc line through
385
+ * `0.1.0-rc.7` silently drops the marker from `Session.append` options
386
+ * (the stamping fix exists on harness master only — no release carries it
387
+ * yet), so audit events written by those builds land unmarked and break
388
+ * resume on stricter hosts. Extend the bound when a new rc line ships that
389
+ * still drops the marker. Non-matching (later rc, stable, or unresolvable)
390
+ * versions are treated as possibly-marker-aware and verified by the
391
+ * append probe.
260
392
  * @param version - the installed peer version string.
261
- * @returns true for the known-unmarked rc.1–rc.6 lines.
393
+ * @returns true for the known-unmarked rc.1–rc.7 lines.
262
394
  */
263
395
  export declare function isUnmarkedHostVersion(version: string): boolean;
264
396
  export {};