diff --git a/package.json b/package.json index ecfe3a4..f4d09c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@slawek/sk-az-tools", - "version": "0.2.1", + "version": "0.3.0", "type": "module", "files": [ "dist", diff --git a/src/cli.ts b/src/cli.ts index 97d2009..3e66fca 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -14,6 +14,7 @@ import { type CliValues = { help?: boolean; + type?: string; "display-name"?: string; "app-id"?: string; resources?: string; @@ -37,6 +38,7 @@ function usage(): string { Commands: login Authenticate selected resources logout Sign out and clear login state + get-token Get access token (azurerm|devops) list-apps List Entra applications list-app-permissions List required permissions for an app list-app-grants List OAuth2 grants for an app @@ -79,6 +81,13 @@ Options: --all Clear login state and remove all cached accounts`; } +function usageGetToken(): string { + return `Usage: sk-az-tools get-token --type|-t [global options] + +Options: + -t, --type Token type: azurerm|devops`; +} + function usageListAppPermissions(): string { return `Usage: sk-az-tools list-app-permissions --app-id|-i [--resolve|-r] [--short|-s] [--filter|-f ] [global options] @@ -120,6 +129,8 @@ function usageCommand(command: string): string { return usageListApps(); case "logout": return usageLogout(); + case "get-token": + return usageGetToken(); case "list-app-permissions": return usageListAppPermissions(); case "list-app-grants": @@ -150,6 +161,7 @@ async function main(): Promise { args: argv.slice(1), options: { help: { type: "boolean", short: "h" }, + type: { type: "string", short: "t" }, "display-name": { type: "string", short: "n" }, "app-id": { type: "string", short: "i" }, resources: { type: "string" }, diff --git a/src/cli/commands.ts b/src/cli/commands.ts index 16fcf5b..64d570f 100644 --- a/src/cli/commands.ts +++ b/src/cli/commands.ts @@ -4,7 +4,8 @@ import { minimatch } from "minimatch"; import { loadPublicConfig } from "../index.ts"; import { getGraphClient } from "../graph/auth.ts"; -import { login, logout } from "../azure/index.ts"; +import { acquireResourceTokenFromLogin, login, logout } from "../azure/index.ts"; +import { getDevOpsApiToken } from "../devops/index.ts"; import { listApps, listAppPermissions, @@ -16,6 +17,7 @@ import { readJsonFromStdin } from "./utils.ts"; type CommandValues = { [key: string]: string | boolean | undefined; + type?: string; resources?: string; "use-device-code"?: boolean; "no-browser"?: boolean; @@ -142,6 +144,49 @@ async function runListResourcePermissionsCommand(values: CommandValues): Promise return result; } +async function runGetTokenCommand(values: CommandValues): Promise { + const tokenType = (values.type ?? "").toString().trim().toLowerCase(); + if (!tokenType) { + throw new Error("--type is required for get-token (allowed: azurerm, devops)"); + } + + const config = await loadPublicConfig(); + if (!config.tenantId) { + throw new Error("tenantId is required"); + } + if (!config.clientId) { + throw new Error("clientId is required"); + } + + if (tokenType === "azurerm") { + const result = await acquireResourceTokenFromLogin({ + tenantId: config.tenantId, + clientId: config.clientId, + resource: "arm", + }); + + const accessToken = result?.accessToken; + if (!accessToken) { + throw new Error("Failed to obtain AzureRM token"); + } + + return { + tokenType, + accessToken, + }; + } + + if (tokenType === "devops") { + const accessToken = await getDevOpsApiToken(config.tenantId, config.clientId); + return { + tokenType, + accessToken, + }; + } + + throw new Error(`Invalid --type '${values.type}'. Allowed: azurerm, devops`); +} + export async function runCommand(command: string, values: CommandValues): Promise { switch (command) { case "login": @@ -158,6 +203,8 @@ export async function runCommand(command: string, values: CommandValues): Promis return runListAppGrantsCommand(values); case "list-resource-permissions": return runListResourcePermissionsCommand(values); + case "get-token": + return runGetTokenCommand(values); default: throw new Error(`Unknown command: ${command}`); }