Skip to content

Commit 583fa11

Browse files
committed
seed webcore admin
1 parent 2e16cb4 commit 583fa11

3 files changed

Lines changed: 43 additions & 5 deletions

File tree

‎robot_orchestrator/boot/fsm.py‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import dataclasses
33
import json
44
import os
5+
import subprocess
56
import time
67
import uuid
78
from dataclasses import dataclass
@@ -15,6 +16,7 @@
1516
from robot_orchestrator.hal.base import ProbeResult
1617
from robot_orchestrator.paths import Paths
1718
from robot_orchestrator.repos.manager import RELEASE_MARKER, RepoManager
19+
from robot_orchestrator.repos.venvs import venv_python
1820
from robot_orchestrator.secrets import store as secrets_store
1921
from robot_orchestrator.secrets.ingest import ingest_payload
2022
from robot_orchestrator.secrets.protocol import SecretsPayload
@@ -174,6 +176,40 @@ def _update_repos(self, facts: BootFacts) -> None:
174176
result = manager.sync()
175177
if result.error is not None and result.sha is None:
176178
facts.repo_update_failures.append(name)
179+
elif name == "web-core":
180+
self._ensure_webcore_admin()
181+
182+
def _ensure_webcore_admin(self) -> None:
183+
repo_state = store.get_repo_state(self.db.conn, "web-core")
184+
if not repo_state or not repo_state.get("current_release"):
185+
return
186+
release_dir = Path(repo_state["current_release"])
187+
marker_path = release_dir / RELEASE_MARKER
188+
if not marker_path.exists():
189+
return
190+
marker = json.loads(marker_path.read_text(encoding="utf-8"))
191+
venv_hash = marker.get("venv_hash")
192+
if not venv_hash:
193+
return
194+
python = venv_python(self.paths.venv_path("web-core", venv_hash))
195+
script = release_dir / "tools" / "create_admin.py"
196+
if not python.exists() or not script.exists():
197+
return
198+
199+
generated = secrets_store.ensure_generated_secrets(self.paths)
200+
regular = secrets_store.load_secrets(self.paths).get("secrets", {}) or {}
201+
admin_password = regular.get("WEBCORE_ADMIN_PASSWORD") or generated.get("WEBCORE_ADMIN_PASSWORD")
202+
if not admin_password:
203+
return
204+
205+
env = {**os.environ, "ADMIN_PASSWORD": admin_password}
206+
try:
207+
subprocess.run(
208+
[str(python), str(script)], cwd=release_dir, env=env,
209+
capture_output=True, text=True, timeout=30.0,
210+
)
211+
except (OSError, subprocess.TimeoutExpired):
212+
pass
177213

178214
def _run_firmware_targets(self, facts: BootFacts) -> None:
179215
for name, workflow in self.firmware_workflows.items():

‎robot_orchestrator/secrets/store.py‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from robot_orchestrator.secrets.protocol import SecretsPayload, WifiCredential
88
from robot_orchestrator.wal.atomic import atomic_write
99

10-
GENERATED_KEYS = ("MASTER_TOKEN", "flask_secret", "ORCH_JWT_SECRET")
10+
GENERATED_KEYS = ("MASTER_TOKEN", "flask_secret", "ORCH_JWT_SECRET", "WEBCORE_ADMIN_PASSWORD")
1111

1212

1313
def _ensure_secrets_dir(paths: Paths) -> None:
@@ -42,9 +42,11 @@ def write_secrets(paths: Paths, payload: SecretsPayload) -> None:
4242

4343

4444
def ensure_generated_secrets(paths: Paths) -> dict:
45-
if not paths.generated_secrets_file.exists():
45+
existing = _load_generated(paths)
46+
missing = [key for key in GENERATED_KEYS if not existing.get(key)]
47+
if missing:
4648
_ensure_secrets_dir(paths)
47-
generated = {key: stdlib_secrets.token_urlsafe(32) for key in GENERATED_KEYS}
49+
generated = {**existing, **{key: stdlib_secrets.token_urlsafe(32) for key in missing}}
4850
blob = yaml.safe_dump(generated, sort_keys=True).encode("utf-8")
4951
atomic_write(paths.generated_secrets_file, blob)
5052
return _load_generated(paths)

‎tests/test_secrets_store.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ def test_write_secrets_permissions(tmp_path: Path):
4646
assert dir_mode == 0o700
4747

4848

49-
def test_ensure_generated_secrets_creates_three_keys(tmp_path: Path):
49+
def test_ensure_generated_secrets_creates_expected_keys(tmp_path: Path):
5050
paths = _make_paths(tmp_path)
5151
generated = store.ensure_generated_secrets(paths)
5252

53-
assert set(generated.keys()) == {"MASTER_TOKEN", "flask_secret", "ORCH_JWT_SECRET"}
53+
assert set(generated.keys()) == {"MASTER_TOKEN", "flask_secret", "ORCH_JWT_SECRET", "WEBCORE_ADMIN_PASSWORD"}
5454
assert all(generated[key] for key in generated)
5555

5656

0 commit comments

Comments
 (0)