@knowttl/mg-axi 0.1.0
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 +1138 -0
- package/dist/api.js +953 -0
- package/dist/app-auth.js +47 -0
- package/dist/auth.js +59 -0
- package/dist/bin/mg-axi.js +7 -0
- package/dist/catalogue.js +2191 -0
- package/dist/cli.js +1314 -0
- package/dist/docs.js +559 -0
- package/dist/doctor.js +75 -0
- package/dist/entra-access-reviews.js +425 -0
- package/dist/entra-apps.js +374 -0
- package/dist/entra-audit-logs.js +381 -0
- package/dist/entra-auth-methods.js +296 -0
- package/dist/entra-ca-policy-update.js +353 -0
- package/dist/entra-certificate-auth.js +384 -0
- package/dist/entra-conditional-access.js +317 -0
- package/dist/entra-contacts.js +827 -0
- package/dist/entra-contracts.js +252 -0
- package/dist/entra-custom-security-attributes.js +464 -0
- package/dist/entra-data-policy-operations.js +274 -0
- package/dist/entra-delegated-admin.js +468 -0
- package/dist/entra-deleted-items.js +461 -0
- package/dist/entra-directory-objects.js +274 -0
- package/dist/entra-directory.js +411 -0
- package/dist/entra-domains.js +399 -0
- package/dist/entra-entitlement-management.js +645 -0
- package/dist/entra-federation-configurations.js +290 -0
- package/dist/entra-grants.js +272 -0
- package/dist/entra-group-lifecycle.js +349 -0
- package/dist/entra-group-member-add.js +278 -0
- package/dist/entra-groups.js +336 -0
- package/dist/entra-identity-providers.js +297 -0
- package/dist/entra-lifecycle-workflows.js +673 -0
- package/dist/entra-multi-tenant-organization.js +309 -0
- package/dist/entra-on-premises-synchronization.js +231 -0
- package/dist/entra-organization.js +398 -0
- package/dist/entra-risk-dismiss.js +191 -0
- package/dist/entra-risk.js +404 -0
- package/dist/entra-roles.js +310 -0
- package/dist/entra-subscriptions.js +289 -0
- package/dist/entra-tenant-information.js +152 -0
- package/dist/entra-terms-of-use.js +380 -0
- package/dist/entra-user-revoke-sessions.js +170 -0
- package/dist/entra-user-update.js +170 -0
- package/dist/entra-users.js +211 -0
- package/dist/graph-session.js +1034 -0
- package/dist/msal-app-provider.js +42 -0
- package/dist/msal-provider.js +82 -0
- package/dist/mutations.js +529 -0
- package/dist/profiles.js +139 -0
- package/dist/setup.js +116 -0
- package/dist/version.js +2 -0
- package/docs/coverage.md +1028 -0
- package/inventory/operations.json +4 -0
- package/inventory/schema.json +71 -0
- package/package.json +32 -0
- package/skills/mg-axi/SKILL.md +293 -0
package/dist/app-auth.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { validateApplicationProfile } from "./profiles.js";
|
|
3
|
+
// The configured Graph audience is the app's consented application grants, never a per-command subset.
|
|
4
|
+
export const graphAudience = (profile) => `https://graph.microsoft.com/.default`;
|
|
5
|
+
// This service is the application credential boundary for CORE-01; tokens never reach CLI output.
|
|
6
|
+
// It has no login method: application profiles never invoke interactive login or delegated fallback.
|
|
7
|
+
export class ApplicationAuth {
|
|
8
|
+
provider;
|
|
9
|
+
now;
|
|
10
|
+
cache = new Map();
|
|
11
|
+
constructor(provider, now = Date.now) {
|
|
12
|
+
this.provider = provider;
|
|
13
|
+
this.now = now;
|
|
14
|
+
}
|
|
15
|
+
async credential(profile, scopes = [graphAudience(profile)]) {
|
|
16
|
+
profile = validateApplicationProfile(profile);
|
|
17
|
+
const requested = this.audience(profile, scopes);
|
|
18
|
+
const key = this.key(profile, requested);
|
|
19
|
+
const hit = this.cache.get(key);
|
|
20
|
+
if (hit && hit.expiresAt > this.now() + 60_000)
|
|
21
|
+
return { ...hit };
|
|
22
|
+
this.cache.delete(key);
|
|
23
|
+
try {
|
|
24
|
+
const credential = this.check(profile, await this.provider.acquire(profile, requested));
|
|
25
|
+
// One identity per profile: a replacement wipes rather than merges.
|
|
26
|
+
this.cache.clear();
|
|
27
|
+
this.cache.set(key, credential);
|
|
28
|
+
return { ...credential };
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
throw this.failure();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
audience(profile, scopes) {
|
|
35
|
+
const configured = [graphAudience(profile)];
|
|
36
|
+
if (scopes.length !== 1 || scopes[0] !== configured[0])
|
|
37
|
+
throw new AxiError("Application profiles use the configured Graph .default audience; delegated scopes are unavailable", "VALIDATION_ERROR", ["mg-axi profile show --profile <name>", "Application permissions apply to the app registration, not to individual commands"]);
|
|
38
|
+
return configured;
|
|
39
|
+
}
|
|
40
|
+
key(profile, scopes) { return JSON.stringify([profile.credentialRef, profile.tenantId, profile.clientId, profile.cloud, scopes]); }
|
|
41
|
+
check(profile, credential) {
|
|
42
|
+
if (!credential.token || credential.tenantId.toLowerCase() !== profile.tenantId.toLowerCase() || credential.clientId.toLowerCase() !== profile.clientId.toLowerCase() || !Number.isFinite(credential.expiresAt) || credential.expiresAt <= this.now() + 60_000)
|
|
43
|
+
throw new Error("Invalid credential context");
|
|
44
|
+
return { ...credential };
|
|
45
|
+
}
|
|
46
|
+
failure() { return new AxiError("Application authentication failed for the configured identity; no user or device-code fallback was attempted", "AUTH_REQUIRED", ["mg-axi profile show --profile <name>", "Ask an administrator to grant application consent for the Graph .default audience on this app registration", "Confirm the certificate thumbprint or federated credential mapping on the app registration"]); }
|
|
47
|
+
}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { validateDelegatedProfile } from "./profiles.js";
|
|
3
|
+
// This service is the credential boundary for CORE-01; tokens never reach CLI output.
|
|
4
|
+
export class DelegatedAuth {
|
|
5
|
+
provider;
|
|
6
|
+
now;
|
|
7
|
+
cache = new Map();
|
|
8
|
+
constructor(provider, now = Date.now) {
|
|
9
|
+
this.provider = provider;
|
|
10
|
+
this.now = now;
|
|
11
|
+
}
|
|
12
|
+
async login(profile, method = "browser", scopes = []) {
|
|
13
|
+
profile = validateDelegatedProfile(profile);
|
|
14
|
+
if (method !== "browser" && method !== "device-code")
|
|
15
|
+
throw new AxiError("Login method must be browser or device-code", "VALIDATION_ERROR", ["mg-axi login --help"]);
|
|
16
|
+
if (method === "device-code" && !profile.allowDeviceCode)
|
|
17
|
+
throw new AxiError("Device code is disabled for this profile", "VALIDATION_ERROR", ["Enable device code only when organization policy permits it; browser login is the default"]);
|
|
18
|
+
const requested = this.scopes(scopes);
|
|
19
|
+
const key = this.key(profile, requested);
|
|
20
|
+
this.cache.clear();
|
|
21
|
+
try {
|
|
22
|
+
const credential = this.check(profile, await this.provider.login(profile, method, requested));
|
|
23
|
+
this.cache.set(key, credential);
|
|
24
|
+
return { status: "authenticated", mode: "delegated", storage: this.provider.storage };
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
throw this.failure("LOGIN_FAILED");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async credential(profile, scopes) {
|
|
31
|
+
profile = validateDelegatedProfile(profile);
|
|
32
|
+
const requested = this.scopes(scopes);
|
|
33
|
+
const key = this.key(profile, requested);
|
|
34
|
+
const hit = this.cache.get(key);
|
|
35
|
+
if (hit && hit.expiresAt > this.now() + 60_000)
|
|
36
|
+
return { ...hit };
|
|
37
|
+
this.cache.delete(key);
|
|
38
|
+
try {
|
|
39
|
+
const credential = this.check(profile, await this.provider.silent(profile, requested));
|
|
40
|
+
this.cache.set(key, credential);
|
|
41
|
+
return { ...credential };
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
throw this.failure("AUTH_REQUIRED");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
scopes(scopes) {
|
|
48
|
+
if (!scopes.length || scopes.some(scope => !/^https:\/\/graph\.microsoft\.com\/[A-Za-z][A-Za-z.-]+$/.test(scope) || scope.endsWith("/.default")))
|
|
49
|
+
throw new AxiError("Explicit delegated Graph scopes are required", "VALIDATION_ERROR", ["mg-axi login --profile <name> --scopes <comma-separated-Graph-scopes>"]);
|
|
50
|
+
return [...new Set(scopes)].sort();
|
|
51
|
+
}
|
|
52
|
+
key(profile, scopes) { return JSON.stringify([profile.credentialRef, profile.tenantId, profile.clientId, profile.cloud, scopes]); }
|
|
53
|
+
check(profile, credential) {
|
|
54
|
+
if (!credential.token || !credential.accountId || credential.tenantId.toLowerCase() !== profile.tenantId.toLowerCase() || credential.clientId.toLowerCase() !== profile.clientId.toLowerCase() || !Number.isFinite(credential.expiresAt) || credential.expiresAt <= this.now() + 60_000)
|
|
55
|
+
throw new Error("Invalid credential context");
|
|
56
|
+
return { ...credential };
|
|
57
|
+
}
|
|
58
|
+
failure(code) { return new AxiError("Authentication unavailable for the configured identity; no interactive fallback was attempted", code, ["mg-axi login --profile <name> --scopes <comma-separated-Graph-scopes>", "Check dedicated app consent and organization sign-in policy", "Restore OS credential store access before retrying login; prior stored accounts must be invalidated before replacement"]); }
|
|
59
|
+
}
|