bt-cli 0.4.18__tar.gz → 0.4.21__tar.gz

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 (173) hide show
  1. {bt_cli-0.4.18 → bt_cli-0.4.21}/.claude/skills/entitle/SKILL.md +34 -0
  2. {bt_cli-0.4.18 → bt_cli-0.4.21}/.github/workflows/release.yml +3 -0
  3. {bt_cli-0.4.18/src/bt_cli/data → bt_cli-0.4.21}/CLAUDE.md +7 -1
  4. {bt_cli-0.4.18 → bt_cli-0.4.21}/PKG-INFO +3 -2
  5. {bt_cli-0.4.18 → bt_cli-0.4.21}/pyproject.toml +3 -2
  6. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/__init__.py +1 -1
  7. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/cli.py +22 -0
  8. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/data/skills/entitle/SKILL.md +34 -0
  9. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/client/base.py +3 -3
  10. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/commands/users.py +7 -3
  11. {bt_cli-0.4.18 → bt_cli-0.4.21}/.claude/skills/bt/SKILL.md +0 -0
  12. {bt_cli-0.4.18 → bt_cli-0.4.21}/.claude/skills/epmw/SKILL.md +0 -0
  13. {bt_cli-0.4.18 → bt_cli-0.4.21}/.claude/skills/pra/SKILL.md +0 -0
  14. {bt_cli-0.4.18 → bt_cli-0.4.21}/.claude/skills/pws/SKILL.md +0 -0
  15. {bt_cli-0.4.18 → bt_cli-0.4.21}/.env.example +0 -0
  16. {bt_cli-0.4.18 → bt_cli-0.4.21}/.github/workflows/ci.yml +0 -0
  17. {bt_cli-0.4.18 → bt_cli-0.4.21}/.gitignore +0 -0
  18. {bt_cli-0.4.18 → bt_cli-0.4.21}/README.md +0 -0
  19. {bt_cli-0.4.18 → bt_cli-0.4.21}/assets/cli-help.png +0 -0
  20. {bt_cli-0.4.18 → bt_cli-0.4.21}/assets/cli-output.png +0 -0
  21. {bt_cli-0.4.18 → bt_cli-0.4.21}/bt-cli.spec +0 -0
  22. {bt_cli-0.4.18 → bt_cli-0.4.21}/bt_entry.py +0 -0
  23. {bt_cli-0.4.18 → bt_cli-0.4.21}/scripts/bt_entry.py +0 -0
  24. {bt_cli-0.4.18 → bt_cli-0.4.21}/scripts/sync-package-data.sh +0 -0
  25. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/commands/__init__.py +0 -0
  26. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/commands/configure.py +0 -0
  27. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/commands/learn.py +0 -0
  28. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/commands/quick.py +0 -0
  29. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/core/__init__.py +0 -0
  30. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/core/auth.py +0 -0
  31. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/core/client.py +0 -0
  32. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/core/config.py +0 -0
  33. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/core/config_file.py +0 -0
  34. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/core/csv_utils.py +0 -0
  35. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/core/errors.py +0 -0
  36. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/core/output.py +0 -0
  37. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/core/prompts.py +0 -0
  38. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/core/rest_debug.py +0 -0
  39. {bt_cli-0.4.18 → bt_cli-0.4.21/src/bt_cli/data}/CLAUDE.md +0 -0
  40. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/data/__init__.py +0 -0
  41. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/data/skills/bt/SKILL.md +0 -0
  42. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/data/skills/epmw/SKILL.md +0 -0
  43. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/data/skills/pra/SKILL.md +0 -0
  44. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/data/skills/pws/SKILL.md +0 -0
  45. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/__init__.py +0 -0
  46. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/client/__init__.py +0 -0
  47. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/commands/__init__.py +0 -0
  48. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/commands/accounts.py +0 -0
  49. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/commands/applications.py +0 -0
  50. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/commands/auth.py +0 -0
  51. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/commands/bundles.py +0 -0
  52. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/commands/integrations.py +0 -0
  53. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/commands/permissions.py +0 -0
  54. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/commands/policies.py +0 -0
  55. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/commands/resources.py +0 -0
  56. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/commands/roles.py +0 -0
  57. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/commands/workflows.py +0 -0
  58. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/models/__init__.py +0 -0
  59. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/models/bundle.py +0 -0
  60. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/models/common.py +0 -0
  61. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/models/integration.py +0 -0
  62. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/models/permission.py +0 -0
  63. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/models/policy.py +0 -0
  64. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/models/resource.py +0 -0
  65. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/models/role.py +0 -0
  66. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/models/user.py +0 -0
  67. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/entitle/models/workflow.py +0 -0
  68. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/__init__.py +0 -0
  69. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/client/__init__.py +0 -0
  70. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/client/base.py +0 -0
  71. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/commands/__init__.py +0 -0
  72. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/commands/audits.py +0 -0
  73. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/commands/auth.py +0 -0
  74. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/commands/computers.py +0 -0
  75. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/commands/events.py +0 -0
  76. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/commands/groups.py +0 -0
  77. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/commands/policies.py +0 -0
  78. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/commands/quick.py +0 -0
  79. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/commands/requests.py +0 -0
  80. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/commands/roles.py +0 -0
  81. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/commands/tasks.py +0 -0
  82. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/commands/users.py +0 -0
  83. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/epmw/models/__init__.py +0 -0
  84. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/__init__.py +0 -0
  85. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/client/__init__.py +0 -0
  86. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/client/base.py +0 -0
  87. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/commands/__init__.py +0 -0
  88. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/commands/auth.py +0 -0
  89. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/commands/import_export.py +0 -0
  90. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/commands/jump_clients.py +0 -0
  91. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/commands/jump_groups.py +0 -0
  92. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/commands/jump_items.py +0 -0
  93. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/commands/jumpoints.py +0 -0
  94. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/commands/policies.py +0 -0
  95. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/commands/quick.py +0 -0
  96. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/commands/teams.py +0 -0
  97. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/commands/users.py +0 -0
  98. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/commands/vault.py +0 -0
  99. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/models/__init__.py +0 -0
  100. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/models/common.py +0 -0
  101. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/models/jump_client.py +0 -0
  102. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/models/jump_group.py +0 -0
  103. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/models/jump_item.py +0 -0
  104. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/models/jumpoint.py +0 -0
  105. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/models/team.py +0 -0
  106. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/models/user.py +0 -0
  107. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pra/models/vault.py +0 -0
  108. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/__init__.py +0 -0
  109. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/client/__init__.py +0 -0
  110. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/client/base.py +0 -0
  111. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/client/beyondinsight.py +0 -0
  112. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/client/passwordsafe.py +0 -0
  113. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/__init__.py +0 -0
  114. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/accounts.py +0 -0
  115. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/assets.py +0 -0
  116. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/auth.py +0 -0
  117. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/clouds.py +0 -0
  118. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/config.py +0 -0
  119. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/credentials.py +0 -0
  120. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/databases.py +0 -0
  121. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/directories.py +0 -0
  122. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/functional.py +0 -0
  123. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/import_export.py +0 -0
  124. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/platforms.py +0 -0
  125. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/quick.py +0 -0
  126. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/search.py +0 -0
  127. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/secrets.py +0 -0
  128. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/systems.py +0 -0
  129. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/users.py +0 -0
  130. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/commands/workgroups.py +0 -0
  131. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/config.py +0 -0
  132. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/models/__init__.py +0 -0
  133. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/models/account.py +0 -0
  134. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/models/asset.py +0 -0
  135. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/models/common.py +0 -0
  136. {bt_cli-0.4.18 → bt_cli-0.4.21}/src/bt_cli/pws/models/system.py +0 -0
  137. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/__init__.py +0 -0
  138. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/conftest.py +0 -0
  139. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/core/__init__.py +0 -0
  140. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/core/test_auth.py +0 -0
  141. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/core/test_config.py +0 -0
  142. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/core/test_errors.py +0 -0
  143. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/core/test_rest_debug.py +0 -0
  144. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/entitle/__init__.py +0 -0
  145. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/entitle/test_client.py +0 -0
  146. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/entitle/test_commands.py +0 -0
  147. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/entitle-smoke-test.sh +0 -0
  148. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/epmw/__init__.py +0 -0
  149. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/epmw/test_client.py +0 -0
  150. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/epmw/test_commands.py +0 -0
  151. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/epmw-quick-test-plan.md +0 -0
  152. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/fixtures/__init__.py +0 -0
  153. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/fixtures/responses.py +0 -0
  154. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/integration/__init__.py +0 -0
  155. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/integration/conftest.py +0 -0
  156. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/integration/helpers.py +0 -0
  157. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/integration/test_entitle_integration.py +0 -0
  158. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/integration/test_epmw_integration.py +0 -0
  159. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/integration/test_epmw_lifecycle.py +0 -0
  160. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/integration/test_pra_integration.py +0 -0
  161. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/integration/test_pra_lifecycle.py +0 -0
  162. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/integration/test_pws_integration.py +0 -0
  163. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/integration/test_pws_lifecycle.py +0 -0
  164. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/pra/__init__.py +0 -0
  165. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/pra/test_client.py +0 -0
  166. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/pra/test_commands.py +0 -0
  167. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/pra-smoke-test.sh +0 -0
  168. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/pra-test-plan.md +0 -0
  169. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/pws/__init__.py +0 -0
  170. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/pws/test_client.py +0 -0
  171. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/pws/test_commands.py +0 -0
  172. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/pws-quick-test-plan.md +0 -0
  173. {bt_cli-0.4.18 → bt_cli-0.4.21}/tests/pws-smoke-test.sh +0 -0
@@ -14,6 +14,40 @@ description: Entitle commands for JIT access, bundles, workflows, and permission
14
14
 
15
15
  List affected resources first, then ask for explicit confirmation.
16
16
 
17
+ ## Performance Tips
18
+
19
+ **ALWAYS use server-side filters** - never download all data and filter locally.
20
+
21
+ ```bash
22
+ # ✓ FAST - Server-side filtering
23
+ bt entitle permissions list --resource <resource_id>
24
+ bt entitle permissions list --user <user_id>
25
+ bt entitle permissions list --integration <integration_id>
26
+
27
+ # ✗ SLOW - Downloads ALL 23k+ permissions, filters locally
28
+ bt entitle permissions list | jq 'select(...)'
29
+ bt entitle permissions list -o json | grep "something"
30
+ ```
31
+
32
+ **Available filters for permissions list:**
33
+
34
+ | Flag | Purpose |
35
+ |------|---------|
36
+ | `--resource -r` | Filter by resource ID |
37
+ | `--user -u` | Filter by user ID |
38
+ | `--integration -i` | Filter by integration ID |
39
+
40
+ **Dataset size warning:** Entitle can have 20,000+ permissions. Unfiltered queries will be very slow.
41
+
42
+ **Workflow - Check standing access for a resource:**
43
+ ```bash
44
+ # 1. Find resource ID
45
+ bt entitle resources list --integration <integration_id> | grep -i "admin"
46
+
47
+ # 2. Query permissions with resource filter (fast)
48
+ bt entitle permissions list --resource <resource_id> -o json | jq -r '.[] | "\(.actor.name) | \(.actor.email)"'
49
+ ```
50
+
17
51
  ## Integrations & Resources
18
52
 
19
53
  ```bash
@@ -236,6 +236,9 @@ jobs:
236
236
  (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) ||
237
237
  (github.event_name == 'workflow_dispatch' && inputs.skip_pypi == false)
238
238
 
239
+ permissions:
240
+ id-token: write # Required for trusted publishing to PyPI
241
+
239
242
  environment:
240
243
  name: pypi
241
244
  url: https://pypi.org/project/bt-cli/
@@ -1,6 +1,6 @@
1
1
  # BT-CLI
2
2
 
3
- BeyondTrust Platform CLI for Password Safe, Entitle, PRA, and EPM Windows.
3
+ BeyondTrust Platform CLI for Password Safe, Entitle, PRA, and EPM Windows. **Version: 0.4.21**
4
4
 
5
5
  ## Setup
6
6
 
@@ -35,6 +35,9 @@ Use these slash commands for detailed product guidance:
35
35
  ## Common Patterns
36
36
 
37
37
  ```bash
38
+ # Version info
39
+ bt version # or bt --version or bt -V
40
+
38
41
  # All list commands support JSON output
39
42
  bt pws systems list -o json
40
43
  bt pra jump-items shell list -o json
@@ -61,6 +64,9 @@ PASSWORD=$(bt pws quick checkout -s server -a admin --raw)
61
64
  - PRA K8s tunnels: Require Linux jumpoint
62
65
  - PWS assets: Must create via workgroup endpoint
63
66
  - ECM integration: PWS system name must match PRA jump item name
67
+ - Entitle permissions: Use server-side filters (`--resource`, `--user`, `--integration`) - dataset can be 20k+ records
68
+ - Entitle users: Use `--all` flag only when needed - default fetches first page only
69
+ - Windows builds: Rich must be pinned to `<14.0.0` (Rich 14 has PyInstaller unicode issues)
64
70
 
65
71
  ## Functional vs Managed Accounts
66
72
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bt-cli
3
- Version: 0.4.18
3
+ Version: 0.4.21
4
4
  Summary: BeyondTrust Platform CLI (unofficial) - Password Safe, Entitle, PRA, EPM
5
5
  Author-email: Dave Grendysz <dgrendysz@beyondtrust.com>
6
6
  License: MIT
@@ -23,8 +23,9 @@ Requires-Dist: httpx>=0.27.0
23
23
  Requires-Dist: pydantic>=2.0.0
24
24
  Requires-Dist: python-dotenv>=1.0.0
25
25
  Requires-Dist: pyyaml>=6.0.0
26
- Requires-Dist: rich<15.0.0,>=13.7.0
26
+ Requires-Dist: rich<14.0.0,>=13.7.0
27
27
  Requires-Dist: shellingham>=1.5.0
28
+ Requires-Dist: truststore>=0.8.0; python_version >= '3.10'
28
29
  Requires-Dist: typer<1.0.0,>=0.12.0
29
30
  Provides-Extra: all
30
31
  Requires-Dist: keyring>=24.0.0; extra == 'all'
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bt-cli"
7
- version = "0.4.18"
7
+ version = "0.4.21"
8
8
  description = "BeyondTrust Platform CLI (unofficial) - Password Safe, Entitle, PRA, EPM"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -39,10 +39,11 @@ dependencies = [
39
39
  "typer>=0.12.0,<1.0.0",
40
40
  "httpx>=0.27.0",
41
41
  "pydantic>=2.0.0",
42
- "rich>=13.7.0,<15.0.0",
42
+ "rich>=13.7.0,<14.0.0", # Pin to 13.x - Rich 14 has PyInstaller issues
43
43
  "python-dotenv>=1.0.0",
44
44
  "pyyaml>=6.0.0",
45
45
  "shellingham>=1.5.0",
46
+ "truststore>=0.8.0;python_version>='3.10'", # Use OS certificate store
46
47
  ]
47
48
 
48
49
  [project.optional-dependencies]
@@ -1,3 +1,3 @@
1
1
  """BeyondTrust Unified Admin CLI."""
2
2
 
3
- __version__ = "0.4.18"
3
+ __version__ = "0.4.21"
@@ -3,6 +3,14 @@
3
3
  import sys
4
4
  from typing import Optional
5
5
 
6
+ # Use OS certificate store instead of bundled certifi (for enterprise CAs)
7
+ # This must be done before any SSL connections are made
8
+ try:
9
+ import truststore
10
+ truststore.inject_into_ssl()
11
+ except ImportError:
12
+ pass # Python < 3.10 or truststore not available
13
+
6
14
  import typer
7
15
 
8
16
  # Check rich version early to give helpful error
@@ -131,6 +139,13 @@ except Exception:
131
139
  pass # Quick module not ready yet
132
140
 
133
141
 
142
+ def _version_callback(value: bool) -> None:
143
+ """Print version and exit."""
144
+ if value:
145
+ print(f"bt-cli version {__version__}")
146
+ raise typer.Exit()
147
+
148
+
134
149
  @app.callback()
135
150
  def main_callback(
136
151
  profile: Optional[str] = typer.Option(
@@ -145,6 +160,13 @@ def main_callback(
145
160
  help="Show REST API calls (method, URL, headers, body)",
146
161
  envvar="BT_SHOW_REST",
147
162
  ),
163
+ version: bool = typer.Option(
164
+ False,
165
+ "--version", "-V",
166
+ help="Show version and exit",
167
+ callback=_version_callback,
168
+ is_eager=True,
169
+ ),
148
170
  ) -> None:
149
171
  """BeyondTrust Platform CLI.
150
172
 
@@ -14,6 +14,40 @@ description: Entitle commands for JIT access, bundles, workflows, and permission
14
14
 
15
15
  List affected resources first, then ask for explicit confirmation.
16
16
 
17
+ ## Performance Tips
18
+
19
+ **ALWAYS use server-side filters** - never download all data and filter locally.
20
+
21
+ ```bash
22
+ # ✓ FAST - Server-side filtering
23
+ bt entitle permissions list --resource <resource_id>
24
+ bt entitle permissions list --user <user_id>
25
+ bt entitle permissions list --integration <integration_id>
26
+
27
+ # ✗ SLOW - Downloads ALL 23k+ permissions, filters locally
28
+ bt entitle permissions list | jq 'select(...)'
29
+ bt entitle permissions list -o json | grep "something"
30
+ ```
31
+
32
+ **Available filters for permissions list:**
33
+
34
+ | Flag | Purpose |
35
+ |------|---------|
36
+ | `--resource -r` | Filter by resource ID |
37
+ | `--user -u` | Filter by user ID |
38
+ | `--integration -i` | Filter by integration ID |
39
+
40
+ **Dataset size warning:** Entitle can have 20,000+ permissions. Unfiltered queries will be very slow.
41
+
42
+ **Workflow - Check standing access for a resource:**
43
+ ```bash
44
+ # 1. Find resource ID
45
+ bt entitle resources list --integration <integration_id> | grep -i "admin"
46
+
47
+ # 2. Query permissions with resource filter (fast)
48
+ bt entitle permissions list --resource <resource_id> -o json | jq -r '.[] | "\(.actor.name) | \(.actor.email)"'
49
+ ```
50
+
17
51
  ## Integrations & Resources
18
52
 
19
53
  ```bash
@@ -351,10 +351,10 @@ class EntitleClient:
351
351
  # =========================================================================
352
352
 
353
353
  def list_users(
354
- self, search: Optional[str] = None, limit: int = 100
354
+ self, search: Optional[str] = None, limit: int = 100, max_pages: Optional[int] = None
355
355
  ) -> list[dict[str, Any]]:
356
- """List all users."""
357
- return self.paginate("/users", {"search": search}, page_size=limit)
356
+ """List users with optional pagination limit."""
357
+ return self.paginate("/users", {"search": search}, page_size=limit, max_pages=max_pages)
358
358
 
359
359
  def get_user(self, user_id: str) -> dict[str, Any]:
360
360
  """Get a user by ID."""
@@ -14,7 +14,8 @@ app = typer.Typer(no_args_is_help=True, help="Manage users")
14
14
  @app.command("list")
15
15
  def list_users(
16
16
  search: Optional[str] = typer.Option(None, "--search", "-s", help="Search by email or name"),
17
- limit: int = typer.Option(100, "--limit", "-l", help="Maximum results to return"),
17
+ limit: int = typer.Option(50, "--limit", "-l", help="Results per page"),
18
+ fetch_all: bool = typer.Option(False, "--all", help="Fetch all results (may be slow for large datasets)"),
18
19
  output: str = typer.Option("table", "--output", "-o", help="Output format: table, json"),
19
20
  ) -> None:
20
21
  """List users in Entitle.
@@ -22,11 +23,14 @@ def list_users(
22
23
  Examples:
23
24
  bt entitle users list
24
25
  bt entitle users list -s "john"
25
- bt entitle users list -l 50 -o json
26
+ bt entitle users list -l 100 --all
27
+ bt entitle users list -o json
26
28
  """
27
29
  try:
28
30
  with get_client() as client:
29
- data = client.list_users(search=search, limit=limit)
31
+ # Only fetch first page by default, use --all for everything
32
+ max_pages = None if fetch_all else 1
33
+ data = client.list_users(search=search, limit=limit, max_pages=max_pages)
30
34
 
31
35
  if output == "json":
32
36
  print_json(data)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes