Skip to main content

dsh-permission-rules

25Stars2Forks2Issues0Watchers

Place a YAML rule gate before DSH tool calls, generating allow/deny/ask decisions based on tool name/parameters/path/agent/network target; control local agent outbound traffic with full read-only audit.

Evidence5/5methodologySourceInstallMaintenanceDSH versionSecurity scan
Machine-auditedInstall commandRepo verifieddsh-plugin topicLicenseREADMEAI wiki
Language
TypeScript
License
Apache-2.0
Branch
main
ai-safetyallow-deny-askapprovalcordisdeepseekdeepseek-harnessdshdsh-plugin

Install

cmdweb profile
$ dsh plugin --profile web add dsh-permission-rules

Run the command above in your terminal to install this plugin via the dsh CLI. You can switch Profile in the top-right corner. New to dsh? Read the beginner tutorial

Install via your agent

Install the DeepSeek Harness plugin PerryLink/dsh-permission-rules for me: review the repository at https://github.com/PerryLink/dsh-permission-rules first, then run the install command and verify the plugin loads successfully.

Paste this instruction to the DSH Web GUI assistant — it will install and verify for you.

One-Line Description

Place a YAML-written allow/deny/ask gate before each tool call in DeepSeek Harness, matching by tool name, parameters, paths, Agent identity, and network targets; overlay a local HTTP/CONNECT proxy to uniformly control subprocess outbound network, all hits write read-only audit logs, but the model cannot see them and is not disturbed by side effects other than blocking.

Core Capabilities

  • Ordered Rule Chain: Each tool call is evaluated using a "first match wins" approach in file order, with matched rules producing one of three actions: allow/deny/ask; deny/ask truncate subsequent rules, while allow and no-match strictly next() pass through without ever blocking downstream.
  • Rich Matching Dimensions: Tool name glob (supports mcp__*), Agent identity selectors (main/subagent/preset:<name>, unknown identity never matches—fail-safe fallback), parameter key-value glob or regex (including !pattern negation and absent missing dimension), workspace-relative paths with arbitrary nesting, when host conditions (environment variables + platform allowlist).
  • Process-Level Network Policy: Built-in local HTTP/CONNECT proxy uniformly controls shell subprocess outbound network; rules can use match.network with domains/ips/ports/schemes (glob, wildcard, CIDR, port range) for target matching; three network modes automatically follow official sandbox presets (readonly→deny-all, workspace-write→whitelist, danger-full-access→allow-all).
  • Hot Reload with Hierarchical Files: Chokidar watches rule file changes with debounce; broken edits preserve old rules without crashing; optional searchUp merges parent directory .dsh/rules.yaml together (closer takes precedence).
  • Complete Read-Only Audit: Every hit and every pass writes permissionRules/decision session event (with ignorable flag), proxy intercepts also write permissionRules/network; logs don't enter model context, only for post-hoc traceback.
  • Visual Settings Panel: Web profile adds a "Permission Rules" settings page showing network mode summary, intercept count, recent intercept list and rule editor, all data fetched via Typert remote API.

Technical Implementation

  • Language: TypeScript (ESM, strict mode; client React 18)
  • Key Dependencies: @deepseek-ai/cordis + @deepseek-ai/schemastery (plugin loading & Config validation), chokidar (rule file watching), yaml (rule file parsing), react (Web settings panel)
  • Architecture Pattern: Functional cordis plugin (name/inject/Config/apply, no default export); apply registers tools/pre-execute listener, /rules command, settings section, local proxy; Web half-package communicates with host via Typert remote API. Rule matching is pure function (no I/O, replayable, unit-testable).
  • Entry Files: src/index.ts (host entry), src/client/index.ts (Web settings panel entry), src/runtime.ts (core assembly & apply), cordis.patch.yml (profile bundle patch)

Use Cases

Suitable for projects that need to add "allowlist/blocklist/graylist" to AI Agent tool calls: for example, protecting secrets/ and .env from arbitrary editing, restricting network outbound to only hit trusted APIs, requiring sensitive operations to go through secondary approval. Typical users are individuals or teams who want to add an auditable, hot-reloadable, traceable rule source security fence to a session or entire organization using pure YAML config files without writing code.

Prerequisites & Compatibility

DependencyMinimum VersionDescription
DeepSeek Harness>=0.1.0-rc.8 <0.2.0All dsh-* peerDependencies and devDependencies locked to rc.8; workshop manifest declares compatibility with rc.5/rc.7/rc.8; starting from rc.8 Session.append will cover ignorable flag
Node.js^22.19.0 || >=24.0.0Enforced by package.json#engines.node
PlatformCross-platformHost side pure JS (no native modules); Web settings panel runs in browser (web profile); caseInsensitivePaths defaults to on on Windows
Native ModulesNoneNo dependency on node-pty/node:sqlite etc.

Installation

dsh plugin --profile web add github:PerryLink/dsh-permission-rules

Configuration Options

ConfigTypeDescriptionDefault
rulesFilestringRule file location, relative paths resolved against session cwd, absolute paths globally effective.dsh/rules.yaml
fallbackPathstringFallback file when rules not found in workspace, absolute or relative to process.cwd()Not set
badFilePolicyenumAction when rule file parsing/compilation fails: fail makes current call error directly; ignore-with-warning warns and continues with empty rulesfail
maxRulesintegerMaximum number of rules in entire effective chain, load fails if exceeded256
maxCachedWorkspacesintegerNumber of cached workspace rule loads (LRU eviction)512
patternModeenumMatching syntax for params/paths/when.env: glob or regexglob
watchbooleanWhether to watch rule file changes and auto-reloadtrue
watchStabilityThresholdMsintegerWatch reload debounce window (milliseconds)200
languageenum/rules command output language: en/zh/es/pt/hien
caseInsensitivePathsbooleanWhether paths vs workspace root comparison ignores ASCII caseAutomatically true on Windows
auditenumAudit granularity: all records hits and passes; hits only records hitsall
searchUpbooleanWhether to traverse parent directories merging all .dsh/rules.yaml (closer takes precedence)false
maxGlobStarsintegerUpper limit on unbounded */** quantity in single glob (backtracking degree protection)2
enforcebooleanWhether to actually block: false enters dry-run, all hits only write audit without blockingtrue
allowUnmarkedAuditbooleanStill write audit on old hosts that don't recognize ignorable flag (defaults to not writing to keep session recoverable)false
network.enabledbooleanNetwork policy master switch, controls proxy, subprocess env var injection, and Web tool mode defaulttrue
network.modeenumNetwork policy mode: auto follows sandbox preset, or fixed deny-all/whitelist/allow-allauto
network.autoFallbackenumFallback mode used by auto when sandbox service not foundallow-all
network.unlistedenumHandling of unmatched targets in whitelist mode: ask (default) or denyask
network.proxyBindstringLocal proxy bind address (loopback only, not publicly listening)127.0.0.1
network.proxyPortintegerLocal proxy port; 0 means auto-allocate free ephemeral port0
network.proxyMaxRecentintegerNumber of entries retained in settings page "Recent Intercepts" list100
network.loopbackenumLoopback target handling: allow (consistent with Codex, defaults to allowing local dev services) or policy (evaluated by rules)allow
network.injectEnvbooleanWhether to inject HTTP_PROXY etc. proxy environment variables for subprocessestrue
network.noProxyenumSubprocess NO_PROXY handling: clear forces policy, preserve keeps originalclear

FAQ

Q: Rules not effective after installation?

A: Installing only mounts the plugin to the profile; you must restart the profile for id: permission-rules line to appear; then you also need a .dsh/rules.yaml in your working directory (or configure a fallback file via fallbackPath), having no rules equals "allow all".

Q: Is it a replacement or complement to dsh-auto-review?

A: Complementary. This plugin produces ask going through approval channel, dsh-auto-review attaches a second AI model for judgment on the approval channel; when only this plugin is installed, ask goes through human or host default behavior, only when both are installed does it form a closed loop of "rule filtering + model review".

Q: How to observe if new policy will accidentally block legitimate calls?

A: In cordis.yml temporarily set enforce to false to enter dry-run: all deny/ask hits only write audit logs with dryRun flag, don't block calls, events flow normally to downstream; after observation switch back to true.

Q: What happens with malformed YAML?

A: With default badFilePolicy: 'fail', the tool call waiting to execute errors directly; in HMR reload scenarios, the last successfully loaded rules are preserved, never crash; to be more forgiving, change to ignore-with-warning to warn and continue with empty rules.

Q: How does network policy work by default? How to change?

A: Default is network.enabled: true and network.mode: 'auto', following official sandbox presets (readonly→deny-all, workspace-write→whitelist, danger-full-access→allow-all), falls back to autoFallback when host has no sandbox service (default allow-all). To fix it, explicitly set mode to one of deny-all/whitelist/allow-all.

Q: Why can't I see audit events on old hosts?

A: Host 0.1.0-rc.6 and earlier discard the ignorable flag, causing audit events without the flag and breaking session recovery on new hosts. The plugin actively downgrades to not write session log audit and prints a one-time warning; to keep audit, set allowUnmarkedAudit: true, but old logs may need running scripts/repair-session-logs.mjs repair.

Q: How to view currently effective rules and recent decisions?

A: Run /rules in session to list all rules and source files, /rules reload to force-reload current workspace rule chain, /rules decisions [n] to see last n decisions in this session (default 10), /rules test <tool> <json> can dry-run rule matching without actually triggering tool call.

Q: How to uninstall?

A: One line dsh plugin --profile web remove dsh-permission-rules does it, transactional uninstall, doesn't affect other plugins or session state outside the profile.

Learning Curve

Beginner — configuration is primarily pure YAML, placing config file in workspace root takes effect immediately; refer back to docs when encountering complex matching dimensions (agent selector, CIDR, backtracking protection).

Known Issues & Limitations

  • Audit downgrade on old hosts: Session.append in 0.1.0-rc.1–0.1.0-rc.7 series doesn't recognize ignorable flag, plugin actively downgrades to not write session log audit and prints one-time warning; to keep audit set allowUnmarkedAudit: true, and accept that old sessions may need scripts/repair-session-logs.mjs repair on new host.
  • Path candidates are heuristic: Only document-listed parameter keys (url/path/file_path etc.) participate in path matching, and only match workspace-relative paths; non-convention keys and references outside absolute paths won't be covered by rules.
  • Glob is a conservative subset: No brace expansion support, need to write two rules or switch to regex mode; maxGlobStars (default 2) rejects globs with too many unbounded stars to prevent backtracking.
  • Regex backtracking protection is structural not exhaustive: Can block common disaster patterns (nested unbounded quantifiers, overlapping quantified literals), but not complete ReDoS detection, untrusted files should stay in glob mode.
  • Proxy layer ask cannot enter interactive approval channel: Local proxy has no session context, when encountering targets requiring approval can only intercept with structured message and write permissionRules/network audit, model sees reason via shell tool error output; only Web tool ask goes through real interactive approval.

Read the usage guide →

Install steps, key points, FAQ and compatibility for this plugin — auto-derived from indexed fields.

Listing badge

Listed on deepseek-plugin.org
[![Listed on deepseek-plugin.org](https://img.shields.io/badge/listed_on-deepseek--plugin.org-007EC6)](https://deepseek-plugin.org/plugins/PerryLink/dsh-permission-rules)

Paste this markdown into your GitHub README to link back to this listing. The badge only states the listing — not a security endorsement.

← Back to plugin directory