@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.
- package/README.md +127 -45
- package/dist/api.js +119 -0
- package/dist/app-auth.js +5 -1
- package/dist/catalogue.js +311 -3
- package/dist/cli.js +44 -12
- package/dist/docs.js +139 -47
- package/dist/entra-apps.js +158 -6
- package/dist/entra-audit-logs.js +93 -12
- package/dist/entra-conditional-access.js +416 -11
- 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-identity-providers.js +7 -4
- package/dist/entra-lifecycle-workflows.js +16 -4
- package/dist/entra-multi-tenant-organization.js +7 -4
- package/dist/entra-on-premises-synchronization.js +6 -4
- package/dist/entra-risk-prevention.js +10 -4
- package/dist/entra-risk.js +11 -4
- package/dist/entra-roles.js +194 -8
- package/dist/entra-terms-of-use.js +13 -8
- package/dist/graph-session.js +1 -0
- package/dist/msal-app-provider.js +96 -13
- package/dist/profiles.js +55 -9
- package/dist/setup.js +5 -2
- package/docs/coverage.md +721 -654
- package/inventory/operations.json +2 -2
- package/inventory/schema.json +1 -1
- package/package.json +1 -1
- package/skills/mg-axi/SKILL.md +34 -1
package/dist/docs.js
CHANGED
|
@@ -37,6 +37,8 @@ const READ_AREA_LABELS = [
|
|
|
37
37
|
["entra user ", "users"],
|
|
38
38
|
["entra group ", "groups"],
|
|
39
39
|
["entra directory-role ", "roles"],
|
|
40
|
+
["entra directory-role-template ", "roles"],
|
|
41
|
+
["entra scoped-role-membership ", "roles"],
|
|
40
42
|
["entra role-assignment ", "roles"],
|
|
41
43
|
["entra pim ", "roles"],
|
|
42
44
|
["entra device ", "devices"],
|
|
@@ -70,6 +72,7 @@ const READ_AREA_LABELS = [
|
|
|
70
72
|
["entra tenant-information ", "tenant information"],
|
|
71
73
|
["entra sign-in ", "sign-ins and audit logs"],
|
|
72
74
|
["entra directory-audit ", "sign-ins and audit logs"],
|
|
75
|
+
["entra provisioning ", "sign-ins and audit logs"],
|
|
73
76
|
["entra application ", "applications and consent grants"],
|
|
74
77
|
["entra service-principal ", "applications and consent grants"],
|
|
75
78
|
["entra risky-user ", "risk"],
|
|
@@ -204,6 +207,9 @@ export function skillDocument() {
|
|
|
204
207
|
"",
|
|
205
208
|
"Configuration defaults to `~/.mg-axi/config.json`; `MG_AXI_CONFIG` selects a separate file.",
|
|
206
209
|
"`mg-axi setup` shows the selected path and writes nothing.",
|
|
210
|
+
"Application profiles authenticate headlessly through credential references: the profile names an env var or file and the environment supplies the value at acquisition time.",
|
|
211
|
+
"Container examples for client secrets, certificate keys and workload federation live in [README.md](../../README.md#mg-axi).",
|
|
212
|
+
"A client secret is weaker than a certificate or federated credential and needs scheduled rotation.",
|
|
207
213
|
"",
|
|
208
214
|
"Agent discovery has two install paths, and either suffices alone.",
|
|
209
215
|
"For ambient context at every agent session start instead of the skill, install the CLI globally and opt into the session hook:",
|
|
@@ -232,7 +238,7 @@ export function skillDocument() {
|
|
|
232
238
|
"Writes preview before sending and need `--execute` plus a typed `--confirm` repeating the target; an already-desired value is a no-op with exit 0, never an error.",
|
|
233
239
|
"Output is TOON on stdout; diagnostics use stderr.",
|
|
234
240
|
"Text truncates at 500 characters (`--full` restores text, never redaction); row caps resume through opaque cursors.",
|
|
235
|
-
"Secrets stay in
|
|
241
|
+
"Secrets stay in credential references, never in argv, config files or output; credential fields carry expiry metadata only.",
|
|
236
242
|
"Tests run offline with fixture credentials; never point tests at a real tenant.",
|
|
237
243
|
"",
|
|
238
244
|
].join("\n");
|
|
@@ -242,14 +248,14 @@ export function skillDocument() {
|
|
|
242
248
|
// remains unimplemented. Family membership comes from the inventory
|
|
243
249
|
// owningSlice and shipped status comes from the catalogue, so a merged
|
|
244
250
|
// write slice flips its own row without touching this template. Blocked,
|
|
245
|
-
// deprecated and
|
|
251
|
+
// deprecated, unavailable and deferred-out-of-v1 variants never count as pending.
|
|
246
252
|
function initialWriteStatus(rows) {
|
|
247
253
|
const families = new Map();
|
|
248
254
|
for (const row of rows) {
|
|
249
255
|
const operation = /^v1\.0:(.+)$/.exec(row.id)?.[1];
|
|
250
256
|
if (operation === undefined || row.owningSlice === null || !/^WRITE-0[1-9]$/.test(row.owningSlice))
|
|
251
257
|
continue;
|
|
252
|
-
if (row.disposition === "intentionally-blocked" || row.disposition === "deprecated" || row.disposition === "unavailable")
|
|
258
|
+
if (row.disposition === "intentionally-blocked" || row.disposition === "deprecated" || row.disposition === "unavailable" || row.disposition === "deferred")
|
|
253
259
|
continue;
|
|
254
260
|
families.set(row.owningSlice, [...(families.get(row.owningSlice) ?? []), operation]);
|
|
255
261
|
}
|
|
@@ -264,7 +270,79 @@ function initialWriteStatus(rows) {
|
|
|
264
270
|
}
|
|
265
271
|
return { shipped, pending };
|
|
266
272
|
}
|
|
267
|
-
const DISPOSITIONS = ["named-command", "reviewed-raw-read", "scheduled", "intentionally-blocked", "deprecated", "unavailable", "excluded"];
|
|
273
|
+
const DISPOSITIONS = ["named-command", "reviewed-raw-read", "scheduled", "deferred", "intentionally-blocked", "deprecated", "unavailable", "excluded"];
|
|
274
|
+
// FULL-01 audit record (2026-10-07, latest origin/main at PR #78): the cutoff
|
|
275
|
+
// is met when no v1.0 row is left scheduled, so the counts below are read
|
|
276
|
+
// from the same generated inventory the Counts section reports. Beta stays
|
|
277
|
+
// scheduled by definition and was never agreed for v1.
|
|
278
|
+
function auditRecord(rows) {
|
|
279
|
+
const v1 = (disposition) => rows.filter(row => row.id.startsWith("v1.0:") && row.disposition === disposition).length;
|
|
280
|
+
const betaScheduled = rows.filter(row => row.id.startsWith("beta:") && row.disposition === "scheduled").length;
|
|
281
|
+
const named = v1("named-command");
|
|
282
|
+
const raw = v1("reviewed-raw-read");
|
|
283
|
+
const scheduled = v1("scheduled");
|
|
284
|
+
if (scheduled !== 0)
|
|
285
|
+
throw new Error(`FULL-01 audit blocked: ${scheduled} v1.0 rows remain scheduled`);
|
|
286
|
+
return [
|
|
287
|
+
"## FULL-01 audit record",
|
|
288
|
+
"",
|
|
289
|
+
"FULL-01 audit (2026-10-07): every agreed v1.0 read has a named command or an",
|
|
290
|
+
"explicit reviewed blocked/unavailable/deprecated/deferred disposition, and no",
|
|
291
|
+
"v1.0 row is left scheduled. The deferred tail is declared out of v1.",
|
|
292
|
+
`- v1.0 named-command: ${named}, reviewed-raw-read: ${raw}, scheduled: ${scheduled}`,
|
|
293
|
+
`- v1.0 deferred (out of v1): ${v1("deferred")}, intentionally-blocked: ${v1("intentionally-blocked")}, deprecated: ${v1("deprecated")}, unavailable: ${v1("unavailable")}`,
|
|
294
|
+
`- beta scheduled (never agreed for v1): ${betaScheduled}`,
|
|
295
|
+
`PR #78 (historical point-in-time) proposed 275 named / 19 raw (294 backed); the generated inventory carries ${named} named / ${raw} raw (${named + raw} backed).`,
|
|
296
|
+
"",
|
|
297
|
+
];
|
|
298
|
+
}
|
|
299
|
+
// COMPLETE-01 audit record (2026-10-07, latest origin/main at this change):
|
|
300
|
+
// the full agreed Entra capability audit including later writes. Five writes
|
|
301
|
+
// ship as named, gated commands through the WRITE-00 mutation coordinator,
|
|
302
|
+
// WRITE-N carries explicit reviewed deferred/blocked/deprecated dispositions
|
|
303
|
+
// rather than scheduled, and no agreed v1.0 operation, read or write, is
|
|
304
|
+
// left merely scheduled. Beta stays scheduled by definition and was never
|
|
305
|
+
// agreed for v1. The declined EXT-02c access-review history reads stay out.
|
|
306
|
+
function completeAuditRecord(rows) {
|
|
307
|
+
const v1 = (disposition) => rows.filter(row => row.id.startsWith("v1.0:") && row.disposition === disposition).length;
|
|
308
|
+
const betaScheduled = rows.filter(row => row.id.startsWith("beta:") && row.disposition === "scheduled").length;
|
|
309
|
+
const named = v1("named-command");
|
|
310
|
+
const raw = v1("reviewed-raw-read");
|
|
311
|
+
const scheduled = v1("scheduled");
|
|
312
|
+
const writeRows = rows.filter(row => row.id.startsWith("v1.0:") && row.disposition === "named-command" && !row.id.includes(":GET:"));
|
|
313
|
+
const writeN = (version, disposition) => rows.filter(row => row.owningSlice === "WRITE-N" && row.id.startsWith(`${version}:`) && row.disposition === disposition).length;
|
|
314
|
+
const writeNScheduled = rows.filter(row => row.owningSlice === "WRITE-N" && row.disposition === "scheduled").length;
|
|
315
|
+
const declinedOut = rows.filter(row => row.owningSlice === "EXT-02c"
|
|
316
|
+
&& (row.disposition === "named-command" || row.disposition === "reviewed-raw-read"));
|
|
317
|
+
if (scheduled !== 0)
|
|
318
|
+
throw new Error(`COMPLETE-01 audit blocked: ${scheduled} v1.0 rows remain scheduled`);
|
|
319
|
+
if (writeNScheduled !== 0)
|
|
320
|
+
throw new Error(`COMPLETE-01 audit blocked: ${writeNScheduled} WRITE-N rows remain scheduled`);
|
|
321
|
+
const writeStatus = initialWriteStatus(rows);
|
|
322
|
+
const expectedWrites = ["WRITE-01", "WRITE-02", "WRITE-03", "WRITE-04", "WRITE-05"];
|
|
323
|
+
const missing = expectedWrites.filter(slice => !writeStatus.shipped.some(entry => entry.startsWith(`${slice} `)));
|
|
324
|
+
if (writeStatus.pending.length > 0 || missing.length > 0) {
|
|
325
|
+
throw new Error(`COMPLETE-01 audit blocked: pending writes: ${[...missing, ...writeStatus.pending].join(", ")}`);
|
|
326
|
+
}
|
|
327
|
+
if (declinedOut.length > 0)
|
|
328
|
+
throw new Error(`COMPLETE-01 audit blocked: declined EXT-02c rows ship: ${declinedOut.map(row => row.id).join(", ")}`);
|
|
329
|
+
return [
|
|
330
|
+
"## COMPLETE-01 audit record",
|
|
331
|
+
"",
|
|
332
|
+
"COMPLETE-01 audit (2026-10-07): the full agreed Entra capability audit including later writes.",
|
|
333
|
+
"Five writes ship as named, gated commands through the WRITE-00 mutation coordinator; WRITE-N carries explicit",
|
|
334
|
+
"reviewed deferred/blocked/deprecated dispositions rather than scheduled; no agreed v1.0 operation, read or",
|
|
335
|
+
"write, is left merely scheduled. Beta stays scheduled by definition and was never agreed for v1.",
|
|
336
|
+
"The declined EXT-02c access-review history reads (ReadWrite least privilege, SAS URLs) stay out.",
|
|
337
|
+
`- v1.0 named-command: ${named} (${named - writeRows.length} reads plus ${writeRows.length} writes below), reviewed-raw-read: ${raw}, scheduled: ${scheduled}`,
|
|
338
|
+
`- v1.0 deferred (out of v1): ${v1("deferred")}, intentionally-blocked: ${v1("intentionally-blocked")}, deprecated: ${v1("deprecated")}, unavailable: ${v1("unavailable")}`,
|
|
339
|
+
`- beta scheduled (never agreed for v1): ${betaScheduled}`,
|
|
340
|
+
`- shipped writes: ${writeStatus.shipped.join(", ")}.`,
|
|
341
|
+
`- WRITE-N (remaining agreed mutations): deferred ${writeN("v1.0", "deferred")}, intentionally-blocked ${writeN("v1.0", "intentionally-blocked")} v1.0 plus ${writeN("beta", "intentionally-blocked")} beta, deprecated ${writeN("v1.0", "deprecated")} v1.0 plus ${writeN("beta", "deprecated")} beta, scheduled ${writeNScheduled}.`,
|
|
342
|
+
"- outstanding upstream limitations (already documented in the repo): P1 for Conditional Access and P2 for risk-based CA, PIM P2 or ID Governance, riskyUsers P2 and Workload Identities Premium for workload risk with hidden riskDetail/riskLevel without it (docs/graph-coverage.md); conservative P1/P2 Graph prerequisite for sign-in/audit logs, registration report excludes disabled users, no tenant-wide method enumeration (docs/graph-coverage.md); v1.0 group-members route omits service principals (README.md member-read warning); 14 unavailable rows with no documented v1.0 GET contract, invitation Create-only Methods table, org-scoped certificateBasedAuthConfiguration routes only, contacts sync-behavior reads without operation permission docs (inventory reasons); EXT-02c history reads need AccessReview.ReadWrite.All with no read scope and return SAS download URLs (docs/coverage.md); write-side limits beside each command, revoke lag/external-user scope/unknown outcome, CA update lockout gates with no concurrency promise, dismissal is not remediation (README.md, docs/execution.md).",
|
|
343
|
+
"",
|
|
344
|
+
];
|
|
345
|
+
}
|
|
268
346
|
// The capability report is generated from the catalogue: every executable
|
|
269
347
|
// read leaf owns one row with its inventory disposition and owning slice,
|
|
270
348
|
// and the counts separate implemented leaves from inventory dispositions.
|
|
@@ -309,6 +387,7 @@ export function capabilityDocument() {
|
|
|
309
387
|
const deferredCustomSecurityRows = rows.filter(row => row.owningSlice === "EXT-01" && row.reason.startsWith("Deferred by firstmate custom-security-attributes scope "));
|
|
310
388
|
const deferredAccessReviewRows = rows.filter(row => row.owningSlice === "EXT-02c");
|
|
311
389
|
const deferredEntitlementRows = rows.filter(row => row.owningSlice === "EXT-02" && row.reason.startsWith("Deferred by firstmate entitlement-management scope "));
|
|
390
|
+
const deferredAppLookupRows = rows.filter(row => row.owningSlice === "READ-07" && row.reason.startsWith("Deferred by firstmate application-lookups scope "));
|
|
312
391
|
const readCount = readLeaves.length + 2;
|
|
313
392
|
const localCount = LEAVES.length - readCount - writeLeaves.length;
|
|
314
393
|
return [
|
|
@@ -318,9 +397,11 @@ export function capabilityDocument() {
|
|
|
318
397
|
"",
|
|
319
398
|
"This is the supported Entra read surface, not full Entra coverage.",
|
|
320
399
|
"Only the commands below have an implemented, tested leaf; every other",
|
|
321
|
-
"operation
|
|
322
|
-
"
|
|
323
|
-
"
|
|
400
|
+
"v1.0 operation is deferred out of v1, and every other beta operation remains",
|
|
401
|
+
"scheduled (never agreed for v1), blocked, deprecated, unavailable or excluded.",
|
|
402
|
+
"Inventory dispositions are generated records from INV-01 joined to the catalogue;",
|
|
403
|
+
"the command list below is the implemented truth and never counts deferred or",
|
|
404
|
+
"scheduled work as complete.",
|
|
324
405
|
"",
|
|
325
406
|
"## Counts",
|
|
326
407
|
"",
|
|
@@ -329,6 +410,8 @@ export function capabilityDocument() {
|
|
|
329
410
|
`- local leaves: ${localCount} (home, profile, login and setup views)`,
|
|
330
411
|
...DISPOSITIONS.map(disposition => `- inventory ${disposition}: ${count(disposition)}`),
|
|
331
412
|
"",
|
|
413
|
+
...auditRecord(rows),
|
|
414
|
+
...completeAuditRecord(rows),
|
|
332
415
|
"## Commands",
|
|
333
416
|
"",
|
|
334
417
|
"| Command | Operation | Inventory (v1.0) | Owning slice |",
|
|
@@ -340,61 +423,61 @@ export function capabilityDocument() {
|
|
|
340
423
|
"## EXT-01 domain scope decisions",
|
|
341
424
|
"",
|
|
342
425
|
"Firstmate decision R1: approve narrowing this change to the eight v1.0 domain reads above.",
|
|
343
|
-
"The operations below
|
|
426
|
+
"The v1.0 operations below carry the deferred disposition (out of v1) and the beta operations remain scheduled (never agreed for v1); no new commands or raw access are approved.",
|
|
344
427
|
"Federation stays out because it can carry signing-certificate material.",
|
|
345
428
|
"Firstmate decision R2: keep the write-family status section as the coverage fix added to scope (resolved-kept).",
|
|
346
429
|
"Both firstmate decisions must also be stated in the PR body by the delivery phase.",
|
|
347
430
|
"",
|
|
348
431
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
349
432
|
"|---|---|---|---|",
|
|
350
|
-
...deferredDomainRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
433
|
+
...deferredDomainRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
351
434
|
"",
|
|
352
435
|
"## EXT-03 identity-provider scope decisions",
|
|
353
436
|
"",
|
|
354
437
|
"This change covers the four v1.0 workforce identity-provider reads above (list, show, count, available-types).",
|
|
355
|
-
"The four beta operations below remain scheduled
|
|
438
|
+
"The four beta operations below remain scheduled (never agreed for v1) for a later EXT-03 subfamily.",
|
|
356
439
|
"Identity-provider reads support v1.0 only; beta needs its own review.",
|
|
357
440
|
"Workforce context only; no external-customer (B2C/External ID tenant) support is claimed.",
|
|
358
441
|
"",
|
|
359
442
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
360
443
|
"|---|---|---|---|",
|
|
361
|
-
...deferredProviderRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
444
|
+
...deferredProviderRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
362
445
|
"",
|
|
363
446
|
"## EXT-01 federation-configuration scope decisions",
|
|
364
447
|
"",
|
|
365
448
|
"This change covers the four v1.0 workforce directory federation-configuration reads above (federation-configuration list, show, count and available-types).",
|
|
366
|
-
"The four beta operations below remain scheduled
|
|
449
|
+
"The four beta operations below remain scheduled (never agreed for v1) for a later EXT-01 subfamily; no new commands or raw access are approved.",
|
|
367
450
|
"Federation-configuration reads support v1.0 only; beta needs its own review.",
|
|
368
451
|
"signingCertificate carries the public token-signing key only and is omitted from default selects; no private key material exists on these resources and the domains navigation property needs its own review.",
|
|
369
|
-
"Workforce context only; domain federationConfiguration sub-reads (/domains/{domain-id}/federationConfiguration)
|
|
452
|
+
"Workforce context only; domain federationConfiguration sub-reads (/domains/{domain-id}/federationConfiguration) carry the deferred disposition in v1.0 (out of v1) and remain scheduled in beta (never agreed for v1) in the later domain federation subfamily.",
|
|
370
453
|
"",
|
|
371
454
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
372
455
|
"|---|---|---|---|",
|
|
373
|
-
...deferredFederationRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
456
|
+
...deferredFederationRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
374
457
|
"",
|
|
375
458
|
"## EXT-03 data-policy-operations scope decisions",
|
|
376
459
|
"",
|
|
377
460
|
"This change covers the three v1.0 workforce data-policy-operation reads above (data-policy-operation list, show and count).",
|
|
378
|
-
"The three beta operations below remain scheduled
|
|
461
|
+
"The three beta operations below remain scheduled (never agreed for v1) for a later EXT-03 subfamily; no new commands or raw access are approved.",
|
|
379
462
|
"Data-policy-operation reads support v1.0 only; beta needs its own review.",
|
|
380
463
|
"storageLocation always renders as the redaction marker; export submission (POST /users/{id}/exportPersonalData) belongs to no read slice.",
|
|
381
464
|
"Workforce context only; no external-customer support is claimed.",
|
|
382
465
|
"",
|
|
383
466
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
384
467
|
"|---|---|---|---|",
|
|
385
|
-
...deferredDataPolicyRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
468
|
+
...deferredDataPolicyRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
386
469
|
"",
|
|
387
470
|
"## EXT-03 risk-prevention scope decisions",
|
|
388
471
|
"",
|
|
389
472
|
"This change covers the ten v1.0 workforce risk-prevention reads above (fraud-protection-provider list, show and count; web-application-firewall-provider list, show and count; web-application-firewall-verification list, show, count and provider show).",
|
|
390
|
-
"The eleven beta operations below remain scheduled
|
|
473
|
+
"The eleven beta operations below remain scheduled (never agreed for v1) for a later EXT-03 subfamily; no new commands or raw access are approved.",
|
|
391
474
|
"Risk-prevention reads support v1.0 only; beta needs its own review.",
|
|
392
475
|
"API keys, client secrets and other key material (Arkose privateKey/publicKey, HUMAN serverToken, Akamai clientSecret/clientToken/accessToken, Cloudflare apiToken) are never selectable and never projected; application profiles are refused before credentials because Graph documents no supported application permission.",
|
|
393
476
|
"Workforce context only; no external-customer support is claimed.",
|
|
394
477
|
"",
|
|
395
478
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
396
479
|
"|---|---|---|---|",
|
|
397
|
-
...deferredRiskPreventionRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
480
|
+
...deferredRiskPreventionRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
398
481
|
"",
|
|
399
482
|
"## EXT-03 invitations scope decisions",
|
|
400
483
|
"",
|
|
@@ -410,12 +493,12 @@ export function capabilityDocument() {
|
|
|
410
493
|
"## EXT-01 organization scope decisions",
|
|
411
494
|
"",
|
|
412
495
|
"The organization scope covers the five organization/branding/localization reads above; the remaining subfamilies need the separate contracts described below.",
|
|
413
|
-
"The operations below
|
|
496
|
+
"The v1.0 operations below carry the deferred disposition (out of v1) and the beta operations remain scheduled (never agreed for v1); no new commands or raw access are approved.",
|
|
414
497
|
"Stream image and CSS bytes stay out because they need a separate binary-output contract; beta-only settings, partner and theme contracts need separate review.",
|
|
415
498
|
"",
|
|
416
499
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
417
500
|
"|---|---|---|---|",
|
|
418
|
-
...deferredOrganizationRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
501
|
+
...deferredOrganizationRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
419
502
|
"",
|
|
420
503
|
"## EXT-01 certificate-auth scope decisions",
|
|
421
504
|
"",
|
|
@@ -437,61 +520,61 @@ export function capabilityDocument() {
|
|
|
437
520
|
"## EXT-01 group lifecycle scope decisions",
|
|
438
521
|
"",
|
|
439
522
|
"This change covers the six v1.0 group lifecycle policy and group setting template reads above (list, show, count per family).",
|
|
440
|
-
"The operations below
|
|
523
|
+
"The v1.0 operations below carry the deferred disposition (out of v1) and the beta operations remain scheduled (never agreed for v1); no new commands or raw access are approved.",
|
|
441
524
|
"Beta policies and templates need their own review; delta-token sync needs its own change-tracking contract beyond the approved list/show/count reads; the POST lookup actions need their own request and projection review.",
|
|
442
525
|
"",
|
|
443
526
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
444
527
|
"|---|---|---|---|",
|
|
445
|
-
...deferredGroupLifecycleRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
528
|
+
...deferredGroupLifecycleRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
446
529
|
"",
|
|
447
530
|
"## EXT-01 custom-security-attributes scope decisions",
|
|
448
531
|
"",
|
|
449
532
|
"This change covers the nine v1.0 attribute-set, custom-security-attribute-definition and allowed-value reads above (list, show, count per family).",
|
|
450
|
-
"The nine beta operations below remain scheduled
|
|
533
|
+
"The nine beta operations below remain scheduled (never agreed for v1) for a later EXT-01 subfamily; no new commands or raw access are approved.",
|
|
451
534
|
"Beta attribute sets, definitions and allowed values need their own review; definition $expand (inline allowedValues) is not reviewed here and stays on the dedicated allowed-value list/show reads.",
|
|
452
535
|
"",
|
|
453
536
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
454
537
|
"|---|---|---|---|",
|
|
455
|
-
...deferredCustomSecurityRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
538
|
+
...deferredCustomSecurityRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
456
539
|
"",
|
|
457
540
|
"## EXT-01 on-premises-synchronization scope decisions",
|
|
458
541
|
"",
|
|
459
542
|
"This change covers the two v1.0 on-premises-synchronization reads above (on-premises-synchronization list and show).",
|
|
460
|
-
"The $count scalar and the three beta operations
|
|
543
|
+
"The $count scalar below carries the deferred disposition (out of v1) and the three beta operations remain scheduled (never agreed for v1); no new commands or raw access are approved.",
|
|
461
544
|
"On-premises-synchronization reads support v1.0 only; beta needs its own review.",
|
|
462
545
|
"Scalar counts need a separate query and response contract from the approved list/show reads.",
|
|
463
546
|
"",
|
|
464
547
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
465
548
|
"|---|---|---|---|",
|
|
466
|
-
...deferredOnPremSyncRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
549
|
+
...deferredOnPremSyncRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
467
550
|
"",
|
|
468
551
|
"## EXT-01 terms-of-use scope decisions",
|
|
469
552
|
"",
|
|
470
553
|
"This change covers the six v1.0 agreement and agreement-acceptance reads above (agreement list/show, one agreement's acceptance list/show, and tenant-wide acceptance list/show).",
|
|
471
|
-
"The
|
|
554
|
+
"The v1.0 operations below carry the deferred disposition (out of v1) and the beta operations remain scheduled (never agreed for v1); no new commands or raw access are approved.",
|
|
472
555
|
"Terms-of-use reads support v1.0 only; beta needs its own review.",
|
|
473
556
|
"Scalar counts need a separate query and response contract from the approved list/show reads; agreement file contents and localizations need a separate binary-output and projection contract, and file bytes are never downloaded or printed.",
|
|
474
557
|
"",
|
|
475
558
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
476
559
|
"|---|---|---|---|",
|
|
477
|
-
...deferredTermsOfUseRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
560
|
+
...deferredTermsOfUseRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
478
561
|
"",
|
|
479
562
|
"## EXT-01 directory-objects scope decisions",
|
|
480
563
|
"",
|
|
481
564
|
"This change covers the three v1.0 directory-object reads above (directory-object list, show and count).",
|
|
482
|
-
"The
|
|
565
|
+
"The v1.0 operations below carry the deferred disposition (out of v1) and the beta operations remain scheduled (never agreed for v1); no new commands or raw access are approved.",
|
|
483
566
|
"Directory-object reads support v1.0 only; beta needs its own review.",
|
|
484
567
|
"Delta-token sync needs its own change-tracking contract beyond the approved list/show/count reads; the POST lookup and validation actions need their own request and projection review.",
|
|
485
568
|
"Rows are polymorphic: only the base-type properties plus the @odata.type discriminator are projected, so subtype secrets or credentials can never appear.",
|
|
486
569
|
"",
|
|
487
570
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
488
571
|
"|---|---|---|---|",
|
|
489
|
-
...deferredDirectoryObjectRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
572
|
+
...deferredDirectoryObjectRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
490
573
|
"",
|
|
491
574
|
"## EXT-01 deleted-items scope decisions",
|
|
492
575
|
"",
|
|
493
576
|
"This change covers the eleven v1.0 deleted directory-item reads above (deleted-user, deleted-group, deleted-application, deleted-service-principal and deleted-administrative-unit list and count, plus deleted-item show).",
|
|
494
|
-
"The rows below
|
|
577
|
+
"The rows below carry the deferred (v1.0, out of v1) or scheduled (beta, never agreed for v1) disposition shown; no new commands or raw access are approved for them.",
|
|
495
578
|
"Deleted-item reads support v1.0 only; beta needs its own review.",
|
|
496
579
|
"Untyped list/count commands do not exist because upstream requires the OData cast as part of the list URI.",
|
|
497
580
|
"Device casts carry no documented v1.0 permission contract: the list/get pages name the supported types and device is not among them.",
|
|
@@ -500,12 +583,12 @@ export function capabilityDocument() {
|
|
|
500
583
|
"",
|
|
501
584
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
502
585
|
"|---|---|---|---|",
|
|
503
|
-
...deferredDeletedItemsRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
586
|
+
...deferredDeletedItemsRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
504
587
|
"",
|
|
505
588
|
"## EXT-01 contacts scope decisions",
|
|
506
589
|
"",
|
|
507
590
|
"This change covers the three v1.0 top-level contact reads above (contact list, show and count), the ten v1.0 manager/directReports navigation reads above (show-manager, list/show/count-direct-reports with user/contact casts), and the eighteen v1.0 memberOf/transitiveMemberOf navigation reads above (list/show/count-member-of with transitive and group/administrativeUnit casts).",
|
|
508
|
-
"The
|
|
591
|
+
"The v1.0 operations below carry the deferred disposition (out of v1) and the beta operations remain scheduled (never agreed for v1); no new commands or raw access are approved.",
|
|
509
592
|
"Contact reads support v1.0 only; beta needs its own review.",
|
|
510
593
|
"Delta-token sync needs its own change-tracking contract beyond the approved reads; the POST lookup actions need their own request and projection review.",
|
|
511
594
|
"Contacts are personal data: top-level default rows carry id, displayName, mail and companyName only; navigation rows carry the @odata.type discriminator plus id and displayName only, and identifying fields need an explicit --select.",
|
|
@@ -513,43 +596,43 @@ export function capabilityDocument() {
|
|
|
513
596
|
"",
|
|
514
597
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
515
598
|
"|---|---|---|---|",
|
|
516
|
-
...deferredContactRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
599
|
+
...deferredContactRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
517
600
|
...unavailableContactRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
518
601
|
"",
|
|
519
602
|
"## EXT-04 partner contracts scope decisions",
|
|
520
603
|
"",
|
|
521
604
|
"Firstmate scope: approve narrowing this change to the three v1.0 partner-contract reads above (list, show, count).",
|
|
522
|
-
"The operations below
|
|
605
|
+
"The v1.0 operations below carry the deferred disposition (out of v1) and the beta operations remain scheduled (never agreed for v1); no new commands or raw access are approved.",
|
|
523
606
|
"Beta contracts need their own review; delta-token sync needs its own change-tracking contract beyond the approved list/show/count reads.",
|
|
524
607
|
"",
|
|
525
608
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
526
609
|
"|---|---|---|---|",
|
|
527
|
-
...deferredContractRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
610
|
+
...deferredContractRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`), "",
|
|
528
611
|
"## EXT-04 delegated-admin scope decisions",
|
|
529
612
|
"",
|
|
530
613
|
"Firstmate scope: approve narrowing this change to the eighteen v1.0 delegated-admin reads above (customer list/show/count, relationship list/show/count, access-assignment list/show/count, operation list/show/count, request list/show/count and service-management-detail list/show/count).",
|
|
531
|
-
"The
|
|
614
|
+
"The operation below carries the deferred disposition (out of v1); no new commands or raw access are approved.",
|
|
532
615
|
"The tenantRelationship container root needs its own projection review; multi-tenant-organization reads shipped in the section below, and tenant-lookup functions ship as tenant-information show under the mg-ext-04e function-argument contract.",
|
|
533
616
|
"",
|
|
534
617
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
535
618
|
"|---|---|---|---|",
|
|
536
|
-
...deferredDelegatedAdminRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
619
|
+
...deferredDelegatedAdminRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`), "",
|
|
537
620
|
"## EXT-04 multi-tenant-organization scope decisions",
|
|
538
621
|
"",
|
|
539
622
|
"Firstmate scope: approve narrowing this change to the four v1.0 multi-tenant-organization reads above (organization show, join-request show, tenant list/count).",
|
|
540
|
-
"The single-member read below
|
|
623
|
+
"The single-member read below carries the deferred disposition (out of v1): its documented least privilege is the write scope MultiTenantOrganization.ReadWrite.All in both delegated and application modes, so no named command or raw access is approved for it until its own least-privilege review lands.",
|
|
541
624
|
"",
|
|
542
625
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
543
626
|
"|---|---|---|---|",
|
|
544
|
-
...deferredMtoRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
627
|
+
...deferredMtoRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`), "",
|
|
545
628
|
"## EXT-04 reports scope decisions",
|
|
546
629
|
"",
|
|
547
630
|
"Firstmate scope: approve deferring the v1.0 relying-party summary read below; no named command or raw access is approved for it.",
|
|
548
|
-
"The relying-party summary read below
|
|
631
|
+
"The relying-party summary read below carries the deferred disposition (out of v1): its period function argument needs a new session-guard function-argument binding beyond the three allowlisted tenant-lookup/commerce routes, and the request-path guard must stay byte-identical to origin/main apart from READ_SCOPES additions, so no named command or raw access is approved for it until its own guard review lands.",
|
|
549
632
|
"",
|
|
550
633
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
551
634
|
"|---|---|---|---|",
|
|
552
|
-
...deferredReportsRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
635
|
+
...deferredReportsRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`), "",
|
|
553
636
|
"## EXT-04 tenant-lookup scope decisions",
|
|
554
637
|
"",
|
|
555
638
|
"Firstmate scope: approve the mg-ext-04e function-argument contract with the three v1.0 reads it unblocks (tenant-information show by domain name or tenant ID, subscription show by commerce subscription ID).",
|
|
@@ -559,7 +642,7 @@ export function capabilityDocument() {
|
|
|
559
642
|
"## EXT-02 access-review scope decisions",
|
|
560
643
|
"",
|
|
561
644
|
"The access-review scope covers the ten reads above (definition, instance, decision, contacted-reviewer and stage list/show reads).",
|
|
562
|
-
"The legacy accessReviews and unified alias reads below
|
|
645
|
+
"The legacy accessReviews and unified alias reads below carry the deferred disposition (out of v1) under the captain-declined EXT-02c follow-up (see docs/build-plan.md); beta-only operations remain scheduled (\"beta needs its own review\").", ,
|
|
563
646
|
"The history reads below are blocked: their documented least privilege is the write scope AccessReview.ReadWrite.All (no read scope), and history instances return SAS download URLs in downloadUri.",
|
|
564
647
|
"No new commands or raw access are approved for any row below.",
|
|
565
648
|
"",
|
|
@@ -570,18 +653,27 @@ export function capabilityDocument() {
|
|
|
570
653
|
"## EXT-02 entitlement-management scope decisions",
|
|
571
654
|
"",
|
|
572
655
|
"The entitlement-management scope covers the eighteen reads above (catalog, access-package, assignment-policy and resource-role-scope list/show/count reads plus assignment and assignment-request list/show/count reads).",
|
|
573
|
-
"Approval and subject reads carry personal data and stay
|
|
656
|
+
"Approval and subject reads carry personal data and stay deferred (out of v1) for later parts with no new commands or raw access approved; so do assignment and request navigation sub-reads (assignment target/accessPackage/assignmentPolicy, request accessPackage/assignment/requestor), the top-level assignment-policy and resource-role-scope lists, catalog navigation reads (accessPackages, resources, resourceScopes, resourceRoles, customWorkflowExtensions), package navigation reads (catalog, incompatible sets), policy navigation reads (questions, custom-extension stages), role/scope link expansion, filterByCurrentUser and additionalAccess functions (parenthesised function segments need their own session-guard binding review), while every beta operation below remains scheduled (never agreed for v1). Raw $expand review is a separate change: the named assignment and request reads flatten one fixed documented expansion in code, and no user-supplied $expand exists on any route.",
|
|
574
657
|
"",
|
|
575
658
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
576
659
|
"|---|---|---|---|",
|
|
577
|
-
...deferredEntitlementRows.map(row => `| \`${row.id}\` | ${row.disposition}
|
|
660
|
+
...deferredEntitlementRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
578
661
|
"",
|
|
579
662
|
"## EXT-02 lifecycle-workflows scope decisions",
|
|
580
663
|
"",
|
|
581
664
|
"This change covers the thirty-three v1.0 lifecycle-workflows first-, second-, third- and fourth-part reads above (workflow, workflow-template and task-definition list/show/count reads, the tenant settings show, top-level run and user/subject processing-result list/show/count reads, task-report list/show/count reads with the task and taskDefinition singles, plus run-nested user/subject/task processing-result list/show/count reads).",
|
|
582
|
-
"Third-level processing results, taskProcessingResults sub-reads under a user or subject result, reprocessed runs, subject sub-reads, workflow tasks, template tasks, versions, insights, deleted items and custom task extensions stay
|
|
665
|
+
"Third-level processing results, taskProcessingResults sub-reads under a user or subject result, reprocessed runs, subject sub-reads, workflow tasks, template tasks, versions, insights, deleted items and custom task extensions stay deferred (out of v1) for follow-up parts with no new commands or raw access approved; so do the six summary functions (the run user/subject summaries plus the four top-level ones), which stay deferred because they need bracketed start/end arguments outside the session-guard function-binding allowlist while the request-path guard cannot change beyond READ_SCOPES additions. Every beta operation below remains scheduled (never agreed for v1) and every mutation (no workflow create/update/delete/activate/run, no settings update, no restore) stays out.",
|
|
583
666
|
"No new commands or raw access are approved for any lifecycle-workflows row outside the thirty-three above.",
|
|
584
667
|
"",
|
|
668
|
+
"## READ-07 application lookups scope decisions",
|
|
669
|
+
"",
|
|
670
|
+
"This change covers seven v1.0 application and service-principal reads above (application and service-principal federated-credential list/show reads with credential metadata only, service-principal app-role-assigned-to list/show reads, and the service-principal app-role-assignment show companion).",
|
|
671
|
+
"The four parenthesised lookups below carry the deferred disposition (out of v1): the (appId='...') alternate-key forms and the federated-credential (name='...') function forms each need a new session-guard binding, and the request-path guard must stay byte-identical to origin/main apart from READ_SCOPES additions, so no named command or raw access is approved for them until their own guard review lands.", ,
|
|
672
|
+
"",
|
|
673
|
+
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
674
|
+
"|---|---|---|---|",
|
|
675
|
+
...deferredAppLookupRows.map(row => `| \`${row.id}\` | ${row.disposition} | ${row.owningSlice} | ${row.reason} |`),
|
|
676
|
+
"",
|
|
585
677
|
"## Named writes",
|
|
586
678
|
"",
|
|
587
679
|
"Each write below runs the WRITE-00 mutation coordinator: hand-enabled profile, immutable scope, preview, explicit `--execute`, typed target confirmation for disruptive effects, durable journal intent/outcome and no replay. Inventory dispositions stay discovery-time records until a metadata refresh reviews them; the implemented review lives beside each command.",
|
|
@@ -593,7 +685,7 @@ export function capabilityDocument() {
|
|
|
593
685
|
`Shipped initial writes: ${writeStatus.shipped.length ? writeStatus.shipped.join(", ") : "none"}.`,
|
|
594
686
|
`Pending initial writes: ${writeStatus.pending.length ? writeStatus.pending.join(", ") : "none"}.`,
|
|
595
687
|
"Extended families (EXT-01 through EXT-04) and the full-Entra audit (FULL-01, COMPLETE-01) own the remaining",
|
|
596
|
-
"
|
|
688
|
+
"deferred rows out of v1; see docs/build-plan.md for their dispatch.",
|
|
597
689
|
"",
|
|
598
690
|
].join("\n");
|
|
599
691
|
}
|