bt-cli 0.4.47__tar.gz → 0.4.49__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 (228) hide show
  1. {bt_cli-0.4.47 → bt_cli-0.4.49}/CLAUDE.md +1 -1
  2. {bt_cli-0.4.47 → bt_cli-0.4.49}/PKG-INFO +1 -1
  3. {bt_cli-0.4.47 → bt_cli-0.4.49}/pyproject.toml +1 -1
  4. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/__init__.py +1 -1
  5. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/data/skills/secrets/SKILL.md +15 -3
  6. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/secrets/commands/dynamic.py +69 -10
  7. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/secrets/test_commands.py +97 -0
  8. {bt_cli-0.4.47 → bt_cli-0.4.49}/.claude/skills/bt/SKILL.md +0 -0
  9. {bt_cli-0.4.47 → bt_cli-0.4.49}/.claude/skills/entitle/SKILL.md +0 -0
  10. {bt_cli-0.4.47 → bt_cli-0.4.49}/.claude/skills/epml/SKILL.md +0 -0
  11. {bt_cli-0.4.47 → bt_cli-0.4.49}/.claude/skills/epmw/SKILL.md +0 -0
  12. {bt_cli-0.4.47 → bt_cli-0.4.49}/.claude/skills/pra/SKILL.md +0 -0
  13. {bt_cli-0.4.47 → bt_cli-0.4.49}/.claude/skills/pws/SKILL.md +0 -0
  14. {bt_cli-0.4.47 → bt_cli-0.4.49}/.env.example +0 -0
  15. {bt_cli-0.4.47 → bt_cli-0.4.49}/.github/workflows/ci.yml +0 -0
  16. {bt_cli-0.4.47 → bt_cli-0.4.49}/.github/workflows/release.yml +0 -0
  17. {bt_cli-0.4.47 → bt_cli-0.4.49}/.gitignore +0 -0
  18. {bt_cli-0.4.47 → bt_cli-0.4.49}/README.md +0 -0
  19. {bt_cli-0.4.47 → bt_cli-0.4.49}/assets/cli-help.png +0 -0
  20. {bt_cli-0.4.47 → bt_cli-0.4.49}/assets/cli-output.png +0 -0
  21. {bt_cli-0.4.47 → bt_cli-0.4.49}/bt-cli.spec +0 -0
  22. {bt_cli-0.4.47 → bt_cli-0.4.49}/bt_entry.py +0 -0
  23. {bt_cli-0.4.47 → bt_cli-0.4.49}/epml-clients-server-side-filters-plan.md +0 -0
  24. {bt_cli-0.4.47 → bt_cli-0.4.49}/epml-implementation-plan.md +0 -0
  25. {bt_cli-0.4.47 → bt_cli-0.4.49}/pf-implementation-plan.md +0 -0
  26. {bt_cli-0.4.47 → bt_cli-0.4.49}/scripts/bt_entry.py +0 -0
  27. {bt_cli-0.4.47 → bt_cli-0.4.49}/scripts/pf_onboard.py +0 -0
  28. {bt_cli-0.4.47 → bt_cli-0.4.49}/scripts/sync-package-data.sh +0 -0
  29. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/cli.py +0 -0
  30. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/commands/__init__.py +0 -0
  31. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/commands/configure.py +0 -0
  32. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/commands/learn.py +0 -0
  33. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/commands/quick.py +0 -0
  34. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/core/__init__.py +0 -0
  35. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/core/auth.py +0 -0
  36. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/core/client.py +0 -0
  37. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/core/config.py +0 -0
  38. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/core/config_file.py +0 -0
  39. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/core/csv_utils.py +0 -0
  40. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/core/errors.py +0 -0
  41. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/core/output.py +0 -0
  42. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/core/prompts.py +0 -0
  43. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/core/rest_debug.py +0 -0
  44. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/data/CLAUDE.md +0 -0
  45. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/data/__init__.py +0 -0
  46. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/data/skills/bt/SKILL.md +0 -0
  47. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/data/skills/entitle/SKILL.md +0 -0
  48. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/data/skills/epml/SKILL.md +0 -0
  49. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/data/skills/epmw/SKILL.md +0 -0
  50. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/data/skills/pra/SKILL.md +0 -0
  51. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/data/skills/pws/SKILL.md +0 -0
  52. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/__init__.py +0 -0
  53. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/client/__init__.py +0 -0
  54. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/client/base.py +0 -0
  55. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/commands/__init__.py +0 -0
  56. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/commands/accounts.py +0 -0
  57. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/commands/applications.py +0 -0
  58. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/commands/auth.py +0 -0
  59. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/commands/bundles.py +0 -0
  60. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/commands/integrations.py +0 -0
  61. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/commands/permissions.py +0 -0
  62. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/commands/policies.py +0 -0
  63. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/commands/requests.py +0 -0
  64. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/commands/resources.py +0 -0
  65. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/commands/roles.py +0 -0
  66. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/commands/users.py +0 -0
  67. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/commands/workflows.py +0 -0
  68. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/models/__init__.py +0 -0
  69. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/models/bundle.py +0 -0
  70. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/models/common.py +0 -0
  71. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/models/integration.py +0 -0
  72. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/models/permission.py +0 -0
  73. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/models/policy.py +0 -0
  74. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/models/resource.py +0 -0
  75. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/models/role.py +0 -0
  76. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/models/user.py +0 -0
  77. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/entitle/models/workflow.py +0 -0
  78. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/__init__.py +0 -0
  79. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/client/__init__.py +0 -0
  80. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/client/base.py +0 -0
  81. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/__init__.py +0 -0
  82. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/audit.py +0 -0
  83. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/auth.py +0 -0
  84. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/client_pkg.py +0 -0
  85. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/clients.py +0 -0
  86. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/external_apis.py +0 -0
  87. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/hosts.py +0 -0
  88. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/iolog.py +0 -0
  89. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/license.py +0 -0
  90. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/quick.py +0 -0
  91. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/rbp_cmdgrps.py +0 -0
  92. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/rbp_entitlement.py +0 -0
  93. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/rbp_hostgrps.py +0 -0
  94. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/rbp_policy.py +0 -0
  95. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/rbp_roles.py +0 -0
  96. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/rbp_tests.py +0 -0
  97. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/rbp_tmdategrps.py +0 -0
  98. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/rbp_tx.py +0 -0
  99. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/rbp_usergrps.py +0 -0
  100. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/settings.py +0 -0
  101. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/siems.py +0 -0
  102. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/commands/users.py +0 -0
  103. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epml/models/__init__.py +0 -0
  104. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/__init__.py +0 -0
  105. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/client/__init__.py +0 -0
  106. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/client/base.py +0 -0
  107. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/commands/__init__.py +0 -0
  108. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/commands/audits.py +0 -0
  109. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/commands/auth.py +0 -0
  110. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/commands/computers.py +0 -0
  111. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/commands/events.py +0 -0
  112. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/commands/groups.py +0 -0
  113. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/commands/policies.py +0 -0
  114. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/commands/quick.py +0 -0
  115. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/commands/requests.py +0 -0
  116. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/commands/roles.py +0 -0
  117. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/commands/tasks.py +0 -0
  118. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/commands/users.py +0 -0
  119. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/epmw/models/__init__.py +0 -0
  120. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/__init__.py +0 -0
  121. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/client/__init__.py +0 -0
  122. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/client/base.py +0 -0
  123. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/commands/__init__.py +0 -0
  124. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/commands/auth.py +0 -0
  125. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/commands/group_policies.py +0 -0
  126. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/commands/import_export.py +0 -0
  127. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/commands/jump_clients.py +0 -0
  128. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/commands/jump_groups.py +0 -0
  129. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/commands/jump_items.py +0 -0
  130. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/commands/jumpoints.py +0 -0
  131. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/commands/policies.py +0 -0
  132. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/commands/quick.py +0 -0
  133. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/commands/teams.py +0 -0
  134. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/commands/users.py +0 -0
  135. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/commands/vault.py +0 -0
  136. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/models/__init__.py +0 -0
  137. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/models/common.py +0 -0
  138. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/models/group_policy.py +0 -0
  139. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/models/jump_client.py +0 -0
  140. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/models/jump_group.py +0 -0
  141. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/models/jump_item.py +0 -0
  142. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/models/jumpoint.py +0 -0
  143. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/models/team.py +0 -0
  144. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/models/user.py +0 -0
  145. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pra/models/vault.py +0 -0
  146. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/__init__.py +0 -0
  147. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/client/__init__.py +0 -0
  148. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/client/base.py +0 -0
  149. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/client/beyondinsight.py +0 -0
  150. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/client/passwordsafe.py +0 -0
  151. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/__init__.py +0 -0
  152. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/accounts.py +0 -0
  153. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/assets.py +0 -0
  154. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/attributes.py +0 -0
  155. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/auth.py +0 -0
  156. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/clouds.py +0 -0
  157. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/config.py +0 -0
  158. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/credentials.py +0 -0
  159. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/databases.py +0 -0
  160. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/directories.py +0 -0
  161. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/functional.py +0 -0
  162. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/import_export.py +0 -0
  163. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/platforms.py +0 -0
  164. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/quick.py +0 -0
  165. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/search.py +0 -0
  166. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/secrets.py +0 -0
  167. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/systems.py +0 -0
  168. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/users.py +0 -0
  169. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/commands/workgroups.py +0 -0
  170. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/config.py +0 -0
  171. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/models/__init__.py +0 -0
  172. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/models/account.py +0 -0
  173. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/models/asset.py +0 -0
  174. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/models/common.py +0 -0
  175. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/pws/models/system.py +0 -0
  176. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/secrets/__init__.py +0 -0
  177. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/secrets/client/__init__.py +0 -0
  178. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/secrets/client/base.py +0 -0
  179. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/secrets/commands/__init__.py +0 -0
  180. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/secrets/commands/_hints.py +0 -0
  181. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/secrets/commands/auth.py +0 -0
  182. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/secrets/commands/folders.py +0 -0
  183. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/secrets/commands/integrations.py +0 -0
  184. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/secrets/commands/leases.py +0 -0
  185. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/secrets/commands/static.py +0 -0
  186. {bt_cli-0.4.47 → bt_cli-0.4.49}/src/bt_cli/secrets/models/__init__.py +0 -0
  187. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/__init__.py +0 -0
  188. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/conftest.py +0 -0
  189. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/core/__init__.py +0 -0
  190. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/core/test_auth.py +0 -0
  191. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/core/test_config.py +0 -0
  192. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/core/test_errors.py +0 -0
  193. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/core/test_rest_debug.py +0 -0
  194. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/entitle/__init__.py +0 -0
  195. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/entitle/test_client.py +0 -0
  196. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/entitle/test_commands.py +0 -0
  197. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/entitle-smoke-test.sh +0 -0
  198. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/epml/__init__.py +0 -0
  199. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/epml/test_client.py +0 -0
  200. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/epml/test_commands.py +0 -0
  201. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/epmw/__init__.py +0 -0
  202. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/epmw/test_client.py +0 -0
  203. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/epmw/test_commands.py +0 -0
  204. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/epmw-quick-test-plan.md +0 -0
  205. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/fixtures/__init__.py +0 -0
  206. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/fixtures/responses.py +0 -0
  207. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/integration/__init__.py +0 -0
  208. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/integration/conftest.py +0 -0
  209. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/integration/helpers.py +0 -0
  210. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/integration/test_entitle_integration.py +0 -0
  211. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/integration/test_epmw_integration.py +0 -0
  212. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/integration/test_epmw_lifecycle.py +0 -0
  213. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/integration/test_pra_integration.py +0 -0
  214. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/integration/test_pra_lifecycle.py +0 -0
  215. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/integration/test_pws_integration.py +0 -0
  216. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/integration/test_pws_lifecycle.py +0 -0
  217. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/pra/__init__.py +0 -0
  218. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/pra/test_client.py +0 -0
  219. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/pra/test_commands.py +0 -0
  220. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/pra-smoke-test.sh +0 -0
  221. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/pra-test-plan.md +0 -0
  222. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/pws/__init__.py +0 -0
  223. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/pws/test_client.py +0 -0
  224. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/pws/test_commands.py +0 -0
  225. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/pws-quick-test-plan.md +0 -0
  226. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/pws-smoke-test.sh +0 -0
  227. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/secrets/__init__.py +0 -0
  228. {bt_cli-0.4.47 → bt_cli-0.4.49}/tests/secrets/test_client.py +0 -0
@@ -1,6 +1,6 @@
1
1
  # BT-CLI
2
2
 
3
- BeyondTrust Platform CLI for Password Safe, Entitle, PRA, EPM Windows, EPM Linux, and the BeyondTrust Secrets API. **Version: 0.4.47**
3
+ BeyondTrust Platform CLI for Password Safe, Entitle, PRA, EPM Windows, EPM Linux, and the BeyondTrust Secrets API. **Version: 0.4.49**
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.47
3
+ Version: 0.4.49
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.47"
7
+ version = "0.4.49"
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.47"
3
+ __version__ = "0.4.49"
@@ -97,12 +97,24 @@ bt secrets dynamic get lab/aws/ec2-readonly
97
97
 
98
98
  # Mint fresh credentials — default prints shell `export AWS_*` lines.
99
99
  bt secrets dynamic generate lab/aws/ec2-readonly
100
- eval $(bt secrets dynamic generate lab/aws/ec2-readonly) # one-liner load into shell
101
- aws sts get-caller-identity # verify
100
+
101
+ # Apply to the current session (a child process can't mutate its parent's env,
102
+ # so the CLI emits shell-native syntax that you eval into your shell):
103
+
104
+ # bash / zsh:
105
+ eval $(bt secrets dynamic generate lab/aws/ec2-readonly)
106
+
107
+ # PowerShell:
108
+ bt secrets dynamic generate lab/aws/ec2-readonly --format powershell | iex
109
+
110
+ # cmd.exe:
111
+ for /f "delims=" %i in ('bt secrets dynamic generate lab/aws/ec2-readonly --format cmd') do %i
112
+
113
+ aws sts get-caller-identity # verify the creds are active
102
114
 
103
115
  # Other formats:
104
116
  bt secrets dynamic generate lab/aws/ec2-readonly --format json # full payload w/ leaseId
105
- bt secrets dynamic generate lab/aws/ec2-readonly --format env # KEY=value (no `export`)
117
+ bt secrets dynamic generate lab/aws/ec2-readonly --format env # bare KEY=value
106
118
  bt secrets dynamic generate lab/aws/ec2-readonly --format dotenv # KEY="value" for .env files
107
119
  ```
108
120
 
@@ -28,10 +28,12 @@ app = typer.Typer(no_args_is_help=True, help="Dynamic secrets (e.g. AWS STS, min
28
28
  class GenerateFormat(str, Enum):
29
29
  """Output formats for `dynamic generate`."""
30
30
 
31
- EXPORT = "export" # default — shell `export AWS_*` lines
32
- ENV = "env" # KEY=value lines (no `export` prefix)
33
- JSON = "json" # raw API payload
34
- DOTENV = "dotenv" # KEY="value" lines suitable for .env files
31
+ EXPORT = "export" # default — bash/zsh `export AWS_*` lines
32
+ POWERSHELL = "powershell" # PowerShell `$env:AWS_* = "..."` lines
33
+ CMD = "cmd" # Windows cmd.exe `set AWS_*=...` lines
34
+ ENV = "env" # bare KEY=value lines (no `export`)
35
+ JSON = "json" # raw API payload
36
+ DOTENV = "dotenv" # KEY="value" lines suitable for .env files
35
37
 
36
38
 
37
39
  def _dynamic_row(item: dict) -> dict:
@@ -44,6 +46,32 @@ def _dynamic_row(item: dict) -> dict:
44
46
  }
45
47
 
46
48
 
49
+ def _apply_hint(full_path: str, fmt: GenerateFormat) -> str:
50
+ """Build a one-line apply-recipe in syntax valid for the chosen format.
51
+
52
+ `eval $(...)`, `| iex`, and `for /f` all swallow comment lines harmlessly,
53
+ so embedding the hint costs nothing when the output is piped through —
54
+ it's just discoverable for users who run the command on its own first.
55
+
56
+ Non-shell formats (env / dotenv / json) get no hint: env/dotenv are for
57
+ writing to files, json is for scripts; neither has a single canonical
58
+ apply command.
59
+ """
60
+ if fmt is GenerateFormat.EXPORT:
61
+ return f"# Tip: apply with -> eval $(bt secrets dynamic generate {full_path})"
62
+ if fmt is GenerateFormat.POWERSHELL:
63
+ return (
64
+ f"# Tip: apply with -> "
65
+ f"bt secrets dynamic generate {full_path} --format powershell | iex"
66
+ )
67
+ if fmt is GenerateFormat.CMD:
68
+ return (
69
+ f'REM Tip: apply with -> for /f "delims=" %i in '
70
+ f"('bt secrets dynamic generate {full_path} --format cmd') do %i"
71
+ )
72
+ return ""
73
+
74
+
47
75
  def _format_credentials(secret: dict, fmt: GenerateFormat) -> str:
48
76
  """Format an AWS STS credential triplet in the requested shape.
49
77
 
@@ -51,6 +79,13 @@ def _format_credentials(secret: dict, fmt: GenerateFormat) -> str:
51
79
  (``accessKeyId``, ``secretAccessKey``, ``sessionToken``). For shell
52
80
  consumption we map those to the standard ``AWS_*`` env-var names that
53
81
  boto3, aws-cli, and the EC2 SDK all read.
82
+
83
+ A subprocess can't mutate its parent shell's environment, so each
84
+ format is designed to be piped into the shell's eval mechanism:
85
+
86
+ * EXPORT → `eval $(bt secrets dynamic generate <path>)`
87
+ * POWERSHELL → `bt secrets dynamic generate <path> --format powershell | iex`
88
+ * CMD → cmd.exe needs a temp .bat or a `for /f` loop — see SKILL.md
54
89
  """
55
90
  aws_map = [
56
91
  ("AWS_ACCESS_KEY_ID", "accessKeyId"),
@@ -63,6 +98,16 @@ def _format_credentials(secret: dict, fmt: GenerateFormat) -> str:
63
98
  value = secret[payload_key]
64
99
  if fmt is GenerateFormat.EXPORT:
65
100
  lines.append(f"export {env_name}={value}")
101
+ elif fmt is GenerateFormat.POWERSHELL:
102
+ # `Invoke-Expression` parses these as statements that set the
103
+ # process env. Quote the value so PowerShell doesn't try to
104
+ # interpret embedded characters.
105
+ lines.append(f'$env:{env_name} = "{value}"')
106
+ elif fmt is GenerateFormat.CMD:
107
+ # `set` in cmd.exe doesn't quote and doesn't tolerate spaces
108
+ # around `=`. Values from STS are alphanumeric-plus-/+=_-, so
109
+ # bare assignment is safe.
110
+ lines.append(f"set {env_name}={value}")
66
111
  elif fmt is GenerateFormat.ENV:
67
112
  lines.append(f"{env_name}={value}")
68
113
  elif fmt is GenerateFormat.DOTENV:
@@ -70,8 +115,13 @@ def _format_credentials(secret: dict, fmt: GenerateFormat) -> str:
70
115
  if not lines:
71
116
  return ""
72
117
  if "expiration" in secret:
73
- # Trailing comment is purely informational — doesn't affect `eval $(...)`.
74
- lines.append(f"# expires: {secret['expiration']}")
118
+ # Trailing comment is informational — all four script-y formats
119
+ # tolerate `#` (bash/PowerShell) or treat the line as a label-style
120
+ # noop for cmd's set, which we replace with REM below.
121
+ if fmt is GenerateFormat.CMD:
122
+ lines.append(f"REM expires: {secret['expiration']}")
123
+ else:
124
+ lines.append(f"# expires: {secret['expiration']}")
75
125
  return "\n".join(lines)
76
126
 
77
127
 
@@ -150,15 +200,21 @@ def generate(
150
200
  full_path: str = typer.Argument(..., help="Full dynamic-secret path"),
151
201
  format_: GenerateFormat = typer.Option(
152
202
  GenerateFormat.EXPORT, "--format", "-F",
153
- help="Output format: export | env | json | dotenv",
203
+ help="Output format: export | powershell | cmd | env | json | dotenv",
154
204
  case_sensitive=False,
155
205
  ),
156
206
  ) -> None:
157
207
  """Mint fresh credentials from a dynamic-secret config.
158
208
 
159
- Default ``--format export`` prints shell ``export AWS_*`` lines suitable
160
- for ``eval $(bt secrets dynamic generate <path>)``. Use ``--format json``
161
- to see the full payload (lease id, expiration, etc.).
209
+ Default ``--format export`` prints shell ``export AWS_*`` lines.
210
+
211
+ \b
212
+ Apply in your current session:
213
+ bash / zsh: eval $(bt secrets dynamic generate <path>)
214
+ PowerShell: bt secrets dynamic generate <path> --format powershell | iex
215
+ cmd.exe: for /f "delims=" %i in ('bt secrets dynamic generate <path> --format cmd') do %i
216
+
217
+ Use ``--format json`` to see the full payload (lease id, expiration).
162
218
 
163
219
  Heads up: every call mints real STS credentials and shows up in the
164
220
  audit trail. Don't loop this in development.
@@ -197,6 +253,9 @@ def generate(
197
253
  print_error("Unrecognized credential shape; printing raw payload")
198
254
  print_json(secret)
199
255
  raise typer.Exit(1)
256
+ hint = _apply_hint(full_path, format_)
257
+ if hint:
258
+ text = f"{text}\n{hint}"
200
259
  typer.echo(text)
201
260
 
202
261
 
@@ -194,6 +194,57 @@ class TestDynamic:
194
194
  assert "export AWS_SESSION_TOKEN=TOK-FAKE" in result.stdout
195
195
  # PAT must not leak in any form
196
196
  assert "PAT_test" not in result.stdout
197
+ # Inline apply-hint includes the actual path the user passed
198
+ assert "eval $(bt secrets dynamic generate lab/aws/ec2-readonly)" in result.stdout
199
+
200
+ @respx.mock
201
+ def test_dynamic_generate_powershell_hint(self, env_overrides):
202
+ respx.post(_url("/dynamic/ec2-readonly/generate")).mock(
203
+ return_value=httpx.Response(201, json={"secret": {
204
+ "accessKeyId": "ASIA-FAKE", "secretAccessKey": "SAK-FAKE",
205
+ "sessionToken": "TOK-FAKE", "expiration": "2026-01-01T00:00:00Z",
206
+ }})
207
+ )
208
+ result = CliRunner().invoke(
209
+ secrets_app, ["dynamic", "generate", "lab/aws/ec2-readonly", "--format", "powershell"],
210
+ )
211
+ assert result.exit_code == 0
212
+ assert "--format powershell | iex" in result.stdout
213
+ # Hint must use # (valid PowerShell comment); not REM
214
+ assert "REM Tip" not in result.stdout
215
+
216
+ @respx.mock
217
+ def test_dynamic_generate_cmd_hint(self, env_overrides):
218
+ respx.post(_url("/dynamic/ec2-readonly/generate")).mock(
219
+ return_value=httpx.Response(201, json={"secret": {
220
+ "accessKeyId": "ASIA-FAKE", "secretAccessKey": "SAK-FAKE",
221
+ "sessionToken": "TOK-FAKE", "expiration": "2026-01-01T00:00:00Z",
222
+ }})
223
+ )
224
+ result = CliRunner().invoke(
225
+ secrets_app, ["dynamic", "generate", "lab/aws/ec2-readonly", "--format", "cmd"],
226
+ )
227
+ assert result.exit_code == 0
228
+ assert "for /f" in result.stdout
229
+ assert "--format cmd" in result.stdout
230
+ # cmd format must use REM (not #) for the apply hint
231
+ assert "REM Tip" in result.stdout
232
+
233
+ @respx.mock
234
+ def test_dynamic_generate_no_hint_for_non_shell_formats(self, env_overrides):
235
+ """env / dotenv / json shouldn't carry an apply hint — no canonical apply mode."""
236
+ respx.post(_url("/dynamic/ec2-readonly/generate")).mock(
237
+ return_value=httpx.Response(201, json={"secret": {
238
+ "accessKeyId": "ASIA-FAKE", "secretAccessKey": "SAK-FAKE",
239
+ "sessionToken": "TOK-FAKE", "expiration": "2026-01-01T00:00:00Z",
240
+ }})
241
+ )
242
+ for fmt in ("env", "dotenv"):
243
+ result = CliRunner().invoke(
244
+ secrets_app, ["dynamic", "generate", "lab/aws/ec2-readonly", "--format", fmt],
245
+ )
246
+ assert result.exit_code == 0, fmt
247
+ assert "Tip: apply with" not in result.stdout, fmt
197
248
 
198
249
  @respx.mock
199
250
  def test_dynamic_generate_json(self, env_overrides):
@@ -226,6 +277,52 @@ class TestDynamic:
226
277
  assert "AWS_ACCESS_KEY_ID=AKIA-FAKE" in result.stdout
227
278
  assert "export" not in result.stdout.split("\n")[0]
228
279
 
280
+ @respx.mock
281
+ def test_dynamic_generate_powershell_shape(self, env_overrides):
282
+ """PowerShell format: $env:VAR = "val" — pipe to Invoke-Expression."""
283
+ respx.post(_url("/dynamic/ec2-readonly/generate")).mock(
284
+ return_value=httpx.Response(201, json={"secret": {
285
+ "accessKeyId": "ASIA-FAKE",
286
+ "secretAccessKey": "SAK-FAKE",
287
+ "sessionToken": "TOK-FAKE",
288
+ "expiration": "2026-01-01T00:00:00Z",
289
+ }})
290
+ )
291
+ result = CliRunner().invoke(
292
+ secrets_app,
293
+ ["dynamic", "generate", "lab/aws/ec2-readonly", "--format", "powershell"],
294
+ )
295
+ assert result.exit_code == 0
296
+ assert '$env:AWS_ACCESS_KEY_ID = "ASIA-FAKE"' in result.stdout
297
+ assert '$env:AWS_SECRET_ACCESS_KEY = "SAK-FAKE"' in result.stdout
298
+ assert '$env:AWS_SESSION_TOKEN = "TOK-FAKE"' in result.stdout
299
+ # Comment must use `#` (valid PowerShell line comment)
300
+ assert "# expires:" in result.stdout
301
+ # Must NOT contain bash `export` syntax
302
+ assert "export AWS_" not in result.stdout
303
+
304
+ @respx.mock
305
+ def test_dynamic_generate_cmd_shape(self, env_overrides):
306
+ """cmd.exe format: set VAR=val — for `for /f` extraction."""
307
+ respx.post(_url("/dynamic/ec2-readonly/generate")).mock(
308
+ return_value=httpx.Response(201, json={"secret": {
309
+ "accessKeyId": "ASIA-FAKE",
310
+ "secretAccessKey": "SAK-FAKE",
311
+ "sessionToken": "TOK-FAKE",
312
+ "expiration": "2026-01-01T00:00:00Z",
313
+ }})
314
+ )
315
+ result = CliRunner().invoke(
316
+ secrets_app,
317
+ ["dynamic", "generate", "lab/aws/ec2-readonly", "--format", "cmd"],
318
+ )
319
+ assert result.exit_code == 0
320
+ assert "set AWS_ACCESS_KEY_ID=ASIA-FAKE" in result.stdout
321
+ assert "set AWS_SECRET_ACCESS_KEY=SAK-FAKE" in result.stdout
322
+ # cmd.exe uses REM, not #, for comments
323
+ assert "REM expires:" in result.stdout
324
+ assert "# expires" not in result.stdout
325
+
229
326
 
230
327
  class TestLeases:
231
328
  @respx.mock
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