@mriekki/lean 0.1.0 → 0.1.1

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.
Files changed (37) hide show
  1. package/README.md +67 -67
  2. package/assets/components.json +33 -33
  3. package/assets/core/distribution.json +51 -51
  4. package/assets/deployment/distribution.json +34 -34
  5. package/assets/generated/ASSEMBLY.json +28 -28
  6. package/assets/generated/deployment/distribution/lean-poc-deploy.py +8 -8
  7. package/assets/generated/deployment/src/lean_poc_deployment/__init__.py +3 -3
  8. package/assets/generated/deployment/src/lean_poc_deployment/__main__.py +3 -3
  9. package/assets/generated/deployment/src/lean_poc_deployment/app_cli.py +140 -140
  10. package/assets/generated/deployment/src/lean_poc_deployment/app_runtime.py +455 -455
  11. package/assets/generated/deployment/src/lean_poc_deployment/app_runtime_remote.py +415 -415
  12. package/assets/generated/deployment/src/lean_poc_deployment/box_platform.py +208 -208
  13. package/assets/generated/deployment/src/lean_poc_deployment/box_platform_assets.py +100 -100
  14. package/assets/generated/deployment/src/lean_poc_deployment/box_platform_remote.py +271 -271
  15. package/assets/generated/deployment/src/lean_poc_deployment/cli.py +437 -437
  16. package/assets/generated/deployment/src/lean_poc_deployment/doctor.py +121 -121
  17. package/assets/generated/deployment/src/lean_poc_deployment/entrypoint.py +25 -25
  18. package/assets/generated/deployment/src/lean_poc_deployment/errors.py +5 -5
  19. package/assets/generated/deployment/src/lean_poc_deployment/keys.py +171 -171
  20. package/assets/generated/deployment/src/lean_poc_deployment/profiles.py +204 -204
  21. package/assets/generated/deployment/src/lean_poc_deployment/route_registry.py +367 -367
  22. package/assets/generated/deployment/src/lean_poc_deployment/route_registry_remote.py +443 -443
  23. package/assets/generated/deployment/src/lean_poc_deployment/security.py +290 -290
  24. package/assets/generated/deployment/src/lean_poc_deployment/sqlite_adapter.py +334 -334
  25. package/assets/generated/deployment/src/lean_poc_deployment/sqlite_adapter_remote.py +339 -339
  26. package/assets/generated/deployment/src/lean_poc_deployment/sqlite_cli.py +85 -85
  27. package/assets/generated/deployment/src/lean_poc_deployment/sqlite_import_recovery.py +437 -437
  28. package/assets/generated/deployment/src/lean_poc_deployment/ssh.py +118 -118
  29. package/assets/generated/deployment/src/lean_poc_deployment/teardown.py +286 -286
  30. package/assets/generated/deployment/src/lean_poc_deployment/teardown_cli.py +120 -120
  31. package/assets/generated/deployment/src/lean_poc_deployment/teardown_remote.py +100 -100
  32. package/assets/generated/deployment/src/lean_poc_deployment/trust.py +278 -278
  33. package/bin/lean.mjs +9 -9
  34. package/package.json +33 -33
  35. package/src/cli.mjs +131 -131
  36. package/src/engine.mjs +243 -243
  37. package/src/package-data.mjs +18 -18
@@ -1,118 +1,118 @@
1
- """Strict SSH verification primitives for logical targets."""
2
-
3
- from __future__ import annotations
4
-
5
- import shutil
6
- import socket
7
- import subprocess
8
- from pathlib import Path
9
- from typing import Any
10
-
11
- from .errors import DeploymentKitError
12
- from .security import check_ssh_material_security, validate_target_trust_file
13
-
14
-
15
- def required_tool(name: str) -> str:
16
- path = shutil.which(name)
17
- if path is None:
18
- raise DeploymentKitError(f"Required OpenSSH tool is unavailable: {name}")
19
- return path
20
-
21
-
22
- def resolve_addresses(profile: dict[str, Any]) -> list[str]:
23
- override = profile["addressOverride"]
24
- if override:
25
- return [override]
26
- try:
27
- answers = socket.getaddrinfo(
28
- profile["hostName"],
29
- profile["port"],
30
- type=socket.SOCK_STREAM,
31
- )
32
- except OSError as error:
33
- raise DeploymentKitError(
34
- f"Cannot resolve target hostname {profile['hostName']}: {error}. "
35
- "Use only a separately verified address override; do not scan the network."
36
- ) from error
37
- addresses = sorted({answer[4][0] for answer in answers})
38
- if not addresses:
39
- raise DeploymentKitError(f"Target hostname {profile['hostName']} returned no addresses.")
40
- return addresses
41
-
42
-
43
- def ssh_args(profile: dict[str, Any], address: str, *, command: str = "true") -> list[str]:
44
- return [
45
- required_tool("ssh"),
46
- "-F",
47
- "none",
48
- "-o",
49
- "BatchMode=yes",
50
- "-o",
51
- "ConnectTimeout=8",
52
- "-o",
53
- "StrictHostKeyChecking=yes",
54
- "-o",
55
- "UpdateHostKeys=no",
56
- "-o",
57
- "CheckHostIP=no",
58
- "-o",
59
- "VerifyHostKeyDNS=no",
60
- "-o",
61
- "GlobalKnownHostsFile=none",
62
- "-o",
63
- f"UserKnownHostsFile={profile['knownHostsFile']}",
64
- "-o",
65
- f"HostKeyAlias={profile['sshAlias']}",
66
- "-o",
67
- f"IdentityFile={profile['identityFile']}",
68
- "-o",
69
- "IdentitiesOnly=yes",
70
- "-o",
71
- "PasswordAuthentication=no",
72
- "-o",
73
- "KbdInteractiveAuthentication=no",
74
- "-o",
75
- "PreferredAuthentications=publickey",
76
- "-o",
77
- "ForwardAgent=no",
78
- "-o",
79
- "ForwardX11=no",
80
- "-o",
81
- "ClearAllForwardings=yes",
82
- "-p",
83
- str(profile["port"]),
84
- f"{profile['user']}@{address}",
85
- command,
86
- ]
87
-
88
-
89
- def verify_access(profile: dict[str, Any]) -> dict[str, str]:
90
- identity = Path(profile["identityFile"])
91
- known_hosts = Path(profile["knownHostsFile"])
92
- if not identity.is_file():
93
- raise DeploymentKitError(f"Dedicated private key is missing: {identity}")
94
- if not known_hosts.is_file() or known_hosts.stat().st_size == 0:
95
- raise DeploymentKitError(
96
- f"Target-specific trust file is missing or empty: {known_hosts}. "
97
- "Enroll trust only after independently verifying the host fingerprint."
98
- )
99
- check_ssh_material_security(identity, known_hosts)
100
- validate_target_trust_file(profile)
101
-
102
- failures: list[str] = []
103
- for address in resolve_addresses(profile):
104
- result = subprocess.run(
105
- ssh_args(profile, address),
106
- check=False,
107
- capture_output=True,
108
- text=True,
109
- encoding="utf-8",
110
- errors="replace",
111
- )
112
- if result.returncode == 0:
113
- return {"targetName": profile["targetName"], "address": address, "status": "verified"}
114
- failures.append(f"{address}: exit {result.returncode}")
115
-
116
- raise DeploymentKitError(
117
- "Public-key SSH verification failed for all resolved addresses: " + "; ".join(failures)
118
- )
1
+ """Strict SSH verification primitives for logical targets."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import shutil
6
+ import socket
7
+ import subprocess
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ from .errors import DeploymentKitError
12
+ from .security import check_ssh_material_security, validate_target_trust_file
13
+
14
+
15
+ def required_tool(name: str) -> str:
16
+ path = shutil.which(name)
17
+ if path is None:
18
+ raise DeploymentKitError(f"Required OpenSSH tool is unavailable: {name}")
19
+ return path
20
+
21
+
22
+ def resolve_addresses(profile: dict[str, Any]) -> list[str]:
23
+ override = profile["addressOverride"]
24
+ if override:
25
+ return [override]
26
+ try:
27
+ answers = socket.getaddrinfo(
28
+ profile["hostName"],
29
+ profile["port"],
30
+ type=socket.SOCK_STREAM,
31
+ )
32
+ except OSError as error:
33
+ raise DeploymentKitError(
34
+ f"Cannot resolve target hostname {profile['hostName']}: {error}. "
35
+ "Use only a separately verified address override; do not scan the network."
36
+ ) from error
37
+ addresses = sorted({answer[4][0] for answer in answers})
38
+ if not addresses:
39
+ raise DeploymentKitError(f"Target hostname {profile['hostName']} returned no addresses.")
40
+ return addresses
41
+
42
+
43
+ def ssh_args(profile: dict[str, Any], address: str, *, command: str = "true") -> list[str]:
44
+ return [
45
+ required_tool("ssh"),
46
+ "-F",
47
+ "none",
48
+ "-o",
49
+ "BatchMode=yes",
50
+ "-o",
51
+ "ConnectTimeout=8",
52
+ "-o",
53
+ "StrictHostKeyChecking=yes",
54
+ "-o",
55
+ "UpdateHostKeys=no",
56
+ "-o",
57
+ "CheckHostIP=no",
58
+ "-o",
59
+ "VerifyHostKeyDNS=no",
60
+ "-o",
61
+ "GlobalKnownHostsFile=none",
62
+ "-o",
63
+ f"UserKnownHostsFile={profile['knownHostsFile']}",
64
+ "-o",
65
+ f"HostKeyAlias={profile['sshAlias']}",
66
+ "-o",
67
+ f"IdentityFile={profile['identityFile']}",
68
+ "-o",
69
+ "IdentitiesOnly=yes",
70
+ "-o",
71
+ "PasswordAuthentication=no",
72
+ "-o",
73
+ "KbdInteractiveAuthentication=no",
74
+ "-o",
75
+ "PreferredAuthentications=publickey",
76
+ "-o",
77
+ "ForwardAgent=no",
78
+ "-o",
79
+ "ForwardX11=no",
80
+ "-o",
81
+ "ClearAllForwardings=yes",
82
+ "-p",
83
+ str(profile["port"]),
84
+ f"{profile['user']}@{address}",
85
+ command,
86
+ ]
87
+
88
+
89
+ def verify_access(profile: dict[str, Any]) -> dict[str, str]:
90
+ identity = Path(profile["identityFile"])
91
+ known_hosts = Path(profile["knownHostsFile"])
92
+ if not identity.is_file():
93
+ raise DeploymentKitError(f"Dedicated private key is missing: {identity}")
94
+ if not known_hosts.is_file() or known_hosts.stat().st_size == 0:
95
+ raise DeploymentKitError(
96
+ f"Target-specific trust file is missing or empty: {known_hosts}. "
97
+ "Enroll trust only after independently verifying the host fingerprint."
98
+ )
99
+ check_ssh_material_security(identity, known_hosts)
100
+ validate_target_trust_file(profile)
101
+
102
+ failures: list[str] = []
103
+ for address in resolve_addresses(profile):
104
+ result = subprocess.run(
105
+ ssh_args(profile, address),
106
+ check=False,
107
+ capture_output=True,
108
+ text=True,
109
+ encoding="utf-8",
110
+ errors="replace",
111
+ )
112
+ if result.returncode == 0:
113
+ return {"targetName": profile["targetName"], "address": address, "status": "verified"}
114
+ failures.append(f"{address}: exit {result.returncode}")
115
+
116
+ raise DeploymentKitError(
117
+ "Public-key SSH verification failed for all resolved addresses: " + "; ".join(failures)
118
+ )