@jacebenson/jsn 4.3.13-dev.102.1 → 4.3.13-dev.104.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.
- package/README.md +9 -0
- package/package.json +1 -1
- package/src/command-audience.js +1 -0
- package/src/commands/cmdb-search.js +38 -0
- package/src/commands/cmdb.js +2 -0
package/README.md
CHANGED
|
@@ -83,6 +83,15 @@ an explicitly selected profile or instance. `updatesets show` also offers a scan
|
|
|
83
83
|
hint. Recommendation/generation of new checks is not part of this command;
|
|
84
84
|
JSN contains no AI and does not infer missing business requirements.
|
|
85
85
|
|
|
86
|
+
### CMDB search
|
|
87
|
+
|
|
88
|
+
`jsn cmdb search "web" --profile work` searches names, FQDNs, IP addresses and
|
|
89
|
+
serial numbers on `cmdb_ci`. Use `--class cmdb_ci_server` for an exact class
|
|
90
|
+
match (excluding subclasses), and bounded `--limit`/`--offset` pagination.
|
|
91
|
+
Search text is literal; encoded-query operators and query scripts are rejected.
|
|
92
|
+
Existing `cmdb list --query` remains available for deliberate encoded queries.
|
|
93
|
+
Results include show/relationship hints and preserve the selected connection.
|
|
94
|
+
|
|
86
95
|
### Supported versions
|
|
87
96
|
|
|
88
97
|
Only the current release and the two preceding releases in each channel are
|
package/package.json
CHANGED
package/src/command-audience.js
CHANGED
|
@@ -4,6 +4,7 @@ const BASIC_COMMANDS = new Set([
|
|
|
4
4
|
'incidents', 'changes', 'requests', 'tasks', 'tickets', 'approvals', 'records',
|
|
5
5
|
'knowledge',
|
|
6
6
|
'groups', 'groupmembers', 'grouproles', 'users', 'setup', 'auth', 'skill',
|
|
7
|
+
'cmdb',
|
|
7
8
|
'version', 'docs', 'history', 'discover', 'completion',
|
|
8
9
|
'catalogitems',
|
|
9
10
|
]);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { assertSafeExactMatch, quoteShellArg } from '../helpers.js';
|
|
2
|
+
import { errAPI, errUsage } from '../errors.js';
|
|
3
|
+
|
|
4
|
+
const FIELDS = ['name', 'fqdn', 'ip_address', 'serial_number'];
|
|
5
|
+
const raw = v => v && typeof v === 'object' ? v.value : v;
|
|
6
|
+
|
|
7
|
+
export function cmdbSearchCmd(wrap) {
|
|
8
|
+
return { command: 'search <text>', describe: 'Find CIs by name, FQDN, IP address, or serial number',
|
|
9
|
+
builder: y => y.positional('text', { type: 'string', describe: 'Literal text; quote multiple words' })
|
|
10
|
+
.option('class', { type: 'string', describe: 'Exact CI class name (not descendants)' })
|
|
11
|
+
.option('limit', { type: 'number', default: 20, describe: 'Maximum CIs (1–100)' })
|
|
12
|
+
.option('offset', { type: 'number', default: 0, describe: 'Starting result offset' }),
|
|
13
|
+
handler: wrap(async (argv, app) => {
|
|
14
|
+
if (typeof argv.text !== 'string' || !argv.text.trim()) throw errUsage('Provide nonempty CI search text.');
|
|
15
|
+
const text = argv.text.trim();
|
|
16
|
+
assertSafeExactMatch(text);
|
|
17
|
+
if ([...text].some(c => c.codePointAt(0) < 32 || c.codePointAt(0) === 127) || /javascript:/i.test(text)) throw errUsage('Search text must not contain query scripts or control characters.');
|
|
18
|
+
if (argv.class !== undefined && !/^[a-z][a-z0-9_]*$/.test(argv.class)) throw errUsage('--class must be an exact CI table name.');
|
|
19
|
+
if (!Number.isInteger(argv.limit) || argv.limit < 1 || argv.limit > 100) throw errUsage('--limit must be from 1 to 100.');
|
|
20
|
+
if (!Number.isInteger(argv.offset) || argv.offset < 0) throw errUsage('--offset must be a nonnegative integer.');
|
|
21
|
+
// Repeat the class restriction in each OR branch: no branch may escape it.
|
|
22
|
+
const query = FIELDS.map(f => `${f}LIKE${text}${argv.class ? `^sys_class_name=${argv.class}` : ''}`).join('^NQ') + '^ORDERBYname^ORDERBYsys_id';
|
|
23
|
+
const params = new URLSearchParams({ sysparm_query: query, sysparm_limit: String(argv.limit + 1), sysparm_offset: String(argv.offset),
|
|
24
|
+
sysparm_fields: 'sys_id,name,sys_class_name,fqdn,ip_address,serial_number', sysparm_display_value: 'all' });
|
|
25
|
+
const rows = await app.sdk.listStrict('cmdb_ci', params);
|
|
26
|
+
if (!Array.isArray(rows) || rows.some(r => !r || typeof r !== 'object' || Array.isArray(r))) throw errAPI(200, 'CMDB search returned no valid record list.');
|
|
27
|
+
const hasMore = rows.length > argv.limit, records = rows.slice(0, argv.limit);
|
|
28
|
+
const connection = argv.profile ? ` --profile ${quoteShellArg(argv.profile)}` : argv.instance ? ` --instance ${quoteShellArg(argv.instance)}` : '';
|
|
29
|
+
const breadcrumbs = records.flatMap(r => /^[a-f0-9]{32}$/i.test(raw(r.sys_id) || '') ? [
|
|
30
|
+
{ action: 'show', cmd: `jsn cmdb show ${raw(r.sys_id)}`, description: String(raw(r.name) || 'Inspect CI') },
|
|
31
|
+
{ action: 'relationships', cmd: `jsn cmdb relationships --ci ${raw(r.sys_id)}`, description: 'Inspect CI dependencies' },
|
|
32
|
+
] : []);
|
|
33
|
+
if (hasMore) breadcrumbs.push({ action: 'next', cmd: `jsn cmdb search ${quoteShellArg(text)} --limit ${argv.limit} --offset ${argv.offset + argv.limit}${argv.class ? ` --class ${argv.class}` : ''}`, description: 'Next matching CIs' });
|
|
34
|
+
app.ok({ table: 'cmdb_ci', search: text, fields: FIELDS, records, count: records.length,
|
|
35
|
+
pagination: { limit: argv.limit, offset: argv.offset, has_more: hasMore } },
|
|
36
|
+
{ summary: `${records.length} matching CI(s)`, breadcrumbs: breadcrumbs.map(h => ({ ...h, cmd: h.cmd + connection })) });
|
|
37
|
+
}) };
|
|
38
|
+
}
|
package/src/commands/cmdb.js
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
resolveFieldsParam,
|
|
16
16
|
} from '../helpers.js';
|
|
17
17
|
import { errNotFound, errUsage } from '../errors.js';
|
|
18
|
+
import { cmdbSearchCmd } from './cmdb-search.js';
|
|
18
19
|
|
|
19
20
|
const SYS_ID_RE = /^[0-9a-f]{32}$/i;
|
|
20
21
|
const MAX_DEPTH = 5;
|
|
@@ -371,6 +372,7 @@ export function cmdbCmd(wrap) {
|
|
|
371
372
|
}),
|
|
372
373
|
builder: (yargs) => {
|
|
373
374
|
return yargs
|
|
375
|
+
.command(cmdbSearchCmd(wrap))
|
|
374
376
|
.command({
|
|
375
377
|
command: 'list',
|
|
376
378
|
describe: 'List CIs from the CMDB (cmdb_ci)',
|