@crediolabs/policy-builder-cli 0.1.18 → 0.2.0
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 +5 -3
- package/dist/bin/policy-builder.js +9 -0
- package/dist/src/commands/merge.d.ts +2 -0
- package/dist/src/commands/merge.js +58 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist-cjs/src/commands/merge.d.ts +2 -0
- package/dist-cjs/src/commands/merge.js +61 -0
- package/dist-cjs/src/index.d.ts +1 -0
- package/dist-cjs/src/index.js +3 -1
- package/package.json +2 -2
- package/src/commands/merge.ts +65 -0
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -58,9 +58,11 @@ small: the two commands that fit a pipe.
|
|
|
58
58
|
|
|
59
59
|
## Security model
|
|
60
60
|
|
|
61
|
-
The CLI holds no key material and signs nothing.
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
The CLI holds no key material and signs nothing. See the
|
|
62
|
+
[architecture document](https://github.com/untangledfinance/octogate/blob/main/docs/architecture.md)
|
|
63
|
+
for what the on-chain interpreter does and does not enforce, and the
|
|
64
|
+
[repository README](https://github.com/untangledfinance/octogate#readme) for
|
|
65
|
+
the contracts' audit status.
|
|
64
66
|
|
|
65
67
|
## License
|
|
66
68
|
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
// `command + subcommand-flags + global-flags` and dispatches to the matching
|
|
27
27
|
// command body. Bad args -> CliError -> non-zero exit (JSON envelope under
|
|
28
28
|
// --json).
|
|
29
|
+
import { runMergeCommand } from "../src/commands/merge.js";
|
|
29
30
|
import { runRecordCommand } from "../src/commands/record.js";
|
|
30
31
|
import { runSynthesizeCommand } from "../src/commands/synthesize.js";
|
|
31
32
|
import { emitCliError, parseFlags } from "../src/output.js";
|
|
@@ -47,6 +48,10 @@ async function main() {
|
|
|
47
48
|
await runSynthesizeCommand(subcommandArgs, flags);
|
|
48
49
|
return;
|
|
49
50
|
}
|
|
51
|
+
case 'merge': {
|
|
52
|
+
await runMergeCommand(subcommandArgs, flags);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
50
55
|
case 'help':
|
|
51
56
|
case '--help':
|
|
52
57
|
case '-h':
|
|
@@ -68,6 +73,10 @@ function printHelp() {
|
|
|
68
73
|
|
|
69
74
|
Usage:
|
|
70
75
|
policy-builder record --network <mainnet|testnet> --hash <tx> | --xdr <b64>
|
|
76
|
+
policy-builder merge --smart-account <C...> --source-account <G...>
|
|
77
|
+
--rule-id <n> --predicate <b64> --step <detach|reinstall>
|
|
78
|
+
[--network <mainnet|testnet>] [--rpc-url <url>]
|
|
79
|
+
[--json] [--quiet] [--out <path>]
|
|
71
80
|
[--json] [--quiet] [--out <path>]
|
|
72
81
|
policy-builder synthesize --mandate <path.json>
|
|
73
82
|
[--oz-config <path.json>] [--confidence <0..1>]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// packages/policy-builder-cli/src/commands/merge.ts
|
|
2
|
+
//
|
|
3
|
+
// `policy-builder merge` subcommand. The tightening remedy for a cross-rule
|
|
4
|
+
// authority overlap.
|
|
5
|
+
//
|
|
6
|
+
// OpenZeppelin enforces only the policies of the context rule a signer NAMES,
|
|
7
|
+
// so a signer in several rules picks which one applies and their authority is
|
|
8
|
+
// the maximum over the matching rules. Adding a second, tighter rule therefore
|
|
9
|
+
// restricts nothing. To actually tighten, the restriction has to become ONE
|
|
10
|
+
// predicate: the conjunction of the installed one and the new one.
|
|
11
|
+
//
|
|
12
|
+
// Two transactions, in order, because `add_policy` refuses a policy already
|
|
13
|
+
// attached to the rule:
|
|
14
|
+
//
|
|
15
|
+
// policy-builder merge --step detach ... sign and submit, wait
|
|
16
|
+
// policy-builder merge --step reinstall ... sign and submit
|
|
17
|
+
//
|
|
18
|
+
// The detach uninstalls the policy, which resets every counter on the rule and
|
|
19
|
+
// leaves it unpoliced until the reinstall confirms. Both are reported as
|
|
20
|
+
// warnings rather than left for the operator to discover afterwards.
|
|
21
|
+
import { runMergePolicy } from '@crediolabs/policy-synth/run';
|
|
22
|
+
import { CliError, formatToolResponse, parsePairs } from "../output.js";
|
|
23
|
+
function missing(message) {
|
|
24
|
+
return new CliError({
|
|
25
|
+
code: 'CLI_MISSING_ARG',
|
|
26
|
+
message,
|
|
27
|
+
severity: 'error',
|
|
28
|
+
retryable: false,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function required(pairs, name) {
|
|
32
|
+
const value = pairs[name];
|
|
33
|
+
if (!value)
|
|
34
|
+
throw missing(`merge: --${name} is required`);
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
export async function runMergeCommand(argv, flags) {
|
|
38
|
+
const pairs = parsePairs(argv);
|
|
39
|
+
const step = required(pairs, 'step');
|
|
40
|
+
if (step !== 'detach' && step !== 'reinstall') {
|
|
41
|
+
throw missing("merge: --step must be 'detach' or 'reinstall'");
|
|
42
|
+
}
|
|
43
|
+
const ruleId = Number(required(pairs, 'rule-id'));
|
|
44
|
+
if (!Number.isInteger(ruleId) || ruleId < 0) {
|
|
45
|
+
throw missing('merge: --rule-id must be a non-negative integer');
|
|
46
|
+
}
|
|
47
|
+
const res = await runMergePolicy({
|
|
48
|
+
smartAccount: required(pairs, 'smart-account'),
|
|
49
|
+
sourceAccount: required(pairs, 'source-account'),
|
|
50
|
+
ruleId,
|
|
51
|
+
incomingPredicateBlobBase64: required(pairs, 'predicate'),
|
|
52
|
+
step,
|
|
53
|
+
...(pairs.network ? { network: pairs.network } : {}),
|
|
54
|
+
...(pairs['rpc-url'] ? { rpcUrl: pairs['rpc-url'] } : {}),
|
|
55
|
+
...(pairs['allow-unpinned-rpc-url'] === 'true' ? { allowUnpinnedRpcUrl: true } : {}),
|
|
56
|
+
});
|
|
57
|
+
return formatToolResponse(res, flags);
|
|
58
|
+
}
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// packages/policy-builder-cli/src/index.ts - public re-exports for the CLI package.
|
|
2
|
+
export { runMergeCommand } from "./commands/merge.js";
|
|
2
3
|
export { runRecordCommand } from "./commands/record.js";
|
|
3
4
|
export { runSynthesizeCommand } from "./commands/synthesize.js";
|
|
4
5
|
export { formatToolResponse, readJsonFile, writeJsonFile } from "./output.js";
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// packages/policy-builder-cli/src/commands/merge.ts
|
|
3
|
+
//
|
|
4
|
+
// `policy-builder merge` subcommand. The tightening remedy for a cross-rule
|
|
5
|
+
// authority overlap.
|
|
6
|
+
//
|
|
7
|
+
// OpenZeppelin enforces only the policies of the context rule a signer NAMES,
|
|
8
|
+
// so a signer in several rules picks which one applies and their authority is
|
|
9
|
+
// the maximum over the matching rules. Adding a second, tighter rule therefore
|
|
10
|
+
// restricts nothing. To actually tighten, the restriction has to become ONE
|
|
11
|
+
// predicate: the conjunction of the installed one and the new one.
|
|
12
|
+
//
|
|
13
|
+
// Two transactions, in order, because `add_policy` refuses a policy already
|
|
14
|
+
// attached to the rule:
|
|
15
|
+
//
|
|
16
|
+
// policy-builder merge --step detach ... sign and submit, wait
|
|
17
|
+
// policy-builder merge --step reinstall ... sign and submit
|
|
18
|
+
//
|
|
19
|
+
// The detach uninstalls the policy, which resets every counter on the rule and
|
|
20
|
+
// leaves it unpoliced until the reinstall confirms. Both are reported as
|
|
21
|
+
// warnings rather than left for the operator to discover afterwards.
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.runMergeCommand = runMergeCommand;
|
|
24
|
+
const run_1 = require("@crediolabs/policy-synth/run");
|
|
25
|
+
const output_ts_1 = require("../output.js");
|
|
26
|
+
function missing(message) {
|
|
27
|
+
return new output_ts_1.CliError({
|
|
28
|
+
code: 'CLI_MISSING_ARG',
|
|
29
|
+
message,
|
|
30
|
+
severity: 'error',
|
|
31
|
+
retryable: false,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function required(pairs, name) {
|
|
35
|
+
const value = pairs[name];
|
|
36
|
+
if (!value)
|
|
37
|
+
throw missing(`merge: --${name} is required`);
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
async function runMergeCommand(argv, flags) {
|
|
41
|
+
const pairs = (0, output_ts_1.parsePairs)(argv);
|
|
42
|
+
const step = required(pairs, 'step');
|
|
43
|
+
if (step !== 'detach' && step !== 'reinstall') {
|
|
44
|
+
throw missing("merge: --step must be 'detach' or 'reinstall'");
|
|
45
|
+
}
|
|
46
|
+
const ruleId = Number(required(pairs, 'rule-id'));
|
|
47
|
+
if (!Number.isInteger(ruleId) || ruleId < 0) {
|
|
48
|
+
throw missing('merge: --rule-id must be a non-negative integer');
|
|
49
|
+
}
|
|
50
|
+
const res = await (0, run_1.runMergePolicy)({
|
|
51
|
+
smartAccount: required(pairs, 'smart-account'),
|
|
52
|
+
sourceAccount: required(pairs, 'source-account'),
|
|
53
|
+
ruleId,
|
|
54
|
+
incomingPredicateBlobBase64: required(pairs, 'predicate'),
|
|
55
|
+
step,
|
|
56
|
+
...(pairs.network ? { network: pairs.network } : {}),
|
|
57
|
+
...(pairs['rpc-url'] ? { rpcUrl: pairs['rpc-url'] } : {}),
|
|
58
|
+
...(pairs['allow-unpinned-rpc-url'] === 'true' ? { allowUnpinnedRpcUrl: true } : {}),
|
|
59
|
+
});
|
|
60
|
+
return (0, output_ts_1.formatToolResponse)(res, flags);
|
|
61
|
+
}
|
package/dist-cjs/src/index.d.ts
CHANGED
package/dist-cjs/src/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// packages/policy-builder-cli/src/index.ts - public re-exports for the CLI package.
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.writeJsonFile = exports.readJsonFile = exports.formatToolResponse = exports.runSynthesizeCommand = exports.runRecordCommand = void 0;
|
|
4
|
+
exports.writeJsonFile = exports.readJsonFile = exports.formatToolResponse = exports.runSynthesizeCommand = exports.runRecordCommand = exports.runMergeCommand = void 0;
|
|
5
|
+
var merge_ts_1 = require("./commands/merge.js");
|
|
6
|
+
Object.defineProperty(exports, "runMergeCommand", { enumerable: true, get: function () { return merge_ts_1.runMergeCommand; } });
|
|
5
7
|
var record_ts_1 = require("./commands/record.js");
|
|
6
8
|
Object.defineProperty(exports, "runRecordCommand", { enumerable: true, get: function () { return record_ts_1.runRecordCommand; } });
|
|
7
9
|
var synthesize_ts_1 = require("./commands/synthesize.js");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crediolabs/policy-builder-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "CLI wrapper around the OZ policy-synth core (record + synthesize) for solo-dev and CI workflows.",
|
|
6
6
|
"type": "module",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"prepack": "bun run build"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@crediolabs/policy-synth": "0.
|
|
66
|
+
"@crediolabs/policy-synth": "0.2.0",
|
|
67
67
|
"@stellar/stellar-sdk": "14.4.0",
|
|
68
68
|
"zod": "3.25.76"
|
|
69
69
|
},
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// packages/policy-builder-cli/src/commands/merge.ts
|
|
2
|
+
//
|
|
3
|
+
// `policy-builder merge` subcommand. The tightening remedy for a cross-rule
|
|
4
|
+
// authority overlap.
|
|
5
|
+
//
|
|
6
|
+
// OpenZeppelin enforces only the policies of the context rule a signer NAMES,
|
|
7
|
+
// so a signer in several rules picks which one applies and their authority is
|
|
8
|
+
// the maximum over the matching rules. Adding a second, tighter rule therefore
|
|
9
|
+
// restricts nothing. To actually tighten, the restriction has to become ONE
|
|
10
|
+
// predicate: the conjunction of the installed one and the new one.
|
|
11
|
+
//
|
|
12
|
+
// Two transactions, in order, because `add_policy` refuses a policy already
|
|
13
|
+
// attached to the rule:
|
|
14
|
+
//
|
|
15
|
+
// policy-builder merge --step detach ... sign and submit, wait
|
|
16
|
+
// policy-builder merge --step reinstall ... sign and submit
|
|
17
|
+
//
|
|
18
|
+
// The detach uninstalls the policy, which resets every counter on the rule and
|
|
19
|
+
// leaves it unpoliced until the reinstall confirms. Both are reported as
|
|
20
|
+
// warnings rather than left for the operator to discover afterwards.
|
|
21
|
+
|
|
22
|
+
import { runMergePolicy } from '@crediolabs/policy-synth/run'
|
|
23
|
+
import { CliError, type CliFlags, formatToolResponse, parsePairs } from '../output.ts'
|
|
24
|
+
|
|
25
|
+
function missing(message: string): CliError {
|
|
26
|
+
return new CliError({
|
|
27
|
+
code: 'CLI_MISSING_ARG',
|
|
28
|
+
message,
|
|
29
|
+
severity: 'error',
|
|
30
|
+
retryable: false,
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function required(pairs: Record<string, string>, name: string): string {
|
|
35
|
+
const value = pairs[name]
|
|
36
|
+
if (!value) throw missing(`merge: --${name} is required`)
|
|
37
|
+
return value
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function runMergeCommand(argv: ReadonlyArray<string>, flags: CliFlags) {
|
|
41
|
+
const pairs = parsePairs(argv)
|
|
42
|
+
|
|
43
|
+
const step = required(pairs, 'step')
|
|
44
|
+
if (step !== 'detach' && step !== 'reinstall') {
|
|
45
|
+
throw missing("merge: --step must be 'detach' or 'reinstall'")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const ruleId = Number(required(pairs, 'rule-id'))
|
|
49
|
+
if (!Number.isInteger(ruleId) || ruleId < 0) {
|
|
50
|
+
throw missing('merge: --rule-id must be a non-negative integer')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const res = await runMergePolicy({
|
|
54
|
+
smartAccount: required(pairs, 'smart-account'),
|
|
55
|
+
sourceAccount: required(pairs, 'source-account'),
|
|
56
|
+
ruleId,
|
|
57
|
+
incomingPredicateBlobBase64: required(pairs, 'predicate'),
|
|
58
|
+
step,
|
|
59
|
+
...(pairs.network ? { network: pairs.network } : {}),
|
|
60
|
+
...(pairs['rpc-url'] ? { rpcUrl: pairs['rpc-url'] } : {}),
|
|
61
|
+
...(pairs['allow-unpinned-rpc-url'] === 'true' ? { allowUnpinnedRpcUrl: true } : {}),
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return formatToolResponse(res, flags)
|
|
65
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// packages/policy-builder-cli/src/index.ts - public re-exports for the CLI package.
|
|
2
2
|
|
|
3
|
+
export { runMergeCommand } from './commands/merge.ts'
|
|
3
4
|
export { runRecordCommand } from './commands/record.ts'
|
|
4
5
|
export { runSynthesizeCommand } from './commands/synthesize.ts'
|
|
5
6
|
export { formatToolResponse, readJsonFile, writeJsonFile } from './output.ts'
|