devs-common 2.0.11__tar.gz → 2.0.13__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.
- {devs_common-2.0.11 → devs_common-2.0.13}/PKG-INFO +1 -1
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/core/container.py +104 -87
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/Dockerfile +5 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common.egg-info/PKG-INFO +1 -1
- {devs_common-2.0.11 → devs_common-2.0.13}/pyproject.toml +1 -1
- {devs_common-2.0.11 → devs_common-2.0.13}/LICENSE +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/README.md +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/__init__.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/config.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/core/__init__.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/core/project.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/core/workspace.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/devs_config.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/exceptions.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/devcontainer.json +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/scripts/copy-ssh.sh +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/scripts/post-create-wrapper.sh +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/scripts/python-venv-integration.sh +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/scripts/screenshot-webapp.sh +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/scripts/setup-workspace.sh +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/scripts/start-tunnel.sh +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/scripts/tunnel-status.sh +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/scripts/webapp-screenshot.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/sudo-scripts/init-firewall.sh +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/sudo-scripts/setup-devs-env.sh +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/sudo-scripts/setup-vscode-cache.sh +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/sudo-scripts/start-services.sh +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/vscode-settings-reference.md +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/utils/__init__.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/utils/config_hash.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/utils/console.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/utils/devcontainer.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/utils/devcontainer_template.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/utils/docker_client.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/utils/file_utils.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/utils/git_utils.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common/utils/repo_cache.py +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common.egg-info/SOURCES.txt +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common.egg-info/dependency_links.txt +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common.egg-info/requires.txt +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/devs_common.egg-info/top_level.txt +0 -0
- {devs_common-2.0.11 → devs_common-2.0.13}/setup.cfg +0 -0
|
@@ -882,13 +882,99 @@ class ContainerManager:
|
|
|
882
882
|
|
|
883
883
|
return tunnel_name
|
|
884
884
|
|
|
885
|
+
def _run_tunnel_auth(self, container_name: str, debug: bool = False) -> bool:
|
|
886
|
+
"""Run interactive VS Code tunnel authentication in a container.
|
|
887
|
+
|
|
888
|
+
Returns:
|
|
889
|
+
True if authentication succeeded
|
|
890
|
+
"""
|
|
891
|
+
console.print("[yellow]Follow the prompts to authenticate:[/yellow]")
|
|
892
|
+
console.print(" 1. A URL and code will be displayed")
|
|
893
|
+
console.print(" 2. Open the URL in your browser")
|
|
894
|
+
console.print(" 3. Enter the code to authenticate with GitHub/Microsoft")
|
|
895
|
+
console.print("")
|
|
896
|
+
|
|
897
|
+
cmd = [
|
|
898
|
+
'docker', 'exec', '-it',
|
|
899
|
+
container_name,
|
|
900
|
+
'/usr/local/bin/code', 'tunnel', 'user', 'login',
|
|
901
|
+
'--provider', 'github'
|
|
902
|
+
]
|
|
903
|
+
|
|
904
|
+
if debug:
|
|
905
|
+
console.print(f"[dim]Running: {' '.join(cmd)}[/dim]")
|
|
906
|
+
|
|
907
|
+
result = subprocess.run(cmd, check=False)
|
|
908
|
+
|
|
909
|
+
if result.returncode == 0:
|
|
910
|
+
console.print("")
|
|
911
|
+
console.print("[bold green]Authentication successful![/bold green]")
|
|
912
|
+
console.print(" Auth persists across container stop/restart cycles.")
|
|
913
|
+
return True
|
|
914
|
+
else:
|
|
915
|
+
console.print("")
|
|
916
|
+
console.print("[yellow]Authentication was cancelled or failed.[/yellow]")
|
|
917
|
+
return False
|
|
918
|
+
|
|
919
|
+
def _start_and_poll_tunnel(self, container_name: str, dev_name: str, tunnel_cmd: str,
|
|
920
|
+
log_file: str, vscode_cmd: str, web_url: str, debug: bool = False) -> bool:
|
|
921
|
+
"""Start a detached tunnel and poll the log for startup confirmation.
|
|
922
|
+
|
|
923
|
+
Returns:
|
|
924
|
+
True if tunnel started (or timed out), False if auth is needed.
|
|
925
|
+
"""
|
|
926
|
+
subprocess.run(
|
|
927
|
+
['docker', 'exec', '-d', container_name,
|
|
928
|
+
'/bin/sh', '-c', f'{tunnel_cmd} > {log_file} 2>&1'],
|
|
929
|
+
check=True
|
|
930
|
+
)
|
|
931
|
+
|
|
932
|
+
console.print("[dim]Waiting for tunnel to start...[/dim]")
|
|
933
|
+
for i in range(15):
|
|
934
|
+
time.sleep(1)
|
|
935
|
+
result = subprocess.run(
|
|
936
|
+
['docker', 'exec', container_name, 'cat', log_file],
|
|
937
|
+
capture_output=True, text=True
|
|
938
|
+
)
|
|
939
|
+
output = result.stdout
|
|
940
|
+
|
|
941
|
+
if 'Open this link' in output or 'vscode.dev/tunnel' in output:
|
|
942
|
+
console.print(f"[bold green]Tunnel running![/bold green]")
|
|
943
|
+
console.print("")
|
|
944
|
+
console.print("[bold]Connect:[/bold]")
|
|
945
|
+
console.print(f" Desktop: {vscode_cmd}")
|
|
946
|
+
console.print(f" Browser: {web_url}")
|
|
947
|
+
console.print("")
|
|
948
|
+
console.print(f"[dim]Use 'devs tunnel {dev_name} --status' to check status[/dim]")
|
|
949
|
+
console.print(f"[dim]Use 'devs tunnel {dev_name} --kill' to stop[/dim]")
|
|
950
|
+
return True
|
|
951
|
+
|
|
952
|
+
if 'log in' in output.lower() or 'device' in output.lower() or 'invalid' in output.lower():
|
|
953
|
+
subprocess.run(
|
|
954
|
+
['docker', 'exec', container_name, '/usr/local/bin/code', 'tunnel', 'kill'],
|
|
955
|
+
capture_output=True
|
|
956
|
+
)
|
|
957
|
+
return False
|
|
958
|
+
|
|
959
|
+
if debug and output.strip():
|
|
960
|
+
console.print(f"[dim]Log ({i+1}s): {output.strip()[-100:]}[/dim]")
|
|
961
|
+
|
|
962
|
+
# Timeout
|
|
963
|
+
result = subprocess.run(
|
|
964
|
+
['docker', 'exec', container_name, 'cat', log_file],
|
|
965
|
+
capture_output=True, text=True
|
|
966
|
+
)
|
|
967
|
+
if result.stdout.strip():
|
|
968
|
+
console.print("[yellow]Tunnel may still be starting. Log output:[/yellow]")
|
|
969
|
+
console.print(result.stdout.strip())
|
|
970
|
+
else:
|
|
971
|
+
console.print("[yellow]Tunnel started but no output yet. Check status with:[/yellow]")
|
|
972
|
+
console.print(f" devs tunnel {dev_name} --status")
|
|
973
|
+
return True
|
|
974
|
+
|
|
885
975
|
def tunnel_auth(self, dev_name: str, workspace_dir: Path, debug: bool = False, live: bool = False, extra_env: Optional[Dict[str, str]] = None) -> None:
|
|
886
976
|
"""Authenticate VS Code tunnel (interactive, per-container setup).
|
|
887
977
|
|
|
888
|
-
Runs the device code flow interactively inside the container. Auth is
|
|
889
|
-
stored in the container's filesystem and persists across stop/restart
|
|
890
|
-
cycles (but not container removal/recreation).
|
|
891
|
-
|
|
892
978
|
Args:
|
|
893
979
|
dev_name: Development environment name
|
|
894
980
|
workspace_dir: Workspace directory path
|
|
@@ -909,34 +995,11 @@ class ContainerManager:
|
|
|
909
995
|
console.print("🔐 Setting up VS Code tunnel authentication...")
|
|
910
996
|
console.print(f" Container: {container_name}")
|
|
911
997
|
console.print("")
|
|
912
|
-
console.print("[yellow]Follow the prompts to authenticate:[/yellow]")
|
|
913
|
-
console.print(" 1. A URL and code will be displayed")
|
|
914
|
-
console.print(" 2. Open the URL in your browser")
|
|
915
|
-
console.print(" 3. Enter the code to authenticate with GitHub/Microsoft")
|
|
916
|
-
console.print("")
|
|
917
998
|
|
|
918
|
-
|
|
919
|
-
'docker', 'exec', '-it',
|
|
920
|
-
container_name,
|
|
921
|
-
'/usr/local/bin/code', 'tunnel', 'user', 'login',
|
|
922
|
-
'--provider', 'github'
|
|
923
|
-
]
|
|
924
|
-
|
|
925
|
-
if debug:
|
|
926
|
-
console.print(f"[dim]Running: {' '.join(cmd)}[/dim]")
|
|
927
|
-
|
|
928
|
-
result = subprocess.run(cmd, check=False)
|
|
929
|
-
|
|
930
|
-
if result.returncode == 0:
|
|
931
|
-
console.print("")
|
|
932
|
-
console.print("[bold green]Authentication successful![/bold green]")
|
|
933
|
-
console.print(" Auth persists across container stop/restart cycles.")
|
|
999
|
+
if self._run_tunnel_auth(container_name, debug=debug):
|
|
934
1000
|
console.print("")
|
|
935
1001
|
console.print(f" Start a tunnel: devs tunnel {dev_name}")
|
|
936
1002
|
console.print(f" Then connect: code --remote tunnel+{tunnel_name} {container_workspace_dir}")
|
|
937
|
-
else:
|
|
938
|
-
console.print("")
|
|
939
|
-
console.print("[yellow]Authentication was cancelled or failed.[/yellow]")
|
|
940
1003
|
|
|
941
1004
|
except (DockerError, subprocess.SubprocessError) as e:
|
|
942
1005
|
raise ContainerError(f"Failed to authenticate tunnel in {dev_name}: {e}")
|
|
@@ -944,8 +1007,7 @@ class ContainerManager:
|
|
|
944
1007
|
def start_tunnel(self, dev_name: str, workspace_dir: Path, debug: bool = False, live: bool = False, extra_env: Optional[Dict[str, str]] = None) -> None:
|
|
945
1008
|
"""Start a VS Code tunnel in the background.
|
|
946
1009
|
|
|
947
|
-
|
|
948
|
-
detached inside the container.
|
|
1010
|
+
If authentication is needed, prompts interactively then retries.
|
|
949
1011
|
|
|
950
1012
|
Args:
|
|
951
1013
|
dev_name: Development environment name
|
|
@@ -966,71 +1028,26 @@ class ContainerManager:
|
|
|
966
1028
|
log_file = '/tmp/vscode-tunnel.log'
|
|
967
1029
|
tunnel_cmd = f'/usr/local/bin/code tunnel --accept-server-license-terms --name {tunnel_name}'
|
|
968
1030
|
vscode_cmd = f"code --remote tunnel+{tunnel_name} {container_workspace_dir}"
|
|
1031
|
+
web_url = f"https://vscode.dev/tunnel/{tunnel_name}{container_workspace_dir}"
|
|
969
1032
|
|
|
970
1033
|
console.print(f"[bold cyan]Starting VS Code tunnel for: {dev_name}[/bold cyan]")
|
|
971
1034
|
console.print(f" Container: {container_name}")
|
|
972
1035
|
console.print(f" Tunnel name: {tunnel_name}")
|
|
973
1036
|
console.print("")
|
|
974
1037
|
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
]
|
|
982
|
-
|
|
983
|
-
if debug:
|
|
984
|
-
console.print(f"[dim]Running: {' '.join(cmd)}[/dim]")
|
|
985
|
-
|
|
986
|
-
subprocess.run(cmd, check=True)
|
|
987
|
-
|
|
988
|
-
# Poll the log to confirm startup and show the URL
|
|
989
|
-
console.print("[dim]Waiting for tunnel to start...[/dim]")
|
|
990
|
-
for i in range(15):
|
|
991
|
-
time.sleep(1)
|
|
992
|
-
result = subprocess.run(
|
|
993
|
-
['docker', 'exec', container_name, 'cat', log_file],
|
|
994
|
-
capture_output=True, text=True
|
|
995
|
-
)
|
|
996
|
-
output = result.stdout
|
|
997
|
-
|
|
998
|
-
if 'Open this link' in output or 'vscode.dev/tunnel' in output:
|
|
999
|
-
console.print(f"[bold green]Tunnel running![/bold green]")
|
|
1000
|
-
console.print("")
|
|
1001
|
-
console.print("[bold]Connect from your local machine:[/bold]")
|
|
1002
|
-
console.print(f" {vscode_cmd}")
|
|
1003
|
-
console.print("")
|
|
1004
|
-
for line in output.split('\n'):
|
|
1005
|
-
if 'vscode.dev/tunnel' in line:
|
|
1006
|
-
console.print(f"[dim]Or open in browser: {line.strip()}[/dim]")
|
|
1007
|
-
console.print(f"[dim]Use 'devs tunnel {dev_name} --status' to check status[/dim]")
|
|
1008
|
-
console.print(f"[dim]Use 'devs tunnel {dev_name} --kill' to stop[/dim]")
|
|
1009
|
-
return
|
|
1010
|
-
|
|
1011
|
-
if 'log in' in output.lower() or 'device' in output.lower() or 'invalid' in output.lower():
|
|
1012
|
-
console.print("[yellow]Authentication required.[/yellow]")
|
|
1013
|
-
console.print(f" Run: devs tunnel {dev_name} --auth")
|
|
1014
|
-
subprocess.run(
|
|
1015
|
-
['docker', 'exec', container_name, '/usr/local/bin/code', 'tunnel', 'kill'],
|
|
1016
|
-
capture_output=True
|
|
1017
|
-
)
|
|
1038
|
+
if not self._start_and_poll_tunnel(container_name, dev_name, tunnel_cmd,
|
|
1039
|
+
log_file, vscode_cmd, web_url, debug=debug):
|
|
1040
|
+
# Auth needed
|
|
1041
|
+
console.print("[yellow]Authentication required. Starting login...[/yellow]")
|
|
1042
|
+
console.print("")
|
|
1043
|
+
if not self._run_tunnel_auth(container_name, debug=debug):
|
|
1018
1044
|
return
|
|
1019
1045
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
['docker', 'exec', container_name, 'cat', log_file],
|
|
1026
|
-
capture_output=True, text=True
|
|
1027
|
-
)
|
|
1028
|
-
if result.stdout.strip():
|
|
1029
|
-
console.print("[yellow]Tunnel may still be starting. Log output:[/yellow]")
|
|
1030
|
-
console.print(result.stdout.strip())
|
|
1031
|
-
else:
|
|
1032
|
-
console.print("[yellow]Tunnel started but no output yet. Check status with:[/yellow]")
|
|
1033
|
-
console.print(f" devs tunnel {dev_name} --status")
|
|
1046
|
+
console.print("")
|
|
1047
|
+
console.print("[dim]Restarting tunnel...[/dim]")
|
|
1048
|
+
console.print("")
|
|
1049
|
+
self._start_and_poll_tunnel(container_name, dev_name, tunnel_cmd,
|
|
1050
|
+
log_file, vscode_cmd, web_url, debug=debug)
|
|
1034
1051
|
|
|
1035
1052
|
except (DockerError, subprocess.SubprocessError) as e:
|
|
1036
1053
|
raise ContainerError(f"Failed to start tunnel in {dev_name}: {e}")
|
|
@@ -125,9 +125,14 @@ RUN curl -fsSL https://claude.ai/install.sh | bash
|
|
|
125
125
|
# Install OpenAI Codex CLI
|
|
126
126
|
RUN npm install -g @openai/codex
|
|
127
127
|
|
|
128
|
+
# Install cloudflared for tunnel support (proxies all HTTP methods correctly)
|
|
128
129
|
# Install VS Code CLI for tunnel support (needs root for /usr/local/bin)
|
|
129
130
|
# Using the standalone CLI which supports the 'tunnel' command
|
|
130
131
|
USER root
|
|
132
|
+
RUN ARCH=$(dpkg --print-architecture) && \
|
|
133
|
+
curl -fSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${ARCH}" -o /usr/local/bin/cloudflared && \
|
|
134
|
+
chmod +x /usr/local/bin/cloudflared
|
|
135
|
+
|
|
131
136
|
RUN ARCH=$(dpkg --print-architecture) && \
|
|
132
137
|
if [ "$ARCH" = "amd64" ]; then \
|
|
133
138
|
curl -fSL 'https://update.code.visualstudio.com/latest/cli-linux-x64/stable' -o /tmp/vscode-cli.tar.gz; \
|
|
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
|
{devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/scripts/post-create-wrapper.sh
RENAMED
|
File without changes
|
{devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/scripts/python-venv-integration.sh
RENAMED
|
File without changes
|
{devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/scripts/screenshot-webapp.sh
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/scripts/webapp-screenshot.py
RENAMED
|
File without changes
|
{devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/sudo-scripts/init-firewall.sh
RENAMED
|
File without changes
|
{devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/sudo-scripts/setup-devs-env.sh
RENAMED
|
File without changes
|
{devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/sudo-scripts/setup-vscode-cache.sh
RENAMED
|
File without changes
|
{devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/sudo-scripts/start-services.sh
RENAMED
|
File without changes
|
{devs_common-2.0.11 → devs_common-2.0.13}/devs_common/templates/vscode-settings-reference.md
RENAMED
|
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
|