@knowttl/mg-axi 0.1.1 → 0.1.3
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 +251 -77
- package/dist/api.js +253 -8
- package/dist/bin/mg-axi-hook.js +31 -0
- package/dist/catalogue.js +693 -2
- package/dist/cli.js +155 -17
- package/dist/docs.js +175 -46
- package/dist/doctor.js +2 -2
- package/dist/entra-access-reviews.js +11 -4
- package/dist/entra-apps.js +171 -14
- package/dist/entra-audit-logs.js +101 -16
- package/dist/entra-auth-methods.js +8 -4
- package/dist/entra-certificate-auth.js +12 -8
- package/dist/entra-conditional-access.js +425 -15
- package/dist/entra-contacts.js +19 -12
- package/dist/entra-contracts.js +7 -4
- package/dist/entra-custom-security-attributes.js +19 -12
- package/dist/entra-data-policy-operations.js +7 -4
- package/dist/entra-delegated-admin.js +55 -6
- package/dist/entra-deleted-items.js +6 -4
- package/dist/entra-directory-objects.js +6 -4
- package/dist/entra-directory.js +19 -12
- package/dist/entra-domains.js +13 -8
- package/dist/entra-entitlement-management.js +12 -4
- package/dist/entra-federation-configurations.js +7 -4
- package/dist/entra-grants.js +8 -4
- package/dist/entra-group-lifecycle.js +13 -8
- package/dist/entra-group-pim.js +431 -0
- package/dist/entra-groups.js +13 -8
- package/dist/entra-identity-providers.js +7 -4
- package/dist/entra-lifecycle-workflows.js +152 -13
- package/dist/entra-multi-tenant-organization.js +7 -4
- package/dist/entra-on-premises-synchronization.js +6 -4
- package/dist/entra-organization.js +13 -8
- package/dist/entra-risk-prevention.js +442 -0
- package/dist/entra-risk.js +224 -9
- package/dist/entra-roles.js +204 -12
- package/dist/entra-subscriptions.js +6 -4
- package/dist/entra-terms-of-use.js +13 -8
- package/dist/entra-users.js +7 -4
- package/dist/graph-session.js +30 -5
- package/dist/hook.js +84 -0
- package/dist/list-totals.js +52 -0
- package/dist/setup.js +9 -1
- package/docs/coverage.md +743 -610
- package/inventory/operations.json +2 -2
- package/inventory/schema.json +1 -1
- package/package.json +4 -3
- package/skills/mg-axi/SKILL.md +86 -1
package/dist/entra-contracts.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-04 partner contracts subfamily: the read mapping behind `mg-axi entra
|
|
3
4
|
// contract list/show/count`. Operation construction stays beside its command;
|
|
4
5
|
// the shared session owns URLs, credentials, paging, retries and error
|
|
@@ -198,20 +199,22 @@ export async function listContracts(session, flags, profile, operation, help, pr
|
|
|
198
199
|
if (!result.complete) {
|
|
199
200
|
return {
|
|
200
201
|
contracts,
|
|
201
|
-
|
|
202
|
+
...listTotals(contracts.length, result.total, "contracts", false),
|
|
203
|
+
complete: false,
|
|
204
|
+
reason: result.reason,
|
|
202
205
|
cursor: result.cursor,
|
|
203
206
|
help: [...truncationHints, resumeHint(profileName), showHint, PARTNER_NOTE],
|
|
204
207
|
};
|
|
205
208
|
}
|
|
206
|
-
const count = { returned: contracts.length, complete: true };
|
|
207
209
|
if (!contracts.length) {
|
|
208
210
|
return {
|
|
209
211
|
contracts,
|
|
210
|
-
|
|
212
|
+
...listTotals(contracts.length, result.total, "contracts", true),
|
|
213
|
+
complete: true,
|
|
211
214
|
help: ["0 contracts matched; the absence of results is the answer, not an error", PARTNER_NOTE],
|
|
212
215
|
};
|
|
213
216
|
}
|
|
214
|
-
return { contracts,
|
|
217
|
+
return { contracts, ...listTotals(contracts.length, result.total, "contracts", true), complete: true, help: [...truncationHints, showHint, PARTNER_NOTE] };
|
|
215
218
|
}
|
|
216
219
|
export async function showContract(session, flags, profile, operation, help, profileName) {
|
|
217
220
|
const { select, fields } = selectedFields(flags, KNOWN_CONTRACTS, KNOWN_CONTRACT_FIELDS, DEFAULT_CONTRACT_SHOW_SELECT, help);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-01 custom-security-attributes subfamily: the read mapping behind
|
|
3
4
|
// `mg-axi entra attribute-set list/show/count`,
|
|
4
5
|
// `mg-axi entra custom-security-attribute-definition list/show/count` and
|
|
@@ -265,20 +266,22 @@ export async function listAttributeSets(session, flags, profile, operation, help
|
|
|
265
266
|
if (!result.complete) {
|
|
266
267
|
return {
|
|
267
268
|
attributeSets: sets,
|
|
268
|
-
|
|
269
|
+
...listTotals(sets.length, result.total, "attribute sets", false),
|
|
270
|
+
complete: false,
|
|
271
|
+
reason: result.reason,
|
|
269
272
|
cursor: result.cursor,
|
|
270
273
|
help: [...truncationHints, resumeHint(profileName), showHint, filterNote],
|
|
271
274
|
};
|
|
272
275
|
}
|
|
273
|
-
const count = { returned: sets.length, complete: true };
|
|
274
276
|
if (!sets.length) {
|
|
275
277
|
return {
|
|
276
278
|
attributeSets: sets,
|
|
277
|
-
|
|
279
|
+
...listTotals(sets.length, result.total, "attribute sets", true),
|
|
280
|
+
complete: true,
|
|
278
281
|
help: [filterNote, "0 attribute sets matched; the absence of results is the answer, not an error"],
|
|
279
282
|
};
|
|
280
283
|
}
|
|
281
|
-
return { attributeSets: sets,
|
|
284
|
+
return { attributeSets: sets, ...listTotals(sets.length, result.total, "attribute sets", true), complete: true, help: [...truncationHints, showHint, filterNote] };
|
|
282
285
|
}
|
|
283
286
|
export async function showAttributeSet(session, flags, profile, operation, help, profileName) {
|
|
284
287
|
const { select, fields } = selectedFields(flags, KNOWN_ATTRIBUTE_SETS, KNOWN_ATTRIBUTE_SET_FIELDS, DEFAULT_ATTRIBUTE_SET_SHOW_SELECT, help, "attribute-set");
|
|
@@ -331,20 +334,22 @@ export async function listCustomSecurityAttributeDefinitions(session, flags, pro
|
|
|
331
334
|
if (!result.complete) {
|
|
332
335
|
return {
|
|
333
336
|
customSecurityAttributeDefinitions: definitions,
|
|
334
|
-
|
|
337
|
+
...listTotals(definitions.length, result.total, "custom security attribute definitions", false),
|
|
338
|
+
complete: false,
|
|
339
|
+
reason: result.reason,
|
|
335
340
|
cursor: result.cursor,
|
|
336
341
|
help: [...truncationHints, resumeHint(profileName), showHint],
|
|
337
342
|
};
|
|
338
343
|
}
|
|
339
|
-
const count = { returned: definitions.length, complete: true };
|
|
340
344
|
if (!definitions.length) {
|
|
341
345
|
return {
|
|
342
346
|
customSecurityAttributeDefinitions: definitions,
|
|
343
|
-
|
|
347
|
+
...listTotals(definitions.length, result.total, "custom security attribute definitions", true),
|
|
348
|
+
complete: true,
|
|
344
349
|
help: ["0 custom security attribute definitions matched; the absence of results is the answer, not an error"],
|
|
345
350
|
};
|
|
346
351
|
}
|
|
347
|
-
return { customSecurityAttributeDefinitions: definitions,
|
|
352
|
+
return { customSecurityAttributeDefinitions: definitions, ...listTotals(definitions.length, result.total, "custom security attribute definitions", true), complete: true, help: [...truncationHints, showHint] };
|
|
348
353
|
}
|
|
349
354
|
export async function showCustomSecurityAttributeDefinition(session, flags, profile, operation, help, profileName) {
|
|
350
355
|
const { select, fields } = selectedFields(flags, KNOWN_DEFINITIONS, KNOWN_CUSTOM_SECURITY_DEFINITION_FIELDS, DEFAULT_DEFINITION_SHOW_SELECT, help, "definition");
|
|
@@ -407,20 +412,22 @@ export async function listAllowedValues(session, flags, profile, operation, help
|
|
|
407
412
|
if (!result.complete) {
|
|
408
413
|
return {
|
|
409
414
|
allowedValues: values,
|
|
410
|
-
|
|
415
|
+
...listTotals(values.length, result.total, "allowed values", false),
|
|
416
|
+
complete: false,
|
|
417
|
+
reason: result.reason,
|
|
411
418
|
cursor: result.cursor,
|
|
412
419
|
help: [...truncationHints, resumeHint(profileName), showHint, filterNote],
|
|
413
420
|
};
|
|
414
421
|
}
|
|
415
|
-
const count = { returned: values.length, complete: true };
|
|
416
422
|
if (!values.length) {
|
|
417
423
|
return {
|
|
418
424
|
allowedValues: values,
|
|
419
|
-
|
|
425
|
+
...listTotals(values.length, result.total, "allowed values", true),
|
|
426
|
+
complete: true,
|
|
420
427
|
help: [filterNote, "0 allowed values matched; the definition may allow free-form values instead of predefined ones"],
|
|
421
428
|
};
|
|
422
429
|
}
|
|
423
|
-
return { allowedValues: values,
|
|
430
|
+
return { allowedValues: values, ...listTotals(values.length, result.total, "allowed values", true), complete: true, help: [...truncationHints, showHint, filterNote] };
|
|
424
431
|
}
|
|
425
432
|
export async function showAllowedValue(session, flags, profile, operation, help, profileName) {
|
|
426
433
|
const { select, fields } = selectedFields(flags, KNOWN_ALLOWED_VALUES, KNOWN_ALLOWED_VALUE_FIELDS, DEFAULT_ALLOWED_VALUE_SHOW_SELECT, help, "allowed-value");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
import { REDACTED } from "./graph-session.js";
|
|
3
4
|
// EXT-03 data-policy-operations subfamily: the read mapping behind
|
|
4
5
|
// `mg-axi entra data-policy-operation list/show/count`. Operation
|
|
@@ -224,20 +225,22 @@ export async function listDataPolicyOperations(session, flags, profile, operatio
|
|
|
224
225
|
if (!result.complete) {
|
|
225
226
|
return {
|
|
226
227
|
dataPolicyOperations: operations,
|
|
227
|
-
|
|
228
|
+
...listTotals(operations.length, result.total, "data-policy operations", false),
|
|
229
|
+
complete: false,
|
|
230
|
+
reason: result.reason,
|
|
228
231
|
cursor: result.cursor,
|
|
229
232
|
help: [...truncationHints, resumeHint(profileName), showHint, WORKFORCE_NOTE],
|
|
230
233
|
};
|
|
231
234
|
}
|
|
232
|
-
const count = { returned: operations.length, complete: true };
|
|
233
235
|
if (!operations.length) {
|
|
234
236
|
return {
|
|
235
237
|
dataPolicyOperations: operations,
|
|
236
|
-
|
|
238
|
+
...listTotals(operations.length, result.total, "data-policy operations", true),
|
|
239
|
+
complete: true,
|
|
237
240
|
help: ["0 data-policy operations matched; the absence of results is the answer, not an error", WORKFORCE_NOTE],
|
|
238
241
|
};
|
|
239
242
|
}
|
|
240
|
-
return { dataPolicyOperations: operations,
|
|
243
|
+
return { dataPolicyOperations: operations, ...listTotals(operations.length, result.total, "data-policy operations", true), complete: true, help: [...truncationHints, showHint, WORKFORCE_NOTE] };
|
|
241
244
|
}
|
|
242
245
|
export async function showDataPolicyOperation(session, flags, profile, operation, help, profileName) {
|
|
243
246
|
const { select, fields } = selectedFields(flags, DEFAULT_SHOW_SELECT, help);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-04 delegated-admin subfamily: the read mapping behind
|
|
3
4
|
// `mg-axi entra delegated-admin-customer list/show`,
|
|
4
5
|
// `mg-axi entra delegated-admin-relationship list/show` and the navigation
|
|
@@ -35,8 +36,8 @@ import { AxiError } from "axi-sdk-js";
|
|
|
35
36
|
// --filter passes through as plain $filter with no $count or ConsistencyLevel
|
|
36
37
|
// contract. serviceManagementDetails documents no query parameters, so both
|
|
37
38
|
// service-management-detail reads run queryless and project locally. The
|
|
38
|
-
// $count scalars
|
|
39
|
-
// for later EXT-04
|
|
39
|
+
// six $count scalars ship in this module; the tenantRelationship container
|
|
40
|
+
// root stays scheduled for a later EXT-04 subfamily, as do the multi-tenant-organization reads
|
|
40
41
|
// (shipped separately) and the tenant-lookup functions (shipped as
|
|
41
42
|
// tenant-information show under mg-ext-04e). Beta stays out. No delegated-admin mutation exists in this slice:
|
|
42
43
|
// relationship creation, approval and termination are writes.
|
|
@@ -389,20 +390,22 @@ async function listResource(session, flags, profile, operation, help, profileNam
|
|
|
389
390
|
if (!result.complete) {
|
|
390
391
|
return {
|
|
391
392
|
[collectionKey]: rows,
|
|
392
|
-
|
|
393
|
+
...listTotals(rows.length, result.total, `${resource.noun}s`, false),
|
|
394
|
+
complete: false,
|
|
395
|
+
reason: result.reason,
|
|
393
396
|
cursor: result.cursor,
|
|
394
397
|
help: [...truncationHints, resumeHint(profileName), showHint, partnerNote(resource)],
|
|
395
398
|
};
|
|
396
399
|
}
|
|
397
|
-
const count = { returned: rows.length, complete: true };
|
|
398
400
|
if (!rows.length) {
|
|
399
401
|
return {
|
|
400
402
|
[collectionKey]: rows,
|
|
401
|
-
|
|
403
|
+
...listTotals(rows.length, result.total, `${resource.noun}s`, true),
|
|
404
|
+
complete: true,
|
|
402
405
|
help: [`0 ${resource.noun}s matched; the absence of results is the answer, not an error`, partnerNote(resource)],
|
|
403
406
|
};
|
|
404
407
|
}
|
|
405
|
-
return { [collectionKey]: rows,
|
|
408
|
+
return { [collectionKey]: rows, ...listTotals(rows.length, result.total, `${resource.noun}s`, true), complete: true, help: [...truncationHints, showHint, partnerNote(resource)] };
|
|
406
409
|
}
|
|
407
410
|
async function showResource(session, flags, profile, operation, help, profileName, resource, rowKey, showCommand) {
|
|
408
411
|
const queryless = resource.queryless === true;
|
|
@@ -466,3 +469,49 @@ export async function listDelegatedAdminServiceManagementDetails(session, flags,
|
|
|
466
469
|
export async function showDelegatedAdminServiceManagementDetail(session, flags, profile, operation, help, profileName) {
|
|
467
470
|
return showResource(session, flags, profile, operation, help, profileName, SERVICE_MANAGEMENT_DETAIL, "delegatedAdminServiceManagementDetail", "entra delegated-admin-customer show-service-management-detail");
|
|
468
471
|
}
|
|
472
|
+
// The $count routes return a text/plain integer scalar rather than a JSON
|
|
473
|
+
// collection, so each leaf reads it through session.execute and accepts only
|
|
474
|
+
// a non-negative integer. There is no --filter/--select/--limit contract on
|
|
475
|
+
// the counts: the catalogue declares no such flags and strict input
|
|
476
|
+
// validation refuses them before credentials. All six share the parent
|
|
477
|
+
// list/show read scope DelegatedAdminRelationship.Read.All, so no new
|
|
478
|
+
// consent is needed.
|
|
479
|
+
function countParentId(flags, label, help) {
|
|
480
|
+
const id = String(flags.id);
|
|
481
|
+
if (!id.trim())
|
|
482
|
+
throw new AxiError(`--id needs the delegated-admin ${label} identifier`, "VALIDATION_ERROR", [help]);
|
|
483
|
+
return id;
|
|
484
|
+
}
|
|
485
|
+
async function countScalar(session, flags, profile, operation, help, profileName, params, rowKey, noun) {
|
|
486
|
+
void profileName;
|
|
487
|
+
const scopes = scopesFor(flags, DEFAULT_DELEGATED_ADMIN_SCOPES, profile, help);
|
|
488
|
+
const raw = await withGuidance(DELEGATED_ADMIN_DENIAL_HINTS, () => session.execute({ profile, operation, params, scopes }));
|
|
489
|
+
if (typeof raw !== "number" || !Number.isInteger(raw) || raw < 0) {
|
|
490
|
+
throw new AxiError(`Graph returned a malformed delegated-admin ${noun} count body`, "GRAPH_ERROR", [
|
|
491
|
+
"Delegated-admin counts carry one non-negative integer scalar; treat anything else as unknown, not empty",
|
|
492
|
+
]);
|
|
493
|
+
}
|
|
494
|
+
return { [rowKey]: raw };
|
|
495
|
+
}
|
|
496
|
+
export async function countDelegatedAdminCustomers(session, flags, profile, operation, help, profileName) {
|
|
497
|
+
return countScalar(session, flags, profile, operation, help, profileName, {}, "delegatedAdminCustomerCount", "customer");
|
|
498
|
+
}
|
|
499
|
+
export async function countDelegatedAdminServiceManagementDetails(session, flags, profile, operation, help, profileName) {
|
|
500
|
+
const customer = countParentId(flags, "customer", help);
|
|
501
|
+
return countScalar(session, flags, profile, operation, help, profileName, { "delegatedAdminCustomer-id": customer }, "delegatedAdminServiceManagementDetailCount", "service-management detail");
|
|
502
|
+
}
|
|
503
|
+
export async function countDelegatedAdminRelationships(session, flags, profile, operation, help, profileName) {
|
|
504
|
+
return countScalar(session, flags, profile, operation, help, profileName, {}, "delegatedAdminRelationshipCount", "relationship");
|
|
505
|
+
}
|
|
506
|
+
export async function countDelegatedAdminAccessAssignments(session, flags, profile, operation, help, profileName) {
|
|
507
|
+
const relationship = countParentId(flags, "relationship", help);
|
|
508
|
+
return countScalar(session, flags, profile, operation, help, profileName, { "delegatedAdminRelationship-id": relationship }, "delegatedAdminAccessAssignmentCount", "access assignment");
|
|
509
|
+
}
|
|
510
|
+
export async function countDelegatedAdminOperations(session, flags, profile, operation, help, profileName) {
|
|
511
|
+
const relationship = countParentId(flags, "relationship", help);
|
|
512
|
+
return countScalar(session, flags, profile, operation, help, profileName, { "delegatedAdminRelationship-id": relationship }, "delegatedAdminRelationshipOperationCount", "relationship operation");
|
|
513
|
+
}
|
|
514
|
+
export async function countDelegatedAdminRequests(session, flags, profile, operation, help, profileName) {
|
|
515
|
+
const relationship = countParentId(flags, "relationship", help);
|
|
516
|
+
return countScalar(session, flags, profile, operation, help, profileName, { "delegatedAdminRelationship-id": relationship }, "delegatedAdminRelationshipRequestCount", "relationship request");
|
|
517
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-01 deleted-items subfamily: the read mapping behind
|
|
3
4
|
// `mg-axi entra deleted-user|deleted-group|deleted-application|
|
|
4
5
|
// deleted-service-principal|deleted-administrative-unit list/count` and
|
|
@@ -402,16 +403,17 @@ export async function listDeletedItems(session, flags, profile, operation, help,
|
|
|
402
403
|
if (!result.complete) {
|
|
403
404
|
return {
|
|
404
405
|
deletedItems: rows,
|
|
405
|
-
|
|
406
|
+
...listTotals(rows.length, result.total, "deleted items", false),
|
|
407
|
+
complete: false,
|
|
408
|
+
reason: result.reason,
|
|
406
409
|
cursor: result.cursor,
|
|
407
410
|
help: [...truncationHints, resumeHint(profileName), showHint, ...groupNote, ...appNote],
|
|
408
411
|
};
|
|
409
412
|
}
|
|
410
|
-
const count = { returned: rows.length, complete: true };
|
|
411
413
|
if (!rows.length) {
|
|
412
|
-
return { deletedItems: rows,
|
|
414
|
+
return { deletedItems: rows, ...listTotals(rows.length, result.total, "deleted items", true), complete: true, help: [emptyNote, ...groupNote, ...appNote] };
|
|
413
415
|
}
|
|
414
|
-
return { deletedItems: rows,
|
|
416
|
+
return { deletedItems: rows, ...listTotals(rows.length, result.total, "deleted items", true), complete: true, help: [...truncationHints, showHint, ...groupNote, ...appNote] };
|
|
415
417
|
}
|
|
416
418
|
export async function showDeletedItem(session, flags, profile, operation, help, profileName) {
|
|
417
419
|
checkShowOperation(operation, help);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-01 directory-objects subfamily: the read mapping behind
|
|
3
4
|
// `mg-axi entra directory-object list/show/count`. Operation construction
|
|
4
5
|
// stays beside its command; the shared session owns URLs, credentials,
|
|
@@ -225,16 +226,17 @@ export async function listDirectoryObjects(session, flags, profile, operation, h
|
|
|
225
226
|
if (!result.complete) {
|
|
226
227
|
return {
|
|
227
228
|
directoryObjects,
|
|
228
|
-
|
|
229
|
+
...listTotals(directoryObjects.length, result.total, "directory objects", false),
|
|
230
|
+
complete: false,
|
|
231
|
+
reason: result.reason,
|
|
229
232
|
cursor: result.cursor,
|
|
230
233
|
help: [...truncationHints, resumeHint(profileName), showHint],
|
|
231
234
|
};
|
|
232
235
|
}
|
|
233
|
-
const count = { returned: directoryObjects.length, complete: true };
|
|
234
236
|
if (!directoryObjects.length) {
|
|
235
|
-
return { directoryObjects,
|
|
237
|
+
return { directoryObjects, ...listTotals(directoryObjects.length, result.total, "directory objects", true), complete: true, help: [EMPTY_NOTE] };
|
|
236
238
|
}
|
|
237
|
-
return { directoryObjects,
|
|
239
|
+
return { directoryObjects, ...listTotals(directoryObjects.length, result.total, "directory objects", true), complete: true, help: [...truncationHints, showHint] };
|
|
238
240
|
}
|
|
239
241
|
export async function showDirectoryObject(session, flags, profile, operation, help, profileName) {
|
|
240
242
|
checkReadOperation(operation, help);
|
package/dist/entra-directory.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// READ-10: the directory-device and administrative-unit read mapping behind
|
|
3
4
|
// `mg-axi entra device list/show`, `mg-axi entra administrative-unit
|
|
4
5
|
// list/show` and `mg-axi entra administrative-unit member list`. Operation
|
|
@@ -260,16 +261,18 @@ export async function listDevices(session, flags, profile, operation, help, prof
|
|
|
260
261
|
if (!result.complete) {
|
|
261
262
|
return {
|
|
262
263
|
devices,
|
|
263
|
-
|
|
264
|
+
...listTotals(devices.length, result.total, "devices", false),
|
|
265
|
+
complete: false,
|
|
266
|
+
reason: result.reason,
|
|
264
267
|
cursor: result.cursor,
|
|
265
268
|
help: [...truncationHints, resumeHint(profileName), showHint, scopeHint],
|
|
266
269
|
};
|
|
267
270
|
}
|
|
268
|
-
const count = { returned: devices.length, complete: true };
|
|
269
271
|
if (!devices.length) {
|
|
270
272
|
return {
|
|
271
273
|
devices,
|
|
272
|
-
|
|
274
|
+
...listTotals(devices.length, result.total, "devices", true),
|
|
275
|
+
complete: true,
|
|
273
276
|
help: [
|
|
274
277
|
`mg-axi entra device list --filter <odata-filter> ${profileHint(profileName)}`,
|
|
275
278
|
"0 devices matched; the absence of results is the answer, not an error",
|
|
@@ -277,7 +280,7 @@ export async function listDevices(session, flags, profile, operation, help, prof
|
|
|
277
280
|
],
|
|
278
281
|
};
|
|
279
282
|
}
|
|
280
|
-
return { devices,
|
|
283
|
+
return { devices, ...listTotals(devices.length, result.total, "devices", true), complete: true, help: [...truncationHints, showHint, scopeHint] };
|
|
281
284
|
}
|
|
282
285
|
export async function showDevice(session, flags, profile, operation, help, profileName) {
|
|
283
286
|
const { select, fields } = selectedFields(flags, KNOWN_DEVICES, KNOWN_DEVICE_FIELDS, DEFAULT_DEVICE_SHOW_SELECT, help);
|
|
@@ -318,23 +321,25 @@ export async function listAdministrativeUnits(session, flags, profile, operation
|
|
|
318
321
|
if (!result.complete) {
|
|
319
322
|
return {
|
|
320
323
|
administrativeUnits: units,
|
|
321
|
-
|
|
324
|
+
...listTotals(units.length, result.total, "administrative units", false),
|
|
325
|
+
complete: false,
|
|
326
|
+
reason: result.reason,
|
|
322
327
|
cursor: result.cursor,
|
|
323
328
|
help: [...truncationHints, resumeHint(profileName), showHint],
|
|
324
329
|
};
|
|
325
330
|
}
|
|
326
|
-
const count = { returned: units.length, complete: true };
|
|
327
331
|
if (!units.length) {
|
|
328
332
|
return {
|
|
329
333
|
administrativeUnits: units,
|
|
330
|
-
|
|
334
|
+
...listTotals(units.length, result.total, "administrative units", true),
|
|
335
|
+
complete: true,
|
|
331
336
|
help: [
|
|
332
337
|
`mg-axi entra administrative-unit list --filter <odata-filter> ${profileHint(profileName)}`,
|
|
333
338
|
"0 administrative units matched; the absence of results is the answer, not an error",
|
|
334
339
|
],
|
|
335
340
|
};
|
|
336
341
|
}
|
|
337
|
-
return { administrativeUnits: units,
|
|
342
|
+
return { administrativeUnits: units, ...listTotals(units.length, result.total, "administrative units", true), complete: true, help: [...truncationHints, showHint] };
|
|
338
343
|
}
|
|
339
344
|
export async function showAdministrativeUnit(session, flags, profile, operation, help, profileName) {
|
|
340
345
|
const { select, fields } = selectedFields(flags, KNOWN_AUS, KNOWN_AU_FIELDS, DEFAULT_AU_SHOW_SELECT, help);
|
|
@@ -390,16 +395,18 @@ export async function listAdministrativeUnitMembers(session, flags, profile, ope
|
|
|
390
395
|
if (!result.complete) {
|
|
391
396
|
return {
|
|
392
397
|
members: rows,
|
|
393
|
-
|
|
398
|
+
...listTotals(rows.length, result.total, "members", false),
|
|
399
|
+
complete: false,
|
|
400
|
+
reason: result.reason,
|
|
394
401
|
cursor: result.cursor,
|
|
395
402
|
help: [...truncationHints, ...limitedHints, hiddenHint, resumeHint(profileName)],
|
|
396
403
|
};
|
|
397
404
|
}
|
|
398
|
-
const count = { returned: rows.length, complete: true };
|
|
399
405
|
if (!rows.length) {
|
|
400
406
|
return {
|
|
401
407
|
members: rows,
|
|
402
|
-
|
|
408
|
+
...listTotals(rows.length, result.total, "members", true),
|
|
409
|
+
complete: true,
|
|
403
410
|
help: [
|
|
404
411
|
...limitedHints,
|
|
405
412
|
hiddenHint,
|
|
@@ -407,5 +414,5 @@ export async function listAdministrativeUnitMembers(session, flags, profile, ope
|
|
|
407
414
|
],
|
|
408
415
|
};
|
|
409
416
|
}
|
|
410
|
-
return { members: rows,
|
|
417
|
+
return { members: rows, ...listTotals(rows.length, result.total, "members", true), complete: true, help: [...truncationHints, ...limitedHints, hiddenHint] };
|
|
411
418
|
}
|
package/dist/entra-domains.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-01 domains subfamily: the read mapping behind `mg-axi entra domain
|
|
3
4
|
// list/show`, the per-domain verification and service-configuration DNS
|
|
4
5
|
// record reads, and the top-level domain DNS record reads. Operation
|
|
@@ -254,20 +255,22 @@ export async function listDomains(session, flags, profile, operation, help, prof
|
|
|
254
255
|
if (!result.complete) {
|
|
255
256
|
return {
|
|
256
257
|
domains,
|
|
257
|
-
|
|
258
|
+
...listTotals(domains.length, result.total, "domains", false),
|
|
259
|
+
complete: false,
|
|
260
|
+
reason: result.reason,
|
|
258
261
|
cursor: result.cursor,
|
|
259
262
|
help: [...truncationHints, resumeHint(profileName), showHint, filterNote],
|
|
260
263
|
};
|
|
261
264
|
}
|
|
262
|
-
const count = { returned: domains.length, complete: true };
|
|
263
265
|
if (!domains.length) {
|
|
264
266
|
return {
|
|
265
267
|
domains,
|
|
266
|
-
|
|
268
|
+
...listTotals(domains.length, result.total, "domains", true),
|
|
269
|
+
complete: true,
|
|
267
270
|
help: [filterNote, "0 domains matched; the absence of results is the answer, not an error"],
|
|
268
271
|
};
|
|
269
272
|
}
|
|
270
|
-
return { domains,
|
|
273
|
+
return { domains, ...listTotals(domains.length, result.total, "domains", true), complete: true, help: [...truncationHints, showHint, filterNote] };
|
|
271
274
|
}
|
|
272
275
|
export async function showDomain(session, flags, profile, operation, help, profileName) {
|
|
273
276
|
const { select, fields } = selectedFields(flags, KNOWN_DOMAINS, KNOWN_DOMAIN_FIELDS, DEFAULT_DOMAIN_SHOW_SELECT, help);
|
|
@@ -321,20 +324,22 @@ async function listDnsRecords(session, flags, profile, operation, help, profileN
|
|
|
321
324
|
if (!result.complete) {
|
|
322
325
|
return {
|
|
323
326
|
[command.collectionKey]: records,
|
|
324
|
-
|
|
327
|
+
...listTotals(records.length, result.total, "DNS records", false),
|
|
328
|
+
complete: false,
|
|
329
|
+
reason: result.reason,
|
|
325
330
|
cursor: result.cursor,
|
|
326
331
|
help: [...truncationHints, resumeHint(profileName), showHint, kindHint],
|
|
327
332
|
};
|
|
328
333
|
}
|
|
329
|
-
const count = { returned: records.length, complete: true };
|
|
330
334
|
if (!records.length) {
|
|
331
335
|
return {
|
|
332
336
|
[command.collectionKey]: records,
|
|
333
|
-
|
|
337
|
+
...listTotals(records.length, result.total, "DNS records", true),
|
|
338
|
+
complete: true,
|
|
334
339
|
help: [kindHint, "0 DNS records matched; the absence of results is the answer, not an error"],
|
|
335
340
|
};
|
|
336
341
|
}
|
|
337
|
-
return { [command.collectionKey]: records,
|
|
342
|
+
return { [command.collectionKey]: records, ...listTotals(records.length, result.total, "DNS records", true), complete: true, help: [...truncationHints, showHint, kindHint] };
|
|
338
343
|
}
|
|
339
344
|
async function showDnsRecord(session, flags, profile, operation, help, profileName, command) {
|
|
340
345
|
const { select, fields } = selectedFields(flags, KNOWN_DNS, KNOWN_DNS_FIELDS, DEFAULT_DNS_SHOW_SELECT, help);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-02 entitlement-management reads: the read-only catalog and
|
|
3
4
|
// access-package mapping plus the assignment and request reads. See
|
|
4
5
|
// README.md for the supported commands and usage. Operation construction
|
|
@@ -348,6 +349,7 @@ function flattenRequestLinks(source) {
|
|
|
348
349
|
const CATALOG_LIST = {
|
|
349
350
|
command: "entra entitlement catalog list",
|
|
350
351
|
key: "catalogs",
|
|
352
|
+
noun: "catalogs",
|
|
351
353
|
known: CATALOG_KNOWN,
|
|
352
354
|
knownList: KNOWN_CATALOG_FIELDS,
|
|
353
355
|
defaultSelect: DEFAULT_CATALOG_LIST_SELECT,
|
|
@@ -360,6 +362,7 @@ const CATALOG_LIST = {
|
|
|
360
362
|
const ACCESS_PACKAGE_LIST = {
|
|
361
363
|
command: "entra entitlement access-package list",
|
|
362
364
|
key: "accessPackages",
|
|
365
|
+
noun: "access packages",
|
|
363
366
|
known: ACCESS_PACKAGE_KNOWN,
|
|
364
367
|
knownList: KNOWN_ACCESS_PACKAGE_FIELDS,
|
|
365
368
|
defaultSelect: DEFAULT_ACCESS_PACKAGE_LIST_SELECT,
|
|
@@ -372,6 +375,7 @@ const ACCESS_PACKAGE_LIST = {
|
|
|
372
375
|
const ASSIGNMENT_POLICY_LIST = {
|
|
373
376
|
command: "entra entitlement assignment-policy list",
|
|
374
377
|
key: "assignmentPolicies",
|
|
378
|
+
noun: "assignment policies",
|
|
375
379
|
known: ASSIGNMENT_POLICY_KNOWN,
|
|
376
380
|
knownList: KNOWN_ASSIGNMENT_POLICY_FIELDS,
|
|
377
381
|
defaultSelect: DEFAULT_ASSIGNMENT_POLICY_LIST_SELECT,
|
|
@@ -384,6 +388,7 @@ const ASSIGNMENT_POLICY_LIST = {
|
|
|
384
388
|
const RESOURCE_ROLE_SCOPE_LIST = {
|
|
385
389
|
command: "entra entitlement resource-role-scope list",
|
|
386
390
|
key: "resourceRoleScopes",
|
|
391
|
+
noun: "resource-role scopes",
|
|
387
392
|
known: RESOURCE_ROLE_SCOPE_KNOWN,
|
|
388
393
|
knownList: KNOWN_RESOURCE_ROLE_SCOPE_FIELDS,
|
|
389
394
|
defaultSelect: DEFAULT_RESOURCE_ROLE_SCOPE_LIST_SELECT,
|
|
@@ -396,6 +401,7 @@ const RESOURCE_ROLE_SCOPE_LIST = {
|
|
|
396
401
|
const ASSIGNMENT_LIST = {
|
|
397
402
|
command: "entra entitlement assignment list",
|
|
398
403
|
key: "assignments",
|
|
404
|
+
noun: "assignments",
|
|
399
405
|
known: ASSIGNMENT_KNOWN,
|
|
400
406
|
knownList: KNOWN_ASSIGNMENT_FIELDS,
|
|
401
407
|
defaultSelect: DEFAULT_ASSIGNMENT_LIST_SELECT,
|
|
@@ -413,6 +419,7 @@ const ASSIGNMENT_LIST = {
|
|
|
413
419
|
const ASSIGNMENT_REQUEST_LIST = {
|
|
414
420
|
command: "entra entitlement assignment-request list",
|
|
415
421
|
key: "assignmentRequests",
|
|
422
|
+
noun: "assignment requests",
|
|
416
423
|
known: ASSIGNMENT_REQUEST_KNOWN,
|
|
417
424
|
knownList: KNOWN_ASSIGNMENT_REQUEST_FIELDS,
|
|
418
425
|
defaultSelect: DEFAULT_ASSIGNMENT_REQUEST_LIST_SELECT,
|
|
@@ -501,16 +508,17 @@ async function listCollection(shape, session, flags, profile, operation, help, p
|
|
|
501
508
|
if (!result.complete) {
|
|
502
509
|
return {
|
|
503
510
|
[shape.key]: rows,
|
|
504
|
-
|
|
511
|
+
...listTotals(rows.length, result.total, shape.noun, false),
|
|
512
|
+
complete: false,
|
|
513
|
+
reason: result.reason,
|
|
505
514
|
cursor: result.cursor,
|
|
506
515
|
help: [...truncationHints, resumeHint, ...standing],
|
|
507
516
|
};
|
|
508
517
|
}
|
|
509
|
-
const count = { returned: rows.length, complete: true };
|
|
510
518
|
if (!rows.length) {
|
|
511
|
-
return { [shape.key]: rows,
|
|
519
|
+
return { [shape.key]: rows, ...listTotals(rows.length, result.total, shape.noun, true), complete: true, help: [shape.emptyNote, ...standing] };
|
|
512
520
|
}
|
|
513
|
-
return { [shape.key]: rows,
|
|
521
|
+
return { [shape.key]: rows, ...listTotals(rows.length, result.total, shape.noun, true), complete: true, help: [...truncationHints, ...standing] };
|
|
514
522
|
}
|
|
515
523
|
async function showOne(key, command, known, knownList, defaultSelect, session, flags, profile, operation, help, profileName, params, malformed, extra) {
|
|
516
524
|
const { select, fields, fetch } = selectedFields(flags, defaultSelect, known, knownList, help, extra?.synthetic);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-01 directory federation-configurations subfamily: the read mapping
|
|
3
4
|
// behind `mg-axi entra federation-configuration list/show/count/available-types`.
|
|
4
5
|
// Operation construction stays beside its command; the shared session owns
|
|
@@ -203,20 +204,22 @@ export async function listFederationConfigurations(session, flags, profile, oper
|
|
|
203
204
|
if (!result.complete) {
|
|
204
205
|
return {
|
|
205
206
|
federationConfigurations: configurations,
|
|
206
|
-
|
|
207
|
+
...listTotals(configurations.length, result.total, "federation configurations", false),
|
|
208
|
+
complete: false,
|
|
209
|
+
reason: result.reason,
|
|
207
210
|
cursor: result.cursor,
|
|
208
211
|
help: [...truncationHints, `Resume losslessly with the same flags plus --cursor <cursor-from-output> ${profileHint(profileName)}`, showHint, CERT_BLOB_NOTE, WORKFORCE_NOTE],
|
|
209
212
|
};
|
|
210
213
|
}
|
|
211
|
-
const count = { returned: configurations.length, complete: true };
|
|
212
214
|
if (!configurations.length) {
|
|
213
215
|
return {
|
|
214
216
|
federationConfigurations: configurations,
|
|
215
|
-
|
|
217
|
+
...listTotals(configurations.length, result.total, "federation configurations", true),
|
|
218
|
+
complete: true,
|
|
216
219
|
help: ["0 federation configurations matched; no SAML or WS-Fed federation is configured for the tenant, or no row passed --filter", CERT_BLOB_NOTE, WORKFORCE_NOTE],
|
|
217
220
|
};
|
|
218
221
|
}
|
|
219
|
-
return { federationConfigurations: configurations,
|
|
222
|
+
return { federationConfigurations: configurations, ...listTotals(configurations.length, result.total, "federation configurations", true), complete: true, help: [...truncationHints, showHint, CERT_BLOB_NOTE, WORKFORCE_NOTE] };
|
|
220
223
|
}
|
|
221
224
|
export async function showFederationConfiguration(session, flags, profile, operation, help, profileName) {
|
|
222
225
|
const { select, fields } = selectedFields(flags, DEFAULT_SHOW_SELECT, help);
|
package/dist/entra-grants.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// READ-08: the Entra consent-grant read mapping behind
|
|
3
4
|
// `mg-axi entra service-principal oauth2-grant list` and
|
|
4
5
|
// `mg-axi entra service-principal app-role-assignment list` for a named
|
|
@@ -181,6 +182,7 @@ const APP_ROLE_DENIAL_HINTS = [
|
|
|
181
182
|
const OAUTH2_GRANT_LIST = {
|
|
182
183
|
command: "entra service-principal oauth2-grant list",
|
|
183
184
|
key: "oauth2PermissionGrants",
|
|
185
|
+
noun: "oauth2 grants",
|
|
184
186
|
known: GRANT_KNOWN,
|
|
185
187
|
knownList: KNOWN_GRANT_FIELDS,
|
|
186
188
|
defaultSelect: DEFAULT_GRANT_SELECT,
|
|
@@ -192,6 +194,7 @@ const OAUTH2_GRANT_LIST = {
|
|
|
192
194
|
const APP_ROLE_LIST = {
|
|
193
195
|
command: "entra service-principal app-role-assignment list",
|
|
194
196
|
key: "appRoleAssignments",
|
|
197
|
+
noun: "app role assignments",
|
|
195
198
|
known: APP_ROLE_KNOWN,
|
|
196
199
|
knownList: KNOWN_APP_ROLE_FIELDS,
|
|
197
200
|
defaultSelect: DEFAULT_APP_ROLE_SELECT,
|
|
@@ -253,16 +256,17 @@ async function listCollection(shape, session, flags, profile, operation, help, p
|
|
|
253
256
|
if (!result.complete) {
|
|
254
257
|
return {
|
|
255
258
|
[shape.key]: rows,
|
|
256
|
-
|
|
259
|
+
...listTotals(rows.length, result.total, shape.noun, false),
|
|
260
|
+
complete: false,
|
|
261
|
+
reason: result.reason,
|
|
257
262
|
cursor: result.cursor,
|
|
258
263
|
help: [...truncationHints, `Resume losslessly with the same flags plus --cursor <cursor-from-output> ${profileHint(profileName)}`, ...standing],
|
|
259
264
|
};
|
|
260
265
|
}
|
|
261
|
-
const count = { returned: rows.length, complete: true };
|
|
262
266
|
if (!rows.length) {
|
|
263
|
-
return { [shape.key]: rows,
|
|
267
|
+
return { [shape.key]: rows, ...listTotals(rows.length, result.total, shape.noun, true), complete: true, help: [shape.emptyNote, ...standing] };
|
|
264
268
|
}
|
|
265
|
-
return { [shape.key]: rows,
|
|
269
|
+
return { [shape.key]: rows, ...listTotals(rows.length, result.total, shape.noun, true), complete: true, help: [...truncationHints, ...standing] };
|
|
266
270
|
}
|
|
267
271
|
export async function listOAuth2Grants(session, flags, profile, operation, help, profileName) {
|
|
268
272
|
return listCollection(OAUTH2_GRANT_LIST, session, flags, profile, operation, help, profileName);
|