You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@superset.apache.org by "alexandrusoare (via GitHub)" <gi...@apache.org> on 2026/06/03 11:32:08 UTC

[PR] feat(security): Add config-based extension hooks for permission overr… [superset]

alexandrusoare opened a new pull request, #40707:
URL: https://github.com/apache/superset/pull/40707

   ### SUMMARY
   Adds config-based extension hooks to Superset's permission system, following the existing `EXTRA_DYNAMIC_QUERY_FILTERS` pattern. These hooks allow deployments to inject custom permission logic without modifying core files.
   
   All hooks are no-ops by default — zero behavioral change without explicit configuration.
   
   **Hooks added:**
   
   | Config key | Location | Purpose |
   | --- | --- | --- |
   | `EXTRA_ACCESS_QUERY_FILTERS["charts"]` | `ChartFilter.apply()` | Inject additional OR conditions for chart visibility |
   | `EXTRA_ACCESS_QUERY_FILTERS["dashboards"]` | `DashboardAccessFilter.apply()` | Inject additional OR conditions for dashboard visibility |
   | `EXTRA_RAISE_FOR_ACCESS_BYPASS` | `raise_for_access()` | Bypass permission checks (including datasource) for externally authorized users |
   | `EXTRA_OWNERSHIP_CHECKS` | `raise_for_ownership()` | Allow edit/delete for users authorized by external systems |
   | `EXTRA_OWNER_AUTO_ADD_SKIP` | `populate_owner_list()` | Prevent auto-adding users as owners when they have external edit access |
   | `EXTRA_CAN_EDIT_RESOLVER` | Chart/Dashboard/Explore GET responses | Add `can_edit` field based on external permission systems |
   
   ### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
   <!--- Skip this if not applicable -->
   
   ### TESTING INSTRUCTIONS
   <!--- Required! What steps can be taken to manually verify the changes? -->
   
   ### ADDITIONAL INFORMATION
   <!--- Check any relevant boxes with "x" -->
   <!--- HINT: Include "Fixes #nnn" if you are fixing an existing issue -->
   - [ ] Has associated issue:
   - [ ] Required feature flags:
   - [ ] Changes UI
   - [ ] Includes DB Migration (follow approval process in [SIP-59](https://github.com/apache/superset/issues/13351))
     - [ ] Migration is atomic, supports rollback & is backwards-compatible
     - [ ] Confirm DB migration upgrade and downgrade tested
     - [ ] Runtime estimates and downtime expectations provided
   - [ ] Introduces new feature or API
   - [ ] Removes existing feature or API
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat(security): Add extension hooks for custom access control, ownership, and asset lifecycle [superset]

Posted by "msyavuz (via GitHub)" <gi...@apache.org>.
msyavuz commented on code in PR #40707:
URL: https://github.com/apache/superset/pull/40707#discussion_r3420499244


##########
superset/security/manager.py:
##########
@@ -4147,6 +4165,13 @@ def raise_for_ownership(self, resource: Model) -> None:
         owners = orig_resource.owners if hasattr(orig_resource, "owners") else []
 
         if g.user.is_anonymous or g.user not in owners:
+            # Extension hook: check if the user is an extra owner
+            resolver = current_app.config.get("EXTRA_OWNERS_RESOLVER")
+            if resolver and not g.user.is_anonymous:
+                extra_owners = resolver(orig_resource)
+                if any(u.id == g.user.id for u in extra_owners):

Review Comment:
   Won't this raise AttributeError if the resolver returns dicts?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat(security): Add config-based extension hooks for permission overr… [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #40707:
URL: https://github.com/apache/superset/pull/40707#issuecomment-4611866658

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat(security): Add extension hooks for custom access control, ownership, and asset lifecycle [superset]

Posted by "msyavuz (via GitHub)" <gi...@apache.org>.
msyavuz commented on code in PR #40707:
URL: https://github.com/apache/superset/pull/40707#discussion_r3420449267


##########
tests/unit_tests/security/test_permission_hooks.py:
##########
@@ -0,0 +1,202 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""Tests for config-based permission extension hooks.
+
+Follows the same pattern as EXTRA_DYNAMIC_QUERY_FILTERS tests in
+tests/unit_tests/databases/api_test.py.
+"""
+
+from unittest.mock import Mock
+
+import pytest
+
+from superset import db
+
+
+@pytest.fixture
+def sample_chart(app_context: None):
+    """Create a minimal chart for testing."""
+    from superset.models.slice import Slice
+
+    chart = Slice(
+        slice_name="test_permission_hooks_chart",
+        datasource_type="table",
+        viz_type="table",
+        params="{}",
+    )
+    db.session.add(chart)
+    db.session.flush()
+    yield chart
+    db.session.delete(chart)
+    db.session.flush()
+
+
+@pytest.fixture
+def sample_user(app_context: None):
+    """Create a minimal user for testing."""
+    from flask_appbuilder.security.sqla.models import User
+
+    user = User(
+        first_name="test",
+        last_name="hooks",
+        username="test_permission_hooks_user",
+        email="test_hooks@example.com",
+    )
+    db.session.add(user)
+    db.session.flush()
+    yield user
+    db.session.delete(user)
+    db.session.flush()
+
+
+def test_extra_owners_resolver_injects_into_extra_owners(sample_chart, monkeypatch):
+    """EXTRA_OWNERS_RESOLVER populates Slice.data['extra_owners'], not 'owners'."""
+    from flask import current_app
+
+    original_owner_ids = [o.id for o in sample_chart.owners]
+
+    # Without config — extra_owners is empty, owners unchanged
+    monkeypatch.setitem(current_app.config, "EXTRA_OWNERS_RESOLVER", None)
+    data = sample_chart.data
+    assert data["owners"] == original_owner_ids
+    assert data["extra_owners"] == []
+
+    # With config — extra_owners populated, owners unchanged
+    def _resolver(resource):
+        return [{"id": 99999, "first_name": "Folder", "last_name": "Editor"}]
+
+    resolver_mock = Mock(side_effect=_resolver)
+    monkeypatch.setitem(current_app.config, "EXTRA_OWNERS_RESOLVER", resolver_mock)
+
+    data = sample_chart.data
+    assert data["owners"] == original_owner_ids
+    assert 99999 in data["extra_owners"]
+    assert resolver_mock.call_count == 1
+
+
+def test_extra_owners_resolver_empty_returns_unchanged(sample_chart, monkeypatch):
+    """EXTRA_OWNERS_RESOLVER returning empty list leaves extra_owners empty."""
+    from flask import current_app
+
+    resolver_mock = Mock(return_value=[])
+    monkeypatch.setitem(current_app.config, "EXTRA_OWNERS_RESOLVER", resolver_mock)
+
+    data = sample_chart.data
+    original_owner_ids = [o.id for o in sample_chart.owners]
+    assert data["owners"] == original_owner_ids
+    assert data["extra_owners"] == []
+    assert resolver_mock.call_count == 1
+
+
+def test_raise_for_access_bypass_skips_checks(app_context: None, monkeypatch):
+    """EXTRA_RAISE_FOR_ACCESS_BYPASS returning True skips all permission checks."""
+    from flask import current_app
+
+    from superset import security_manager
+
+    bypass_mock = Mock(return_value=True)
+    monkeypatch.setitem(
+        current_app.config, "EXTRA_RAISE_FOR_ACCESS_BYPASS", bypass_mock
+    )
+
+    security_manager.raise_for_access(dashboard=None, chart=None)
+    assert bypass_mock.call_count == 1
+
+
+def test_raise_for_access_no_bypass_without_config(app_context: None, monkeypatch):
+    """Without EXTRA_RAISE_FOR_ACCESS_BYPASS, normal checks proceed."""
+    from flask import current_app
+
+    from superset import security_manager
+
+    monkeypatch.setitem(current_app.config, "EXTRA_RAISE_FOR_ACCESS_BYPASS", None)
+    security_manager.raise_for_access(dashboard=None, chart=None)
+
+
+def test_ownership_check_allows_non_owner(sample_chart, sample_user, monkeypatch):
+    """EXTRA_OWNERSHIP_CHECKS returning True allows a non-owner to pass."""
+    from flask import current_app, g
+
+    from superset import security_manager
+
+    check_mock = Mock(return_value=True)
+    monkeypatch.setitem(current_app.config, "EXTRA_OWNERSHIP_CHECKS", check_mock)

Review Comment:
   This is not checked by raise_for_ownership



##########
tests/unit_tests/security/test_permission_hooks.py:
##########
@@ -0,0 +1,202 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""Tests for config-based permission extension hooks.
+
+Follows the same pattern as EXTRA_DYNAMIC_QUERY_FILTERS tests in
+tests/unit_tests/databases/api_test.py.
+"""
+
+from unittest.mock import Mock
+
+import pytest
+
+from superset import db
+
+
+@pytest.fixture
+def sample_chart(app_context: None):
+    """Create a minimal chart for testing."""
+    from superset.models.slice import Slice
+
+    chart = Slice(
+        slice_name="test_permission_hooks_chart",
+        datasource_type="table",
+        viz_type="table",
+        params="{}",
+    )
+    db.session.add(chart)
+    db.session.flush()
+    yield chart
+    db.session.delete(chart)
+    db.session.flush()
+
+
+@pytest.fixture
+def sample_user(app_context: None):
+    """Create a minimal user for testing."""
+    from flask_appbuilder.security.sqla.models import User
+
+    user = User(
+        first_name="test",
+        last_name="hooks",
+        username="test_permission_hooks_user",
+        email="test_hooks@example.com",
+    )
+    db.session.add(user)
+    db.session.flush()
+    yield user
+    db.session.delete(user)
+    db.session.flush()
+
+
+def test_extra_owners_resolver_injects_into_extra_owners(sample_chart, monkeypatch):
+    """EXTRA_OWNERS_RESOLVER populates Slice.data['extra_owners'], not 'owners'."""
+    from flask import current_app
+
+    original_owner_ids = [o.id for o in sample_chart.owners]
+
+    # Without config — extra_owners is empty, owners unchanged
+    monkeypatch.setitem(current_app.config, "EXTRA_OWNERS_RESOLVER", None)
+    data = sample_chart.data
+    assert data["owners"] == original_owner_ids
+    assert data["extra_owners"] == []
+
+    # With config — extra_owners populated, owners unchanged
+    def _resolver(resource):
+        return [{"id": 99999, "first_name": "Folder", "last_name": "Editor"}]
+
+    resolver_mock = Mock(side_effect=_resolver)
+    monkeypatch.setitem(current_app.config, "EXTRA_OWNERS_RESOLVER", resolver_mock)
+
+    data = sample_chart.data
+    assert data["owners"] == original_owner_ids
+    assert 99999 in data["extra_owners"]
+    assert resolver_mock.call_count == 1
+
+
+def test_extra_owners_resolver_empty_returns_unchanged(sample_chart, monkeypatch):
+    """EXTRA_OWNERS_RESOLVER returning empty list leaves extra_owners empty."""
+    from flask import current_app
+
+    resolver_mock = Mock(return_value=[])
+    monkeypatch.setitem(current_app.config, "EXTRA_OWNERS_RESOLVER", resolver_mock)
+
+    data = sample_chart.data
+    original_owner_ids = [o.id for o in sample_chart.owners]
+    assert data["owners"] == original_owner_ids
+    assert data["extra_owners"] == []
+    assert resolver_mock.call_count == 1
+
+
+def test_raise_for_access_bypass_skips_checks(app_context: None, monkeypatch):
+    """EXTRA_RAISE_FOR_ACCESS_BYPASS returning True skips all permission checks."""
+    from flask import current_app
+
+    from superset import security_manager
+
+    bypass_mock = Mock(return_value=True)
+    monkeypatch.setitem(
+        current_app.config, "EXTRA_RAISE_FOR_ACCESS_BYPASS", bypass_mock
+    )
+
+    security_manager.raise_for_access(dashboard=None, chart=None)
+    assert bypass_mock.call_count == 1
+
+
+def test_raise_for_access_no_bypass_without_config(app_context: None, monkeypatch):
+    """Without EXTRA_RAISE_FOR_ACCESS_BYPASS, normal checks proceed."""
+    from flask import current_app
+
+    from superset import security_manager
+
+    monkeypatch.setitem(current_app.config, "EXTRA_RAISE_FOR_ACCESS_BYPASS", None)
+    security_manager.raise_for_access(dashboard=None, chart=None)
+
+
+def test_ownership_check_allows_non_owner(sample_chart, sample_user, monkeypatch):
+    """EXTRA_OWNERSHIP_CHECKS returning True allows a non-owner to pass."""
+    from flask import current_app, g
+
+    from superset import security_manager
+
+    check_mock = Mock(return_value=True)
+    monkeypatch.setitem(current_app.config, "EXTRA_OWNERSHIP_CHECKS", check_mock)
+    monkeypatch.setattr(g, "user", sample_user, raising=False)
+
+    security_manager.raise_for_ownership(sample_chart)
+    check_mock.assert_called_once()
+
+
+def test_owner_auto_add_skip_prevents_auto_add(
+    sample_user, app_context: None, monkeypatch
+):
+    """EXTRA_OWNER_AUTO_ADD_SKIP returning True prevents auto-adding current user."""
+    from flask import current_app, g
+    from flask_appbuilder.security.sqla.models import User
+
+    from superset.commands.utils import populate_owner_list
+
+    other_user = User(
+        first_name="other",
+        last_name="skip",
+        username="test_skip_other",
+        email="skip_other@example.com",
+    )
+    db.session.add(other_user)
+    db.session.flush()
+
+    skip_mock = Mock(return_value=True)
+    monkeypatch.setitem(current_app.config, "EXTRA_OWNER_AUTO_ADD_SKIP", skip_mock)

Review Comment:
   Same here



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat(security): Add config-based extension hooks for permission overr… [superset]

Posted by "codecov[bot] (via GitHub)" <gi...@apache.org>.
codecov[bot] commented on PR #40707:
URL: https://github.com/apache/superset/pull/40707#issuecomment-4611949390

   ## [Codecov](https://app.codecov.io/gh/apache/superset/pull/40707?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) Report
   :x: Patch coverage is `20.96774%` with `49 lines` in your changes missing coverage. Please review.
   :white_check_mark: Project coverage is 55.44%. Comparing base ([`b9dc9d7`](https://app.codecov.io/gh/apache/superset/commit/b9dc9d722e62d2417076272e29c08280ac6c51d2?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)) to head ([`8c818be`](https://app.codecov.io/gh/apache/superset/commit/8c818beedbe4dc10eaa9a6622df3069ec402b3a7?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)).
   
   | [Files with missing lines](https://app.codecov.io/gh/apache/superset/pull/40707?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | Patch % | Lines |
   |---|---|---|
   | [superset/charts/filters.py](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&filepath=superset%2Fcharts%2Ffilters.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3VwZXJzZXQvY2hhcnRzL2ZpbHRlcnMucHk=) | 0.00% | [9 Missing :warning: ](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) |
   | [superset/charts/api.py](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&filepath=superset%2Fcharts%2Fapi.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3VwZXJzZXQvY2hhcnRzL2FwaS5weQ==) | 22.22% | [7 Missing :warning: ](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) |
   | [superset/commands/explore/get.py](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&filepath=superset%2Fcommands%2Fexplore%2Fget.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3VwZXJzZXQvY29tbWFuZHMvZXhwbG9yZS9nZXQucHk=) | 0.00% | [7 Missing :warning: ](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) |
   | [superset/dashboards/api.py](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&filepath=superset%2Fdashboards%2Fapi.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3VwZXJzZXQvZGFzaGJvYXJkcy9hcGkucHk=) | 12.50% | [7 Missing :warning: ](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) |
   | [superset/dashboards/filters.py](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&filepath=superset%2Fdashboards%2Ffilters.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3VwZXJzZXQvZGFzaGJvYXJkcy9maWx0ZXJzLnB5) | 0.00% | [7 Missing :warning: ](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) |
   | [superset/security/manager.py](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&filepath=superset%2Fsecurity%2Fmanager.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3VwZXJzZXQvc2VjdXJpdHkvbWFuYWdlci5weQ==) | 12.50% | [6 Missing and 1 partial :warning: ](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) |
   | [superset/commands/utils.py](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&filepath=superset%2Fcommands%2Futils.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3VwZXJzZXQvY29tbWFuZHMvdXRpbHMucHk=) | 16.66% | [5 Missing :warning: ](https://app.codecov.io/gh/apache/superset/pull/40707?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) |
   > :exclamation:  There is a different number of reports uploaded between BASE (b9dc9d7) and HEAD (8c818be). Click for more details.
   > 
   > <details><summary>HEAD has 80 uploads less than BASE</summary>
   >
   >| Flag | BASE (b9dc9d7) | HEAD (8c818be) |
   >|------|------|------|
   >|python|70|2|
   >|presto|7|1|
   >|hive|7|1|
   ></details>
   
   <details><summary>Additional details and impacted files</summary>
   
   
   
   ```diff
   @@            Coverage Diff             @@
   ##           master   #40707      +/-   ##
   ==========================================
   - Coverage   64.08%   55.44%   -8.65%     
   ==========================================
     Files        2663     2663              
     Lines      143289   143344      +55     
     Branches    32952    32970      +18     
   ==========================================
   - Hits        91832    79481   -12351     
   - Misses      49871    63153   +13282     
   + Partials     1586      710     -876     
   ```
   
   | [Flag](https://app.codecov.io/gh/apache/superset/pull/40707/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | Coverage Δ | |
   |---|---|---|
   | [hive](https://app.codecov.io/gh/apache/superset/pull/40707/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `39.78% <20.96%> (-0.02%)` | :arrow_down: |
   | [mysql](https://app.codecov.io/gh/apache/superset/pull/40707/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `?` | |
   | [postgres](https://app.codecov.io/gh/apache/superset/pull/40707/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `?` | |
   | [presto](https://app.codecov.io/gh/apache/superset/pull/40707/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `41.37% <20.96%> (-0.02%)` | :arrow_down: |
   | [python](https://app.codecov.io/gh/apache/superset/pull/40707/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `41.43% <20.96%> (-18.60%)` | :arrow_down: |
   | [sqlite](https://app.codecov.io/gh/apache/superset/pull/40707/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `?` | |
   | [unit](https://app.codecov.io/gh/apache/superset/pull/40707/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `?` | |
   
   Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#carryforward-flags-in-the-pull-request-comment) to find out more.
   </details>
   
   [:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/apache/superset/pull/40707?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).   
   :loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).
   <details><summary> :rocket: New features to boost your workflow: </summary>
   
   - :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
   - :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
   </details>


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat(security): Add config-based extension hooks for permission overr… [superset]

Posted by "netlify[bot] (via GitHub)" <gi...@apache.org>.
netlify[bot] commented on PR #40707:
URL: https://github.com/apache/superset/pull/40707#issuecomment-4612303238

   ### <span aria-hidden="true">✅</span> Deploy Preview for *superset-docs-preview* ready!
   
   
   |  Name | Link |
   |:-:|------------------------|
   |<span aria-hidden="true">🔨</span> Latest commit | 71802107ffecd0e07795f61dfa79ea80f2f2e012 |
   |<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/projects/superset-docs-preview/deploys/6a201dae36aa7d00087ceb30 |
   |<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-40707--superset-docs-preview.netlify.app](https://deploy-preview-40707--superset-docs-preview.netlify.app) |
   |<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTQwNzA3LS1zdXBlcnNldC1kb2NzLXByZXZpZXcubmV0bGlmeS5hcHAifQ.FeZm9Mp4u21uBP1FOiTCi7A3Aik78eSgq07EiDK8RxU)<br /><br />_Use your smartphone camera to open QR code link._</details> |
   |<span aria-hidden="true">🤖</span> Make changes | [Run an agent on this branch](https://app.netlify.com/projects/superset-docs-preview/agent-runs#HctBCoNADAXQu2TdYlpBizfwGNF8UdTJkJmCIt69Q3dv8y6KbnvM1BE9aHAJ41wsGw4J6t9k4qgmSK4ifF9SWiw8cWSEv2azNZWpiJudvZbbyJtfKqgbkVaZ-dOOGGqm-wc) |
   ---
   <!-- [superset-docs-preview Preview](https://deploy-preview-40707--superset-docs-preview.netlify.app) -->
   _To edit notification comments on pull requests, go to your [Netlify project configuration](https://app.netlify.com/projects/superset-docs-preview/configuration/notifications#deploy-notifications)._


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat(security): Add extension hooks for custom access control, ownership, and asset lifecycle [superset]

Posted by "alexandrusoare (via GitHub)" <gi...@apache.org>.
alexandrusoare merged PR #40707:
URL: https://github.com/apache/superset/pull/40707


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat(security): Add extension hooks for custom access control, ownership, and asset lifecycle [superset]

Posted by "alexandrusoare (via GitHub)" <gi...@apache.org>.
alexandrusoare commented on code in PR #40707:
URL: https://github.com/apache/superset/pull/40707#discussion_r3420519270


##########
superset/security/manager.py:
##########
@@ -4147,6 +4165,13 @@ def raise_for_ownership(self, resource: Model) -> None:
         owners = orig_resource.owners if hasattr(orig_resource, "owners") else []
 
         if g.user.is_anonymous or g.user not in owners:
+            # Extension hook: check if the user is an extra owner
+            resolver = current_app.config.get("EXTRA_OWNERS_RESOLVER")
+            if resolver and not g.user.is_anonymous:
+                extra_owners = resolver(orig_resource)
+                if any(u.id == g.user.id for u in extra_owners):

Review Comment:
   Great catch, improved the check



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat(security): Add extension hooks for custom access control, ownership, and asset lifecycle [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #40707:
URL: https://github.com/apache/superset/pull/40707#issuecomment-4719851444

   **Bito Automatic Review Skipped – PR Already Merged**<br/><br/>Bito scheduled an automatic review for this pull request, but the review was skipped because this PR was merged before the review could be run.<br/>No action is needed if you didn't intend to review it. To get a review, you can type `/review` in a comment and save it


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org