bt-cli 0.4.41__tar.gz → 0.4.42__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 (210) hide show
  1. {bt_cli-0.4.41 → bt_cli-0.4.42}/PKG-INFO +1 -1
  2. bt_cli-0.4.42/epml-clients-server-side-filters-plan.md +206 -0
  3. bt_cli-0.4.42/pf-implementation-plan.md +187 -0
  4. {bt_cli-0.4.41 → bt_cli-0.4.42}/pyproject.toml +1 -1
  5. bt_cli-0.4.42/scripts/pf_onboard.py +356 -0
  6. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/__init__.py +1 -1
  7. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/data/skills/epml/SKILL.md +12 -3
  8. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/client/base.py +32 -0
  9. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/__init__.py +2 -0
  10. bt_cli-0.4.42/src/bt_cli/epml/commands/clients.py +190 -0
  11. {bt_cli-0.4.41 → bt_cli-0.4.42}/.claude/skills/bt/SKILL.md +0 -0
  12. {bt_cli-0.4.41 → bt_cli-0.4.42}/.claude/skills/entitle/SKILL.md +0 -0
  13. {bt_cli-0.4.41 → bt_cli-0.4.42}/.claude/skills/epml/SKILL.md +0 -0
  14. {bt_cli-0.4.41 → bt_cli-0.4.42}/.claude/skills/epmw/SKILL.md +0 -0
  15. {bt_cli-0.4.41 → bt_cli-0.4.42}/.claude/skills/pra/SKILL.md +0 -0
  16. {bt_cli-0.4.41 → bt_cli-0.4.42}/.claude/skills/pws/SKILL.md +0 -0
  17. {bt_cli-0.4.41 → bt_cli-0.4.42}/.env.example +0 -0
  18. {bt_cli-0.4.41 → bt_cli-0.4.42}/.github/workflows/ci.yml +0 -0
  19. {bt_cli-0.4.41 → bt_cli-0.4.42}/.github/workflows/release.yml +0 -0
  20. {bt_cli-0.4.41 → bt_cli-0.4.42}/.gitignore +0 -0
  21. {bt_cli-0.4.41 → bt_cli-0.4.42}/CLAUDE.md +0 -0
  22. {bt_cli-0.4.41 → bt_cli-0.4.42}/README.md +0 -0
  23. {bt_cli-0.4.41 → bt_cli-0.4.42}/assets/cli-help.png +0 -0
  24. {bt_cli-0.4.41 → bt_cli-0.4.42}/assets/cli-output.png +0 -0
  25. {bt_cli-0.4.41 → bt_cli-0.4.42}/bt-cli.spec +0 -0
  26. {bt_cli-0.4.41 → bt_cli-0.4.42}/bt_entry.py +0 -0
  27. {bt_cli-0.4.41 → bt_cli-0.4.42}/epml-implementation-plan.md +0 -0
  28. {bt_cli-0.4.41 → bt_cli-0.4.42}/scripts/bt_entry.py +0 -0
  29. {bt_cli-0.4.41 → bt_cli-0.4.42}/scripts/sync-package-data.sh +0 -0
  30. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/cli.py +0 -0
  31. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/commands/__init__.py +0 -0
  32. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/commands/configure.py +0 -0
  33. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/commands/learn.py +0 -0
  34. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/commands/quick.py +0 -0
  35. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/core/__init__.py +0 -0
  36. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/core/auth.py +0 -0
  37. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/core/client.py +0 -0
  38. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/core/config.py +0 -0
  39. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/core/config_file.py +0 -0
  40. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/core/csv_utils.py +0 -0
  41. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/core/errors.py +0 -0
  42. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/core/output.py +0 -0
  43. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/core/prompts.py +0 -0
  44. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/core/rest_debug.py +0 -0
  45. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/data/CLAUDE.md +0 -0
  46. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/data/__init__.py +0 -0
  47. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/data/skills/bt/SKILL.md +0 -0
  48. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/data/skills/entitle/SKILL.md +0 -0
  49. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/data/skills/epmw/SKILL.md +0 -0
  50. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/data/skills/pra/SKILL.md +0 -0
  51. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/data/skills/pws/SKILL.md +0 -0
  52. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/__init__.py +0 -0
  53. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/client/__init__.py +0 -0
  54. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/client/base.py +0 -0
  55. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/commands/__init__.py +0 -0
  56. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/commands/accounts.py +0 -0
  57. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/commands/applications.py +0 -0
  58. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/commands/auth.py +0 -0
  59. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/commands/bundles.py +0 -0
  60. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/commands/integrations.py +0 -0
  61. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/commands/permissions.py +0 -0
  62. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/commands/policies.py +0 -0
  63. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/commands/requests.py +0 -0
  64. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/commands/resources.py +0 -0
  65. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/commands/roles.py +0 -0
  66. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/commands/users.py +0 -0
  67. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/commands/workflows.py +0 -0
  68. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/models/__init__.py +0 -0
  69. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/models/bundle.py +0 -0
  70. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/models/common.py +0 -0
  71. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/models/integration.py +0 -0
  72. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/models/permission.py +0 -0
  73. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/models/policy.py +0 -0
  74. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/models/resource.py +0 -0
  75. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/models/role.py +0 -0
  76. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/models/user.py +0 -0
  77. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/entitle/models/workflow.py +0 -0
  78. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/__init__.py +0 -0
  79. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/client/__init__.py +0 -0
  80. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/audit.py +0 -0
  81. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/auth.py +0 -0
  82. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/client_pkg.py +0 -0
  83. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/external_apis.py +0 -0
  84. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/hosts.py +0 -0
  85. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/iolog.py +0 -0
  86. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/license.py +0 -0
  87. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/quick.py +0 -0
  88. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/rbp_cmdgrps.py +0 -0
  89. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/rbp_entitlement.py +0 -0
  90. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/rbp_hostgrps.py +0 -0
  91. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/rbp_policy.py +0 -0
  92. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/rbp_roles.py +0 -0
  93. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/rbp_tests.py +0 -0
  94. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/rbp_tmdategrps.py +0 -0
  95. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/rbp_tx.py +0 -0
  96. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/rbp_usergrps.py +0 -0
  97. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/settings.py +0 -0
  98. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/siems.py +0 -0
  99. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/commands/users.py +0 -0
  100. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epml/models/__init__.py +0 -0
  101. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/__init__.py +0 -0
  102. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/client/__init__.py +0 -0
  103. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/client/base.py +0 -0
  104. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/commands/__init__.py +0 -0
  105. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/commands/audits.py +0 -0
  106. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/commands/auth.py +0 -0
  107. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/commands/computers.py +0 -0
  108. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/commands/events.py +0 -0
  109. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/commands/groups.py +0 -0
  110. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/commands/policies.py +0 -0
  111. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/commands/quick.py +0 -0
  112. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/commands/requests.py +0 -0
  113. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/commands/roles.py +0 -0
  114. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/commands/tasks.py +0 -0
  115. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/commands/users.py +0 -0
  116. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/epmw/models/__init__.py +0 -0
  117. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/__init__.py +0 -0
  118. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/client/__init__.py +0 -0
  119. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/client/base.py +0 -0
  120. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/commands/__init__.py +0 -0
  121. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/commands/auth.py +0 -0
  122. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/commands/import_export.py +0 -0
  123. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/commands/jump_clients.py +0 -0
  124. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/commands/jump_groups.py +0 -0
  125. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/commands/jump_items.py +0 -0
  126. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/commands/jumpoints.py +0 -0
  127. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/commands/policies.py +0 -0
  128. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/commands/quick.py +0 -0
  129. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/commands/teams.py +0 -0
  130. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/commands/users.py +0 -0
  131. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/commands/vault.py +0 -0
  132. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/models/__init__.py +0 -0
  133. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/models/common.py +0 -0
  134. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/models/jump_client.py +0 -0
  135. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/models/jump_group.py +0 -0
  136. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/models/jump_item.py +0 -0
  137. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/models/jumpoint.py +0 -0
  138. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/models/team.py +0 -0
  139. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/models/user.py +0 -0
  140. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pra/models/vault.py +0 -0
  141. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/__init__.py +0 -0
  142. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/client/__init__.py +0 -0
  143. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/client/base.py +0 -0
  144. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/client/beyondinsight.py +0 -0
  145. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/client/passwordsafe.py +0 -0
  146. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/__init__.py +0 -0
  147. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/accounts.py +0 -0
  148. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/assets.py +0 -0
  149. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/attributes.py +0 -0
  150. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/auth.py +0 -0
  151. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/clouds.py +0 -0
  152. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/config.py +0 -0
  153. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/credentials.py +0 -0
  154. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/databases.py +0 -0
  155. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/directories.py +0 -0
  156. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/functional.py +0 -0
  157. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/import_export.py +0 -0
  158. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/platforms.py +0 -0
  159. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/quick.py +0 -0
  160. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/search.py +0 -0
  161. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/secrets.py +0 -0
  162. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/systems.py +0 -0
  163. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/users.py +0 -0
  164. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/commands/workgroups.py +0 -0
  165. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/config.py +0 -0
  166. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/models/__init__.py +0 -0
  167. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/models/account.py +0 -0
  168. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/models/asset.py +0 -0
  169. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/models/common.py +0 -0
  170. {bt_cli-0.4.41 → bt_cli-0.4.42}/src/bt_cli/pws/models/system.py +0 -0
  171. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/__init__.py +0 -0
  172. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/conftest.py +0 -0
  173. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/core/__init__.py +0 -0
  174. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/core/test_auth.py +0 -0
  175. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/core/test_config.py +0 -0
  176. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/core/test_errors.py +0 -0
  177. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/core/test_rest_debug.py +0 -0
  178. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/entitle/__init__.py +0 -0
  179. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/entitle/test_client.py +0 -0
  180. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/entitle/test_commands.py +0 -0
  181. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/entitle-smoke-test.sh +0 -0
  182. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/epml/__init__.py +0 -0
  183. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/epml/test_client.py +0 -0
  184. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/epml/test_commands.py +0 -0
  185. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/epmw/__init__.py +0 -0
  186. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/epmw/test_client.py +0 -0
  187. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/epmw/test_commands.py +0 -0
  188. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/epmw-quick-test-plan.md +0 -0
  189. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/fixtures/__init__.py +0 -0
  190. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/fixtures/responses.py +0 -0
  191. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/integration/__init__.py +0 -0
  192. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/integration/conftest.py +0 -0
  193. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/integration/helpers.py +0 -0
  194. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/integration/test_entitle_integration.py +0 -0
  195. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/integration/test_epmw_integration.py +0 -0
  196. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/integration/test_epmw_lifecycle.py +0 -0
  197. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/integration/test_pra_integration.py +0 -0
  198. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/integration/test_pra_lifecycle.py +0 -0
  199. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/integration/test_pws_integration.py +0 -0
  200. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/integration/test_pws_lifecycle.py +0 -0
  201. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/pra/__init__.py +0 -0
  202. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/pra/test_client.py +0 -0
  203. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/pra/test_commands.py +0 -0
  204. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/pra-smoke-test.sh +0 -0
  205. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/pra-test-plan.md +0 -0
  206. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/pws/__init__.py +0 -0
  207. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/pws/test_client.py +0 -0
  208. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/pws/test_commands.py +0 -0
  209. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/pws-quick-test-plan.md +0 -0
  210. {bt_cli-0.4.41 → bt_cli-0.4.42}/tests/pws-smoke-test.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bt-cli
3
- Version: 0.4.41
3
+ Version: 0.4.42
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
@@ -0,0 +1,206 @@
1
+ # Plan: Server-side filters + pagination on `bt epml clients list`
2
+
3
+ ## Goal
4
+
5
+ Today `bt epml clients list` fetches the **entire** license-client inventory in one shot and filters client-side. The EPMLC API at `GET /api/epml/license/clients` supports server-side pagination, sorting, date-windowing, and pattern matching (per the [reference](https://docs.beyondtrust.com/epm-l/reference/epmlgetlicenseclients)). We don't expose any of that. On a tenant with thousands of clients it's slow and unnecessarily heavy.
6
+
7
+ This plan adds the missing flags, keeps current behavior working, and tightens the listing for large tenants.
8
+
9
+ ## Current vs server
10
+
11
+ | Server query param | Type | Today's CLI | Notes |
12
+ |---|---|---|---|
13
+ | `limit` | int | ❌ missing | server-side page size |
14
+ | `offset` | int | ❌ missing | server-side page offset |
15
+ | `older` | int (epoch) | ❌ missing | last-updated **before** |
16
+ | `newer` | int (epoch) | ❌ missing | last-updated **since** |
17
+ | `order` | enum (`uuid`/`fqdn`/`addr`/`lastupdated`/`retired`) | ❌ missing | sort field |
18
+ | `direction` | enum (`asc`/`desc`) | ❌ missing | sort direction |
19
+ | `fqdn` | string (wildcard) | ⚠️ client-side substring | server-side wildcard match |
20
+ | `addr` | string (wildcard) | ❌ missing | server-side wildcard match |
21
+ | `exclude_retired` | bool | ⚠️ client-side filter (`--include-retired` flips) | server-side equivalent |
22
+ | `--component` | n/a | ✓ client-side only | NOT in server API; keep local |
23
+
24
+ Source method: `EPMLClient.list_license_clients(host_id)` at `src/bt_cli/epml/client/base.py:237`.
25
+ CLI command: `list_clients` at `src/bt_cli/epml/commands/clients.py:56`.
26
+
27
+ ## Proposed CLI surface
28
+
29
+ ```
30
+ bt epml clients list [OPTIONS]
31
+
32
+ --host, -H PMUL host id (uses host-scoped path)
33
+ --component, -c License bucket filter (CLIENT-SIDE; server doesn't have this)
34
+ {RBPClnts, PBULPolClnts, FIMClnts, SudoPolClnts}
35
+ --fqdn TEXT FQDN wildcard (server-side; supports * and ?)
36
+ --addr TEXT Address wildcard (server-side; supports * and ?)
37
+ --include-retired Include retired clients (default: hidden via server's
38
+ exclude_retired=true; flag flips it to false)
39
+ --since TEXT Only clients updated since this time
40
+ (accepts ISO-8601, "1h", "7d", or epoch)
41
+ --before TEXT Only clients updated before this time (same formats)
42
+ --order [uuid|fqdn|addr|lastupdated|retired]
43
+ Sort field (default: fqdn)
44
+ --direction [asc|desc] Sort direction (default: asc)
45
+ --limit, -n INTEGER Page size (default: 200; max: server-defined)
46
+ --all Iterate all pages until exhausted (overrides --limit
47
+ for the per-call value but pages internally)
48
+ --output, -o table | json
49
+ ```
50
+
51
+ ### Flag-naming notes
52
+
53
+ - `--since` / `--before` are friendlier than `--newer` / `--older`. Accept ISO-8601, relative durations (`1h`, `7d`, `30m`), and raw epoch ints. Convert to epoch before the API call.
54
+ - `--addr` mirrors the API param name verbatim (server already speaks wildcards there).
55
+ - `--component` stays as a **client-side** filter with a warning in `--help` since the server doesn't support it.
56
+ - Drop the current `--fqdn` substring behavior in favor of the server's wildcard matcher. If the user passes a plain string like `web-01`, transparently wrap in `*web-01*` so the substring UX is preserved. Document the auto-wrap behavior.
57
+ - Default to `--exclude-retired=true` (matches today's UX where retired clients are hidden unless `--include-retired` is passed). Done via flipping the server param.
58
+
59
+ ## Implementation steps
60
+
61
+ ### 1. Extend `EPMLClient.list_license_clients`
62
+
63
+ ```python
64
+ def list_license_clients(
65
+ self,
66
+ host_id: Optional[int] = None,
67
+ *,
68
+ limit: Optional[int] = None,
69
+ offset: Optional[int] = None,
70
+ older: Optional[int] = None, # epoch
71
+ newer: Optional[int] = None, # epoch
72
+ order: Optional[str] = None, # uuid|fqdn|addr|lastupdated|retired
73
+ direction: Optional[str] = None, # asc|desc
74
+ fqdn: Optional[str] = None,
75
+ addr: Optional[str] = None,
76
+ exclude_retired: Optional[bool] = None,
77
+ ) -> Dict[str, Any]:
78
+ """GET license clients with full server-side filter set."""
79
+ params: Dict[str, Any] = {}
80
+ for k, v in (
81
+ ("limit", limit), ("offset", offset),
82
+ ("older", older), ("newer", newer),
83
+ ("order", order), ("direction", direction),
84
+ ("fqdn", fqdn), ("addr", addr),
85
+ ("exclude_retired", exclude_retired),
86
+ ):
87
+ if v is not None:
88
+ params[k] = v
89
+ if host_id is not None:
90
+ return self.get(f"/api/pbul/{host_id}/licenseinfo/clients", params=params or None)
91
+ return self.get("/api/epml/license/clients", params=params or None)
92
+ ```
93
+
94
+ Backwards-compatible: existing call sites pass no kwargs.
95
+
96
+ ### 2. Add a paginating helper for `--all`
97
+
98
+ ```python
99
+ def iter_license_clients(
100
+ self,
101
+ page_size: int = 200,
102
+ **filters,
103
+ ) -> Iterator[Dict[str, Any]]:
104
+ """Yield every matching client across as many pages as needed."""
105
+ offset = 0
106
+ while True:
107
+ page = self.list_license_clients(limit=page_size, offset=offset, **filters)
108
+ rows = (page.get("Data") or page.get("data") or []) if isinstance(page, dict) else []
109
+ if not rows:
110
+ return
111
+ yield from rows
112
+ if len(rows) < page_size:
113
+ return
114
+ offset += page_size
115
+ ```
116
+
117
+ ### 3. Update the CLI command
118
+
119
+ In `src/bt_cli/epml/commands/clients.py`:
120
+ - Add the new typer options.
121
+ - Parse `--since`/`--before` to epoch using a small helper (accept `1h`/`7d`/`30m` patterns + ISO-8601 + raw integer).
122
+ - Auto-wrap plain `--fqdn` values in `*` if no glob char present (preserves substring UX).
123
+ - Branch on `--all`: paginate via `iter_license_clients`, otherwise single page.
124
+ - Keep `--component` as a post-filter (server doesn't support it). Document this in the option help text.
125
+
126
+ ### 4. Time-spec parser
127
+
128
+ Small new helper in `core/timeparse.py` (or co-located if there's no shared util module):
129
+
130
+ ```python
131
+ def parse_time_to_epoch(s: str) -> int:
132
+ """Accept '1h', '7d', '30m', ISO-8601, or raw epoch int. Return UTC epoch."""
133
+ ...
134
+ ```
135
+
136
+ Used by both `--since` and `--before`. Tests cover each input form.
137
+
138
+ ### 5. Output formatting
139
+
140
+ No change needed — `_flatten_user`-style helpers already handle the row shape. Only thing to verify: when paginating with `--all`, table rendering streams or buffers? For now buffer (dataset typically <10k rows; rich.Table handles fine). Document the trade-off.
141
+
142
+ ### 6. Tests
143
+
144
+ In `tests/epml/test_clients.py` (or wherever the existing client tests live):
145
+
146
+ - `test_list_license_clients_passes_server_params` — respx-mock, assert query string carries all the params we set
147
+ - `test_list_license_clients_no_params_unchanged` — backwards compat: no kwargs → no `params` arg → same URL as today
148
+ - `test_iter_license_clients_paginates` — three pages of 200 + a partial; verify offset progression and termination
149
+ - `test_iter_license_clients_terminates_on_short_page`
150
+ - `test_clients_list_command_auto_wraps_fqdn_substring` — `--fqdn web-01` becomes `*web-01*`; `--fqdn '*web*'` is passed through
151
+ - `test_clients_list_command_since_relative` — `--since 1h` parses correctly
152
+ - `test_clients_list_command_since_iso` — ISO-8601 form
153
+ - `test_clients_list_component_is_post_filter` — server returns 100 rows; `--component RBPClnts` filters client-side
154
+ - `test_parse_time_to_epoch_accepts_*` — unit tests for the helper
155
+
156
+ ### 7. Skill + docs
157
+
158
+ Update `src/bt_cli/data/skills/epml/SKILL.md`:
159
+ - The "License clients" section already exists. Replace with the new flag set.
160
+ - Add a one-liner about `--all` and the auto-wrap fqdn behavior.
161
+
162
+ Update `src/bt_cli/data/CLAUDE.md` if it has a clients line.
163
+
164
+ Update `btcli/CLAUDE.md`'s API quirks table — add a note that EPML clients endpoint supports server-side pagination and sorting.
165
+
166
+ ## Backwards compatibility
167
+
168
+ - `--component`, `--fqdn`, `--include-retired`, `--host`, `--output` all keep their current meaning.
169
+ - `--fqdn`'s substring semantics preserved via the auto-wrap.
170
+ - Default sort changes from "whatever the server returned" to `fqdn asc` — small cosmetic change; document it.
171
+
172
+ ## Edge cases
173
+
174
+ - **Empty Data array on a non-zero `Total`** — server bug or a filter that removed everything; treat as "end of pages" in `iter_license_clients`.
175
+ - **Server caps `limit`** — if the server returns fewer rows than asked, that's normal pagination, not necessarily end-of-data. The "fewer than page_size → done" heuristic is good enough today but could need revisiting.
176
+ - **`--all` with `--limit`** — `--limit` becomes the per-call page size; `--all` toggles iteration. Document.
177
+ - **Wildcard escape** — server interprets `*` and `?`. If a user has a literal `*` in an fqdn (unlikely but possible), no escape syntax exists. Note in help text.
178
+
179
+ ## Verification
180
+
181
+ ```bash
182
+ # Single page, default
183
+ bt epml clients list
184
+
185
+ # Server-side fqdn wildcard
186
+ bt epml clients list --fqdn 'web-*'
187
+
188
+ # Server-side address wildcard
189
+ bt epml clients list --addr '10.0.0.*'
190
+
191
+ # Recent activity
192
+ bt epml clients list --since 1h
193
+ bt epml clients list --since 2026-05-01T00:00:00Z
194
+
195
+ # Sorted
196
+ bt epml clients list --order lastupdated --direction desc --limit 20
197
+
198
+ # Full sweep
199
+ bt epml clients list --all -o json | jq '.Data | length'
200
+ ```
201
+
202
+ ## Out of scope
203
+
204
+ - `bt epml clients retire` flag additions (separate endpoint; can mirror later if needed).
205
+ - Changing the `host-scoped` URL behavior (`/api/pbul/{hostid}/licenseinfo/clients`) — current logic keeps it.
206
+ - Streaming output for `--all` (buffer for now).
@@ -0,0 +1,187 @@
1
+ # Plan: Add Pathfinder (PF) Product to BeyondTrust CLI
2
+
3
+ ## Context
4
+
5
+ The BeyondTrust CLI (`bt-cli`) currently supports 4 products: PWS, PRA, Entitle, and EPMW. The Pathfinder platform (internally "Nomine Authentication API") handles identity management — users, machine-to-machine auth, SAML providers, site/product access control, tokens, and auditing. Its OpenAPI spec lives at `/projects/reference/apidoc/pf/swagger.yaml` (67+ endpoints, 80+ schemas). This plan adds full PF support following the established patterns.
6
+
7
+ ## Command Tree: `bt pf`
8
+
9
+ ```
10
+ bt pf
11
+ auth test|status
12
+ users list|get|me|access|my-access|update|delete|bulk-delete|invite|cancel-invite
13
+ machines list|get|create|delete|activate
14
+ auditing list
15
+ saml list|create|import|update|delete
16
+ product-access list|org|org-defaults|grant|revoke|grant-org|revoke-org
17
+ site-access list|org|grant|revoke|grant-org|revoke-org
18
+ tokens list|create|delete
19
+ mcp-tokens list|create|delete
20
+ mfa enable|disable|disable-user|count
21
+ ```
22
+
23
+ ## Implementation Phases
24
+
25
+ ### Phase 1: Foundation (core infra + auth test)
26
+
27
+ **1a. Add `MachineAuth` strategy** — `src/bt_cli/core/auth.py`
28
+ - New class: `MachineAuth(AuthStrategy)` with `machine_id`, `machine_secret`
29
+ - `authenticate()`: POST `/bt.identity/Machine/AccessToken` with JSON `{machineId, machineSecret}`
30
+ - Returns `{access_token, token_type, expires_in}` → sets Bearer token
31
+ - No sign_out needed (JWT is stateless)
32
+
33
+ **1b. Add `PFConfig`** — `src/bt_cli/core/config.py`
34
+ - Dataclass: `PFConfig(ProductConfig)` with `machine_id: str`, `machine_secret: str`
35
+ - `load_pf_config()` function — env vars: `BT_PF_API_URL`, `BT_PF_MACHINE_ID`, `BT_PF_MACHINE_SECRET`, `BT_PF_VERIFY_SSL`, `BT_PF_TIMEOUT`
36
+ - Add `"pf": load_pf_config` to `load_config()` dispatcher
37
+
38
+ **1c. Update config_file.py** — `src/bt_cli/core/config_file.py`
39
+ - Add `"pf"` entry to `PRODUCTS` dict (fields: api_url, machine_id, machine_secret, verify_ssl, timeout)
40
+
41
+ **1d. Create module structure:**
42
+ - `src/bt_cli/pf/__init__.py`
43
+ - `src/bt_cli/pf/client/__init__.py` — exports `PFClient, get_client`
44
+ - `src/bt_cli/pf/client/base.py` — client with context manager, token caching, HTTP methods
45
+ - `src/bt_cli/pf/commands/__init__.py` — registers all sub-typer apps
46
+ - `src/bt_cli/pf/commands/auth.py` — `test` (call list_users limit=1) and `status`
47
+ - `src/bt_cli/pf/models/__init__.py`
48
+ - `src/bt_cli/pf/models/common.py` — `CommandResponse` base model
49
+
50
+ **1e. Register in CLI** — `src/bt_cli/cli.py`
51
+ - Add `_get_pf_app()` lazy loader (after line 83)
52
+ - Add `app.add_typer()` registration (after line 124)
53
+ - Update help text in `main_callback` docstring to include Pathfinder
54
+
55
+ **Verify:** `bt pf auth test` connects and authenticates.
56
+
57
+ ### Phase 2: Core Resources (users, machines, auditing)
58
+
59
+ **2a. Models:**
60
+ - `models/user.py` — `NomineUser` (id, email, firstName, lastName, active, mfaEnabled)
61
+ - `models/machine.py` — `Machine` (id, activationToken, active, tenantId, organizationId, timestamps)
62
+ - `models/audit.py` — `AuditRecord` (id, userId, organizationId, auditTimeUtc, description, metadata)
63
+
64
+ **2b. Client methods** in `pf/client/base.py`:
65
+ - Users: `list_users()`, `get_user_info()`, `get_user_access()`, `get_my_access()`, `update_user()`, `delete_user()`, `bulk_delete_users()`, `invite_user()`, `cancel_invitation()`
66
+ - Machines: `list_machines()`, `get_machine()`, `create_machine()`, `delete_machine()`, `activate_machine()`
67
+ - Auditing: `list_audit_records()`
68
+
69
+ **2c. Commands:**
70
+ - `commands/users.py` — 10 subcommands
71
+ - `commands/machines.py` — 5 subcommands
72
+ - `commands/auditing.py` — 1 subcommand (list with date/email/description filters)
73
+
74
+ **API quirks:**
75
+ - `GET /api/Users` returns plain array (no pagination wrapper)
76
+ - `GET /api/Machine` returns only UUIDs in `machines[]`, need `GET /api/Machine/{id}` for details
77
+ - Machine create returns `activationToken` (30min TTL) → `activate` exchanges code for `machineSecret`
78
+
79
+ ### Phase 3: Access Management (product-access, site-access, saml)
80
+
81
+ **3a. Models:**
82
+ - `models/access.py` — `ProductAccessRule`, `SiteAccessRule`
83
+ - `models/saml_provider.py` — `SamlProvider`
84
+
85
+ **3b. Client methods:**
86
+ - Product access: `list_product_access()`, `list_org_product_access()`, `get_org_defaults()`, `grant_product_access()`, `revoke_product_access()`, `grant_org_product_access()`, `revoke_org_product_access()`
87
+ - Site access: `list_site_access()`, `list_org_site_access()`, `grant_site_access()`, `revoke_site_access()`, `grant_org_site_access()`, `revoke_org_site_access()`
88
+ - SAML: `list_saml_providers()`, `create_saml_provider()`, `import_saml_provider()`, `update_saml_provider()`, `delete_saml_provider()`
89
+
90
+ **3c. Commands:**
91
+ - `commands/product_access.py` — 7 subcommands
92
+ - `commands/site_access.py` — 6 subcommands
93
+ - `commands/saml.py` — 5 subcommands (import reads XML file from disk)
94
+
95
+ ### Phase 4: Tokens & MFA
96
+
97
+ **4a. Models:**
98
+ - `models/token.py` — `UserPersonalAccessToken`, `UserMcpAccessToken`
99
+
100
+ **4b. Commands:**
101
+ - `commands/tokens.py` — list, create (--expiration-days), delete
102
+ - `commands/mcp_tokens.py` — list, create (--expiration-days), delete
103
+ - `commands/mfa.py` — enable (--token-code), disable, disable-user, count
104
+
105
+ ### Phase 5: CLI Integration
106
+
107
+ Update `src/bt_cli/cli.py`:
108
+ - Add `_test_pf_connection()` → call `get_user_info()` for whoami
109
+ - Add PF to `whoami` command results
110
+ - Add PF section to `tree_command` + add `"pf"` to valid product list
111
+ - Add all PF commands to `_get_all_commands()`
112
+ - Update `skills` command help text
113
+
114
+ ### Phase 6: Tests
115
+
116
+ **6a. Fixtures** — `tests/conftest.py`: add `mock_pf_config`, `pf_env_vars`
117
+ **6b. Mock responses** — `tests/fixtures/responses.py`: add `PF_*` constants
118
+ **6c. Test files:**
119
+ - `tests/pf/__init__.py`
120
+ - `tests/pf/test_client.py` — client unit tests with `@respx.mock`
121
+ - `tests/pf/test_commands.py` — CLI command tests with patched config/client
122
+
123
+ ### Phase 7: Skill File
124
+
125
+ - `src/bt_cli/data/skills/pf/SKILL.md` — command reference, destructive ops warnings, workflow examples, API quirks
126
+ - Update `btcli/CLAUDE.md` and `src/bt_cli/data/CLAUDE.md` to include PF
127
+
128
+ ## Files to Create (27 files)
129
+
130
+ | File | Purpose |
131
+ |------|---------|
132
+ | `src/bt_cli/pf/__init__.py` | Package marker |
133
+ | `src/bt_cli/pf/client/__init__.py` | Export PFClient, get_client |
134
+ | `src/bt_cli/pf/client/base.py` | HTTP client with Machine auth token caching |
135
+ | `src/bt_cli/pf/commands/__init__.py` | Register all command sub-apps |
136
+ | `src/bt_cli/pf/commands/auth.py` | test, status |
137
+ | `src/bt_cli/pf/commands/users.py` | User management (10 commands) |
138
+ | `src/bt_cli/pf/commands/machines.py` | Machine registration (5 commands) |
139
+ | `src/bt_cli/pf/commands/auditing.py` | Audit log listing |
140
+ | `src/bt_cli/pf/commands/saml.py` | SAML provider CRUD + import |
141
+ | `src/bt_cli/pf/commands/product_access.py` | Product access rules (7 commands) |
142
+ | `src/bt_cli/pf/commands/site_access.py` | Site access rules (6 commands) |
143
+ | `src/bt_cli/pf/commands/tokens.py` | Personal access tokens |
144
+ | `src/bt_cli/pf/commands/mcp_tokens.py` | MCP access tokens |
145
+ | `src/bt_cli/pf/commands/mfa.py` | MFA management |
146
+ | `src/bt_cli/pf/models/__init__.py` | Package marker |
147
+ | `src/bt_cli/pf/models/common.py` | CommandResponse base |
148
+ | `src/bt_cli/pf/models/user.py` | NomineUser |
149
+ | `src/bt_cli/pf/models/machine.py` | Machine |
150
+ | `src/bt_cli/pf/models/audit.py` | AuditRecord |
151
+ | `src/bt_cli/pf/models/saml_provider.py` | SamlProvider |
152
+ | `src/bt_cli/pf/models/access.py` | ProductAccessRule, SiteAccessRule |
153
+ | `src/bt_cli/pf/models/token.py` | PAT, MCP token models |
154
+ | `tests/pf/__init__.py` | Test package |
155
+ | `tests/pf/test_client.py` | Client unit tests |
156
+ | `tests/pf/test_commands.py` | CLI command tests |
157
+ | `src/bt_cli/data/skills/pf/SKILL.md` | Claude Code skill |
158
+
159
+ ## Files to Modify (7 files)
160
+
161
+ | File | Change |
162
+ |------|--------|
163
+ | `src/bt_cli/core/auth.py` | Add `MachineAuth` class (~30 lines) |
164
+ | `src/bt_cli/core/config.py` | Add `PFConfig` dataclass + `load_pf_config()` (~40 lines) |
165
+ | `src/bt_cli/core/config_file.py` | Add `"pf"` to PRODUCTS dict (~15 lines) |
166
+ | `src/bt_cli/cli.py` | Lazy loader, registration, whoami, tree, find, help text |
167
+ | `tests/conftest.py` | Add `mock_pf_config`, `pf_env_vars` fixtures |
168
+ | `tests/fixtures/responses.py` | Add `PF_*` mock response constants |
169
+ | `btcli/CLAUDE.md` + `src/bt_cli/data/CLAUDE.md` | Add PF to docs |
170
+
171
+ ## Key Design Decisions
172
+
173
+ 1. **Auth: New `MachineAuth` strategy** — PF uses `machineId`+`machineSecret` → JWT, not standard OAuth form-encoded flow. Clean separation.
174
+ 2. **No path prefix** — PF endpoints are at `/api/*` and `/bt.identity/*` directly off base URL (unlike PWS `/api/public/v3` or Entitle `/public/v1`).
175
+ 3. **Pagination** — PF uses `page`/`pageSize` but some endpoints (GET /api/Users) return plain arrays. Client handles both.
176
+ 4. **Skip browser/internal endpoints** — `/bt.identity/Authentication/*`, `/api/noauth/*`, `/api/Support/*`, `/Test/*` are not CLI-appropriate.
177
+ 5. **Env var prefix: `BT_PF_`** — Consistent with `BT_PWS_`, `BT_PRA_`, etc.
178
+
179
+ ## Verification
180
+
181
+ 1. `bt pf auth test` — connects with machine credentials
182
+ 2. `bt pf users list` / `bt pf users me` — reads user data
183
+ 3. `bt pf machines list` — lists registered machines
184
+ 4. `bt tree pf` — shows full command tree
185
+ 5. `bt whoami` — includes PF status
186
+ 6. `pytest tests/pf/ -v` — all unit tests pass
187
+ 7. `bt find saml` — finds PF SAML commands
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bt-cli"
7
- version = "0.4.41"
7
+ version = "0.4.42"
8
8
  description = "BeyondTrust Platform CLI (unofficial) - Password Safe, Entitle, PRA, EPM"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"