bt-cli 0.4.7__py3-none-any.whl

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.
Files changed (121) hide show
  1. bt_cli/__init__.py +3 -0
  2. bt_cli/cli.py +830 -0
  3. bt_cli/commands/__init__.py +1 -0
  4. bt_cli/commands/configure.py +415 -0
  5. bt_cli/commands/learn.py +229 -0
  6. bt_cli/commands/quick.py +784 -0
  7. bt_cli/core/__init__.py +1 -0
  8. bt_cli/core/auth.py +213 -0
  9. bt_cli/core/client.py +313 -0
  10. bt_cli/core/config.py +393 -0
  11. bt_cli/core/config_file.py +420 -0
  12. bt_cli/core/csv_utils.py +91 -0
  13. bt_cli/core/errors.py +247 -0
  14. bt_cli/core/output.py +205 -0
  15. bt_cli/core/prompts.py +87 -0
  16. bt_cli/core/rest_debug.py +221 -0
  17. bt_cli/data/CLAUDE.md +88 -0
  18. bt_cli/data/__init__.py +0 -0
  19. bt_cli/data/skills/bt/SKILL.md +98 -0
  20. bt_cli/data/skills/entitle/SKILL.md +159 -0
  21. bt_cli/data/skills/epmw/SKILL.md +145 -0
  22. bt_cli/data/skills/pra/SKILL.md +149 -0
  23. bt_cli/data/skills/pws/SKILL.md +197 -0
  24. bt_cli/entitle/__init__.py +1 -0
  25. bt_cli/entitle/client/__init__.py +5 -0
  26. bt_cli/entitle/client/base.py +443 -0
  27. bt_cli/entitle/commands/__init__.py +24 -0
  28. bt_cli/entitle/commands/accounts.py +53 -0
  29. bt_cli/entitle/commands/applications.py +39 -0
  30. bt_cli/entitle/commands/auth.py +68 -0
  31. bt_cli/entitle/commands/bundles.py +218 -0
  32. bt_cli/entitle/commands/integrations.py +60 -0
  33. bt_cli/entitle/commands/permissions.py +70 -0
  34. bt_cli/entitle/commands/policies.py +97 -0
  35. bt_cli/entitle/commands/resources.py +131 -0
  36. bt_cli/entitle/commands/roles.py +74 -0
  37. bt_cli/entitle/commands/users.py +123 -0
  38. bt_cli/entitle/commands/workflows.py +187 -0
  39. bt_cli/entitle/models/__init__.py +31 -0
  40. bt_cli/entitle/models/bundle.py +28 -0
  41. bt_cli/entitle/models/common.py +37 -0
  42. bt_cli/entitle/models/integration.py +30 -0
  43. bt_cli/entitle/models/permission.py +27 -0
  44. bt_cli/entitle/models/policy.py +25 -0
  45. bt_cli/entitle/models/resource.py +29 -0
  46. bt_cli/entitle/models/role.py +28 -0
  47. bt_cli/entitle/models/user.py +24 -0
  48. bt_cli/entitle/models/workflow.py +55 -0
  49. bt_cli/epmw/__init__.py +1 -0
  50. bt_cli/epmw/client/__init__.py +5 -0
  51. bt_cli/epmw/client/base.py +848 -0
  52. bt_cli/epmw/commands/__init__.py +33 -0
  53. bt_cli/epmw/commands/audits.py +250 -0
  54. bt_cli/epmw/commands/auth.py +55 -0
  55. bt_cli/epmw/commands/computers.py +140 -0
  56. bt_cli/epmw/commands/events.py +233 -0
  57. bt_cli/epmw/commands/groups.py +215 -0
  58. bt_cli/epmw/commands/policies.py +673 -0
  59. bt_cli/epmw/commands/quick.py +348 -0
  60. bt_cli/epmw/commands/requests.py +224 -0
  61. bt_cli/epmw/commands/roles.py +78 -0
  62. bt_cli/epmw/commands/tasks.py +38 -0
  63. bt_cli/epmw/commands/users.py +219 -0
  64. bt_cli/epmw/models/__init__.py +1 -0
  65. bt_cli/pra/__init__.py +1 -0
  66. bt_cli/pra/client/__init__.py +5 -0
  67. bt_cli/pra/client/base.py +618 -0
  68. bt_cli/pra/commands/__init__.py +30 -0
  69. bt_cli/pra/commands/auth.py +55 -0
  70. bt_cli/pra/commands/import_export.py +442 -0
  71. bt_cli/pra/commands/jump_clients.py +139 -0
  72. bt_cli/pra/commands/jump_groups.py +146 -0
  73. bt_cli/pra/commands/jump_items.py +638 -0
  74. bt_cli/pra/commands/jumpoints.py +95 -0
  75. bt_cli/pra/commands/policies.py +197 -0
  76. bt_cli/pra/commands/quick.py +470 -0
  77. bt_cli/pra/commands/teams.py +81 -0
  78. bt_cli/pra/commands/users.py +87 -0
  79. bt_cli/pra/commands/vault.py +564 -0
  80. bt_cli/pra/models/__init__.py +27 -0
  81. bt_cli/pra/models/common.py +12 -0
  82. bt_cli/pra/models/jump_client.py +25 -0
  83. bt_cli/pra/models/jump_group.py +15 -0
  84. bt_cli/pra/models/jump_item.py +72 -0
  85. bt_cli/pra/models/jumpoint.py +19 -0
  86. bt_cli/pra/models/team.py +14 -0
  87. bt_cli/pra/models/user.py +17 -0
  88. bt_cli/pra/models/vault.py +45 -0
  89. bt_cli/pws/__init__.py +1 -0
  90. bt_cli/pws/client/__init__.py +5 -0
  91. bt_cli/pws/client/base.py +356 -0
  92. bt_cli/pws/client/beyondinsight.py +869 -0
  93. bt_cli/pws/client/passwordsafe.py +1786 -0
  94. bt_cli/pws/commands/__init__.py +33 -0
  95. bt_cli/pws/commands/accounts.py +372 -0
  96. bt_cli/pws/commands/assets.py +311 -0
  97. bt_cli/pws/commands/auth.py +166 -0
  98. bt_cli/pws/commands/clouds.py +221 -0
  99. bt_cli/pws/commands/config.py +344 -0
  100. bt_cli/pws/commands/credentials.py +347 -0
  101. bt_cli/pws/commands/databases.py +306 -0
  102. bt_cli/pws/commands/directories.py +199 -0
  103. bt_cli/pws/commands/functional.py +298 -0
  104. bt_cli/pws/commands/import_export.py +452 -0
  105. bt_cli/pws/commands/platforms.py +118 -0
  106. bt_cli/pws/commands/quick.py +1646 -0
  107. bt_cli/pws/commands/search.py +256 -0
  108. bt_cli/pws/commands/secrets.py +1343 -0
  109. bt_cli/pws/commands/systems.py +389 -0
  110. bt_cli/pws/commands/users.py +415 -0
  111. bt_cli/pws/commands/workgroups.py +166 -0
  112. bt_cli/pws/config.py +18 -0
  113. bt_cli/pws/models/__init__.py +19 -0
  114. bt_cli/pws/models/account.py +186 -0
  115. bt_cli/pws/models/asset.py +102 -0
  116. bt_cli/pws/models/common.py +132 -0
  117. bt_cli/pws/models/system.py +121 -0
  118. bt_cli-0.4.7.dist-info/METADATA +172 -0
  119. bt_cli-0.4.7.dist-info/RECORD +121 -0
  120. bt_cli-0.4.7.dist-info/WHEEL +4 -0
  121. bt_cli-0.4.7.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,221 @@
1
+ """REST API debugging module for bt-cli.
2
+
3
+ Provides httpx event hooks to display API call details when --show-rest is enabled.
4
+ """
5
+
6
+ import json
7
+ import re
8
+ from typing import Any, Dict
9
+
10
+ import httpx
11
+ from rich.console import Console
12
+ from rich.panel import Panel
13
+ from rich.syntax import Syntax
14
+
15
+ # Global flag for REST debugging
16
+ _show_rest = False
17
+
18
+ # Console for output
19
+ _console = Console(stderr=True)
20
+
21
+
22
+ def set_show_rest(enabled: bool) -> None:
23
+ """Enable or disable REST API call display."""
24
+ global _show_rest
25
+ _show_rest = enabled
26
+
27
+
28
+ def is_show_rest() -> bool:
29
+ """Check if REST debugging is enabled."""
30
+ return _show_rest
31
+
32
+
33
+ def _sanitize_headers(headers: httpx.Headers) -> Dict[str, str]:
34
+ """Sanitize headers by fully redacting sensitive values.
35
+
36
+ Security: Never show any part of sensitive values like tokens or API keys.
37
+ """
38
+ sanitized = {}
39
+ sensitive_patterns = [
40
+ r"authorization",
41
+ r"ps-auth",
42
+ r"x-api-key",
43
+ r"api-key",
44
+ r"secret",
45
+ r"token",
46
+ r"password",
47
+ r"bearer",
48
+ ]
49
+
50
+ for key, value in headers.items():
51
+ key_lower = key.lower()
52
+ is_sensitive = any(re.search(p, key_lower) for p in sensitive_patterns)
53
+
54
+ if is_sensitive and value:
55
+ # Fully redact sensitive values - never show any characters
56
+ sanitized[key] = "[REDACTED]"
57
+ else:
58
+ sanitized[key] = value
59
+
60
+ return sanitized
61
+
62
+
63
+ def _sanitize_body(body: Any) -> Any:
64
+ """Sanitize request/response body by redacting sensitive fields.
65
+
66
+ Security: Redact credentials in form data and JSON bodies.
67
+ """
68
+ if body is None:
69
+ return None
70
+
71
+ # Sensitive field names (case-insensitive matching)
72
+ sensitive_fields = {
73
+ "password", "secret", "token", "api_key", "apikey", "api-key",
74
+ "client_secret", "client-secret", "clientsecret",
75
+ "authorization", "bearer", "credential", "credentials",
76
+ "access_token", "refresh_token", "id_token",
77
+ }
78
+
79
+ if isinstance(body, dict):
80
+ sanitized = {}
81
+ for key, value in body.items():
82
+ key_lower = key.lower().replace("-", "_")
83
+ if any(s in key_lower for s in sensitive_fields):
84
+ sanitized[key] = "[REDACTED]"
85
+ elif isinstance(value, (dict, list)):
86
+ sanitized[key] = _sanitize_body(value)
87
+ else:
88
+ sanitized[key] = value
89
+ return sanitized
90
+ elif isinstance(body, list):
91
+ return [_sanitize_body(item) for item in body]
92
+ else:
93
+ return body
94
+
95
+
96
+ def _truncate_body(body: Any, max_length: int = 500, sanitize: bool = True) -> str:
97
+ """Truncate body for display.
98
+
99
+ Args:
100
+ body: Request/response body
101
+ max_length: Maximum characters to display
102
+ sanitize: If True, redact sensitive fields before display
103
+ """
104
+ if body is None:
105
+ return "(empty)"
106
+
107
+ if isinstance(body, bytes):
108
+ try:
109
+ body = body.decode("utf-8")
110
+ except UnicodeDecodeError:
111
+ return f"(binary data, {len(body)} bytes)"
112
+
113
+ # Sanitize sensitive data before display
114
+ if sanitize and isinstance(body, (dict, list)):
115
+ body = _sanitize_body(body)
116
+
117
+ if isinstance(body, (dict, list)):
118
+ body = json.dumps(body, indent=2)
119
+
120
+ body_str = str(body)
121
+ if len(body_str) > max_length:
122
+ return body_str[:max_length] + f"\n... ({len(body_str) - max_length} more chars)"
123
+ return body_str
124
+
125
+
126
+ def log_request(request: httpx.Request) -> None:
127
+ """Log outgoing HTTP request."""
128
+ if not _show_rest:
129
+ return
130
+
131
+ # Build request info
132
+ method = request.method
133
+ url = str(request.url)
134
+ headers = _sanitize_headers(request.headers)
135
+
136
+ # Get request body if present
137
+ body = None
138
+ if request.content:
139
+ try:
140
+ body = json.loads(request.content)
141
+ except (json.JSONDecodeError, UnicodeDecodeError):
142
+ body = request.content
143
+
144
+ # Build output
145
+ lines = [
146
+ f"[bold cyan]{method}[/bold cyan] [white]{url}[/white]",
147
+ "",
148
+ "[dim]Headers:[/dim]",
149
+ ]
150
+
151
+ for key, value in headers.items():
152
+ lines.append(f" [green]{key}:[/green] {value}")
153
+
154
+ if body:
155
+ lines.append("")
156
+ lines.append("[dim]Body:[/dim]")
157
+ body_str = _truncate_body(body, max_length=300)
158
+ lines.append(f" {body_str}")
159
+
160
+ _console.print(Panel(
161
+ "\n".join(lines),
162
+ title="[bold yellow]REST Request[/bold yellow]",
163
+ border_style="yellow",
164
+ expand=False,
165
+ ))
166
+
167
+
168
+ def log_response(response: httpx.Response) -> None:
169
+ """Log HTTP response."""
170
+ if not _show_rest:
171
+ return
172
+
173
+ # Get status info
174
+ status_code = response.status_code
175
+ status_text = response.reason_phrase or ""
176
+
177
+ # Color based on status
178
+ if status_code < 300:
179
+ status_color = "green"
180
+ elif status_code < 400:
181
+ status_color = "yellow"
182
+ else:
183
+ status_color = "red"
184
+
185
+ # Get response body
186
+ try:
187
+ # Need to read the response to get body
188
+ response.read()
189
+ body = response.json()
190
+ except (json.JSONDecodeError, UnicodeDecodeError):
191
+ body = response.text if response.text else "(empty)"
192
+ except Exception:
193
+ body = "(could not read response)"
194
+
195
+ # Build output
196
+ lines = [
197
+ f"[bold {status_color}]{status_code} {status_text}[/bold {status_color}]",
198
+ "",
199
+ "[dim]Response Body:[/dim]",
200
+ _truncate_body(body, max_length=500),
201
+ ]
202
+
203
+ _console.print(Panel(
204
+ "\n".join(lines),
205
+ title="[bold blue]REST Response[/bold blue]",
206
+ border_style="blue",
207
+ expand=False,
208
+ ))
209
+ _console.print() # Add spacing between calls
210
+
211
+
212
+ def get_event_hooks() -> Dict[str, list]:
213
+ """Get httpx event hooks for request/response logging.
214
+
215
+ Usage:
216
+ client = httpx.Client(event_hooks=get_event_hooks())
217
+ """
218
+ return {
219
+ "request": [log_request],
220
+ "response": [log_response],
221
+ }
bt_cli/data/CLAUDE.md ADDED
@@ -0,0 +1,88 @@
1
+ # BT-Admin CLI
2
+
3
+ BeyondTrust Platform CLI for Password Safe, Entitle, PRA, and EPM Windows.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ cd /home/admin/entitl-sko/bt-cli
9
+ source .venv/bin/activate && source .env
10
+ bt whoami # Test all connections
11
+ ```
12
+
13
+ ## Skills Available
14
+
15
+ Use these slash commands for detailed product guidance:
16
+
17
+ | Skill | Purpose |
18
+ |-------|---------|
19
+ | `/bt` | Cross-product commands (PASM onboard/offboard/search) |
20
+ | `/pws` | Password Safe - credentials, systems, secrets |
21
+ | `/pra` | PRA - jump items, vault, SSH CA |
22
+ | `/entitle` | Entitle - JIT access, bundles, workflows |
23
+ | `/epmw` | EPM Windows - computers, policies, requests |
24
+
25
+ ## Command Structure
26
+
27
+ | Product | Command | Key Operations |
28
+ |---------|---------|----------------|
29
+ | Cross-product | `bt quick` | `pasm-onboard`, `pasm-offboard`, `pasm-search` |
30
+ | Password Safe | `bt pws` | `systems`, `accounts`, `credentials`, `secrets`, `quick` |
31
+ | PRA | `bt pra` | `jump-items`, `vault`, `jump-groups`, `quick` |
32
+ | Entitle | `bt entitle` | `integrations`, `resources`, `bundles`, `permissions` |
33
+ | EPM Windows | `bt epmw` | `computers`, `groups`, `policies`, `requests`, `quick` |
34
+
35
+ ## Common Patterns
36
+
37
+ ```bash
38
+ # All list commands support JSON output
39
+ bt pws systems list -o json
40
+ bt pra jump-items shell list -o json
41
+
42
+ # Quick commands combine multiple API calls
43
+ bt pws quick checkout -s "system" -a "account"
44
+ bt pws quick onboard -n "host" -i "10.0.1.50" -w 3
45
+
46
+ # Raw output for scripting
47
+ PASSWORD=$(bt pws quick checkout -s server -a admin --raw)
48
+ ```
49
+
50
+ ## API Quirks (Gotchas)
51
+
52
+ | Product | Pagination | Response Format |
53
+ |---------|------------|-----------------|
54
+ | PWS | `limit`/`offset` | `{"TotalCount": N, "Data": [...]}` |
55
+ | Entitle | `page`/`perPage` | `{"result": [...], "pagination": {...}}` |
56
+ | PRA | `per_page`/`current_page` (1-indexed) | Array (pagination in headers) |
57
+ | EPMW | `pageNumber`/`pageSize` | `{"data": [...], "totalCount": N}` |
58
+
59
+ **Important:**
60
+ - EPMW computers: Use `archive` not `delete` (405 error)
61
+ - PRA K8s tunnels: Require Linux jumpoint
62
+ - PWS assets: Must create via workgroup endpoint
63
+ - ECM integration: PWS system name must match PRA jump item name
64
+
65
+ ## Key Reference IDs
66
+
67
+ | Resource | ID | Notes |
68
+ |----------|-----|-------|
69
+ | PWS Workgroup AWS | 3 | |
70
+ | PWS Workgroup Datacenter | 2 | |
71
+ | PWS Functional Account | 7 | SSH key auth |
72
+ | PRA Jumpoint AWS | 3 | |
73
+ | PRA Jumpoint Datacenter | 2 | |
74
+ | PRA ec2-admin SSH CA | 31 | For EC2 provisioning |
75
+
76
+ ## Project Structure
77
+
78
+ ```
79
+ src/bt_cli/
80
+ ├── cli.py # Root dispatcher
81
+ ├── core/ # Shared (config, auth, output)
82
+ ├── pws/ # Password Safe
83
+ ├── pra/ # PRA
84
+ ├── entitle/ # Entitle
85
+ └── epmw/ # EPM Windows
86
+ ```
87
+
88
+ Each product follows: `client/` (API), `commands/` (CLI), `models/` (Pydantic)
File without changes
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: bt
3
+ description: BeyondTrust platform CLI cross-product commands. Use when working across PWS, PRA, Entitle, or EPMW together, or for PASM workflows combining Password Safe and PRA.
4
+ ---
5
+
6
+ # BT-Admin Cross-Product Commands
7
+
8
+ CLI for BeyondTrust platform: Password Safe, PRA, Entitle, EPM Windows.
9
+
10
+ ## IMPORTANT: Destructive Operations
11
+
12
+ **ALWAYS confirm with the user before running destructive commands:**
13
+ - `delete` - Removes resources permanently
14
+ - `offboard` - Removes systems/accounts from management
15
+ - `archive` - Archives computers (EPMW)
16
+ - `revoke` - Revokes permissions (Entitle)
17
+
18
+ Before executing any destructive operation:
19
+ 1. List what will be affected
20
+ 2. Ask user for explicit confirmation
21
+ 3. Never use `--force` flag without user approval
22
+
23
+ ## Setup
24
+
25
+ ```bash
26
+ cd /home/admin/entitl-sko/bt-cli
27
+ source .venv/bin/activate && source .env
28
+ ```
29
+
30
+ ## Test All Connections
31
+
32
+ ```bash
33
+ bt whoami # Test all configured products
34
+ bt whoami -o json # JSON output
35
+ ```
36
+
37
+ ## Cross-Product Quick Commands (`bt quick`)
38
+
39
+ ### PASM Search (PWS + PRA)
40
+ Find systems/accounts across both products. Shows ECM alignment (names must match for credential injection).
41
+
42
+ ```bash
43
+ bt quick pasm-search axion
44
+ bt quick pasm-search web-server -o json
45
+ ```
46
+
47
+ ### PASM Onboard (PWS + PRA)
48
+ Onboard a host to both Password Safe and PRA in one command.
49
+
50
+ ```bash
51
+ # Linux SSH host
52
+ bt quick pasm-onboard -n "my-server" -i "10.0.1.50" -w 3 -j 3 -g 24
53
+
54
+ # Full options
55
+ bt quick pasm-onboard \
56
+ --name "web-01" \
57
+ --ip "10.0.1.100" \
58
+ --workgroup 3 \
59
+ --jumpoint 3 \
60
+ --jump-group 24 \
61
+ --functional-account 7 \
62
+ --elevation "sudo" \
63
+ --pra-username "ec2-admin"
64
+
65
+ # Windows RDP host
66
+ bt quick pasm-onboard -n "win-srv" -i "10.0.2.10" -w 2 -p 1 -j 3 -g 31 --jump-type rdp --port 3389
67
+
68
+ # Skip one product
69
+ bt quick pasm-onboard -n "pra-only" -i "10.0.1.5" -j 3 -g 24 --skip-pws
70
+ bt quick pasm-onboard -n "pws-only" -i "10.0.1.6" -w 3 --skip-pra
71
+ ```
72
+
73
+ ### PASM Offboard
74
+ Remove from both products.
75
+
76
+ ```bash
77
+ bt quick pasm-offboard -n "my-server"
78
+ bt quick pasm-offboard -n "web-01" --force
79
+ ```
80
+
81
+ ## Environment Reference IDs
82
+
83
+ | Resource | ID | Notes |
84
+ |----------|-----|-------|
85
+ | PWS Workgroup (AWS) | 3 | AWS_Account Workgroup |
86
+ | PWS Workgroup (Datacenter) | 2 | Datacenter_West |
87
+ | PWS Functional Account | 7 | pws-functional SSH key |
88
+ | PWS Platform Linux | 2 | |
89
+ | PWS Platform Windows | 1 | |
90
+ | PRA Jumpoint (AWS) | 3 | AWS Account |
91
+ | PRA Jumpoint (Datacenter) | 2 | Data Center 01 |
92
+ | PRA Vault Account (ec2-admin) | 31 | SSH CA for EC2 |
93
+ | Entitle PRA Integration | bb2a3c79-02a9-45d9-be7f-f209d97cb1d7 | |
94
+ | Entitle Customer Access | 22f4960f-b2ee-435f-9fa2-b82baeca06b2 | Virtual integration |
95
+
96
+ ## Product-Specific Skills
97
+
98
+ Use `/pws`, `/pra`, `/entitle`, `/epmw` for product-specific commands.
@@ -0,0 +1,159 @@
1
+ ---
2
+ name: entitle
3
+ description: Entitle commands for JIT access, bundles, workflows, and permissions. Use when working with access requests, approval workflows, or managing user entitlements.
4
+ ---
5
+
6
+ # Entitle Commands (`bt entitle`)
7
+
8
+ ## IMPORTANT: Destructive Operations
9
+
10
+ **ALWAYS confirm with the user before:**
11
+ - `bt entitle resources delete` - Deletes resource from integration
12
+ - `bt entitle bundles delete` - Deletes access bundle
13
+ - `bt entitle permissions revoke` - Revokes active permission
14
+
15
+ List affected resources first, then ask for explicit confirmation.
16
+
17
+ ## Integrations & Resources
18
+
19
+ ```bash
20
+ # List integrations (connected apps)
21
+ bt entitle integrations list
22
+ bt entitle integrations get <integration_id>
23
+
24
+ # List resources in an integration
25
+ bt entitle resources list --integration <integration_id>
26
+ bt entitle resources get <resource_id>
27
+
28
+ # Virtual integration resources
29
+ bt entitle resources create-virtual \
30
+ --name "Customer-05 (Bing7)" \
31
+ --integration 22f4960f-b2ee-435f-9fa2-b82baeca06b2 \
32
+ --source-role-id <role_id> \
33
+ --role-name "Start Session"
34
+ bt entitle resources delete <resource_id>
35
+ ```
36
+
37
+ ## Bundles
38
+
39
+ Access bundles group multiple roles across integrations.
40
+
41
+ ```bash
42
+ bt entitle bundles list
43
+ bt entitle bundles get <bundle_id>
44
+ bt entitle bundles create \
45
+ --name "Dev AWS Access" \
46
+ --description "Development AWS console access" \
47
+ --workflow <workflow_id> \
48
+ --role <role_id> \
49
+ --duration 3600
50
+ bt entitle bundles delete <bundle_id>
51
+ ```
52
+
53
+ ## Workflows
54
+
55
+ ```bash
56
+ bt entitle workflows list
57
+ bt entitle workflows get <workflow_id>
58
+ ```
59
+
60
+ **Available Workflows:**
61
+ | Name | Type | Use Case |
62
+ |------|------|----------|
63
+ | Auto Approve | Automatic | Requests <= 12 hours |
64
+ | Low sensitivity | Simple | Single approver |
65
+ | Medium Sensitivity | Standard | Standard approval |
66
+ | Production access | Multi-step | Duration-based tiers |
67
+
68
+ ## Users & Permissions
69
+
70
+ ```bash
71
+ # Users
72
+ bt entitle users list
73
+ bt entitle users get <user_id>
74
+
75
+ # Active permissions
76
+ bt entitle permissions list
77
+ bt entitle permissions list --user <user_id>
78
+ bt entitle permissions revoke <permission_id>
79
+
80
+ # Accounts
81
+ bt entitle accounts list --integration <integration_id>
82
+ ```
83
+
84
+ ## Roles & Policies
85
+
86
+ ```bash
87
+ bt entitle roles list
88
+ bt entitle roles list --resource <resource_id>
89
+ bt entitle roles get <role_id>
90
+
91
+ bt entitle policies list
92
+ bt entitle policies get <policy_id>
93
+ ```
94
+
95
+ ## Common Workflows
96
+
97
+ ### Add PRA Jump Group to Entitle
98
+
99
+ **Important:** PRA integration sync is **asynchronous** (runs hourly). After creating a new PRA jump group, either:
100
+ - Wait up to 1 hour for auto-sync
101
+ - Or manually trigger sync in Entitle UI: Integrations → PRA → Sync Now
102
+
103
+ ```bash
104
+ # 1. Trigger PRA sync in Entitle UI (or wait for hourly sync)
105
+
106
+ # 2. Find the new PRA resource
107
+ bt entitle resources list --integration bb2a3c79-02a9-45d9-be7f-f209d97cb1d7
108
+
109
+ # 3. Get "Start Sessions Only" role ID
110
+ bt entitle roles list --resource <pra_resource_id>
111
+
112
+ # 4. Add to Customer Access virtual integration
113
+ bt entitle resources create-virtual \
114
+ --name "Customer-05" \
115
+ --integration 22f4960f-b2ee-435f-9fa2-b82baeca06b2 \
116
+ --source-role-id <role_id> \
117
+ --role-name "Start Session"
118
+ ```
119
+
120
+ ### Check User Access
121
+
122
+ ```bash
123
+ bt entitle permissions list --user "user@example.com" -o json
124
+ ```
125
+
126
+ ## Key IDs
127
+
128
+ | Resource | ID |
129
+ |----------|-----|
130
+ | PRA Integration | bb2a3c79-02a9-45d9-be7f-f209d97cb1d7 |
131
+ | Customer Access (Virtual) | 22f4960f-b2ee-435f-9fa2-b82baeca06b2 |
132
+ | AWS SandBox | (check `bt entitle integrations list`) |
133
+
134
+ ## Integrations Available
135
+
136
+ - Cloud10 (Virtual Application)
137
+ - NexusDyn - Azure
138
+ - Customer Access (Virtual)
139
+ - Privileged Remote Access (PRA)
140
+ - AWS - SandBox Account
141
+ - Nexusdyn - Postgres ERP Database
142
+ - NexusDyn - EntraID
143
+
144
+ ## Supported Applications (75+)
145
+
146
+ **Cloud:** AWS, Azure, GCP, Oracle OCI
147
+ **Identity:** Okta, Entra ID, OneLogin, JumpCloud
148
+ **DevOps:** GitHub, GitLab, Jenkins, Terraform Cloud
149
+ **Databases:** Postgres, MySQL, MSSQL, MongoDB, Snowflake
150
+ **Kubernetes:** EKS, AKS, GKE, Rancher
151
+ **BeyondTrust:** Password Safe, PRA, Remote Support
152
+
153
+ ## API Notes
154
+
155
+ - Base path: `/public/v1`
156
+ - Pagination: `page`/`perPage`
157
+ - Response: `{"result": [...], "pagination": {...}}`
158
+ - All IDs are UUIDs (strings)
159
+ - Bearer token auth
@@ -0,0 +1,145 @@
1
+ ---
2
+ name: epmw
3
+ description: EPM Windows commands for endpoint privilege management. Use when working with Windows computers, policies, admin access requests, or audit logs.
4
+ ---
5
+
6
+ # EPM Windows Commands (`bt epmw`)
7
+
8
+ ## IMPORTANT: Destructive Operations
9
+
10
+ **ALWAYS confirm with the user before:**
11
+ - `bt epmw computers archive` - Archives computer from management
12
+ - `bt epmw groups delete` - Deletes computer group
13
+ - `bt epmw policies delete` - Deletes policy
14
+ - `bt epmw quick stale --delete` - Deletes stale computers
15
+
16
+ List affected resources first, then ask for explicit confirmation.
17
+
18
+ ## Quick Commands
19
+
20
+ ```bash
21
+ # Find stale computers (not checked in recently)
22
+ bt epmw quick stale # 24+ hours
23
+ bt epmw quick stale --hours 48 # 48+ hours
24
+ bt epmw quick stale -h 12 -g "Workstations"
25
+
26
+ # Delete stale computers
27
+ bt epmw quick stale --delete # With confirmation
28
+ bt epmw quick stale --delete --force # Skip confirmation
29
+
30
+ # Find disconnected computers
31
+ bt epmw quick disconnected
32
+ bt epmw quick disconnected -g "Servers"
33
+
34
+ # Status summary by group
35
+ bt epmw quick status
36
+ bt epmw quick status -g "Datacenter"
37
+ ```
38
+
39
+ ## Computers
40
+
41
+ ```bash
42
+ bt epmw computers list
43
+ bt epmw computers list -o json
44
+ bt epmw computers get <computer_id>
45
+ bt epmw computers delete <computer_id>
46
+ bt epmw computers archive <computer_id>
47
+ bt epmw computers unarchive <computer_id>
48
+ ```
49
+
50
+ ## Groups
51
+
52
+ ```bash
53
+ bt epmw groups list
54
+ bt epmw groups get <group_id>
55
+ bt epmw groups create --name "NewGroup" --description "Description"
56
+ bt epmw groups update <group_id> --name "UpdatedName"
57
+ bt epmw groups delete <group_id>
58
+ bt epmw groups assign-policy <group_id> --policy <policy_id>
59
+ bt epmw groups assign-computers <group_id> --computers <id1>,<id2>
60
+ ```
61
+
62
+ ## Policies
63
+
64
+ ```bash
65
+ bt epmw policies list
66
+ bt epmw policies get <policy_id>
67
+ bt epmw policies groups <policy_id> # Show assigned groups
68
+
69
+ # Download policy XML (for template)
70
+ bt epmw policies download <policy_id> > template.xml
71
+
72
+ # Create policy from XML
73
+ bt epmw policies create -n "My Policy" -f template.xml
74
+
75
+ # Policy revisions
76
+ bt epmw policies revisions list <policy_id>
77
+ bt epmw policies revisions get <policy_id> <revision_id>
78
+ bt epmw policies revisions upload <policy_id> -f policy.xml
79
+ ```
80
+
81
+ ## Admin Access Requests
82
+
83
+ ```bash
84
+ bt epmw requests list
85
+ bt epmw requests get <request_id>
86
+ bt epmw requests create --computer <id> --duration 30 --reason "Maintenance"
87
+ bt epmw requests approve <request_id>
88
+ bt epmw requests deny <request_id> --reason "Not authorized"
89
+ ```
90
+
91
+ ## Users & Roles
92
+
93
+ ```bash
94
+ bt epmw users list
95
+ bt epmw users get <user_id>
96
+ bt epmw users create --username "newuser" --email "user@example.com"
97
+ bt epmw users enable <user_id>
98
+ bt epmw users disable <user_id>
99
+ bt epmw users assign-roles <user_id> --roles <role1>,<role2>
100
+
101
+ bt epmw roles list
102
+ bt epmw roles get <role_id>
103
+ ```
104
+
105
+ ## Audits
106
+
107
+ ```bash
108
+ # Activity audits
109
+ bt epmw audits activity list
110
+ bt epmw audits activity get <audit_id>
111
+
112
+ # Authorization requests
113
+ bt epmw audits authorization list
114
+ bt epmw audits authorization get <audit_id>
115
+
116
+ # Request audits
117
+ bt epmw audits requests list
118
+ bt epmw audits requests get <audit_id>
119
+ ```
120
+
121
+ ## Key Groups
122
+
123
+ | ID | Name | Computers |
124
+ |----|------|-----------|
125
+ | 042267ec-... | Servers - Datacenter1 | CorpMem01, CorpMem02 |
126
+ | 1c8f6310-... | Workstations - Datacenter1 | CorpWS01, CorpWS02 |
127
+ | 67ca23ad-... | Engineering | BenC-Skynet |
128
+
129
+ ## Key Computers
130
+
131
+ | Host | Domain | Group | Status |
132
+ |------|--------|-------|--------|
133
+ | CorpMem01 | nexusdyn.corp | Servers | Connected |
134
+ | CorpMem02 | nexusdyn.corp | Servers | Connected |
135
+ | CorpWS01 | nexusdyn.corp | Workstations | Connected |
136
+ | CorpWS02 | nexusdyn.corp | Workstations | Connected |
137
+
138
+ ## API Notes
139
+
140
+ - Base path: `/management-api/v3`
141
+ - Token endpoint: `/oauth/token`
142
+ - Pagination: `pageNumber`/`pageSize`
143
+ - Response: `{"data": [...], "totalCount": N}`
144
+ - All IDs are UUIDs
145
+ - Delete returns 405 - use archive instead