sigild 0.0.1 → 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.
- package/README.md +142 -33
- package/THREAT_MODEL.md +47 -19
- package/dist/src/bin/sigil-hook-post.d.ts +3 -0
- package/dist/src/bin/sigil-hook-post.d.ts.map +1 -0
- package/dist/src/bin/sigil-hook-post.js +15 -0
- package/dist/src/bin/sigil-hook-post.js.map +1 -0
- package/dist/src/bin/sigil-hook-pre.d.ts +3 -0
- package/dist/src/bin/sigil-hook-pre.d.ts.map +1 -0
- package/dist/src/bin/sigil-hook-pre.js +18 -0
- package/dist/src/bin/sigil-hook-pre.js.map +1 -0
- package/dist/src/bin/sigil-mcp.d.ts +3 -0
- package/dist/src/bin/sigil-mcp.d.ts.map +1 -0
- package/dist/src/bin/sigil-mcp.js +90 -0
- package/dist/src/bin/sigil-mcp.js.map +1 -0
- package/dist/src/bin/sigil.d.ts +3 -0
- package/dist/src/bin/sigil.d.ts.map +1 -0
- package/dist/src/bin/sigil.js +9 -0
- package/dist/src/bin/sigil.js.map +1 -0
- package/dist/src/cli/args.d.ts +26 -0
- package/dist/src/cli/args.d.ts.map +1 -0
- package/dist/src/cli/args.js +36 -0
- package/dist/src/cli/args.js.map +1 -0
- package/dist/src/cli/index.d.ts +7 -0
- package/dist/src/cli/index.d.ts.map +1 -0
- package/dist/src/cli/index.js +7 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/cli/main.d.ts +26 -0
- package/dist/src/cli/main.d.ts.map +1 -0
- package/dist/src/cli/main.js +197 -0
- package/dist/src/cli/main.js.map +1 -0
- package/dist/src/cli/paths.d.ts +18 -0
- package/dist/src/cli/paths.d.ts.map +1 -0
- package/dist/src/cli/paths.js +13 -0
- package/dist/src/cli/paths.js.map +1 -0
- package/dist/src/cli/portal.d.ts +59 -0
- package/dist/src/cli/portal.d.ts.map +1 -0
- package/dist/src/cli/portal.js +112 -0
- package/dist/src/cli/portal.js.map +1 -0
- package/dist/src/cli/status.d.ts +28 -0
- package/dist/src/cli/status.d.ts.map +1 -0
- package/dist/src/cli/status.js +59 -0
- package/dist/src/cli/status.js.map +1 -0
- package/dist/src/cli/unlock.d.ts +36 -0
- package/dist/src/cli/unlock.d.ts.map +1 -0
- package/dist/src/cli/unlock.js +77 -0
- package/dist/src/cli/unlock.js.map +1 -0
- package/dist/src/control/client.d.ts +26 -0
- package/dist/src/control/client.d.ts.map +1 -0
- package/dist/src/control/client.js +76 -0
- package/dist/src/control/client.js.map +1 -0
- package/dist/src/control/index.d.ts +4 -0
- package/dist/src/control/index.d.ts.map +1 -0
- package/dist/src/control/index.js +4 -0
- package/dist/src/control/index.js.map +1 -0
- package/dist/src/control/protocol.d.ts +54 -0
- package/dist/src/control/protocol.d.ts.map +1 -0
- package/dist/src/control/protocol.js +60 -0
- package/dist/src/control/protocol.js.map +1 -0
- package/dist/src/control/server.d.ts +52 -0
- package/dist/src/control/server.d.ts.map +1 -0
- package/dist/src/control/server.js +199 -0
- package/dist/src/control/server.js.map +1 -0
- package/dist/src/daemon/handles.d.ts +35 -6
- package/dist/src/daemon/handles.d.ts.map +1 -1
- package/dist/src/daemon/handles.js +83 -28
- package/dist/src/daemon/handles.js.map +1 -1
- package/dist/src/daemon/index.d.ts +2 -3
- package/dist/src/daemon/index.d.ts.map +1 -1
- package/dist/src/daemon/index.js +2 -3
- package/dist/src/daemon/index.js.map +1 -1
- package/dist/src/daemon/methods.d.ts +13 -0
- package/dist/src/daemon/methods.d.ts.map +1 -1
- package/dist/src/daemon/methods.js +50 -1
- package/dist/src/daemon/methods.js.map +1 -1
- package/dist/src/hooks/command-scanner.d.ts +5 -0
- package/dist/src/hooks/command-scanner.d.ts.map +1 -0
- package/dist/src/hooks/command-scanner.js +117 -0
- package/dist/src/hooks/command-scanner.js.map +1 -0
- package/dist/src/hooks/glob.d.ts +8 -0
- package/dist/src/hooks/glob.d.ts.map +1 -0
- package/dist/src/hooks/glob.js +98 -0
- package/dist/src/hooks/glob.js.map +1 -0
- package/dist/src/hooks/index.d.ts +9 -0
- package/dist/src/hooks/index.d.ts.map +1 -0
- package/dist/src/hooks/index.js +9 -0
- package/dist/src/hooks/index.js.map +1 -0
- package/dist/src/hooks/install.d.ts +29 -0
- package/dist/src/hooks/install.d.ts.map +1 -0
- package/dist/src/hooks/install.js +86 -0
- package/dist/src/hooks/install.js.map +1 -0
- package/dist/src/hooks/path-blocker.d.ts +29 -0
- package/dist/src/hooks/path-blocker.d.ts.map +1 -0
- package/dist/src/hooks/path-blocker.js +59 -0
- package/dist/src/hooks/path-blocker.js.map +1 -0
- package/dist/src/hooks/post-tool-use.d.ts +13 -0
- package/dist/src/hooks/post-tool-use.d.ts.map +1 -0
- package/dist/src/hooks/post-tool-use.js +45 -0
- package/dist/src/hooks/post-tool-use.js.map +1 -0
- package/dist/src/hooks/pre-tool-use.d.ts +8 -0
- package/dist/src/hooks/pre-tool-use.d.ts.map +1 -0
- package/dist/src/hooks/pre-tool-use.js +38 -0
- package/dist/src/hooks/pre-tool-use.js.map +1 -0
- package/dist/src/hooks/protocol.d.ts +41 -0
- package/dist/src/hooks/protocol.d.ts.map +1 -0
- package/dist/src/hooks/protocol.js +27 -0
- package/dist/src/hooks/protocol.js.map +1 -0
- package/dist/src/hooks/redactor.d.ts +19 -0
- package/dist/src/hooks/redactor.d.ts.map +1 -0
- package/dist/src/hooks/redactor.js +71 -0
- package/dist/src/hooks/redactor.js.map +1 -0
- package/dist/src/mcp/index.d.ts +4 -0
- package/dist/src/mcp/index.d.ts.map +1 -0
- package/dist/src/mcp/index.js +4 -0
- package/dist/src/mcp/index.js.map +1 -0
- package/dist/src/mcp/protocol.d.ts +98 -0
- package/dist/src/mcp/protocol.d.ts.map +1 -0
- package/dist/src/mcp/protocol.js +79 -0
- package/dist/src/mcp/protocol.js.map +1 -0
- package/dist/src/mcp/server.d.ts +46 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +108 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools.d.ts +16 -0
- package/dist/src/mcp/tools.d.ts.map +1 -0
- package/dist/src/mcp/tools.js +117 -0
- package/dist/src/mcp/tools.js.map +1 -0
- package/dist/src/policy/evaluate.d.ts +13 -0
- package/dist/src/policy/evaluate.d.ts.map +1 -0
- package/dist/src/policy/evaluate.js +73 -0
- package/dist/src/policy/evaluate.js.map +1 -0
- package/dist/src/policy/index.d.ts +5 -0
- package/dist/src/policy/index.d.ts.map +1 -0
- package/dist/src/policy/index.js +5 -0
- package/dist/src/policy/index.js.map +1 -0
- package/dist/src/policy/loader.d.ts +33 -0
- package/dist/src/policy/loader.d.ts.map +1 -0
- package/dist/src/policy/loader.js +170 -0
- package/dist/src/policy/loader.js.map +1 -0
- package/dist/src/policy/template.d.ts +10 -0
- package/dist/src/policy/template.d.ts.map +1 -0
- package/dist/src/policy/template.js +69 -0
- package/dist/src/policy/template.js.map +1 -0
- package/dist/src/policy/types.d.ts +62 -0
- package/dist/src/policy/types.d.ts.map +1 -0
- package/dist/src/policy/types.js +10 -0
- package/dist/src/policy/types.js.map +1 -0
- package/package.json +9 -3
- package/dist/src/bin/sigild.d.ts +0 -3
- package/dist/src/bin/sigild.d.ts.map +0 -1
- package/dist/src/bin/sigild.js +0 -30
- package/dist/src/bin/sigild.js.map +0 -1
- package/dist/src/daemon/rpc.d.ts +0 -61
- package/dist/src/daemon/rpc.d.ts.map +0 -1
- package/dist/src/daemon/rpc.js +0 -76
- package/dist/src/daemon/rpc.js.map +0 -1
- package/dist/src/daemon/runtime.d.ts +0 -40
- package/dist/src/daemon/runtime.d.ts.map +0 -1
- package/dist/src/daemon/runtime.js +0 -61
- package/dist/src/daemon/runtime.js.map +0 -1
- package/dist/src/daemon/server.d.ts +0 -53
- package/dist/src/daemon/server.d.ts.map +0 -1
- package/dist/src/daemon/server.js +0 -103
- package/dist/src/daemon/server.js.map +0 -1
|
@@ -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":"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"}
|
|
@@ -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 @@
|
|
|
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,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sigild",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"mcpName": "io.github.cdrn/sigil",
|
|
5
|
+
"description": "Claude can sign, but never see. MCP server + CLI that keeps private keys out of the LLM's context window.",
|
|
5
6
|
"license": "Apache-2.0",
|
|
6
7
|
"author": "Chris Doran",
|
|
7
8
|
"homepage": "https://github.com/cdrn/sigil#readme",
|
|
@@ -30,7 +31,11 @@
|
|
|
30
31
|
],
|
|
31
32
|
"type": "module",
|
|
32
33
|
"bin": {
|
|
33
|
-
"
|
|
34
|
+
"sigil": "dist/src/bin/sigil.js",
|
|
35
|
+
"sigil-mcp": "dist/src/bin/sigil-mcp.js",
|
|
36
|
+
"sigild": "dist/src/bin/sigil-mcp.js",
|
|
37
|
+
"sigil-hook-pre": "dist/src/bin/sigil-hook-pre.js",
|
|
38
|
+
"sigil-hook-post": "dist/src/bin/sigil-hook-post.js"
|
|
34
39
|
},
|
|
35
40
|
"files": [
|
|
36
41
|
"dist/src/**/*",
|
|
@@ -48,6 +53,7 @@
|
|
|
48
53
|
"test:watch": "node --watch --test 'dist/test/**/*.test.js'"
|
|
49
54
|
},
|
|
50
55
|
"dependencies": {
|
|
56
|
+
"@iarna/toml": "2.2.5",
|
|
51
57
|
"@noble/ciphers": "1.3.0",
|
|
52
58
|
"@noble/hashes": "1.8.0",
|
|
53
59
|
"@noble/secp256k1": "3.1.0"
|
package/dist/src/bin/sigild.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sigild.d.ts","sourceRoot":"","sources":["../../../src/bin/sigild.ts"],"names":[],"mappings":""}
|
package/dist/src/bin/sigild.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import { readPassphrase } from '../daemon/passphrase.js';
|
|
5
|
-
import { runDaemon } from '../daemon/runtime.js';
|
|
6
|
-
const sigilHome = process.env['SIGIL_HOME'] ?? join(homedir(), '.sigil');
|
|
7
|
-
let shutting = false;
|
|
8
|
-
async function main() {
|
|
9
|
-
const handle = await runDaemon({
|
|
10
|
-
sigilHome,
|
|
11
|
-
passphrase: () => readPassphrase('sigil passphrase: '),
|
|
12
|
-
onLog: (e) => process.stderr.write(JSON.stringify(e) + '\n'),
|
|
13
|
-
});
|
|
14
|
-
process.stderr.write(`sigild ready: ${handle.portals} portal(s) loaded, listening on ${handle.socketPath}\n`);
|
|
15
|
-
const shutdown = async (signal) => {
|
|
16
|
-
if (shutting)
|
|
17
|
-
return;
|
|
18
|
-
shutting = true;
|
|
19
|
-
process.stderr.write(`sigild: ${signal} received, shutting down\n`);
|
|
20
|
-
await handle.shutdown();
|
|
21
|
-
process.exit(0);
|
|
22
|
-
};
|
|
23
|
-
process.on('SIGINT', () => { void shutdown('SIGINT'); });
|
|
24
|
-
process.on('SIGTERM', () => { void shutdown('SIGTERM'); });
|
|
25
|
-
}
|
|
26
|
-
main().catch((err) => {
|
|
27
|
-
process.stderr.write(`sigild: ${err.message}\n`);
|
|
28
|
-
process.exit(1);
|
|
29
|
-
});
|
|
30
|
-
//# sourceMappingURL=sigild.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sigild.js","sourceRoot":"","sources":["../../../src/bin/sigild.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AAEzE,IAAI,QAAQ,GAAG,KAAK,CAAC;AAErB,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC;QAC7B,SAAS;QACT,UAAU,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,oBAAoB,CAAC;QACtD,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,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iBAAiB,MAAM,CAAC,OAAO,mCAAmC,MAAM,CAAC,UAAU,IAAI,CACxF,CAAC;IAEF,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAiB,EAAE;QACvD,IAAI,QAAQ;YAAE,OAAO;QACrB,QAAQ,GAAG,IAAI,CAAC;QAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,MAAM,4BAA4B,CAAC,CAAC;QACpE,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;IAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;IACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/src/daemon/rpc.d.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JSON-RPC 2.0 over newline-delimited JSON (NDJSON).
|
|
3
|
-
* Pure functions only — no IO. The server in server.ts wires this onto sockets.
|
|
4
|
-
*
|
|
5
|
-
* We use the strict JSON-RPC 2.0 envelope: every request has `jsonrpc: "2.0"`,
|
|
6
|
-
* a method, and either an id (for requests expecting a response) or no id (for
|
|
7
|
-
* notifications, which sigil currently rejects since every sign decision needs
|
|
8
|
-
* to round-trip through the audit log).
|
|
9
|
-
*/
|
|
10
|
-
export declare const RPC_VERSION = "2.0";
|
|
11
|
-
export type RpcId = string | number | null;
|
|
12
|
-
export interface RpcRequest {
|
|
13
|
-
jsonrpc: '2.0';
|
|
14
|
-
id: RpcId;
|
|
15
|
-
method: string;
|
|
16
|
-
params: unknown;
|
|
17
|
-
}
|
|
18
|
-
export interface RpcSuccess {
|
|
19
|
-
jsonrpc: '2.0';
|
|
20
|
-
id: RpcId;
|
|
21
|
-
result: unknown;
|
|
22
|
-
}
|
|
23
|
-
export interface RpcErrorObject {
|
|
24
|
-
code: number;
|
|
25
|
-
message: string;
|
|
26
|
-
data?: unknown;
|
|
27
|
-
}
|
|
28
|
-
export interface RpcError {
|
|
29
|
-
jsonrpc: '2.0';
|
|
30
|
-
id: RpcId;
|
|
31
|
-
error: RpcErrorObject;
|
|
32
|
-
}
|
|
33
|
-
export type RpcResponse = RpcSuccess | RpcError;
|
|
34
|
-
export declare const RPC_PARSE_ERROR = -32700;
|
|
35
|
-
export declare const RPC_INVALID_REQUEST = -32600;
|
|
36
|
-
export declare const RPC_METHOD_NOT_FOUND = -32601;
|
|
37
|
-
export declare const RPC_INVALID_PARAMS = -32602;
|
|
38
|
-
export declare const RPC_INTERNAL_ERROR = -32603;
|
|
39
|
-
export declare const RPC_PORTAL_NOT_FOUND = -32000;
|
|
40
|
-
export declare const RPC_POLICY_DENIED = -32001;
|
|
41
|
-
export declare const RPC_INVALID_PAYLOAD = -32002;
|
|
42
|
-
export type ParseResult = {
|
|
43
|
-
kind: 'request';
|
|
44
|
-
request: RpcRequest;
|
|
45
|
-
} | {
|
|
46
|
-
kind: 'parse_error';
|
|
47
|
-
} | {
|
|
48
|
-
kind: 'invalid';
|
|
49
|
-
id: RpcId;
|
|
50
|
-
reason: string;
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* Parse a single NDJSON line into a JSON-RPC request.
|
|
54
|
-
* Returns either a valid request, a parse_error (if the line is not JSON), or
|
|
55
|
-
* an invalid envelope along with the id that should be echoed in the error
|
|
56
|
-
* response (which is null if the id couldn't be extracted).
|
|
57
|
-
*/
|
|
58
|
-
export declare function parseRequest(line: string): ParseResult;
|
|
59
|
-
export declare function encodeResponse(id: RpcId, result: unknown): string;
|
|
60
|
-
export declare function encodeError(id: RpcId, code: number, message: string, data?: unknown): string;
|
|
61
|
-
//# sourceMappingURL=rpc.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../../../src/daemon/rpc.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,WAAW,QAAQ,CAAC;AAEjC,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,cAAc,CAAC;CACvB;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC;AAGhD,eAAO,MAAM,eAAe,SAAS,CAAC;AACtC,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAC1C,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,eAAO,MAAM,kBAAkB,SAAS,CAAC;AACzC,eAAO,MAAM,kBAAkB,SAAS,CAAC;AAGzC,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,eAAO,MAAM,iBAAiB,SAAS,CAAC;AACxC,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAE1C,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAuCtD;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAGjE;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAI5F"}
|