@sonisoft/now-sdk-ext-cli 5.1.0 → 5.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 +560 -213
- package/dist/commands/policy/status.d.ts +27 -0
- package/dist/commands/policy/status.d.ts.map +1 -0
- package/dist/commands/policy/status.js +67 -0
- package/dist/commands/policy/status.js.map +1 -0
- package/dist/common/authenticated-command.d.ts +3 -0
- package/dist/common/authenticated-command.d.ts.map +1 -1
- package/dist/common/authenticated-command.js +49 -1
- package/dist/common/authenticated-command.js.map +1 -1
- package/dist/common/policy.d.ts +32 -0
- package/dist/common/policy.d.ts.map +1 -0
- package/dist/common/policy.js +68 -0
- package/dist/common/policy.js.map +1 -0
- package/oclif.manifest.json +1873 -213
- package/package.json +46 -43
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
/**
|
|
3
|
+
* Reports what this invocation is permitted to do, and which layer decided.
|
|
4
|
+
*
|
|
5
|
+
* Exists because precedence bugs are otherwise invisible: a user sees "refused" with no
|
|
6
|
+
* way to tell whether the environment denied it, a flag denied it, or nothing granted
|
|
7
|
+
* it — and the fix is completely different in each case.
|
|
8
|
+
*
|
|
9
|
+
* Extends plain `Command`, not `AuthenticatedCommand`: answering "what may I do" must
|
|
10
|
+
* not require working credentials. Someone diagnosing a refusal should not have to get
|
|
11
|
+
* past auth first.
|
|
12
|
+
*/
|
|
13
|
+
export default class PolicyStatus extends Command {
|
|
14
|
+
static description: string;
|
|
15
|
+
static enableJsonFlag: boolean;
|
|
16
|
+
static examples: string[];
|
|
17
|
+
static flags: {
|
|
18
|
+
'deny-execute': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
19
|
+
'deny-write': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
20
|
+
'read-only': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
21
|
+
};
|
|
22
|
+
run(): Promise<{
|
|
23
|
+
permitted: Record<string, unknown>;
|
|
24
|
+
source: string;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/commands/policy/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAQ,MAAM,aAAa,CAAA;AAK1C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,OAAO;IAC/C,MAAM,CAAC,WAAW,SAIG;IACvB,MAAM,CAAC,cAAc,UAAO;IAC5B,MAAM,CAAC,QAAQ,WAIZ;IACH,MAAM,CAAC,KAAK;;;;MAIT;IAEY,GAAG,IAAI,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAC;CA2ClF"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import { checkRequirement, currentLayers, DENY_ENV } from '@sonisoft/now-sdk-ext-core';
|
|
3
|
+
import { installCliPolicy } from '../../common/policy.js';
|
|
4
|
+
/**
|
|
5
|
+
* Reports what this invocation is permitted to do, and which layer decided.
|
|
6
|
+
*
|
|
7
|
+
* Exists because precedence bugs are otherwise invisible: a user sees "refused" with no
|
|
8
|
+
* way to tell whether the environment denied it, a flag denied it, or nothing granted
|
|
9
|
+
* it — and the fix is completely different in each case.
|
|
10
|
+
*
|
|
11
|
+
* Extends plain `Command`, not `AuthenticatedCommand`: answering "what may I do" must
|
|
12
|
+
* not require working credentials. Someone diagnosing a refusal should not have to get
|
|
13
|
+
* past auth first.
|
|
14
|
+
*/
|
|
15
|
+
export default class PolicyStatus extends Command {
|
|
16
|
+
static description = 'Show what this invocation is permitted to change on the instance, and why.\n\n' +
|
|
17
|
+
'Changes are permitted by default. NEX_POLICY_DENY, set in the environment, ' +
|
|
18
|
+
'outranks every command-line flag — that is the only layer an agent driving this ' +
|
|
19
|
+
'CLI cannot reach.';
|
|
20
|
+
static enableJsonFlag = true;
|
|
21
|
+
static examples = [
|
|
22
|
+
'<%= config.bin %> <%= command.id %>',
|
|
23
|
+
'<%= config.bin %> <%= command.id %> --read-only',
|
|
24
|
+
'NEX_POLICY_DENY=all <%= config.bin %> <%= command.id %>',
|
|
25
|
+
];
|
|
26
|
+
static flags = {
|
|
27
|
+
'deny-execute': Flags.boolean({ description: 'Evaluate as if --deny-execute were passed.' }),
|
|
28
|
+
'deny-write': Flags.boolean({ description: 'Evaluate as if --deny-write were passed.' }),
|
|
29
|
+
'read-only': Flags.boolean({ description: 'Evaluate as if --read-only were passed.' }),
|
|
30
|
+
};
|
|
31
|
+
async run() {
|
|
32
|
+
const { flags } = await this.parse(PolicyStatus);
|
|
33
|
+
const warnings = [];
|
|
34
|
+
installCliPolicy(flags, (m) => warnings.push(m));
|
|
35
|
+
const verbs = ['write', 'execute'];
|
|
36
|
+
const permitted = {};
|
|
37
|
+
for (const verb of verbs) {
|
|
38
|
+
const decision = checkRequirement({ target: 'instance', verbs: [verb] });
|
|
39
|
+
permitted[verb] = { allowed: decision.allowed, decidedBy: decision.decidingLayer };
|
|
40
|
+
}
|
|
41
|
+
const envSet = Boolean(process.env[DENY_ENV]);
|
|
42
|
+
const result = { permitted, source: envSet ? `${DENY_ENV} is set` : 'no environment lockdown' };
|
|
43
|
+
if (!this.jsonEnabled()) {
|
|
44
|
+
this.log('Instance changes');
|
|
45
|
+
for (const verb of verbs) {
|
|
46
|
+
const entry = permitted[verb];
|
|
47
|
+
const mark = entry.allowed ? 'permitted' : 'REFUSED ';
|
|
48
|
+
this.log(` ${verb.padEnd(8)} ${mark} (${entry.decidedBy})`);
|
|
49
|
+
}
|
|
50
|
+
this.log('');
|
|
51
|
+
this.log('Reads are never gated.');
|
|
52
|
+
this.log(envSet
|
|
53
|
+
? `${DENY_ENV} is set in the environment and outranks every flag.`
|
|
54
|
+
: `${DENY_ENV} is not set. Set it in your shell profile or container ` +
|
|
55
|
+
`environment to deny changes in a way a command-line flag cannot undo.`);
|
|
56
|
+
// Ordered, because the order IS the behaviour.
|
|
57
|
+
this.log('');
|
|
58
|
+
this.log('Layers, highest priority first:');
|
|
59
|
+
for (const layer of currentLayers())
|
|
60
|
+
this.log(` ${layer.name}`);
|
|
61
|
+
for (const warning of warnings)
|
|
62
|
+
this.warn(warning);
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/policy/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,9 +6,12 @@ export declare abstract class AuthenticatedCommand<T extends typeof Command> ext
|
|
|
6
6
|
static baseFlags: {
|
|
7
7
|
auth: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
8
8
|
'cred-store': Interfaces.BooleanFlag<boolean>;
|
|
9
|
+
'deny-execute': Interfaces.BooleanFlag<boolean>;
|
|
10
|
+
'deny-write': Interfaces.BooleanFlag<boolean>;
|
|
9
11
|
'log-dir': Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
10
12
|
'log-file': Interfaces.BooleanFlag<boolean>;
|
|
11
13
|
'log-level': Interfaces.OptionFlag<"info" | "debug" | "warn" | "error" | "trace", Interfaces.CustomOptions>;
|
|
14
|
+
'read-only': Interfaces.BooleanFlag<boolean>;
|
|
12
15
|
};
|
|
13
16
|
static enableJsonFlag: boolean;
|
|
14
17
|
protected _logger: Logger;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticated-command.d.ts","sourceRoot":"","sources":["../../src/common/authenticated-command.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAS,UAAU,EAAE,MAAM,aAAa,CAAA;AAExD,OAAO,
|
|
1
|
+
{"version":3,"file":"authenticated-command.d.ts","sourceRoot":"","sources":["../../src/common/authenticated-command.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAS,UAAU,EAAE,MAAM,aAAa,CAAA;AAExD,OAAO,EAAgD,MAAM,EAAE,kBAAkB,EAA8B,MAAM,4BAA4B,CAAC;AAOlJ,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,OAAO,OAAO,IAAI,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,OAAO,oBAAoB,CAAC,WAAW,CAAC,CAAC,CAAA;AAC7H,MAAM,MAAM,IAAI,CAAC,CAAC,SAAS,OAAO,OAAO,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;AAE/E,8BAAsB,oBAAoB,CAAC,CAAC,SAAS,OAAO,OAAO,CAAE,SAAQ,OAAO;IAElF,MAAM,CAAC,SAAS;;;;;;;;;MA4Df;IAEC,MAAM,CAAC,cAAc,UAAO;IAChC,SAAS,CAAC,OAAO,EAAG,MAAM,CAAC;IACvB,SAAS,CAAC,IAAI,EAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACzB,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,KAAK,EAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC/B,SAAS,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IAEnC,IAAW,MAAM,IAAI,MAAM,CAE1B;IAED,IAAW,MAAM,CAAC,MAAM,EAAE,MAAM,EAE/B;cAEa,KAAK,CAAC,GAAG,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,GAAG,CAAC;cA8BrD,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC;IAO9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiFlC;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAIvB;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ;CA0BjB"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { getCredentials } from "@servicenow/sdk-cli/dist/auth/index.js";
|
|
3
|
-
import { configureLogging, flushLogs, ServiceNowInstance } from '@sonisoft/now-sdk-ext-core';
|
|
3
|
+
import { configureLogging, flushLogs, isPolicyRefusal, ServiceNowInstance } from '@sonisoft/now-sdk-ext-core';
|
|
4
4
|
import { LogFactory } from '../util/log-factory.js';
|
|
5
|
+
import { installCliPolicy } from './policy.js';
|
|
5
6
|
export class AuthenticatedCommand extends Command {
|
|
6
7
|
// // define flags that can be inherited by any command that extends BaseCommand
|
|
7
8
|
static baseFlags = {
|
|
@@ -16,6 +17,26 @@ export class AuthenticatedCommand extends Command {
|
|
|
16
17
|
helpGroup: 'GLOBAL',
|
|
17
18
|
required: false,
|
|
18
19
|
}),
|
|
20
|
+
// Changes are PERMITTED by default; these take permission away.
|
|
21
|
+
//
|
|
22
|
+
// Deliberately deny-direction rather than `--allow-write`. With a permissive
|
|
23
|
+
// default an allow-flag would grant nothing it did not already have, and it could
|
|
24
|
+
// not override NEX_POLICY_DENY either, so it would ship as a no-op. If the default
|
|
25
|
+
// ever flips to deny, the allow flags arrive in that same change.
|
|
26
|
+
//
|
|
27
|
+
// These are agent-reachable, which is fine: an agent can only ever RESTRICT itself
|
|
28
|
+
// with them. The layer an agent cannot reach is NEX_POLICY_DENY, which outranks
|
|
29
|
+
// every flag — that is what makes pointing nex at production meaningful.
|
|
30
|
+
'deny-execute': Flags.boolean({
|
|
31
|
+
description: 'Refuse background scripts, flow runs and ATF runs for this invocation.',
|
|
32
|
+
helpGroup: 'GLOBAL',
|
|
33
|
+
required: false,
|
|
34
|
+
}),
|
|
35
|
+
'deny-write': Flags.boolean({
|
|
36
|
+
description: 'Refuse any change to instance data for this invocation.',
|
|
37
|
+
helpGroup: 'GLOBAL',
|
|
38
|
+
required: false,
|
|
39
|
+
}),
|
|
19
40
|
'log-dir': Flags.string({
|
|
20
41
|
description: 'Directory to write log files to. Implies --log-file.',
|
|
21
42
|
helpGroup: 'GLOBAL',
|
|
@@ -37,6 +58,12 @@ export class AuthenticatedCommand extends Command {
|
|
|
37
58
|
options: ['debug', 'warn', 'error', 'info', 'trace'],
|
|
38
59
|
summary: 'Specify level for logging.',
|
|
39
60
|
})(),
|
|
61
|
+
'read-only': Flags.boolean({
|
|
62
|
+
description: 'Refuse every change to the instance — equivalent to ' +
|
|
63
|
+
'--deny-write --deny-execute. Reads are unaffected.',
|
|
64
|
+
helpGroup: 'GLOBAL',
|
|
65
|
+
required: false,
|
|
66
|
+
}),
|
|
40
67
|
};
|
|
41
68
|
// add the --json flag
|
|
42
69
|
static enableJsonFlag = true;
|
|
@@ -52,6 +79,19 @@ export class AuthenticatedCommand extends Command {
|
|
|
52
79
|
this._logger = logger;
|
|
53
80
|
}
|
|
54
81
|
async catch(err) {
|
|
82
|
+
// A refusal is a decision, not a crash. Render it as the CLI's own error with
|
|
83
|
+
// remediation, rather than letting a stack trace reach the user for something they
|
|
84
|
+
// asked for by passing a flag. Handled first, before the generic path below.
|
|
85
|
+
if (isPolicyRefusal(err)) {
|
|
86
|
+
this.authLogger?.warn("Refused by policy.", { message: err.message });
|
|
87
|
+
await flushLogs();
|
|
88
|
+
this.error(err.message, {
|
|
89
|
+
suggestions: [
|
|
90
|
+
'Reads are unaffected — only changes to the instance were refused.',
|
|
91
|
+
'Run `nex policy status` to see what is permitted and which layer decided.',
|
|
92
|
+
],
|
|
93
|
+
});
|
|
94
|
+
}
|
|
55
95
|
// authLogger is assigned partway through init(), so anything that throws
|
|
56
96
|
// before that point — a missing required flag, for instance — arrived here
|
|
57
97
|
// with it still undefined and produced "Cannot read properties of undefined
|
|
@@ -102,6 +142,14 @@ export class AuthenticatedCommand extends Command {
|
|
|
102
142
|
});
|
|
103
143
|
this.logger = LogFactory.createLogger(this.ctor.name);
|
|
104
144
|
this.authLogger = LogFactory.createLogger("AuthenticatedCommand");
|
|
145
|
+
// Install the permission ladder before anything can issue a request. Core's gate
|
|
146
|
+
// is inert until this runs, so ordering matters: after logging (so a malformed
|
|
147
|
+
// NEX_POLICY_DENY has somewhere to warn) and before the first credential fetch.
|
|
148
|
+
//
|
|
149
|
+
// Note there is no per-command classification. The gate sits at the HTTP layer and
|
|
150
|
+
// decides per REQUEST, so `update-set current` reading or writing depending on
|
|
151
|
+
// --set, and `script-sync sync` going both ways, need no special handling here.
|
|
152
|
+
installCliPolicy(this.flags, (message) => this.authLogger.warn(message));
|
|
105
153
|
// const wrapper:CredentialWrapper = new CredentialWrapper();
|
|
106
154
|
// const credential:Creds = await (flags.auth ? wrapper.getStoredCredentialsByAlias(flags.auth) : wrapper.getStoredCredentialsByAlias( 'fluent-default'));
|
|
107
155
|
// const credentialArgs = {"_": "get-credentials", auth: flags.auth || "fluent-default"};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticated-command.js","sourceRoot":"","sources":["../../src/common/authenticated-command.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAc,MAAM,aAAa,CAAA;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAU,kBAAkB,EAA8B,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"authenticated-command.js","sourceRoot":"","sources":["../../src/common/authenticated-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type PolicyLayer, Verb } from '@sonisoft/now-sdk-ext-core';
|
|
2
|
+
/**
|
|
3
|
+
* Builds and installs the permission ladder for one `nex` invocation.
|
|
4
|
+
*
|
|
5
|
+
* Changes are PERMITTED by default. This is not the strongest posture available — an
|
|
6
|
+
* agent that decides to run `nex bulk delete` still just does it — but it is the one
|
|
7
|
+
* that does not break every existing script and CI job, and the machinery is arranged
|
|
8
|
+
* so flipping is a one-line change (see DEFAULT_ALLOW below).
|
|
9
|
+
*
|
|
10
|
+
* What it does buy today: `NEX_POLICY_DENY`, set somewhere the agent cannot write,
|
|
11
|
+
* outranks every flag. That is the difference between "the agent probably will not
|
|
12
|
+
* write to prod" and "the agent cannot".
|
|
13
|
+
*/
|
|
14
|
+
export interface PolicyFlags {
|
|
15
|
+
'deny-execute'?: boolean;
|
|
16
|
+
'deny-write'?: boolean;
|
|
17
|
+
'read-only'?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** The verbs a set of flags takes away. */
|
|
20
|
+
export declare function deniedByFlags(flags: PolicyFlags): Verb[];
|
|
21
|
+
/**
|
|
22
|
+
* Assembles the ladder, highest priority first.
|
|
23
|
+
*
|
|
24
|
+
* Order is the whole design. `NEX_POLICY_DENY` sits above the flags so a flag cannot
|
|
25
|
+
* grant past it; the permissive default sits at the bottom so anything above it can
|
|
26
|
+
* take permission away.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildLayers(flags: PolicyFlags, warn: (message: string) => void): PolicyLayer[];
|
|
29
|
+
/** Installs the policy for this process. Call once, from init(), before any request. */
|
|
30
|
+
export declare function installCliPolicy(flags: PolicyFlags, warn: (message: string) => void): void;
|
|
31
|
+
export { ALLOW_ENV, DENY_ENV } from '@sonisoft/now-sdk-ext-core';
|
|
32
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/common/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,WAAW,EAEhB,IAAI,EACL,MAAM,4BAA4B,CAAA;AAEnC;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,WAAW;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,2CAA2C;AAC3C,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,EAAE,CAUxD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,WAAW,EAAE,CAuB9F;AAwBD,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAG1F;AAID,OAAO,EAAC,SAAS,EAAE,QAAQ,EAAC,MAAM,4BAA4B,CAAA"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { allowFromEnvironment, DENY_ENV, denyFromEnvironment, denyLayer, grantLayer, installPolicy, setRemediationWriter, } from '@sonisoft/now-sdk-ext-core';
|
|
2
|
+
/** The verbs a set of flags takes away. */
|
|
3
|
+
export function deniedByFlags(flags) {
|
|
4
|
+
const denied = new Set();
|
|
5
|
+
if (flags['read-only']) {
|
|
6
|
+
denied.add('write');
|
|
7
|
+
denied.add('execute');
|
|
8
|
+
}
|
|
9
|
+
if (flags['deny-write'])
|
|
10
|
+
denied.add('write');
|
|
11
|
+
if (flags['deny-execute'])
|
|
12
|
+
denied.add('execute');
|
|
13
|
+
return [...denied];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Assembles the ladder, highest priority first.
|
|
17
|
+
*
|
|
18
|
+
* Order is the whole design. `NEX_POLICY_DENY` sits above the flags so a flag cannot
|
|
19
|
+
* grant past it; the permissive default sits at the bottom so anything above it can
|
|
20
|
+
* take permission away.
|
|
21
|
+
*/
|
|
22
|
+
export function buildLayers(flags, warn) {
|
|
23
|
+
const layers = [];
|
|
24
|
+
// 0. Operator lockdown. The only rung an agent cannot reach — and only when set
|
|
25
|
+
// somewhere it cannot write. A project-local .mcp.json or a committed .env is
|
|
26
|
+
// still editable by anything with file access; a shell profile is not.
|
|
27
|
+
const envDeny = denyFromEnvironment(process.env, warn);
|
|
28
|
+
if (envDeny)
|
|
29
|
+
layers.push(envDeny);
|
|
30
|
+
// 1. Per-invocation denials. Agent-reachable, but they only ever restrict.
|
|
31
|
+
const flagDenied = deniedByFlags(flags);
|
|
32
|
+
if (flagDenied.length > 0)
|
|
33
|
+
layers.push(denyLayer('command-line flag', flagDenied));
|
|
34
|
+
// 2. Grants from the environment. Inert while the default is permissive; kept in
|
|
35
|
+
// place so the ladder does not have to be rebuilt when the default flips.
|
|
36
|
+
const envAllow = allowFromEnvironment(process.env, warn);
|
|
37
|
+
if (envAllow)
|
|
38
|
+
layers.push(envAllow);
|
|
39
|
+
// 3. THE DEFAULT. Delete this one layer to make `nex` deny-by-default; everything
|
|
40
|
+
// above keeps working unchanged.
|
|
41
|
+
layers.push(grantLayer('default (changes permitted)', ['write', 'execute']));
|
|
42
|
+
return layers;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Explains a refusal in terms of what the user can actually do about it.
|
|
46
|
+
*
|
|
47
|
+
* Names the deciding layer, because "refused" without "by what" is unactionable — and
|
|
48
|
+
* the fix differs completely: unset an environment variable, or drop a flag.
|
|
49
|
+
*/
|
|
50
|
+
function remediation(verbs, missing, layer) {
|
|
51
|
+
const what = missing === 'execute' ? 'running scripts or flows' : 'changing instance data';
|
|
52
|
+
if (layer.startsWith(DENY_ENV)) {
|
|
53
|
+
return `Refused: ${what} is denied by ${DENY_ENV}. ` +
|
|
54
|
+
`This is set in the environment, not on the command line — unset it there to allow this.`;
|
|
55
|
+
}
|
|
56
|
+
if (layer === 'command-line flag') {
|
|
57
|
+
return `Refused: ${what} is denied by a flag on this command. ` +
|
|
58
|
+
`Remove --read-only / --deny-${missing} to allow it.`;
|
|
59
|
+
}
|
|
60
|
+
return `Refused: ${what} is not permitted (${layer}).`;
|
|
61
|
+
}
|
|
62
|
+
/** Installs the policy for this process. Call once, from init(), before any request. */
|
|
63
|
+
export function installCliPolicy(flags, warn) {
|
|
64
|
+
installPolicy(buildLayers(flags, warn));
|
|
65
|
+
setRemediationWriter(remediation);
|
|
66
|
+
}
|
|
67
|
+
export { ALLOW_ENV, DENY_ENV } from '@sonisoft/now-sdk-ext-core';
|
|
68
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/common/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,oBAAoB,EACpB,QAAQ,EACR,mBAAmB,EACnB,SAAS,EACT,UAAU,EACV,aAAa,EAEb,oBAAoB,GAErB,MAAM,4BAA4B,CAAA;AAqBnC,2CAA2C;AAC3C,MAAM,UAAU,aAAa,CAAC,KAAkB;IAC9C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAQ,CAAA;IAC9B,IAAI,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QACnB,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACvB,CAAC;IAED,IAAI,KAAK,CAAC,YAAY,CAAC;QAAE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC5C,IAAI,KAAK,CAAC,cAAc,CAAC;QAAE,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IAChD,OAAO,CAAC,GAAG,MAAM,CAAC,CAAA;AACpB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,KAAkB,EAAE,IAA+B;IAC7E,MAAM,MAAM,GAAkB,EAAE,CAAA;IAEhC,gFAAgF;IAChF,iFAAiF;IACjF,0EAA0E;IAC1E,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACtD,IAAI,OAAO;QAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAEjC,2EAA2E;IAC3E,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,CAAC,CAAA;IACvC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,mBAAmB,EAAE,UAAU,CAAC,CAAC,CAAA;IAElF,iFAAiF;IACjF,6EAA6E;IAC7E,MAAM,QAAQ,GAAG,oBAAoB,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACxD,IAAI,QAAQ;QAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAEnC,kFAAkF;IAClF,oCAAoC;IACpC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,6BAA6B,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;IAE5E,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,KAAsB,EAAE,OAAa,EAAE,KAAa;IACvE,MAAM,IAAI,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,wBAAwB,CAAA;IAE1F,IAAI,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,OAAO,YAAY,IAAI,iBAAiB,QAAQ,IAAI;YAClD,yFAAyF,CAAA;IAC7F,CAAC;IAED,IAAI,KAAK,KAAK,mBAAmB,EAAE,CAAC;QAClC,OAAO,YAAY,IAAI,wCAAwC;YAC7D,+BAA+B,OAAO,eAAe,CAAA;IACzD,CAAC;IAED,OAAO,YAAY,IAAI,sBAAsB,KAAK,IAAI,CAAA;AACxD,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,gBAAgB,CAAC,KAAkB,EAAE,IAA+B;IAClF,aAAa,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAA;IACvC,oBAAoB,CAAC,WAAW,CAAC,CAAA;AACnC,CAAC;AAID,OAAO,EAAC,SAAS,EAAE,QAAQ,EAAC,MAAM,4BAA4B,CAAA"}
|