{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/PerryLink/dsh-permission-rules/main/docs/rules-format.schema.json", "title": "dsh-permission-rules rule file", "description": "Declarative allow/deny/ask permission rules for DeepSeek Harness, evaluated in file order with first-match-wins semantics.", "type": "object", "additionalProperties": false, "properties": { "rules": { "description": "The ordered rule list; omitted or empty means an empty rule set (everything passes through).", "type": "array", "items": { "$ref": "#/$defs/rule" } } }, "$defs": { "rule": { "type": "object", "additionalProperties": false, "required": ["action", "reason"], "properties": { "match": { "$ref": "#/$defs/match" }, "action": { "description": "What the rule does to a matching tool call.", "enum": ["allow", "deny", "ask"] }, "reason": { "description": "Non-empty explanation; deny/ask reasons become model-visible tool results or approval reasons.", "type": "string", "minLength": 1 }, "enabled": { "description": "false keeps the rule visible but inert (displayed as disabled).", "type": "boolean" }, "description": { "description": "Optional one-line explanation shown by /rules.", "type": "string", "minLength": 1 }, "tags": { "description": "Free-form labels shown by /rules.", "type": "array", "items": { "type": "string", "minLength": 1 } } } }, "match": { "description": "Match dimensions combined with AND; absent dimensions impose no restriction.", "type": "object", "additionalProperties": false, "properties": { "tools": { "description": "Tool-name globs (always glob semantics, regardless of patternMode).", "type": "array", "items": { "type": "string", "minLength": 1 } }, "agents": { "description": "Agent-identity selector globs (main, subagent, preset:); any selector matching any candidate satisfies the dimension. Unknown identity never matches.", "type": "array", "items": { "type": "string", "minLength": 1 } }, "params": { "description": "Param key to pattern(s). EVERY key must be present and match; a !-prefixed pattern negates. Scalars are stringified; arrays and nested objects contribute their scalar leaves.", "type": "object", "additionalProperties": { "oneOf": [ { "$ref": "#/$defs/pattern" }, { "type": "array", "items": { "$ref": "#/$defs/pattern" }, "minItems": 1 } ] } }, "paths": { "description": "Workspace-relative path patterns; ANY candidate path matching ANY pattern satisfies the dimension. Candidates come from documented argument keys at any nesting depth.", "type": "array", "items": { "type": "string", "minLength": 1 } }, "absent": { "description": "Argument keys that must be ABSENT; every listed key must be missing.", "type": "array", "items": { "type": "string", "minLength": 1 } }, "when": { "description": "Host conditions: every listed env var must be present and match; any listed platform matches.", "type": "object", "additionalProperties": false, "properties": { "env": { "type": "object", "additionalProperties": { "oneOf": [ { "$ref": "#/$defs/pattern" }, { "type": "array", "items": { "$ref": "#/$defs/pattern" }, "minItems": 1 } ] } }, "platform": { "type": "array", "items": { "enum": ["aix", "android", "darwin", "freebsd", "linux", "openbsd", "sunos", "win32"] } } } }, "argv": { "description": "Shell command decomposition scope: the call must carry a command-string argument whose lexical decomposition (command words, argument tokens, redirect targets, pipeline signature) satisfies every listed field. command/pipeline are globs; args/anyArg follow patternMode. args requires EVERY pattern to match some token; anyArg requires SOME token to match a pattern; a !-prefixed args/anyArg pattern negates. A block must name at least one field.", "type": "object", "additionalProperties": false, "properties": { "command": { "description": "Command-word globs; ANY simple-command word matching ANY pattern satisfies the field.", "type": "array", "items": { "type": "string", "minLength": 1 } }, "args": { "description": "Argument-token patterns; EVERY pattern must match at least one token; a !-prefixed pattern negates.", "type": "array", "items": { "$ref": "#/$defs/pattern" }, "minItems": 1 }, "anyArg": { "description": "Argument-token patterns; ANY token matching ANY pattern satisfies the field; a !-prefixed pattern negates.", "type": "array", "items": { "$ref": "#/$defs/pattern" }, "minItems": 1 }, "pipeline": { "description": "Pipeline-signature globs matched against the command words joined by `|` (e.g. curl|sh); ANY pattern matching satisfies the field.", "type": "array", "items": { "type": "string", "minLength": 1 } } } }, "network": { "description": "Network scope (a network rule): the call must carry a URL candidate (a web-tool URL argument, or a URL embedded in bash/pwsh command text) — or, at the proxy layer, a connection target — satisfying every listed dimension. domains are subdomain-inclusive unless wildcarded; ips accept IPv4/IPv6 literals, globs, and IPv4 CIDRs; ports accept \"*\", one port, or an inclusive low-high range (numeric YAML ports accepted); schemes are http/https. A network block must name at least one dimension.", "type": "object", "additionalProperties": false, "properties": { "domains": { "description": "Domain patterns; ANY matching the target host satisfies the dimension.", "type": "array", "items": { "type": "string", "minLength": 1 } }, "ips": { "description": "IP literals, globs, or IPv4 CIDRs; an IPv4-mapped IPv6 literal (::ffff:169.254.169.254, ::ffff:a9fe:a9fe) is unmapped to its dotted IPv4 form before matching, and a mapped pattern also covers the plain IPv4 spelling; ANY matching the target address satisfies the dimension.", "type": "array", "items": { "type": "string", "minLength": 1 } }, "ports": { "description": "\"*\", one port, or an inclusive low-high range; ANY matching the effective port satisfies the dimension.", "type": "array", "items": { "oneOf": [ { "type": "string", "minLength": 1 }, { "type": "integer", "minimum": 0, "maximum": 65535 } ] } }, "schemes": { "description": "Target scheme must be one of these.", "type": "array", "items": { "enum": ["http", "https"] } } } } } }, "pattern": { "oneOf": [ { "type": "string", "minLength": 1 }, { "type": "number" }, { "type": "boolean" } ] } } }