mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-18 15:33:02 +00:00
Merge pull request #3476 from IvanaH8/rbac-scope-table-makefile
[rbac] Generate scope table for docs
This commit is contained in:
@@ -66,7 +66,12 @@ metrics: source/reference/metrics.rst
|
|||||||
source/reference/metrics.rst: generate-metrics.py
|
source/reference/metrics.rst: generate-metrics.py
|
||||||
python3 generate-metrics.py
|
python3 generate-metrics.py
|
||||||
|
|
||||||
html: rest-api metrics
|
scopes: source/rbac/scope-table.md
|
||||||
|
|
||||||
|
source/rbac/scope-table.md: source/rbac/generate-scope-table.py
|
||||||
|
python3 source/rbac/generate-scope-table.py
|
||||||
|
|
||||||
|
html: rest-api metrics scopes
|
||||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||||
|
@@ -212,7 +212,7 @@ if on_rtd:
|
|||||||
# build both metrics and rest-api, since RTD doesn't run make
|
# build both metrics and rest-api, since RTD doesn't run make
|
||||||
from subprocess import check_call as sh
|
from subprocess import check_call as sh
|
||||||
|
|
||||||
sh(['make', 'metrics', 'rest-api'], cwd=docs)
|
sh(['make', 'metrics', 'rest-api', 'scopes'], cwd=docs)
|
||||||
|
|
||||||
# -- Spell checking -------------------------------------------------------
|
# -- Spell checking -------------------------------------------------------
|
||||||
|
|
||||||
|
99
docs/source/rbac/generate-scope-table.py
Normal file
99
docs/source/rbac/generate-scope-table.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import os
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from pytablewriter import MarkdownTableWriter
|
||||||
|
|
||||||
|
from jupyterhub.scopes import scope_definitions
|
||||||
|
|
||||||
|
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
class ScopeTableGenerator:
|
||||||
|
def __init__(self):
|
||||||
|
self.scopes = scope_definitions
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_writer(cls, table_name, headers, values):
|
||||||
|
writer = MarkdownTableWriter()
|
||||||
|
writer.table_name = table_name
|
||||||
|
writer.headers = headers
|
||||||
|
writer.value_matrix = values
|
||||||
|
writer.margin = 1
|
||||||
|
return writer
|
||||||
|
|
||||||
|
def _get_scope_relationships(self):
|
||||||
|
"""Returns a tuple of dictionary of all scope-subscope pairs and a list of just subscopes:
|
||||||
|
|
||||||
|
({scope: subscope}, [subscopes])
|
||||||
|
|
||||||
|
used for creating hierarchical scope table in _parse_scopes()
|
||||||
|
"""
|
||||||
|
pairs = []
|
||||||
|
for scope in self.scopes.keys():
|
||||||
|
if self.scopes[scope].get('subscopes'):
|
||||||
|
for subscope in self.scopes[scope]['subscopes']:
|
||||||
|
pairs.append((scope, subscope))
|
||||||
|
else:
|
||||||
|
pairs.append((scope, None))
|
||||||
|
subscopes = [pair[1] for pair in pairs]
|
||||||
|
pairs_dict = defaultdict(list)
|
||||||
|
for scope, subscope in pairs:
|
||||||
|
pairs_dict[scope].append(subscope)
|
||||||
|
return pairs_dict, subscopes
|
||||||
|
|
||||||
|
def _get_top_scopes(self, subscopes):
|
||||||
|
"""Returns a list of highest level scopes
|
||||||
|
(not a subscope of any other scopes)"""
|
||||||
|
top_scopes = []
|
||||||
|
for scope in self.scopes.keys():
|
||||||
|
if scope not in subscopes:
|
||||||
|
top_scopes.append(scope)
|
||||||
|
return top_scopes
|
||||||
|
|
||||||
|
def _parse_scopes(self):
|
||||||
|
"""Returns a list of table rows where row:
|
||||||
|
[indented scopename string, scope description string]"""
|
||||||
|
scope_pairs, subscopes = self._get_scope_relationships()
|
||||||
|
top_scopes = self._get_top_scopes(subscopes)
|
||||||
|
|
||||||
|
table_rows = []
|
||||||
|
md_indent = " "
|
||||||
|
|
||||||
|
def _add_subscopes(table_rows, scopename, depth=0):
|
||||||
|
description = self.scopes[scopename]['description']
|
||||||
|
table_row = [f"{md_indent*depth}`{scopename}`", description]
|
||||||
|
table_rows.append(table_row)
|
||||||
|
for subscope in scope_pairs[scopename]:
|
||||||
|
if subscope:
|
||||||
|
_add_subscopes(table_rows, subscope, depth + 1)
|
||||||
|
|
||||||
|
for scope in top_scopes:
|
||||||
|
_add_subscopes(table_rows, scope)
|
||||||
|
|
||||||
|
return table_rows
|
||||||
|
|
||||||
|
def write_table(self):
|
||||||
|
"""Generates the scope table in markdown format and writes it into scope-table.md file"""
|
||||||
|
filename = f"{HERE}/scope-table.md"
|
||||||
|
table_name = ""
|
||||||
|
headers = ["Scope", "Description"]
|
||||||
|
values = self._parse_scopes()
|
||||||
|
writer = self.create_writer(table_name, headers, values)
|
||||||
|
|
||||||
|
title = "Table 1. Available scopes and their hierarchy"
|
||||||
|
content = f"{title}\n{writer.dumps()}"
|
||||||
|
with open(filename, 'w') as f:
|
||||||
|
f.write(content)
|
||||||
|
print(f"Generated {filename}.")
|
||||||
|
print(
|
||||||
|
"Run 'make clean' before 'make html' to ensure the built scopes.html contains latest scope table changes."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
table_generator = ScopeTableGenerator()
|
||||||
|
table_generator.write_table()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@@ -81,37 +81,10 @@ The payload of an API call can be filtered both horizontally and vertically simu
|
|||||||
## Available scopes
|
## Available scopes
|
||||||
|
|
||||||
Table below lists all available scopes and illustrates their hierarchy. Indented scopes indicate subscopes of the scope(s) above them.
|
Table below lists all available scopes and illustrates their hierarchy. Indented scopes indicate subscopes of the scope(s) above them.
|
||||||
% TODO: Automatically generate this table from code when creating docs
|
|
||||||
Table 1. Available scopes and their hierarchy
|
```{include} scope-table.md
|
||||||
| Scope name | Description |
|
|
||||||
| :--------- | :---------- |
|
```
|
||||||
| (no scope) | Allows for only identifying the owning entity. |
|
|
||||||
| `self` | Metascope, grants access to user's own resources; resolves to (no scope) for services. |
|
|
||||||
| `all` | Metascope, valid for tokens only. Grants access to everything that the token's owning entity can do. |
|
|
||||||
| `admin:users` | Grants read, write, create and delete access to users and their authentication state _but not their servers or tokens._ |
|
|
||||||
| `admin:users:auth_state` | Grants access to users' authentication state only. |
|
|
||||||
| `users` | Grants read and write permissions to users' models _apart from servers, tokens and authentication state_. |
|
|
||||||
| `users:activity` | Grants access to read and post users' activity only. |
|
|
||||||
| `read:users` | Read-only access to users' models _apart from servers, tokens and authentication state_. |
|
|
||||||
| `read:users:name` | Read-only access to users' names. |
|
|
||||||
| `read:users:roles` | Read-only access to a list of users' roles names. |
|
|
||||||
| `read:users:groups` | Read-only access to a list of users' group names. |
|
|
||||||
| `read:users:activity` | Read-only access to users' activity. |
|
|
||||||
| `admin:users:servers` | Grants read, start/stop, create and delete permissions to users' servers and their state. |
|
|
||||||
| `admin:users:server_state` | Grants access to servers' state only. |
|
|
||||||
| `users:servers` | Allows for starting/stopping users' servers in addition to read access to their models. _Does not include the server state_. |
|
|
||||||
| `read:users:servers` | Read-only access to users' server models. _Does not include the server state_. |
|
|
||||||
| `users:tokens` | Grants read, write, create and delete permissions to users' tokens. |
|
|
||||||
| `read:users:tokens` | Read-only access to users' tokens. |
|
|
||||||
| `admin:groups` | Grants read, write, create and delete access to groups. |
|
|
||||||
| `groups` | Grants read and write permissions to groups, including adding/removing users to/from groups. |
|
|
||||||
| `read:groups` | Read-only access to groups. |
|
|
||||||
| `read:services` | Read-only access to service models. |
|
|
||||||
| `read:services:name` | Read-only access to service names. |
|
|
||||||
| `read:services:roles` | Read-only access to a list of service roles names. |
|
|
||||||
| `read:hub` | Read-only access to detailed information about the Hub. |
|
|
||||||
| `proxy` | Allows for obtaining information about the proxy's routing table, for syncing the Hub with proxy and notifying the Hub about a new proxy. |
|
|
||||||
| `shutdown` | Grants access to shutdown the hub. |
|
|
||||||
|
|
||||||
```{Caution}
|
```{Caution}
|
||||||
Note that only the {ref}`horizontal filtering <horizontal-filtering-target>` can be added to scopes to customize them. \
|
Note that only the {ref}`horizontal filtering <horizontal-filtering-target>` can be added to scopes to customize them. \
|
||||||
|
@@ -11,6 +11,87 @@ from . import orm
|
|||||||
from . import roles
|
from . import roles
|
||||||
|
|
||||||
|
|
||||||
|
scope_definitions = {
|
||||||
|
'(no_scope)': {'description': 'Allows for only identifying the owning entity.'},
|
||||||
|
'self': {
|
||||||
|
'description': 'Metascope, grants access to user’s own resources only; resolves to (no_scope) for services.'
|
||||||
|
},
|
||||||
|
'all': {
|
||||||
|
'description': 'Metascope, valid for tokens only. Grants access to everything that the token’s owning entity can access.'
|
||||||
|
},
|
||||||
|
'admin:users': {
|
||||||
|
'description': 'Grants read, write, create and delete access to users and their authentication state but not their servers or tokens.',
|
||||||
|
'subscopes': ['admin:users:auth_state', 'users'],
|
||||||
|
},
|
||||||
|
'admin:users:auth_state': {
|
||||||
|
'description': 'Grants access to users’ authentication state only.'
|
||||||
|
},
|
||||||
|
'users': {
|
||||||
|
'description': 'Grants read and write permissions to users’ models apart from servers, tokens and authentication state.',
|
||||||
|
'subscopes': ['read:users', 'users:activity'],
|
||||||
|
},
|
||||||
|
'read:users': {
|
||||||
|
'description': 'Read-only access to users’ models apart from servers, tokens and authentication state.',
|
||||||
|
'subscopes': [
|
||||||
|
'read:users:name',
|
||||||
|
'read:users:groups',
|
||||||
|
'read:users:activity',
|
||||||
|
'read:users:roles',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'read:users:name': {'description': 'Read-only access to users’ names.'},
|
||||||
|
'read:users:groups': {'description': 'Read-only access to users’ group names.'},
|
||||||
|
'read:users:roles': {'description': 'Read-only access to users’ role names.'},
|
||||||
|
'read:users:activity': {'description': 'Read-only access to users’ last activity.'},
|
||||||
|
'users:activity': {
|
||||||
|
'description': 'Grants access to read and post users’ last activity only.',
|
||||||
|
'subscopes': ['read:users:activity'],
|
||||||
|
},
|
||||||
|
'admin:users:servers': {
|
||||||
|
'description': 'Grants read, start/stop, create and delete permissions to users’ servers and their state.',
|
||||||
|
'subscopes': ['admin:users:server_state', 'users:servers'],
|
||||||
|
},
|
||||||
|
'admin:users:server_state': {
|
||||||
|
'description': 'Grants access to servers’ state only.'
|
||||||
|
},
|
||||||
|
'users:servers': {
|
||||||
|
'description': 'Allows for starting/stopping users’ servers in addition to read access to their models. Does not include the server state.',
|
||||||
|
'subscopes': ['read:users:servers'],
|
||||||
|
},
|
||||||
|
'read:users:servers': {
|
||||||
|
'description': 'Read-only access to users’ names and their server models. Does not include the server state.',
|
||||||
|
'subscopes': ['read:users:name'],
|
||||||
|
},
|
||||||
|
'users:tokens': {
|
||||||
|
'description': 'Grants read, write, create and delete permissions to users’ tokens.',
|
||||||
|
'subscopes': ['read:users:tokens'],
|
||||||
|
},
|
||||||
|
'read:users:tokens': {'description': 'Read-only access to users’ tokens.'},
|
||||||
|
'admin:groups': {
|
||||||
|
'description': 'Grants read, write, create and delete access to groups.',
|
||||||
|
'subscopes': ['groups'],
|
||||||
|
},
|
||||||
|
'groups': {
|
||||||
|
'description': 'Grants read and write permissions to groups, including adding/removing users to/from groups.',
|
||||||
|
'subscopes': ['read:groups'],
|
||||||
|
},
|
||||||
|
'read:groups': {'description': 'Read-only access to groups’ models.'},
|
||||||
|
'read:services': {
|
||||||
|
'description': 'Read-only access to service models.',
|
||||||
|
'subscopes': ['read:services:name', 'read:services:roles'],
|
||||||
|
},
|
||||||
|
'read:services:name': {'description': 'Read-only access to service names.'},
|
||||||
|
'read:services:roles': {'description': 'Read-only access to service role names.'},
|
||||||
|
'read:hub': {
|
||||||
|
'description': 'Read-only access to detailed information about the Hub.'
|
||||||
|
},
|
||||||
|
'proxy': {
|
||||||
|
'description': 'Allows for obtaining information about the proxy’s routing table, for syncing the Hub with proxy and notifying the Hub about a new proxy.'
|
||||||
|
},
|
||||||
|
'shutdown': {'description': 'Grants access to shutdown the hub.'},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Scope(Enum):
|
class Scope(Enum):
|
||||||
ALL = True
|
ALL = True
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user