dh-cli 0.4.3__tar.gz → 0.4.5__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.
- {dh_cli-0.4.3 → dh_cli-0.4.5}/PKG-INFO +1 -1
- {dh_cli-0.4.3 → dh_cli-0.4.5}/pyproject.toml +1 -1
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/hz/deploy.py +15 -3
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/hz/test.py +73 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/hz/tf.py +18 -3
- {dh_cli-0.4.3 → dh_cli-0.4.5}/.gitignore +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/LICENSE +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/README.md +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/__init__.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/__init__.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/aws_batch.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/__init__.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/boltz.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/cancel.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/clean.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/embed_t5.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/finalize.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/list_jobs.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/local.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/logs.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/protmpnn.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/protmpnn_to_boltz.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/retry.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/status.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/submit.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/train.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/commands/wait_for.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/fasta_utils.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/h5_utils.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/job_id.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/manifest.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/batch/s3_transport.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/cloud_commands.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/codeartifact.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/engines_studios/__init__.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/engines_studios/api_client.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/engines_studios/auth.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/engines_studios/engine_commands.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/engines_studios/progress.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/engines_studios/ssh_config.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/engines_studios/studio_commands.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/github_commands.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/hz/__init__.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/hz/local.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/hz/users.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/main.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/utility_commands.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/src/dh_cli/warehouse.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/tests/hz/test_init.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/tests/hz/test_suites.py +0 -0
- {dh_cli-0.4.3 → dh_cli-0.4.5}/tests/hz/test_users.py +0 -0
|
@@ -7,11 +7,21 @@ from dh_cli.hz import require_repo, run_script
|
|
|
7
7
|
deploy_app = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]})
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
def _confirm_deploy(target: str, env: str) -> None:
|
|
11
|
+
color = typer.colors.RED if env == "prod" else typer.colors.BRIGHT_GREEN
|
|
12
|
+
env_styled = typer.style(env, fg=color, bold=True)
|
|
13
|
+
typer.echo(f"\n Deploying {target} to {env_styled}\n")
|
|
14
|
+
if not typer.confirm(" Continue?"):
|
|
15
|
+
raise typer.Abort()
|
|
16
|
+
typer.echo()
|
|
17
|
+
|
|
18
|
+
|
|
10
19
|
@deploy_app.command("api")
|
|
11
20
|
def deploy_api(
|
|
12
|
-
env: str = typer.Option("
|
|
21
|
+
env: str = typer.Option("dev", "--env", "-e", help="Environment: prod or dev."),
|
|
13
22
|
):
|
|
14
23
|
"""Build and deploy the Horizyn API server."""
|
|
24
|
+
_confirm_deploy("api", env)
|
|
15
25
|
repo = require_repo("horizyn-api")
|
|
16
26
|
script = repo / f"server/build-and-push-{env}.sh"
|
|
17
27
|
run_script(script, cwd=repo)
|
|
@@ -19,9 +29,10 @@ def deploy_api(
|
|
|
19
29
|
|
|
20
30
|
@deploy_app.command("docking")
|
|
21
31
|
def deploy_docking(
|
|
22
|
-
env: str = typer.Option("
|
|
32
|
+
env: str = typer.Option("dev", "--env", "-e", help="Environment: prod or dev."),
|
|
23
33
|
):
|
|
24
34
|
"""Build and deploy the docking service."""
|
|
35
|
+
_confirm_deploy("docking", env)
|
|
25
36
|
repo = require_repo("horizyn-api")
|
|
26
37
|
script = repo / f"docking_service/build-and-push-{env}.sh"
|
|
27
38
|
run_script(script, cwd=repo)
|
|
@@ -29,9 +40,10 @@ def deploy_docking(
|
|
|
29
40
|
|
|
30
41
|
@deploy_app.command("frontend")
|
|
31
42
|
def deploy_frontend(
|
|
32
|
-
env: str = typer.Option("
|
|
43
|
+
env: str = typer.Option("dev", "--env", "-e", help="Environment: prod or dev."),
|
|
33
44
|
):
|
|
34
45
|
"""Build and deploy the Horizyn frontend."""
|
|
46
|
+
_confirm_deploy("frontend", env)
|
|
35
47
|
repo = require_repo("horizyn-frontend")
|
|
36
48
|
script = repo / "scripts/deploy.sh"
|
|
37
49
|
run_script(script, args=[env], cwd=repo)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Run integration test suites."""
|
|
2
2
|
|
|
3
|
+
import os
|
|
3
4
|
import re
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import Optional
|
|
@@ -48,6 +49,75 @@ def _resolve_suites(
|
|
|
48
49
|
return matched
|
|
49
50
|
|
|
50
51
|
|
|
52
|
+
def _ensure_jwt_token(env: str, test_dir: Path) -> None:
|
|
53
|
+
"""Ensure HORIZYN_TOKEN is set, prompting interactively if needed.
|
|
54
|
+
|
|
55
|
+
Checks (in order): env var with expiry validation, cached token file,
|
|
56
|
+
then falls back to interactive Cognito passwordless auth.
|
|
57
|
+
Sets os.environ["HORIZYN_TOKEN"] so child processes inherit it.
|
|
58
|
+
"""
|
|
59
|
+
import json
|
|
60
|
+
import subprocess
|
|
61
|
+
import time
|
|
62
|
+
|
|
63
|
+
token_script = test_dir / "get_jwt_token.py"
|
|
64
|
+
cache_dir = Path.home() / ".horizyn"
|
|
65
|
+
cache_file = cache_dir / f"token_{env}"
|
|
66
|
+
|
|
67
|
+
def _token_valid(token: str) -> bool:
|
|
68
|
+
"""Check JWT expiry without verification (5-minute buffer)."""
|
|
69
|
+
import base64
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
payload = token.split(".")[1]
|
|
73
|
+
padding = 4 - len(payload) % 4
|
|
74
|
+
if padding != 4:
|
|
75
|
+
payload += "=" * padding
|
|
76
|
+
decoded = json.loads(base64.urlsafe_b64decode(payload))
|
|
77
|
+
return time.time() < (decoded.get("exp", 0) - 300)
|
|
78
|
+
except Exception:
|
|
79
|
+
return False
|
|
80
|
+
|
|
81
|
+
# 1. Check existing env var
|
|
82
|
+
existing = os.environ.get("HORIZYN_TOKEN", "")
|
|
83
|
+
if existing and _token_valid(existing):
|
|
84
|
+
typer.secho(" Using existing HORIZYN_TOKEN", fg=typer.colors.GREEN)
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
# 2. Check cached token file
|
|
88
|
+
if cache_file.exists():
|
|
89
|
+
cached = cache_file.read_text().strip()
|
|
90
|
+
if cached and _token_valid(cached):
|
|
91
|
+
os.environ["HORIZYN_TOKEN"] = cached
|
|
92
|
+
typer.secho(f" Using cached token from {cache_file}", fg=typer.colors.GREEN)
|
|
93
|
+
return
|
|
94
|
+
cache_file.unlink(missing_ok=True)
|
|
95
|
+
|
|
96
|
+
# 3. Interactive: run get_jwt_token.py (prompts go to stderr, token to stdout)
|
|
97
|
+
typer.echo()
|
|
98
|
+
typer.secho(" No valid token found — starting authentication.", fg=typer.colors.YELLOW)
|
|
99
|
+
typer.echo()
|
|
100
|
+
|
|
101
|
+
result = subprocess.run(
|
|
102
|
+
["python3", str(token_script), "--env", env],
|
|
103
|
+
capture_output=False,
|
|
104
|
+
stdout=subprocess.PIPE,
|
|
105
|
+
text=True,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if result.returncode != 0 or not result.stdout.strip():
|
|
109
|
+
typer.secho(" Authentication failed.", fg=typer.colors.RED, err=True)
|
|
110
|
+
raise typer.Exit(1)
|
|
111
|
+
|
|
112
|
+
token = result.stdout.strip()
|
|
113
|
+
os.environ["HORIZYN_TOKEN"] = token
|
|
114
|
+
|
|
115
|
+
# Cache for future runs
|
|
116
|
+
cache_dir.mkdir(mode=0o700, exist_ok=True)
|
|
117
|
+
cache_file.write_text(token)
|
|
118
|
+
cache_file.chmod(0o600)
|
|
119
|
+
|
|
120
|
+
|
|
51
121
|
@test_app.command("list")
|
|
52
122
|
def list_tests(
|
|
53
123
|
target: str = typer.Option("local", "--target", "-t", help="local or deployed."),
|
|
@@ -98,9 +168,12 @@ def test_deployed(
|
|
|
98
168
|
test_dir = repo / "test/server/deployed"
|
|
99
169
|
|
|
100
170
|
if not suites:
|
|
171
|
+
# run_all_tests.sh handles its own token flow
|
|
101
172
|
run_script(test_dir / "run_all_tests.sh", args=[env], cwd=test_dir)
|
|
102
173
|
return
|
|
103
174
|
|
|
175
|
+
_ensure_jwt_token(env, test_dir)
|
|
176
|
+
|
|
104
177
|
available = _discover_suites(test_dir)
|
|
105
178
|
selected = _resolve_suites(available, suites)
|
|
106
179
|
|
|
@@ -16,6 +16,15 @@ TF_MODULES = {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
def _confirm_tf(target: str, env: str) -> None:
|
|
20
|
+
color = typer.colors.RED if env == "prod" else typer.colors.BRIGHT_GREEN
|
|
21
|
+
env_styled = typer.style(env, fg=color, bold=True)
|
|
22
|
+
typer.echo(f"\n Terraform apply: {target} in {env_styled}\n")
|
|
23
|
+
if not typer.confirm(" Continue?"):
|
|
24
|
+
raise typer.Abort()
|
|
25
|
+
typer.echo()
|
|
26
|
+
|
|
27
|
+
|
|
19
28
|
def _run_tf(target: str, env: str, action: str) -> None:
|
|
20
29
|
repo = require_repo("blueprints")
|
|
21
30
|
module_path = TF_MODULES.get((target, env))
|
|
@@ -28,26 +37,32 @@ def _run_tf(target: str, env: str, action: str) -> None:
|
|
|
28
37
|
|
|
29
38
|
@tf_app.command("api")
|
|
30
39
|
def tf_api(
|
|
31
|
-
env: str = typer.Option("
|
|
40
|
+
env: str = typer.Option("dev", "--env", "-e", help="Environment: prod or dev."),
|
|
32
41
|
yolo: bool = typer.Option(False, "--yolo", help="Auto-approve (no confirmation prompt)."),
|
|
33
42
|
):
|
|
34
43
|
"""Terraform apply for the Horizyn API server."""
|
|
44
|
+
if not yolo:
|
|
45
|
+
_confirm_tf("api", env)
|
|
35
46
|
_run_tf("api", env, "yolo" if yolo else "plan")
|
|
36
47
|
|
|
37
48
|
|
|
38
49
|
@tf_app.command("frontend")
|
|
39
50
|
def tf_frontend(
|
|
40
|
-
env: str = typer.Option("
|
|
51
|
+
env: str = typer.Option("dev", "--env", "-e", help="Environment: prod or dev."),
|
|
41
52
|
yolo: bool = typer.Option(False, "--yolo", help="Auto-approve (no confirmation prompt)."),
|
|
42
53
|
):
|
|
43
54
|
"""Terraform apply for the Horizyn frontend."""
|
|
55
|
+
if not yolo:
|
|
56
|
+
_confirm_tf("frontend", env)
|
|
44
57
|
_run_tf("frontend", env, "yolo" if yolo else "plan")
|
|
45
58
|
|
|
46
59
|
|
|
47
60
|
@tf_app.command("docking")
|
|
48
61
|
def tf_docking(
|
|
49
|
-
env: str = typer.Option("
|
|
62
|
+
env: str = typer.Option("dev", "--env", "-e", help="Environment: prod or dev."),
|
|
50
63
|
yolo: bool = typer.Option(False, "--yolo", help="Auto-approve (no confirmation prompt)."),
|
|
51
64
|
):
|
|
52
65
|
"""Terraform apply for the Boltz docking service."""
|
|
66
|
+
if not yolo:
|
|
67
|
+
_confirm_tf("docking", env)
|
|
53
68
|
_run_tf("docking", env, "yolo" if yolo else "plan")
|
|
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
|