Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions superset/commands/tag/delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@
from functools import partial
from typing import Any

from jinja2.exceptions import TemplateError
from marshmallow import ValidationError

from superset import security_manager
from superset.commands.base import BaseCommand
from superset.commands.exceptions import TagNotFoundValidationError
from superset.commands.tag.exceptions import (
TagAccessValidationError,
TagDeleteFailedError,
TagDeleteForbiddenValidationError,
TaggedObjectDeleteFailedError,
Expand All @@ -32,7 +34,7 @@
)
from superset.commands.tag.utils import to_object_model, to_object_type
from superset.daos.tag import TagDAO
from superset.exceptions import SupersetSecurityException
from superset.exceptions import SupersetParseError, SupersetSecurityException
from superset.tags.models import ObjectType, TagType
from superset.utils.decorators import on_error, transaction
from superset.views.base import DeleteMixin
Expand Down Expand Up @@ -110,7 +112,29 @@ def _validate_object_access(
elif object_type == ObjectType.chart:
security_manager.raise_for_access(chart=target_object)
elif object_type == ObjectType.query:
security_manager.raise_for_access(query=target_object)
# Authorizing a query without blanket database access parses
# its Jinja-templated SQL. Malformed Jinja (``TemplateError``)
# or a partition macro that references a table which cannot be
# resolved statically (``SupersetParseError``) is a validation
# failure, not an opaque 500. Append a ``ValidationError`` so it
# composites cleanly into ``TagInvalidError`` (the delete route
# calls ``normalized_messages()`` on it).
try:
security_manager.raise_for_access(query=target_object)
except (TemplateError, SupersetParseError) as ex:
logger.warning(
"Failed to render Jinja SQL while validating access "
"for %s %s: %s",
object_type,
object_id,
ex,
)
exceptions.append(
TagAccessValidationError(
f"Access validation failed for {object_type} "
f"{object_id}: {ex}"
)
)
elif object_type == ObjectType.dataset:
security_manager.raise_for_access(datasource=target_object)
else:
Expand Down
12 changes: 12 additions & 0 deletions superset/commands/tag/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ def __init__(self, message: str) -> None:
super().__init__(message, field_name="tags")


class TagAccessValidationError(ValidationError):
"""The access check for a tagged object could not be completed -- e.g. a
saved query whose Jinja-templated SQL is malformed (``TemplateError``) or
references a table that cannot be resolved statically (``SupersetParseError``).
A ``ValidationError`` so it composites into ``TagInvalidError`` and supports
``CommandInvalidError.normalized_messages()`` rather than crashing it.
"""

def __init__(self, message: str) -> None:
super().__init__(message, field_name="tags")


class TaggedObjectDeleteFailedError(DeleteFailedError):
message = _("Tagged Object could not be deleted.")

Expand Down
Loading
Loading