dmunozv04 opened a new issue, #45032:
URL: https://github.com/apache/superset/issues/45032

   *Please make sure you are familiar with the SIP process documented*
   [here](https://github.com/apache/superset/issues/5602). The SIP will be 
numbered by a committer upon acceptance.
   
   ## [SIP] Proposal for role import and export
   
   ### Motivation
   
   Superset instance administrators may need to move roles between instances, 
such as from development to staging or production. It can also be useful to 
export roles for documentation purposes.
   This has been mentioned before in [this GitHub 
discussion](https://github.com/apache/superset/discussions/27238) but it was 
never implemented.
   Flask-AppBuilder already supports this via CLI commands (using the 
`export-roles` and `import-roles` commands).
   
   ### Proposed Change
   
   This feature would add a new option in the Security -> List Roles page to 
allow administrator users without CLI access to import/export roles.
   
   
   #### Screenshots
   
   <img width="919" height="845" alt="Image" 
src="https://github.com/user-attachments/assets/6894bfa3-6c12-4b51-9640-037cf694e7df";
 />
   <img width="919" height="786" alt="Image" 
src="https://github.com/user-attachments/assets/9a593a17-81ed-4983-ac52-4e793e97ebfc";
 />
   <img width="919" height="845" alt="Image" 
src="https://github.com/user-attachments/assets/b3f53424-7121-4950-8302-3453f372cd73";
 />
   
   Superset has two different types of role permissions:
   
   - Application permissions, which can be identified by the fab permission and 
view_menu; such as `can_read` on `Dashboard`.
   - Data permissions, which refer to database or datasource (dataset) access. 
Their view_menu names are fragile since they can easily be changed, so ideally 
their uuids would be used.
   
   Since built-in roles are managed by Superset, they shouldn't be affected by 
this feature.
   
   This SIP proposes two API design options:
   
   #### Option 1: FAB-like JSON endpoints
   
   This option would reuse the role structure that Flask-AppBuilder supports 
via its CLI.
   Permissions are represented by a `(permission.name, view_menu.name)` pair.
   
   ```http
   GET /api/v1/security/roles/export/?q=<Rison-encoded-role-ids>
   ```
   
   The response would be a JSON array of the selected roles:
   
   ```json
   [
     {
       "name": "FinanceReader",
       "permissions": [
         {
           "permission": {
             "name": "can_read"
           },
           "view_menu": {
             "name": "Dashboard"
           }
         },
         {
           "permission": {
             "name": "database_access"
           },
           "view_menu": {
             "name": "[<database-name>].(id:<database-id>)"
           }
         },
         {
           "permission": {
             "name": "catalog_access"
           },
           "view_menu": {
             "name": "[<database-name>].[finance]"
           }
         },
         {
           "permission": {
             "name": "schema_access"
           },
           "view_menu": {
             "name": "[<database-name>].[finance].[reporting]"
           }
         },
         {
           "permission": {
             "name": "datasource_access"
           },
           "view_menu": {
             "name": "[<database-name>].[<dataset-name>](id:<dataset-id>)"
           }
         },
         {
           "permission": {
             "name": "datasource_access"
           },
           "view_menu": {
             "name": 
"[<semantic-layer-name>](id:<semantic-layer-uuid-without-hyphens>)"
           }
         },
         {
           "permission": {
             "name": "datasource_access"
           },
           "view_menu": {
             "name": 
"[<semantic-layer-name>].[<semantic-view-name>](id:<semantic-view-id>)"
           }
         }
       ]
     }
   ]
   ```
   
   The UI would turn this response into a JSON file download.
   Import would also accept the same JSON payload.
   
   ```http
   POST /api/v1/security/roles/import/
   Content-Type: application/json
   ```
   
   The main advantage of this format is its compatibility with FAB's CLI.
   The main drawback is the datasource names could change and break 
exports/imports.
   
   #### Option 2: YAML role definitions with UUID references
   
   This option would export each role as a YAML file. Exports would return a 
ZIP, just like the existing dataset exports.
   The format would look like this:
   
   ```text
   roles_export_<timestamp>.zip
   ├── metadata.yaml
   └── roles/
       ├── analytics_viewer.yaml
       └── finance_reader.yaml
   ```
   
   The `metadata.yaml` would have a similar structure as the existing exports:
   
   ```yaml
   version: 1.0.0
   type: Role
   timestamp: '<timestamp>'
   ```
   
   A role document could have this structure:
   
   Resource type can be a SQL dataset, a semantic layer or semantic view.
   Optional resource labels make the exported document human-readable, and are 
ignored by imports.
   
   ```yaml
   version: 1.0.0
   type: role
   role:
     name: FinanceReader
     permissions:
       # FAB permission: a permission and a view menu.
       - permission: can_read
         view_menu: Dashboard
   
       # Access to one database.
       - permission: database_access
         resource:
           type: database
           uuid: <database-uuid>
           label: Finance warehouse # Display only
   
       # Catalog and schema names are part of the permission identity.
       - permission: catalog_access
         resource:
           type: catalog
           database_uuid: <database-uuid>
           database_label: Finance warehouse # Display only
           name: finance
   
       - permission: schema_access
         resource:
           type: schema
           database_uuid: <database-uuid>
           database_label: Finance warehouse # Display only
           catalog: finance
           name: reporting
   
       # datasource_access can target different objects.
       - permission: datasource_access
         resource:
           type: dataset
           uuid: <dataset-uuid>
           label: Monthly revenue # Display only
           database_label: Finance warehouse # Display only;
   
       - permission: datasource_access
         resource:
           type: semantic_layer
           uuid: <semantic-layer-uuid>
           label: Finance metrics # Display only
   
       - permission: datasource_access
         resource:
           type: semantic_view
           uuid: <semantic-view-uuid>
           label: Revenue by month # Display only
   ```
   
   On import, Superset would resolve the UUID to the destination object, or 
fail if the object doesn't exist. This is the main advantage of this option, 
being resistant to changes such as renaming.
   
   The import endpoint would accept a ZIP archive, expecting the format 
explained above.
   
   ```http
   GET /api/v1/security/roles/export/?q=<Rison-encoded-role-ids>
   Accept: application/zip
   
   POST /api/v1/security/roles/import/
   Content-Type: application/zip
   ```
   
   Another advantage of this format is that it supports versioning, if needed 
in the future.
   Option 2 seems like the better choice, but I wanted to leave the choice in 
case maintainers felt the other option was better.
   A reference PR is also provided Implementing option 1, used to create the 
screenshots above: #45031
   
   #### Import conflict handling
   
   Regardless of the option selected, the proposal shoud decide how conflicts 
could be handled.
   An additive import option would create missing roles and also add 
permissions to
   existing roles, while retaining permissions that aren't in the import.
   An overwrite option, with a warning similar to the one used for dataset 
imports,
   would be authoritative and remove permissions absent from the import.
   
   ### New or Changed Public Interfaces
   
   #### REST API
   
   Both options add administrator protected endpoints for exporting and 
importing role definitions.
   
   The API interface would be different depending on the option selected, but 
the endpoints would be the same:
   
   | Method | Path | Description |
   |--------|------|-------------|
   | `GET` | `/api/v1/security/roles/export/?q=<Rison-encoded-role-ids>` | 
Export selected roles to JSON/ZIP archive |
   | `POST` | `/api/v1/security/roles/import/` | Import roles from JSON/ZIP 
archive |
   
   #### UI
   
   New buttons would also be added in the List Roles interface to export a 
single role, export multiple selected roles and import roles.
   
   ### New dependencies
   
   No new dependencies are expected.
   
   ### Migration Plan and Compatibility
   
   No database migrations are expected.
   No existing features are expected to change.
   
   ### Rejected Alternatives
   
   - Using the existing `superset fab export-roles` and `superset fab 
import-roles` CLI commands, since they're only accessible for administrators 
with console access.
   - Wiring the FAB export/import logic to the API endpoints, since the FAB 
functions accept file paths and would complicate request handling.
   


-- 
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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to