Merge pull request #3476 from IvanaH8/rbac-scope-table-makefile

[rbac] Generate scope table for docs
This commit is contained in:
Min RK
2021-05-25 09:18:08 +02:00
committed by GitHub
5 changed files with 191 additions and 33 deletions

View File

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

View File

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

View 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()

View File

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

View File

@@ -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 users own resources only; resolves to (no_scope) for services.'
},
'all': {
'description': 'Metascope, valid for tokens only. Grants access to everything that the tokens 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 proxys 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