azp-cli 1.2.0 → 1.3.1
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/CHANGELOG.md +11 -0
- package/README.md +110 -31
- package/package.json +15 -11
- package/src/auth.ts +13 -0
- package/src/index.ts +7 -10
- package/src/ui.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [1.3.1](https://github.com/tapanmeena/azp-cli/compare/v1.3.0...v1.3.1) (2026-01-14)
|
|
6
|
+
|
|
7
|
+
## [1.3.0](https://github.com/tapanmeena/azp-cli/compare/v1.2.0...v1.3.0) (2026-01-14)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* add Azure CLI installation check before authentication ([c291268](https://github.com/tapanmeena/azp-cli/commit/c291268359854e7da74a0cea046741c0449609d7))
|
|
13
|
+
* update package.json with repository type; rename CLI command to 'check-update' and adjust header formatting ([8ef92d4](https://github.com/tapanmeena/azp-cli/commit/8ef92d4da233459f7631f2bf4f85ed5a4113c918))
|
|
14
|
+
* update README with new features and installation instructions; refactor CLI command name to 'azp' ([24510f7](https://github.com/tapanmeena/azp-cli/commit/24510f78f44f9e1570d93c8b750aa6a41b27b62e))
|
|
15
|
+
|
|
5
16
|
## [1.2.0](https://github.com/tapanmeena/azp-cli/compare/v1.1.0...v1.2.0) (2026-01-13)
|
|
6
17
|
|
|
7
18
|
|
package/README.md
CHANGED
|
@@ -14,6 +14,10 @@ A command-line interface tool for managing Azure Privileged Identity Management
|
|
|
14
14
|
- ✨ **Beautiful UI** - Polished terminal experience with spinners and colors
|
|
15
15
|
- 🔄 **Multi-role Support** - Activate or deactivate multiple roles at once
|
|
16
16
|
- 📊 **Status Tracking** - Real-time feedback on activation/deactivation status
|
|
17
|
+
- 💾 **Presets** - Save and reuse activation/deactivation configurations
|
|
18
|
+
- 🚀 **Non-interactive Mode** - CLI flags for scripting and automation
|
|
19
|
+
- 🔔 **Update Notifications** - Automatic update checks with configurable behavior
|
|
20
|
+
- 📤 **JSON Output** - Machine-readable output for integration with other tools
|
|
17
21
|
|
|
18
22
|
## Prerequisites
|
|
19
23
|
|
|
@@ -38,7 +42,22 @@ az account show
|
|
|
38
42
|
|
|
39
43
|
## Installation
|
|
40
44
|
|
|
41
|
-
###
|
|
45
|
+
### Global Installation (Recommended)
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Using npm
|
|
49
|
+
npm install -g azp-cli
|
|
50
|
+
|
|
51
|
+
# Using pnpm
|
|
52
|
+
pnpm add -g azp-cli
|
|
53
|
+
|
|
54
|
+
# Using yarn
|
|
55
|
+
yarn global add azp-cli
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
After installation, the `azp` command will be available globally.
|
|
59
|
+
|
|
60
|
+
### From Source (Development)
|
|
42
61
|
|
|
43
62
|
```bash
|
|
44
63
|
# Clone the repository
|
|
@@ -47,13 +66,12 @@ cd azp-cli
|
|
|
47
66
|
|
|
48
67
|
# Install dependencies
|
|
49
68
|
pnpm install
|
|
50
|
-
# or
|
|
51
|
-
npm install
|
|
52
69
|
|
|
53
70
|
# Build the project
|
|
54
71
|
pnpm build
|
|
55
|
-
|
|
56
|
-
|
|
72
|
+
|
|
73
|
+
# Link globally for development
|
|
74
|
+
npm link
|
|
57
75
|
```
|
|
58
76
|
|
|
59
77
|
## Usage
|
|
@@ -61,24 +79,38 @@ npm run build
|
|
|
61
79
|
### Running the CLI
|
|
62
80
|
|
|
63
81
|
```bash
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
82
|
+
# After global installation
|
|
83
|
+
azp
|
|
84
|
+
|
|
85
|
+
# Or with specific commands
|
|
86
|
+
azp activate
|
|
87
|
+
azp deactivate
|
|
88
|
+
azp preset list
|
|
89
|
+
azp update
|
|
68
90
|
|
|
69
|
-
#
|
|
70
|
-
|
|
91
|
+
# Development mode (from source)
|
|
92
|
+
pnpm dev
|
|
71
93
|
```
|
|
72
94
|
|
|
73
95
|
### Commands
|
|
74
96
|
|
|
75
|
-
| Command | Alias
|
|
76
|
-
| ------------ |
|
|
77
|
-
| `activate` | `a`
|
|
78
|
-
| `deactivate` | `d`
|
|
79
|
-
| `
|
|
80
|
-
| `
|
|
81
|
-
| `help` | -
|
|
97
|
+
| Command | Alias | Description |
|
|
98
|
+
| ------------ | --------- | -------------------------------------- |
|
|
99
|
+
| `activate` | `a` | Activate a role in Azure PIM (default) |
|
|
100
|
+
| `deactivate` | `d` | Deactivate a role in Azure PIM |
|
|
101
|
+
| `preset` | - | Manage reusable presets |
|
|
102
|
+
| `update` | `upgrade` | Check for a newer version |
|
|
103
|
+
| `help` | - | Display help information |
|
|
104
|
+
|
|
105
|
+
#### Preset Subcommands
|
|
106
|
+
|
|
107
|
+
| Command | Description |
|
|
108
|
+
| --------------- | -------------------------------------------- |
|
|
109
|
+
| `preset list` | List all available presets |
|
|
110
|
+
| `preset show` | Show details of a specific preset |
|
|
111
|
+
| `preset add` | Add a new preset (interactive wizard) |
|
|
112
|
+
| `preset edit` | Edit an existing preset (interactive wizard) |
|
|
113
|
+
| `preset remove` | Remove a preset |
|
|
82
114
|
|
|
83
115
|
### Updates
|
|
84
116
|
|
|
@@ -102,9 +134,11 @@ The update-check cache is stored alongside presets in your config directory:
|
|
|
102
134
|
- macOS/Linux: `~/.config/azp-cli/update-check.json` (or `$XDG_CONFIG_HOME/azp-cli/update-check.json`)
|
|
103
135
|
- Windows: `%APPDATA%\azp-cli\update-check.json`
|
|
104
136
|
|
|
105
|
-
###
|
|
137
|
+
### Non-interactive Mode (Automation)
|
|
106
138
|
|
|
107
|
-
Use flags to activate PIM roles directly without going through the
|
|
139
|
+
Use flags to activate or deactivate PIM roles directly without going through the interactive menu, perfect for scripting and CI/CD workflows.
|
|
140
|
+
|
|
141
|
+
#### Activation Examples
|
|
108
142
|
|
|
109
143
|
```bash
|
|
110
144
|
# Activate a single role by name (non-interactive)
|
|
@@ -135,6 +169,43 @@ azp activate --no-interactive --dry-run \
|
|
|
135
169
|
--output json
|
|
136
170
|
```
|
|
137
171
|
|
|
172
|
+
#### Deactivation Examples
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# Deactivate specific roles
|
|
176
|
+
azp deactivate --no-interactive --yes \
|
|
177
|
+
--subscription-id <SUBSCRIPTION_GUID> \
|
|
178
|
+
--role-name "Owner" \
|
|
179
|
+
--justification "Task completed"
|
|
180
|
+
|
|
181
|
+
# Deactivate across all subscriptions (omit subscription-id)
|
|
182
|
+
azp deactivate --no-interactive --yes \
|
|
183
|
+
--role-name "Contributor" \
|
|
184
|
+
--allow-multiple
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### Available Flags
|
|
188
|
+
|
|
189
|
+
**Common flags (activate/deactivate):**
|
|
190
|
+
|
|
191
|
+
- `--no-interactive` - Disable interactive prompts
|
|
192
|
+
- `-y, --yes` - Skip confirmation prompts
|
|
193
|
+
- `--subscription-id <id>` - Target subscription (optional for deactivate)
|
|
194
|
+
- `--role-name <name>` - Role name(s) to target (can be repeated)
|
|
195
|
+
- `--allow-multiple` - Allow multiple role matches
|
|
196
|
+
- `--dry-run` - Preview without submitting
|
|
197
|
+
- `--output <text|json>` - Output format (default: text)
|
|
198
|
+
- `--quiet` - Suppress non-essential output
|
|
199
|
+
|
|
200
|
+
**Activation-specific:**
|
|
201
|
+
|
|
202
|
+
- `--duration-hours <n>` - Duration (1-8 hours, default varies by role)
|
|
203
|
+
- `--justification <text>` - Justification for activation
|
|
204
|
+
|
|
205
|
+
**Deactivation-specific:**
|
|
206
|
+
|
|
207
|
+
- `--justification <text>` - Justification for deactivation (optional)
|
|
208
|
+
|
|
138
209
|
## Presets
|
|
139
210
|
|
|
140
211
|
Presets let you save your daily activation/deactivation routines (subscription + role names + duration + justification) and reuse them with `--preset <name>`.
|
|
@@ -163,24 +234,27 @@ A preset can define one or both blocks:
|
|
|
163
234
|
- `${datetime}` → ISO timestamp
|
|
164
235
|
- `${userPrincipalName}` → resolved from Microsoft Graph `/me`
|
|
165
236
|
|
|
166
|
-
### Common
|
|
237
|
+
### Common Workflows
|
|
167
238
|
|
|
168
239
|
```bash
|
|
169
240
|
# Create a preset (interactive wizard)
|
|
170
241
|
azp preset add daily-ops
|
|
171
242
|
|
|
243
|
+
# Create a preset with Azure integration (fetches subscriptions/roles)
|
|
244
|
+
azp preset add daily-ops --from-azure
|
|
245
|
+
|
|
172
246
|
# Edit a preset (interactive wizard)
|
|
173
247
|
azp preset edit daily-ops
|
|
174
248
|
|
|
175
|
-
#
|
|
176
|
-
azp preset add daily-ops
|
|
177
|
-
|
|
178
|
-
# List presets
|
|
249
|
+
# List all presets
|
|
179
250
|
azp preset list
|
|
180
251
|
|
|
181
|
-
# Show one preset
|
|
252
|
+
# Show one preset details
|
|
182
253
|
azp preset show daily-ops
|
|
183
254
|
|
|
255
|
+
# Remove a preset
|
|
256
|
+
azp preset remove daily-ops
|
|
257
|
+
|
|
184
258
|
# Use a preset (flags still override preset values)
|
|
185
259
|
azp activate --preset daily-ops --yes
|
|
186
260
|
|
|
@@ -293,6 +367,8 @@ git push --follow-tags
|
|
|
293
367
|
4. Publish to npm (if desired):
|
|
294
368
|
|
|
295
369
|
```bash
|
|
370
|
+
npm publish
|
|
371
|
+
# or
|
|
296
372
|
pnpm publish
|
|
297
373
|
```
|
|
298
374
|
|
|
@@ -301,11 +377,14 @@ pnpm publish
|
|
|
301
377
|
```
|
|
302
378
|
azp-cli/
|
|
303
379
|
├── src/
|
|
304
|
-
│ ├── index.ts
|
|
305
|
-
│ ├── auth.ts
|
|
306
|
-
│ ├── azure-pim.ts
|
|
307
|
-
│ ├── cli.ts
|
|
308
|
-
│
|
|
380
|
+
│ ├── index.ts # CLI entry point and command definitions
|
|
381
|
+
│ ├── auth.ts # Azure authentication handling
|
|
382
|
+
│ ├── azure-pim.ts # Azure PIM API operations
|
|
383
|
+
│ ├── cli.ts # Interactive menu and user flows
|
|
384
|
+
│ ├── presets.ts # Preset configuration and storage
|
|
385
|
+
│ ├── presets-cli.ts # Preset wizard flows
|
|
386
|
+
│ ├── ui.ts # Terminal UI utilities (spinners, formatting)
|
|
387
|
+
│ └── update-check.ts # Update notification system
|
|
309
388
|
├── package.json
|
|
310
389
|
├── tsconfig.json
|
|
311
390
|
└── README.md
|
package/package.json
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azp-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Terminal app to manage Azure PIM role activations",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"azp": "./dist/index.js"
|
|
8
8
|
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"build": "tsc",
|
|
11
|
-
"start": "node dist/index.js",
|
|
12
|
-
"dev": "ts-node -r tsconfig-paths/register src/index.ts",
|
|
13
|
-
"lint": "tsc -p tsconfig.json --noEmit",
|
|
14
|
-
"release": "standard-version",
|
|
15
|
-
"release:dry": "standard-version --dry-run"
|
|
16
|
-
},
|
|
17
9
|
"keywords": [
|
|
18
10
|
"azure",
|
|
19
11
|
"pim",
|
|
@@ -25,8 +17,12 @@
|
|
|
25
17
|
"name": "Tapan Meena",
|
|
26
18
|
"email": "tapanmeena1998@gmail.com"
|
|
27
19
|
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/tapanmeena/azp-cli.git"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/tapanmeena/azp-cli#readme",
|
|
28
25
|
"license": "ISC",
|
|
29
|
-
"packageManager": "pnpm@10.28.0",
|
|
30
26
|
"dependencies": {
|
|
31
27
|
"@azure/arm-authorization": "^9.0.0",
|
|
32
28
|
"@azure/arm-resources-subscriptions": "^2.1.0",
|
|
@@ -47,5 +43,13 @@
|
|
|
47
43
|
"ts-node": "^10.9.2",
|
|
48
44
|
"tsconfig-paths": "^4.2.0",
|
|
49
45
|
"typescript": "^5.9.3"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc",
|
|
49
|
+
"start": "node dist/index.js",
|
|
50
|
+
"dev": "ts-node -r tsconfig-paths/register src/index.ts",
|
|
51
|
+
"lint": "tsc -p tsconfig.json --noEmit",
|
|
52
|
+
"release": "standard-version",
|
|
53
|
+
"release:dry": "standard-version --dry-run"
|
|
50
54
|
}
|
|
51
|
-
}
|
|
55
|
+
}
|
package/src/auth.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { exec } from "child_process";
|
|
2
|
+
import { promisify } from "util";
|
|
1
3
|
import { AzureCliCredential } from "@azure/identity";
|
|
2
4
|
import { Client } from "@microsoft/microsoft-graph-client";
|
|
3
5
|
import { TokenCredentialAuthenticationProvider } from "@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials";
|
|
@@ -23,7 +25,18 @@ const getCredential = (): AzureCliCredential => {
|
|
|
23
25
|
return cachedCredential;
|
|
24
26
|
};
|
|
25
27
|
|
|
28
|
+
const execAsync = promisify(exec);
|
|
29
|
+
|
|
30
|
+
const checkAzureCliInstalled = async (): Promise<void> => {
|
|
31
|
+
try {
|
|
32
|
+
await execAsync("az --version");
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new Error("Azure CLI is not installed or not in PATH. Please install it to use this tool.");
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
26
38
|
export const authenticate = async (): Promise<AuthContext> => {
|
|
39
|
+
await checkAzureCliInstalled();
|
|
27
40
|
startSpinner("Authenticating with Azure CLI...");
|
|
28
41
|
|
|
29
42
|
try {
|
package/src/index.ts
CHANGED
|
@@ -5,7 +5,6 @@ import inquirer from "inquirer";
|
|
|
5
5
|
import { name as npmPackageName, version } from "../package.json";
|
|
6
6
|
import { authenticate } from "./auth";
|
|
7
7
|
import { activateOnce, deactivateOnce, showMainMenu } from "./cli";
|
|
8
|
-
import { runPresetAddWizard, runPresetEditWizard } from "./presets-cli";
|
|
9
8
|
import {
|
|
10
9
|
expandTemplate,
|
|
11
10
|
getDefaultPresetsFilePath,
|
|
@@ -13,12 +12,13 @@ import {
|
|
|
13
12
|
listPresetNames,
|
|
14
13
|
loadPresets,
|
|
15
14
|
removePreset,
|
|
16
|
-
savePresets,
|
|
17
15
|
resolveActivatePresetOptions,
|
|
18
16
|
resolveDeactivatePresetOptions,
|
|
17
|
+
savePresets,
|
|
19
18
|
setDefaultPresetName,
|
|
20
19
|
upsertPreset,
|
|
21
20
|
} from "./presets";
|
|
21
|
+
import { runPresetAddWizard, runPresetEditWizard } from "./presets-cli";
|
|
22
22
|
import { configureUi, logBlank, logDim, logError, logInfo, logSuccess, logWarning, showHeader } from "./ui";
|
|
23
23
|
import { checkForUpdate } from "./update-check";
|
|
24
24
|
|
|
@@ -98,7 +98,7 @@ const resolveValue = <T>(command: Command, optionName: string, cliValue: T, pres
|
|
|
98
98
|
|
|
99
99
|
const program = new Command();
|
|
100
100
|
|
|
101
|
-
program.name("azp
|
|
101
|
+
program.name("azp").description("Azure PIM CLI - A CLI tool for Azure Privilege Identity Management (PIM)").version(version);
|
|
102
102
|
|
|
103
103
|
program
|
|
104
104
|
.command("activate", { isDefault: true })
|
|
@@ -153,8 +153,7 @@ program
|
|
|
153
153
|
const hasSubscriptionFromCli = getOptionValueSource(command, "subscriptionId") === "cli";
|
|
154
154
|
|
|
155
155
|
const defaultPresetName = presets.data.defaults?.activatePreset;
|
|
156
|
-
const shouldUseDefaultPreset =
|
|
157
|
-
!explicitPresetName && Boolean(defaultPresetName) && (!hasSubscriptionFromCli || !hasRoleNamesFromCli);
|
|
156
|
+
const shouldUseDefaultPreset = !explicitPresetName && Boolean(defaultPresetName) && (!hasSubscriptionFromCli || !hasRoleNamesFromCli);
|
|
158
157
|
|
|
159
158
|
const presetNameToUse = explicitPresetName ?? (shouldUseDefaultPreset ? defaultPresetName : undefined);
|
|
160
159
|
|
|
@@ -349,9 +348,9 @@ program
|
|
|
349
348
|
});
|
|
350
349
|
|
|
351
350
|
program
|
|
352
|
-
.command("update")
|
|
351
|
+
.command("check-update")
|
|
353
352
|
.description("Check if a newer azp-cli version is available")
|
|
354
|
-
.alias("
|
|
353
|
+
.alias("update")
|
|
355
354
|
.option("--check-only", "Only check and print status (no upgrade instructions)")
|
|
356
355
|
.option("--output <text|json>", "Output format", "text")
|
|
357
356
|
.option("--quiet", "Suppress non-essential output (recommended with --output json)")
|
|
@@ -525,9 +524,7 @@ presetCommand
|
|
|
525
524
|
const entry = getPreset(loaded.data, name);
|
|
526
525
|
if (!entry) {
|
|
527
526
|
const names = listPresetNames(loaded.data);
|
|
528
|
-
throw new Error(
|
|
529
|
-
`Preset not found: "${name}". Presets file: ${loaded.filePath}. Available: ${names.length ? names.join(", ") : "(none)"}`
|
|
530
|
-
);
|
|
527
|
+
throw new Error(`Preset not found: "${name}". Presets file: ${loaded.filePath}. Available: ${names.length ? names.join(", ") : "(none)"}`);
|
|
531
528
|
}
|
|
532
529
|
|
|
533
530
|
if (output === "json") {
|