portacode 1.4.15.dev20__py3-none-any.whl → 1.4.15.dev22__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.
portacode/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '1.4.15.dev20'
32
- __version_tuple__ = version_tuple = (1, 4, 15, 'dev20')
31
+ __version__ = version = '1.4.15.dev22'
32
+ __version_tuple__ = version_tuple = (1, 4, 15, 'dev22')
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -608,28 +608,37 @@ def _build_bootstrap_steps(
608
608
  steps.extend(
609
609
  [
610
610
  {"name": "user_exists", "cmd": f"id -u {user} >/dev/null 2>&1 || adduser --disabled-password --gecos '' {user}", "retries": 0},
611
- {
612
- "name": "add_sudo",
613
- "cmd": (
614
- f"if command -v usermod >/dev/null 2>&1; then "
615
- " if ! getent group sudo >/dev/null 2>&1; then "
616
- " if command -v groupadd >/dev/null 2>&1; then "
617
- " groupadd sudo >/dev/null 2>&1 || true; "
618
- " fi; "
619
- " fi; "
620
- f" usermod -aG sudo {user}; "
621
- "else "
622
- " for grp in wheel sudo; do "
623
- " if ! getent group \"$grp\" >/dev/null 2>&1 && command -v groupadd >/dev/null 2>&1; then "
624
- " groupadd \"$grp\" >/dev/null 2>&1 || true; "
625
- " fi; "
626
- " addgroup \"$grp\" >/dev/null 2>&1 || true; "
627
- f" addgroup {user} \"$grp\" >/dev/null 2>&1 || true; "
628
- " done; "
629
- "fi"
630
- ),
631
- "retries": 0,
632
- },
611
+ {
612
+ "name": "add_sudo",
613
+ "cmd": (
614
+ f"if command -v usermod >/dev/null 2>&1; then "
615
+ " if ! getent group sudo >/dev/null 2>&1; then "
616
+ " if command -v groupadd >/dev/null 2>&1; then "
617
+ " groupadd sudo >/dev/null 2>&1 || true; "
618
+ " fi; "
619
+ " fi; "
620
+ f" usermod -aG sudo {user}; "
621
+ "else "
622
+ " for grp in wheel sudo; do "
623
+ " if ! getent group \"$grp\" >/dev/null 2>&1 && command -v groupadd >/dev/null 2>&1; then "
624
+ " groupadd \"$grp\" >/dev/null 2>&1 || true; "
625
+ " fi; "
626
+ " addgroup \"$grp\" >/dev/null 2>&1 || true; "
627
+ f" addgroup {user} \"$grp\" >/dev/null 2>&1 || true; "
628
+ " done; "
629
+ "fi"
630
+ ),
631
+ "retries": 0,
632
+ },
633
+ {
634
+ "name": "add_sudoers",
635
+ "cmd": (
636
+ f"cat <<'EOF' >/etc/sudoers.d/portacode && chmod 0440 /etc/sudoers.d/portacode\n"
637
+ f"{user} ALL=(ALL) NOPASSWD:ALL\n"
638
+ "EOF"
639
+ ),
640
+ "retries": 0,
641
+ },
633
642
  ]
634
643
  )
635
644
  if password:
@@ -892,6 +901,10 @@ def _run_pct(vmid: int, cmd: str, input_text: Optional[str] = None) -> Dict[str,
892
901
  }
893
902
 
894
903
 
904
+ def _su_command(user: str, command: str) -> str:
905
+ return f"su - {user} -s /bin/sh -c {shlex.quote(command)}"
906
+
907
+
895
908
  def _run_pct_check(vmid: int, cmd: str) -> Dict[str, Any]:
896
909
  res = _run_pct(vmid, cmd)
897
910
  if res["returncode"] != 0:
@@ -951,7 +964,7 @@ def _push_bytes_to_container(
951
964
 
952
965
 
953
966
  def _resolve_portacode_key_dir(vmid: int, user: str) -> str:
954
- data_dir_cmd = f"su - {user} -c 'echo -n ${{XDG_DATA_HOME:-$HOME/.local/share}}'"
967
+ data_dir_cmd = _su_command(user, "echo -n ${XDG_DATA_HOME:-$HOME/.local/share}")
955
968
  data_home = _run_pct_check(vmid, data_dir_cmd)["stdout"].strip()
956
969
  portacode_dir = f"{data_home}/portacode"
957
970
  _run_pct_exec_check(vmid, ["mkdir", "-p", portacode_dir])
@@ -968,18 +981,19 @@ def _deploy_device_keypair(vmid: int, user: str, private_key: str, public_key: s
968
981
 
969
982
 
970
983
  def _portacode_connect_and_read_key(vmid: int, user: str, timeout_s: int = 10) -> Dict[str, Any]:
971
- cmd = ["pct", "exec", str(vmid), "--", "bash", "-lc", f"su - {user} -c 'portacode connect'"]
984
+ su_connect_cmd = _su_command(user, "portacode connect")
985
+ cmd = ["pct", "exec", str(vmid), "--", "/bin/sh", "-c", su_connect_cmd]
972
986
  proc = subprocess.Popen(cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
973
987
  start = time.time()
974
988
 
975
- data_dir_cmd = f"su - {user} -c 'echo -n ${{XDG_DATA_HOME:-$HOME/.local/share}}'"
989
+ data_dir_cmd = _su_command(user, "echo -n ${XDG_DATA_HOME:-$HOME/.local/share}")
976
990
  data_dir = _run_pct_check(vmid, data_dir_cmd)["stdout"].strip()
977
991
  key_dir = f"{data_dir}/portacode/keys"
978
992
  pub_path = f"{key_dir}/id_portacode.pub"
979
993
  priv_path = f"{key_dir}/id_portacode"
980
994
 
981
995
  def file_size(path: str) -> Optional[int]:
982
- stat_cmd = f"su - {user} -c 'test -s {path} && stat -c %s {path}'"
996
+ stat_cmd = _su_command(user, f"test -s {path} && stat -c %s {path}")
983
997
  res = _run_pct(vmid, stat_cmd)
984
998
  if res["returncode"] != 0:
985
999
  return None
@@ -1037,7 +1051,7 @@ def _portacode_connect_and_read_key(vmid: int, user: str, timeout_s: int = 10) -
1037
1051
  final_pub = file_size(pub_path)
1038
1052
  final_priv = file_size(priv_path)
1039
1053
  if final_pub and final_priv:
1040
- key_res = _run_pct(vmid, f"su - {user} -c 'cat {pub_path}'")
1054
+ key_res = _run_pct(vmid, _su_command(user, f"cat {pub_path}"))
1041
1055
  if not process_exited:
1042
1056
  proc.terminate()
1043
1057
  try:
@@ -1077,7 +1091,7 @@ def _portacode_connect_and_read_key(vmid: int, user: str, timeout_s: int = 10) -
1077
1091
  except subprocess.TimeoutExpired:
1078
1092
  proc.kill()
1079
1093
 
1080
- key_res = _run_pct(vmid, f"su - {user} -c 'cat {pub_path}'")
1094
+ key_res = _run_pct(vmid, _su_command(user, f"cat {pub_path}"))
1081
1095
  return {
1082
1096
  "ok": True,
1083
1097
  "public_key": key_res["stdout"].strip(),
@@ -1620,7 +1634,7 @@ class CreateProxmoxContainerHandler(SyncHandler):
1620
1634
  on_behalf_of_device=device_id,
1621
1635
  )
1622
1636
 
1623
- cmd = f"su - {payload['username']} -c 'sudo -S portacode service install'"
1637
+ cmd = _su_command(payload["username"], "sudo -S portacode service install")
1624
1638
  res = _run_pct(vmid, cmd, input_text=payload["password"] + "\n")
1625
1639
 
1626
1640
  if res["returncode"] != 0:
@@ -1752,7 +1766,7 @@ class StartPortacodeServiceHandler(SyncHandler):
1752
1766
  on_behalf_of_device=on_behalf_of_device,
1753
1767
  )
1754
1768
 
1755
- cmd = f"su - {user} -c 'sudo -S portacode service install'"
1769
+ cmd = _su_command(user, "sudo -S portacode service install")
1756
1770
  res = _run_pct(vmid, cmd, input_text=password + "\n")
1757
1771
 
1758
1772
  if res["returncode"] != 0:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: portacode
3
- Version: 1.4.15.dev20
3
+ Version: 1.4.15.dev22
4
4
  Summary: Portacode CLI client and SDK
5
5
  Home-page: https://github.com/portacode/portacode
6
6
  Author: Meena Erian
@@ -1,7 +1,7 @@
1
1
  portacode/README.md,sha256=4dKtpvR8LNgZPVz37GmkQCMWIr_u25Ao63iW56s7Ke4,775
2
2
  portacode/__init__.py,sha256=oB3sV1wXr-um-RXio73UG8E5Xx6cF2ZVJveqjNmC-vQ,1086
3
3
  portacode/__main__.py,sha256=jmHTGC1hzmo9iKJLv-SSYe9BSIbPPZ2IOpecI03PlTs,296
4
- portacode/_version.py,sha256=EtNExlVc69CYMOUqVHfUwnvcPdwIJ3mbJi0bUDaa61w,721
4
+ portacode/_version.py,sha256=z7lXmOxYLq8fS-I__y_TOSG2PjKGvcyPe277IbceWCk,721
5
5
  portacode/cli.py,sha256=mGLKoZ-T2FBF7IA9wUq0zyG0X9__-A1ao7gajjcVRH8,21828
6
6
  portacode/data.py,sha256=5-s291bv8J354myaHm1Y7CQZTZyRzMU3TGe5U4hb-FA,1591
7
7
  portacode/keypair.py,sha256=0OO4vHDcF1XMxCDqce61xFTlFwlTcmqe5HyGsXFEt7s,5838
@@ -22,7 +22,7 @@ portacode/connection/handlers/diff_handlers.py,sha256=iYTIRCcpEQ03vIPKZCsMTE5aZb
22
22
  portacode/connection/handlers/file_handlers.py,sha256=nAJH8nXnX07xxD28ngLpgIUzcTuRwZBNpEGEKdRqohw,39507
23
23
  portacode/connection/handlers/project_aware_file_handlers.py,sha256=AqgMnDqX2893T2NsrvUSCwjN5VKj4Pb2TN0S_SuboOE,9803
24
24
  portacode/connection/handlers/project_state_handlers.py,sha256=v6ZefGW9i7n1aZLq2jOGumJIjYb6aHlPI4m1jkYewm8,1686
25
- portacode/connection/handlers/proxmox_infra.py,sha256=1cL2X6ovdyjt2nWRav6bq-ic8wnLvl2WbxmbxPcutTk,70607
25
+ portacode/connection/handlers/proxmox_infra.py,sha256=7sAWKaMR0jJD6ZZ62mX6hxtizjYIfDNHZ3C7MMdBITw,71179
26
26
  portacode/connection/handlers/registry.py,sha256=qXGE60sYEWg6ZtVQzFcZ5YI2XWR6lMgw4hAL9x5qR1I,6181
27
27
  portacode/connection/handlers/session.py,sha256=uNGfiO_1B9-_yjJKkpvmbiJhIl6b-UXlT86UTfd6WYE,42219
28
28
  portacode/connection/handlers/system_handlers.py,sha256=fr12QpOr_Z8KYGUU-AYrTQwRPAcrLK85hvj3SEq1Kw8,14757
@@ -65,7 +65,7 @@ portacode/utils/__init__.py,sha256=NgBlWTuNJESfIYJzP_3adI1yJQJR0XJLRpSdVNaBAN0,3
65
65
  portacode/utils/diff_apply.py,sha256=4Oi7ft3VUCKmiUE4VM-OeqO7Gk6H7PF3WnN4WHXtjxI,15157
66
66
  portacode/utils/diff_renderer.py,sha256=S76StnQ2DLfsz4Gg0m07UwPfRp8270PuzbNaQq-rmYk,13850
67
67
  portacode/utils/ntp_clock.py,sha256=VqCnWCTehCufE43W23oB-WUdAZGeCcLxkmIOPwInYHc,2499
68
- portacode-1.4.15.dev20.dist-info/licenses/LICENSE,sha256=2FGbCnUDgRYuQTkB1O1dUUpu5CVAjK1j4_p6ack9Z54,1066
68
+ portacode-1.4.15.dev22.dist-info/licenses/LICENSE,sha256=2FGbCnUDgRYuQTkB1O1dUUpu5CVAjK1j4_p6ack9Z54,1066
69
69
  test_modules/README.md,sha256=Do_agkm9WhSzueXjRAkV_xEj6Emy5zB3N3VKY5Roce8,9274
70
70
  test_modules/__init__.py,sha256=1LcbHodIHsB0g-g4NGjSn6AMuCoGbymvXPYLOb6Z7F0,53
71
71
  test_modules/test_device_online.py,sha256=QtYq0Dq9vME8Gp2O4fGSheqVf8LUtpsSKosXXk56gGM,1654
@@ -91,8 +91,8 @@ testing_framework/core/playwright_manager.py,sha256=Tw46qwxIhOFkS48C2IWIQHHNpEe-
91
91
  testing_framework/core/runner.py,sha256=j2QwNJmAxVBmJvcbVS7DgPJUKPNzqfLmt_4NNdaKmZU,19297
92
92
  testing_framework/core/shared_cli_manager.py,sha256=BESSNtyQb7BOlaOvZmm04T8Uezjms4KCBs2MzTxvzYQ,8790
93
93
  testing_framework/core/test_discovery.py,sha256=2FZ9fJ8Dp5dloA-fkgXoJ_gCMC_nYPBnA3Hs2xlagzM,4928
94
- portacode-1.4.15.dev20.dist-info/METADATA,sha256=Iy_i4HjHxat7PXmtofy00vurrM3SPQHTmyUUcQ0BMrI,13052
95
- portacode-1.4.15.dev20.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
96
- portacode-1.4.15.dev20.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
97
- portacode-1.4.15.dev20.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
98
- portacode-1.4.15.dev20.dist-info/RECORD,,
94
+ portacode-1.4.15.dev22.dist-info/METADATA,sha256=IL51OS2iXUpi5GlUhmVB_pg2pPLLIK9Vs7HZgq2lKNI,13052
95
+ portacode-1.4.15.dev22.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
96
+ portacode-1.4.15.dev22.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
97
+ portacode-1.4.15.dev22.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
98
+ portacode-1.4.15.dev22.dist-info/RECORD,,