bt-cli 0.4.27__tar.gz → 0.4.29__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.27 → bt_cli-0.4.29}/CLAUDE.md +1 -1
- {bt_cli-0.4.27 → bt_cli-0.4.29}/PKG-INFO +1 -1
- {bt_cli-0.4.27 → bt_cli-0.4.29}/pyproject.toml +1 -1
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/__init__.py +1 -1
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/commands/configure.py +218 -2
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/client/base.py +12 -4
- {bt_cli-0.4.27 → bt_cli-0.4.29}/.claude/skills/bt/SKILL.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/.claude/skills/entitle/SKILL.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/.claude/skills/epmw/SKILL.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/.claude/skills/pra/SKILL.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/.claude/skills/pws/SKILL.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/.env.example +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/.github/workflows/ci.yml +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/.github/workflows/release.yml +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/.gitignore +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/README.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/assets/cli-help.png +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/assets/cli-output.png +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/bt-cli.spec +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/bt_entry.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/scripts/bt_entry.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/scripts/sync-package-data.sh +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/cli.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/commands/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/commands/learn.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/commands/quick.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/core/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/core/auth.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/core/client.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/core/config.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/core/config_file.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/core/csv_utils.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/core/errors.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/core/output.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/core/prompts.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/core/rest_debug.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/data/CLAUDE.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/data/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/data/skills/bt/SKILL.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/data/skills/entitle/SKILL.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/data/skills/epmw/SKILL.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/data/skills/pra/SKILL.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/data/skills/pws/SKILL.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/client/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/client/base.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/commands/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/commands/accounts.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/commands/applications.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/commands/auth.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/commands/bundles.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/commands/integrations.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/commands/permissions.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/commands/policies.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/commands/resources.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/commands/roles.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/commands/users.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/commands/workflows.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/models/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/models/bundle.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/models/common.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/models/integration.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/models/permission.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/models/policy.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/models/resource.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/models/role.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/models/user.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/entitle/models/workflow.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/client/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/client/base.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/commands/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/commands/audits.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/commands/auth.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/commands/computers.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/commands/events.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/commands/groups.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/commands/policies.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/commands/quick.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/commands/requests.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/commands/roles.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/commands/tasks.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/commands/users.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/epmw/models/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/client/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/commands/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/commands/auth.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/commands/import_export.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/commands/jump_clients.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/commands/jump_groups.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/commands/jump_items.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/commands/jumpoints.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/commands/policies.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/commands/quick.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/commands/teams.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/commands/users.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/commands/vault.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/models/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/models/common.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/models/jump_client.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/models/jump_group.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/models/jump_item.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/models/jumpoint.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/models/team.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/models/user.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pra/models/vault.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/client/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/client/base.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/client/beyondinsight.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/client/passwordsafe.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/accounts.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/assets.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/attributes.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/auth.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/clouds.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/config.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/credentials.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/databases.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/directories.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/functional.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/import_export.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/platforms.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/quick.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/search.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/secrets.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/systems.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/users.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/commands/workgroups.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/config.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/models/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/models/account.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/models/asset.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/models/common.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/src/bt_cli/pws/models/system.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/conftest.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/core/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/core/test_auth.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/core/test_config.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/core/test_errors.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/core/test_rest_debug.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/entitle/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/entitle/test_client.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/entitle/test_commands.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/entitle-smoke-test.sh +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/epmw/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/epmw/test_client.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/epmw/test_commands.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/epmw-quick-test-plan.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/fixtures/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/fixtures/responses.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/integration/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/integration/conftest.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/integration/helpers.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/integration/test_entitle_integration.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/integration/test_epmw_integration.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/integration/test_epmw_lifecycle.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/integration/test_pra_integration.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/integration/test_pra_lifecycle.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/integration/test_pws_integration.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/integration/test_pws_lifecycle.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/pra/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/pra/test_client.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/pra/test_commands.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/pra-smoke-test.sh +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/pra-test-plan.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/pws/__init__.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/pws/test_client.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/pws/test_commands.py +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/pws-quick-test-plan.md +0 -0
- {bt_cli-0.4.27 → bt_cli-0.4.29}/tests/pws-smoke-test.sh +0 -0
|
@@ -298,11 +298,21 @@ def show_config(
|
|
|
298
298
|
profile: Optional[str] = typer.Option(None, "--profile", help="Profile to show"),
|
|
299
299
|
show_secrets: bool = typer.Option(False, "--show-secrets", help="Show secret values"),
|
|
300
300
|
) -> None:
|
|
301
|
-
"""Show
|
|
301
|
+
"""Show configuration from config file.
|
|
302
|
+
|
|
303
|
+
Note: This only shows profiles saved to ~/.bt-cli/config.yaml.
|
|
304
|
+
If you're using environment variables or .env file, use:
|
|
305
|
+
|
|
306
|
+
bt configure effective
|
|
307
|
+
|
|
308
|
+
to see the actual configuration in use.
|
|
309
|
+
"""
|
|
302
310
|
config = load_config_file()
|
|
303
311
|
|
|
304
312
|
if not config.profiles:
|
|
305
|
-
print_warning("No
|
|
313
|
+
print_warning("No profiles in config file. Run 'bt configure' to set up.")
|
|
314
|
+
console.print("\n[dim]Tip: If using .env or environment variables, run:[/dim]")
|
|
315
|
+
console.print("[cyan] bt configure effective[/cyan]")
|
|
306
316
|
raise typer.Exit(0)
|
|
307
317
|
|
|
308
318
|
profiles_to_show = [profile] if profile else config.list_profiles()
|
|
@@ -413,3 +423,209 @@ def show_path() -> None:
|
|
|
413
423
|
console.print("[green]Config file exists[/green]")
|
|
414
424
|
else:
|
|
415
425
|
console.print("[yellow]Config file does not exist yet[/yellow]")
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
@app.command("import-env")
|
|
429
|
+
def import_from_env(
|
|
430
|
+
profile: str = typer.Option("default", "--profile", "-p", help="Profile name to save as"),
|
|
431
|
+
force: bool = typer.Option(False, "--force", "-f", help="Overwrite existing profile"),
|
|
432
|
+
) -> None:
|
|
433
|
+
"""Import configuration from environment variables into a profile.
|
|
434
|
+
|
|
435
|
+
This saves the current BT_* environment variables (including .env file)
|
|
436
|
+
into a named profile in the config file. Useful for:
|
|
437
|
+
|
|
438
|
+
- Converting .env setup to profile-based config
|
|
439
|
+
- Creating profiles from existing environment
|
|
440
|
+
- Backing up current config to file
|
|
441
|
+
|
|
442
|
+
Example:
|
|
443
|
+
bt configure import-env --profile production
|
|
444
|
+
"""
|
|
445
|
+
import os
|
|
446
|
+
from dotenv import load_dotenv, find_dotenv
|
|
447
|
+
from rich.prompt import Confirm
|
|
448
|
+
|
|
449
|
+
# Load .env if present
|
|
450
|
+
env_file = find_dotenv()
|
|
451
|
+
if env_file:
|
|
452
|
+
load_dotenv(env_file)
|
|
453
|
+
console.print(f"[dim]Loaded .env from: {env_file}[/dim]\n")
|
|
454
|
+
|
|
455
|
+
config = load_config_file()
|
|
456
|
+
|
|
457
|
+
# Check if profile exists
|
|
458
|
+
if profile in config.profiles and not force:
|
|
459
|
+
if not Confirm.ask(f"Profile '{profile}' exists. Overwrite?", default=False):
|
|
460
|
+
print_info("Cancelled")
|
|
461
|
+
raise typer.Exit(0)
|
|
462
|
+
|
|
463
|
+
# Product environment variable mappings
|
|
464
|
+
env_mappings = {
|
|
465
|
+
"pws": {
|
|
466
|
+
"api_url": "BT_PWS_API_URL",
|
|
467
|
+
"api_key": "BT_PWS_API_KEY",
|
|
468
|
+
"client_id": "BT_PWS_CLIENT_ID",
|
|
469
|
+
"client_secret": "BT_PWS_CLIENT_SECRET",
|
|
470
|
+
"run_as": "BT_PWS_RUN_AS",
|
|
471
|
+
"verify_ssl": "BT_PWS_VERIFY_SSL",
|
|
472
|
+
"timeout": "BT_PWS_TIMEOUT",
|
|
473
|
+
},
|
|
474
|
+
"pra": {
|
|
475
|
+
"api_url": "BT_PRA_API_URL",
|
|
476
|
+
"client_id": "BT_PRA_CLIENT_ID",
|
|
477
|
+
"client_secret": "BT_PRA_CLIENT_SECRET",
|
|
478
|
+
"verify_ssl": "BT_PRA_VERIFY_SSL",
|
|
479
|
+
"timeout": "BT_PRA_TIMEOUT",
|
|
480
|
+
},
|
|
481
|
+
"entitle": {
|
|
482
|
+
"api_url": "BT_ENTITLE_API_URL",
|
|
483
|
+
"api_key": "BT_ENTITLE_API_KEY",
|
|
484
|
+
"verify_ssl": "BT_ENTITLE_VERIFY_SSL",
|
|
485
|
+
"timeout": "BT_ENTITLE_TIMEOUT",
|
|
486
|
+
},
|
|
487
|
+
"epmw": {
|
|
488
|
+
"api_url": "BT_EPM_API_URL",
|
|
489
|
+
"client_id": "BT_EPM_CLIENT_ID",
|
|
490
|
+
"client_secret": "BT_EPM_CLIENT_SECRET",
|
|
491
|
+
"verify_ssl": "BT_EPM_VERIFY_SSL",
|
|
492
|
+
"timeout": "BT_EPM_TIMEOUT",
|
|
493
|
+
},
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
imported = []
|
|
497
|
+
for product, env_vars in env_mappings.items():
|
|
498
|
+
product_config = {}
|
|
499
|
+
for setting, env_var in env_vars.items():
|
|
500
|
+
value = os.getenv(env_var)
|
|
501
|
+
if value:
|
|
502
|
+
# Convert types
|
|
503
|
+
if setting == "verify_ssl":
|
|
504
|
+
product_config[setting] = value.lower() not in ("false", "0", "no")
|
|
505
|
+
elif setting == "timeout":
|
|
506
|
+
try:
|
|
507
|
+
product_config[setting] = float(value)
|
|
508
|
+
except ValueError:
|
|
509
|
+
product_config[setting] = 30.0
|
|
510
|
+
else:
|
|
511
|
+
product_config[setting] = value
|
|
512
|
+
|
|
513
|
+
if product_config.get("api_url"):
|
|
514
|
+
# Infer auth_method for PWS
|
|
515
|
+
if product == "pws":
|
|
516
|
+
if product_config.get("api_key"):
|
|
517
|
+
product_config["auth_method"] = "apikey"
|
|
518
|
+
elif product_config.get("client_id"):
|
|
519
|
+
product_config["auth_method"] = "oauth"
|
|
520
|
+
|
|
521
|
+
config.set_product_config(product, product_config, profile)
|
|
522
|
+
imported.append(product)
|
|
523
|
+
|
|
524
|
+
if imported:
|
|
525
|
+
if not config.default_profile or profile == "default":
|
|
526
|
+
config.default_profile = profile
|
|
527
|
+
save_config_file(config)
|
|
528
|
+
print_success(f"Imported {', '.join(imported)} into profile '{profile}'")
|
|
529
|
+
console.print(f"[dim]Config saved to: {CONFIG_FILE}[/dim]")
|
|
530
|
+
else:
|
|
531
|
+
print_warning("No configuration found in environment variables")
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
@app.command("effective")
|
|
535
|
+
def show_effective_config(
|
|
536
|
+
show_secrets: bool = typer.Option(False, "--show-secrets", help="Show secret values"),
|
|
537
|
+
) -> None:
|
|
538
|
+
"""Show effective configuration from all sources.
|
|
539
|
+
|
|
540
|
+
Shows what configuration is actually in use, combining:
|
|
541
|
+
- Environment variables (BT_PWS_*, BT_PRA_*, etc.)
|
|
542
|
+
- .env file (if present)
|
|
543
|
+
- Config file profiles (~/.bt-cli/config.yaml)
|
|
544
|
+
|
|
545
|
+
This is useful for debugging why the CLI connects successfully
|
|
546
|
+
but 'bt configure show' appears empty.
|
|
547
|
+
"""
|
|
548
|
+
import os
|
|
549
|
+
from dotenv import load_dotenv, find_dotenv
|
|
550
|
+
|
|
551
|
+
# Load .env if present
|
|
552
|
+
env_file = find_dotenv()
|
|
553
|
+
if env_file:
|
|
554
|
+
load_dotenv(env_file)
|
|
555
|
+
console.print(f"[dim]Loaded .env from: {env_file}[/dim]\n")
|
|
556
|
+
|
|
557
|
+
def mask_secret(key: str, value: str) -> str:
|
|
558
|
+
if not value:
|
|
559
|
+
return "[dim]not set[/dim]"
|
|
560
|
+
if not show_secrets and any(s in key.lower() for s in ["secret", "key", "password"]):
|
|
561
|
+
return "****" + value[-4:] if len(value) > 4 else "****"
|
|
562
|
+
return value
|
|
563
|
+
|
|
564
|
+
# Product environment variable mappings
|
|
565
|
+
products = {
|
|
566
|
+
"Password Safe": {
|
|
567
|
+
"api_url": "BT_PWS_API_URL",
|
|
568
|
+
"api_key": "BT_PWS_API_KEY",
|
|
569
|
+
"client_id": "BT_PWS_CLIENT_ID",
|
|
570
|
+
"client_secret": "BT_PWS_CLIENT_SECRET",
|
|
571
|
+
"run_as": "BT_PWS_RUN_AS",
|
|
572
|
+
"verify_ssl": "BT_PWS_VERIFY_SSL",
|
|
573
|
+
"timeout": "BT_PWS_TIMEOUT",
|
|
574
|
+
},
|
|
575
|
+
"PRA": {
|
|
576
|
+
"api_url": "BT_PRA_API_URL",
|
|
577
|
+
"client_id": "BT_PRA_CLIENT_ID",
|
|
578
|
+
"client_secret": "BT_PRA_CLIENT_SECRET",
|
|
579
|
+
"verify_ssl": "BT_PRA_VERIFY_SSL",
|
|
580
|
+
"timeout": "BT_PRA_TIMEOUT",
|
|
581
|
+
},
|
|
582
|
+
"Entitle": {
|
|
583
|
+
"api_url": "BT_ENTITLE_API_URL",
|
|
584
|
+
"api_key": "BT_ENTITLE_API_KEY",
|
|
585
|
+
"verify_ssl": "BT_ENTITLE_VERIFY_SSL",
|
|
586
|
+
"timeout": "BT_ENTITLE_TIMEOUT",
|
|
587
|
+
},
|
|
588
|
+
"EPM Windows": {
|
|
589
|
+
"api_url": "BT_EPM_API_URL",
|
|
590
|
+
"client_id": "BT_EPM_CLIENT_ID",
|
|
591
|
+
"client_secret": "BT_EPM_CLIENT_SECRET",
|
|
592
|
+
"verify_ssl": "BT_EPM_VERIFY_SSL",
|
|
593
|
+
"timeout": "BT_EPM_TIMEOUT",
|
|
594
|
+
},
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
# Check active profile
|
|
598
|
+
active_profile = os.getenv("BT_PROFILE", "default")
|
|
599
|
+
console.print(f"[bold]Active Profile:[/bold] {active_profile}\n")
|
|
600
|
+
|
|
601
|
+
# Show effective config for each product
|
|
602
|
+
for product_name, env_vars in products.items():
|
|
603
|
+
table = Table(title=product_name, show_header=True, title_style="bold cyan")
|
|
604
|
+
table.add_column("Setting", style="green")
|
|
605
|
+
table.add_column("Env Var", style="dim")
|
|
606
|
+
table.add_column("Value")
|
|
607
|
+
table.add_column("Source", style="dim")
|
|
608
|
+
|
|
609
|
+
has_config = False
|
|
610
|
+
for setting, env_var in env_vars.items():
|
|
611
|
+
value = os.getenv(env_var, "")
|
|
612
|
+
if value:
|
|
613
|
+
has_config = True
|
|
614
|
+
source = ".env" if env_file else "environment"
|
|
615
|
+
table.add_row(setting, env_var, mask_secret(setting, value), source)
|
|
616
|
+
|
|
617
|
+
if has_config:
|
|
618
|
+
console.print(table)
|
|
619
|
+
console.print()
|
|
620
|
+
else:
|
|
621
|
+
console.print(f"[dim]{product_name}: not configured[/dim]\n")
|
|
622
|
+
|
|
623
|
+
# Also show config file info
|
|
624
|
+
config = load_config_file()
|
|
625
|
+
if config.profiles:
|
|
626
|
+
console.print("[bold]Config File Profiles:[/bold]")
|
|
627
|
+
for profile_name in config.list_profiles():
|
|
628
|
+
products_list = list(config.profiles[profile_name].keys())
|
|
629
|
+
is_default = " (default)" if profile_name == config.default_profile else ""
|
|
630
|
+
console.print(f" {profile_name}{is_default}: {', '.join(products_list)}")
|
|
631
|
+
console.print(f"\n[dim]Note: Environment variables override config file settings[/dim]")
|
|
@@ -489,19 +489,27 @@ class PRAClient:
|
|
|
489
489
|
name: Optional[str] = None,
|
|
490
490
|
hostname: Optional[str] = None,
|
|
491
491
|
) -> List[Dict[str, Any]]:
|
|
492
|
-
"""List Protocol Tunnel Jump items (TCP, MSSQL, K8s) with optional filters.
|
|
492
|
+
"""List Protocol Tunnel Jump items (TCP, MSSQL, K8s) with optional filters.
|
|
493
|
+
|
|
494
|
+
Note: tunnel_type is filtered client-side as the API doesn't support it.
|
|
495
|
+
"""
|
|
493
496
|
params = {}
|
|
494
497
|
if jump_group_id:
|
|
495
498
|
params["jump_group_id"] = jump_group_id
|
|
496
|
-
if tunnel_type:
|
|
497
|
-
params["tunnel_type"] = tunnel_type
|
|
498
499
|
if tag:
|
|
499
500
|
params["tag"] = tag
|
|
500
501
|
if name:
|
|
501
502
|
params["name"] = name
|
|
502
503
|
if hostname:
|
|
503
504
|
params["hostname"] = hostname
|
|
504
|
-
|
|
505
|
+
|
|
506
|
+
items = self.get_paginated("/jump-item/protocol-tunnel-jump", params)
|
|
507
|
+
|
|
508
|
+
# Filter tunnel_type client-side (API doesn't support this filter)
|
|
509
|
+
if tunnel_type:
|
|
510
|
+
items = [i for i in items if i.get("tunnel_type") == tunnel_type]
|
|
511
|
+
|
|
512
|
+
return items
|
|
505
513
|
|
|
506
514
|
def get_protocol_tunnel(self, item_id: int) -> Dict[str, Any]:
|
|
507
515
|
"""Get a Protocol Tunnel Jump item."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|