@knowttl/mg-axi 0.1.1 → 0.1.2
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 +149 -38
- package/dist/api.js +134 -8
- package/dist/bin/mg-axi-hook.js +31 -0
- package/dist/catalogue.js +390 -2
- package/dist/cli.js +116 -8
- package/dist/docs.js +45 -5
- package/dist/doctor.js +2 -2
- package/dist/entra-access-reviews.js +11 -4
- package/dist/entra-apps.js +13 -8
- package/dist/entra-audit-logs.js +8 -4
- package/dist/entra-auth-methods.js +8 -4
- package/dist/entra-certificate-auth.js +12 -8
- package/dist/entra-conditional-access.js +9 -4
- 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-group-pim.js +431 -0
- package/dist/entra-groups.js +13 -8
- package/dist/entra-lifecycle-workflows.js +136 -9
- package/dist/entra-organization.js +13 -8
- package/dist/entra-risk-prevention.js +436 -0
- package/dist/entra-risk.js +213 -5
- package/dist/entra-roles.js +10 -4
- package/dist/entra-subscriptions.js +6 -4
- package/dist/entra-users.js +7 -4
- package/dist/graph-session.js +29 -5
- package/dist/hook.js +84 -0
- package/dist/list-totals.js +52 -0
- package/dist/setup.js +5 -0
- package/docs/coverage.md +79 -13
- package/inventory/operations.json +2 -2
- package/package.json +4 -3
- package/skills/mg-axi/SKILL.md +56 -1
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { encode } from "@toon-format/toon";
|
|
2
|
-
import {
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { AxiError, installSessionStartHooks, runAxiCli } from "axi-sdk-js";
|
|
3
5
|
import { LEAVES, home, leafHelp, operationFor, resolveCommand, DESCRIPTION, TOP_LEVEL_HELP } from "./catalogue.js";
|
|
4
6
|
import { VERSION } from "./version.js";
|
|
5
7
|
import { Profiles } from "./profiles.js";
|
|
@@ -10,11 +12,12 @@ import { revokeUserSessions } from "./entra-user-revoke-sessions.js";
|
|
|
10
12
|
import { createMutationCoordinator, mutationFetchTransport } from "./mutations.js";
|
|
11
13
|
import { TRANSITIVE_OPERATION, listGroupMemberOf, listGroupMembers, listGroups, showGroup } from "./entra-groups.js";
|
|
12
14
|
import { listDirectoryRoles, showDirectoryRole, listRoleAssignments, listPimEligible, listPimActive } from "./entra-roles.js";
|
|
15
|
+
import { listGroupAssignmentSchedules, showGroupAssignmentSchedule, listGroupAssignmentInstances, showGroupAssignmentInstance, listGroupEligibilitySchedules, showGroupEligibilitySchedule, listGroupEligibilityInstances, showGroupEligibilityInstance, listGroupEligibilityRequests, showGroupEligibilityRequest } from "./entra-group-pim.js";
|
|
13
16
|
import { listAdministrativeUnitMembers, listAdministrativeUnits, listDevices, showAdministrativeUnit, showDevice } from "./entra-directory.js";
|
|
14
17
|
import { listSignIns, showSignIn, listDirectoryAudits, showDirectoryAudit } from "./entra-audit-logs.js";
|
|
15
18
|
import { listApplicationOwners, listApplications, listServicePrincipalOwners, listServicePrincipals, showApplication, showServicePrincipal } from "./entra-apps.js";
|
|
16
19
|
import { listAppRoleAssignments, listOAuth2Grants } from "./entra-grants.js";
|
|
17
|
-
import { listRiskyUsers, showRiskyUser, listRiskDetections, showRiskDetection } from "./entra-risk.js";
|
|
20
|
+
import { listRiskyUsers, showRiskyUser, listRiskDetections, showRiskDetection, listRiskyServicePrincipals, showRiskyServicePrincipal, listRiskyServicePrincipalHistory, showRiskyServicePrincipalHistory, listServicePrincipalRiskDetections, showServicePrincipalRiskDetection } from "./entra-risk.js";
|
|
18
21
|
import { dismissRiskyUser } from "./entra-risk-dismiss.js";
|
|
19
22
|
import { listPolicies, showPolicy, listNamedLocations, showNamedLocation } from "./entra-conditional-access.js";
|
|
20
23
|
import { listBrandingLocalizations, listOrganizations, showBranding, showBrandingLocalization, showOrganization } from "./entra-organization.js";
|
|
@@ -28,7 +31,7 @@ import { listDirectoryObjects, showDirectoryObject, countDirectoryObjects } from
|
|
|
28
31
|
import { listDeletedItems, showDeletedItem, countDeletedItems } from "./entra-deleted-items.js";
|
|
29
32
|
import { listContacts, showContact, countContacts, showContactManager, listContactDirectReports, showContactDirectReport, countContactDirectReports, castDirectReports, listContactMemberOf, showContactMemberOf, countContactMemberOf, transitMembership, castMembership } from "./entra-contacts.js";
|
|
30
33
|
import { countContracts, listContracts, showContract } from "./entra-contracts.js";
|
|
31
|
-
import { listDelegatedAdminCustomers, showDelegatedAdminCustomer, listDelegatedAdminRelationships, showDelegatedAdminRelationship, listDelegatedAdminAccessAssignments, showDelegatedAdminAccessAssignment, listDelegatedAdminOperations, showDelegatedAdminOperation, listDelegatedAdminRequests, showDelegatedAdminRequest, listDelegatedAdminServiceManagementDetails, showDelegatedAdminServiceManagementDetail } from "./entra-delegated-admin.js";
|
|
34
|
+
import { listDelegatedAdminCustomers, showDelegatedAdminCustomer, listDelegatedAdminRelationships, showDelegatedAdminRelationship, listDelegatedAdminAccessAssignments, showDelegatedAdminAccessAssignment, listDelegatedAdminOperations, showDelegatedAdminOperation, listDelegatedAdminRequests, showDelegatedAdminRequest, listDelegatedAdminServiceManagementDetails, showDelegatedAdminServiceManagementDetail, countDelegatedAdminCustomers, countDelegatedAdminServiceManagementDetails, countDelegatedAdminRelationships, countDelegatedAdminAccessAssignments, countDelegatedAdminOperations, countDelegatedAdminRequests } from "./entra-delegated-admin.js";
|
|
32
35
|
import { listMultiTenantOrganizationTenants, showMultiTenantOrganization, showMultiTenantOrganizationJoinRequest, countMultiTenantOrganizationTenants } from "./entra-multi-tenant-organization.js";
|
|
33
36
|
import { showTenantInformation } from "./entra-tenant-information.js";
|
|
34
37
|
import { countLifecyclePolicies, listLifecyclePolicies, showLifecyclePolicy, countSettingTemplates, listSettingTemplates, showSettingTemplate } from "./entra-group-lifecycle.js";
|
|
@@ -36,9 +39,10 @@ import { listAttributeSets, showAttributeSet, countAttributeSets, listCustomSecu
|
|
|
36
39
|
import { listIdentityProviders, showIdentityProvider, countIdentityProviders, availableIdentityProviderTypes } from "./entra-identity-providers.js";
|
|
37
40
|
import { listFederationConfigurations, showFederationConfiguration, countFederationConfigurations, availableFederationProviderTypes } from "./entra-federation-configurations.js";
|
|
38
41
|
import { listDataPolicyOperations, showDataPolicyOperation, countDataPolicyOperations } from "./entra-data-policy-operations.js";
|
|
42
|
+
import { listFraudProtectionProviders, showFraudProtectionProvider, countFraudProtectionProviders, listWafProviders, showWafProvider, countWafProviders, listWafVerifications, showWafVerification, countWafVerifications, showVerificationProvider } from "./entra-risk-prevention.js";
|
|
39
43
|
import { listDefinitions, showDefinition, listInstances, showInstance, listDecisions, showDecision, listContactedReviewers, showContactedReviewer, listStages, showStage } from "./entra-access-reviews.js";
|
|
40
44
|
import { listCatalogs, showCatalog, countCatalogs, listAccessPackages, showAccessPackage, countAccessPackages, listAssignmentPolicies, showAssignmentPolicy, countAssignmentPolicies, listResourceRoleScopes, showResourceRoleScope, countResourceRoleScopes, listAssignments, showAssignment, countAssignments, listAssignmentRequests, showAssignmentRequest, countAssignmentRequests } from "./entra-entitlement-management.js";
|
|
41
|
-
import { listWorkflows, showWorkflow, countWorkflows, listWorkflowTemplates, showWorkflowTemplate, countWorkflowTemplates, listTaskDefinitions, showTaskDefinition, countTaskDefinitions, showLifecycleSettings, listRuns, showRun, countRuns, listUserProcessingResults, showUserProcessingResult, countUserProcessingResults, listSubjectProcessingResults, showSubjectProcessingResult, countSubjectProcessingResults, listTaskReports, showTaskReport, countTaskReports, showTaskReportTask, showTaskReportTaskDefinition } from "./entra-lifecycle-workflows.js";
|
|
45
|
+
import { listWorkflows, showWorkflow, countWorkflows, listWorkflowTemplates, showWorkflowTemplate, countWorkflowTemplates, listTaskDefinitions, showTaskDefinition, countTaskDefinitions, showLifecycleSettings, listRuns, showRun, countRuns, listUserProcessingResults, showUserProcessingResult, countUserProcessingResults, listSubjectProcessingResults, showSubjectProcessingResult, countSubjectProcessingResults, listTaskReports, showTaskReport, countTaskReports, showTaskReportTask, showTaskReportTaskDefinition, listRunUserProcessingResults, showRunUserProcessingResult, countRunUserProcessingResults, listRunSubjectProcessingResults, showRunSubjectProcessingResult, countRunSubjectProcessingResults, listRunTaskProcessingResults, showRunTaskProcessingResult, countRunTaskProcessingResults } from "./entra-lifecycle-workflows.js";
|
|
42
46
|
import { listAuthenticationMethods, listRegistrationDetails } from "./entra-auth-methods.js";
|
|
43
47
|
import { addGroupMember } from "./entra-group-member-add.js";
|
|
44
48
|
import { fetchTransport } from "./api.js";
|
|
@@ -62,6 +66,36 @@ function localHome(name) {
|
|
|
62
66
|
output.help.unshift("npx -y @knowttl/mg-axi profile list", "npx -y @knowttl/mg-axi login --help");
|
|
63
67
|
return output;
|
|
64
68
|
}
|
|
69
|
+
// One dispatch for the hook installer: resolve the sibling hook entry point
|
|
70
|
+
// installed next to this binary and register it as the SessionStart command
|
|
71
|
+
// for Claude Code, Codex and OpenCode through the SDK. No config, profile,
|
|
72
|
+
// transport or network is involved; the hook itself prints the local-only
|
|
73
|
+
// summary from src/hook.ts. Install failures throw loudly; hook failures
|
|
74
|
+
// never do.
|
|
75
|
+
function runSetupHooks() {
|
|
76
|
+
const hookPath = join(dirname(process.argv[1] ?? ""), "mg-axi-hook.js");
|
|
77
|
+
if (!existsSync(hookPath)) {
|
|
78
|
+
throw new AxiError("Cannot locate the mg-axi-hook entry point", "HOOK_INSTALL_FAILED", [
|
|
79
|
+
"Reinstall @knowttl/mg-axi so dist/bin/mg-axi-hook.js sits next to the main entry point",
|
|
80
|
+
"Run mg-axi setup hooks again after reinstalling",
|
|
81
|
+
]);
|
|
82
|
+
}
|
|
83
|
+
const failures = [];
|
|
84
|
+
installSessionStartHooks({
|
|
85
|
+
marker: "mg-axi-hook",
|
|
86
|
+
execPath: hookPath,
|
|
87
|
+
binaryNames: ["mg-axi-hook"],
|
|
88
|
+
distEntrypoints: ["dist/bin/mg-axi-hook.js"],
|
|
89
|
+
onError: (message) => { failures.push(message); },
|
|
90
|
+
});
|
|
91
|
+
if (failures.length > 0) {
|
|
92
|
+
throw new AxiError("Failed to install mg-axi agent hooks", "HOOK_INSTALL_FAILED", failures);
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
hooks: { status: "installed", integrations: "Claude Code, Codex, OpenCode" },
|
|
96
|
+
help: ["Restart your agent session to receive mg-axi ambient context"],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
65
99
|
async function readCursor(cursor) {
|
|
66
100
|
if (cursor !== "-")
|
|
67
101
|
return cursor;
|
|
@@ -98,6 +132,8 @@ export async function executeArgv(argv, overrides = {}) {
|
|
|
98
132
|
return profiles.resolve(flags.profile);
|
|
99
133
|
if (leaf.path === "setup")
|
|
100
134
|
return setupView(profiles);
|
|
135
|
+
if (leaf.path === "setup hooks")
|
|
136
|
+
return runSetupHooks();
|
|
101
137
|
if (leaf.path === "doctor") {
|
|
102
138
|
const names = doctorTargets(profiles, flags.profile);
|
|
103
139
|
let delegated = overrides.delegated;
|
|
@@ -238,7 +274,7 @@ export async function executeArgv(argv, overrides = {}) {
|
|
|
238
274
|
default: return countResourceRoleScopes(session, flags, selected.profile, operation, help, selected.name);
|
|
239
275
|
}
|
|
240
276
|
}
|
|
241
|
-
if (leaf.path === "entra lifecycle workflow list" || leaf.path === "entra lifecycle workflow show" || leaf.path === "entra lifecycle workflow count" || leaf.path === "entra lifecycle workflow-template list" || leaf.path === "entra lifecycle workflow-template show" || leaf.path === "entra lifecycle workflow-template count" || leaf.path === "entra lifecycle task-definition list" || leaf.path === "entra lifecycle task-definition show" || leaf.path === "entra lifecycle task-definition count" || leaf.path === "entra lifecycle settings show" || leaf.path === "entra lifecycle run list" || leaf.path === "entra lifecycle run show" || leaf.path === "entra lifecycle run count" || leaf.path === "entra lifecycle user-processing-result list" || leaf.path === "entra lifecycle user-processing-result show" || leaf.path === "entra lifecycle user-processing-result count" || leaf.path === "entra lifecycle subject-processing-result list" || leaf.path === "entra lifecycle subject-processing-result show" || leaf.path === "entra lifecycle subject-processing-result count" || leaf.path === "entra lifecycle task-report list" || leaf.path === "entra lifecycle task-report show" || leaf.path === "entra lifecycle task-report count" || leaf.path === "entra lifecycle task-report task show" || leaf.path === "entra lifecycle task-report task-definition show") {
|
|
277
|
+
if (leaf.path === "entra lifecycle workflow list" || leaf.path === "entra lifecycle workflow show" || leaf.path === "entra lifecycle workflow count" || leaf.path === "entra lifecycle workflow-template list" || leaf.path === "entra lifecycle workflow-template show" || leaf.path === "entra lifecycle workflow-template count" || leaf.path === "entra lifecycle task-definition list" || leaf.path === "entra lifecycle task-definition show" || leaf.path === "entra lifecycle task-definition count" || leaf.path === "entra lifecycle settings show" || leaf.path === "entra lifecycle run list" || leaf.path === "entra lifecycle run show" || leaf.path === "entra lifecycle run count" || leaf.path === "entra lifecycle user-processing-result list" || leaf.path === "entra lifecycle user-processing-result show" || leaf.path === "entra lifecycle user-processing-result count" || leaf.path === "entra lifecycle subject-processing-result list" || leaf.path === "entra lifecycle subject-processing-result show" || leaf.path === "entra lifecycle subject-processing-result count" || leaf.path === "entra lifecycle task-report list" || leaf.path === "entra lifecycle task-report show" || leaf.path === "entra lifecycle task-report count" || leaf.path === "entra lifecycle task-report task show" || leaf.path === "entra lifecycle task-report task-definition show" || leaf.path === "entra lifecycle run user-processing-result list" || leaf.path === "entra lifecycle run user-processing-result show" || leaf.path === "entra lifecycle run user-processing-result count" || leaf.path === "entra lifecycle run subject-processing-result list" || leaf.path === "entra lifecycle run subject-processing-result show" || leaf.path === "entra lifecycle run subject-processing-result count" || leaf.path === "entra lifecycle run task-processing-result list" || leaf.path === "entra lifecycle run task-processing-result show" || leaf.path === "entra lifecycle run task-processing-result count") {
|
|
242
278
|
if (String(flags["api-version"] ?? "v1.0") !== "v1.0") {
|
|
243
279
|
throw new AxiError("Lifecycle-workflow reads support v1.0 only; beta needs its own review", "VALIDATION_ERROR", [leafHelp(leaf)]);
|
|
244
280
|
}
|
|
@@ -287,6 +323,15 @@ export async function executeArgv(argv, overrides = {}) {
|
|
|
287
323
|
case "entra lifecycle task-report count": return countTaskReports(session, flags, selected.profile, operation, help, selected.name);
|
|
288
324
|
case "entra lifecycle task-report task show": return showTaskReportTask(session, flags, selected.profile, operation, help, selected.name);
|
|
289
325
|
case "entra lifecycle task-report task-definition show": return showTaskReportTaskDefinition(session, flags, selected.profile, operation, help, selected.name);
|
|
326
|
+
case "entra lifecycle run user-processing-result list": return listRunUserProcessingResults(session, flags, selected.profile, operation, help, selected.name);
|
|
327
|
+
case "entra lifecycle run user-processing-result show": return showRunUserProcessingResult(session, flags, selected.profile, operation, help, selected.name);
|
|
328
|
+
case "entra lifecycle run user-processing-result count": return countRunUserProcessingResults(session, flags, selected.profile, operation, help, selected.name);
|
|
329
|
+
case "entra lifecycle run subject-processing-result list": return listRunSubjectProcessingResults(session, flags, selected.profile, operation, help, selected.name);
|
|
330
|
+
case "entra lifecycle run subject-processing-result show": return showRunSubjectProcessingResult(session, flags, selected.profile, operation, help, selected.name);
|
|
331
|
+
case "entra lifecycle run subject-processing-result count": return countRunSubjectProcessingResults(session, flags, selected.profile, operation, help, selected.name);
|
|
332
|
+
case "entra lifecycle run task-processing-result list": return listRunTaskProcessingResults(session, flags, selected.profile, operation, help, selected.name);
|
|
333
|
+
case "entra lifecycle run task-processing-result show": return showRunTaskProcessingResult(session, flags, selected.profile, operation, help, selected.name);
|
|
334
|
+
case "entra lifecycle run task-processing-result count": return countRunTaskProcessingResults(session, flags, selected.profile, operation, help, selected.name);
|
|
290
335
|
default: return showLifecycleSettings(session, flags, selected.profile, operation, help, selected.name);
|
|
291
336
|
}
|
|
292
337
|
}
|
|
@@ -541,6 +586,11 @@ export async function executeArgv(argv, overrides = {}) {
|
|
|
541
586
|
});
|
|
542
587
|
}
|
|
543
588
|
if (leaf.path === "entra directory-role list" || leaf.path === "entra directory-role show" || leaf.path === "entra role-assignment list" || leaf.path === "entra pim eligible list" || leaf.path === "entra pim active list"
|
|
589
|
+
|| leaf.path === "entra pim group-assignment-schedule list" || leaf.path === "entra pim group-assignment-schedule show"
|
|
590
|
+
|| leaf.path === "entra pim group-assignment-instance list" || leaf.path === "entra pim group-assignment-instance show"
|
|
591
|
+
|| leaf.path === "entra pim group-eligibility-schedule list" || leaf.path === "entra pim group-eligibility-schedule show"
|
|
592
|
+
|| leaf.path === "entra pim group-eligibility-instance list" || leaf.path === "entra pim group-eligibility-instance show"
|
|
593
|
+
|| leaf.path === "entra pim group-eligibility-request list" || leaf.path === "entra pim group-eligibility-request show"
|
|
544
594
|
|| leaf.path === "entra device list" || leaf.path === "entra device show"
|
|
545
595
|
|| leaf.path === "entra administrative-unit list" || leaf.path === "entra administrative-unit show"
|
|
546
596
|
|| leaf.path === "entra administrative-unit member list") {
|
|
@@ -569,6 +619,16 @@ export async function executeArgv(argv, overrides = {}) {
|
|
|
569
619
|
case "entra role-assignment list": return listRoleAssignments(session, flags, selected.profile, operation, help, selected.name);
|
|
570
620
|
case "entra pim eligible list": return listPimEligible(session, flags, selected.profile, operation, help, selected.name);
|
|
571
621
|
case "entra pim active list": return listPimActive(session, flags, selected.profile, operation, help, selected.name);
|
|
622
|
+
case "entra pim group-assignment-schedule list": return listGroupAssignmentSchedules(session, flags, selected.profile, operation, help, selected.name);
|
|
623
|
+
case "entra pim group-assignment-schedule show": return showGroupAssignmentSchedule(session, flags, selected.profile, operation, help, selected.name);
|
|
624
|
+
case "entra pim group-assignment-instance list": return listGroupAssignmentInstances(session, flags, selected.profile, operation, help, selected.name);
|
|
625
|
+
case "entra pim group-assignment-instance show": return showGroupAssignmentInstance(session, flags, selected.profile, operation, help, selected.name);
|
|
626
|
+
case "entra pim group-eligibility-schedule list": return listGroupEligibilitySchedules(session, flags, selected.profile, operation, help, selected.name);
|
|
627
|
+
case "entra pim group-eligibility-schedule show": return showGroupEligibilitySchedule(session, flags, selected.profile, operation, help, selected.name);
|
|
628
|
+
case "entra pim group-eligibility-instance list": return listGroupEligibilityInstances(session, flags, selected.profile, operation, help, selected.name);
|
|
629
|
+
case "entra pim group-eligibility-instance show": return showGroupEligibilityInstance(session, flags, selected.profile, operation, help, selected.name);
|
|
630
|
+
case "entra pim group-eligibility-request list": return listGroupEligibilityRequests(session, flags, selected.profile, operation, help, selected.name);
|
|
631
|
+
case "entra pim group-eligibility-request show": return showGroupEligibilityRequest(session, flags, selected.profile, operation, help, selected.name);
|
|
572
632
|
case "entra device list": return listDevices(session, flags, selected.profile, operation, help, selected.name);
|
|
573
633
|
case "entra device show": return showDevice(session, flags, selected.profile, operation, help, selected.name);
|
|
574
634
|
case "entra administrative-unit list": return listAdministrativeUnits(session, flags, selected.profile, operation, help, selected.name);
|
|
@@ -702,7 +762,7 @@ export async function executeArgv(argv, overrides = {}) {
|
|
|
702
762
|
help: leafHelp(leaf),
|
|
703
763
|
});
|
|
704
764
|
}
|
|
705
|
-
if (leaf.path === "entra risky-user list" || leaf.path === "entra risky-user show" || leaf.path === "entra risk-detection list" || leaf.path === "entra risk-detection show") {
|
|
765
|
+
if (leaf.path === "entra risky-user list" || leaf.path === "entra risky-user show" || leaf.path === "entra risk-detection list" || leaf.path === "entra risk-detection show" || leaf.path === "entra risky-service-principal list" || leaf.path === "entra risky-service-principal show" || leaf.path === "entra risky-service-principal history list" || leaf.path === "entra risky-service-principal history show" || leaf.path === "entra service-principal-risk-detection list" || leaf.path === "entra service-principal-risk-detection show") {
|
|
706
766
|
const selected = profiles.resolve(flags.profile);
|
|
707
767
|
const operation = operationFor(leaf, String(flags["api-version"] ?? "v1.0"));
|
|
708
768
|
if (!operation || operation.method !== "GET") {
|
|
@@ -728,7 +788,13 @@ export async function executeArgv(argv, overrides = {}) {
|
|
|
728
788
|
case "entra risky-user list": return listRiskyUsers(session, flags, selected.profile, operation, help, selected.name);
|
|
729
789
|
case "entra risky-user show": return showRiskyUser(session, flags, selected.profile, operation, help, selected.name);
|
|
730
790
|
case "entra risk-detection list": return listRiskDetections(session, flags, selected.profile, operation, help, selected.name);
|
|
731
|
-
|
|
791
|
+
case "entra risk-detection show": return showRiskDetection(session, flags, selected.profile, operation, help, selected.name);
|
|
792
|
+
case "entra risky-service-principal list": return listRiskyServicePrincipals(session, flags, selected.profile, operation, help, selected.name);
|
|
793
|
+
case "entra risky-service-principal show": return showRiskyServicePrincipal(session, flags, selected.profile, operation, help, selected.name);
|
|
794
|
+
case "entra risky-service-principal history list": return listRiskyServicePrincipalHistory(session, flags, selected.profile, operation, help, selected.name);
|
|
795
|
+
case "entra risky-service-principal history show": return showRiskyServicePrincipalHistory(session, flags, selected.profile, operation, help, selected.name);
|
|
796
|
+
case "entra service-principal-risk-detection list": return listServicePrincipalRiskDetections(session, flags, selected.profile, operation, help, selected.name);
|
|
797
|
+
default: return showServicePrincipalRiskDetection(session, flags, selected.profile, operation, help, selected.name);
|
|
732
798
|
}
|
|
733
799
|
}
|
|
734
800
|
if (leaf.path === "entra domain list" || leaf.path === "entra domain show"
|
|
@@ -1106,7 +1172,7 @@ export async function executeArgv(argv, overrides = {}) {
|
|
|
1106
1172
|
default: return countContracts(session, flags, selected.profile, operation, help, selected.name);
|
|
1107
1173
|
}
|
|
1108
1174
|
}
|
|
1109
|
-
if (leaf.path === "entra delegated-admin-customer list" || leaf.path === "entra delegated-admin-customer show" || leaf.path === "entra delegated-admin-relationship list" || leaf.path === "entra delegated-admin-relationship show" || leaf.path === "entra delegated-admin-relationship list-access-assignments" || leaf.path === "entra delegated-admin-relationship show-access-assignment" || leaf.path === "entra delegated-admin-relationship list-operations" || leaf.path === "entra delegated-admin-relationship show-operation" || leaf.path === "entra delegated-admin-relationship list-requests" || leaf.path === "entra delegated-admin-relationship show-request" || leaf.path === "entra delegated-admin-customer list-service-management-details" || leaf.path === "entra delegated-admin-customer show-service-management-detail") {
|
|
1175
|
+
if (leaf.path === "entra delegated-admin-customer list" || leaf.path === "entra delegated-admin-customer show" || leaf.path === "entra delegated-admin-relationship list" || leaf.path === "entra delegated-admin-relationship show" || leaf.path === "entra delegated-admin-relationship list-access-assignments" || leaf.path === "entra delegated-admin-relationship show-access-assignment" || leaf.path === "entra delegated-admin-relationship list-operations" || leaf.path === "entra delegated-admin-relationship show-operation" || leaf.path === "entra delegated-admin-relationship list-requests" || leaf.path === "entra delegated-admin-relationship show-request" || leaf.path === "entra delegated-admin-customer list-service-management-details" || leaf.path === "entra delegated-admin-customer show-service-management-detail" || leaf.path === "entra delegated-admin-customer count" || leaf.path === "entra delegated-admin-customer count-service-management-details" || leaf.path === "entra delegated-admin-relationship count" || leaf.path === "entra delegated-admin-relationship count-access-assignments" || leaf.path === "entra delegated-admin-relationship count-operations" || leaf.path === "entra delegated-admin-relationship count-requests") {
|
|
1110
1176
|
if (String(flags["api-version"] ?? "v1.0") !== "v1.0") {
|
|
1111
1177
|
throw new AxiError("Delegated-admin reads support v1.0 only; beta needs its own review", "VALIDATION_ERROR", [leafHelp(leaf)]);
|
|
1112
1178
|
}
|
|
@@ -1141,6 +1207,12 @@ export async function executeArgv(argv, overrides = {}) {
|
|
|
1141
1207
|
case "entra delegated-admin-relationship list-requests": return listDelegatedAdminRequests(session, flags, selected.profile, operation, help, selected.name);
|
|
1142
1208
|
case "entra delegated-admin-relationship show-request": return showDelegatedAdminRequest(session, flags, selected.profile, operation, help, selected.name);
|
|
1143
1209
|
case "entra delegated-admin-customer list-service-management-details": return listDelegatedAdminServiceManagementDetails(session, flags, selected.profile, operation, help, selected.name);
|
|
1210
|
+
case "entra delegated-admin-customer count": return countDelegatedAdminCustomers(session, flags, selected.profile, operation, help, selected.name);
|
|
1211
|
+
case "entra delegated-admin-customer count-service-management-details": return countDelegatedAdminServiceManagementDetails(session, flags, selected.profile, operation, help, selected.name);
|
|
1212
|
+
case "entra delegated-admin-relationship count": return countDelegatedAdminRelationships(session, flags, selected.profile, operation, help, selected.name);
|
|
1213
|
+
case "entra delegated-admin-relationship count-access-assignments": return countDelegatedAdminAccessAssignments(session, flags, selected.profile, operation, help, selected.name);
|
|
1214
|
+
case "entra delegated-admin-relationship count-operations": return countDelegatedAdminOperations(session, flags, selected.profile, operation, help, selected.name);
|
|
1215
|
+
case "entra delegated-admin-relationship count-requests": return countDelegatedAdminRequests(session, flags, selected.profile, operation, help, selected.name);
|
|
1144
1216
|
default: return showDelegatedAdminServiceManagementDetail(session, flags, selected.profile, operation, help, selected.name);
|
|
1145
1217
|
}
|
|
1146
1218
|
}
|
|
@@ -1288,6 +1360,42 @@ export async function executeArgv(argv, overrides = {}) {
|
|
|
1288
1360
|
default: return countDataPolicyOperations(session, flags, selected.profile, operation, help, selected.name);
|
|
1289
1361
|
}
|
|
1290
1362
|
}
|
|
1363
|
+
if (leaf.path === "entra fraud-protection-provider list" || leaf.path === "entra fraud-protection-provider show" || leaf.path === "entra fraud-protection-provider count" || leaf.path === "entra web-application-firewall-provider list" || leaf.path === "entra web-application-firewall-provider show" || leaf.path === "entra web-application-firewall-provider count" || leaf.path === "entra web-application-firewall-verification list" || leaf.path === "entra web-application-firewall-verification show" || leaf.path === "entra web-application-firewall-verification count" || leaf.path === "entra web-application-firewall-verification provider show") {
|
|
1364
|
+
if (String(flags["api-version"] ?? "v1.0") !== "v1.0") {
|
|
1365
|
+
throw new AxiError("Risk-prevention reads support v1.0 only; beta needs its own review", "VALIDATION_ERROR", [leafHelp(leaf)]);
|
|
1366
|
+
}
|
|
1367
|
+
const selected = profiles.resolve(flags.profile);
|
|
1368
|
+
const operation = operationFor(leaf, "v1.0");
|
|
1369
|
+
if (!operation || operation.method !== "GET") {
|
|
1370
|
+
throw new AxiError(`Unknown catalogued Graph operation for ${leaf.path}`, "VALIDATION_ERROR", [leafHelp(leaf)]);
|
|
1371
|
+
}
|
|
1372
|
+
let delegated = overrides.delegated;
|
|
1373
|
+
let application = overrides.application;
|
|
1374
|
+
if (!delegated) {
|
|
1375
|
+
const { DelegatedAuth: Service } = await import("./auth.js");
|
|
1376
|
+
const { MsalProvider } = await import("./msal-provider.js");
|
|
1377
|
+
delegated = new Service(new MsalProvider());
|
|
1378
|
+
}
|
|
1379
|
+
if (!application) {
|
|
1380
|
+
const { ApplicationAuth: Service } = await import("./app-auth.js");
|
|
1381
|
+
const { MsalApplicationProvider } = await import("./msal-app-provider.js");
|
|
1382
|
+
application = new Service(new MsalApplicationProvider());
|
|
1383
|
+
}
|
|
1384
|
+
const session = new GraphSession({ delegated, application, transport: overrides.transport ?? fetchTransport });
|
|
1385
|
+
const help = leafHelp(leaf);
|
|
1386
|
+
switch (leaf.path) {
|
|
1387
|
+
case "entra fraud-protection-provider list": return listFraudProtectionProviders(session, flags, selected.profile, operation, help, selected.name);
|
|
1388
|
+
case "entra fraud-protection-provider show": return showFraudProtectionProvider(session, flags, selected.profile, operation, help, selected.name);
|
|
1389
|
+
case "entra fraud-protection-provider count": return countFraudProtectionProviders(session, flags, selected.profile, operation, help);
|
|
1390
|
+
case "entra web-application-firewall-provider list": return listWafProviders(session, flags, selected.profile, operation, help, selected.name);
|
|
1391
|
+
case "entra web-application-firewall-provider show": return showWafProvider(session, flags, selected.profile, operation, help, selected.name);
|
|
1392
|
+
case "entra web-application-firewall-provider count": return countWafProviders(session, flags, selected.profile, operation, help);
|
|
1393
|
+
case "entra web-application-firewall-verification list": return listWafVerifications(session, flags, selected.profile, operation, help, selected.name);
|
|
1394
|
+
case "entra web-application-firewall-verification show": return showWafVerification(session, flags, selected.profile, operation, help, selected.name);
|
|
1395
|
+
case "entra web-application-firewall-verification count": return countWafVerifications(session, flags, selected.profile, operation, help);
|
|
1396
|
+
default: return showVerificationProvider(session, flags, selected.profile, operation, help, selected.name);
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1291
1399
|
const operation = operationFor(leaf, String(flags["api-version"] ?? "v1.0"));
|
|
1292
1400
|
throw new AxiError(`Command is not executable: ${operation?.disposition ?? "unavailable"} (${operation?.owningSlice ?? "no inventory mapping"})`, "NOT_IMPLEMENTED", [leafHelp(leaf)]);
|
|
1293
1401
|
}
|
package/dist/docs.js
CHANGED
|
@@ -74,10 +74,15 @@ const READ_AREA_LABELS = [
|
|
|
74
74
|
["entra service-principal ", "applications and consent grants"],
|
|
75
75
|
["entra risky-user ", "risk"],
|
|
76
76
|
["entra risk-detection ", "risk"],
|
|
77
|
+
["entra risky-service-principal ", "risk"],
|
|
78
|
+
["entra service-principal-risk-detection ", "risk"],
|
|
77
79
|
["entra conditional-access ", "Conditional Access"],
|
|
78
80
|
["entra identity-provider ", "identity providers"],
|
|
79
81
|
["entra federation-configuration ", "federation configurations"],
|
|
80
82
|
["entra data-policy-operation ", "data policy operations"],
|
|
83
|
+
["entra fraud-protection-provider ", "risk prevention"],
|
|
84
|
+
["entra web-application-firewall-provider ", "risk prevention"],
|
|
85
|
+
["entra web-application-firewall-verification ", "risk prevention"],
|
|
81
86
|
["entra access-review ", "access reviews"],
|
|
82
87
|
["entra entitlement catalog ", "entitlement catalogs and access packages"],
|
|
83
88
|
["entra entitlement access-package ", "entitlement catalogs and access packages"],
|
|
@@ -200,6 +205,19 @@ export function skillDocument() {
|
|
|
200
205
|
"Configuration defaults to `~/.mg-axi/config.json`; `MG_AXI_CONFIG` selects a separate file.",
|
|
201
206
|
"`mg-axi setup` shows the selected path and writes nothing.",
|
|
202
207
|
"",
|
|
208
|
+
"Agent discovery has two install paths, and either suffices alone.",
|
|
209
|
+
"For ambient context at every agent session start instead of the skill, install the CLI globally and opt into the session hook:",
|
|
210
|
+
"",
|
|
211
|
+
"```sh",
|
|
212
|
+
"npm install --global @knowttl/mg-axi",
|
|
213
|
+
"mg-axi setup hooks",
|
|
214
|
+
"```",
|
|
215
|
+
"",
|
|
216
|
+
"This installs a `SessionStart` hook for Claude Code, Codex and OpenCode that prints a short local-only summary (configured profile names with tenant labels, auth-cache presence, write posture and version).",
|
|
217
|
+
"The hook makes no network, Graph or sign-in call, and prints a short `not configured` record with exit 0 when unconfigured.",
|
|
218
|
+
"Restart the agent session after running the installer.",
|
|
219
|
+
"No other ordinary command installs hooks, plugins or configuration.",
|
|
220
|
+
"",
|
|
203
221
|
"## Selecting a profile",
|
|
204
222
|
"",
|
|
205
223
|
"Read leaves accept `--profile <name>`.",
|
|
@@ -273,6 +291,7 @@ export function capabilityDocument() {
|
|
|
273
291
|
const deferredProviderRows = rows.filter(row => row.owningSlice === "EXT-03" && row.reason.startsWith("Deferred to a later EXT-03 "));
|
|
274
292
|
const deferredFederationRows = rows.filter(row => row.owningSlice === "EXT-01" && row.reason.startsWith("Deferred by firstmate federation-configuration scope "));
|
|
275
293
|
const deferredDataPolicyRows = rows.filter(row => row.owningSlice === "EXT-03" && row.reason.startsWith("Deferred by firstmate data-policy-operations scope "));
|
|
294
|
+
const deferredRiskPreventionRows = rows.filter(row => row.owningSlice === "EXT-03" && row.reason.startsWith("Deferred by firstmate risk-prevention scope "));
|
|
276
295
|
const unavailableInvitationRows = rows.filter(row => row.owningSlice === "EXT-03" && row.reason.startsWith("Marked unavailable by firstmate EXT-03b decision: "));
|
|
277
296
|
const deferredOrganizationRows = rows.filter(row => row.owningSlice === "EXT-01" && row.reason.startsWith("Deferred by firstmate organization scope "));
|
|
278
297
|
const unavailableCertAuthRows = rows.filter(row => row.owningSlice === "EXT-01" && row.reason.startsWith("Marked unavailable by firstmate mg-ext-01d decision: "));
|
|
@@ -285,6 +304,7 @@ export function capabilityDocument() {
|
|
|
285
304
|
const deferredContractRows = rows.filter(row => row.owningSlice === "EXT-04" && row.reason.startsWith("Deferred by firstmate contracts scope "));
|
|
286
305
|
const deferredDelegatedAdminRows = rows.filter(row => row.owningSlice === "EXT-04" && row.reason.startsWith("Deferred by firstmate delegated-admin scope "));
|
|
287
306
|
const deferredMtoRows = rows.filter(row => row.owningSlice === "EXT-04" && row.reason.startsWith("Deferred by firstmate multi-tenant-organization scope "));
|
|
307
|
+
const deferredReportsRows = rows.filter(row => row.owningSlice === "EXT-04" && row.reason.startsWith("Deferred by firstmate reports scope "));
|
|
288
308
|
const deferredGroupLifecycleRows = rows.filter(row => row.owningSlice === "EXT-01" && row.reason.startsWith("Deferred by firstmate group-lifecycle scope "));
|
|
289
309
|
const deferredCustomSecurityRows = rows.filter(row => row.owningSlice === "EXT-01" && row.reason.startsWith("Deferred by firstmate custom-security-attributes scope "));
|
|
290
310
|
const deferredAccessReviewRows = rows.filter(row => row.owningSlice === "EXT-02c");
|
|
@@ -364,6 +384,18 @@ export function capabilityDocument() {
|
|
|
364
384
|
"|---|---|---|---|",
|
|
365
385
|
...deferredDataPolicyRows.map(row => `| \`${row.id}\` | ${row.disposition} (deferred) | ${row.owningSlice} | ${row.reason} |`),
|
|
366
386
|
"",
|
|
387
|
+
"## EXT-03 risk-prevention scope decisions",
|
|
388
|
+
"",
|
|
389
|
+
"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 with an explicit deferred disposition to a later EXT-03 subfamily; no new commands or raw access are approved.",
|
|
391
|
+
"Risk-prevention reads support v1.0 only; beta needs its own review.",
|
|
392
|
+
"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
|
+
"Workforce context only; no external-customer support is claimed.",
|
|
394
|
+
"",
|
|
395
|
+
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
396
|
+
"|---|---|---|---|",
|
|
397
|
+
...deferredRiskPreventionRows.map(row => `| \`${row.id}\` | ${row.disposition} (deferred) | ${row.owningSlice} | ${row.reason} |`),
|
|
398
|
+
"",
|
|
367
399
|
"## EXT-03 invitations scope decisions",
|
|
368
400
|
"",
|
|
369
401
|
"Firstmate decision (mg-ext-03b inbox 001): do not implement these reads and add no scope.",
|
|
@@ -495,9 +527,9 @@ export function capabilityDocument() {
|
|
|
495
527
|
...deferredContractRows.map(row => `| \`${row.id}\` | ${row.disposition} (deferred) | ${row.owningSlice} | ${row.reason} |`), "",
|
|
496
528
|
"## EXT-04 delegated-admin scope decisions",
|
|
497
529
|
"",
|
|
498
|
-
"Firstmate scope: approve narrowing this change to the
|
|
530
|
+
"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).",
|
|
499
531
|
"The operations below remain scheduled with an explicit deferred disposition to a later EXT-04 subfamily; no new commands or raw access are approved.",
|
|
500
|
-
"
|
|
532
|
+
"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.",
|
|
501
533
|
"",
|
|
502
534
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
503
535
|
"|---|---|---|---|",
|
|
@@ -510,6 +542,14 @@ export function capabilityDocument() {
|
|
|
510
542
|
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
511
543
|
"|---|---|---|---|",
|
|
512
544
|
...deferredMtoRows.map(row => `| \`${row.id}\` | ${row.disposition} (deferred) | ${row.owningSlice} | ${row.reason} |`), "",
|
|
545
|
+
"## EXT-04 reports scope decisions",
|
|
546
|
+
"",
|
|
547
|
+
"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 remains scheduled with an explicit deferred disposition: 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
|
+
"",
|
|
550
|
+
"| Inventory operation | Disposition | Owning slice | Deferral reason |",
|
|
551
|
+
"|---|---|---|---|",
|
|
552
|
+
...deferredReportsRows.map(row => `| \`${row.id}\` | ${row.disposition} (deferred) | ${row.owningSlice} | ${row.reason} |`), "",
|
|
513
553
|
"## EXT-04 tenant-lookup scope decisions",
|
|
514
554
|
"",
|
|
515
555
|
"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).",
|
|
@@ -538,9 +578,9 @@ export function capabilityDocument() {
|
|
|
538
578
|
"",
|
|
539
579
|
"## EXT-02 lifecycle-workflows scope decisions",
|
|
540
580
|
"",
|
|
541
|
-
"This change covers the
|
|
542
|
-
"
|
|
543
|
-
"No new commands or raw access are approved for any lifecycle-workflows row outside the
|
|
581
|
+
"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 scheduled 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 and every mutation (no workflow create/update/delete/activate/run, no settings update, no restore) stays out.",
|
|
583
|
+
"No new commands or raw access are approved for any lifecycle-workflows row outside the thirty-three above.",
|
|
544
584
|
"",
|
|
545
585
|
"## Named writes",
|
|
546
586
|
"",
|
package/dist/doctor.js
CHANGED
|
@@ -44,8 +44,8 @@ export async function runDoctor(args) {
|
|
|
44
44
|
// surfaced row, remainder buffered in a discarded cursor. Doctor keeps
|
|
45
45
|
// no cursor and accepts none; recovery reruns doctor, not the read.
|
|
46
46
|
const result = (await listUsers(args.session, { limit: "1" }, selected.profile, operation, `npx -y @knowttl/mg-axi ${DOCTOR_CHECK} --help`, name));
|
|
47
|
-
if (!result.
|
|
48
|
-
throw new AxiError(`Doctor read incomplete: ${result.
|
|
47
|
+
if (!result.complete && result.reason !== "row limit reached; buffered remainder is preserved in the cursor") {
|
|
48
|
+
throw new AxiError(`Doctor read incomplete: ${result.reason}`, "GRAPH_ERROR", [rerun]);
|
|
49
49
|
}
|
|
50
50
|
profiles.push({ name, mode: selected.profile.mode, check: DOCTOR_CHECK, status: "ok",
|
|
51
51
|
detail: result.users.length ? "1 user row returned" : "0 users matched; the absence of results is the answer" });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-02 access-reviews subfamily: the read-only access-review mapping.
|
|
3
4
|
// See README.md for the supported commands and usage. Operation construction
|
|
4
5
|
// stays beside its command; the shared session owns URLs, credentials, paging,
|
|
@@ -236,6 +237,7 @@ const ACCESS_REVIEW_DENIAL_HINTS = [
|
|
|
236
237
|
const DEFINITION_LIST = {
|
|
237
238
|
command: "entra access-review definition list",
|
|
238
239
|
key: "definitions",
|
|
240
|
+
noun: "access-review definitions",
|
|
239
241
|
known: DEFINITION_KNOWN,
|
|
240
242
|
knownList: KNOWN_DEFINITION_FIELDS,
|
|
241
243
|
defaultSelect: DEFAULT_DEFINITION_LIST_SELECT,
|
|
@@ -249,6 +251,7 @@ const DEFINITION_LIST = {
|
|
|
249
251
|
const INSTANCE_LIST = {
|
|
250
252
|
command: "entra access-review instance list",
|
|
251
253
|
key: "instances",
|
|
254
|
+
noun: "access-review instances",
|
|
252
255
|
known: INSTANCE_KNOWN,
|
|
253
256
|
knownList: KNOWN_INSTANCE_FIELDS,
|
|
254
257
|
defaultSelect: DEFAULT_INSTANCE_LIST_SELECT,
|
|
@@ -261,6 +264,7 @@ const INSTANCE_LIST = {
|
|
|
261
264
|
const DECISION_LIST = {
|
|
262
265
|
command: "entra access-review decision list",
|
|
263
266
|
key: "decisions",
|
|
267
|
+
noun: "access-review decisions",
|
|
264
268
|
known: DECISION_KNOWN,
|
|
265
269
|
knownList: KNOWN_DECISION_FIELDS,
|
|
266
270
|
defaultSelect: DEFAULT_DECISION_SELECT,
|
|
@@ -273,6 +277,7 @@ const DECISION_LIST = {
|
|
|
273
277
|
const CONTACTED_REVIEWER_LIST = {
|
|
274
278
|
command: "entra access-review contacted-reviewer list",
|
|
275
279
|
key: "contactedReviewers",
|
|
280
|
+
noun: "contacted reviewers",
|
|
276
281
|
known: CONTACTED_REVIEWER_KNOWN,
|
|
277
282
|
knownList: KNOWN_CONTACTED_REVIEWER_FIELDS,
|
|
278
283
|
defaultSelect: DEFAULT_CONTACTED_REVIEWER_LIST_SELECT,
|
|
@@ -286,6 +291,7 @@ const CONTACTED_REVIEWER_LIST = {
|
|
|
286
291
|
const STAGE_LIST = {
|
|
287
292
|
command: "entra access-review stage list",
|
|
288
293
|
key: "stages",
|
|
294
|
+
noun: "access-review stages",
|
|
289
295
|
known: STAGE_KNOWN,
|
|
290
296
|
knownList: KNOWN_STAGE_FIELDS,
|
|
291
297
|
defaultSelect: DEFAULT_STAGE_LIST_SELECT,
|
|
@@ -347,16 +353,17 @@ async function listCollection(shape, session, flags, profile, operation, help, p
|
|
|
347
353
|
if (!result.complete) {
|
|
348
354
|
return {
|
|
349
355
|
[shape.key]: rows,
|
|
350
|
-
|
|
356
|
+
...listTotals(rows.length, result.total, shape.noun, false),
|
|
357
|
+
complete: false,
|
|
358
|
+
reason: result.reason,
|
|
351
359
|
cursor: result.cursor,
|
|
352
360
|
help: [...truncationHints, resumeHint, ...standing],
|
|
353
361
|
};
|
|
354
362
|
}
|
|
355
|
-
const count = { returned: rows.length, complete: true };
|
|
356
363
|
if (!rows.length) {
|
|
357
|
-
return { [shape.key]: rows,
|
|
364
|
+
return { [shape.key]: rows, ...listTotals(rows.length, result.total, shape.noun, true), complete: true, help: [shape.emptyNote, ...standing] };
|
|
358
365
|
}
|
|
359
|
-
return { [shape.key]: rows,
|
|
366
|
+
return { [shape.key]: rows, ...listTotals(rows.length, result.total, shape.noun, true), complete: true, help: [...truncationHints, ...standing] };
|
|
360
367
|
}
|
|
361
368
|
async function showOne(key, command, known, knownList, defaultSelect, session, flags, profile, operation, help, profileName, params, malformed) {
|
|
362
369
|
const { select, fields } = selectedFields(flags, defaultSelect, known, knownList, help);
|
package/dist/entra-apps.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
import { SAFE_CREDENTIAL_FIELDS } from "./graph-session.js";
|
|
3
4
|
// READ-07: the Entra application and service-principal read mapping behind
|
|
4
5
|
// `mg-axi entra application list/show`, `mg-axi entra service-principal
|
|
@@ -270,23 +271,25 @@ async function listCollection(session, flags, profile, operation, help, profileN
|
|
|
270
271
|
if (!result.complete) {
|
|
271
272
|
return {
|
|
272
273
|
[key]: rows,
|
|
273
|
-
|
|
274
|
+
...listTotals(rows.length, result.total, emptyNoun, false),
|
|
275
|
+
complete: false,
|
|
276
|
+
reason: result.reason,
|
|
274
277
|
cursor: result.cursor,
|
|
275
278
|
help: [...truncationHints, resumeHint(profileName), showHint],
|
|
276
279
|
};
|
|
277
280
|
}
|
|
278
|
-
const count = { returned: rows.length, complete: true };
|
|
279
281
|
if (!rows.length) {
|
|
280
282
|
return {
|
|
281
283
|
[key]: rows,
|
|
282
|
-
|
|
284
|
+
...listTotals(rows.length, result.total, emptyNoun, true),
|
|
285
|
+
complete: true,
|
|
283
286
|
help: [
|
|
284
287
|
`0 ${emptyNoun} matched; the absence of results is the answer, not an error`,
|
|
285
288
|
showHint,
|
|
286
289
|
],
|
|
287
290
|
};
|
|
288
291
|
}
|
|
289
|
-
return { [key]: rows,
|
|
292
|
+
return { [key]: rows, ...listTotals(rows.length, result.total, emptyNoun, true), complete: true, help: [...truncationHints, showHint] };
|
|
290
293
|
}
|
|
291
294
|
async function showSingle(session, flags, profile, operation, help, profileName, command, key, known, knownList, defaults, param, flag) {
|
|
292
295
|
checkReadOperation(operation, help);
|
|
@@ -351,20 +354,22 @@ async function listOwners(session, flags, profile, operation, help, profileName,
|
|
|
351
354
|
if (!result.complete) {
|
|
352
355
|
return {
|
|
353
356
|
owners: rows,
|
|
354
|
-
|
|
357
|
+
...listTotals(rows.length, result.total, "owners", false),
|
|
358
|
+
complete: false,
|
|
359
|
+
reason: result.reason,
|
|
355
360
|
cursor: result.cursor,
|
|
356
361
|
help: [...truncationHints, ...limitedHints, resumeHint(profileName)],
|
|
357
362
|
};
|
|
358
363
|
}
|
|
359
|
-
const count = { returned: rows.length, complete: true };
|
|
360
364
|
if (!rows.length) {
|
|
361
365
|
return {
|
|
362
366
|
owners: rows,
|
|
363
|
-
|
|
367
|
+
...listTotals(rows.length, result.total, "owners", true),
|
|
368
|
+
complete: true,
|
|
364
369
|
help: [...limitedHints, "0 owners matched; the absence of results is the answer, not an error"],
|
|
365
370
|
};
|
|
366
371
|
}
|
|
367
|
-
return { owners: rows,
|
|
372
|
+
return { owners: rows, ...listTotals(rows.length, result.total, "owners", true), complete: true, help: [...truncationHints, ...limitedHints] };
|
|
368
373
|
}
|
|
369
374
|
export async function listApplicationOwners(session, flags, profile, operation, help, profileName) {
|
|
370
375
|
return listOwners(session, flags, profile, operation, help, profileName, "entra application owner list", "application-id", "application");
|
package/dist/entra-audit-logs.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// READ-05: the Entra sign-in and directory-audit read mapping behind
|
|
3
4
|
// `mg-axi entra sign-in list/show` and `mg-axi entra directory-audit
|
|
4
5
|
// list/show`. Operation construction stays beside its command; the shared
|
|
@@ -228,6 +229,7 @@ const AUDIT_DENIAL_HINTS = [
|
|
|
228
229
|
];
|
|
229
230
|
const SIGNIN_LIST = {
|
|
230
231
|
noun: "sign-in",
|
|
232
|
+
plural: "sign-ins",
|
|
231
233
|
key: "signIns",
|
|
232
234
|
dateField: "createdDateTime",
|
|
233
235
|
known: SIGNIN_KNOWN,
|
|
@@ -243,6 +245,7 @@ const SIGNIN_LIST = {
|
|
|
243
245
|
};
|
|
244
246
|
const AUDIT_LIST = {
|
|
245
247
|
noun: "directory-audit",
|
|
248
|
+
plural: "directory audits",
|
|
246
249
|
key: "directoryAudits",
|
|
247
250
|
dateField: "activityDateTime",
|
|
248
251
|
known: AUDIT_KNOWN,
|
|
@@ -313,16 +316,17 @@ async function listLogs(shape, session, flags, profile, operation, help, profile
|
|
|
313
316
|
if (!result.complete) {
|
|
314
317
|
return {
|
|
315
318
|
[shape.key]: rows,
|
|
316
|
-
|
|
319
|
+
...listTotals(rows.length, result.total, shape.plural, false),
|
|
320
|
+
complete: false,
|
|
321
|
+
reason: result.reason,
|
|
317
322
|
cursor: result.cursor,
|
|
318
323
|
help: [...truncationHints, `Resume losslessly with the same flags plus --cursor - ${profileHint(profileName)} and supply the returned cursor on stdin`, showHint],
|
|
319
324
|
};
|
|
320
325
|
}
|
|
321
|
-
const count = { returned: rows.length, complete: true };
|
|
322
326
|
if (!rows.length) {
|
|
323
|
-
return { [shape.key]: rows,
|
|
327
|
+
return { [shape.key]: rows, ...listTotals(rows.length, result.total, shape.plural, true), complete: true, help: shape.emptyHints(profileName) };
|
|
324
328
|
}
|
|
325
|
-
return { [shape.key]: rows,
|
|
329
|
+
return { [shape.key]: rows, ...listTotals(rows.length, result.total, shape.plural, true), complete: true, help: [...truncationHints, showHint] };
|
|
326
330
|
}
|
|
327
331
|
const SIGNIN_SHOW = {
|
|
328
332
|
noun: "sign-in",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// READ-04: the Entra authentication-method and registration-report read
|
|
3
4
|
// mapping behind `mg-axi entra user authentication-method list` and
|
|
4
5
|
// `mg-axi entra registration list`. Operation construction stays beside its
|
|
@@ -203,6 +204,7 @@ const REPORT_DENIAL_HINTS = [
|
|
|
203
204
|
const METHOD_LIST = {
|
|
204
205
|
command: "entra user authentication-method list",
|
|
205
206
|
key: "authenticationMethods",
|
|
207
|
+
noun: "authentication methods",
|
|
206
208
|
known: KNOWN_METHODS,
|
|
207
209
|
knownList: KNOWN_METHOD_FIELDS,
|
|
208
210
|
defaultSelect: DEFAULT_METHOD_SELECT,
|
|
@@ -218,6 +220,7 @@ const METHOD_LIST = {
|
|
|
218
220
|
const REPORT_LIST = {
|
|
219
221
|
command: "entra registration list",
|
|
220
222
|
key: "registrationDetails",
|
|
223
|
+
noun: "registration rows",
|
|
221
224
|
known: KNOWN_REPORT,
|
|
222
225
|
knownList: KNOWN_REPORT_FIELDS,
|
|
223
226
|
defaultSelect: DEFAULT_REPORT_SELECT,
|
|
@@ -274,16 +277,17 @@ async function listCollection(shape, session, flags, profile, operation, help, p
|
|
|
274
277
|
if (!result.complete) {
|
|
275
278
|
return {
|
|
276
279
|
[shape.key]: rows,
|
|
277
|
-
|
|
280
|
+
...listTotals(rows.length, result.total, shape.noun, false),
|
|
281
|
+
complete: false,
|
|
282
|
+
reason: result.reason,
|
|
278
283
|
cursor: result.cursor,
|
|
279
284
|
help: [...truncationHints, `Resume losslessly with the same flags plus --cursor <cursor-from-output> ${profileHint(profileName)}`, ...standing],
|
|
280
285
|
};
|
|
281
286
|
}
|
|
282
|
-
const count = { returned: rows.length, complete: true };
|
|
283
287
|
if (!rows.length) {
|
|
284
|
-
return { [shape.key]: rows,
|
|
288
|
+
return { [shape.key]: rows, ...listTotals(rows.length, result.total, shape.noun, true), complete: true, help: [shape.emptyNote, ...standing] };
|
|
285
289
|
}
|
|
286
|
-
return { [shape.key]: rows,
|
|
290
|
+
return { [shape.key]: rows, ...listTotals(rows.length, result.total, shape.noun, true), complete: true, help: [...truncationHints, ...standing] };
|
|
287
291
|
}
|
|
288
292
|
export async function listAuthenticationMethods(session, flags, profile, operation, help, profileName) {
|
|
289
293
|
const user = String(flags.user);
|