Publish curated Unraid-AppOps-Gateway source from 2e6cf771e11a9cdc8b2e2453586a16d518adf40b
This commit is contained in:
1 parent
5d598db0df
commit
631b846397
10 files changed
+4709
-8
No files matched your search
@@ -0,0 +1,327 @@
|
||||
"""Fixed, write-only import of the existing WorkMesh controller credential."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hmac
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from typing import Any, TextIO
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from sqlalchemy.dialects.sqlite import insert as sqlite_insert
|
||||
from sqlmodel import Session
|
||||
|
||||
from ..core.time import utc_now
|
||||
from ..db.models import Secret
|
||||
from ..db.session import engine
|
||||
from . import secret_store
|
||||
from .audit_logger import log_event
|
||||
from .deployment_broker import DeploymentBrokerClient
|
||||
from .secret_store import get_secret, secret_storage_status
|
||||
from .workmesh_promotion import _safe_preflight
|
||||
|
||||
SECRET_REF = "WORKMESH_DEPLOYMENT_BROKER"
|
||||
TARGET = "jens/workmesh"
|
||||
_ACTION = "deployment.secret.import_workmesh_controller"
|
||||
_PURPOSE = "fixed_workmesh_controller_promotion"
|
||||
_USED_BY = ["deployment:workmesh_promotion"]
|
||||
_API_VERSION = "itworx.workmesh-controller-secret-import/v1"
|
||||
_REVISION = re.compile(r"^[0-9a-f]{40}$")
|
||||
_AUDIT_ID = re.compile(r"^audit-[0-9a-f]{12}$")
|
||||
_MIN_CREDENTIAL_BYTES = 32
|
||||
_MAX_CREDENTIAL_BYTES = 256
|
||||
_FAILURE_CODES = frozenset({
|
||||
"revision_invalid", "credential_invalid", "secret_reference_unreadable",
|
||||
"secret_reference_conflict", "database_unavailable", "secret_storage_unavailable",
|
||||
"session_not_clean", "controller_https_unverified", "controller_preflight_unavailable",
|
||||
"controller_preflight_rejected", "audit_commit_failed", "secret_readback_failed",
|
||||
"import_failed",
|
||||
})
|
||||
|
||||
|
||||
def _safe_error_code(code: object) -> str:
|
||||
return code if isinstance(code, str) and code in _FAILURE_CODES else "import_failed"
|
||||
|
||||
|
||||
class WorkMeshSecretImportError(ValueError):
|
||||
"""Sanitized failure with a fixed operator-visible reason code."""
|
||||
|
||||
def __init__(self, code: str):
|
||||
self.code = _safe_error_code(code)
|
||||
super().__init__(self.code)
|
||||
|
||||
|
||||
def _reject(code: str) -> None:
|
||||
raise WorkMeshSecretImportError(code)
|
||||
|
||||
|
||||
def _rollback_quietly(session: Session) -> bool:
|
||||
try:
|
||||
session.rollback()
|
||||
except Exception: # noqa: BLE001 - rollback errors must not reach output.
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _validate_input(credential: object, revision: object) -> tuple[str, str]:
|
||||
if (
|
||||
not isinstance(revision, str)
|
||||
or len(revision) != 40
|
||||
or not _REVISION.fullmatch(revision)
|
||||
):
|
||||
_reject("revision_invalid")
|
||||
if not isinstance(credential, str):
|
||||
_reject("credential_invalid")
|
||||
if not _MIN_CREDENTIAL_BYTES <= len(credential) <= _MAX_CREDENTIAL_BYTES:
|
||||
_reject("credential_invalid")
|
||||
try:
|
||||
raw = credential.encode("ascii")
|
||||
except UnicodeEncodeError:
|
||||
_reject("credential_invalid")
|
||||
if (
|
||||
not _MIN_CREDENTIAL_BYTES <= len(raw) <= _MAX_CREDENTIAL_BYTES
|
||||
or not credential.isprintable()
|
||||
or any(character.isspace() for character in credential)
|
||||
):
|
||||
_reject("credential_invalid")
|
||||
return credential, revision
|
||||
|
||||
|
||||
def _controller_is_verified_https(broker: DeploymentBrokerClient) -> bool:
|
||||
try:
|
||||
return (
|
||||
isinstance(broker.base_url, str)
|
||||
and urlparse(broker.base_url).scheme == "https"
|
||||
and broker.verify_tls is True
|
||||
and broker.configuration_error() is None
|
||||
)
|
||||
except Exception: # noqa: BLE001 - config errors may include sensitive values.
|
||||
return False
|
||||
|
||||
|
||||
def _read_existing(session: Session, credential: str) -> bool:
|
||||
"""Check the fixed row without touching its timestamps or metadata."""
|
||||
try:
|
||||
row = session.get(Secret, SECRET_REF)
|
||||
if row is None:
|
||||
session.commit()
|
||||
return False
|
||||
existing = get_secret(session, SECRET_REF, touch=False)
|
||||
if existing is None:
|
||||
_reject("secret_reference_unreadable")
|
||||
if not hmac.compare_digest(existing, credential):
|
||||
_reject("secret_reference_conflict")
|
||||
session.commit()
|
||||
return True
|
||||
except WorkMeshSecretImportError:
|
||||
_rollback_quietly(session)
|
||||
raise
|
||||
except Exception: # noqa: BLE001 - database errors are not operator output.
|
||||
_rollback_quietly(session)
|
||||
_reject("database_unavailable")
|
||||
|
||||
|
||||
def _store_if_absent(
|
||||
session: Session,
|
||||
credential: str,
|
||||
*,
|
||||
revision: str,
|
||||
preflight_sha256: str,
|
||||
) -> bool:
|
||||
"""Atomically add the fixed row; a concurrent value is never replaced."""
|
||||
try:
|
||||
encrypted = secret_store._fernet().encrypt(credential.encode("ascii")).decode("ascii")
|
||||
now = utc_now()
|
||||
metadata = {
|
||||
"purpose": _PURPOSE,
|
||||
"repository": TARGET,
|
||||
"revision": revision,
|
||||
"preflightSha256": preflight_sha256,
|
||||
}
|
||||
insert = (
|
||||
sqlite_insert(Secret)
|
||||
.values(
|
||||
id=SECRET_REF,
|
||||
name=SECRET_REF,
|
||||
encrypted_value=encrypted,
|
||||
created_at=now,
|
||||
updated_at=now,
|
||||
last_used_at=None,
|
||||
used_by_json=list(_USED_BY),
|
||||
metadata_json=metadata,
|
||||
)
|
||||
.on_conflict_do_nothing(index_elements=[Secret.id])
|
||||
)
|
||||
inserted = session.exec(insert).rowcount == 1
|
||||
row = session.get(Secret, SECRET_REF)
|
||||
if row is None:
|
||||
_reject("database_unavailable")
|
||||
stored = get_secret(session, SECRET_REF, touch=False)
|
||||
if stored is None:
|
||||
_reject("secret_reference_unreadable")
|
||||
if not hmac.compare_digest(stored, credential):
|
||||
_reject("secret_reference_conflict")
|
||||
return inserted
|
||||
except WorkMeshSecretImportError:
|
||||
_rollback_quietly(session)
|
||||
raise
|
||||
except Exception: # noqa: BLE001 - crypto/database details stay private.
|
||||
_rollback_quietly(session)
|
||||
_reject("database_unavailable")
|
||||
|
||||
|
||||
def import_workmesh_deployment_secret(
|
||||
session: Session,
|
||||
credential: str,
|
||||
*,
|
||||
revision: str,
|
||||
broker: DeploymentBrokerClient | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Bind an existing target credential after exact fixed-target preflight."""
|
||||
value, requested_revision = _validate_input(credential, revision)
|
||||
try:
|
||||
if secret_storage_status().get("productionReady") is not True:
|
||||
_reject("secret_storage_unavailable")
|
||||
except WorkMeshSecretImportError:
|
||||
raise
|
||||
except Exception: # noqa: BLE001 - storage configuration may contain secrets.
|
||||
_reject("secret_storage_unavailable")
|
||||
|
||||
if session.new or session.dirty or session.deleted:
|
||||
_reject("session_not_clean")
|
||||
_read_existing(session, value)
|
||||
|
||||
client = DeploymentBrokerClient() if broker is None else broker
|
||||
if not _controller_is_verified_https(client):
|
||||
_reject("controller_https_unverified")
|
||||
try:
|
||||
preflight = client.workmesh_promotion_preflight(
|
||||
requested_revision,
|
||||
secret=value,
|
||||
)
|
||||
except Exception: # noqa: BLE001 - transport errors may contain the key.
|
||||
_reject("controller_preflight_unavailable")
|
||||
if not isinstance(preflight, dict):
|
||||
_reject("controller_preflight_rejected")
|
||||
try:
|
||||
safe = _safe_preflight(preflight, requested_revision)
|
||||
except Exception: # noqa: BLE001 - reject malformed or hostile response objects.
|
||||
safe = None
|
||||
if safe is None:
|
||||
_reject("controller_preflight_rejected")
|
||||
preflight_sha256 = safe["preflightSha256"]
|
||||
|
||||
inserted = _store_if_absent(
|
||||
session,
|
||||
value,
|
||||
revision=requested_revision,
|
||||
preflight_sha256=preflight_sha256,
|
||||
)
|
||||
outcome = "imported" if inserted else "already_present"
|
||||
try:
|
||||
audit = log_event(
|
||||
session,
|
||||
source="deployment",
|
||||
identity="operator",
|
||||
action_id=_ACTION,
|
||||
target=TARGET,
|
||||
risk="high",
|
||||
policy_decision="operator_import",
|
||||
reason="Imported the fixed WorkMesh controller credential after verified preflight.",
|
||||
result="success",
|
||||
execution_plan={
|
||||
"storeReference": SECRET_REF,
|
||||
"repository": TARGET,
|
||||
"revision": requested_revision,
|
||||
"preflightSha256": preflight_sha256,
|
||||
},
|
||||
after_state={
|
||||
"storeReference": SECRET_REF,
|
||||
"status": "configured",
|
||||
"repository": TARGET,
|
||||
"revision": requested_revision,
|
||||
"preflightSha256": preflight_sha256,
|
||||
"outcome": outcome,
|
||||
},
|
||||
redacted_metadata={
|
||||
"purpose": _PURPOSE,
|
||||
"storeReference": SECRET_REF,
|
||||
"repository": TARGET,
|
||||
"revision": requested_revision,
|
||||
"preflightSha256": preflight_sha256,
|
||||
"outcome": outcome,
|
||||
},
|
||||
)
|
||||
except Exception: # noqa: BLE001 - commit/audit failures must not echo details.
|
||||
_rollback_quietly(session)
|
||||
_reject("audit_commit_failed")
|
||||
audit_id = audit.id if isinstance(audit.id, str) else ""
|
||||
if not _AUDIT_ID.fullmatch(audit_id):
|
||||
_reject("audit_commit_failed")
|
||||
|
||||
try:
|
||||
readback = get_secret(session, SECRET_REF, touch=False)
|
||||
except Exception: # noqa: BLE001 - do not expose ciphertext/decryption details.
|
||||
_reject("secret_readback_failed")
|
||||
if readback is None or not hmac.compare_digest(readback, value):
|
||||
_reject("secret_readback_failed")
|
||||
return {
|
||||
"apiVersion": _API_VERSION,
|
||||
"status": outcome,
|
||||
"secretRef": SECRET_REF,
|
||||
"repository": TARGET,
|
||||
"revision": requested_revision,
|
||||
"preflightSha256": preflight_sha256,
|
||||
"auditId": audit_id,
|
||||
"readback": "verified",
|
||||
}
|
||||
|
||||
|
||||
def _write_result(stream: TextIO, value: dict[str, str]) -> None:
|
||||
stream.write(json.dumps(value, sort_keys=True, separators=(",", ":")) + "\n")
|
||||
stream.flush()
|
||||
|
||||
|
||||
def main(
|
||||
argv: list[str] | None = None,
|
||||
*,
|
||||
stdin=None,
|
||||
stdout: TextIO | None = None,
|
||||
) -> int:
|
||||
"""Import the single fixed reference from bounded stdin."""
|
||||
arguments = sys.argv[1:] if argv is None else argv
|
||||
output = sys.stdout if stdout is None else stdout
|
||||
if len(arguments) != 1 or not isinstance(arguments[0], str) or not _REVISION.fullmatch(arguments[0]):
|
||||
_write_result(output, {"status": "blocked", "reason": "invalid_arguments"})
|
||||
return 2
|
||||
source = getattr(sys.stdin, "buffer", sys.stdin) if stdin is None else stdin
|
||||
try:
|
||||
raw = source.read(_MAX_CREDENTIAL_BYTES + 1)
|
||||
if not isinstance(raw, bytes) or len(raw) > _MAX_CREDENTIAL_BYTES:
|
||||
_write_result(output, {"status": "blocked", "reason": "invalid_input"})
|
||||
return 2
|
||||
try:
|
||||
credential = raw.decode("ascii")
|
||||
except UnicodeDecodeError:
|
||||
_write_result(output, {"status": "blocked", "reason": "invalid_input"})
|
||||
return 2
|
||||
with Session(engine) as session:
|
||||
result = import_workmesh_deployment_secret(
|
||||
session,
|
||||
credential,
|
||||
revision=arguments[0],
|
||||
broker=DeploymentBrokerClient(),
|
||||
)
|
||||
_write_result(output, {key: str(value) for key, value in result.items()})
|
||||
return 0
|
||||
except WorkMeshSecretImportError as error:
|
||||
_write_result(output, {"status": "blocked", "reason": _safe_error_code(error.code)})
|
||||
return 2
|
||||
except Exception: # noqa: BLE001 - never print traceback or arbitrary values.
|
||||
_write_result(output, {"status": "blocked", "reason": "import_failed"})
|
||||
return 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user