@knowttl/mg-axi 0.1.2 → 0.1.4

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.
@@ -1,9 +1,12 @@
1
1
  import { AxiError } from "axi-sdk-js";
2
+ import { KNOWN_APP_ROLE_FIELDS } from "./entra-grants.js";
2
3
  import { listTotals } from "./list-totals.js";
3
4
  import { SAFE_CREDENTIAL_FIELDS } from "./graph-session.js";
4
5
  // READ-07: the Entra application and service-principal read mapping behind
5
6
  // `mg-axi entra application list/show`, `mg-axi entra service-principal
6
- // list/show` and the two `owner list` relationship reads. Operation
7
+ // list/show`, the two `owner list` relationship reads, the service-principal
8
+ // `app-role-assigned-to` and `app-role-assignment show` assignment reads and
9
+ // the two `federated-credential` collections. Operation
7
10
  // construction stays beside its command; the shared session owns URLs,
8
11
  // credentials, paging, retries and error translation, and the SDK owns TOON
9
12
  // rendering. This module only maps flags to session calls and projects rows
@@ -14,14 +17,18 @@ import { SAFE_CREDENTIAL_FIELDS } from "./graph-session.js";
14
17
  // servicePrincipal-list-owners operation documentation on 2026-10-04.
15
18
  // Delegated and application reads take Application.Read.All; the object id
16
19
  // (`id`) is never conflated with the client ID (`appId`) - both ride in the
17
- // compact list defaults so callers can see the distinction. Consent grants
18
- // (appRoleAssignments, oauth2PermissionGrants) are READ-08 and stay out of
19
- // this slice; only owners are projected as relationships.
20
+ // compact list defaults so callers can see the distinction. Delegated
21
+ // permission grants (oauth2PermissionGrants) are READ-08 and stay out of
22
+ // this slice; only owners, direct assignments and federated credentials are
23
+ // projected as relationships. Alternate-key lookups by appId and
24
+ // federated-credential lookups by name stay out too: they need a validated
25
+ // function-argument binding the session guard does not have, and widening
26
+ // the guard is out of scope for a read slice.
20
27
  //
21
28
  // Credential safety belongs to the shared session's SAFE_CREDENTIAL_FIELDS
22
29
  // projection, applied before collection buffering and again on cursor decode.
23
30
  // Local projection uses that same allowlist for the displayed view.
24
- // The six GET operations below are the only ones this module ever binds;
31
+ // The thirteen GET operations below are the only ones this module ever binds;
25
32
  // secret-minting routes (addPassword, addKey) and every write stay refused before
26
33
  // credentials via checkReadOperation.
27
34
  // Every application property this slice may request or display. Anything
@@ -52,6 +59,20 @@ export const KNOWN_SP_FIELDS = [
52
59
  "passwordCredentials",
53
60
  ];
54
61
  const KNOWN_SPS = new Set(KNOWN_SP_FIELDS);
62
+ const KNOWN_ASSIGNED = new Set(KNOWN_APP_ROLE_FIELDS);
63
+ // Federated-credential rows carry workload-identity metadata only: issuer,
64
+ // subject and audiences name the trusted token source. There is no secret
65
+ // material on this resource, and the projection still drops anything outside
66
+ // this set so a future property can never leak through.
67
+ export const KNOWN_FEDERATED_FIELDS = [
68
+ "id",
69
+ "name",
70
+ "issuer",
71
+ "subject",
72
+ "description",
73
+ "audiences",
74
+ ];
75
+ const KNOWN_FEDERATED = new Set(KNOWN_FEDERATED_FIELDS);
55
76
  // Owner rows are directoryObjects of mixed types; richer per-type fields
56
77
  // need single-object reads, so only these stay selectable.
57
78
  export const KNOWN_OWNER_FIELDS = ["id", "displayName", "mail"];
@@ -68,6 +89,17 @@ const DEFAULT_APP_SHOW_SELECT = [...KNOWN_APP_FIELDS];
68
89
  const DEFAULT_SP_SHOW_SELECT = [...KNOWN_SP_FIELDS];
69
90
  // Compact owner rows: identifier, display name and address.
70
91
  const DEFAULT_OWNER_SELECT = ["id", "displayName", "mail"];
92
+ // Compact federated-credential rows: the credential id, its name and the
93
+ // trusted token source. The full set adds the human description and the
94
+ // audience list.
95
+ const DEFAULT_FEDERATED_LIST_SELECT = ["id", "name", "issuer", "subject"];
96
+ const DEFAULT_FEDERATED_SHOW_SELECT = [...KNOWN_FEDERATED_FIELDS];
97
+ // Compact assignment rows: the assignment id, the granted role and who
98
+ // holds it. principalId is constant for one service principal's
99
+ // appRoleAssignments list but varies across appRoleAssignedTo rows.
100
+ const DEFAULT_ASSIGNED_LIST_SELECT = ["id", "appRoleId", "principalDisplayName", "principalId", "principalType", "resourceDisplayName", "resourceId"];
101
+ ;
102
+ const DEFAULT_ASSIGNED_SHOW_SELECT = [...KNOWN_APP_ROLE_FIELDS];
71
103
  // Application.Read.All covers applications, service principals and owners in
72
104
  // both modes; delegated reads default to it unless --scopes overrides it.
73
105
  export const DEFAULT_DELEGATED_SCOPES = ["https://graph.microsoft.com/Application.Read.All"];
@@ -78,9 +110,16 @@ const READ_OPERATIONS = {
78
110
  "GET:/applications": "application",
79
111
  "GET:/applications/{application-id}": "application",
80
112
  "GET:/applications/{application-id}/owners": "application",
113
+ "GET:/applications/{application-id}/federatedIdentityCredentials": "application",
114
+ "GET:/applications/{application-id}/federatedIdentityCredentials/{federatedIdentityCredential-id}": "application",
81
115
  "GET:/servicePrincipals": "service-principal",
82
116
  "GET:/servicePrincipals/{servicePrincipal-id}": "service-principal",
83
117
  "GET:/servicePrincipals/{servicePrincipal-id}/owners": "service-principal",
118
+ "GET:/servicePrincipals/{servicePrincipal-id}/appRoleAssignedTo": "service-principal",
119
+ "GET:/servicePrincipals/{servicePrincipal-id}/appRoleAssignedTo/{appRoleAssignment-id}": "service-principal",
120
+ "GET:/servicePrincipals/{servicePrincipal-id}/appRoleAssignments/{appRoleAssignment-id}": "service-principal",
121
+ "GET:/servicePrincipals/{servicePrincipal-id}/federatedIdentityCredentials": "service-principal",
122
+ "GET:/servicePrincipals/{servicePrincipal-id}/federatedIdentityCredentials/{federatedIdentityCredential-id}": "service-principal",
84
123
  };
85
124
  function checkReadOperation(operation, help) {
86
125
  // Version stays the session's decision: beta reads remain preview-gated
@@ -88,7 +127,7 @@ function checkReadOperation(operation, help) {
88
127
  // fabricated secret-minting or write route can never reach credentials.
89
128
  const route = `${operation.method}:${operation.path}`;
90
129
  if (operation.method !== "GET" || !Object.hasOwn(READ_OPERATIONS, route)) {
91
- throw new AxiError(`Refused non-read route ${operation.id}: READ-07 serves only the six catalogued application and service-principal GETs`, "VALIDATION_ERROR", [
130
+ throw new AxiError(`Refused non-read route ${operation.id}: READ-07 serves only the thirteen catalogued application and service-principal GETs`, "VALIDATION_ERROR", [
92
131
  help,
93
132
  "Secret-minting routes (addPassword, addKey) and writes are never constructed here; consent grants belong to READ-08",
94
133
  ]);
@@ -377,3 +416,116 @@ export async function listApplicationOwners(session, flags, profile, operation,
377
416
  export async function listServicePrincipalOwners(session, flags, profile, operation, help, profileName) {
378
417
  return listOwners(session, flags, profile, operation, help, profileName, "entra service-principal owner list", "servicePrincipal-id", "service-principal");
379
418
  }
419
+ async function listChildCollection(session, flags, profile, operation, help, profileName, child, known, knownList, defaults) {
420
+ checkReadOperation(operation, help);
421
+ const parent = String(flags[child.parentFlag]);
422
+ if (!parent.trim())
423
+ throw new AxiError(`--${child.parentFlag} needs ${child.parentLabel}`, "VALIDATION_ERROR", [help]);
424
+ const common = collectionCommon(session, flags, known, knownList, defaults, operation, help, profile);
425
+ const args = collectArgs(profile, operation, common, flags, help);
426
+ args.params = { [child.parentParam]: parent };
427
+ const result = await session.collect(args);
428
+ const effectiveFlags = { ...flags, select: result.query.$select ?? defaults.join(",") };
429
+ if (result.query.$filter !== undefined)
430
+ effectiveFlags.filter = result.query.$filter;
431
+ const rows = [];
432
+ let truncated = false;
433
+ for (const row of result.value) {
434
+ const projected = project(row, common.fields, common.full);
435
+ rows.push(projected.row);
436
+ truncated = truncated || projected.truncated;
437
+ }
438
+ const truncationHints = truncated ? [fullHint(child.command, effectiveFlags, profileName)] : [];
439
+ if (!result.complete) {
440
+ return {
441
+ [child.key]: rows,
442
+ ...listTotals(rows.length, result.total, child.emptyNoun, false),
443
+ complete: false,
444
+ reason: result.reason,
445
+ cursor: result.cursor,
446
+ help: [...truncationHints, resumeHint(profileName), child.showHint],
447
+ };
448
+ }
449
+ if (!rows.length) {
450
+ return {
451
+ [child.key]: rows,
452
+ ...listTotals(rows.length, result.total, child.emptyNoun, true),
453
+ complete: true,
454
+ help: [
455
+ `0 ${child.emptyNoun} matched; the absence of results is the answer, not an error`,
456
+ child.showHint,
457
+ ],
458
+ };
459
+ }
460
+ return { [child.key]: rows, ...listTotals(rows.length, result.total, child.emptyNoun, true), complete: true, help: [...truncationHints, child.showHint] };
461
+ }
462
+ async function showChildObject(session, flags, profile, operation, help, profileName, command, key, known, knownList, defaults, parentParam, parentFlag, parentLabel, childParam) {
463
+ checkReadOperation(operation, help);
464
+ const parent = String(flags[parentFlag]);
465
+ if (!parent.trim())
466
+ throw new AxiError(`--${parentFlag} needs ${parentLabel}`, "VALIDATION_ERROR", [help]);
467
+ const { select, fields } = selectedFields(flags, known, knownList, defaults, help);
468
+ const scopes = scopesFor(flags, profile, help);
469
+ const full = flags.full === true;
470
+ const raw = await session.execute({
471
+ profile,
472
+ operation,
473
+ params: { [parentParam]: parent, [childParam]: String(flags.id) },
474
+ query: { $select: select.join(",") },
475
+ scopes,
476
+ });
477
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
478
+ throw new AxiError("Graph returned a malformed child object body", "GRAPH_ERROR", [
479
+ "Single-object reads carry one object; treat anything else as unknown, not empty",
480
+ ]);
481
+ }
482
+ const { row, truncated } = project(raw, fields, full);
483
+ if (truncated)
484
+ return { [key]: row, help: [fullHint(command, flags, profileName)] };
485
+ return { [key]: row };
486
+ }
487
+ export async function listApplicationFederatedCredentials(session, flags, profile, operation, help, profileName) {
488
+ return listChildCollection(session, flags, profile, operation, help, profileName, {
489
+ command: "entra application federated-credential list",
490
+ key: "federatedCredentials",
491
+ emptyNoun: "federated credentials",
492
+ showHint: `mg-axi entra application federated-credential show --application <application-object-id> --id <credential-id> ${profileHint(profileName)}`,
493
+ parentParam: "application-id",
494
+ parentFlag: "application",
495
+ parentLabel: "the owning application object ID",
496
+ }, KNOWN_FEDERATED, KNOWN_FEDERATED_FIELDS, DEFAULT_FEDERATED_LIST_SELECT);
497
+ }
498
+ export async function showApplicationFederatedCredential(session, flags, profile, operation, help, profileName) {
499
+ return showChildObject(session, flags, profile, operation, help, profileName, "entra application federated-credential show", "federatedCredential", KNOWN_FEDERATED, KNOWN_FEDERATED_FIELDS, DEFAULT_FEDERATED_SHOW_SELECT, "application-id", "application", "the owning application object ID", "federatedIdentityCredential-id");
500
+ }
501
+ export async function listServicePrincipalFederatedCredentials(session, flags, profile, operation, help, profileName) {
502
+ return listChildCollection(session, flags, profile, operation, help, profileName, {
503
+ command: "entra service-principal federated-credential list",
504
+ key: "federatedCredentials",
505
+ emptyNoun: "federated credentials",
506
+ showHint: `mg-axi entra service-principal federated-credential show --service-principal <service-principal-object-id> --id <credential-id> ${profileHint(profileName)}`,
507
+ parentParam: "servicePrincipal-id",
508
+ parentFlag: "service-principal",
509
+ parentLabel: "the owning service-principal object ID",
510
+ }, KNOWN_FEDERATED, KNOWN_FEDERATED_FIELDS, DEFAULT_FEDERATED_LIST_SELECT);
511
+ }
512
+ export async function showServicePrincipalFederatedCredential(session, flags, profile, operation, help, profileName) {
513
+ return showChildObject(session, flags, profile, operation, help, profileName, "entra service-principal federated-credential show", "federatedCredential", KNOWN_FEDERATED, KNOWN_FEDERATED_FIELDS, DEFAULT_FEDERATED_SHOW_SELECT, "servicePrincipal-id", "service-principal", "the owning service-principal object ID", "federatedIdentityCredential-id");
514
+ }
515
+ export async function listServicePrincipalAssignedTo(session, flags, profile, operation, help, profileName) {
516
+ return listChildCollection(session, flags, profile, operation, help, profileName, {
517
+ command: "entra service-principal app-role-assigned-to list",
518
+ key: "appRoleAssignedTo",
519
+ emptyNoun: "app role assignments",
520
+ showHint: `mg-axi entra service-principal app-role-assigned-to show --service-principal <service-principal-object-id> --id <assignment-id> ${profileHint(profileName)}`,
521
+ parentParam: "servicePrincipal-id",
522
+ parentFlag: "service-principal",
523
+ parentLabel: "the resource service-principal object ID",
524
+ }, KNOWN_ASSIGNED, KNOWN_APP_ROLE_FIELDS, DEFAULT_ASSIGNED_LIST_SELECT);
525
+ }
526
+ export async function showServicePrincipalAssignedTo(session, flags, profile, operation, help, profileName) {
527
+ return showChildObject(session, flags, profile, operation, help, profileName, "entra service-principal app-role-assigned-to show", "appRoleAssignedTo", KNOWN_ASSIGNED, KNOWN_APP_ROLE_FIELDS, DEFAULT_ASSIGNED_SHOW_SELECT, "servicePrincipal-id", "service-principal", "the resource service-principal object ID", "appRoleAssignment-id");
528
+ }
529
+ export async function showServicePrincipalAppRoleAssignment(session, flags, profile, operation, help, profileName) {
530
+ return showChildObject(session, flags, profile, operation, help, profileName, "entra service-principal app-role-assignment show", "appRoleAssignment", KNOWN_ASSIGNED, KNOWN_APP_ROLE_FIELDS, DEFAULT_ASSIGNED_SHOW_SELECT, "servicePrincipal-id", "service-principal", "the client service-principal object ID", "appRoleAssignment-id");
531
+ }
@@ -1,18 +1,24 @@
1
1
  import { AxiError } from "axi-sdk-js";
2
2
  import { listTotals } from "./list-totals.js";
3
- // READ-05: the Entra sign-in and directory-audit read mapping behind
4
- // `mg-axi entra sign-in list/show` and `mg-axi entra directory-audit
5
- // list/show`. Operation construction stays beside its command; the shared
3
+ // READ-05: the Entra sign-in, directory-audit and provisioning-log read
4
+ // mapping behind `mg-axi entra sign-in list/show`, `mg-axi entra
5
+ // directory-audit list/show` and `mg-axi entra provisioning list/show`.
6
+ // Operation construction stays beside its command; the shared
6
7
  // session owns URLs, credentials, paging, retries and error translation, and
7
8
  // the SDK owns TOON rendering. This module only maps flags to session calls,
8
9
  // bounds every collection query in time, and projects rows for compact output.
9
10
  //
10
11
  // Reviewed against the v1.0 signin-list and directoryaudit-list operation
11
- // documentation on 2026-10-04. Both collections read D/A AuditLog.Read.All;
12
- // delegated sign-in reads additionally accept Global Reader, Reports Reader,
13
- // Security Administrator, Security Operator or Security Reader, while
14
- // delegated directory-audit reads accept Reports Reader, Security
15
- // Administrator or Security Reader. Graph omits appliedConditionalAccessPolicies
12
+ // documentation on 2026-10-04 and the provisioningobjectsummary-list
13
+ // documentation on 2026-10-06. Sign-in and directory-audit collections read
14
+ // D/A AuditLog.Read.All; delegated sign-in reads additionally accept Global
15
+ // Reader, Reports Reader, Security Administrator, Security Operator or
16
+ // Security Reader, while delegated directory-audit reads accept Reports
17
+ // Reader, Security Administrator or Security Reader. The provisioning
18
+ // collection reads D/A AuditLog.Read.All and Directory.Read.All together;
19
+ // delegated reads accept the same five roles as sign-ins, Reports Reader is
20
+ // the least privileged role for the logs, and the tenant needs a P1 or P2
21
+ // licence. Graph omits appliedConditionalAccessPolicies
16
22
  // without a CA-data permission/role, so an absent property is reported as
17
23
  // unavailable rather than invented. Sign-in/audit Graph reporting carries a
18
24
  // conservative P1/P2 deployment prerequisite; retention and premium fields
@@ -55,13 +61,45 @@ export const KNOWN_AUDIT_FIELDS = [
55
61
  ];
56
62
  const SIGNIN_KNOWN = new Set(KNOWN_SIGNIN_FIELDS);
57
63
  const AUDIT_KNOWN = new Set(KNOWN_AUDIT_FIELDS);
64
+ // The full reviewed provisioningObjectSummary property set. None of these
65
+ // is credential material (no password, key or secret properties), and the
66
+ // known-set gate rejects anything else before credentials; the session's
67
+ // shared redaction stays the backstop for secret-shaped values.
68
+ export const KNOWN_PROVISIONING_FIELDS = [
69
+ "id",
70
+ "activityDateTime",
71
+ "tenantId",
72
+ "jobId",
73
+ "cycleId",
74
+ "changeId",
75
+ "action",
76
+ "durationInMilliseconds",
77
+ "sourceSystem",
78
+ "sourceIdentity",
79
+ "targetSystem",
80
+ "targetIdentity",
81
+ "provisioningStatusInfo",
82
+ "provisioningSteps",
83
+ "modifiedProperties",
84
+ "servicePrincipal",
85
+ "initiatedBy",
86
+ ];
87
+ const PROVISIONING_KNOWN = new Set(KNOWN_PROVISIONING_FIELDS);
58
88
  // Compact list rows: identifier, time, who/what happened, and outcome.
59
89
  const DEFAULT_SIGNIN_LIST_SELECT = ["id", "createdDateTime", "userPrincipalName", "appDisplayName"];
60
90
  const DEFAULT_AUDIT_LIST_SELECT = ["id", "activityDateTime", "activityDisplayName", "result"];
91
+ const DEFAULT_PROVISIONING_LIST_SELECT = ["id", "activityDateTime", "action", "provisioningStatusInfo"];
61
92
  // Show rows: the full reviewed server set for one object.
62
93
  const DEFAULT_SIGNIN_SHOW_SELECT = [...KNOWN_SIGNIN_FIELDS];
63
94
  const DEFAULT_AUDIT_SHOW_SELECT = [...KNOWN_AUDIT_FIELDS];
95
+ const DEFAULT_PROVISIONING_SHOW_SELECT = [...KNOWN_PROVISIONING_FIELDS];
64
96
  export const DEFAULT_DELEGATED_SCOPES = ["https://graph.microsoft.com/AuditLog.Read.All"];
97
+ // Provisioning reads need both directory scopes; the pair is the documented
98
+ // least-privileged delegated set and both names already sit in READ_SCOPES.
99
+ export const DEFAULT_PROVISIONING_SCOPES = [
100
+ "https://graph.microsoft.com/AuditLog.Read.All",
101
+ "https://graph.microsoft.com/Directory.Read.All",
102
+ ];
65
103
  const TRUNCATE_AT = 500;
66
104
  // Graph omits this property without CA-data access instead of failing, so an
67
105
  // absent value reports the missing prerequisite rather than an empty result.
@@ -88,7 +126,7 @@ function fieldList(raw, flag, known, knownList, help) {
88
126
  }
89
127
  return fields;
90
128
  }
91
- function scopesFor(flags, profile, help) {
129
+ function scopesFor(flags, profile, help, defaultScopes = DEFAULT_DELEGATED_SCOPES) {
92
130
  if (profile.mode === "application") {
93
131
  if (flags.scopes !== undefined) {
94
132
  throw new AxiError("Application profiles use the configured Graph .default audience; delegated scopes are unavailable", "VALIDATION_ERROR", [help, "mg-axi profile show --profile <name>"]);
@@ -96,7 +134,7 @@ function scopesFor(flags, profile, help) {
96
134
  return undefined;
97
135
  }
98
136
  if (flags.scopes === undefined)
99
- return [...DEFAULT_DELEGATED_SCOPES];
137
+ return [...defaultScopes];
100
138
  const scopes = String(flags.scopes)
101
139
  .split(",")
102
140
  .map(scope => scope.trim())
@@ -227,11 +265,16 @@ const AUDIT_DENIAL_HINTS = [
227
265
  "Directory-audit reads need AuditLog.Read.All plus a supported directory role: Reports Reader, Security Administrator or Security Reader for delegated access, or admin-consented AuditLog.Read.All for application access",
228
266
  "Audit Graph reporting carries a conservative P1/P2 deployment prerequisite; retention stays a separate constraint",
229
267
  ];
268
+ const PROVISIONING_DENIAL_HINTS = [
269
+ "Provisioning-log reads need AuditLog.Read.All and Directory.Read.All plus a supported directory role: Global Reader, Reports Reader, Security Administrator, Security Operator or Security Reader for delegated access, or admin-consented AuditLog.Read.All and Directory.Read.All for application access",
270
+ "Provisioning logs need a Microsoft Entra ID P1 or P2 licence on the tenant; retention is 30 days on premium and 7 days on free",
271
+ ];
230
272
  const SIGNIN_LIST = {
231
273
  noun: "sign-in",
232
274
  plural: "sign-ins",
233
275
  key: "signIns",
234
276
  dateField: "createdDateTime",
277
+ defaultScopes: DEFAULT_DELEGATED_SCOPES,
235
278
  known: SIGNIN_KNOWN,
236
279
  knownList: KNOWN_SIGNIN_FIELDS,
237
280
  defaultSelect: DEFAULT_SIGNIN_LIST_SELECT,
@@ -248,6 +291,7 @@ const AUDIT_LIST = {
248
291
  plural: "directory audits",
249
292
  key: "directoryAudits",
250
293
  dateField: "activityDateTime",
294
+ defaultScopes: DEFAULT_DELEGATED_SCOPES,
251
295
  known: AUDIT_KNOWN,
252
296
  knownList: KNOWN_AUDIT_FIELDS,
253
297
  defaultSelect: DEFAULT_AUDIT_LIST_SELECT,
@@ -259,6 +303,23 @@ const AUDIT_LIST = {
259
303
  "0 directory audits matched in this window; widen --since/--until or loosen --filter - the absence of results is the answer, not an error",
260
304
  ],
261
305
  };
306
+ const PROVISIONING_LIST = {
307
+ noun: "provisioning",
308
+ plural: "provisioning events",
309
+ key: "provisioning",
310
+ dateField: "activityDateTime",
311
+ defaultScopes: DEFAULT_PROVISIONING_SCOPES,
312
+ known: PROVISIONING_KNOWN,
313
+ knownList: KNOWN_PROVISIONING_FIELDS,
314
+ defaultSelect: DEFAULT_PROVISIONING_LIST_SELECT,
315
+ unavailable: {},
316
+ denialHints: PROVISIONING_DENIAL_HINTS,
317
+ showHint: "mg-axi entra provisioning show --id <provisioning-id>",
318
+ emptyHints: profileName => [
319
+ `mg-axi entra provisioning list --since <earlier-iso-time> ${profileHint(profileName)}`,
320
+ "0 provisioning events matched in this window; widen --since/--until or loosen --filter - the absence of results is the answer, not an error",
321
+ ],
322
+ };
262
323
  async function listLogs(shape, session, flags, profile, operation, help, profileName) {
263
324
  const cursor = flags.cursor === undefined ? undefined : String(flags.cursor);
264
325
  if (cursor !== undefined && !cursor.trim())
@@ -280,7 +341,7 @@ async function listLogs(shape, session, flags, profile, operation, help, profile
280
341
  }
281
342
  const savedSelect = saved?.$select;
282
343
  const { select, fields } = selectedFields(flags, savedSelect === undefined ? shape.defaultSelect : fieldList(savedSelect, "select", shape.known, shape.knownList, help), shape.known, shape.knownList, help);
283
- const scopes = scopesFor(flags, profile, help);
344
+ const scopes = scopesFor(flags, profile, help, shape.defaultScopes);
284
345
  const full = flags.full === true;
285
346
  const filter = boundedFilter(shape.dateField, flags, help);
286
347
  const query = { $select: select.join(",") };
@@ -332,6 +393,7 @@ const SIGNIN_SHOW = {
332
393
  noun: "sign-in",
333
394
  key: "signIn",
334
395
  param: "signIn-id",
396
+ defaultScopes: DEFAULT_DELEGATED_SCOPES,
335
397
  known: SIGNIN_KNOWN,
336
398
  knownList: KNOWN_SIGNIN_FIELDS,
337
399
  defaultSelect: DEFAULT_SIGNIN_SHOW_SELECT,
@@ -343,6 +405,7 @@ const AUDIT_SHOW = {
343
405
  noun: "directory-audit",
344
406
  key: "directoryAudit",
345
407
  param: "directoryAudit-id",
408
+ defaultScopes: DEFAULT_DELEGATED_SCOPES,
346
409
  known: AUDIT_KNOWN,
347
410
  knownList: KNOWN_AUDIT_FIELDS,
348
411
  defaultSelect: DEFAULT_AUDIT_SHOW_SELECT,
@@ -350,9 +413,21 @@ const AUDIT_SHOW = {
350
413
  denialHints: AUDIT_DENIAL_HINTS,
351
414
  idFlag: "<directory-audit-id>",
352
415
  };
416
+ const PROVISIONING_SHOW = {
417
+ noun: "provisioning",
418
+ key: "provisioning",
419
+ param: "provisioningObjectSummary-id",
420
+ defaultScopes: DEFAULT_PROVISIONING_SCOPES,
421
+ known: PROVISIONING_KNOWN,
422
+ knownList: KNOWN_PROVISIONING_FIELDS,
423
+ defaultSelect: DEFAULT_PROVISIONING_SHOW_SELECT,
424
+ unavailable: {},
425
+ denialHints: PROVISIONING_DENIAL_HINTS,
426
+ idFlag: "<provisioning-id>",
427
+ };
353
428
  async function showLog(shape, session, flags, profile, operation, help, profileName) {
354
429
  const { select, fields } = selectedFields(flags, shape.defaultSelect, shape.known, shape.knownList, help);
355
- const scopes = scopesFor(flags, profile, help);
430
+ const scopes = scopesFor(flags, profile, help, shape.defaultScopes);
356
431
  const full = flags.full === true;
357
432
  const raw = await withGuidance(shape.denialHints, () => session.execute({
358
433
  profile,
@@ -383,3 +458,9 @@ export async function listDirectoryAudits(session, flags, profile, operation, he
383
458
  export async function showDirectoryAudit(session, flags, profile, operation, help, profileName) {
384
459
  return showLog(AUDIT_SHOW, session, flags, profile, operation, help, profileName);
385
460
  }
461
+ export async function listProvisioning(session, flags, profile, operation, help, profileName) {
462
+ return listLogs(PROVISIONING_LIST, session, flags, profile, operation, help, profileName);
463
+ }
464
+ export async function showProvisioning(session, flags, profile, operation, help, profileName) {
465
+ return showLog(PROVISIONING_SHOW, session, flags, profile, operation, help, profileName);
466
+ }