@sonisoft/now-sdk-ext-cli 3.0.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +500 -164
  2. package/bin/argv-guard.js +25 -0
  3. package/bin/argv-secrets.js +103 -0
  4. package/bin/credstore-boot.js +67 -0
  5. package/bin/dev.js +8 -0
  6. package/bin/run.js +8 -0
  7. package/dist/commands/auth/delete.d.ts +17 -0
  8. package/dist/commands/auth/delete.d.ts.map +1 -0
  9. package/dist/commands/auth/delete.js +34 -0
  10. package/dist/commands/auth/delete.js.map +1 -0
  11. package/dist/commands/auth/doctor.d.ts +23 -0
  12. package/dist/commands/auth/doctor.d.ts.map +1 -0
  13. package/dist/commands/auth/doctor.js +87 -0
  14. package/dist/commands/auth/doctor.js.map +1 -0
  15. package/dist/commands/auth/list.d.ts +15 -0
  16. package/dist/commands/auth/list.d.ts.map +1 -0
  17. package/dist/commands/auth/list.js +42 -0
  18. package/dist/commands/auth/list.js.map +1 -0
  19. package/dist/commands/auth/use.d.ts +16 -0
  20. package/dist/commands/auth/use.d.ts.map +1 -0
  21. package/dist/commands/auth/use.js +20 -0
  22. package/dist/commands/auth/use.js.map +1 -0
  23. package/dist/common/authenticated-command.d.ts +10 -0
  24. package/dist/common/authenticated-command.d.ts.map +1 -1
  25. package/dist/common/authenticated-command.js +65 -12
  26. package/dist/common/authenticated-command.js.map +1 -1
  27. package/dist/common/cred-store-flag.d.ts +17 -0
  28. package/dist/common/cred-store-flag.d.ts.map +1 -0
  29. package/dist/common/cred-store-flag.js +23 -0
  30. package/dist/common/cred-store-flag.js.map +1 -0
  31. package/dist/common/scope-autocomplete.d.ts.map +1 -1
  32. package/dist/common/scope-autocomplete.js +8 -0
  33. package/dist/common/scope-autocomplete.js.map +1 -1
  34. package/oclif.manifest.json +1550 -825
  35. package/package.json +3 -2
@@ -0,0 +1,25 @@
1
+ /* eslint-disable n/no-process-exit, unicorn/no-process-exit -- this runs before
2
+ oclif exists, so there is no error handler to throw into; an uncaught rejection
3
+ here would print a stack trace instead of the remediation. */
4
+
5
+ /**
6
+ * Side-effecting half of the argv secret check.
7
+ *
8
+ * Split from bin/argv-secrets.js so the detection logic can be imported and
9
+ * tested without the import itself terminating the test process.
10
+ *
11
+ * Imported for its side effect by bin/run.js and bin/dev.js, before
12
+ * credstore-boot.js — a secret in argv should be refused before anything reads,
13
+ * stores, or logs a credential.
14
+ */
15
+
16
+ import {findSecretArgument, secretArgumentMessage} from './argv-secrets.js'
17
+
18
+ // slice(2): skip the node binary and the script path, so a secret-shaped
19
+ // filename in the invocation cannot trip the check.
20
+ const found = findSecretArgument(process.argv.slice(2))
21
+
22
+ if (found) {
23
+ process.stderr.write(secretArgumentMessage(found))
24
+ process.exit(2)
25
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Refuse to run when a secret was passed as a command-line argument.
3
+ *
4
+ * Anything in argv is already exposed by the time this runs: the shell has
5
+ * written it to history, and it is visible to every process on the host via
6
+ * `ps auxww` for as long as this one lives. Neither can be undone from here.
7
+ *
8
+ * So this is not really prevention — it is detection plus an honest message. The
9
+ * user needs to know the value leaked and should be rotated, which is strictly
10
+ * more useful than oclif's "Nonexistent flag: --password". Refusing to run also
11
+ * makes the habit fail fast rather than working quietly until someone greps a
12
+ * shell history.
13
+ *
14
+ * None of these flags exist on any `nex` command today, so nothing legitimate is
15
+ * blocked. The check is deliberately conservative about that: it matches on flag
16
+ * NAME only, never on the shape of a value, because `nex exec` takes arbitrary
17
+ * scripts and `--query`, `--filter`, `--data`, `--payload` and `--spec` all take
18
+ * arbitrary text that can look like anything.
19
+ *
20
+ * Kept as plain JS in bin/ for the same reason as credstore-boot.js: it runs
21
+ * before oclif and before any build output is required.
22
+ */
23
+
24
+ /**
25
+ * Long flags whose value would be a credential.
26
+ *
27
+ * Short flags are deliberately excluded — `-p` and `-t` are too easily something
28
+ * else, and a false positive here blocks legitimate work.
29
+ */
30
+ const SECRET_FLAGS = new Set([
31
+ '--password',
32
+ '--passwd',
33
+ '--pass',
34
+ '--secret',
35
+ '--client-secret',
36
+ '--clientsecret',
37
+ '--token',
38
+ '--access-token',
39
+ '--refresh-token',
40
+ '--id-token',
41
+ '--auth-token',
42
+ '--user-token',
43
+ '--session-token',
44
+ '--api-key',
45
+ '--apikey',
46
+ '--credential',
47
+ '--credentials',
48
+ ])
49
+
50
+ /**
51
+ * Returns details of the first secret-bearing argument, or null.
52
+ *
53
+ * Only reports when a value is actually present. `--password` with nothing after
54
+ * it, or followed by another flag, carries no secret — oclif will reject it as a
55
+ * missing value, which is not this file's problem.
56
+ *
57
+ * @param {string[]} argv
58
+ * @returns {{flag: string, form: 'inline' | 'separate'} | null}
59
+ */
60
+ export function findSecretArgument(argv) {
61
+ if (!Array.isArray(argv)) return null
62
+
63
+ for (const [index, arg] of argv.entries()) {
64
+ if (typeof arg !== 'string' || !arg.startsWith('--')) continue
65
+
66
+ const equals = arg.indexOf('=')
67
+ const name = (equals === -1 ? arg : arg.slice(0, equals)).toLowerCase()
68
+ if (!SECRET_FLAGS.has(name)) continue
69
+
70
+ if (equals !== -1) {
71
+ // `--password=` with nothing after it carries no value.
72
+ if (arg.length > equals + 1) return {flag: name, form: 'inline'}
73
+ continue
74
+ }
75
+
76
+ const next = argv[index + 1]
77
+ if (next !== undefined && !next.startsWith('-')) return {flag: name, form: 'separate'}
78
+ }
79
+
80
+ return null
81
+ }
82
+
83
+ /**
84
+ * Human-facing message for a detected secret argument.
85
+ *
86
+ * Leads with the exposure rather than the refusal, because the exposure is the
87
+ * part the user has to act on and cannot undo.
88
+ *
89
+ * @param {{flag: string}} found
90
+ * @returns {string}
91
+ */
92
+ export function secretArgumentMessage(found) {
93
+ return (
94
+ `nex: refusing to run — a secret was passed on the command line (${found.flag}).\n` +
95
+ `\nThat value is already in your shell history and was visible in the process\n` +
96
+ `list while this command started. Treat it as compromised and rotate it.\n` +
97
+ `\nRemediation: store credentials once instead of passing them per command.\n` +
98
+ ` now-sdk auth --add <instance> # add a credential\n` +
99
+ ` nex auth list # see what is stored\n` +
100
+ ` nex --auth <alias> ... # select one per command\n` +
101
+ `\nFor non-interactive use, set the value in the environment rather than argv.\n`
102
+ )
103
+ }
@@ -0,0 +1,67 @@
1
+ /* eslint-disable n/no-process-exit, unicorn/no-process-exit -- this runs before
2
+ oclif exists, so there is no error handler to throw into; an uncaught rejection
3
+ here would print a stack trace instead of the remediation. */
4
+
5
+ /**
6
+ * Opt in to headless-safe credential storage.
7
+ *
8
+ * By default `nex` uses the ServiceNow SDK exactly as it ships: credentials come
9
+ * from the OS keyring, `now-sdk auth --add` still manages them, and this file
10
+ * does nothing. That default is deliberate — `nex` must behave identically for
11
+ * someone who has never heard of sn-credstore.
12
+ *
13
+ * Pass `--cred-store` (or set SN_CRED_STORE_ENABLE=1) to redirect the SDK's
14
+ * credential storage to @sonisoft/sn-credstore instead. That matters when the
15
+ * keyring cannot be unlocked: over SSH, from a systemd unit, in CI, or from an
16
+ * agent. In those sessions `KeyChain.getPassword()` swallows the failure and
17
+ * returns null, so the SDK reports "Default Credential has not been set" — which
18
+ * is indistinguishable from genuinely having no credentials.
19
+ *
20
+ * Imported for its side effect by bin/run.js and bin/dev.js, before oclif.
21
+ *
22
+ * The import stays dynamic even though sn-credstore is now a declared
23
+ * dependency, because it must NOT run unless asked: importing
24
+ * '@sonisoft/sn-credstore/register' installs the shim as a side effect, so a
25
+ * static import would install it on every invocation regardless of the flag.
26
+ *
27
+ * argv is read directly rather than through oclif's parser because the shim has
28
+ * to be installed before AuthenticatedCommand.init() resolves credentials, and
29
+ * that runs before any flag this file cares about has been parsed. The flag is
30
+ * still declared in AuthenticatedCommand.baseFlags so it appears in --help and
31
+ * is not rejected as unknown.
32
+ */
33
+
34
+ /**
35
+ * True when the user asked for the credential store.
36
+ *
37
+ * SN_CRED_STORE_DISABLE wins over everything, so there is always one variable
38
+ * that switches the shim off no matter what else is set — including in a shell
39
+ * where SN_CRED_STORE_ENABLE is exported globally.
40
+ */
41
+ function credStoreRequested() {
42
+ if (process.env.SN_CRED_STORE_DISABLE) return false
43
+ if (process.env.SN_CRED_STORE_ENABLE) return true
44
+ return process.argv.includes('--cred-store')
45
+ }
46
+
47
+ if (credStoreRequested()) {
48
+ try {
49
+ await import('@sonisoft/sn-credstore/register')
50
+ } catch (error) {
51
+ // sn-credstore is a declared dependency now, so there is no "not
52
+ // installed" case left to tolerate — a failure here is a real failure.
53
+ //
54
+ // Continuing would silently fall back to the keyring, which is both the
55
+ // one thing the user just said not to do and actively unsafe: the SDK's
56
+ // next credential write reseeds from a failed read, wiping every other
57
+ // alias. Refusing to start is the safe outcome.
58
+ process.stderr.write(
59
+ `nex: the credential store failed to initialise: ${error?.message ?? error}\n` +
60
+ `${error?.remediation ? `\nRemediation: ${error.remediation}\n` : ''}` +
61
+ `\nTo run against the OS keyring instead, drop --cred-store.\n`,
62
+ )
63
+ process.exit(1)
64
+ }
65
+ } else if (process.env.SN_CRED_STORE_DEBUG) {
66
+ process.stderr.write('nex: credential store not requested — using the SDK keyring\n')
67
+ }
package/bin/dev.js CHANGED
@@ -1,6 +1,14 @@
1
1
  #!/usr/bin/env -S node --loader ts-node/esm --disable-warning=ExperimentalWarning
2
2
 
3
+ // FIRST, deliberately: refuse to run if a secret was passed in argv, before
4
+ // anything can read, store, or log it. See bin/argv-guard.js.
3
5
  // eslint-disable-next-line n/shebang
6
+ import './argv-guard.js'
7
+
8
+ // THEN: redirect SDK credential storage off the OS keyring before anything can
9
+ // read credentials. See bin/credstore-boot.js.
10
+ import './credstore-boot.js'
11
+
4
12
  import {execute} from '@oclif/core'
5
13
 
6
14
  await execute({development: true, dir: import.meta.url})
package/bin/run.js CHANGED
@@ -1,5 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // FIRST, deliberately: refuse to run if a secret was passed in argv, before
4
+ // anything can read, store, or log it. See bin/argv-guard.js.
5
+ import './argv-guard.js'
6
+
7
+ // THEN: redirect SDK credential storage off the OS keyring before anything can
8
+ // read credentials. See bin/credstore-boot.js.
9
+ import './credstore-boot.js'
10
+
3
11
  import {execute} from '@oclif/core'
4
12
 
5
13
  await execute({dir: import.meta.url})
@@ -0,0 +1,17 @@
1
+ import { Command } from '@oclif/core';
2
+ export declare class AuthDelete extends Command {
3
+ static args: {
4
+ alias: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: {
8
+ command: string;
9
+ description: string;
10
+ }[];
11
+ static flags: {
12
+ all: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
13
+ 'cred-store': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
14
+ };
15
+ run(): Promise<void>;
16
+ }
17
+ //# sourceMappingURL=delete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/delete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,OAAO,EAAQ,MAAM,aAAa,CAAA;AAKhD,qBAAa,UAAW,SAAQ,OAAO;IACrC,MAAM,CAAC,IAAI;;MAEV;IACH,MAAM,CAAC,WAAW,SAEsE;IACxF,MAAM,CAAC,QAAQ;;;QAGZ;IACH,MAAM,CAAC,KAAK;;;MAGT;IAEK,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAmB3B"}
@@ -0,0 +1,34 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { deleteAlias, deleteAllAliases } from '@sonisoft/sn-credstore';
3
+ import { credStoreFlag } from '../../common/cred-store-flag.js';
4
+ export class AuthDelete extends Command {
5
+ static args = {
6
+ alias: Args.string({ description: 'Alias to remove', required: false }),
7
+ };
8
+ static description = 'Remove a credential from the store.\n\n' +
9
+ 'This does not touch the OS keyring — a copy stored there before migrating remains.';
10
+ static examples = [
11
+ { command: '<%= config.bin %> <%= command.id %> dev206299', description: 'Remove one alias' },
12
+ { command: '<%= config.bin %> <%= command.id %> --all', description: 'Remove every stored credential' },
13
+ ];
14
+ static flags = {
15
+ ...credStoreFlag,
16
+ all: Flags.boolean({ description: 'Remove every stored credential', required: false }),
17
+ };
18
+ async run() {
19
+ const { args, flags } = await this.parse(AuthDelete);
20
+ if (flags.all) {
21
+ await deleteAllAliases();
22
+ this.log('Removed all stored credentials.');
23
+ return;
24
+ }
25
+ if (!args.alias) {
26
+ this.error('An alias is required, or --all to remove every credential.');
27
+ }
28
+ if (!(await deleteAlias(args.alias))) {
29
+ this.error(`No such alias "${args.alias}".`, { suggestions: ['Run "nex auth list" to see stored aliases.'] });
30
+ }
31
+ this.log(`Removed "${args.alias}".`);
32
+ }
33
+ }
34
+ //# sourceMappingURL=delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.js","sourceRoot":"","sources":["../../../src/commands/auth/delete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAC,MAAM,aAAa,CAAA;AAChD,OAAO,EAAC,WAAW,EAAE,gBAAgB,EAAC,MAAM,wBAAwB,CAAA;AAEpE,OAAO,EAAC,aAAa,EAAC,MAAM,iCAAiC,CAAA;AAE7D,MAAM,OAAO,UAAW,SAAQ,OAAO;IACrC,MAAM,CAAC,IAAI,GAAG;QACZ,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAC,WAAW,EAAE,iBAAiB,EAAE,QAAQ,EAAE,KAAK,EAAC,CAAC;KACtE,CAAA;IACH,MAAM,CAAC,WAAW,GACd,yCAAyC;QACzC,oFAAoF,CAAA;IACxF,MAAM,CAAC,QAAQ,GAAG;QACd,EAAC,OAAO,EAAE,+CAA+C,EAAE,WAAW,EAAE,kBAAkB,EAAC;QAC3F,EAAC,OAAO,EAAE,2CAA2C,EAAE,WAAW,EAAE,gCAAgC,EAAC;KACtG,CAAA;IACH,MAAM,CAAC,KAAK,GAAG;QACX,GAAG,aAAa;QAChB,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,EAAC,WAAW,EAAE,gCAAgC,EAAE,QAAQ,EAAE,KAAK,EAAC,CAAC;KACrF,CAAA;IAED,KAAK,CAAC,GAAG;QACP,MAAM,EAAC,IAAI,EAAE,KAAK,EAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;QAElD,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;YACd,MAAM,gBAAgB,EAAE,CAAA;YACxB,IAAI,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAA;YAC3C,OAAM;QACR,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAA;QAC1E,CAAC;QAED,IAAI,CAAC,CAAC,MAAM,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,KAAK,CAAC,kBAAkB,IAAI,CAAC,KAAK,IAAI,EAAE,EAAC,WAAW,EAAE,CAAC,4CAA4C,CAAC,EAAC,CAAC,CAAA;QAC7G,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,KAAK,IAAI,CAAC,CAAA;IACtC,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { Command } from '@oclif/core';
2
+ /**
3
+ * Diagnose credential storage.
4
+ *
5
+ * The failure this exists for is silent: a locked keyring makes
6
+ * `KeyChain.getPassword()` return null, which the SDK reports as "Default
7
+ * Credential has not been set" — indistinguishable from having no credentials.
8
+ * So the first thing to report is whether the shim actually installed.
9
+ */
10
+ export declare class AuthDoctor extends Command {
11
+ static args: {};
12
+ static description: string;
13
+ static enableJsonFlag: boolean;
14
+ static examples: {
15
+ command: string;
16
+ description: string;
17
+ }[];
18
+ static flags: {
19
+ 'cred-store': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
20
+ };
21
+ run(): Promise<unknown>;
22
+ }
23
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,aAAa,CAAA;AAKnC;;;;;;;GAOG;AACH,qBAAa,UAAW,SAAQ,OAAO;IACrC,MAAM,CAAC,IAAI,KAAK;IAChB,MAAM,CAAC,WAAW,SAC2F;IAC7G,MAAM,CAAC,cAAc,UAAO;IAC5B,MAAM,CAAC,QAAQ;;;QAGd;IACH,MAAM,CAAC,KAAK;;MAAqB;IAGzB,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;CAsE9B"}
@@ -0,0 +1,87 @@
1
+ import { Command } from '@oclif/core';
2
+ import { listAliases, loadConfig, PATCHED_ENV_VAR, probeAll } from '@sonisoft/sn-credstore';
3
+ import { credStoreFlag } from '../../common/cred-store-flag.js';
4
+ /**
5
+ * Diagnose credential storage.
6
+ *
7
+ * The failure this exists for is silent: a locked keyring makes
8
+ * `KeyChain.getPassword()` return null, which the SDK reports as "Default
9
+ * Credential has not been set" — indistinguishable from having no credentials.
10
+ * So the first thing to report is whether the shim actually installed.
11
+ */
12
+ export class AuthDoctor extends Command {
13
+ static args = {};
14
+ static description = 'Diagnose credential storage: whether the SDK shim is active, which backend is in use, and what is stored.';
15
+ static enableJsonFlag = true;
16
+ static examples = [
17
+ { command: '<%= config.bin %> <%= command.id %>', description: 'Check credential storage health' },
18
+ { command: '<%= config.bin %> <%= command.id %> --json', description: 'Machine-readable output for CI' },
19
+ ];
20
+ static flags = { ...credStoreFlag };
21
+ async run() {
22
+ await this.parse(AuthDoctor);
23
+ const config = loadConfig();
24
+ const shimActive = process.env[PATCHED_ENV_VAR] === '1';
25
+ const backends = await probeAll(config);
26
+ // listAliases reads the active backend, so it can legitimately fail (no
27
+ // systemd in a container, an undecryptable blob after a reimage). That is a
28
+ // finding to report, not a crash.
29
+ let summary;
30
+ let readError;
31
+ try {
32
+ summary = await listAliases(config);
33
+ }
34
+ catch (error) {
35
+ readError = error instanceof Error ? error.message : String(error);
36
+ }
37
+ const report = {
38
+ aliases: summary?.aliases ?? [],
39
+ backends,
40
+ path: config.blobPath,
41
+ shimActive,
42
+ store: config.store,
43
+ ...(readError ? { readError } : {}),
44
+ };
45
+ if (this.jsonEnabled())
46
+ return report;
47
+ this.log(`shim active : ${shimActive ? 'yes' : 'no'}`);
48
+ if (!shimActive) {
49
+ // "no" is the DEFAULT, not a fault — the shim is opt-in. The previous
50
+ // wording ("NO", plus a hint to check SN_CRED_STORE_DISABLE) read as though
51
+ // something were broken, and pointed at the one variable that is almost
52
+ // never the reason. Say what to do instead.
53
+ this.log('');
54
+ this.log(' The SDK is reading the OS keyring. That is the default and works fine with an');
55
+ this.log(' interactive desktop session.');
56
+ this.log('');
57
+ this.log(' In a headless session — SSH, systemd, CI, an agent — the keyring cannot be');
58
+ this.log(' unlocked and will report no credentials whatever is stored. To use the store');
59
+ this.log(' listed below instead, pass --cred-store or set SN_CRED_STORE_ENABLE=1.');
60
+ if (process.env.SN_CRED_STORE_DISABLE) {
61
+ this.log('');
62
+ this.log(' NOTE: SN_CRED_STORE_DISABLE is set, which overrides both of those.');
63
+ }
64
+ }
65
+ this.log(`store : ${config.store}`);
66
+ this.log(`path : ${config.blobPath}`);
67
+ this.log('');
68
+ this.log('backends:');
69
+ for (const backend of backends) {
70
+ const state = backend.available ? 'available' : 'unavailable';
71
+ this.log(` ${backend.id.padEnd(14)} ${state}${backend.error ? ` — ${backend.error}` : ''}`);
72
+ this.log(` ${''.padEnd(14)} ${backend.description}`);
73
+ }
74
+ this.log('');
75
+ if (readError) {
76
+ this.log(`credentials : COULD NOT READ — ${readError}`);
77
+ }
78
+ else {
79
+ this.log(`credentials : ${report.aliases.length} stored`);
80
+ for (const info of report.aliases) {
81
+ this.log(` ${info.isDefault ? '*' : ' '} ${info.alias} (${info.type}) ${info.instanceUrl}`);
82
+ }
83
+ }
84
+ return report;
85
+ }
86
+ }
87
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/commands/auth/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { Command } from '@oclif/core';
2
+ export declare class AuthList extends Command {
3
+ static args: {};
4
+ static description: string;
5
+ static enableJsonFlag: boolean;
6
+ static examples: {
7
+ command: string;
8
+ description: string;
9
+ }[];
10
+ static flags: {
11
+ 'cred-store': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
12
+ };
13
+ run(): Promise<unknown>;
14
+ }
15
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,aAAa,CAAA;AAKnC,qBAAa,QAAS,SAAQ,OAAO;IACnC,MAAM,CAAC,IAAI,KAAK;IAChB,MAAM,CAAC,WAAW,SAIY;IAC9B,MAAM,CAAC,cAAc,UAAO;IAC5B,MAAM,CAAC,QAAQ;;;QAGd;IACH,MAAM,CAAC,KAAK;;MAAqB;IAGzB,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;CAiC9B"}
@@ -0,0 +1,42 @@
1
+ import { Command } from '@oclif/core';
2
+ import { listAliases } from '@sonisoft/sn-credstore';
3
+ import { credStoreFlag } from '../../common/cred-store-flag.js';
4
+ export class AuthList extends Command {
5
+ static args = {};
6
+ static description = 'List credentials in the headless-safe credential store.\n\n' +
7
+ 'These are the credentials the ServiceNow SDK reads via the sn-credstore shim, ' +
8
+ 'which works in non-interactive sessions where the OS keyring cannot be unlocked.\n\n' +
9
+ 'Secrets are never printed.';
10
+ static enableJsonFlag = true;
11
+ static examples = [
12
+ { command: '<%= config.bin %> <%= command.id %>', description: 'List stored credentials' },
13
+ { command: '<%= config.bin %> <%= command.id %> --json', description: 'List as JSON for scripting' },
14
+ ];
15
+ static flags = { ...credStoreFlag };
16
+ async run() {
17
+ await this.parse(AuthList);
18
+ const summary = await listAliases();
19
+ if (this.jsonEnabled())
20
+ return summary;
21
+ this.log(summary.description);
22
+ this.log('');
23
+ if (summary.aliases.length === 0) {
24
+ this.log('No credentials stored.');
25
+ this.log('');
26
+ this.log('Import existing ones: sn-credstore import --from keyring');
27
+ this.log('Or add a new one: now-sdk-x auth --add <instance>');
28
+ return summary;
29
+ }
30
+ for (const info of summary.aliases) {
31
+ this.log(`${info.isDefault ? '*' : ' '} ${info.alias}`);
32
+ this.log(` host = ${info.instanceUrl}`);
33
+ this.log(` type = ${info.type}`);
34
+ this.log(info.type === 'basic'
35
+ ? ` username = ${info.username}`
36
+ : // Expired is not an error worth flagging red: the next use refreshes it.
37
+ ` expires = ${new Date(info.expiresAt * 1000).toISOString()}${info.expired ? ' (EXPIRED — refreshes on next use)' : ''}`);
38
+ }
39
+ return summary;
40
+ }
41
+ }
42
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/commands/auth/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,aAAa,CAAA;AACnC,OAAO,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAA;AAElD,OAAO,EAAC,aAAa,EAAC,MAAM,iCAAiC,CAAA;AAE7D,MAAM,OAAO,QAAS,SAAQ,OAAO;IACnC,MAAM,CAAC,IAAI,GAAG,EAAE,CAAA;IAChB,MAAM,CAAC,WAAW,GAChB,6DAA6D;QAC7D,gFAAgF;QAChF,sFAAsF;QACtF,4BAA4B,CAAA;IAC9B,MAAM,CAAC,cAAc,GAAG,IAAI,CAAA;IAC5B,MAAM,CAAC,QAAQ,GAAG;QAChB,EAAC,OAAO,EAAE,qCAAqC,EAAE,WAAW,EAAE,yBAAyB,EAAC;QACxF,EAAC,OAAO,EAAE,4CAA4C,EAAE,WAAW,EAAE,4BAA4B,EAAC;KACnG,CAAA;IACH,MAAM,CAAC,KAAK,GAAG,EAAC,GAAG,aAAa,EAAC,CAAA;IAG/B,KAAK,CAAC,GAAG;QACP,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QAC1B,MAAM,OAAO,GAAG,MAAM,WAAW,EAAE,CAAA;QAEnC,IAAI,IAAI,CAAC,WAAW,EAAE;YAAE,OAAO,OAAO,CAAA;QAEtC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;QAC7B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAEZ,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,IAAI,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAA;YAClC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YACZ,IAAI,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAA;YACrE,IAAI,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAA;YAClE,OAAO,OAAO,CAAA;QAChB,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,CAAA;YACvD,IAAI,CAAC,GAAG,CAAC,gBAAgB,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;YAC5C,IAAI,CAAC,GAAG,CAAC,gBAAgB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;YACrC,IAAI,CAAC,GAAG,CACN,IAAI,CAAC,IAAI,KAAK,OAAO;gBACnB,CAAC,CAAC,oBAAoB,IAAI,CAAC,QAAQ,EAAE;gBACrC,CAAC,CAAC,yEAAyE;oBACzE,mBAAmB,IAAI,IAAI,CAAC,IAAI,CAAC,SAAU,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,GAC/D,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,qCAAqC,CAAC,CAAC,CAAC,EACzD,EAAE,CACP,CAAA;QACH,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { Command } from '@oclif/core';
2
+ export declare class AuthUse extends Command {
3
+ static args: {
4
+ alias: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: {
8
+ command: string;
9
+ description: string;
10
+ }[];
11
+ static flags: {
12
+ 'cred-store': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
13
+ };
14
+ run(): Promise<void>;
15
+ }
16
+ //# sourceMappingURL=use.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/use.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,OAAO,EAAC,MAAM,aAAa,CAAA;AAKzC,qBAAa,OAAQ,SAAQ,OAAO;IAClC,MAAM,CAAC,IAAI;;MAEV;IACH,MAAM,CAAC,WAAW,SAE+B;IACjD,MAAM,CAAC,QAAQ;;;QAA0G;IACzH,MAAM,CAAC,KAAK;;MAAqB;IAEzB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAS3B"}
@@ -0,0 +1,20 @@
1
+ import { Args, Command } from '@oclif/core';
2
+ import { setDefaultAlias } from '@sonisoft/sn-credstore';
3
+ import { credStoreFlag } from '../../common/cred-store-flag.js';
4
+ export class AuthUse extends Command {
5
+ static args = {
6
+ alias: Args.string({ description: 'Alias to make the default', required: true }),
7
+ };
8
+ static description = 'Set the default credential alias.\n\n' +
9
+ 'Commands run without --auth use this alias.';
10
+ static examples = [{ command: '<%= config.bin %> <%= command.id %> dev206299', description: 'Make dev206299 the default' }];
11
+ static flags = { ...credStoreFlag };
12
+ async run() {
13
+ const { args } = await this.parse(AuthUse);
14
+ if (!(await setDefaultAlias(args.alias))) {
15
+ this.error(`No such alias "${args.alias}".`, { suggestions: ['Run "nex auth list" to see stored aliases.'] });
16
+ }
17
+ this.log(`Default alias is now "${args.alias}"`);
18
+ }
19
+ }
20
+ //# sourceMappingURL=use.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use.js","sourceRoot":"","sources":["../../../src/commands/auth/use.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAE,OAAO,EAAC,MAAM,aAAa,CAAA;AACzC,OAAO,EAAC,eAAe,EAAC,MAAM,wBAAwB,CAAA;AAEtD,OAAO,EAAC,aAAa,EAAC,MAAM,iCAAiC,CAAA;AAE7D,MAAM,OAAO,OAAQ,SAAQ,OAAO;IAClC,MAAM,CAAC,IAAI,GAAG;QACZ,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAC,WAAW,EAAE,2BAA2B,EAAE,QAAQ,EAAE,IAAI,EAAC,CAAC;KAC/E,CAAA;IACH,MAAM,CAAC,WAAW,GACd,uCAAuC;QACvC,6CAA6C,CAAA;IACjD,MAAM,CAAC,QAAQ,GAAG,CAAC,EAAC,OAAO,EAAE,+CAA+C,EAAE,WAAW,EAAE,4BAA4B,EAAC,CAAC,CAAA;IACzH,MAAM,CAAC,KAAK,GAAG,EAAC,GAAG,aAAa,EAAC,CAAA;IAE/B,KAAK,CAAC,GAAG;QACP,MAAM,EAAC,IAAI,EAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAExC,IAAI,CAAC,CAAC,MAAM,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC,KAAK,CAAC,kBAAkB,IAAI,CAAC,KAAK,IAAI,EAAE,EAAC,WAAW,EAAE,CAAC,4CAA4C,CAAC,EAAC,CAAC,CAAA;QAC7G,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,yBAAyB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAA;IAClD,CAAC"}
@@ -5,6 +5,7 @@ export type Args<T extends typeof Command> = Interfaces.InferredArgs<T['args']>;
5
5
  export declare abstract class AuthenticatedCommand<T extends typeof Command> extends Command {
6
6
  static baseFlags: {
7
7
  auth: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
8
+ 'cred-store': Interfaces.BooleanFlag<boolean>;
8
9
  'log-level': Interfaces.OptionFlag<"info" | "debug" | "warn" | "error" | "trace", Interfaces.CustomOptions>;
9
10
  };
10
11
  static enableJsonFlag: boolean;
@@ -20,5 +21,14 @@ export declare abstract class AuthenticatedCommand<T extends typeof Command> ext
20
21
  }): Promise<any>;
21
22
  protected finally(_: Error | undefined): Promise<any>;
22
23
  init(): Promise<void>;
24
+ /**
25
+ * Fail with remediation the user can act on.
26
+ *
27
+ * The keyring failure mode this guards against is silent: in a non-interactive
28
+ * session the keyring cannot be unlocked, `KeyChain.getPassword()` swallows the
29
+ * error and returns null, and the SDK reports it as "no credentials" — which is
30
+ * indistinguishable from genuinely having none. So say which of the two it is.
31
+ */
32
+ private failAuth;
23
33
  }
24
34
  //# sourceMappingURL=authenticated-command.d.ts.map
@@ -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,EAAE,MAAM,EAAE,kBAAkB,EAA8B,MAAM,4BAA4B,CAAC;AAMpG,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;;;MASf;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;cAQrD,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC;IAK9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAwCnC"}
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,EAAE,MAAM,EAAE,kBAAkB,EAA8B,MAAM,4BAA4B,CAAC;AAMpG,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;;;;MAmBf;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;cAUrD,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC;IAK9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAuDlC;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ;CA0BjB"}