44 lines
1.5 KiB
Python
44 lines
1.5 KiB
Python
"""Helpers for translating account names to Kubernetes namespace names."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import re
|
|
|
|
|
|
_DNS_LABEL = re.compile(r"^[a-z0-9](?:[-a-z0-9]*[a-z0-9])?$")
|
|
_INVALID_DNS_LABEL_CHARS = re.compile(r"[^a-z0-9-]+")
|
|
|
|
|
|
def is_valid_namespace_name(namespace_name: str) -> bool:
|
|
"""Return whether a name meets Kubernetes DNS-label constraints."""
|
|
return (
|
|
isinstance(namespace_name, str)
|
|
and len(namespace_name) <= 63
|
|
and bool(_DNS_LABEL.fullmatch(namespace_name))
|
|
)
|
|
|
|
|
|
def user_namespace(username: str) -> str:
|
|
"""Return a stable, DNS-label-safe namespace for a username.
|
|
|
|
Existing valid usernames retain their current namespace. Names that need
|
|
normalization receive a short digest so normalization cannot silently
|
|
merge accounts such as ``miki.dz08`` and ``miki-dz08``.
|
|
"""
|
|
normalized_username = str(username).strip().lower()
|
|
if not normalized_username:
|
|
raise ValueError("Username must not be empty")
|
|
|
|
candidate = f"user-{normalized_username}"
|
|
if is_valid_namespace_name(candidate):
|
|
return candidate
|
|
|
|
safe_username = _INVALID_DNS_LABEL_CHARS.sub("-", normalized_username)
|
|
safe_username = re.sub(r"-+", "-", safe_username).strip("-") or "user"
|
|
digest = hashlib.sha256(normalized_username.encode("utf-8")).hexdigest()[:8]
|
|
suffix = f"-{digest}"
|
|
max_base_length = 63 - len("user-") - len(suffix)
|
|
safe_username = safe_username[:max_base_length].rstrip("-") or "user"
|
|
return f"user-{safe_username}{suffix}"
|