fix: relocate server runtime secrets

This commit is contained in:
2025-10-17 19:51:35 -06:00
parent 98ee77caca
commit 43967e758d
6 changed files with 101 additions and 8 deletions

View File

@@ -14,7 +14,9 @@ import jwt
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ed25519
_KEY_DIR = Path(__file__).resolve().parent.parent / "keys"
from Modules.runtime import ensure_runtime_dir, runtime_path
_KEY_DIR = runtime_path("keys")
_KEY_FILE = _KEY_DIR / "borealis-jwt-ed25519.key"
@@ -96,7 +98,7 @@ def load_service() -> JWTService:
def _load_or_create_private_key() -> ed25519.Ed25519PrivateKey:
_KEY_DIR.mkdir(parents=True, exist_ok=True)
ensure_runtime_dir("keys")
if _KEY_FILE.exists():
with _KEY_FILE.open("rb") as fh:
return serialization.load_pem_private_key(fh.read(), password=None)

View File

@@ -19,7 +19,9 @@ from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.x509.oid import NameOID
_CERT_DIR = Path(__file__).resolve().parent.parent / "certs"
from Modules.runtime import ensure_runtime_dir, runtime_path
_CERT_DIR = runtime_path("certs")
_CERT_FILE = _CERT_DIR / "borealis-server-cert.pem"
_KEY_FILE = _CERT_DIR / "borealis-server-key.pem"
_BUNDLE_FILE = _CERT_DIR / "borealis-server-bundle.pem"
@@ -35,7 +37,7 @@ def ensure_certificate(common_name: str = "Borealis Server") -> Tuple[Path, Path
Returns (cert_path, key_path, bundle_path).
"""
_CERT_DIR.mkdir(parents=True, exist_ok=True)
ensure_runtime_dir("certs")
regenerate = not (_CERT_FILE.exists() and _KEY_FILE.exists())
if not regenerate:

View File

@@ -10,9 +10,11 @@ from typing import Tuple
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ed25519
from Modules.runtime import ensure_runtime_dir, runtime_path
from .keys import base64_from_spki_der
_KEY_DIR = Path(__file__).resolve().parent.parent / "keys"
_KEY_DIR = runtime_path("keys")
_SIGNING_KEY_FILE = _KEY_DIR / "borealis-script-ed25519.key"
_SIGNING_PUB_FILE = _KEY_DIR / "borealis-script-ed25519.pub"
@@ -41,7 +43,7 @@ def load_signer() -> ScriptSigner:
def _load_or_create() -> ed25519.Ed25519PrivateKey:
_KEY_DIR.mkdir(parents=True, exist_ok=True)
ensure_runtime_dir("keys")
if _SIGNING_KEY_FILE.exists():
with _SIGNING_KEY_FILE.open("rb") as fh:
return serialization.load_pem_private_key(fh.read(), password=None)

View File

@@ -0,0 +1,78 @@
"""Utility helpers for locating runtime storage paths.
The Borealis repository keeps the authoritative source code under ``Data/``
so that the bootstrap scripts can copy those assets into sibling ``Server/``
and ``Agent/`` directories for execution. Runtime artefacts such as TLS
certificates or signing keys must therefore live outside ``Data`` to avoid
polluting the template tree. This module centralises the path selection so
other modules can rely on a consistent location regardless of whether they
are executed from the copied runtime directory or directly from ``Data``
during development.
"""
from __future__ import annotations
import os
from functools import lru_cache
from pathlib import Path
from typing import Optional
def _env_path(name: str) -> Optional[Path]:
"""Return a resolved ``Path`` for the given environment variable."""
value = os.environ.get(name)
if not value:
return None
try:
return Path(value).expanduser().resolve()
except Exception:
return None
@lru_cache(maxsize=None)
def project_root() -> Path:
"""Best-effort detection of the repository root."""
env = _env_path("BOREALIS_PROJECT_ROOT")
if env:
return env
current = Path(__file__).resolve()
for parent in current.parents:
if (parent / "Borealis.ps1").exists() or (parent / ".git").is_dir():
return parent
# Fallback to the ancestor that corresponds to ``<repo>/`` when the module
# lives under ``Data/Server/Modules``.
try:
return current.parents[4]
except IndexError:
return current.parent
@lru_cache(maxsize=None)
def server_runtime_root() -> Path:
"""Location where the running server stores mutable artefacts."""
env = _env_path("BOREALIS_SERVER_ROOT")
if env:
return env
root = project_root()
runtime = root / "Server" / "Borealis"
return runtime
def runtime_path(*parts: str) -> Path:
"""Return a path relative to the server runtime root."""
return server_runtime_root().joinpath(*parts)
def ensure_runtime_dir(*parts: str) -> Path:
"""Create (if required) and return a runtime directory."""
path = runtime_path(*parts)
path.mkdir(parents=True, exist_ok=True)
return path

View File

@@ -4,16 +4,20 @@ import react from '@vitejs/plugin-react';
import path from 'path';
import fs from 'fs';
const runtimeCertDir = process.env.BOREALIS_CERT_DIR;
const certCandidates = [
process.env.BOREALIS_TLS_CERT,
runtimeCertDir && path.resolve(runtimeCertDir, 'borealis-server-cert.pem'),
path.resolve(__dirname, '../certs/borealis-server-cert.pem'),
path.resolve(__dirname, '../../Data/Server/certs/borealis-server-cert.pem'),
path.resolve(__dirname, '../../../Server/Borealis/certs/borealis-server-cert.pem'),
] as const;
const keyCandidates = [
process.env.BOREALIS_TLS_KEY,
runtimeCertDir && path.resolve(runtimeCertDir, 'borealis-server-key.pem'),
path.resolve(__dirname, '../certs/borealis-server-key.pem'),
path.resolve(__dirname, '../../Data/Server/certs/borealis-server-key.pem'),
path.resolve(__dirname, '../../../Server/Borealis/certs/borealis-server-key.pem'),
] as const;
const pickFirst = (candidates: readonly (string | undefined)[]) => {

View File

@@ -20,6 +20,7 @@ Section Guide:
import os
import sys
from pathlib import Path
# Ensure the modular server package is importable when the runtime is launched
# from a packaged directory (e.g., Server/Borealis). We look for the canonical
@@ -167,6 +168,10 @@ TLS_CERT_PATH, TLS_KEY_PATH, TLS_BUNDLE_PATH = certificates.certificate_paths()
os.environ.setdefault("BOREALIS_TLS_CERT", TLS_CERT_PATH)
os.environ.setdefault("BOREALIS_TLS_KEY", TLS_KEY_PATH)
os.environ.setdefault("BOREALIS_TLS_BUNDLE", TLS_BUNDLE_PATH)
try:
os.environ.setdefault("BOREALIS_CERT_DIR", str(Path(TLS_CERT_PATH).resolve().parent))
except Exception:
pass
JWT_SERVICE = jwt_service_module.load_service()
SCRIPT_SIGNER = signing.load_signer()