fix(dashboard-testing): require run ACL principal and share VIEW predicate
This commit is contained in:
@@ -120,11 +120,11 @@ def _run_to_dict(run: ScenarioRun) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def _get_run_or_404(db, run_id: str, current_user=None) -> ScenarioRun:
|
||||
def _get_run_or_404(db, run_id: str, current_user) -> ScenarioRun:
|
||||
# Object ACL is mandatory: `current_user` is a required argument so no future caller can
|
||||
# reintroduce the fail-open default. A foreign run is indistinguishable from a missing one.
|
||||
run = db.query(ScenarioRun).filter(ScenarioRun.id == run_id).first()
|
||||
# Object ACL: a foreign run is indistinguishable from a missing one. Callers that omit the
|
||||
# principal are internal seams that already proved authority.
|
||||
if run is None or (current_user is not None and not run_accessible(db, current_user, run)):
|
||||
if run is None or not run_accessible(db, current_user, run):
|
||||
raise HTTPException(status_code=404, detail={"code": "RUN_NOT_FOUND"})
|
||||
return run
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ from typing import Any, NoReturn
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from src.core.auth.permission_utils import user_has_permission
|
||||
from src.models.scenario_artifact import ScenarioArtifact
|
||||
from src.models.scenario_run import ScenarioRun
|
||||
from src.services.agent_runs.artifacts import get_draft_storage
|
||||
@@ -85,15 +86,11 @@ def _fail(status_code: int, code: str, message: str, *, retryable: bool = False)
|
||||
|
||||
|
||||
# #region ScenarioExecution.ArtifactContent.HasView [C:2] [TYPE Function] [SEMANTICS scenario,artifact,rbac]
|
||||
# @BRIEF Mirror has_permission("scenario:result", "VIEW") including the admin bypass.
|
||||
# @BRIEF scenario:result VIEW via the shared predicate (case/whitespace-insensitive, admin bypass).
|
||||
# @REJECTED Hand-rolling the role/permission loop here was rejected — an exact "VIEW" equality
|
||||
# diverges from has_permission when a permission row is lowercased or padded.
|
||||
def _has_result_view(user: object) -> bool:
|
||||
for role in getattr(user, "roles", None) or []:
|
||||
if getattr(role, "is_admin", False):
|
||||
return True
|
||||
for perm in getattr(role, "permissions", None) or []:
|
||||
if getattr(perm, "resource", None) == _VIEW_RESOURCE and getattr(perm, "action", None) == _VIEW_ACTION:
|
||||
return True
|
||||
return False
|
||||
return user_has_permission(user, _VIEW_RESOURCE, _VIEW_ACTION)
|
||||
# #endregion ScenarioExecution.ArtifactContent.HasView
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user