fix(dashboard-testing): require run ACL principal and share VIEW predicate

This commit is contained in:
2026-09-24 09:34:51 +03:00
parent d8b0bd58ad
commit 233edfd135
2 changed files with 9 additions and 12 deletions

View File

@@ -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

View File

@@ -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