sigild 0.0.2 → 0.0.3

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 (40) hide show
  1. package/README.md +40 -4
  2. package/THREAT_MODEL.md +18 -7
  3. package/dist/src/bin/sigil-mcp.js +4 -1
  4. package/dist/src/bin/sigil-mcp.js.map +1 -1
  5. package/dist/src/cli/main.d.ts.map +1 -1
  6. package/dist/src/cli/main.js +47 -2
  7. package/dist/src/cli/main.js.map +1 -1
  8. package/dist/src/cli/paths.d.ts +1 -0
  9. package/dist/src/cli/paths.d.ts.map +1 -1
  10. package/dist/src/cli/paths.js +1 -0
  11. package/dist/src/cli/paths.js.map +1 -1
  12. package/dist/src/cli/portal.d.ts +9 -0
  13. package/dist/src/cli/portal.d.ts.map +1 -1
  14. package/dist/src/cli/portal.js +24 -5
  15. package/dist/src/cli/portal.js.map +1 -1
  16. package/dist/src/daemon/methods.d.ts +7 -0
  17. package/dist/src/daemon/methods.d.ts.map +1 -1
  18. package/dist/src/daemon/methods.js +37 -0
  19. package/dist/src/daemon/methods.js.map +1 -1
  20. package/dist/src/policy/evaluate.d.ts +13 -0
  21. package/dist/src/policy/evaluate.d.ts.map +1 -0
  22. package/dist/src/policy/evaluate.js +73 -0
  23. package/dist/src/policy/evaluate.js.map +1 -0
  24. package/dist/src/policy/index.d.ts +5 -0
  25. package/dist/src/policy/index.d.ts.map +1 -0
  26. package/dist/src/policy/index.js +5 -0
  27. package/dist/src/policy/index.js.map +1 -0
  28. package/dist/src/policy/loader.d.ts +33 -0
  29. package/dist/src/policy/loader.d.ts.map +1 -0
  30. package/dist/src/policy/loader.js +170 -0
  31. package/dist/src/policy/loader.js.map +1 -0
  32. package/dist/src/policy/template.d.ts +10 -0
  33. package/dist/src/policy/template.d.ts.map +1 -0
  34. package/dist/src/policy/template.js +69 -0
  35. package/dist/src/policy/template.js.map +1 -0
  36. package/dist/src/policy/types.d.ts +62 -0
  37. package/dist/src/policy/types.d.ts.map +1 -0
  38. package/dist/src/policy/types.js +10 -0
  39. package/dist/src/policy/types.js.map +1 -0
  40. package/package.json +2 -1
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  `sigil` is a local signing tool and Claude Code integration that lets agentic coding tools use private keys without ever putting key material in the model's context window.
6
6
 
7
- **Status:** pre-alpha (v0.0.1 published as a name-stake placeholder). The MCP server, CLI, unlock flow, and ward hooks all work end-to-end. The policy engine and out-of-band confirmation gate are not yet implemented; until they land, sigil signs anything the agent asks once the keys are unlocked. **Do not use this with real funds yet.** Build plan lives in the [tracking issue](https://github.com/cdrn/sigil/issues/9).
7
+ **Status:** pre-alpha. The MCP server, CLI, unlock flow, ward hooks, and policy engine (static checks) all work end-to-end. Out-of-band confirmation, rolling-window value caps, and EIP-712 domain allowlists are not yet implemented. Until they land and until the supply-chain attestations promised for v0.1.0 ship **do not use this with real funds yet.** Build plan lives in the [tracking issue](https://github.com/cdrn/sigil/issues/9).
8
8
 
9
9
  ## What it is
10
10
 
@@ -22,7 +22,7 @@ Sign methods exposed today: EIP-191 personal_sign, EIP-1559 + legacy transaction
22
22
 
23
23
  - Not a hardware wallet replacement. If you can use a Ledger or YubiKey, do that.
24
24
  - Not a custody solution. It runs on your laptop or VPS and protects you from one specific class of failure: leaking key material through an LLM agent.
25
- - Not yet a substitute for policy. The library prevents *ingestion* of keys; the policy engine (issue [#3](https://github.com/cdrn/sigil/issues/3)) will prevent *misuse* of signing authority. Both matter see the threat model.
25
+ - A first cut of *bounding signing authority* via the policy engine — but not the full thing. v1 covers static checks (chain ID, destination allowlist, per-tx value cap, function-selector allowlist, on/off toggles for personal_sign and EIP-712). Rolling-window caps, EIP-712 domain allowlists, and out-of-band human confirmation are tracked in [#3](https://github.com/cdrn/sigil/issues/3) + [#4](https://github.com/cdrn/sigil/issues/4) and will land incrementally.
26
26
 
27
27
  ## Install
28
28
 
@@ -43,7 +43,12 @@ sigil init
43
43
  # 2. Encrypt a private key into sigil's keystore. Source key is deleted by default.
44
44
  # Accepts either 32 raw bytes or 64 hex chars (with optional 0x prefix).
45
45
  sigil portal add eth:bot --key-file ./bot.key
46
- # → prompts for a passphrase, derives the address, writes ~/.sigil/keys/eth:bot.sigil
46
+ # → prompts for a passphrase, derives the address, writes
47
+ # ~/.sigil/keys/eth:bot.sigil AND ~/.sigil/policy/eth:bot.toml (permissive)
48
+ #
49
+ # Pass --strict to start with a locked-down policy template you fill in
50
+ # before any sign succeeds:
51
+ # sigil portal add eth:bot --key-file ./bot.key --strict
47
52
 
48
53
  # 3. Open Claude Code. It spawns sigil-mcp automatically via your MCP config.
49
54
  # sigil-mcp boots locked — the first sign attempt will return DAEMON_LOCKED.
@@ -68,11 +73,18 @@ sigil init [--user]
68
73
  .claude/settings.json. With --user, writes ~/.claude/settings.json
69
74
  instead. Idempotent — preserves your unrelated settings.
70
75
 
71
- sigil portal add <handle> --key-file <path> [--no-remove-source]
76
+ sigil portal add <handle> --key-file <path> [--no-remove-source] [--strict]
72
77
  Encrypt the key with your passphrase and store it at
73
78
  ~/.sigil/keys/<handle>.sigil (mode 0600). Handle format is
74
79
  <kind>:<name> where kind is "eth". The source key file is deleted
75
80
  by default — pass --no-remove-source to keep it.
81
+ Also writes ~/.sigil/policy/<handle>.toml — permissive by default
82
+ (signs anything), or use --strict for a locked-down template you
83
+ fill in before signs succeed.
84
+
85
+ sigil policy show <handle>
86
+ Print the current policy file for a portal. Validates schema; exits
87
+ 1 if the file is missing or malformed.
76
88
 
77
89
  sigil portal list
78
90
  List the encrypted keyfiles on disk with their derived addresses.
@@ -105,6 +117,30 @@ Each Claude Code window spawns its own `sigil-mcp`. They share the on-disk keyfi
105
117
 
106
118
  OS-keychain integration (planned, v0.3) will make unlock zero-touch for users who set it up.
107
119
 
120
+ ## Policy engine
121
+
122
+ Once a portal is unlocked, signing authority over its key is real. To bound the blast radius of a successful prompt injection, every portal has a policy file at `~/.sigil/policy/<handle>.toml`. Two modes:
123
+
124
+ **Permissive** (default for `sigil portal add`): no rules. Sign anything the agent asks. The key isolation guarantees still hold — your key never enters the agent's context — but the unlocked portal can be made to sign whatever an attacker can get the agent to ask for. Useful for: testnet bots, demo flows, anyone who only cares about the context-window protection.
125
+
126
+ **Strict** (opt in with `--strict`): every sign request is checked. Generated template:
127
+
128
+ ```toml
129
+ mode = "strict"
130
+
131
+ chain_ids = [1] # allowed chain IDs
132
+ allow_to = [] # allowed destination addresses (lowercase 0x)
133
+ max_value_wei = "0" # per-tx cap, in wei, as decimal string
134
+ allowed_selectors = [] # 4-byte function selectors, e.g. "0xa9059cbb"
135
+
136
+ allow_message_signing = false # EIP-191 personal_sign (e.g. SIWE)
137
+ allow_typed_data = false # EIP-712 (Permit, OpenSea — can be financial)
138
+ ```
139
+
140
+ A failed rule throws `POLICY_DENIED` (-32001) back to the agent with the human-readable reason ("tx denied — value X exceeds max_value_wei Y"), and the deny is appended to the hash-chained audit log alongside allows. Denies are forensically the more interesting half — they're the prompt-injection canary.
141
+
142
+ What's deferred to follow-up PRs (still in [#3](https://github.com/cdrn/sigil/issues/3)): rolling-window value caps (e.g. 1 ETH/day per portal), EIP-712 domain + primary-type allowlists, decoded-calldata arg checks, and the `require_confirm_above_wei` outcome that hooks into the OOB push gate ([#4](https://github.com/cdrn/sigil/issues/4)).
143
+
108
144
  ## Supply chain posture
109
145
 
110
146
  Key-management libraries die from supply chain compromise, not from clever attacks on the code. Given the npm ecosystem in 2026 (Mini Shai-Hulud, Axios, pgserve, TanStack), `sigil` commits to:
package/THREAT_MODEL.md CHANGED
@@ -48,13 +48,24 @@ Defenses:
48
48
 
49
49
  A defended key still loses you money if the agent can be tricked into signing the wrong payload. Prompt injection through transaction calldata, web content, or repo files can redirect signing intent.
50
50
 
51
- Defenses (policy engine, per portal planned, issue [#3](https://github.com/cdrn/sigil/issues/3)):
52
- - Destination allowlists (`allow_to`)
53
- - Per-tx and rolling-window value caps
54
- - Allowed function selectors (only `transfer`, `approve`, etc.)
55
- - Chain ID allowlists
56
- - Out-of-band human confirmation above a configurable value threshold (push to ntfy / Pushover / Telegram / Apple Push), issue [#4](https://github.com/cdrn/sigil/issues/4)
57
- - Append-only audit log with monotonic counter (already implemented)
51
+ The policy engine (per-portal `~/.sigil/policy/<handle>.toml`) is the layer that bounds this. v1 ships static checks; further work is staged in [#3](https://github.com/cdrn/sigil/issues/3) and [#4](https://github.com/cdrn/sigil/issues/4).
52
+
53
+ **Shipped (v1):**
54
+ - Two-mode policy. `permissive` mode (default for `sigil portal add`) does no checks — useful for users who only want the key-isolation guarantee. `strict` mode enforces every rule below.
55
+ - Destination allowlist (`allow_to`).
56
+ - Chain ID allowlist (`chain_ids`).
57
+ - Per-tx value cap (`max_value_wei`).
58
+ - Function selector allowlist (`allowed_selectors`) — 4-byte selector match, no calldata decoding.
59
+ - On/off toggles for personal_sign (`allow_message_signing`) and EIP-712 typed data (`allow_typed_data`).
60
+ - Append-only hash-chained audit log records both allow AND deny decisions. Denies are the prompt-injection canary.
61
+ - Runtime fail-closed when the policy file is missing for a portal — keys can't be used without an explicit decision.
62
+
63
+ **Planned:**
64
+ - Rolling-window value caps (`max_value_per_hour_wei`, etc.) backed by a per-portal ledger with flock for multi-instance safety.
65
+ - EIP-712 domain + primary-type allowlists (today `allow_typed_data` is binary; OpenSea-style approvals deserve finer control).
66
+ - Decoded-calldata arg checks ("allow `transfer(addr, amt)` only when `amt <= 100e18` and `addr in list`"). Needs a BYO-ABI registry per portal.
67
+ - Out-of-band human confirmation above a configurable value threshold (push to ntfy / Pushover / Telegram / Apple Push), [#4](https://github.com/cdrn/sigil/issues/4).
68
+ - `allow_contract_creation` toggle — currently strict mode always denies tx with `to: null`.
58
69
 
59
70
  ### 3. Supply chain compromise of `sigil` itself
60
71
 
@@ -5,6 +5,7 @@ import { resolvePaths } from '../cli/paths.js';
5
5
  import { startControlServer } from '../control/index.js';
6
6
  import { HandleTable } from '../daemon/handles.js';
7
7
  import { runMcpStdio } from '../mcp/server.js';
8
+ import { FileSystemPolicyResolver } from '../policy/index.js';
8
9
  /**
9
10
  * sigil-mcp: single-process MCP server for sigil. Spawned by Claude Code per
10
11
  * session via the .claude/settings.json mcpServers entry.
@@ -27,8 +28,10 @@ async function main() {
27
28
  const paths = resolvePaths(process.env);
28
29
  mkdirSync(paths.home, { recursive: true, mode: 0o700 });
29
30
  mkdirSync(paths.keysDir, { recursive: true, mode: 0o700 });
31
+ mkdirSync(paths.policyDir, { recursive: true, mode: 0o700 });
30
32
  const handles = new HandleTable();
31
33
  const audit = new AuditWriter(paths.auditLog);
34
+ const policy = new FileSystemPolicyResolver(paths.policyDir);
32
35
  let controlClosed = false;
33
36
  let control = null;
34
37
  try {
@@ -67,7 +70,7 @@ async function main() {
67
70
  process.on('SIGINT', () => process.exit(0));
68
71
  process.on('SIGTERM', () => process.exit(0));
69
72
  await runMcpStdio({
70
- context: { handles, audit },
73
+ context: { handles, audit, policy },
71
74
  stdin: process.stdin,
72
75
  stdout: process.stdout,
73
76
  onLog: (e) => process.stderr.write(JSON.stringify(e) + '\n'),
@@ -1 +1 @@
1
- {"version":3,"file":"sigil-mcp.js","sourceRoot":"","sources":["../../../src/bin/sigil-mcp.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sigil-mcp.js","sourceRoot":"","sources":["../../../src/bin/sigil-mcp.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAE9D;;;;;;;;;;;;;;;;;GAiBG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACxC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,SAAS,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAE7D,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAI,wBAAwB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAE7D,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,IAAI,OAAO,GAA0D,IAAI,CAAC;IAC1E,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,kBAAkB,CAAC;YACjC,UAAU,EAAE,KAAK,CAAC,aAAa;YAC/B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,OAAO;YACP,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;SACtE,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wEAAwE;QACxE,oEAAoE;QACpE,uEAAuE;QACvE,oDAAoD;QACpD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,0CAA2C,GAAa,CAAC,OAAO,KAAK;YACrE,uEAAuE;YACvE,mEAAmE;YACnE,8DAA8D,CAC/D,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,kEAAkE,KAAK,CAAC,OAAO,KAAK,CACrF,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,QAAQ,GAAG,GAAS,EAAE;QAC1B,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,IAAI,CAAC,aAAa,IAAI,OAAO,EAAE,CAAC;YAC9B,aAAa,GAAG,IAAI,CAAC;YACrB,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAqB,CAAC,CAAC,CAAC;QACrD,CAAC;IACH,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7C,MAAM,WAAW,CAAC;QAChB,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE;QACnC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;KAC7D,CAAC,CAAC;IAEH,wEAAwE;IACxE,6CAA6C;IAC7C,IAAI,OAAO,IAAI,CAAC,aAAa,EAAE,CAAC;QAC9B,aAAa,GAAG,IAAI,CAAC;QACrB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;IAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;IACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/cli/main.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AA0BpD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC5C,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CA+G/D"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/cli/main.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AA8BpD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC5C,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAkJ/D"}
@@ -1,5 +1,8 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
1
3
  import { readPassphrase } from '../daemon/passphrase.js';
2
4
  import { installInto } from '../hooks/install.js';
5
+ import { parsePolicy } from '../policy/index.js';
3
6
  import { ArgsError, parseSubcommand } from './args.js';
4
7
  import { resolvePaths } from './paths.js';
5
8
  import { portalAdd, portalListFromDisk, portalRemove } from './portal.js';
@@ -10,14 +13,17 @@ const USAGE = `sigil — local signing control for Claude Code
10
13
  Usage:
11
14
  sigil init [--user]
12
15
  sigil status
13
- sigil portal add <handle> --key-file <path> [--no-remove-source]
16
+ sigil portal add <handle> --key-file <path> [--no-remove-source] [--strict]
14
17
  sigil portal list
15
18
  sigil portal remove <handle>
19
+ sigil policy show <handle>
16
20
  sigil unlock
17
21
  sigil lock
18
22
 
19
23
  "sigil init" writes the MCP server registration + tool hooks into
20
24
  .claude/settings.json (or ~/.claude/settings.json with --user).
25
+ "sigil portal add" writes a permissive policy by default; pass --strict
26
+ to get a locked-down template you fill in before any sign succeeds.
21
27
  "sigil unlock" prompts for the passphrase and pushes it to the running
22
28
  sigil-mcp process (spawned by Claude Code) over the control socket.
23
29
  Set SIGIL_HOME to override ~/.sigil.
@@ -79,6 +85,7 @@ export async function runCli(opts) {
79
85
  options: {
80
86
  'key-file': { type: 'string' },
81
87
  'no-remove-source': { type: 'boolean' },
88
+ 'strict': { type: 'boolean' },
82
89
  },
83
90
  },
84
91
  list: { options: {} },
@@ -92,16 +99,22 @@ export async function runCli(opts) {
92
99
  if (typeof keyFile !== 'string' || keyFile.length === 0) {
93
100
  throw new ArgsError('portal add: --key-file is required');
94
101
  }
102
+ const policyMode = sub.options['strict'] === true ? 'strict' : 'permissive';
95
103
  const passphrase = await askPassphrase();
96
104
  try {
97
- const { address, keyfilePath } = portalAdd(paths, {
105
+ const { address, keyfilePath, policyPath } = portalAdd(paths, {
98
106
  handle,
99
107
  keyFile,
100
108
  passphrase,
109
+ policyMode,
101
110
  ...(sub.options['no-remove-source'] === true ? { removeSource: false } : {}),
102
111
  ...(opts.kdfParams ? { kdfParams: opts.kdfParams } : {}),
103
112
  });
104
113
  out.write(`added ${handle} (${address}) → ${keyfilePath}\n`);
114
+ out.write(`policy: ${policyMode} → ${policyPath}\n`);
115
+ if (policyMode === 'strict') {
116
+ out.write(`note: strict policy denies everything until you edit ${policyPath}\n`);
117
+ }
105
118
  }
106
119
  finally {
107
120
  passphrase.fill(0);
@@ -137,6 +150,38 @@ export async function runCli(opts) {
137
150
  return { code: result.removed ? 0 : 1 };
138
151
  }
139
152
  }
153
+ if (head === 'policy') {
154
+ const sub = parseSubcommand(rest, { show: { options: {} } });
155
+ if (sub.command === 'show') {
156
+ const handle = sub.positionals[0];
157
+ if (!handle)
158
+ throw new ArgsError('policy show: missing handle');
159
+ const policyPath = join(paths.policyDir, `${handle}.toml`);
160
+ let source;
161
+ try {
162
+ source = readFileSync(policyPath, 'utf8');
163
+ }
164
+ catch (e) {
165
+ if (e.code === 'ENOENT') {
166
+ err.write(`policy: no file at ${policyPath}\n`);
167
+ return { code: 1 };
168
+ }
169
+ throw e;
170
+ }
171
+ // Validate by parsing — surface schema errors as exit 1.
172
+ try {
173
+ parsePolicy(source);
174
+ }
175
+ catch (e) {
176
+ err.write(`policy: ${e.message}\n`);
177
+ err.write(`(file at ${policyPath} is on disk but doesn't parse — fix it before signing)\n`);
178
+ return { code: 1 };
179
+ }
180
+ out.write(source);
181
+ out.write(`# ${policyPath}\n`);
182
+ return { code: 0 };
183
+ }
184
+ }
140
185
  throw new ArgsError(`unknown subcommand "${head}"`);
141
186
  }
142
187
  catch (e) {
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../../../src/cli/main.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../../src/cli/main.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,7 @@
10
10
  export interface SigilPaths {
11
11
  readonly home: string;
12
12
  readonly keysDir: string;
13
+ readonly policyDir: string;
13
14
  readonly controlSocket: string;
14
15
  readonly auditLog: string;
15
16
  }
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/cli/paths.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,UAAU,CAQ7E"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/cli/paths.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,UAAU,CAS7E"}
@@ -5,6 +5,7 @@ export function resolvePaths(env = process.env) {
5
5
  return {
6
6
  home,
7
7
  keysDir: join(home, 'keys'),
8
+ policyDir: join(home, 'policy'),
8
9
  controlSocket: env['SIGIL_CONTROL_SOCK'] ?? join(home, 'control.sock'),
9
10
  auditLog: join(home, 'audit.log'),
10
11
  };
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/cli/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAkBjC,MAAM,UAAU,YAAY,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC/D,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC5D,OAAO;QACL,IAAI;QACJ,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;QAC3B,aAAa,EAAE,GAAG,CAAC,oBAAoB,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC;QACtE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;KAClC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/cli/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAmBjC,MAAM,UAAU,YAAY,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC/D,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC5D,OAAO;QACL,IAAI;QACJ,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;QAC3B,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC;QAC/B,aAAa,EAAE,GAAG,CAAC,oBAAoB,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC;QACtE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;KAClC,CAAC;AACJ,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { type KdfParams, SecretBuffer } from '../crypto/index.js';
2
+ import { type PolicyMode } from '../policy/index.js';
2
3
  import type { SigilPaths } from './paths.js';
3
4
  export interface PortalAddOpts {
4
5
  handle: string;
@@ -16,6 +17,13 @@ export interface PortalAddOpts {
16
17
  * the suite fast. The CLI binary never sets this.
17
18
  */
18
19
  kdfParams?: KdfParams;
20
+ /**
21
+ * Policy template to write at provisioning time. Defaults to "permissive"
22
+ * (signs anything the agent asks — same UX as today, key still protected
23
+ * from context). Pass "strict" to write a locked-down template the user
24
+ * must edit before signing succeeds.
25
+ */
26
+ policyMode?: PolicyMode;
19
27
  }
20
28
  /**
21
29
  * Reads a private key from disk, encrypts it with the passphrase, writes it
@@ -29,6 +37,7 @@ export interface PortalAddOpts {
29
37
  export declare function portalAdd(paths: SigilPaths, opts: PortalAddOpts): {
30
38
  address: string;
31
39
  keyfilePath: string;
40
+ policyPath: string;
32
41
  };
33
42
  export interface PortalInfo {
34
43
  handle: string;
@@ -1 +1 @@
1
- {"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../../src/cli/portal.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAW,YAAY,EAAa,MAAM,oBAAoB,CAAC;AAGtF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CA4B1G;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,EAAE,CAgBtF;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAMlF;AAqBD,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../../src/cli/portal.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAW,YAAY,EAAa,MAAM,oBAAoB,CAAC;AAGtF,OAAO,EAAE,KAAK,UAAU,EAAkB,MAAM,oBAAoB,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,aAAa,GAClB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAqC9D;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,EAAE,CAgBtF;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAalF;AAqBD,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -3,6 +3,7 @@ import { join } from 'node:path';
3
3
  import { sealKey, SecretBuffer, unsealKey } from '../crypto/index.js';
4
4
  import { addressFromPrivateKey } from '../eth/index.js';
5
5
  import { HandleTable } from '../daemon/handles.js';
6
+ import { policyTemplate } from '../policy/index.js';
6
7
  /**
7
8
  * Reads a private key from disk, encrypts it with the passphrase, writes it
8
9
  * to the keys directory under <handle>.sigil, and (by default) deletes the
@@ -15,10 +16,15 @@ import { HandleTable } from '../daemon/handles.js';
15
16
  export function portalAdd(paths, opts) {
16
17
  HandleTable.parseHandle(opts.handle); // validates format
17
18
  mkdirSync(paths.keysDir, { recursive: true, mode: 0o700 });
19
+ mkdirSync(paths.policyDir, { recursive: true, mode: 0o700 });
18
20
  const destPath = join(paths.keysDir, `${opts.handle}.sigil`);
19
21
  if (existsSync(destPath)) {
20
22
  throw new Error(`portal "${opts.handle}" already exists at ${destPath}; remove it first`);
21
23
  }
24
+ const policyPath = join(paths.policyDir, `${opts.handle}.toml`);
25
+ if (existsSync(policyPath)) {
26
+ throw new Error(`policy file for "${opts.handle}" already exists at ${policyPath}; remove it first`);
27
+ }
22
28
  const raw = readFileSync(opts.keyFile);
23
29
  const priv = normalizePrivateKey(raw);
24
30
  let address;
@@ -32,13 +38,16 @@ export function portalAdd(paths, opts) {
32
38
  finally {
33
39
  priv.fill(0);
34
40
  }
41
+ // Write the policy file alongside the keyfile. Mode 0o600 — it's not secret
42
+ // per se, but it does describe what this key can sign, which is sensitive.
43
+ writeFileSync(policyPath, policyTemplate(opts.policyMode ?? 'permissive'), { mode: 0o600 });
35
44
  if (opts.removeSource !== false) {
36
45
  try {
37
46
  unlinkSync(opts.keyFile);
38
47
  }
39
48
  catch { /* best-effort cleanup; file may already be gone */ }
40
49
  }
41
- return { address, keyfilePath: destPath };
50
+ return { address, keyfilePath: destPath, policyPath };
42
51
  }
43
52
  /**
44
53
  * Lists portals by reading the keys directory and decrypting each keyfile
@@ -68,10 +77,20 @@ export function portalListFromDisk(paths, passphrase) {
68
77
  export function portalRemove(paths, handle) {
69
78
  HandleTable.parseHandle(handle); // validates format
70
79
  const destPath = join(paths.keysDir, `${handle}.sigil`);
71
- if (!existsSync(destPath))
72
- return { removed: false, path: destPath };
73
- unlinkSync(destPath);
74
- return { removed: true, path: destPath };
80
+ const policyPath = join(paths.policyDir, `${handle}.toml`);
81
+ const keyfileExisted = existsSync(destPath);
82
+ if (keyfileExisted)
83
+ unlinkSync(destPath);
84
+ // Best-effort policy cleanup. We don't fail the remove if the keyfile is
85
+ // missing but the policy file isn't, or vice versa — better to err on the
86
+ // side of cleaning up orphans.
87
+ if (existsSync(policyPath)) {
88
+ try {
89
+ unlinkSync(policyPath);
90
+ }
91
+ catch { /* ignore */ }
92
+ }
93
+ return { removed: keyfileExisted, path: destPath };
75
94
  }
76
95
  // ---------------------------------------------------------------------------
77
96
  // Helpers
@@ -1 +1 @@
1
- {"version":3,"file":"portal.js","sourceRoot":"","sources":["../../../src/cli/portal.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"portal.js","sourceRoot":"","sources":["../../../src/cli/portal.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { type AuditWriter } from '../audit/index.js';
2
+ import { type PolicyResolver } from '../policy/index.js';
2
3
  import { type HandleTable } from './handles.js';
3
4
  export declare const RPC_INVALID_PARAMS = -32602;
4
5
  export declare const RPC_METHOD_NOT_FOUND = -32601;
@@ -14,6 +15,12 @@ export declare class RpcMethodError extends Error {
14
15
  export interface MethodContext {
15
16
  handles: HandleTable;
16
17
  audit: AuditWriter;
18
+ /**
19
+ * Resolves the per-portal policy at evaluation time. Wrapped in an
20
+ * interface so tests can inject a constant policy without touching the
21
+ * filesystem.
22
+ */
23
+ policy: PolicyResolver;
17
24
  }
18
25
  export type MethodHandler = (params: unknown, ctx: MethodContext) => unknown;
19
26
  export declare const METHODS: Readonly<Record<string, MethodHandler>>;
@@ -1 +1 @@
1
- {"version":3,"file":"methods.d.ts","sourceRoot":"","sources":["../../../src/daemon/methods.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAW3B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAKhD,eAAO,MAAM,kBAAkB,SAAS,CAAC;AACzC,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAE3C,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,eAAO,MAAM,iBAAiB,SAAS,CAAC;AACxC,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAC1C,eAAO,MAAM,iBAAiB,SAAS,CAAC;AAExC,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;gBACX,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAM1D;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC;AAoN7E,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAK1D,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAMrF"}
1
+ {"version":3,"file":"methods.d.ts","sourceRoot":"","sources":["../../../src/daemon/methods.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAW3B,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAKhD,eAAO,MAAM,kBAAkB,SAAS,CAAC;AACzC,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAE3C,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,eAAO,MAAM,iBAAiB,SAAS,CAAC;AACxC,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAC1C,eAAO,MAAM,iBAAiB,SAAS,CAAC;AAExC,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;gBACX,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAM1D;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,WAAW,CAAC;IACnB;;;;OAIG;IACH,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC;AA4P7E,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAK1D,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAMrF"}
@@ -1,4 +1,5 @@
1
1
  import { personalSign, signTransaction, signTypedData, } from '../eth/index.js';
2
+ import { evaluate, PolicyLoadError, } from '../policy/index.js';
2
3
  // Error codes — these match JSON-RPC 2.0 standard error codes plus a
3
4
  // sigil-specific range (-32000..-32099). They flow through the MCP wire
4
5
  // unchanged so the client sees the exact diagnosis.
@@ -51,6 +52,35 @@ function requirePortal(handles, handle) {
51
52
  }
52
53
  return sb.bytes();
53
54
  }
55
+ /**
56
+ * Resolve the portal's policy and evaluate the request. On Deny — or on any
57
+ * PolicyLoadError (missing file, malformed TOML) — appends a deny entry to
58
+ * the audit log AND throws RPC_POLICY_DENIED. Returns silently on Allow.
59
+ *
60
+ * The order is: require unlocked + portal first, then policy. That way the
61
+ * caller's mistakes (wrong handle, daemon locked) error before we touch the
62
+ * policy file at all.
63
+ */
64
+ function gatePolicy(ctx, handle, kind, payload, request) {
65
+ let reason;
66
+ try {
67
+ const policy = ctx.policy.resolve(handle);
68
+ const decision = evaluate(request, policy);
69
+ if (decision.allow)
70
+ return;
71
+ reason = decision.reason;
72
+ }
73
+ catch (err) {
74
+ if (err instanceof PolicyLoadError) {
75
+ reason = err.message;
76
+ }
77
+ else {
78
+ throw err;
79
+ }
80
+ }
81
+ ctx.audit.append({ kind, portal: handle, payload, decision: 'deny', reason });
82
+ throw new RpcMethodError(RPC_POLICY_DENIED, reason);
83
+ }
54
84
  // ---------------------------------------------------------------------------
55
85
  // Methods
56
86
  // ---------------------------------------------------------------------------
@@ -63,6 +93,9 @@ const sigil_eth_sign_message = (params, ctx) => {
63
93
  const messageHex = asString(obj, 'message', 'eth_sign_message');
64
94
  const message = hexToBuf(messageHex, 'eth_sign_message', 'message');
65
95
  const priv = requirePortal(ctx.handles, portal);
96
+ gatePolicy(ctx, portal, 'eth_sign_message', { message: messageHex }, {
97
+ kind: 'message', messageBytes: message,
98
+ });
66
99
  const sig = personalSign(message, priv);
67
100
  const sigHex = ('0x' + sig.toString('hex'));
68
101
  ctx.audit.append({
@@ -175,6 +208,7 @@ const sigil_eth_sign_transaction = (params, ctx) => {
175
208
  }
176
209
  const tx = asTx(txObj);
177
210
  const priv = requirePortal(ctx.handles, portal);
211
+ gatePolicy(ctx, portal, 'eth_sign_transaction', { tx: txObj }, { kind: 'transaction', tx });
178
212
  const signed = signTransaction(tx, priv);
179
213
  ctx.audit.append({
180
214
  kind: 'eth_sign_transaction',
@@ -195,6 +229,9 @@ const sigil_eth_sign_typed_data = (params, ctx) => {
195
229
  // We trust the typed-data shape minimally — sign-typed.ts will throw
196
230
  // on missing fields; we wrap that as INVALID_PARAMS for the caller.
197
231
  const priv = requirePortal(ctx.handles, portal);
232
+ gatePolicy(ctx, portal, 'eth_sign_typed_data', { typedData: td }, {
233
+ kind: 'typed_data', typedData: td,
234
+ });
198
235
  let sig;
199
236
  try {
200
237
  sig = signTypedData(td, priv);
@@ -1 +1 @@
1
- {"version":3,"file":"methods.js","sourceRoot":"","sources":["../../../src/daemon/methods.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"methods.js","sourceRoot":"","sources":["../../../src/daemon/methods.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,YAAY,EAEZ,eAAe,EACf,aAAa,GAEd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,QAAQ,EACR,eAAe,GAGhB,MAAM,oBAAoB,CAAC;AAG5B,qEAAqE;AACrE,wEAAwE;AACxE,oDAAoD;AACpD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAK,CAAC;AACzC,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAK,CAAC;AAC3C,kBAAkB;AAClB,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAK,CAAC;AAC3C,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAK,CAAC;AACxC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,KAAK,CAAC;AAC1C,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAK,CAAC;AAExC,MAAM,OAAO,cAAe,SAAQ,KAAK;IAC9B,IAAI,CAAS;IACb,IAAI,CAAU;IACvB,YAAY,IAAY,EAAE,OAAe,EAAE,IAAc;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAeD,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,SAAS,QAAQ,CAAC,MAAe,EAAE,UAAkB;IACnD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,GAAG,UAAU,4BAA4B,CAAC,CAAC;IAC1F,CAAC;IACD,OAAO,MAAiC,CAAC;AAC3C,CAAC;AAED,SAAS,QAAQ,CAAC,GAA4B,EAAE,GAAW,EAAE,UAAkB;IAC7E,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,GAAG,UAAU,KAAK,GAAG,mBAAmB,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS,EAAE,UAAkB,EAAE,GAAW;IAC1D,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,GAAG,UAAU,KAAK,GAAG,0BAA0B,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,aAAa,CAAC,OAAoB,EAAE,MAAc;IACzD,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;QAC1B,MAAM,IAAI,cAAc,CACtB,iBAAiB,EACjB,iEAAiE,CAClE,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,MAAM,IAAI,cAAc,CAAC,oBAAoB,EAAE,WAAW,MAAM,aAAa,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC;AACpB,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,UAAU,CACjB,GAAkB,EAClB,MAAc,EACd,IAAY,EACZ,OAAgB,EAChB,OAAsB;IAEtB,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3C,IAAI,QAAQ,CAAC,KAAK;YAAE,OAAO;QAC3B,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,eAAe,EAAE,CAAC;YACnC,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IACD,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9E,MAAM,IAAI,cAAc,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;AACtD,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAM,kBAAkB,GAAkB,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE;IACzD,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;AACzC,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAkB,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;IAC5D,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,kBAAkB,CAAC,CAAC;IAC3D,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,EAAE,SAAS,EAAE,kBAAkB,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,EAAE,kBAAkB,EAAE,SAAS,CAAC,CAAC;IACpE,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAChD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE;QACnE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO;KACvC,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAQ,CAAC;IACnD,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,kBAAkB;QACxB,MAAM;QACN,OAAO,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE;QAChC,QAAQ,EAAE,OAAO;QACjB,GAAG,EAAE,MAAM;KACZ,CAAC,CAAC;IACH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AAC/B,CAAC,CAAC;AAEF,SAAS,IAAI,CAAC,GAA4B;IACxC,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5C,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,wCAAwC,CAAC,CAAC;IACzF,CAAC;IAED,MAAM,GAAG,GAAG,CAAC,GAAW,EAAU,EAAE;QAClC,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACH,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;YACnB,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,OAAO,GAAG,4BAA4B,CAAC,CAAC;YACvF,CAAC;QACH,CAAC;QACD,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClC,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,OAAO,GAAG,iCAAiC,CAAC,CAAC;YAC5F,CAAC;YACD,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;QACnB,CAAC;QACD,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,OAAO,GAAG,mCAAmC,CAAC,CAAC;IAC9F,CAAC,CAAC;IAEF,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;IACrB,IAAI,EAAE,KAAK,IAAI,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE,CAAC;QAC1C,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,mCAAmC,CAAC,CAAC;IACpF,CAAC;IACD,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,4CAA4C,CAAC,CAAC;IAC7F,CAAC;IAED,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,kCAAkC,CAAC,CAAC;IACnF,CAAC;IAED,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,MAAM,EAAE,GAAa;YACnB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC;YACvB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC;YACnB,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC;YACzB,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC;YACzB,EAAE,EAAE,EAA0B;YAC9B,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC;YACnB,IAAI,EAAE,IAAqB;SAC5B,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,UAAU;IACV,MAAM,aAAa,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC;IACxC,IAAI,UAAmC,CAAC;IACxC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,UAAU,GAAG,EAAE,CAAC;IAClB,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;QACxC,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YACzC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrE,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;YACtF,CAAC;YACD,MAAM,EAAE,GAAG,IAA+B,CAAC;YAC3C,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC3B,MAAM,IAAI,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC;YAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAClE,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,WAAW,CAAC,CAAC;YAC/E,CAAC;YACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,6BAA6B,CAAC,CAAC;YACjG,CAAC;YACD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;gBACrB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC5D,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;gBACtF,CAAC;YACH,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,IAAqB,EAAE,WAAW,EAAE,IAAuB,EAAE,CAAC;QAClF,CAAC,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,yCAAyC,CAAC,CAAC;IAC1F,CAAC;IACD,MAAM,EAAE,GAAc;QACpB,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC;QACvB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC;QACnB,oBAAoB,EAAE,GAAG,CAAC,sBAAsB,CAAC;QACjD,YAAY,EAAE,GAAG,CAAC,cAAc,CAAC;QACjC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC;QACzB,EAAE,EAAE,EAA0B;QAC9B,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC;QACnB,IAAI,EAAE,IAAqB;QAC3B,UAAU;KACX,CAAC;IACF,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,0BAA0B,GAAkB,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;IAChE,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,sBAAsB,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;IACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,4CAA4C,CAAC,CAAC;IAC7F,CAAC;IACD,MAAM,EAAE,GAAG,IAAI,CAAC,KAAgC,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAChD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,sBAAsB,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5F,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,sBAAsB;QAC5B,MAAM;QACN,OAAO,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE;QACtB,QAAQ,EAAE,OAAO;QACjB,GAAG,EAAE,MAAM;KACZ,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC,CAAC;AAEF,MAAM,yBAAyB,GAAkB,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;IAC/D,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,qBAAqB,CAAC,CAAC;IAC9D,MAAM,EAAE,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC;IAC5B,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,+CAA+C,CAAC,CAAC;IAChG,CAAC;IACD,qEAAqE;IACrE,oEAAoE;IACpE,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAChD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,qBAAqB,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE;QAChE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,EAAe;KAC/C,CAAC,CAAC;IACH,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,aAAa,CAAC,EAAe,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,cAAc,CACtB,kBAAkB,EAClB,wBAAyB,GAAa,CAAC,OAAO,EAAE,CACjD,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAQ,CAAC;IACnD,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,qBAAqB;QAC3B,MAAM;QACN,OAAO,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;QAC1B,QAAQ,EAAE,OAAO;QACjB,GAAG,EAAE,MAAM;KACZ,CAAC,CAAC;IACH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AAC/B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAA4C,MAAM,CAAC,MAAM,CAAC;IAC5E,kBAAkB;IAClB,sBAAsB;IACtB,0BAA0B;IAC1B,yBAAyB;CAC1B,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAc,EAAE,MAAe,EAAE,GAAkB;IAC1E,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,cAAc,CAAC,oBAAoB,EAAE,qBAAqB,MAAM,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { Policy, PolicyDecision, PolicyRequest } from './types.js';
2
+ /**
3
+ * Pure evaluator. Takes a (request, policy), returns Allow or Deny(reason).
4
+ *
5
+ * The reason string is what the caller writes into the audit log and surfaces
6
+ * as the RPC_POLICY_DENIED error message — write it for a human.
7
+ *
8
+ * Permissive mode short-circuits to Allow for everything. Strict mode walks
9
+ * the rules in a fixed order and returns the first failing one — the order
10
+ * doesn't matter for correctness, only for which reason the user sees first.
11
+ */
12
+ export declare function evaluate(request: PolicyRequest, policy: Policy): PolicyDecision;
13
+ //# sourceMappingURL=evaluate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../../src/policy/evaluate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAExE;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CAoB/E"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Pure evaluator. Takes a (request, policy), returns Allow or Deny(reason).
3
+ *
4
+ * The reason string is what the caller writes into the audit log and surfaces
5
+ * as the RPC_POLICY_DENIED error message — write it for a human.
6
+ *
7
+ * Permissive mode short-circuits to Allow for everything. Strict mode walks
8
+ * the rules in a fixed order and returns the first failing one — the order
9
+ * doesn't matter for correctness, only for which reason the user sees first.
10
+ */
11
+ export function evaluate(request, policy) {
12
+ if (policy.mode === 'permissive')
13
+ return { allow: true };
14
+ switch (request.kind) {
15
+ case 'transaction':
16
+ return evaluateTransaction(request.tx, policy);
17
+ case 'message':
18
+ return policy.allowMessageSigning
19
+ ? { allow: true }
20
+ : {
21
+ allow: false,
22
+ reason: 'personal_sign denied — strict mode + allow_message_signing=false',
23
+ };
24
+ case 'typed_data':
25
+ return policy.allowTypedData
26
+ ? { allow: true }
27
+ : {
28
+ allow: false,
29
+ reason: 'EIP-712 typed-data denied — strict mode + allow_typed_data=false',
30
+ };
31
+ }
32
+ }
33
+ function evaluateTransaction(tx, policy) {
34
+ // 1. chain ID
35
+ if (!policy.chainIds.includes(Number(tx.chainId))) {
36
+ return {
37
+ allow: false,
38
+ reason: `tx denied — chain ${tx.chainId} not in chain_ids ${JSON.stringify(policy.chainIds)}`,
39
+ };
40
+ }
41
+ // 2. contract creation (to: null) — denied by default; future "allow_contract_creation" toggle
42
+ if (tx.to === null) {
43
+ return { allow: false, reason: 'tx denied — contract creation not allowed' };
44
+ }
45
+ // 3. destination allowlist (case-insensitive; allow_to is pre-lowercased)
46
+ const to = tx.to.toLowerCase();
47
+ if (!policy.allowTo.includes(to)) {
48
+ return { allow: false, reason: `tx denied — destination ${to} not in allow_to` };
49
+ }
50
+ // 4. per-tx value cap
51
+ if (tx.value > policy.maxValueWei) {
52
+ return {
53
+ allow: false,
54
+ reason: `tx denied — value ${tx.value} wei exceeds max_value_wei ${policy.maxValueWei}`,
55
+ };
56
+ }
57
+ // 5. function selector allowlist (only for txs with calldata)
58
+ const dataHex = typeof tx.data === 'string' ? tx.data : ('0x' + tx.data.toString('hex'));
59
+ if (dataHex.length > 2) {
60
+ if (dataHex.length < 10) {
61
+ return { allow: false, reason: `tx denied — calldata too short to extract selector` };
62
+ }
63
+ const selector = dataHex.slice(0, 10).toLowerCase();
64
+ if (!policy.allowedSelectors.includes(selector)) {
65
+ return {
66
+ allow: false,
67
+ reason: `tx denied — selector ${selector} not in allowed_selectors`,
68
+ };
69
+ }
70
+ }
71
+ return { allow: true };
72
+ }
73
+ //# sourceMappingURL=evaluate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../../../src/policy/evaluate.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAsB,EAAE,MAAc;IAC7D,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzD,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,aAAa;YAChB,OAAO,mBAAmB,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACjD,KAAK,SAAS;YACZ,OAAO,MAAM,CAAC,mBAAmB;gBAC/B,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;gBACjB,CAAC,CAAC;oBACE,KAAK,EAAE,KAAK;oBACZ,MAAM,EAAE,kEAAkE;iBAC3E,CAAC;QACR,KAAK,YAAY;YACf,OAAO,MAAM,CAAC,cAAc;gBAC1B,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;gBACjB,CAAC,CAAC;oBACE,KAAK,EAAE,KAAK;oBACZ,MAAM,EAAE,kEAAkE;iBAC3E,CAAC;IACV,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,EAAc,EAAE,MAAc;IACzD,cAAc;IACd,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAClD,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,qBAAqB,EAAE,CAAC,OAAO,qBAAqB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;SAC9F,CAAC;IACJ,CAAC;IAED,+FAA+F;IAC/F,IAAI,EAAE,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,2CAA2C,EAAE,CAAC;IAC/E,CAAC;IAED,0EAA0E;IAC1E,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,CAAC;IACnF,CAAC;IAED,sBAAsB;IACtB,IAAI,EAAE,CAAC,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QAClC,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,qBAAqB,EAAE,CAAC,KAAK,8BAA8B,MAAM,CAAC,WAAW,EAAE;SACxF,CAAC;IACJ,CAAC;IAED,8DAA8D;IAC9D,MAAM,OAAO,GAAG,OAAO,EAAE,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IACzF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YACxB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,oDAAoD,EAAE,CAAC;QACxF,CAAC;QACD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QACpD,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChD,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,wBAAwB,QAAQ,2BAA2B;aACpE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { type Policy, type PolicyRequest, type PolicyDecision, type PolicyResolver, PolicyLoadError, } from './types.js';
2
+ export { parsePolicy, FileSystemPolicyResolver, permissivePolicyResolver, } from './loader.js';
3
+ export { evaluate } from './evaluate.js';
4
+ export { type PolicyMode, PERMISSIVE_TEMPLATE, STRICT_TEMPLATE, policyTemplate, } from './template.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/policy/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,WAAW,EACX,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,KAAK,UAAU,EACf,mBAAmB,EACnB,eAAe,EACf,cAAc,GACf,MAAM,eAAe,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { PolicyLoadError, } from './types.js';
2
+ export { parsePolicy, FileSystemPolicyResolver, permissivePolicyResolver, } from './loader.js';
3
+ export { evaluate } from './evaluate.js';
4
+ export { PERMISSIVE_TEMPLATE, STRICT_TEMPLATE, policyTemplate, } from './template.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/policy/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,WAAW,EACX,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAEL,mBAAmB,EACnB,eAAe,EACf,cAAc,GACf,MAAM,eAAe,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { type Policy, type PolicyResolver } from './types.js';
2
+ /**
3
+ * Parse + validate + normalize a TOML policy file. Throws PolicyLoadError on
4
+ * any schema violation with a message pointing at the offending field.
5
+ *
6
+ * Normalization:
7
+ * - addresses lowercased so allowlist membership is case-insensitive
8
+ * - selectors lowercased likewise
9
+ * - max_value_wei string → bigint
10
+ *
11
+ * Permissive mode tolerates missing strict fields (they're ignored anyway).
12
+ * Strict mode applies defaults: chain_ids must be present; everything else
13
+ * defaults to a closed/zero value.
14
+ */
15
+ export declare function parsePolicy(source: string): Policy;
16
+ /**
17
+ * A PolicyResolver that returns the same permissive policy for every handle.
18
+ * Useful for tests that want to exercise sign methods without provisioning
19
+ * a TOML file per portal.
20
+ */
21
+ export declare function permissivePolicyResolver(): PolicyResolver;
22
+ /**
23
+ * File-backed PolicyResolver: reads ~/.sigil/policy/<handle>.toml every time
24
+ * resolve() is called. Sign calls are human-paced so the read is cheap; the
25
+ * fresh read also means policy edits take effect immediately (no daemon
26
+ * restart).
27
+ */
28
+ export declare class FileSystemPolicyResolver implements PolicyResolver {
29
+ #private;
30
+ constructor(policyDir: string);
31
+ resolve(handle: string): Policy;
32
+ }
33
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/policy/loader.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,MAAM,EAAmB,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAM/E;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA+DlD;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,cAAc,CAWzD;AAED;;;;;GAKG;AACH,qBAAa,wBAAyB,YAAW,cAAc;;gBAEjD,SAAS,EAAE,MAAM;IAG7B,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAehC"}
@@ -0,0 +1,170 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import toml from '@iarna/toml';
4
+ import { PolicyLoadError } from './types.js';
5
+ const ADDR_RE = /^0x[0-9a-fA-F]{40}$/;
6
+ const SELECTOR_RE = /^0x[0-9a-fA-F]{8}$/;
7
+ const DEC_RE = /^[0-9]+$/;
8
+ /**
9
+ * Parse + validate + normalize a TOML policy file. Throws PolicyLoadError on
10
+ * any schema violation with a message pointing at the offending field.
11
+ *
12
+ * Normalization:
13
+ * - addresses lowercased so allowlist membership is case-insensitive
14
+ * - selectors lowercased likewise
15
+ * - max_value_wei string → bigint
16
+ *
17
+ * Permissive mode tolerates missing strict fields (they're ignored anyway).
18
+ * Strict mode applies defaults: chain_ids must be present; everything else
19
+ * defaults to a closed/zero value.
20
+ */
21
+ export function parsePolicy(source) {
22
+ let raw;
23
+ try {
24
+ raw = toml.parse(source);
25
+ }
26
+ catch (err) {
27
+ throw new PolicyLoadError(`policy: invalid TOML — ${err.message}`, err);
28
+ }
29
+ const mode = raw['mode'];
30
+ if (mode !== 'permissive' && mode !== 'strict') {
31
+ throw new PolicyLoadError(`policy.mode must be "permissive" or "strict" (got ${JSON.stringify(mode)})`);
32
+ }
33
+ if (mode === 'permissive') {
34
+ return {
35
+ mode: 'permissive',
36
+ chainIds: [],
37
+ allowTo: [],
38
+ maxValueWei: 0n,
39
+ allowedSelectors: [],
40
+ allowMessageSigning: true,
41
+ allowTypedData: true,
42
+ };
43
+ }
44
+ // strict mode — every field is consulted; apply defaults for absent ones.
45
+ const chainIds = asNumberArray(raw['chain_ids'], 'chain_ids', { required: true });
46
+ for (const id of chainIds) {
47
+ if (!Number.isInteger(id) || id < 0) {
48
+ throw new PolicyLoadError(`policy.chain_ids[*] must be non-negative integers (got ${id})`);
49
+ }
50
+ }
51
+ const allowToRaw = asStringArray(raw['allow_to'], 'allow_to');
52
+ const allowTo = allowToRaw.map((s, i) => {
53
+ if (!ADDR_RE.test(s)) {
54
+ throw new PolicyLoadError(`policy.allow_to[${i}] must be 0x-prefixed 20-byte address`);
55
+ }
56
+ return s.toLowerCase();
57
+ });
58
+ const maxValueWei = parseMaxValue(raw['max_value_wei']);
59
+ const selectorsRaw = asStringArray(raw['allowed_selectors'], 'allowed_selectors');
60
+ const allowedSelectors = selectorsRaw.map((s, i) => {
61
+ if (!SELECTOR_RE.test(s)) {
62
+ throw new PolicyLoadError(`policy.allowed_selectors[${i}] must be 0x + 4 hex bytes (got ${JSON.stringify(s)})`);
63
+ }
64
+ return s.toLowerCase();
65
+ });
66
+ const allowMessageSigning = asBool(raw['allow_message_signing'], 'allow_message_signing', false);
67
+ const allowTypedData = asBool(raw['allow_typed_data'], 'allow_typed_data', false);
68
+ return {
69
+ mode: 'strict',
70
+ chainIds,
71
+ allowTo,
72
+ maxValueWei,
73
+ allowedSelectors,
74
+ allowMessageSigning,
75
+ allowTypedData,
76
+ };
77
+ }
78
+ /**
79
+ * A PolicyResolver that returns the same permissive policy for every handle.
80
+ * Useful for tests that want to exercise sign methods without provisioning
81
+ * a TOML file per portal.
82
+ */
83
+ export function permissivePolicyResolver() {
84
+ const policy = {
85
+ mode: 'permissive',
86
+ chainIds: [],
87
+ allowTo: [],
88
+ maxValueWei: 0n,
89
+ allowedSelectors: [],
90
+ allowMessageSigning: true,
91
+ allowTypedData: true,
92
+ };
93
+ return { resolve: () => policy };
94
+ }
95
+ /**
96
+ * File-backed PolicyResolver: reads ~/.sigil/policy/<handle>.toml every time
97
+ * resolve() is called. Sign calls are human-paced so the read is cheap; the
98
+ * fresh read also means policy edits take effect immediately (no daemon
99
+ * restart).
100
+ */
101
+ export class FileSystemPolicyResolver {
102
+ #policyDir;
103
+ constructor(policyDir) {
104
+ this.#policyDir = policyDir;
105
+ }
106
+ resolve(handle) {
107
+ const path = join(this.#policyDir, `${handle}.toml`);
108
+ let source;
109
+ try {
110
+ source = readFileSync(path, 'utf8');
111
+ }
112
+ catch (err) {
113
+ if (err.code === 'ENOENT') {
114
+ throw new PolicyLoadError(`policy: no policy file for portal "${handle}" at ${path} — run "sigil portal add" to provision`);
115
+ }
116
+ throw new PolicyLoadError(`policy: failed to read ${path}`, err);
117
+ }
118
+ return parsePolicy(source);
119
+ }
120
+ }
121
+ // ---------------------------------------------------------------------------
122
+ // Helpers
123
+ // ---------------------------------------------------------------------------
124
+ function asNumberArray(v, name, opts = {}) {
125
+ if (v === undefined) {
126
+ if (opts.required)
127
+ throw new PolicyLoadError(`policy.${name} is required in strict mode`);
128
+ return [];
129
+ }
130
+ if (!Array.isArray(v))
131
+ throw new PolicyLoadError(`policy.${name} must be an array`);
132
+ return v.map((item, i) => {
133
+ if (typeof item !== 'number') {
134
+ throw new PolicyLoadError(`policy.${name}[${i}] must be a number (got ${typeof item})`);
135
+ }
136
+ return item;
137
+ });
138
+ }
139
+ function asStringArray(v, name) {
140
+ if (v === undefined)
141
+ return [];
142
+ if (!Array.isArray(v))
143
+ throw new PolicyLoadError(`policy.${name} must be an array`);
144
+ return v.map((item, i) => {
145
+ if (typeof item !== 'string') {
146
+ throw new PolicyLoadError(`policy.${name}[${i}] must be a string (got ${typeof item})`);
147
+ }
148
+ return item;
149
+ });
150
+ }
151
+ function asBool(v, name, def) {
152
+ if (v === undefined)
153
+ return def;
154
+ if (typeof v !== 'boolean') {
155
+ throw new PolicyLoadError(`policy.${name} must be a boolean (got ${typeof v})`);
156
+ }
157
+ return v;
158
+ }
159
+ function parseMaxValue(v) {
160
+ if (v === undefined)
161
+ return 0n;
162
+ if (typeof v !== 'string') {
163
+ throw new PolicyLoadError(`policy.max_value_wei must be a decimal string (e.g. "100000000000000000"); got ${typeof v}`);
164
+ }
165
+ if (!DEC_RE.test(v)) {
166
+ throw new PolicyLoadError(`policy.max_value_wei must be a decimal integer string (got ${JSON.stringify(v)})`);
167
+ }
168
+ return BigInt(v);
169
+ }
170
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/policy/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * TOML template strings written by `sigil portal add`. Hand-written rather
3
+ * than serialized so we can include explanatory comments — TOML serializers
4
+ * generally strip those.
5
+ */
6
+ export declare const PERMISSIVE_TEMPLATE = "# sigil policy file \u2014 permissive mode (default)\n#\n# This portal will sign anything the agent asks for. Your private key is\n# still encrypted at rest and never enters Claude's context, but signing\n# authority is unbounded.\n#\n# To restrict what this portal can sign, run:\n#\n# sigil portal remove <handle>\n# sigil portal add <handle> --key-file <path> --strict\n#\n# ...and edit the resulting policy file. Or just change \"permissive\" below\n# to \"strict\" and add the rules in the commented template at:\n# https://github.com/cdrn/sigil#policy-engine\n\nmode = \"permissive\"\n";
7
+ export declare const STRICT_TEMPLATE = "# sigil policy file \u2014 strict mode\n#\n# Every sign request is checked against the rules below before the key is\n# used. Edit the values to fit your portal. Anything you leave at the\n# default-zero/empty state will deny.\n\nmode = \"strict\"\n\n# Allowed chain IDs (decimal). At least one is required.\n# 1 = ethereum mainnet\n# 8453 = base\n# 42161 = arbitrum one\n# 10 = optimism\n# 11155111 = sepolia testnet\nchain_ids = [1]\n\n# Allowed destination addresses (lowercase 0x-prefixed). Empty = no tx allowed.\n# Example:\n# allow_to = [\"0x000000000000000000000000000000000000dead\"]\nallow_to = []\n\n# Per-tx value cap in wei. Default 0 = no ETH sends allowed at all.\n# 0.1 ether = \"100000000000000000\"\n# 1 ether = \"1000000000000000000\"\n# Quoted because uint256 doesn't fit in a TOML integer.\nmax_value_wei = \"0\"\n\n# 4-byte function selectors that are callable. Empty = pure ETH sends only.\n# Common selectors:\n# \"0xa9059cbb\" ERC-20 transfer(address,uint256)\n# \"0x095ea7b3\" ERC-20 approve(address,uint256)\n# \"0x23b872dd\" ERC-20 transferFrom(address,address,uint256)\nallowed_selectors = []\n\n# EIP-191 personal_sign \u2014 typically safe (used by Sign-In With Ethereum and\n# similar login flows). Set true to permit.\nallow_message_signing = false\n\n# EIP-712 typed data \u2014 CAN authorize off-chain financial actions (Permit,\n# OpenSea orders, gasless approvals). Treat with the same care as signing\n# transactions. Set true to permit.\nallow_typed_data = false\n";
8
+ export type PolicyMode = 'permissive' | 'strict';
9
+ export declare function policyTemplate(mode: PolicyMode): string;
10
+ //# sourceMappingURL=template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../../src/policy/template.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,mBAAmB,wlBAgB/B,CAAC;AAEF,eAAO,MAAM,eAAe,2/CA0C3B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,QAAQ,CAAC;AAEjD,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAEvD"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * TOML template strings written by `sigil portal add`. Hand-written rather
3
+ * than serialized so we can include explanatory comments — TOML serializers
4
+ * generally strip those.
5
+ */
6
+ export const PERMISSIVE_TEMPLATE = `# sigil policy file — permissive mode (default)
7
+ #
8
+ # This portal will sign anything the agent asks for. Your private key is
9
+ # still encrypted at rest and never enters Claude's context, but signing
10
+ # authority is unbounded.
11
+ #
12
+ # To restrict what this portal can sign, run:
13
+ #
14
+ # sigil portal remove <handle>
15
+ # sigil portal add <handle> --key-file <path> --strict
16
+ #
17
+ # ...and edit the resulting policy file. Or just change "permissive" below
18
+ # to "strict" and add the rules in the commented template at:
19
+ # https://github.com/cdrn/sigil#policy-engine
20
+
21
+ mode = "permissive"
22
+ `;
23
+ export const STRICT_TEMPLATE = `# sigil policy file — strict mode
24
+ #
25
+ # Every sign request is checked against the rules below before the key is
26
+ # used. Edit the values to fit your portal. Anything you leave at the
27
+ # default-zero/empty state will deny.
28
+
29
+ mode = "strict"
30
+
31
+ # Allowed chain IDs (decimal). At least one is required.
32
+ # 1 = ethereum mainnet
33
+ # 8453 = base
34
+ # 42161 = arbitrum one
35
+ # 10 = optimism
36
+ # 11155111 = sepolia testnet
37
+ chain_ids = [1]
38
+
39
+ # Allowed destination addresses (lowercase 0x-prefixed). Empty = no tx allowed.
40
+ # Example:
41
+ # allow_to = ["0x000000000000000000000000000000000000dead"]
42
+ allow_to = []
43
+
44
+ # Per-tx value cap in wei. Default 0 = no ETH sends allowed at all.
45
+ # 0.1 ether = "100000000000000000"
46
+ # 1 ether = "1000000000000000000"
47
+ # Quoted because uint256 doesn't fit in a TOML integer.
48
+ max_value_wei = "0"
49
+
50
+ # 4-byte function selectors that are callable. Empty = pure ETH sends only.
51
+ # Common selectors:
52
+ # "0xa9059cbb" ERC-20 transfer(address,uint256)
53
+ # "0x095ea7b3" ERC-20 approve(address,uint256)
54
+ # "0x23b872dd" ERC-20 transferFrom(address,address,uint256)
55
+ allowed_selectors = []
56
+
57
+ # EIP-191 personal_sign — typically safe (used by Sign-In With Ethereum and
58
+ # similar login flows). Set true to permit.
59
+ allow_message_signing = false
60
+
61
+ # EIP-712 typed data — CAN authorize off-chain financial actions (Permit,
62
+ # OpenSea orders, gasless approvals). Treat with the same care as signing
63
+ # transactions. Set true to permit.
64
+ allow_typed_data = false
65
+ `;
66
+ export function policyTemplate(mode) {
67
+ return mode === 'permissive' ? PERMISSIVE_TEMPLATE : STRICT_TEMPLATE;
68
+ }
69
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../../src/policy/template.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;CAgBlC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0C9B,CAAC;AAIF,MAAM,UAAU,cAAc,CAAC,IAAgB;IAC7C,OAAO,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,eAAe,CAAC;AACvE,CAAC"}
@@ -0,0 +1,62 @@
1
+ import type { SignableTx, TypedData } from '../eth/index.js';
2
+ /**
3
+ * A loaded + validated per-portal policy.
4
+ *
5
+ * Stored on disk at ~/.sigil/policy/<handle>.toml; loaded once per sign call
6
+ * (cheap — file is small, sign calls are human-paced).
7
+ *
8
+ * Two modes:
9
+ * - "permissive": evaluator returns Allow for everything. The other fields
10
+ * are ignored. This is the default written by `sigil portal add`; the
11
+ * user is opting into key isolation without any signing constraints.
12
+ * - "strict": every field below is enforced. `sigil portal add --strict`
13
+ * writes a template with conservative defaults the user fills in.
14
+ *
15
+ * `max_value_wei` is a string in the TOML and is parsed to bigint at load
16
+ * time — uint256 doesn't fit in TOML's int64.
17
+ */
18
+ export interface Policy {
19
+ mode: 'permissive' | 'strict';
20
+ chainIds: readonly number[];
21
+ /** Lowercase 0x-prefixed addresses, normalized at load time. */
22
+ allowTo: readonly string[];
23
+ /** Per-tx value cap, in wei. 0n means "no value sends allowed at all". */
24
+ maxValueWei: bigint;
25
+ /** 4-byte function selectors, lowercase 0x-prefixed, normalized at load time. */
26
+ allowedSelectors: readonly string[];
27
+ allowMessageSigning: boolean;
28
+ allowTypedData: boolean;
29
+ }
30
+ /** What the evaluator gets asked about. */
31
+ export type PolicyRequest = {
32
+ kind: 'transaction';
33
+ tx: SignableTx;
34
+ } | {
35
+ kind: 'message';
36
+ messageBytes: Buffer;
37
+ } | {
38
+ kind: 'typed_data';
39
+ typedData: TypedData;
40
+ };
41
+ /** Evaluator output. Reason is human-readable + audit-loggable on Deny. */
42
+ export type PolicyDecision = {
43
+ allow: true;
44
+ } | {
45
+ allow: false;
46
+ reason: string;
47
+ };
48
+ /**
49
+ * Resolves a portal handle to its current policy. Wrapped in an interface so
50
+ * tests can inject a constant policy without going through the filesystem.
51
+ *
52
+ * Throws PolicyLoadError if the file is missing or malformed. Sign methods
53
+ * treat any throw as a hard Deny + audit it.
54
+ */
55
+ export interface PolicyResolver {
56
+ resolve(handle: string): Policy;
57
+ }
58
+ export declare class PolicyLoadError extends Error {
59
+ readonly cause?: unknown;
60
+ constructor(message: string, cause?: unknown);
61
+ }
62
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/policy/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE7D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,YAAY,GAAG,QAAQ,CAAC;IAC9B,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,gEAAgE;IAChE,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,2CAA2C;AAC3C,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,EAAE,EAAE,UAAU,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,SAAS,CAAA;CAAE,CAAC;AAEjD,2EAA2E;AAC3E,MAAM,MAAM,cAAc,GACtB;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GACf;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,SAAkB,KAAK,CAAC,EAAE,OAAO,CAAC;gBACtB,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAK7C"}
@@ -0,0 +1,10 @@
1
+ export class PolicyLoadError extends Error {
2
+ cause;
3
+ constructor(message, cause) {
4
+ super(message);
5
+ this.name = 'PolicyLoadError';
6
+ if (cause !== undefined)
7
+ this.cause = cause;
8
+ }
9
+ }
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/policy/types.ts"],"names":[],"mappings":"AAqDA,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACtB,KAAK,CAAW;IAClC,YAAY,OAAe,EAAE,KAAe;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAC9C,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigild",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "mcpName": "io.github.cdrn/sigil",
5
5
  "description": "Claude can sign, but never see. MCP server + CLI that keeps private keys out of the LLM's context window.",
6
6
  "license": "Apache-2.0",
@@ -53,6 +53,7 @@
53
53
  "test:watch": "node --watch --test 'dist/test/**/*.test.js'"
54
54
  },
55
55
  "dependencies": {
56
+ "@iarna/toml": "2.2.5",
56
57
  "@noble/ciphers": "1.3.0",
57
58
  "@noble/hashes": "1.8.0",
58
59
  "@noble/secp256k1": "3.1.0"