bt-cli 0.4.30__tar.gz → 0.4.31__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 (174) hide show
  1. {bt_cli-0.4.30 → bt_cli-0.4.31}/CLAUDE.md +1 -1
  2. {bt_cli-0.4.30 → bt_cli-0.4.31}/PKG-INFO +1 -1
  3. {bt_cli-0.4.30 → bt_cli-0.4.31}/pyproject.toml +1 -1
  4. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/__init__.py +1 -1
  5. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/client/passwordsafe.py +48 -24
  6. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/users.py +11 -5
  7. {bt_cli-0.4.30 → bt_cli-0.4.31}/.claude/skills/bt/SKILL.md +0 -0
  8. {bt_cli-0.4.30 → bt_cli-0.4.31}/.claude/skills/entitle/SKILL.md +0 -0
  9. {bt_cli-0.4.30 → bt_cli-0.4.31}/.claude/skills/epmw/SKILL.md +0 -0
  10. {bt_cli-0.4.30 → bt_cli-0.4.31}/.claude/skills/pra/SKILL.md +0 -0
  11. {bt_cli-0.4.30 → bt_cli-0.4.31}/.claude/skills/pws/SKILL.md +0 -0
  12. {bt_cli-0.4.30 → bt_cli-0.4.31}/.env.example +0 -0
  13. {bt_cli-0.4.30 → bt_cli-0.4.31}/.github/workflows/ci.yml +0 -0
  14. {bt_cli-0.4.30 → bt_cli-0.4.31}/.github/workflows/release.yml +0 -0
  15. {bt_cli-0.4.30 → bt_cli-0.4.31}/.gitignore +0 -0
  16. {bt_cli-0.4.30 → bt_cli-0.4.31}/README.md +0 -0
  17. {bt_cli-0.4.30 → bt_cli-0.4.31}/assets/cli-help.png +0 -0
  18. {bt_cli-0.4.30 → bt_cli-0.4.31}/assets/cli-output.png +0 -0
  19. {bt_cli-0.4.30 → bt_cli-0.4.31}/bt-cli.spec +0 -0
  20. {bt_cli-0.4.30 → bt_cli-0.4.31}/bt_entry.py +0 -0
  21. {bt_cli-0.4.30 → bt_cli-0.4.31}/scripts/bt_entry.py +0 -0
  22. {bt_cli-0.4.30 → bt_cli-0.4.31}/scripts/sync-package-data.sh +0 -0
  23. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/cli.py +0 -0
  24. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/commands/__init__.py +0 -0
  25. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/commands/configure.py +0 -0
  26. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/commands/learn.py +0 -0
  27. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/commands/quick.py +0 -0
  28. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/core/__init__.py +0 -0
  29. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/core/auth.py +0 -0
  30. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/core/client.py +0 -0
  31. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/core/config.py +0 -0
  32. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/core/config_file.py +0 -0
  33. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/core/csv_utils.py +0 -0
  34. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/core/errors.py +0 -0
  35. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/core/output.py +0 -0
  36. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/core/prompts.py +0 -0
  37. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/core/rest_debug.py +0 -0
  38. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/data/CLAUDE.md +0 -0
  39. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/data/__init__.py +0 -0
  40. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/data/skills/bt/SKILL.md +0 -0
  41. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/data/skills/entitle/SKILL.md +0 -0
  42. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/data/skills/epmw/SKILL.md +0 -0
  43. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/data/skills/pra/SKILL.md +0 -0
  44. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/data/skills/pws/SKILL.md +0 -0
  45. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/__init__.py +0 -0
  46. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/client/__init__.py +0 -0
  47. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/client/base.py +0 -0
  48. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/commands/__init__.py +0 -0
  49. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/commands/accounts.py +0 -0
  50. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/commands/applications.py +0 -0
  51. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/commands/auth.py +0 -0
  52. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/commands/bundles.py +0 -0
  53. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/commands/integrations.py +0 -0
  54. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/commands/permissions.py +0 -0
  55. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/commands/policies.py +0 -0
  56. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/commands/resources.py +0 -0
  57. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/commands/roles.py +0 -0
  58. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/commands/users.py +0 -0
  59. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/commands/workflows.py +0 -0
  60. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/models/__init__.py +0 -0
  61. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/models/bundle.py +0 -0
  62. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/models/common.py +0 -0
  63. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/models/integration.py +0 -0
  64. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/models/permission.py +0 -0
  65. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/models/policy.py +0 -0
  66. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/models/resource.py +0 -0
  67. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/models/role.py +0 -0
  68. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/models/user.py +0 -0
  69. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/entitle/models/workflow.py +0 -0
  70. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/__init__.py +0 -0
  71. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/client/__init__.py +0 -0
  72. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/client/base.py +0 -0
  73. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/commands/__init__.py +0 -0
  74. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/commands/audits.py +0 -0
  75. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/commands/auth.py +0 -0
  76. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/commands/computers.py +0 -0
  77. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/commands/events.py +0 -0
  78. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/commands/groups.py +0 -0
  79. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/commands/policies.py +0 -0
  80. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/commands/quick.py +0 -0
  81. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/commands/requests.py +0 -0
  82. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/commands/roles.py +0 -0
  83. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/commands/tasks.py +0 -0
  84. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/commands/users.py +0 -0
  85. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/epmw/models/__init__.py +0 -0
  86. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/__init__.py +0 -0
  87. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/client/__init__.py +0 -0
  88. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/client/base.py +0 -0
  89. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/commands/__init__.py +0 -0
  90. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/commands/auth.py +0 -0
  91. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/commands/import_export.py +0 -0
  92. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/commands/jump_clients.py +0 -0
  93. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/commands/jump_groups.py +0 -0
  94. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/commands/jump_items.py +0 -0
  95. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/commands/jumpoints.py +0 -0
  96. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/commands/policies.py +0 -0
  97. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/commands/quick.py +0 -0
  98. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/commands/teams.py +0 -0
  99. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/commands/users.py +0 -0
  100. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/commands/vault.py +0 -0
  101. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/models/__init__.py +0 -0
  102. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/models/common.py +0 -0
  103. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/models/jump_client.py +0 -0
  104. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/models/jump_group.py +0 -0
  105. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/models/jump_item.py +0 -0
  106. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/models/jumpoint.py +0 -0
  107. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/models/team.py +0 -0
  108. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/models/user.py +0 -0
  109. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pra/models/vault.py +0 -0
  110. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/__init__.py +0 -0
  111. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/client/__init__.py +0 -0
  112. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/client/base.py +0 -0
  113. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/client/beyondinsight.py +0 -0
  114. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/__init__.py +0 -0
  115. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/accounts.py +0 -0
  116. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/assets.py +0 -0
  117. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/attributes.py +0 -0
  118. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/auth.py +0 -0
  119. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/clouds.py +0 -0
  120. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/config.py +0 -0
  121. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/credentials.py +0 -0
  122. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/databases.py +0 -0
  123. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/directories.py +0 -0
  124. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/functional.py +0 -0
  125. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/import_export.py +0 -0
  126. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/platforms.py +0 -0
  127. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/quick.py +0 -0
  128. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/search.py +0 -0
  129. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/secrets.py +0 -0
  130. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/systems.py +0 -0
  131. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/commands/workgroups.py +0 -0
  132. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/config.py +0 -0
  133. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/models/__init__.py +0 -0
  134. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/models/account.py +0 -0
  135. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/models/asset.py +0 -0
  136. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/models/common.py +0 -0
  137. {bt_cli-0.4.30 → bt_cli-0.4.31}/src/bt_cli/pws/models/system.py +0 -0
  138. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/__init__.py +0 -0
  139. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/conftest.py +0 -0
  140. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/core/__init__.py +0 -0
  141. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/core/test_auth.py +0 -0
  142. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/core/test_config.py +0 -0
  143. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/core/test_errors.py +0 -0
  144. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/core/test_rest_debug.py +0 -0
  145. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/entitle/__init__.py +0 -0
  146. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/entitle/test_client.py +0 -0
  147. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/entitle/test_commands.py +0 -0
  148. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/entitle-smoke-test.sh +0 -0
  149. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/epmw/__init__.py +0 -0
  150. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/epmw/test_client.py +0 -0
  151. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/epmw/test_commands.py +0 -0
  152. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/epmw-quick-test-plan.md +0 -0
  153. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/fixtures/__init__.py +0 -0
  154. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/fixtures/responses.py +0 -0
  155. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/integration/__init__.py +0 -0
  156. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/integration/conftest.py +0 -0
  157. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/integration/helpers.py +0 -0
  158. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/integration/test_entitle_integration.py +0 -0
  159. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/integration/test_epmw_integration.py +0 -0
  160. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/integration/test_epmw_lifecycle.py +0 -0
  161. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/integration/test_pra_integration.py +0 -0
  162. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/integration/test_pra_lifecycle.py +0 -0
  163. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/integration/test_pws_integration.py +0 -0
  164. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/integration/test_pws_lifecycle.py +0 -0
  165. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/pra/__init__.py +0 -0
  166. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/pra/test_client.py +0 -0
  167. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/pra/test_commands.py +0 -0
  168. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/pra-smoke-test.sh +0 -0
  169. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/pra-test-plan.md +0 -0
  170. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/pws/__init__.py +0 -0
  171. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/pws/test_client.py +0 -0
  172. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/pws/test_commands.py +0 -0
  173. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/pws-quick-test-plan.md +0 -0
  174. {bt_cli-0.4.30 → bt_cli-0.4.31}/tests/pws-smoke-test.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  # BT-CLI
2
2
 
3
- BeyondTrust Platform CLI for Password Safe, Entitle, PRA, and EPM Windows. **Version: 0.4.29**
3
+ BeyondTrust Platform CLI for Password Safe, Entitle, PRA, and EPM Windows. **Version: 0.4.31**
4
4
 
5
5
  ## Setup
6
6
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bt-cli
3
- Version: 0.4.30
3
+ Version: 0.4.31
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bt-cli"
7
- version = "0.4.30"
7
+ version = "0.4.31"
8
8
  description = "BeyondTrust Platform CLI (unofficial) - Password Safe, Entitle, PRA, EPM"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,3 +1,3 @@
1
1
  """BeyondTrust Unified Admin CLI."""
2
2
 
3
- __version__ = "0.4.30"
3
+ __version__ = "0.4.31"
@@ -821,16 +821,29 @@ class PasswordSafeMixin:
821
821
  ) -> list[dict[str, Any]]:
822
822
  """List user groups.
823
823
 
824
- Args:
825
- search: Optional name filter
826
-
827
- Returns:
828
- List of user group objects
824
+ /UserGroups does not support pagination. The ``name`` server-side
825
+ param is an exact match, so filtering is handled client-side.
829
826
  """
830
- params = {}
827
+ result = self.get("/UserGroups")
828
+ if isinstance(result, list):
829
+ groups = result
830
+ elif isinstance(result, dict):
831
+ if "GroupID" in result:
832
+ groups = [result]
833
+ else:
834
+ groups = result.get("Data", result.get("results", []))
835
+ else:
836
+ groups = []
837
+
831
838
  if search:
832
- params["name"] = search
833
- return self.paginate("/UserGroups", params=params)
839
+ search_lower = search.lower()
840
+ groups = [
841
+ g for g in groups
842
+ if search_lower in (g.get("Name", "") or "").lower()
843
+ or search_lower in (g.get("Description", "") or "").lower()
844
+ ]
845
+
846
+ return groups
834
847
 
835
848
  def get_user_group(self: "PasswordSafeClient", group_id: int) -> dict[str, Any]:
836
849
  """Get a user group by ID.
@@ -848,13 +861,16 @@ class PasswordSafeMixin:
848
861
  ) -> list[dict[str, Any]]:
849
862
  """Get users in a user group.
850
863
 
851
- Args:
852
- group_id: User group ID
853
-
854
- Returns:
855
- List of user objects (includes ClientID, AccessPolicyID for API users)
864
+ /UserGroups/{id}/Users does not support pagination.
856
865
  """
857
- return self.paginate(f"/UserGroups/{group_id}/Users")
866
+ result = self.get(f"/UserGroups/{group_id}/Users")
867
+ if isinstance(result, list):
868
+ return result
869
+ if isinstance(result, dict):
870
+ if "UserID" in result:
871
+ return [result]
872
+ return result.get("Data", result.get("results", []))
873
+ return []
858
874
 
859
875
  # =========================================================================
860
876
  # Users
@@ -864,20 +880,29 @@ class PasswordSafeMixin:
864
880
  self: "PasswordSafeClient",
865
881
  search: Optional[str] = None,
866
882
  limit: Optional[int] = None,
883
+ include_inactive: bool = False,
867
884
  ) -> list[dict[str, Any]]:
868
885
  """List users.
869
886
 
870
- Args:
871
- search: Optional username search filter (client-side filtering)
872
- limit: Maximum number of results (None for all)
873
-
874
- Returns:
875
- List of user objects
887
+ /Users does not support pagination. The ``username`` server-side
888
+ param is an exact match (returns a single user dict or 404), so
889
+ searching is handled client-side across username/first/last/email.
876
890
  """
877
- # API doesn't support server-side search, so we fetch all and filter client-side
878
- users = self.paginate("/Users")
891
+ params: dict[str, Any] = {}
892
+ if include_inactive:
893
+ params["includeInactive"] = "true"
894
+
895
+ result = self.get("/Users", params=params)
896
+ if isinstance(result, list):
897
+ users = result
898
+ elif isinstance(result, dict):
899
+ if "UserID" in result:
900
+ users = [result]
901
+ else:
902
+ users = result.get("Data", result.get("results", []))
903
+ else:
904
+ users = []
879
905
 
880
- # Apply client-side search filter
881
906
  if search:
882
907
  search_lower = search.lower()
883
908
  users = [
@@ -888,7 +913,6 @@ class PasswordSafeMixin:
888
913
  or search_lower in (u.get("EmailAddress", "") or "").lower()
889
914
  ]
890
915
 
891
- # Apply limit
892
916
  if limit is not None:
893
917
  users = users[:limit]
894
918
 
@@ -179,23 +179,29 @@ def print_roles_table(roles: list[dict], title: str = "Roles") -> None:
179
179
 
180
180
  @app.command("list")
181
181
  def list_users(
182
- search: Optional[str] = typer.Option(None, "--search", "-s", help="Search by username"),
182
+ search: Optional[str] = typer.Option(None, "--search", "-s", help="Search by username (also matches first/last/email)"),
183
183
  limit: int = typer.Option(50, "--limit", "-l", help="Maximum results (default: 50)"),
184
- fetch_all: bool = typer.Option(False, "--all", help="Fetch all results (may be slow)"),
184
+ fetch_all: bool = typer.Option(False, "--all", help="Fetch all results"),
185
+ include_inactive: bool = typer.Option(False, "--include-inactive", help="Include inactive users"),
185
186
  output: str = typer.Option("table", "--output", "-o", help="Output format: table or json"),
186
187
  ) -> None:
187
188
  """List all users.
188
189
 
189
190
  Examples:
190
- bt pws users list # First 50 users
191
- bt pws users list --all # All users
191
+ bt pws users list # First 50 active users
192
+ bt pws users list --all # All active users
193
+ bt pws users list --include-inactive # Include inactive users
192
194
  bt pws users list -s "admin" # Search by username
193
195
  bt pws users list -o json # JSON output
194
196
  """
195
197
  try:
196
198
  with get_client() as client:
197
199
  client.authenticate()
198
- users = client.list_users(search=search, limit=None if fetch_all else limit)
200
+ users = client.list_users(
201
+ search=search,
202
+ limit=None if fetch_all else limit,
203
+ include_inactive=include_inactive,
204
+ )
199
205
 
200
206
  if output == "json":
201
207
  console.print_json(json.dumps(users, default=str))
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
File without changes