@sonisoft/now-sdk-ext-cli 5.0.1 → 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/LICENSE +21 -0
- package/README.md +827 -197
- 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 +12 -0
- package/dist/common/authenticated-command.d.ts.map +1 -1
- package/dist/common/authenticated-command.js +98 -4
- 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/dist/util/log-factory.d.ts +7 -1
- package/dist/util/log-factory.d.ts.map +1 -1
- package/dist/util/log-factory.js +8 -3
- package/dist/util/log-factory.js.map +1 -1
- package/oclif.manifest.json +3681 -882
- 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,7 +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>;
|
|
11
|
+
'log-dir': Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
12
|
+
'log-file': Interfaces.BooleanFlag<boolean>;
|
|
9
13
|
'log-level': Interfaces.OptionFlag<"info" | "debug" | "warn" | "error" | "trace", Interfaces.CustomOptions>;
|
|
14
|
+
'read-only': Interfaces.BooleanFlag<boolean>;
|
|
10
15
|
};
|
|
11
16
|
static enableJsonFlag: boolean;
|
|
12
17
|
protected _logger: Logger;
|
|
@@ -21,6 +26,13 @@ export declare abstract class AuthenticatedCommand<T extends typeof Command> ext
|
|
|
21
26
|
}): Promise<any>;
|
|
22
27
|
protected finally(_: Error | undefined): Promise<any>;
|
|
23
28
|
init(): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Whether --log-level was given on the command line rather than defaulted.
|
|
31
|
+
*
|
|
32
|
+
* oclif reports its own default as a parsed value, so `flags['log-level']` cannot
|
|
33
|
+
* distinguish "the user asked for info" from "nobody said anything".
|
|
34
|
+
*/
|
|
35
|
+
private argvHasLogLevel;
|
|
24
36
|
/**
|
|
25
37
|
* Fail with remediation the user can act on.
|
|
26
38
|
*
|
|
@@ -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 { 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,12 +17,53 @@ 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
|
+
}),
|
|
40
|
+
'log-dir': Flags.string({
|
|
41
|
+
description: 'Directory to write log files to. Implies --log-file.',
|
|
42
|
+
helpGroup: 'GLOBAL',
|
|
43
|
+
required: false,
|
|
44
|
+
}),
|
|
45
|
+
// Logging to a file is opt-in. It used to be unconditional, writing
|
|
46
|
+
// ./logs/*.log into whatever directory nex happened to be run from — including
|
|
47
|
+
// CI checkouts — with no way to turn it off. See NEX-3.
|
|
48
|
+
'log-file': Flags.boolean({
|
|
49
|
+
description: 'Write logs to a file. Defaults to $XDG_STATE_HOME/now-sdk-ext/logs ' +
|
|
50
|
+
'(~/.local/state/now-sdk-ext/logs). Off by default; without this, nex logs ' +
|
|
51
|
+
'warnings and errors to stderr only.',
|
|
52
|
+
helpGroup: 'GLOBAL',
|
|
53
|
+
required: false,
|
|
54
|
+
}),
|
|
19
55
|
'log-level': Flags.option({
|
|
20
56
|
default: 'info',
|
|
21
57
|
helpGroup: 'GLOBAL',
|
|
22
58
|
options: ['debug', 'warn', 'error', 'info', 'trace'],
|
|
23
59
|
summary: 'Specify level for logging.',
|
|
24
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
|
+
}),
|
|
25
67
|
};
|
|
26
68
|
// add the --json flag
|
|
27
69
|
static enableJsonFlag = true;
|
|
@@ -37,15 +79,35 @@ export class AuthenticatedCommand extends Command {
|
|
|
37
79
|
this._logger = logger;
|
|
38
80
|
}
|
|
39
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
|
+
}
|
|
40
95
|
// authLogger is assigned partway through init(), so anything that throws
|
|
41
96
|
// before that point — a missing required flag, for instance — arrived here
|
|
42
97
|
// with it still undefined and produced "Cannot read properties of undefined
|
|
43
98
|
// (reading 'error')", hiding the actual usage error behind a TypeError.
|
|
44
99
|
this.authLogger?.error("Globally caught exception occurred.", err);
|
|
100
|
+
// Flush HERE, not only in finally(). super.catch() routes into oclif's error
|
|
101
|
+
// handler, which can terminate the process — so finally() is not guaranteed to
|
|
102
|
+
// run, and the record that just got logged is precisely the one worth keeping.
|
|
103
|
+
// Winston buffers, so without this the failure line is lost intermittently.
|
|
104
|
+
await flushLogs();
|
|
45
105
|
return super.catch(err);
|
|
46
106
|
}
|
|
47
107
|
async finally(_) {
|
|
48
|
-
// called after run and catch regardless of whether or not the command errored
|
|
108
|
+
// called after run and catch regardless of whether or not the command errored.
|
|
109
|
+
// Covers the success path; the failure path already flushed in catch().
|
|
110
|
+
await flushLogs();
|
|
49
111
|
return super.finally(_);
|
|
50
112
|
}
|
|
51
113
|
async init() {
|
|
@@ -63,8 +125,31 @@ export class AuthenticatedCommand extends Command {
|
|
|
63
125
|
// value under that exact name. Reading `flags.logLevel` always yielded
|
|
64
126
|
// undefined, silently pinning every command to 'info'.
|
|
65
127
|
const logLevel = this.flags['log-level'] || 'info';
|
|
66
|
-
|
|
67
|
-
|
|
128
|
+
const logDir = this.flags['log-dir'];
|
|
129
|
+
// Configure BEFORE creating any logger. Core's loggers are field initializers on
|
|
130
|
+
// ~43 manager classes and take no arguments, so this process-wide call is the only
|
|
131
|
+
// thing that reaches them — a per-logger level never did.
|
|
132
|
+
configureLogging({
|
|
133
|
+
// --log-dir implies --log-file; requiring both would make `--log-dir ./x` alone
|
|
134
|
+
// silently produce nothing, which reads as a broken flag.
|
|
135
|
+
dir: logDir,
|
|
136
|
+
file: Boolean(this.flags['log-file']) || Boolean(logDir),
|
|
137
|
+
level: logLevel,
|
|
138
|
+
// --json puts machine-readable output on stdout. Warnings on stderr do not
|
|
139
|
+
// corrupt it, but they do land in a terminal the caller is likely piping, so
|
|
140
|
+
// stay quiet unless the level was asked for explicitly.
|
|
141
|
+
...(this.jsonEnabled() && !this.argvHasLogLevel() ? { consoleLevel: 'error' } : {}),
|
|
142
|
+
});
|
|
143
|
+
this.logger = LogFactory.createLogger(this.ctor.name);
|
|
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));
|
|
68
153
|
// const wrapper:CredentialWrapper = new CredentialWrapper();
|
|
69
154
|
// const credential:Creds = await (flags.auth ? wrapper.getStoredCredentialsByAlias(flags.auth) : wrapper.getStoredCredentialsByAlias( 'fluent-default'));
|
|
70
155
|
// const credentialArgs = {"_": "get-credentials", auth: flags.auth || "fluent-default"};
|
|
@@ -96,6 +181,15 @@ export class AuthenticatedCommand extends Command {
|
|
|
96
181
|
};
|
|
97
182
|
this.instance = new ServiceNowInstance(snSettings);
|
|
98
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* Whether --log-level was given on the command line rather than defaulted.
|
|
186
|
+
*
|
|
187
|
+
* oclif reports its own default as a parsed value, so `flags['log-level']` cannot
|
|
188
|
+
* distinguish "the user asked for info" from "nobody said anything".
|
|
189
|
+
*/
|
|
190
|
+
argvHasLogLevel() {
|
|
191
|
+
return this.argv.some((a) => a === '--log-level' || a.startsWith('--log-level='));
|
|
192
|
+
}
|
|
99
193
|
/**
|
|
100
194
|
* Fail with remediation the user can act on.
|
|
101
195
|
*
|
|
@@ -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,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"}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { Logger } from "@sonisoft/now-sdk-ext-core";
|
|
2
2
|
export declare class LogFactory {
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The level is NOT a parameter any more. Core builds one logger for the process,
|
|
5
|
+
* so a per-logger level would only ever have applied to the two loggers created
|
|
6
|
+
* here and never to the ~43 inside core. Set it with `configureLogging({level})`,
|
|
7
|
+
* which AuthenticatedCommand.init does before calling this.
|
|
8
|
+
*/
|
|
9
|
+
static createLogger(name: string): Logger;
|
|
4
10
|
}
|
|
5
11
|
//# sourceMappingURL=log-factory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-factory.d.ts","sourceRoot":"","sources":["../../src/util/log-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAGpD,qBAAa,UAAU;
|
|
1
|
+
{"version":3,"file":"log-factory.d.ts","sourceRoot":"","sources":["../../src/util/log-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAGpD,qBAAa,UAAU;IACnB;;;;;OAKG;WACW,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAGnD"}
|
package/dist/util/log-factory.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { Logger } from "@sonisoft/now-sdk-ext-core";
|
|
2
2
|
export class LogFactory {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The level is NOT a parameter any more. Core builds one logger for the process,
|
|
5
|
+
* so a per-logger level would only ever have applied to the two loggers created
|
|
6
|
+
* here and never to the ~43 inside core. Set it with `configureLogging({level})`,
|
|
7
|
+
* which AuthenticatedCommand.init does before calling this.
|
|
8
|
+
*/
|
|
9
|
+
static createLogger(name) {
|
|
10
|
+
return new Logger(name);
|
|
6
11
|
}
|
|
7
12
|
}
|
|
8
13
|
//# sourceMappingURL=log-factory.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-factory.js","sourceRoot":"","sources":["../../src/util/log-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAGpD,MAAM,OAAO,UAAU;
|
|
1
|
+
{"version":3,"file":"log-factory.js","sourceRoot":"","sources":["../../src/util/log-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAGpD,MAAM,OAAO,UAAU;IACnB;;;;;OAKG;IACI,MAAM,CAAC,YAAY,CAAC,IAAY;QACnC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;CACJ"}
|