bt-cli 0.4.72__tar.gz → 0.4.73__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.
- {bt_cli-0.4.72 → bt_cli-0.4.73}/CLAUDE.md +2 -1
- {bt_cli-0.4.72 → bt_cli-0.4.73}/PKG-INFO +1 -1
- {bt_cli-0.4.72 → bt_cli-0.4.73}/pyproject.toml +1 -1
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/__init__.py +1 -1
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/cli.py +100 -350
- bt_cli-0.4.73/src/bt_cli/core/command_tree.py +82 -0
- bt_cli-0.4.73/tests/core/test_command_tree.py +111 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/.claude/skills/bt/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/.claude/skills/entitle/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/.claude/skills/epml/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/.claude/skills/epmw/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/.claude/skills/pra/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/.claude/skills/pws/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/.env.example +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/.github/workflows/ci.yml +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/.github/workflows/release.yml +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/.gitignore +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/README.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/assets/cli-help.png +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/assets/cli-output.png +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/bt-cli-cheatsheet.html +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/bt-cli.spec +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/bt_entry.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/epml-clients-server-side-filters-plan.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/epml-implementation-plan.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/pf-implementation-plan.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/scripts/bt_entry.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/scripts/pf_onboard.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/scripts/sync-package-data.sh +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/commands/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/commands/configure.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/commands/learn.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/commands/quick.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/core/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/core/auth.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/core/client.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/core/config.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/core/config_file.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/core/csv_utils.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/core/errors.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/core/output.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/core/prompts.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/core/rest_debug.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/data/CLAUDE.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/data/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/data/skills/bt/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/data/skills/entitle/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/data/skills/epml/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/data/skills/epmw/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/data/skills/pf/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/data/skills/pra/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/data/skills/pws/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/data/skills/secrets/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/data/skills/session-analysis/SKILL.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/client/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/client/base.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/accounts.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/applications.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/audit.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/auth.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/bundles.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/integrations.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/jit.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/permissions.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/policies.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/requests.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/resources.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/roles.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/users.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/commands/workflows.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/models/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/models/bundle.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/models/common.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/models/integration.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/models/permission.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/models/policy.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/models/resource.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/models/role.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/models/user.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/entitle/models/workflow.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/client/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/client/base.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/audit.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/auth.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/client_pkg.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/clients.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/external_apis.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/hosts.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/iolog.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/license.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/quick.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_cmdgrps.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_entitlement.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_hostgrps.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_policy.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_roles.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_tests.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_tmdategrps.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_tx.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/rbp_usergrps.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/settings.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/siems.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/commands/users.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epml/models/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/client/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/client/base.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/audits.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/auth.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/computers.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/events.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/groups.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/policies.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/quick.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/requests.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/roles.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/tasks.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/commands/users.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/epmw/models/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pf/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pf/client/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pf/client/base.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pf/commands/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pf/commands/auth.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pf/commands/machines.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pf/commands/tokens.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pf/commands/user.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pf/commands/users.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/client/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/client/base.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/commands/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/commands/auth.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/commands/group_policies.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/commands/import_export.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/commands/jump_clients.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/commands/jump_groups.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/commands/jump_items.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/commands/jumpoints.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/commands/policies.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/commands/quick.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/commands/teams.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/commands/users.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/commands/vault.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/models/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/models/common.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/models/group_policy.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/models/jump_client.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/models/jump_group.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/models/jump_item.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/models/jumpoint.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/models/team.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/models/user.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pra/models/vault.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/client/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/client/base.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/client/beyondinsight.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/client/passwordsafe.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/accounts.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/assets.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/attributes.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/audit.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/auth.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/clouds.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/config.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/credentials.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/databases.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/directories.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/functional.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/import_export.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/platforms.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/quick.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/search.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/secrets.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/sessions.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/systems.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/users.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/commands/workgroups.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/config.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/models/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/models/account.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/models/asset.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/models/common.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/pws/models/system.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/secrets/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/secrets/client/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/secrets/client/base.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/_hints.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/auth.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/dynamic.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/folders.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/integrations.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/leases.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/secrets/commands/static.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/src/bt_cli/secrets/models/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/conftest.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/core/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/core/test_auth.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/core/test_config.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/core/test_config_file.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/core/test_errors.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/core/test_json_stdout_purity.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/core/test_output.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/core/test_rest_debug.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/entitle/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/entitle/test_client.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/entitle/test_commands.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/entitle-smoke-test.sh +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/epml/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/epml/test_client.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/epml/test_commands.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/epmw/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/epmw/test_client.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/epmw/test_commands.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/epmw-quick-test-plan.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/fixtures/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/fixtures/responses.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/integration/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/integration/conftest.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/integration/helpers.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/integration/test_entitle_integration.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/integration/test_epmw_integration.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/integration/test_epmw_lifecycle.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/integration/test_pra_integration.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/integration/test_pra_lifecycle.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/integration/test_pws_integration.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/integration/test_pws_lifecycle.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pf/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pf/test_client.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pf/test_commands.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pra/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pra/test_client.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pra/test_commands.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pra/test_jump_item_fixes.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pra-smoke-test.sh +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pra-test-plan.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pws/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pws/test_client.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pws/test_commands.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pws/test_quick_sessions.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pws-quick-test-plan.md +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/pws-smoke-test.sh +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/secrets/__init__.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/secrets/test_client.py +0 -0
- {bt_cli-0.4.72 → bt_cli-0.4.73}/tests/secrets/test_commands.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.
|
|
3
|
+
BeyondTrust Platform CLI for Password Safe, Entitle, PRA, EPM Windows, EPM Linux, and the BeyondTrust Secrets API. **Version: 0.4.73**
|
|
4
4
|
|
|
5
5
|
## Setup
|
|
6
6
|
|
|
@@ -83,6 +83,7 @@ PASSWORD=$(bt pws quick checkout -s server -a admin --raw)
|
|
|
83
83
|
- PWS assets: Must create via workgroup endpoint
|
|
84
84
|
- ECM integration: PWS system name must match PRA jump item name
|
|
85
85
|
- **`-o json` is pure JSON on stdout — in every product.** All human status/progress banners *and interactive prompts* go to **stderr** (`core/output.py` `err_console`; `typer.confirm`/`typer.prompt` are called with `err=True`), so `... -o json | jq` and `json.load(stdin)` are safe even for `quick` workflow commands that narrate their steps. Enforced by static guards in `tests/core/test_json_stdout_purity.py` — when adding a command, use `print_success`/`print_warning`/`print_info` or `err_console.print` for anything that isn't the command's data. Consequence: piping *table* output to a file drops the narration (it's on stderr) — that's intended. PRA API 4xx `errors` objects are surfaced field-by-field, not collapsed to "Validation Failed".
|
|
86
|
+
- **`bt tree` / `bt find` are derived from the live Typer app** (`core/command_tree.py` walks the Click tree) — **never hardcode a command list**. They used to be hand-maintained literals and silently drifted to 278-of-460 commands missing (all of `bt pws sessions`/`audit`, the whole `bt pf` product) before 0.4.73. `tests/core/test_command_tree.py` fails if any registered command is undiscoverable. New commands need no tree/find edit; help text comes from the docstring's first line.
|
|
86
87
|
- **PRA tunnel create gates fields by `tunnel_type`**: tcp→`--ports`, mssql→`--username`/`--database`, k8s→`--url`/`--ca-cert`. **psql/mysql are created BARE** — the public Config API has no write path for their username/database (POST rejects, PATCH no-ops, PUT 405s) though GET shows them; CLI warns + ignores those flags. Set in `/login` UI.
|
|
87
88
|
- **PRA `export jump-items` defaults to a REAL export** (all types: shell/rdp/vnc/web/tunnel, full type-specific columns) that round-trips through `import jump-items`; `--sample` gives the blank template. `bt pra jump-items web create` exists.
|
|
88
89
|
- **PRA vault `associate -t protocol_tunnel` is MSSQL-only** (live-verified): server rejects psql/mysql/tcp/k8s with "Only SQL Server Tunnels are allowed" — use tag/criteria association for those. **TCP `--ports` needs listen;destination *pairs*** (even count; odd → 400 "number of parameters is invalid"). Jumpoint listing is `bt pra jumpoints list` (plural).
|
|
@@ -263,9 +263,10 @@ def find_command(
|
|
|
263
263
|
bt find secret # Find secret-related commands
|
|
264
264
|
bt find jump # Find jump-related commands
|
|
265
265
|
"""
|
|
266
|
+
from rich.markup import escape
|
|
266
267
|
from rich.table import Table
|
|
267
268
|
|
|
268
|
-
#
|
|
269
|
+
# Built from the live command tree, so it can never drift from reality
|
|
269
270
|
commands = _get_all_commands()
|
|
270
271
|
|
|
271
272
|
# Search
|
|
@@ -276,7 +277,7 @@ def find_command(
|
|
|
276
277
|
matches.append((cmd_path, cmd_help))
|
|
277
278
|
|
|
278
279
|
if not matches:
|
|
279
|
-
console.print(f"[yellow]No commands found matching '{term}'[/yellow]")
|
|
280
|
+
console.print(f"[yellow]No commands found matching '{escape(term)}'[/yellow]")
|
|
280
281
|
console.print("\nTry: bt tree # Show all commands")
|
|
281
282
|
return
|
|
282
283
|
|
|
@@ -286,374 +287,123 @@ def find_command(
|
|
|
286
287
|
|
|
287
288
|
for cmd_path, cmd_help in sorted(matches):
|
|
288
289
|
# Truncate help text
|
|
289
|
-
|
|
290
|
-
table.add_row(cmd_path,
|
|
290
|
+
short = cmd_help[:60] + "..." if len(cmd_help) > 60 else cmd_help
|
|
291
|
+
table.add_row(escape(cmd_path), escape(short))
|
|
291
292
|
|
|
292
293
|
console.print(table)
|
|
293
294
|
console.print(f"\n[dim]{len(matches)} command(s) found[/dim]")
|
|
294
295
|
|
|
295
296
|
|
|
297
|
+
def _chunk_verbs(names: list[str], width: int = 58) -> list[str]:
|
|
298
|
+
"""Pack subcommand names into pipe-joined lines of at most `width` chars."""
|
|
299
|
+
rows: list[str] = []
|
|
300
|
+
current = ""
|
|
301
|
+
for name in names:
|
|
302
|
+
candidate = f"{current}|{name}" if current else name
|
|
303
|
+
if current and len(candidate) > width:
|
|
304
|
+
rows.append(current)
|
|
305
|
+
current = name
|
|
306
|
+
else:
|
|
307
|
+
current = candidate
|
|
308
|
+
if current:
|
|
309
|
+
rows.append(current)
|
|
310
|
+
return rows
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def _render_tree_node(node, group, full: bool, top_level: bool = False) -> None:
|
|
314
|
+
"""Recursively add a Click group's children to a Rich tree node.
|
|
315
|
+
|
|
316
|
+
Groups whose children are all leaves collapse onto a single line
|
|
317
|
+
("accounts list|get|create|delete") to keep the full tree readable;
|
|
318
|
+
--full expands every command onto its own line with its help text.
|
|
319
|
+
"""
|
|
320
|
+
from rich.markup import escape
|
|
321
|
+
|
|
322
|
+
from .core import command_tree as ct
|
|
323
|
+
|
|
324
|
+
for name, sub in ct.children(group):
|
|
325
|
+
style = "bold yellow" if top_level else "green"
|
|
326
|
+
label = f"[{style}]{escape(name)}[/{style}]"
|
|
327
|
+
help_text = ct.short_help(sub)
|
|
328
|
+
|
|
329
|
+
if not ct.is_group(sub):
|
|
330
|
+
if help_text:
|
|
331
|
+
label += f" - [dim]{escape(help_text)}[/dim]"
|
|
332
|
+
node.add(label)
|
|
333
|
+
continue
|
|
334
|
+
|
|
335
|
+
kids = ct.children(sub)
|
|
336
|
+
if kids and not ct.has_subgroups(sub) and not full and not top_level:
|
|
337
|
+
# Compact: collapse the group's verbs onto as few lines as possible.
|
|
338
|
+
# Chunked by hand because Rich would character-wrap "a|b|c" mid-word.
|
|
339
|
+
rows = _chunk_verbs([n for n, _ in kids])
|
|
340
|
+
if len(rows) == 1:
|
|
341
|
+
node.add(f"{label} {escape(rows[0])}")
|
|
342
|
+
else:
|
|
343
|
+
child = node.add(label)
|
|
344
|
+
for row in rows:
|
|
345
|
+
child.add(escape(row))
|
|
346
|
+
continue
|
|
347
|
+
|
|
348
|
+
if help_text:
|
|
349
|
+
label += f" - [dim]{escape(help_text)}[/dim]"
|
|
350
|
+
_render_tree_node(node.add(label), sub, full)
|
|
351
|
+
|
|
352
|
+
|
|
296
353
|
@app.command("tree")
|
|
297
354
|
def tree_command(
|
|
298
|
-
|
|
355
|
+
path: Optional[list[str]] = typer.Argument(
|
|
356
|
+
None, help="Filter to a command path, e.g. 'pws' or 'pws sessions'"
|
|
357
|
+
),
|
|
358
|
+
full: bool = typer.Option(
|
|
359
|
+
False, "--full", "-f", help="Expand every command on its own line with help text"
|
|
360
|
+
),
|
|
299
361
|
) -> None:
|
|
300
362
|
"""Show command hierarchy tree.
|
|
301
363
|
|
|
302
|
-
|
|
364
|
+
Built by introspecting the live command tree, so it always reflects
|
|
365
|
+
every registered command.
|
|
303
366
|
|
|
304
367
|
Examples:
|
|
305
|
-
bt tree
|
|
306
|
-
bt tree pws
|
|
307
|
-
bt tree
|
|
368
|
+
bt tree # Show all commands
|
|
369
|
+
bt tree pws # Show only PWS commands
|
|
370
|
+
bt tree pws sessions # Drill into a subcommand group
|
|
371
|
+
bt tree pws --full # One line per command, with help text
|
|
308
372
|
"""
|
|
373
|
+
from rich.markup import escape
|
|
309
374
|
from rich.tree import Tree
|
|
310
375
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
# PWS
|
|
330
|
-
if not product or product == "pws":
|
|
331
|
-
pws = tree.add("[bold yellow]pws[/bold yellow] - Password Safe")
|
|
332
|
-
pws.add("[green]auth[/green] test")
|
|
333
|
-
pws.add("[green]search[/green] <query> - Search across all entities")
|
|
334
|
-
|
|
335
|
-
systems = pws.add("[green]systems[/green] list|get|create|update|delete")
|
|
336
|
-
accounts = pws.add("[green]accounts[/green] list|get|create|update|delete|rotate")
|
|
337
|
-
pws.add("[green]functional[/green] list|get|create|update|delete")
|
|
338
|
-
pws.add("[green]assets[/green] list|search|get|create|update|delete")
|
|
339
|
-
pws.add("[green]credentials[/green] checkout|checkin")
|
|
340
|
-
pws.add("[green]platforms[/green] list|get")
|
|
341
|
-
pws.add("[green]workgroups[/green] list|get")
|
|
342
|
-
|
|
343
|
-
secrets = pws.add("[green]secrets[/green]")
|
|
344
|
-
secrets.add("safes list|get|create|delete")
|
|
345
|
-
secrets.add("folders list|get|create|delete")
|
|
346
|
-
secrets.add("secrets list|get|create|create-text|create-file|delete")
|
|
347
|
-
|
|
348
|
-
pws.add("[green]quick[/green] checkout|onboard|offboard")
|
|
349
|
-
|
|
350
|
-
# PRA
|
|
351
|
-
if not product or product == "pra":
|
|
352
|
-
pra = tree.add("[bold yellow]pra[/bold yellow] - Privileged Remote Access")
|
|
353
|
-
pra.add("[green]auth[/green] test")
|
|
354
|
-
pra.add("[green]jumpoint[/green] list|get")
|
|
355
|
-
pra.add("[green]jump-groups[/green] list|get|create")
|
|
356
|
-
|
|
357
|
-
ji = pra.add("[green]jump-items[/green]")
|
|
358
|
-
ji.add("shell list|get|create|update|delete")
|
|
359
|
-
ji.add("rdp list|get|create|delete")
|
|
360
|
-
|
|
361
|
-
vault = pra.add("[green]vault[/green]")
|
|
362
|
-
vault.add("accounts list|get|create|delete|checkout|checkin|get-user-data|get-public-key")
|
|
363
|
-
vault.add("groups list|get")
|
|
364
|
-
|
|
365
|
-
pra.add("[green]users[/green] list|get|update|delete|group-policies|provision")
|
|
366
|
-
pra.add("[green]teams[/green] list|get")
|
|
367
|
-
pol = pra.add("[green]policies[/green]")
|
|
368
|
-
pol.add("jump list|get")
|
|
369
|
-
pol.add("session list")
|
|
370
|
-
pol.add("group list|get|create|update|delete|copy|provision")
|
|
371
|
-
pol.add(" + jumpoints|members|jump-groups|vault-accounts|")
|
|
372
|
-
pol.add(" vault-account-groups|teams (list|add|remove)")
|
|
373
|
-
|
|
374
|
-
pra.add("[green]quick[/green] shell-jump|rdp-jump|change-group-policy-update")
|
|
375
|
-
|
|
376
|
-
# Entitle
|
|
377
|
-
if not product or product == "entitle":
|
|
378
|
-
ent = tree.add("[bold yellow]entitle[/bold yellow] - Just-in-Time Access")
|
|
379
|
-
ent.add("[green]auth[/green] test")
|
|
380
|
-
ent.add("[green]integrations[/green] list|get")
|
|
381
|
-
ent.add("[green]resources[/green] list|get|create-virtual|delete")
|
|
382
|
-
ent.add("[green]roles[/green] list|get")
|
|
383
|
-
ent.add("[green]bundles[/green] list|get|create|delete")
|
|
384
|
-
ent.add("[green]workflows[/green] list|get")
|
|
385
|
-
ent.add("[green]users[/green] list|get")
|
|
386
|
-
ent.add("[green]permissions[/green] list|revoke")
|
|
387
|
-
ent.add("[green]policies[/green] list|get")
|
|
388
|
-
ent.add("[green]accounts[/green] list")
|
|
389
|
-
ent.add("[green]agents[/green] list|get|status")
|
|
390
|
-
|
|
391
|
-
# EPMW
|
|
392
|
-
if not product or product == "epmw":
|
|
393
|
-
epmw = tree.add("[bold yellow]epmw[/bold yellow] - EPM Windows")
|
|
394
|
-
epmw.add("[green]auth[/green] test")
|
|
395
|
-
epmw.add("[green]computers[/green] list|get|archive")
|
|
396
|
-
epmw.add("[green]groups[/green] list|get")
|
|
397
|
-
epmw.add("[green]policies[/green] list|get")
|
|
398
|
-
epmw.add("[green]requests[/green] list|get|approve|deny")
|
|
399
|
-
epmw.add("[green]quick[/green] approve-all")
|
|
400
|
-
|
|
401
|
-
# EPML
|
|
402
|
-
if not product or product == "epml":
|
|
403
|
-
epml = tree.add("[bold yellow]epml[/bold yellow] - EPM Linux")
|
|
404
|
-
epml.add("[green]auth[/green] test|status")
|
|
405
|
-
epml.add("[green]settings[/green] list|get")
|
|
406
|
-
epml.add("[green]users[/green] list|get")
|
|
407
|
-
epml.add("[green]hosts[/green] list|features")
|
|
408
|
-
epml.add("[green]license[/green] get")
|
|
409
|
-
epml.add("[green]siems[/green] list")
|
|
410
|
-
audit = epml.add("[green]audit[/green]")
|
|
411
|
-
audit.add("sessions list|categories")
|
|
412
|
-
epml.add("[green]client-pkg[/green] list|status|link")
|
|
413
|
-
epml.add("[green]external-apis[/green] list|get")
|
|
414
|
-
epml.add("[green]iolog[/green] list")
|
|
415
|
-
rbp = epml.add("[green]rbp[/green] - Role-Based Policy")
|
|
416
|
-
rbp.add("cmdgrps list|create|delete + commands list|add|clear|replace")
|
|
417
|
-
rbp.add("hostgrps list|create|delete + hosts list|add|clear|replace")
|
|
418
|
-
rbp.add("usergrps list|create|create-multiple|delete + users list|add|clear|replace")
|
|
419
|
-
rbp.add("tmdategrps list|create|delete + tmdates list|add|clear|replace")
|
|
420
|
-
rbp.add("roles list|create|delete|duplicate")
|
|
421
|
-
rbp.add(" + cmdgrps|hostgrps|usergrps|tmdategrps list|add|remove")
|
|
422
|
-
rbp.add("entitlement run [--raw]")
|
|
423
|
-
rbp.add("policy export|import|revert|versions|diff|snapshot|delete-all")
|
|
424
|
-
rbp.add("tests suites list|get|create|update|delete")
|
|
425
|
-
rbp.add(" + tests add|update|delete + run --suite <id>")
|
|
426
|
-
rbp.add("tx status|begin|commit|rollback|abort")
|
|
427
|
-
epml.add("[green]quick[/green] tests-then-deploy")
|
|
428
|
-
|
|
429
|
-
# Secrets API
|
|
430
|
-
if not product or product == "secrets":
|
|
431
|
-
secrets = tree.add("[bold yellow]secrets[/bold yellow] - BeyondTrust Secrets API")
|
|
432
|
-
secrets.add("[green]auth[/green] test|status")
|
|
433
|
-
secrets.add("[green]folders[/green] list|get|create|delete")
|
|
434
|
-
secrets.add("[green]static[/green] list|get|create|update|delete")
|
|
435
|
-
secrets.add("[green]dynamic[/green] list|get|generate|create|delete")
|
|
436
|
-
secrets.add("[green]leases[/green] list|get|revoke")
|
|
437
|
-
secrets.add("[green]integrations[/green] list|get|create|update|delete")
|
|
438
|
-
|
|
439
|
-
# Quick
|
|
440
|
-
if not product or product == "quick":
|
|
441
|
-
quick = tree.add("[bold yellow]quick[/bold yellow] - Cross-product workflows")
|
|
442
|
-
quick.add("[green]pasm-onboard[/green] - Onboard to PWS + PRA")
|
|
443
|
-
quick.add("[green]pasm-offboard[/green] - Remove from PWS + PRA")
|
|
444
|
-
quick.add("[green]pasm-search[/green] - Search across PWS + PRA")
|
|
376
|
+
from .core import command_tree as ct
|
|
377
|
+
|
|
378
|
+
root = ct.get_root_command()
|
|
379
|
+
parts = [p.lower() for p in (path or [])]
|
|
380
|
+
|
|
381
|
+
node_cmd = ct.resolve(root, parts)
|
|
382
|
+
if node_cmd is None:
|
|
383
|
+
console.print(f"[red]Unknown command path: {escape(' '.join(parts))}[/red]")
|
|
384
|
+
available = ", ".join(n for n, _ in ct.children(root))
|
|
385
|
+
console.print(f"Available: {escape(available)}")
|
|
386
|
+
raise typer.Exit(1)
|
|
387
|
+
|
|
388
|
+
label = "[bold cyan]" + " ".join(["bt"] + parts) + "[/bold cyan]"
|
|
389
|
+
if not ct.is_group(node_cmd):
|
|
390
|
+
help_text = ct.short_help(node_cmd)
|
|
391
|
+
console.print(f"{label}" + (f" - [dim]{escape(help_text)}[/dim]" if help_text else ""))
|
|
392
|
+
return
|
|
445
393
|
|
|
394
|
+
tree = Tree(label)
|
|
395
|
+
_render_tree_node(tree, node_cmd, full, top_level=not parts)
|
|
446
396
|
console.print(tree)
|
|
447
397
|
|
|
398
|
+
total = sum(1 for _ in ct.walk(node_cmd))
|
|
399
|
+
console.print(f"\n[dim]{total} command(s)[/dim]")
|
|
400
|
+
|
|
448
401
|
|
|
449
402
|
def _get_all_commands() -> list[tuple[str, str]]:
|
|
450
|
-
"""
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
("bt find <term>", "Search for commands by name or description"),
|
|
455
|
-
("bt tree", "Show command hierarchy tree"),
|
|
456
|
-
("bt skills", "Install Claude Code skills"),
|
|
457
|
-
("bt configure", "Configure bt-cli settings"),
|
|
458
|
-
# PWS
|
|
459
|
-
("bt pws auth test", "Test Password Safe connection"),
|
|
460
|
-
("bt pws search <query>", "Search across all PWS entities"),
|
|
461
|
-
("bt pws systems list", "List managed systems"),
|
|
462
|
-
("bt pws systems get", "Get a managed system"),
|
|
463
|
-
("bt pws systems create", "Create a managed system"),
|
|
464
|
-
("bt pws systems update", "Update a managed system"),
|
|
465
|
-
("bt pws systems delete", "Delete a managed system"),
|
|
466
|
-
("bt pws accounts list", "List managed accounts"),
|
|
467
|
-
("bt pws accounts get", "Get a managed account"),
|
|
468
|
-
("bt pws accounts create", "Create a managed account"),
|
|
469
|
-
("bt pws accounts update", "Update a managed account"),
|
|
470
|
-
("bt pws accounts delete", "Delete a managed account"),
|
|
471
|
-
("bt pws accounts rotate", "Rotate account password"),
|
|
472
|
-
("bt pws functional list", "List functional accounts (for auto-management)"),
|
|
473
|
-
("bt pws functional get", "Get a functional account"),
|
|
474
|
-
("bt pws functional create", "Create a functional account"),
|
|
475
|
-
("bt pws functional update", "Update a functional account"),
|
|
476
|
-
("bt pws functional delete", "Delete a functional account"),
|
|
477
|
-
("bt pws assets list", "List assets"),
|
|
478
|
-
("bt pws assets search", "Search assets"),
|
|
479
|
-
("bt pws assets get", "Get an asset"),
|
|
480
|
-
("bt pws assets create", "Create an asset"),
|
|
481
|
-
("bt pws assets update", "Update an asset"),
|
|
482
|
-
("bt pws assets delete", "Delete an asset"),
|
|
483
|
-
("bt pws credentials checkout", "Check out account credentials"),
|
|
484
|
-
("bt pws credentials checkin", "Check in account credentials"),
|
|
485
|
-
("bt pws secrets safes list", "List Secrets Safe safes"),
|
|
486
|
-
("bt pws secrets folders list", "List Secrets Safe folders"),
|
|
487
|
-
("bt pws secrets secrets list", "List secrets"),
|
|
488
|
-
("bt pws secrets secrets create", "Create a secret"),
|
|
489
|
-
("bt pws secrets secrets create-text", "Create a text secret (supports --file)"),
|
|
490
|
-
("bt pws secrets secrets create-file", "Create a file secret"),
|
|
491
|
-
("bt pws quick checkout", "Quick checkout workflow"),
|
|
492
|
-
("bt pws quick onboard", "Quick onboard system + account"),
|
|
493
|
-
("bt pws quick offboard", "Quick offboard system"),
|
|
494
|
-
# PRA
|
|
495
|
-
("bt pra auth test", "Test PRA connection"),
|
|
496
|
-
("bt pra jumpoint list", "List jumpoints"),
|
|
497
|
-
("bt pra jump-groups list", "List jump groups"),
|
|
498
|
-
("bt pra jump-groups create", "Create a jump group"),
|
|
499
|
-
("bt pra jump-items shell list", "List shell jump items"),
|
|
500
|
-
("bt pra jump-items shell create", "Create a shell jump item"),
|
|
501
|
-
("bt pra jump-items shell update", "Update a shell jump item"),
|
|
502
|
-
("bt pra jump-items shell delete", "Delete a shell jump item"),
|
|
503
|
-
("bt pra jump-items rdp list", "List RDP jump items"),
|
|
504
|
-
("bt pra jump-items rdp create", "Create an RDP jump item"),
|
|
505
|
-
("bt pra vault accounts list", "List vault accounts"),
|
|
506
|
-
("bt pra vault accounts get", "Get a vault account"),
|
|
507
|
-
("bt pra vault accounts create", "Create a vault account"),
|
|
508
|
-
("bt pra vault accounts checkout", "Checkout vault credentials"),
|
|
509
|
-
("bt pra vault accounts get-user-data", "Generate EC2 user-data for SSH CA"),
|
|
510
|
-
("bt pra vault accounts get-public-key", "Get SSH CA public key"),
|
|
511
|
-
("bt pra users list", "List PRA users"),
|
|
512
|
-
("bt pra users update", "Update a user (--unlock to clear failed_logins)"),
|
|
513
|
-
("bt pra users group-policies", "Show GPs a user is a member of"),
|
|
514
|
-
("bt pra users provision -u <id>", "Recompute permissions for a user"),
|
|
515
|
-
("bt pra policies group list", "List Group Policies"),
|
|
516
|
-
("bt pra policies group create --name X", "Create a Group Policy"),
|
|
517
|
-
("bt pra policies group copy <id> --name Y", "Duplicate a Group Policy"),
|
|
518
|
-
("bt pra policies group members list <id>", "List members of a GP"),
|
|
519
|
-
("bt pra policies group jump-groups add <id>", "Attach a Jump Group to a GP"),
|
|
520
|
-
("bt pra policies group vault-accounts add <id>", "Attach a Vault Account to a GP"),
|
|
521
|
-
("bt pra policies group teams add <id>", "Attach a Team to a GP"),
|
|
522
|
-
("bt pra quick change-group-policy-update", "Interactive: toggle a user's GP memberships"),
|
|
523
|
-
# Entitle
|
|
524
|
-
("bt entitle auth test", "Test Entitle connection"),
|
|
525
|
-
("bt entitle integrations list", "List integrations"),
|
|
526
|
-
("bt entitle resources list", "List resources"),
|
|
527
|
-
("bt entitle resources create-virtual", "Create a virtual resource"),
|
|
528
|
-
("bt entitle roles list", "List roles"),
|
|
529
|
-
("bt entitle bundles list", "List bundles"),
|
|
530
|
-
("bt entitle workflows list", "List workflows"),
|
|
531
|
-
("bt entitle users list", "List users"),
|
|
532
|
-
("bt entitle permissions list", "List permissions"),
|
|
533
|
-
("bt entitle permissions revoke", "Revoke a permission"),
|
|
534
|
-
("bt entitle agents list", "List agents"),
|
|
535
|
-
("bt entitle agents status", "Show agent status summary"),
|
|
536
|
-
# EPMW
|
|
537
|
-
("bt epmw auth test", "Test EPM Windows connection"),
|
|
538
|
-
("bt epmw computers list", "List managed computers"),
|
|
539
|
-
("bt epmw computers archive", "Archive a computer"),
|
|
540
|
-
("bt epmw groups list", "List computer groups"),
|
|
541
|
-
("bt epmw policies list", "List policies"),
|
|
542
|
-
("bt epmw requests list", "List elevation requests"),
|
|
543
|
-
("bt epmw requests approve", "Approve an elevation request"),
|
|
544
|
-
("bt epmw requests deny", "Deny an elevation request"),
|
|
545
|
-
("bt epmw quick approve-all", "Approve all pending requests"),
|
|
546
|
-
# EPML
|
|
547
|
-
("bt epml auth test", "Test EPM Linux connection"),
|
|
548
|
-
("bt epml auth status", "Show EPM Linux configuration status"),
|
|
549
|
-
("bt epml settings list", "List site-level settings"),
|
|
550
|
-
("bt epml settings get", "Get a single setting by key"),
|
|
551
|
-
("bt epml users list", "List EPM Linux users"),
|
|
552
|
-
("bt epml users get", "Get a user by ID"),
|
|
553
|
-
("bt epml hosts list", "List PMUL hosts"),
|
|
554
|
-
("bt epml hosts features", "Show feature flags per PMUL host"),
|
|
555
|
-
("bt epml license get", "Get the EPM Linux license"),
|
|
556
|
-
("bt epml siems list", "List SIEM forwarders"),
|
|
557
|
-
("bt epml audit sessions list", "List audit session records"),
|
|
558
|
-
("bt epml audit sessions categories", "List audit session categories"),
|
|
559
|
-
("bt epml client-pkg list", "List built client installer packages"),
|
|
560
|
-
("bt epml client-pkg status", "Client package build status"),
|
|
561
|
-
("bt epml client-pkg link", "Get presigned download URL for a package"),
|
|
562
|
-
("bt epml external-apis list", "List external API integrations"),
|
|
563
|
-
("bt epml external-apis get", "Get an external API by ID"),
|
|
564
|
-
("bt epml iolog list", "List iolog files for a host"),
|
|
565
|
-
# EPML RBP
|
|
566
|
-
("bt epml rbp cmdgrps list", "List RBP command groups"),
|
|
567
|
-
("bt epml rbp cmdgrps create", "Create an RBP command group"),
|
|
568
|
-
("bt epml rbp cmdgrps delete", "Delete RBP command groups"),
|
|
569
|
-
("bt epml rbp cmdgrps commands list", "List commands within a cmdgrp"),
|
|
570
|
-
("bt epml rbp cmdgrps commands add", "Add commands to a cmdgrp"),
|
|
571
|
-
("bt epml rbp cmdgrps commands clear", "Clear ALL commands in a cmdgrp"),
|
|
572
|
-
("bt epml rbp cmdgrps commands replace", "Replace cmdgrp's full command list"),
|
|
573
|
-
("bt epml rbp hostgrps list", "List RBP host groups"),
|
|
574
|
-
("bt epml rbp hostgrps create", "Create an RBP host group"),
|
|
575
|
-
("bt epml rbp hostgrps delete", "Delete RBP host groups"),
|
|
576
|
-
("bt epml rbp hostgrps hosts list", "List hosts within a hostgrp"),
|
|
577
|
-
("bt epml rbp hostgrps hosts add", "Add hosts to a hostgrp"),
|
|
578
|
-
("bt epml rbp hostgrps hosts clear", "Clear ALL hosts in a hostgrp"),
|
|
579
|
-
("bt epml rbp hostgrps hosts replace", "Replace hostgrp's full host list"),
|
|
580
|
-
("bt epml rbp usergrps list", "List RBP user groups"),
|
|
581
|
-
("bt epml rbp usergrps create", "Create an RBP user group"),
|
|
582
|
-
("bt epml rbp usergrps create-multiple", "Bulk-create user groups from a JSON file"),
|
|
583
|
-
("bt epml rbp usergrps delete", "Delete RBP user groups"),
|
|
584
|
-
("bt epml rbp usergrps users list", "List users within a usergrp"),
|
|
585
|
-
("bt epml rbp usergrps users add", "Add users to a usergrp"),
|
|
586
|
-
("bt epml rbp usergrps users clear", "Clear ALL users in a usergrp"),
|
|
587
|
-
("bt epml rbp usergrps users replace", "Replace usergrp's full user list"),
|
|
588
|
-
("bt epml rbp tmdategrps list", "List RBP time/date groups"),
|
|
589
|
-
("bt epml rbp tmdategrps create", "Create an RBP time/date group"),
|
|
590
|
-
("bt epml rbp tmdategrps delete", "Delete RBP time/date groups"),
|
|
591
|
-
("bt epml rbp tmdategrps tmdates list", "List time/date entries in a group"),
|
|
592
|
-
("bt epml rbp tmdategrps tmdates add", "Add time/date entries"),
|
|
593
|
-
("bt epml rbp tmdategrps tmdates clear", "Clear ALL time/dates in a group"),
|
|
594
|
-
("bt epml rbp tmdategrps tmdates replace", "Replace the group's full tmdate list"),
|
|
595
|
-
("bt epml rbp roles list", "List RBP roles"),
|
|
596
|
-
("bt epml rbp roles create", "Create an RBP role"),
|
|
597
|
-
("bt epml rbp roles delete", "Delete RBP roles"),
|
|
598
|
-
("bt epml rbp roles duplicate", "Duplicate an RBP role"),
|
|
599
|
-
("bt epml rbp roles cmdgrps list/add/remove", "Manage cmdgrps on a role"),
|
|
600
|
-
("bt epml rbp roles hostgrps list/add/remove", "Manage hostgrps on a role"),
|
|
601
|
-
("bt epml rbp roles usergrps list/add/remove", "Manage usergrps on a role"),
|
|
602
|
-
("bt epml rbp roles tmdategrps list/add/remove", "Manage tmdategrps on a role"),
|
|
603
|
-
("bt epml rbp entitlement run", "Run the entitlement report"),
|
|
604
|
-
("bt epml rbp policy export", "Export the full RBP DB"),
|
|
605
|
-
("bt epml rbp policy import", "Import an RBP DB serialization"),
|
|
606
|
-
("bt epml rbp policy revert", "Revert policy to last committed state"),
|
|
607
|
-
("bt epml rbp policy versions", "List RBP policy versions"),
|
|
608
|
-
("bt epml rbp policy diff", "Diff current draft against a prior version"),
|
|
609
|
-
("bt epml rbp policy snapshot", "Get full current RBP snapshot"),
|
|
610
|
-
("bt epml rbp policy delete-all", "Delete the entire RBP DB (destructive)"),
|
|
611
|
-
("bt epml rbp tx status", "Show RBP transaction state"),
|
|
612
|
-
("bt epml rbp tx begin", "Begin an RBP transaction"),
|
|
613
|
-
("bt epml rbp tx commit", "Commit the RBP transaction"),
|
|
614
|
-
("bt epml rbp tx rollback", "Rollback the RBP transaction"),
|
|
615
|
-
("bt epml rbp tx abort", "Abort the RBP transaction"),
|
|
616
|
-
("bt epml rbp tests suites list", "List RBP test suites"),
|
|
617
|
-
("bt epml rbp tests suites get", "Get a test suite (with tests)"),
|
|
618
|
-
("bt epml rbp tests suites create", "Create a test suite"),
|
|
619
|
-
("bt epml rbp tests suites update", "Update a test suite"),
|
|
620
|
-
("bt epml rbp tests suites delete", "Delete a test suite"),
|
|
621
|
-
("bt epml rbp tests tests add", "Add a test to a suite"),
|
|
622
|
-
("bt epml rbp tests tests update", "Update a test"),
|
|
623
|
-
("bt epml rbp tests tests delete", "Delete a test"),
|
|
624
|
-
("bt epml rbp tests run", "Run a test suite, exit non-zero on failure"),
|
|
625
|
-
("bt epml quick tests-then-deploy", "Run tests, commit or rollback the open RBP transaction"),
|
|
626
|
-
# Secrets API
|
|
627
|
-
("bt secrets auth test", "Test BeyondTrust Secrets API connection"),
|
|
628
|
-
("bt secrets auth status", "Show Secrets API configuration status"),
|
|
629
|
-
("bt secrets folders list", "List folders (server-side filter)"),
|
|
630
|
-
("bt secrets folders get", "Get folder metadata"),
|
|
631
|
-
("bt secrets folders create", "Create a folder"),
|
|
632
|
-
("bt secrets folders delete", "Delete a folder"),
|
|
633
|
-
("bt secrets static list", "List static secrets"),
|
|
634
|
-
("bt secrets static get", "Get a static secret value"),
|
|
635
|
-
("bt secrets static create", "Create a static secret"),
|
|
636
|
-
("bt secrets static update", "Update a static secret (bumps version)"),
|
|
637
|
-
("bt secrets static delete", "Delete a static secret"),
|
|
638
|
-
("bt secrets dynamic list", "List dynamic-secret configs"),
|
|
639
|
-
("bt secrets dynamic get", "Get a dynamic-secret config"),
|
|
640
|
-
("bt secrets dynamic generate", "Mint a fresh dynamic credential (e.g. AWS STS)"),
|
|
641
|
-
("bt secrets dynamic create", "Create a dynamic-secret config"),
|
|
642
|
-
("bt secrets dynamic delete", "Delete a dynamic-secret config"),
|
|
643
|
-
("bt secrets leases list", "List active leases for a dynamic secret"),
|
|
644
|
-
("bt secrets leases get", "Get lease details by id"),
|
|
645
|
-
("bt secrets leases revoke", "Revoke a lease (scope-gated; lab returns 403)"),
|
|
646
|
-
("bt secrets integrations list", "List integrations"),
|
|
647
|
-
("bt secrets integrations get", "Get an integration"),
|
|
648
|
-
("bt secrets integrations create", "Create an integration"),
|
|
649
|
-
("bt secrets integrations update", "Update an integration (PUT or --partial PATCH)"),
|
|
650
|
-
("bt secrets integrations delete", "Delete an integration"),
|
|
651
|
-
# Quick
|
|
652
|
-
("bt quick pasm-onboard", "Onboard host to PWS + PRA (Total PASM)"),
|
|
653
|
-
("bt quick pasm-offboard", "Offboard host from PWS + PRA"),
|
|
654
|
-
("bt quick pasm-search", "Search across PWS + PRA"),
|
|
655
|
-
]
|
|
656
|
-
return commands
|
|
403
|
+
"""List every command with its help text, read from the live command tree."""
|
|
404
|
+
from .core import command_tree as ct
|
|
405
|
+
|
|
406
|
+
return list(ct.walk(ct.get_root_command()))
|
|
657
407
|
|
|
658
408
|
|
|
659
409
|
@app.command("skills")
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Introspection over the live Typer command tree.
|
|
2
|
+
|
|
3
|
+
`bt tree` and `bt find` used to be hand-maintained lists that silently drifted
|
|
4
|
+
from the real command surface every time a command was added. Everything here
|
|
5
|
+
walks the actual command objects instead, so the two can never disagree again.
|
|
6
|
+
|
|
7
|
+
Deliberately does NOT ``import click``. Typer >= 0.26 vendors click as the
|
|
8
|
+
private ``typer._click`` and no longer declares a click dependency, so a
|
|
9
|
+
top-level import fails outright on a stock install; and its ``TyperGroup``
|
|
10
|
+
subclasses ``Command`` rather than a ``Group``, so ``isinstance(cmd, Group)``
|
|
11
|
+
is wrong there too. Duck-typing on ``.commands`` is correct on every typer
|
|
12
|
+
version the project supports (>=0.12).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from typing import Any, Iterator, Optional
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_root_command() -> Any:
|
|
19
|
+
"""Return the root command object for the `bt` app."""
|
|
20
|
+
from typer.main import get_command
|
|
21
|
+
|
|
22
|
+
from ..cli import app
|
|
23
|
+
|
|
24
|
+
return get_command(app)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def is_group(cmd: Any) -> bool:
|
|
28
|
+
"""True if the command has subcommands (a group, in any typer version)."""
|
|
29
|
+
commands = getattr(cmd, "commands", None)
|
|
30
|
+
return commands is not None and hasattr(commands, "items")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def short_help(cmd: Any) -> str:
|
|
34
|
+
"""First meaningful line of a command's help text."""
|
|
35
|
+
text = getattr(cmd, "short_help", None) or getattr(cmd, "help", None) or ""
|
|
36
|
+
for line in text.splitlines():
|
|
37
|
+
line = line.strip()
|
|
38
|
+
if line:
|
|
39
|
+
return line
|
|
40
|
+
return ""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def children(group: Any) -> list[tuple[str, Any]]:
|
|
44
|
+
"""Visible child commands of a group, sorted by name."""
|
|
45
|
+
return [
|
|
46
|
+
(name, cmd)
|
|
47
|
+
for name, cmd in sorted(group.commands.items())
|
|
48
|
+
if not getattr(cmd, "hidden", False)
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def has_subgroups(group: Any) -> bool:
|
|
53
|
+
return any(is_group(cmd) for _, cmd in children(group))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def walk(cmd: Any, path: Optional[list[str]] = None) -> Iterator[tuple[str, str]]:
|
|
57
|
+
"""Yield (full command path, short help) for every leaf command, depth-first.
|
|
58
|
+
|
|
59
|
+
A group that can be invoked on its own (``invoke_without_command``) is
|
|
60
|
+
yielded as a runnable command in addition to being recursed into.
|
|
61
|
+
"""
|
|
62
|
+
path = path or ["bt"]
|
|
63
|
+
if is_group(cmd):
|
|
64
|
+
if getattr(cmd, "invoke_without_command", False):
|
|
65
|
+
yield " ".join(path), short_help(cmd)
|
|
66
|
+
for name, sub in children(cmd):
|
|
67
|
+
yield from walk(sub, path + [name])
|
|
68
|
+
else:
|
|
69
|
+
yield " ".join(path), short_help(cmd)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def resolve(root: Any, parts: list[str]) -> Optional[Any]:
|
|
73
|
+
"""Follow a command path (e.g. ["pws", "sessions"]) from the root."""
|
|
74
|
+
cmd = root
|
|
75
|
+
for part in parts:
|
|
76
|
+
if not is_group(cmd):
|
|
77
|
+
return None
|
|
78
|
+
sub = cmd.commands.get(part)
|
|
79
|
+
if sub is None or getattr(sub, "hidden", False):
|
|
80
|
+
return None
|
|
81
|
+
cmd = sub
|
|
82
|
+
return cmd
|