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
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
@echo
@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
from subprocess import check_call as sh
sh(['make', 'metrics', 'rest-api'], cwd=docs)
sh(['make', 'metrics', 'rest-api', 'scopes'], cwd=docs)
# -- 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
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
| 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. |
```{include} scope-table.md
```
```{Caution}
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
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):
ALL = True