fix(delivery): align readiness with local database authority
This commit is contained in:
@@ -420,6 +420,11 @@ its memory, process and privilege limits remain fixed. These operator budgets
|
||||
do not change student execution budgets. Startup opens admission only after all
|
||||
required readiness queries succeed.
|
||||
|
||||
Database authority queries use the fixed local TCP/Unix endpoints with TLS disabled
|
||||
and a five-second connection deadline. SQL remains read-only with a two-second
|
||||
statement limit. The identity operator needs EXECUTE on the audited authority
|
||||
function, with no direct account/session access or unlogged authority entrypoint.
|
||||
|
||||
Broker metadata uses one fixed read-only RPC with a five-second remote deadline
|
||||
and a 30-second CLI process deadline, within the helper's 45-second limit. It reads
|
||||
queue metadata, vhost limits, usernames/tags and permissions; it does not read
|
||||
|
||||
@@ -51,12 +51,24 @@ PRIVILEGES = {
|
||||
"accounts:SELECT": False,
|
||||
},
|
||||
"identity": {
|
||||
"accounts:SELECT": True,
|
||||
"accounts:is_administrator:UPDATE": True,
|
||||
"accounts:SELECT": False,
|
||||
"accounts:is_administrator:UPDATE": False,
|
||||
"accounts:password_hash:SELECT": False,
|
||||
"sessions:token_hash:SELECT": False,
|
||||
"evaluations:SELECT": False,
|
||||
"evaluations:state:UPDATE": False,
|
||||
},
|
||||
}
|
||||
AUTHORITY_FUNCTIONS = (
|
||||
"public.kf_manage_account_authority(text,text)",
|
||||
"public.kf_manage_account_authority_unlogged(text,text)",
|
||||
)
|
||||
|
||||
|
||||
def function_privileges(role: str) -> dict:
|
||||
return {
|
||||
name: role == "identity" and name == AUTHORITY_FUNCTIONS[0] for name in AUTHORITY_FUNCTIONS
|
||||
}
|
||||
|
||||
|
||||
def binding() -> tuple[dict, dict, Path]:
|
||||
@@ -260,6 +272,7 @@ def validate_role(role: str, observed: dict) -> None:
|
||||
"set_role": False,
|
||||
"connection_limit": 8,
|
||||
"privileges": PRIVILEGES[role],
|
||||
"functions": function_privileges(role),
|
||||
}
|
||||
if canonical(observed) != canonical(expected):
|
||||
raise DeliveryError("database role authority differs")
|
||||
@@ -272,7 +285,11 @@ async def roles(endpoints: dict) -> dict:
|
||||
for role, requirements in PRIVILEGES.items():
|
||||
connection = await asyncpg.connect(
|
||||
endpoints["database"][role],
|
||||
timeout=2,
|
||||
# Connections are restricted to numeric loopback or a private Unix
|
||||
# socket; PostgreSQL has TLS disabled. Avoid home-certificate lookup
|
||||
# inside ProtectHome and allow the bounded local SCRAM handshake.
|
||||
ssl=False,
|
||||
timeout=5,
|
||||
command_timeout=2,
|
||||
server_settings={
|
||||
"application_name": "kf-node-health",
|
||||
@@ -304,6 +321,12 @@ async def roles(endpoints: dict) -> dict:
|
||||
else "SELECT has_column_privilege(current_user,$1,$2,$3)",
|
||||
*parts,
|
||||
)
|
||||
observed["functions"] = {
|
||||
name: await connection.fetchval(
|
||||
"SELECT has_function_privilege(current_user,$1,'EXECUTE')", name
|
||||
)
|
||||
for name in AUTHORITY_FUNCTIONS
|
||||
}
|
||||
validate_role(role, observed)
|
||||
result[role] = {"authority_verified": True}
|
||||
finally:
|
||||
|
||||
Reference in New Issue
Block a user