praetorian-cli 2.4.7__tar.gz → 2.4.9__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 (169) hide show
  1. {praetorian_cli-2.4.7/praetorian_cli.egg-info → praetorian_cli-2.4.9}/PKG-INFO +117 -1
  2. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/README.md +115 -0
  3. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/access.py +125 -0
  4. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/add.py +28 -6
  5. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/agent.py +21 -3
  6. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/chariot.py +8 -1
  7. praetorian_cli-2.4.9/praetorian_cli/handlers/cli_decorators.py +658 -0
  8. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/configure.py +3 -1
  9. praetorian_cli-2.4.9/praetorian_cli/handlers/hunt.py +156 -0
  10. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/list.py +2 -1
  11. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/run.py +34 -0
  12. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/ssh_utils.py +1 -28
  13. praetorian_cli-2.4.9/praetorian_cli/handlers/test.py +202 -0
  14. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/main.py +53 -2
  15. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/chariot.py +21 -14
  16. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/accounts.py +19 -1
  17. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/aegis.py +1 -2
  18. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/assets.py +0 -1
  19. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/files.py +4 -2
  20. praetorian_cli-2.4.9/praetorian_cli/sdk/entities/hunts.py +99 -0
  21. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/preseeds.py +3 -3
  22. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/seeds.py +9 -7
  23. praetorian_cli-2.4.9/praetorian_cli/sdk/exceptions.py +63 -0
  24. praetorian_cli-2.4.9/praetorian_cli/sdk/keychain.py +357 -0
  25. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/mcp_server.py +30 -8
  26. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/model/aegis.py +28 -1
  27. praetorian_cli-2.4.9/praetorian_cli/sdk/test/test_access_github.py +201 -0
  28. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_account.py +3 -2
  29. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_agent.py +3 -2
  30. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_asset.py +3 -2
  31. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_attribute.py +3 -2
  32. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_capabilities.py +3 -2
  33. praetorian_cli-2.4.9/praetorian_cli/sdk/test/test_cli_errors.py +802 -0
  34. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_configuration.py +3 -2
  35. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_conversation.py +4 -3
  36. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_definition.py +3 -2
  37. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_file.py +3 -2
  38. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_job.py +3 -2
  39. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_key.py +3 -2
  40. praetorian_cli-2.4.9/praetorian_cli/sdk/test/test_keychain.py +321 -0
  41. praetorian_cli-2.4.9/praetorian_cli/sdk/test/test_keychain_cache.py +50 -0
  42. praetorian_cli-2.4.9/praetorian_cli/sdk/test/test_mcp.py +243 -0
  43. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_my_by_raw_query.py +7 -7
  44. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_preseed.py +3 -2
  45. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_risk.py +3 -2
  46. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_run_cli.py +33 -0
  47. praetorian_cli-2.4.9/praetorian_cli/sdk/test/test_sdk_exceptions.py +564 -0
  48. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_search.py +3 -2
  49. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_seed.py +3 -2
  50. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_setting.py +3 -2
  51. praetorian_cli-2.4.9/praetorian_cli/sdk/test/test_test_handler.py +560 -0
  52. praetorian_cli-2.4.9/praetorian_cli/sdk/test/test_test_target.py +369 -0
  53. praetorian_cli-2.4.9/praetorian_cli/sdk/test/test_update_check.py +2063 -0
  54. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_webhook.py +3 -2
  55. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_webpage.py +3 -2
  56. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_z_cli.py +20 -6
  57. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/utils.py +33 -3
  58. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9/praetorian_cli.egg-info}/PKG-INFO +117 -1
  59. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli.egg-info/SOURCES.txt +11 -0
  60. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli.egg-info/requires.txt +1 -0
  61. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/setup.cfg +2 -1
  62. praetorian_cli-2.4.7/praetorian_cli/handlers/cli_decorators.py +0 -83
  63. praetorian_cli-2.4.7/praetorian_cli/handlers/test.py +0 -29
  64. praetorian_cli-2.4.7/praetorian_cli/sdk/keychain.py +0 -200
  65. praetorian_cli-2.4.7/praetorian_cli/sdk/test/test_mcp.py +0 -28
  66. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/LICENSE +0 -0
  67. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/MANIFEST.in +0 -0
  68. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/__init__.py +0 -0
  69. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/__init__.py +0 -0
  70. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/aegis.py +0 -0
  71. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/critfinder.py +0 -0
  72. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/delete.py +0 -0
  73. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/engagement.py +0 -0
  74. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/enrich.py +0 -0
  75. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/export.py +0 -0
  76. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/find.py +0 -0
  77. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/get.py +0 -0
  78. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/imports.py +0 -0
  79. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/link.py +0 -0
  80. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/query.py +0 -0
  81. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/report.py +0 -0
  82. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/script.py +0 -0
  83. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/search.py +0 -0
  84. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/unlink.py +0 -0
  85. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/update.py +0 -0
  86. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/handlers/utils.py +0 -0
  87. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/runners/__init__.py +0 -0
  88. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/runners/local.py +0 -0
  89. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/scripts/__init__.py +0 -0
  90. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/scripts/commands/__init__.py +0 -0
  91. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/scripts/commands/nmap-example.py +0 -0
  92. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/scripts/utils.py +0 -0
  93. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/__init__.py +0 -0
  94. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/__init__.py +0 -0
  95. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/account_discovery.py +0 -0
  96. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/ad.py +0 -0
  97. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/agents.py +0 -0
  98. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/attributes.py +0 -0
  99. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/capabilities.py +0 -0
  100. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/configurations.py +0 -0
  101. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/conversations.py +0 -0
  102. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/credentials.py +0 -0
  103. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/definitions.py +0 -0
  104. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/integrations.py +0 -0
  105. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/jobs.py +0 -0
  106. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/keys.py +0 -0
  107. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/reports.py +0 -0
  108. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/risks.py +0 -0
  109. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/scanners.py +0 -0
  110. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/schedules.py +0 -0
  111. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/schema.py +0 -0
  112. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/search.py +0 -0
  113. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/settings.py +0 -0
  114. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/statistics.py +0 -0
  115. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/webhook.py +0 -0
  116. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/entities/webpage.py +0 -0
  117. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/guard.py +0 -0
  118. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/model/__init__.py +0 -0
  119. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/model/globals.py +0 -0
  120. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/model/query.py +0 -0
  121. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/model/utils.py +0 -0
  122. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/__init__.py +0 -0
  123. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/pytest.ini +0 -0
  124. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_access_aws.py +0 -0
  125. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_bulk.py +0 -0
  126. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_credential_process.py +0 -0
  127. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_credentials.py +0 -0
  128. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_export_cli.py +0 -0
  129. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_extend.py +0 -0
  130. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_local_runner.py +0 -0
  131. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/test_report.py +0 -0
  132. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/sdk/test/ui_mocks.py +0 -0
  133. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/__init__.py +0 -0
  134. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/__init__.py +0 -0
  135. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/account_selector.py +0 -0
  136. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/commands/__init__.py +0 -0
  137. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/commands/cp.py +0 -0
  138. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/commands/help.py +0 -0
  139. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/commands/info.py +0 -0
  140. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/commands/job.py +0 -0
  141. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/commands/job_helpers.py +0 -0
  142. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/commands/list.py +0 -0
  143. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/commands/proxy.py +0 -0
  144. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/commands/schedule.py +0 -0
  145. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/commands/schedule_helpers.py +0 -0
  146. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/commands/set.py +0 -0
  147. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/commands/ssh.py +0 -0
  148. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/constants.py +0 -0
  149. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/menu.py +0 -0
  150. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/theme.py +0 -0
  151. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/aegis/utils.py +0 -0
  152. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/console/__init__.py +0 -0
  153. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/console/commands/__init__.py +0 -0
  154. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/console/commands/accounts.py +0 -0
  155. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/console/commands/context.py +0 -0
  156. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/console/commands/data.py +0 -0
  157. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/console/commands/marcus.py +0 -0
  158. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/console/commands/reporting.py +0 -0
  159. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/console/commands/search.py +0 -0
  160. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/console/commands/tools.py +0 -0
  161. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/console/console.py +0 -0
  162. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/console/context.py +0 -0
  163. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/console/renderer.py +0 -0
  164. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/conversation/__init__.py +0 -0
  165. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli/ui/conversation/textual_chat.py +0 -0
  166. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli.egg-info/dependency_links.txt +0 -0
  167. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli.egg-info/entry_points.txt +0 -0
  168. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/praetorian_cli.egg-info/top_level.txt +0 -0
  169. {praetorian_cli-2.4.7 → praetorian_cli-2.4.9}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: praetorian-cli
3
- Version: 2.4.7
3
+ Version: 2.4.9
4
4
  Summary: For interacting with the Guard API
5
5
  Home-page: https://github.com/praetorian-inc/praetorian-cli
6
6
  Author: Praetorian
@@ -14,6 +14,7 @@ License-File: LICENSE
14
14
  Requires-Dist: click>=8.1.7
15
15
  Requires-Dist: boto3>=1.34.0
16
16
  Requires-Dist: requests>=2.31.0
17
+ Requires-Dist: truststore>=0.10.0
17
18
  Requires-Dist: pytest>=8.0.2
18
19
  Requires-Dist: mcp>=1.12.2
19
20
  Requires-Dist: anyio>=3.0.0
@@ -44,6 +45,7 @@ Dynamic: license-file
44
45
  - [Signing up](#signing-up)
45
46
  - [Authentication](#authentication)
46
47
  - [Using the CLI](#using-the-cli)
48
+ - [Update checks](#update-checks)
47
49
  - [Operators](#operators)
48
50
  - [Interactive Console](#interactive-console)
49
51
  - [Install local security tools (optional)](#install-local-security-tools-optional)
@@ -52,6 +54,7 @@ Dynamic: license-file
52
54
  - [Developers](#developers)
53
55
  - [SDK](#sdk)
54
56
  - [Developing external scripts](#developing-external-scripts)
57
+ - [Running the test suite](#running-the-test-suite)
55
58
  - [Contributing](#contributing)
56
59
  - [Support](#support)
57
60
  - [License](#license)
@@ -146,6 +149,10 @@ export PRAETORIAN_CLI_API_KEY_ID=your-api-key-id-here
146
149
  export PRAETORIAN_CLI_API_KEY_SECRET=your-api-key-here
147
150
  ```
148
151
 
152
+ The backend API URL and the Cognito emulator endpoint (`aws_endpoint_url`)
153
+ must be HTTPS; the CLI refuses to send credentials over plaintext HTTP. For local development against a loopback endpoint (`localhost`,
154
+ `127.0.0.1`, `::1`), set `PRAETORIAN_CLI_ALLOW_HTTP_LOOPBACK=1`.
155
+
149
156
  For more advanced configuration options or managing access in SSO organizations see
150
157
  [the documentation on configuration](https://github.com/praetorian-inc/praetorian-cli/blob/main/docs/configure.md).
151
158
 
@@ -174,6 +181,72 @@ To get detailed information about a specific asset, run:
174
181
  guard --account guard+example@praetorian.com get asset <ASSET_KEY>
175
182
  ```
176
183
 
184
+ ## Update checks
185
+
186
+ After a command finishes, the CLI may check PyPI for a newer release of
187
+ `praetorian-cli` and print a three-line upgrade advisory to stderr. The check is
188
+ deliberately quiet and infrequent:
189
+
190
+ - **At most once every 24 hours.** Every attempt is recorded at
191
+ `${XDG_CACHE_HOME:-~/.cache}/praetorian-cli/update-check.json` *before* the
192
+ request is made, so a refresh that fails — offline, DNS, timeout, a malformed
193
+ response — is rate-limited exactly like one that succeeds, and keeps
194
+ advertising the last version it did learn. Between refreshes the check reads
195
+ that file and makes no network request at all — as long as the record is a
196
+ plain file that belongs to you and is no larger than 64 KiB. Anything else at
197
+ that path is ignored as though it were absent, so the next invocation refreshes
198
+ and replaces it rather than trusting what it found. Commands that start at the
199
+ same instant are excluded by a marker file created beside that record, so eight
200
+ concurrent invocations perform one refresh rather than eight — including when
201
+ the request fails instantly, since the attempt is recorded before it is made.
202
+ A process killed mid-refresh leaves the marker behind, which defers the next
203
+ refresh that is actually due rather than permitting an extra one — by up to a
204
+ minute, or up to two if the clock steps backwards in between, since a marker
205
+ counts as held while its age is within a minute in *either* direction. A
206
+ relative `XDG_CACHE_HOME` is
207
+ ignored in favour of `~/.cache`, as the base-directory spec requires —
208
+ honouring it would put a separate cache in every working directory and so
209
+ defeat the limit outright. If the cache directory cannot be written at all (a
210
+ read-only home, one owned by another user, or one reached through a symlink),
211
+ the check does not run: a probe whose rate we cannot limit is one we do not
212
+ send.
213
+ - **Only when a human is watching.** It is skipped unless **both** stdout and
214
+ stderr are a terminal, and skipped when `CI` or `GITHUB_ACTIONS` is set or
215
+ `TERM=dumb`. Piping either stream — `guard list assets | jq` — turns it off.
216
+ A script you launch by hand from your own terminal inherits your terminal, so
217
+ treat the opt-out below, not this gate, as the way to guarantee silence.
218
+ - **Never in place of your command's work.** A command that raises skips the
219
+ check, and a group that is only delegating to a subcommand leaves the check to
220
+ the subcommand that does the work. A command that reports an error but still
221
+ exits `0` is the one case where an advisory can follow a visible error.
222
+ - **Not on the path you run day to day.** The daily refresh passes a 2-second
223
+ timeout to `requests`, which bounds how long the server may go without
224
+ sending data — not total wall-clock, so DNS, TLS, redirects and a slow trickle
225
+ are outside it. Ordinary failures are swallowed and cannot change your exit
226
+ code; `Ctrl-C` and process-control exceptions raised during the check still
227
+ propagate, by design, so that interrupting the CLI always works.
228
+
229
+ ### Disabling it
230
+
231
+ ```zsh
232
+ export PRAETORIAN_CLI_DISABLE_UPDATE_CHECK=1
233
+ ```
234
+
235
+ `1`, `true`, `yes` or `on` (any case). Nothing is read or written — no request,
236
+ no cache file.
237
+
238
+ ### Privacy
239
+
240
+ A refresh is an unauthenticated `GET` to `https://pypi.org/pypi/praetorian-cli/json`.
241
+ It sends no account, profile, command, or argument — only what any HTTPS request
242
+ inherently reveals to the server: your IP address and the fact that some
243
+ `praetorian-cli` install asked for the package index at that moment. Because
244
+ every attempt is recorded before it is made and concurrent attempts are
245
+ excluded, that happens at most once per day per user account on the machine —
246
+ several users each get their own cache — so your per-command usage cadence is
247
+ not exposed. If contacting
248
+ pypi.org at all is unacceptable in your environment, set the variable above.
249
+
177
250
  # Operators
178
251
 
179
252
  ## Interactive Console
@@ -370,6 +443,49 @@ For developing scripts, you can refer to
370
443
  this [readme file](https://github.com/praetorian-inc/praetorian-cli/blob/main/docs/script-development.md).
371
444
 
372
445
 
446
+ ## Running the test suite
447
+
448
+ `guard test` runs the integration suites that ship with the package. **Some of
449
+ those suites create, modify and delete real entities in whatever account the
450
+ selected profile points at**, so the command is gated.
451
+
452
+ Suites are selected with `-s`/`--suite`:
453
+
454
+ | Suite | What it runs | Touches a live account? |
455
+ | --- | --- | --- |
456
+ | `safe` *(default)* | Local, offline unit tests | No |
457
+ | `coherence` | End-to-end entity lifecycle tests | **Yes — creates and deletes assets, risks, settings, configurations** |
458
+ | `cli` | CLI-level integration tests | **Yes — mutating** |
459
+ | `tui` | Terminal UI tests | No |
460
+
461
+ A bare `guard test` runs the `safe` suite only. It executes with a temporary
462
+ `HOME` and with credential environment variables stripped, so it cannot reach
463
+ your real credentials.
464
+
465
+ The mutating suites additionally require:
466
+
467
+ 1. **An explicit profile and account.** Both must be given and non-empty —
468
+ `guard --profile <profile> --account <account> test --suite coherence`.
469
+ There is no fallback: an unset or blank value is an error, so the suite can
470
+ never quietly run against a default profile.
471
+ 2. **Interactive confirmation.** The command prints the suite, profile, account,
472
+ and whether the suite is live and mutating, then asks you to confirm.
473
+ Declining — or a non-interactive invocation, which cannot confirm — exits
474
+ non-zero without running any test.
475
+
476
+ ```zsh
477
+ # Safe by default — no account is touched.
478
+ guard test
479
+
480
+ # Mutating suite: target must be explicit, and you must confirm.
481
+ guard --profile "United States" --account guard+scratch@praetorian.com \
482
+ test --suite coherence
483
+ ```
484
+
485
+ Never point a mutating suite at a production account. Use a dedicated scratch
486
+ account whose contents you are willing to lose.
487
+
488
+
373
489
  ## Contributing
374
490
 
375
491
  We welcome contributions from the community, from scripts, to the core CLI and SDK. To contribute, fork this
@@ -20,6 +20,7 @@
20
20
  - [Signing up](#signing-up)
21
21
  - [Authentication](#authentication)
22
22
  - [Using the CLI](#using-the-cli)
23
+ - [Update checks](#update-checks)
23
24
  - [Operators](#operators)
24
25
  - [Interactive Console](#interactive-console)
25
26
  - [Install local security tools (optional)](#install-local-security-tools-optional)
@@ -28,6 +29,7 @@
28
29
  - [Developers](#developers)
29
30
  - [SDK](#sdk)
30
31
  - [Developing external scripts](#developing-external-scripts)
32
+ - [Running the test suite](#running-the-test-suite)
31
33
  - [Contributing](#contributing)
32
34
  - [Support](#support)
33
35
  - [License](#license)
@@ -122,6 +124,10 @@ export PRAETORIAN_CLI_API_KEY_ID=your-api-key-id-here
122
124
  export PRAETORIAN_CLI_API_KEY_SECRET=your-api-key-here
123
125
  ```
124
126
 
127
+ The backend API URL and the Cognito emulator endpoint (`aws_endpoint_url`)
128
+ must be HTTPS; the CLI refuses to send credentials over plaintext HTTP. For local development against a loopback endpoint (`localhost`,
129
+ `127.0.0.1`, `::1`), set `PRAETORIAN_CLI_ALLOW_HTTP_LOOPBACK=1`.
130
+
125
131
  For more advanced configuration options or managing access in SSO organizations see
126
132
  [the documentation on configuration](https://github.com/praetorian-inc/praetorian-cli/blob/main/docs/configure.md).
127
133
 
@@ -150,6 +156,72 @@ To get detailed information about a specific asset, run:
150
156
  guard --account guard+example@praetorian.com get asset <ASSET_KEY>
151
157
  ```
152
158
 
159
+ ## Update checks
160
+
161
+ After a command finishes, the CLI may check PyPI for a newer release of
162
+ `praetorian-cli` and print a three-line upgrade advisory to stderr. The check is
163
+ deliberately quiet and infrequent:
164
+
165
+ - **At most once every 24 hours.** Every attempt is recorded at
166
+ `${XDG_CACHE_HOME:-~/.cache}/praetorian-cli/update-check.json` *before* the
167
+ request is made, so a refresh that fails — offline, DNS, timeout, a malformed
168
+ response — is rate-limited exactly like one that succeeds, and keeps
169
+ advertising the last version it did learn. Between refreshes the check reads
170
+ that file and makes no network request at all — as long as the record is a
171
+ plain file that belongs to you and is no larger than 64 KiB. Anything else at
172
+ that path is ignored as though it were absent, so the next invocation refreshes
173
+ and replaces it rather than trusting what it found. Commands that start at the
174
+ same instant are excluded by a marker file created beside that record, so eight
175
+ concurrent invocations perform one refresh rather than eight — including when
176
+ the request fails instantly, since the attempt is recorded before it is made.
177
+ A process killed mid-refresh leaves the marker behind, which defers the next
178
+ refresh that is actually due rather than permitting an extra one — by up to a
179
+ minute, or up to two if the clock steps backwards in between, since a marker
180
+ counts as held while its age is within a minute in *either* direction. A
181
+ relative `XDG_CACHE_HOME` is
182
+ ignored in favour of `~/.cache`, as the base-directory spec requires —
183
+ honouring it would put a separate cache in every working directory and so
184
+ defeat the limit outright. If the cache directory cannot be written at all (a
185
+ read-only home, one owned by another user, or one reached through a symlink),
186
+ the check does not run: a probe whose rate we cannot limit is one we do not
187
+ send.
188
+ - **Only when a human is watching.** It is skipped unless **both** stdout and
189
+ stderr are a terminal, and skipped when `CI` or `GITHUB_ACTIONS` is set or
190
+ `TERM=dumb`. Piping either stream — `guard list assets | jq` — turns it off.
191
+ A script you launch by hand from your own terminal inherits your terminal, so
192
+ treat the opt-out below, not this gate, as the way to guarantee silence.
193
+ - **Never in place of your command's work.** A command that raises skips the
194
+ check, and a group that is only delegating to a subcommand leaves the check to
195
+ the subcommand that does the work. A command that reports an error but still
196
+ exits `0` is the one case where an advisory can follow a visible error.
197
+ - **Not on the path you run day to day.** The daily refresh passes a 2-second
198
+ timeout to `requests`, which bounds how long the server may go without
199
+ sending data — not total wall-clock, so DNS, TLS, redirects and a slow trickle
200
+ are outside it. Ordinary failures are swallowed and cannot change your exit
201
+ code; `Ctrl-C` and process-control exceptions raised during the check still
202
+ propagate, by design, so that interrupting the CLI always works.
203
+
204
+ ### Disabling it
205
+
206
+ ```zsh
207
+ export PRAETORIAN_CLI_DISABLE_UPDATE_CHECK=1
208
+ ```
209
+
210
+ `1`, `true`, `yes` or `on` (any case). Nothing is read or written — no request,
211
+ no cache file.
212
+
213
+ ### Privacy
214
+
215
+ A refresh is an unauthenticated `GET` to `https://pypi.org/pypi/praetorian-cli/json`.
216
+ It sends no account, profile, command, or argument — only what any HTTPS request
217
+ inherently reveals to the server: your IP address and the fact that some
218
+ `praetorian-cli` install asked for the package index at that moment. Because
219
+ every attempt is recorded before it is made and concurrent attempts are
220
+ excluded, that happens at most once per day per user account on the machine —
221
+ several users each get their own cache — so your per-command usage cadence is
222
+ not exposed. If contacting
223
+ pypi.org at all is unacceptable in your environment, set the variable above.
224
+
153
225
  # Operators
154
226
 
155
227
  ## Interactive Console
@@ -346,6 +418,49 @@ For developing scripts, you can refer to
346
418
  this [readme file](https://github.com/praetorian-inc/praetorian-cli/blob/main/docs/script-development.md).
347
419
 
348
420
 
421
+ ## Running the test suite
422
+
423
+ `guard test` runs the integration suites that ship with the package. **Some of
424
+ those suites create, modify and delete real entities in whatever account the
425
+ selected profile points at**, so the command is gated.
426
+
427
+ Suites are selected with `-s`/`--suite`:
428
+
429
+ | Suite | What it runs | Touches a live account? |
430
+ | --- | --- | --- |
431
+ | `safe` *(default)* | Local, offline unit tests | No |
432
+ | `coherence` | End-to-end entity lifecycle tests | **Yes — creates and deletes assets, risks, settings, configurations** |
433
+ | `cli` | CLI-level integration tests | **Yes — mutating** |
434
+ | `tui` | Terminal UI tests | No |
435
+
436
+ A bare `guard test` runs the `safe` suite only. It executes with a temporary
437
+ `HOME` and with credential environment variables stripped, so it cannot reach
438
+ your real credentials.
439
+
440
+ The mutating suites additionally require:
441
+
442
+ 1. **An explicit profile and account.** Both must be given and non-empty —
443
+ `guard --profile <profile> --account <account> test --suite coherence`.
444
+ There is no fallback: an unset or blank value is an error, so the suite can
445
+ never quietly run against a default profile.
446
+ 2. **Interactive confirmation.** The command prints the suite, profile, account,
447
+ and whether the suite is live and mutating, then asks you to confirm.
448
+ Declining — or a non-interactive invocation, which cannot confirm — exits
449
+ non-zero without running any test.
450
+
451
+ ```zsh
452
+ # Safe by default — no account is touched.
453
+ guard test
454
+
455
+ # Mutating suite: target must be explicit, and you must confirm.
456
+ guard --profile "United States" --account guard+scratch@praetorian.com \
457
+ test --suite coherence
458
+ ```
459
+
460
+ Never point a mutating suite at a production account. Use a dedicated scratch
461
+ account whose contents you are willing to lose.
462
+
463
+
349
464
  ## Contributing
350
465
 
351
466
  We welcome contributions from the community, from scripts, to the core CLI and SDK. To contribute, fork this
@@ -1,9 +1,11 @@
1
1
  import os
2
+ import shlex
2
3
 
3
4
  import click
4
5
 
5
6
  from praetorian_cli.handlers.chariot import chariot
6
7
  from praetorian_cli.handlers.cli_decorators import cli_handler
8
+ from praetorian_cli.handlers.utils import error
7
9
 
8
10
 
9
11
  def extract_prefix(email):
@@ -207,3 +209,126 @@ def aws(sdk, account, prefix):
207
209
  click.echo(f'Wrote {len(all_profiles)} AWS profile(s) to ~/.aws/config:')
208
210
  for profile_name, _ in all_profiles:
209
211
  click.echo(f' {profile_name}')
212
+
213
+
214
+ @access.command()
215
+ @cli_handler
216
+ @click.option('--org', default=None,
217
+ help='GitHub organization to retrieve a token for. Required when the '
218
+ 'account has more than one GitHub integration.')
219
+ @click.option('--format', 'output_format', default='token',
220
+ type=click.Choice(['token', 'env']), show_default=True,
221
+ help='Output shape. token: bare token on stdout. '
222
+ 'env: export GITHUB_TOKEN / GH_TOKEN lines for `eval`.')
223
+ def github(sdk, org, output_format):
224
+ """Retrieve a temporary GitHub App installation token.
225
+
226
+ Looks up github integrations for the active account, asks the broker to
227
+ mint a 1-hour App installation token, and prints it. Guard only brokers
228
+ temporary App installation tokens; static PATs are refused server-side.
229
+
230
+ The account is inherited from the top-level guard --account flag.
231
+
232
+ \b
233
+ Example usages:
234
+ - guard access github
235
+ - guard --account chariot+client@praetorian.com access github --org acme-inc
236
+ - eval "$(guard access github --format env)" && gh auth status
237
+ """
238
+ account = sdk.keychain.account
239
+
240
+ integrations, _ = sdk.integrations.list(name_filter='github')
241
+ if not integrations:
242
+ error(f'No GitHub integrations found for account {account}')
243
+
244
+ integration = _select_github_integration(integrations, org)
245
+ target = integration.get('value') or integration.get('key', '')
246
+
247
+ token = _fetch_github_app_token(sdk, integration.get('key', ''), target)
248
+ if not token:
249
+ error(f'No GitHub App installation token was retrieved for {target}.')
250
+
251
+ _print_github_token(token, output_format)
252
+
253
+
254
+ def _select_github_integration(integrations, org):
255
+ """Pick the one integration to mint a token for.
256
+
257
+ A single integration is used as-is. With several, --org disambiguates by
258
+ matching the integration value (a repo/org URL) or its trailing path
259
+ segment; ambiguity without --org is an error rather than a guess.
260
+ """
261
+ if org:
262
+ matches = [i for i in integrations if _matches_org(i, org)]
263
+ if not matches:
264
+ error(f'No GitHub integration matching --org {org!r}. Available:\n'
265
+ + _integration_list(integrations))
266
+ if len(matches) > 1:
267
+ error(f'--org {org!r} matches more than one GitHub integration:\n'
268
+ + _integration_list(matches))
269
+ return matches[0]
270
+
271
+ if len(integrations) > 1:
272
+ error('This account has more than one GitHub integration. '
273
+ 'Select one with --org:\n' + _integration_list(integrations))
274
+
275
+ return integrations[0]
276
+
277
+
278
+ def _matches_org(integration, org):
279
+ value = (integration.get('value') or '').rstrip('/')
280
+ org = org.strip().rstrip('/').lower()
281
+ return value.lower() == org or value.rsplit('/', 1)[-1].lower() == org
282
+
283
+
284
+ def _integration_list(integrations):
285
+ return '\n'.join(f' {i.get("value") or i.get("key", "")}' for i in integrations)
286
+
287
+
288
+ def _fetch_github_app_token(sdk, integration_key, target):
289
+ """Resolve a github credential via the broker.
290
+
291
+ Github integrations don't use the standard "Asset + Credential record"
292
+ pattern that from-parent walks: the OAuth installation flow stores the
293
+ binding (installation_id, value) directly on the Account record, and the
294
+ broker reads it from SSM keyed by the integration's own key
295
+ (backend/pkg/services/account/integration_utils.go writes
296
+ aws.Secrets.Set(account.Key, account.Secret); the github handler reads
297
+ aws.Secrets.Get(request.CredentialID)). So for github, CredentialID *is*
298
+ the integration key, and the right resolution is by-target.
299
+
300
+ Returns the token string on success, None after printing a stderr message
301
+ on failure.
302
+ """
303
+ try:
304
+ result = sdk.credentials.get(
305
+ integration_key, 'env-integration', 'github', ['token'],
306
+ resolution='by-target',
307
+ )
308
+ except Exception as e:
309
+ msg = str(e)
310
+ if '[403]' in msg or 'unauthorized' in msg.lower():
311
+ click.echo(
312
+ f'{target}: Guard denied the request. End-user retrieval of '
313
+ 'GitHub App installation tokens may not be enabled on this '
314
+ 'deployment yet.',
315
+ err=True,
316
+ )
317
+ else:
318
+ click.echo(f'{target}: {msg.splitlines()[0]}', err=True)
319
+ return None
320
+
321
+ token = (result or {}).get('credentialValue', {}).get('github')
322
+ if not isinstance(token, str) or not token:
323
+ click.echo(f'{target}: broker returned no token', err=True)
324
+ return None
325
+ return token
326
+
327
+
328
+ def _print_github_token(token, output_format):
329
+ if output_format == 'env':
330
+ quoted = shlex.quote(token)
331
+ click.echo(f'export GITHUB_TOKEN={quoted}')
332
+ click.echo(f'export GH_TOKEN={quoted}')
333
+ else:
334
+ click.echo(token)
@@ -61,16 +61,16 @@ def asset(sdk, identifier, group, asset_type, status, surface, resource_type):
61
61
  @add.command()
62
62
  @cli_handler
63
63
  @click.argument('path')
64
- @click.option('-n', '--name', help='The file name in Guard. Default: the full path of the uploaded file')
65
- def file(sdk, path, name):
64
+ @click.option('-n', '--name', help='Destination path in Guard storage. Without this flag, the file is placed automatically')
65
+ @click.option('--public', 'is_public', is_flag=True, default=False, help='Share file with the customer (Praetorian users only)')
66
+ def file(sdk, path, name, is_public):
66
67
  """ Upload a file
67
68
 
68
69
  This commands takes the path to a local file and uploads it to the
69
70
  Guard file system. The Guard file system is where the platform
70
71
  stores proofs of exploit, risk definitions, and other supporting data.
71
72
 
72
- User files reside in the "home/" folder. Those files appear in the app
73
- at https://guard.praetorian.com/app/files
73
+ User files appear in the app at https://guard.praetorian.com/app/files
74
74
 
75
75
  \b
76
76
  Arguments:
@@ -79,10 +79,32 @@ def file(sdk, path, name):
79
79
  \b
80
80
  Example usages:
81
81
  - guard add file ./file.txt
82
- - guard add file ./file.txt --name "home/file.txt"
82
+ - guard add file ./file.txt --public
83
+ - guard add file ./file.txt --name "custom/path/file.txt"
83
84
  """
84
85
  try:
85
- sdk.files.add(path, name)
86
+ expanded = os.path.expanduser(path)
87
+ filename = os.path.basename(expanded)
88
+ praetorian = False
89
+
90
+ if name:
91
+ # if name is provided, use it as the destination path regardless of whether
92
+ # the path follows the Guard file system filepath conventions. If it does not
93
+ # follow the conventions, it will still be uploaded but it will not be
94
+ # displayed in the Guard app UI.
95
+ dest_path = name
96
+ elif sdk.is_praetorian_user():
97
+ if is_public:
98
+ dest_path = f'home/shared-with/{filename}'
99
+ else:
100
+ dest_path = f'home/internal/{filename}'
101
+ praetorian = True
102
+ else:
103
+ dest_path = f'home/shared-by/{filename}'
104
+
105
+ sdk.files.add(expanded, dest_path, praetorian=praetorian)
106
+ size = os.path.getsize(expanded)
107
+ click.echo(f'Uploaded {expanded} -> {dest_path} ({size} bytes)')
86
108
  except Exception as e:
87
109
  error(f'Unable to upload file {path}. Error: {e}')
88
110
 
@@ -7,6 +7,11 @@ from praetorian_cli.handlers.chariot import chariot
7
7
  from praetorian_cli.handlers.cli_decorators import cli_handler
8
8
  from praetorian_cli.handlers.utils import error
9
9
 
10
+ # Default MCP tool allow profile: read-only query/list/get tools. Sensitive
11
+ # tools (see praetorian_cli.sdk.mcp_server.SENSITIVE_TOOL_PATTERNS) are never
12
+ # matched by these wildcards — they require an exact-name -a entry.
13
+ DEFAULT_MCP_TOOLS = ['search_by_query', '*_list', '*_get']
14
+
10
15
 
11
16
  @chariot.group()
12
17
  def agent():
@@ -38,19 +43,28 @@ def mcp():
38
43
 
39
44
  @mcp.command()
40
45
  @cli_handler
41
- @click.option('--allowed', '-a', type=str, multiple=True, default=['search_by_query', '*_list', '*_get'])
46
+ @click.option('--allowed', '-a', type=str, multiple=True, default=DEFAULT_MCP_TOOLS)
42
47
  def start(sdk, allowed):
43
48
  """ Starts the Guard MCP server
44
49
 
50
+ The default profile exposes read-only query/list/get tools. Tools that
51
+ return or manage secrets (accounts_*, credentials_*, integrations_*,
52
+ keys_*, webhook_*) are never matched by wildcard patterns — the default
53
+ profile included — and are only exposed by passing the exact tool name
54
+ with -a (e.g. -a credentials_get). Opting in accounts_assume_role is
55
+ higher-consequence than a read tool: it switches the session's tenant for
56
+ all subsequent tool calls.
57
+
45
58
  \b
46
59
  Example usages:
47
60
  - guard agent mcp start
48
61
  - guard agent mcp start -a search_by_term -a risk_add
49
62
  - guard agent mcp start -a search_* -a risk_add
63
+ - guard agent mcp start -a credentials_get # exact name required for sensitive tools
50
64
 
51
65
  \b
52
66
  Claude code configuration/usage:
53
- - claude mcp add chariot -- guard agent mcp start # read-only
67
+ - claude mcp add chariot -- guard agent mcp start # default read-only, non-sensitive tools
54
68
  - claude mcp add chariot -- guard agent mcp start -a search_by_query -a risk_add -a asset_add # select write tools
55
69
  - claude "show me my chariot assets from the example.com domain"
56
70
  - claude "show me my chariot assets with port 22 open"
@@ -61,11 +75,15 @@ def start(sdk, allowed):
61
75
  sdk.agents.start_mcp_server(allowed)
62
76
 
63
77
  @mcp.command()
64
- @click.option('--allowed', '-a', type=str, multiple=True, default=['search_by_query', '*_list', '*_get'])
78
+ @click.option('--allowed', '-a', type=str, multiple=True, default=DEFAULT_MCP_TOOLS)
65
79
  @cli_handler
66
80
  def tools(sdk, allowed):
67
81
  """ Lists available mcp tools
68
82
 
83
+ Sensitive tools (accounts_*, credentials_*, integrations_*, keys_*,
84
+ webhook_*) never match wildcard patterns and appear only when named
85
+ exactly with -a.
86
+
69
87
  \b
70
88
  Example usages:
71
89
  - guard agent mcp tools
@@ -4,7 +4,14 @@ import click
4
4
  @click.group()
5
5
  @click.pass_context
6
6
  def chariot(click_context):
7
- # import done here to avoid circular import errors in praetorian_cli/handlers/cli_decorators.py
7
+ from praetorian_cli.handlers.test import TestTarget
8
+
9
+ if isinstance(click_context.obj, TestTarget):
10
+ return
11
+
12
+ # Deferred import: keeps the cost of importing the whole SDK off the
13
+ # module-import path, so `guard --help` and unrelated commands do not pay
14
+ # for it. ENG-6585 owns making this lazy loading systematic.
8
15
  from praetorian_cli.sdk.chariot import Chariot
9
16
 
10
17
  """ Command group for interacting with the Guard product """