bt-cli 0.4.23__py3-none-any.whl → 0.4.24__py3-none-any.whl

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/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """BeyondTrust Unified Admin CLI."""
2
2
 
3
- __version__ = "0.4.23"
3
+ __version__ = "0.4.24"
bt_cli/pra/client/base.py CHANGED
@@ -183,6 +183,17 @@ class PRAClient:
183
183
  response = self._client.delete(url, headers=self._headers())
184
184
  response.raise_for_status()
185
185
 
186
+ def delete_with_body(self, endpoint: str, data: Dict[str, Any]) -> None:
187
+ """Make DELETE request to API with JSON body.
188
+
189
+ Args:
190
+ endpoint: API endpoint path
191
+ data: JSON body data
192
+ """
193
+ url = f"{self.api_base}{endpoint}"
194
+ response = self._client.request("DELETE", url, headers=self._headers(), json=data)
195
+ response.raise_for_status()
196
+
186
197
  def close(self) -> None:
187
198
  """Close the HTTP client."""
188
199
  self._client.close()
@@ -429,6 +440,14 @@ class PRAClient:
429
440
  params["jump_group_id"] = jump_group_id
430
441
  return self.get_paginated("/jump-item/web-jump", params)
431
442
 
443
+ def get_web_jump(self, item_id: int) -> Dict[str, Any]:
444
+ """Get a Web Jump item."""
445
+ return self.get(f"/jump-item/web-jump/{item_id}")
446
+
447
+ def delete_web_jump(self, item_id: int) -> None:
448
+ """Delete a Web Jump item."""
449
+ self.delete(f"/jump-item/web-jump/{item_id}")
450
+
432
451
  def list_protocol_tunnels(
433
452
  self,
434
453
  jump_group_id: Optional[int] = None,
@@ -561,6 +580,58 @@ class PRAClient:
561
580
  """Delete a Vault account."""
562
581
  self.delete(f"/vault/account/{account_id}")
563
582
 
583
+ def associate_vault_account_jump_item(
584
+ self,
585
+ account_id: int,
586
+ jump_item_id: int,
587
+ jump_item_type: str = "shell_jump",
588
+ ) -> Dict[str, Any]:
589
+ """Associate a Vault account with a Jump Item.
590
+
591
+ Args:
592
+ account_id: Vault Account ID
593
+ jump_item_id: Jump Item ID to associate
594
+ jump_item_type: Type of jump item - 'shell_jump', 'remote_rdp', 'remote_vnc', 'web_jump'
595
+
596
+ Returns:
597
+ The created association
598
+ """
599
+ data = {
600
+ "id": jump_item_id,
601
+ "type": jump_item_type,
602
+ }
603
+ return self.post(f"/vault/account/{account_id}/jump-item-association/jump-item", data)
604
+
605
+ def disassociate_vault_account_jump_item(
606
+ self,
607
+ account_id: int,
608
+ jump_item_id: int,
609
+ jump_item_type: str = "shell_jump",
610
+ ) -> None:
611
+ """Remove association between a Vault account and a Jump Item.
612
+
613
+ Args:
614
+ account_id: Vault Account ID
615
+ jump_item_id: Jump Item ID to disassociate
616
+ jump_item_type: Type of jump item - 'shell_jump', 'remote_rdp', etc.
617
+ """
618
+ # API requires body with id and type, not path parameters
619
+ self.delete_with_body(
620
+ f"/vault/account/{account_id}/jump-item-association/jump-item",
621
+ {"id": jump_item_id, "type": jump_item_type}
622
+ )
623
+
624
+ def list_vault_account_jump_items(self, account_id: int) -> Dict[str, Any]:
625
+ """List Jump Items associated with a Vault account.
626
+
627
+ Args:
628
+ account_id: Vault Account ID
629
+
630
+ Returns:
631
+ Association info with filter criteria and jump_items list
632
+ """
633
+ return self.get(f"/vault/account/{account_id}/jump-item-association")
634
+
564
635
  def list_vault_account_groups(self) -> List[Dict[str, Any]]:
565
636
  """List Vault account groups."""
566
637
  return self.get_paginated("/vault/account-group")
@@ -458,6 +458,70 @@ def list_web_jumps(
458
458
  raise typer.Exit(1)
459
459
 
460
460
 
461
+ @web_app.command("get")
462
+ def get_web_jump(
463
+ item_id: int = typer.Argument(..., help="Web Jump ID"),
464
+ output: OutputFormat = typer.Option(OutputFormat.JSON, "--output", "-o"),
465
+ ):
466
+ """Get Web Jump details."""
467
+ from bt_cli.pra.client import get_client
468
+
469
+ try:
470
+ client = get_client()
471
+ item = client.get_web_jump(item_id)
472
+
473
+ if output == OutputFormat.JSON:
474
+ print_json(item)
475
+ else:
476
+ from rich.console import Console
477
+ from rich.panel import Panel
478
+ console = Console()
479
+ console.print(Panel(
480
+ f"[bold]{item.get('name', '')}[/bold]\n\n"
481
+ f"[dim]URL:[/dim] {item.get('url', '')}\n"
482
+ f"[dim]Username:[/dim] {item.get('username', '') or '-'}\n"
483
+ f"[dim]Jump Group:[/dim] {item.get('jump_group_id', '')}\n"
484
+ f"[dim]Jumpoint:[/dim] {item.get('jumpoint_id', '')}",
485
+ title="Web Jump Details",
486
+ subtitle=f"ID: {item.get('id', '')}",
487
+ ))
488
+ except httpx.HTTPStatusError as e:
489
+ print_api_error(e, "get web jump")
490
+ raise typer.Exit(1)
491
+ except httpx.RequestError as e:
492
+ print_api_error(e, "get web jump")
493
+ raise typer.Exit(1)
494
+ except Exception as e:
495
+ print_api_error(e, "get web jump")
496
+ raise typer.Exit(1)
497
+
498
+
499
+ @web_app.command("delete")
500
+ def delete_web_jump(
501
+ item_id: int = typer.Argument(..., help="Web Jump ID"),
502
+ force: bool = typer.Option(False, "--force", "-f", help="Skip confirmation"),
503
+ ):
504
+ """Delete a Web Jump item."""
505
+ from bt_cli.pra.client import get_client
506
+
507
+ if not force:
508
+ typer.confirm(f"Delete web jump {item_id}?", abort=True)
509
+
510
+ try:
511
+ client = get_client()
512
+ client.delete_web_jump(item_id)
513
+ print_success(f"Deleted web jump {item_id}")
514
+ except httpx.HTTPStatusError as e:
515
+ print_api_error(e, "delete web jump")
516
+ raise typer.Exit(1)
517
+ except httpx.RequestError as e:
518
+ print_api_error(e, "delete web jump")
519
+ raise typer.Exit(1)
520
+ except Exception as e:
521
+ print_api_error(e, "delete web jump")
522
+ raise typer.Exit(1)
523
+
524
+
461
525
  # Protocol Tunnel subcommands (TCP, MSSQL, PostgreSQL, MySQL, K8s)
462
526
  tunnel_app = typer.Typer(no_args_is_help=True, help="Protocol Tunnel Jump items (TCP, MSSQL, PostgreSQL, MySQL, K8s)")
463
527
  app.add_typer(tunnel_app, name="tunnel")
@@ -517,6 +517,125 @@ def rotate_vault_account(
517
517
  raise typer.Exit(1)
518
518
 
519
519
 
520
+ @accounts_app.command("associate")
521
+ def associate_vault_account_jump_item(
522
+ account_id: int = typer.Argument(..., help="Vault Account ID"),
523
+ jump_item_id: int = typer.Option(..., "--jump-item", "-j", help="Jump Item ID to associate"),
524
+ jump_item_type: str = typer.Option(
525
+ "shell_jump", "--type", "-t",
526
+ help="Jump item type: shell_jump, remote_rdp, remote_vnc, web_jump"
527
+ ),
528
+ output: OutputFormat = typer.Option(OutputFormat.JSON, "--output", "-o"),
529
+ ):
530
+ """Associate a Vault account with a Jump Item.
531
+
532
+ Links a vault account to a jump item so credentials can be injected
533
+ automatically when accessing that jump item.
534
+
535
+ Examples:
536
+ # Associate vault account 5 with shell jump item 10
537
+ bt pra vault accounts associate 5 -j 10
538
+
539
+ # Associate with RDP jump item
540
+ bt pra vault accounts associate 5 -j 10 -t remote_rdp
541
+ """
542
+ from bt_cli.pra.client import get_client
543
+
544
+ try:
545
+ client = get_client()
546
+ result = client.associate_vault_account_jump_item(account_id, jump_item_id, jump_item_type)
547
+ print_success(f"Associated vault account {account_id} with jump item {jump_item_id}")
548
+
549
+ if output == OutputFormat.JSON:
550
+ print_json(result)
551
+ except httpx.HTTPStatusError as e:
552
+ print_api_error(e, "associate vault account")
553
+ raise typer.Exit(1)
554
+ except httpx.RequestError as e:
555
+ print_api_error(e, "associate vault account")
556
+ raise typer.Exit(1)
557
+ except Exception as e:
558
+ print_api_error(e, "associate vault account")
559
+ raise typer.Exit(1)
560
+
561
+
562
+ @accounts_app.command("disassociate")
563
+ def disassociate_vault_account_jump_item(
564
+ account_id: int = typer.Argument(..., help="Vault Account ID"),
565
+ jump_item_id: int = typer.Option(..., "--jump-item", "-j", help="Jump Item ID to disassociate"),
566
+ jump_item_type: str = typer.Option(
567
+ "shell_jump", "--type", "-t",
568
+ help="Jump item type: shell_jump, remote_rdp, remote_vnc, web_jump"
569
+ ),
570
+ force: bool = typer.Option(False, "--force", "-f", help="Skip confirmation"),
571
+ ):
572
+ """Remove association between a Vault account and a Jump Item.
573
+
574
+ Examples:
575
+ bt pra vault accounts disassociate 5 -j 10
576
+ bt pra vault accounts disassociate 5 -j 10 -t remote_rdp
577
+ bt pra vault accounts disassociate 5 -j 10 -f # Skip confirmation
578
+ """
579
+ from bt_cli.pra.client import get_client
580
+
581
+ if not force:
582
+ typer.confirm(
583
+ f"Remove association between vault account {account_id} and jump item {jump_item_id}?",
584
+ abort=True
585
+ )
586
+
587
+ try:
588
+ client = get_client()
589
+ client.disassociate_vault_account_jump_item(account_id, jump_item_id, jump_item_type)
590
+ print_success(f"Removed association between vault account {account_id} and jump item {jump_item_id}")
591
+ except httpx.HTTPStatusError as e:
592
+ print_api_error(e, "disassociate vault account")
593
+ raise typer.Exit(1)
594
+ except httpx.RequestError as e:
595
+ print_api_error(e, "disassociate vault account")
596
+ raise typer.Exit(1)
597
+ except Exception as e:
598
+ print_api_error(e, "disassociate vault account")
599
+ raise typer.Exit(1)
600
+
601
+
602
+ @accounts_app.command("list-jump-items")
603
+ def list_vault_account_jump_items(
604
+ account_id: int = typer.Argument(..., help="Vault Account ID"),
605
+ output: OutputFormat = typer.Option(OutputFormat.TABLE, "--output", "-o"),
606
+ ):
607
+ """List Jump Items associated with a Vault account.
608
+
609
+ Examples:
610
+ bt pra vault accounts list-jump-items 5
611
+ bt pra vault accounts list-jump-items 5 -o json
612
+ """
613
+ from bt_cli.pra.client import get_client
614
+
615
+ try:
616
+ client = get_client()
617
+ result = client.list_vault_account_jump_items(account_id)
618
+ items = result.get("jump_items", [])
619
+
620
+ if output == OutputFormat.JSON:
621
+ print_json(result)
622
+ else:
623
+ columns = [
624
+ ("ID", "id"),
625
+ ("Type", "type"),
626
+ ]
627
+ print_table(items, columns, title=f"Jump Items for Vault Account {account_id}")
628
+ except httpx.HTTPStatusError as e:
629
+ print_api_error(e, "list vault account jump items")
630
+ raise typer.Exit(1)
631
+ except httpx.RequestError as e:
632
+ print_api_error(e, "list vault account jump items")
633
+ raise typer.Exit(1)
634
+ except Exception as e:
635
+ print_api_error(e, "list vault account jump items")
636
+ raise typer.Exit(1)
637
+
638
+
520
639
  # Account Groups subcommands
521
640
  groups_app = typer.Typer(no_args_is_help=True, help="Vault account groups")
522
641
  app.add_typer(groups_app, name="groups")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bt-cli
3
- Version: 0.4.23
3
+ Version: 0.4.24
4
4
  Summary: BeyondTrust Platform CLI (unofficial) - Password Safe, Entitle, PRA, EPM
5
5
  Author-email: Dave Grendysz <dgrendysz@beyondtrust.com>
6
6
  License: MIT
@@ -1,4 +1,4 @@
1
- bt_cli/__init__.py,sha256=1MfYcztwcSEhKTwQC2ESNpnnD7bVe9PRCTQZnBRv2Gg,61
1
+ bt_cli/__init__.py,sha256=1um9AdjxOZ2geJPX6lv7t8AvQmixsoXRKqFn3mWiKss,61
2
2
  bt_cli/cli.py,sha256=Fd-p9O2IR-LJfDewkQbLRE6tPe9FVLkGJgUHup2Z08Q,30254
3
3
  bt_cli/commands/__init__.py,sha256=Wrf3ZV1sf7JCilbv93VqoWWTyj0d-y4saAaVFD5apU8,38
4
4
  bt_cli/commands/configure.py,sha256=WElK9grslla0_rqdAmDh0vYpLVH5jP21l1fiYl7vvOw,14364
@@ -64,19 +64,19 @@ bt_cli/epmw/commands/users.py,sha256=NAsb-qqGyONlG8PHtRiUBv6mQClKANS9jH2dViDxoCk
64
64
  bt_cli/epmw/models/__init__.py,sha256=jm_REiWMSPhDmnNM_TLqv3aXYlu95mke56a1IOKyjK8,26
65
65
  bt_cli/pra/__init__.py,sha256=tXFUETts83T4QArnv-1OlyKV2Tkoav3wXF7vyeo0iGg,57
66
66
  bt_cli/pra/client/__init__.py,sha256=nfND6hokLySFKanCmiTXwVIUuc_bdWSNNszPQGkzInY,105
67
- bt_cli/pra/client/base.py,sha256=GjYZIddFWrt6VS9PPeFiAXdSxMbmGUpg_5aG7StiSuQ,19909
67
+ bt_cli/pra/client/base.py,sha256=9xFXakWG1LVDskGP_6jEoCHT2-AqCmtY1J8d0jauEzM,22372
68
68
  bt_cli/pra/commands/__init__.py,sha256=QvMeHPKE5niK48VVldXAUsuRB6Xq5XzWo1a7IiqtSNI,1490
69
69
  bt_cli/pra/commands/auth.py,sha256=NXZG2cwRcf6bmMIhNxIMkiWg1NWyxzn77wiorjA_M-8,1701
70
70
  bt_cli/pra/commands/import_export.py,sha256=hGxLSHGQW3YTDWoUThYzczY1cKIOCmXvlAuVjlCnipE,17195
71
71
  bt_cli/pra/commands/jump_clients.py,sha256=WuZSqeAT4BwJ18e0NT9xZTQMTZoXmDA-cfIchwbn8bU,4799
72
72
  bt_cli/pra/commands/jump_groups.py,sha256=MDeVJUYza2MqocCBrbfTsGUQZQIPBOCj6zteC8ysYqI,4561
73
- bt_cli/pra/commands/jump_items.py,sha256=3a1sVheFoA0ug3FPW4aW8B0a5dkKsLXoO2zPMX-Sxr4,23884
73
+ bt_cli/pra/commands/jump_items.py,sha256=KR0WMid6Ud-Ky0XiD1LDC2zs-EbQ23KCJWsT9cT-kqc,26047
74
74
  bt_cli/pra/commands/jumpoints.py,sha256=hSxu6BTXVaRvwgaFJrNeSxaDPcvvmH6aGxiat7G2Ees,3075
75
75
  bt_cli/pra/commands/policies.py,sha256=5ekjEGKaIEdjpuUYyuBUvNdJgH3GKQkajRep0_i8QxI,6139
76
76
  bt_cli/pra/commands/quick.py,sha256=W0JrS5XYMfl5Jl0PjroeAbFGWszPsu-NFH0_REy6Qkk,18892
77
77
  bt_cli/pra/commands/teams.py,sha256=tr_stOR6CkvcZ4jDFg6gUbPZ-d8dvnN_wEgdA_hTepc,2346
78
78
  bt_cli/pra/commands/users.py,sha256=Ui9ByM2CIaI8hN4N9zkTD3Rw2gIU0jlHVWKpZEnaR3c,2733
79
- bt_cli/pra/commands/vault.py,sha256=xH9HIer-X4lrTJblEvKB3z0QgvhGkqa_ANYgOjSHoNo,21391
79
+ bt_cli/pra/commands/vault.py,sha256=nQkoLpUebDOzuvSrvc1DmYVZ6ALAwQeKfx2uGXdjmI8,25832
80
80
  bt_cli/pra/models/__init__.py,sha256=5S6ogGJDZY1O8gCFbCCQ5vN61wocP5J-EO2s55ebV2Y,614
81
81
  bt_cli/pra/models/common.py,sha256=hnQOndbt38YiLuS2kZxbpK4QsX1ONyKtOgE6RcWFjVU,247
82
82
  bt_cli/pra/models/jump_client.py,sha256=M3-4U66rcPzrfjAUFzQ0xxgWTPuBg5DdLCwJrgP9O3k,684
@@ -115,7 +115,7 @@ bt_cli/pws/models/account.py,sha256=OSCMyULPOH1Yu2WOzK0ZQhSRrggGpb2JPHScwGLqUgI,
115
115
  bt_cli/pws/models/asset.py,sha256=Fl0AlR4_9Yyyu36FL1eKF29DNsxsB-r7FaOBRlfOg2Q,4081
116
116
  bt_cli/pws/models/common.py,sha256=D9Ah4ob5CIiFhTt_IR9nF2cBWRHS2z9OyBR2Sss5yzw,3487
117
117
  bt_cli/pws/models/system.py,sha256=D_J0x1A92H2n6BsaBEK9PSAAcs3BTifA5-M9SQqQFGA,5856
118
- bt_cli-0.4.23.dist-info/METADATA,sha256=79M9O5hAPcL89kM_zUfHbOyO7DO1tI3YVGBEpCVhkqw,11862
119
- bt_cli-0.4.23.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
120
- bt_cli-0.4.23.dist-info/entry_points.txt,sha256=NCOEqTI-XKpJOux0JKKhbRElz0B7upayh_d99X5hoLs,38
121
- bt_cli-0.4.23.dist-info/RECORD,,
118
+ bt_cli-0.4.24.dist-info/METADATA,sha256=UCpkU0kKxyQ1vs9Ra3g_ge4mk2SK0X5pVR5_r3v8EUA,11862
119
+ bt_cli-0.4.24.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
120
+ bt_cli-0.4.24.dist-info/entry_points.txt,sha256=NCOEqTI-XKpJOux0JKKhbRElz0B7upayh_d99X5hoLs,38
121
+ bt_cli-0.4.24.dist-info/RECORD,,