Merge branch 'main' into doc-scopes-read-user

This commit is contained in:
Min RK
2025-02-19 09:03:56 +01:00
committed by GitHub
7 changed files with 161 additions and 118 deletions

2
.gitignore vendored
View File

@@ -7,8 +7,6 @@ node_modules
dist
docs/_build
docs/build
docs/source/_static/rest-api
docs/source/rbac/scope-table.md
docs/source/reference/metrics.md
.ipynb_checkpoints

View File

@@ -33,7 +33,7 @@ repos:
rev: v4.0.0-alpha.8
hooks:
- id: prettier
exclude: .*/templates/.*
exclude: .*/templates/.*|docs/source/_static/rest-api.yml|docs/source/rbac/scope-table.md
# autoformat HTML templates
- repo: https://github.com/djlint/djLint
@@ -56,3 +56,16 @@ repos:
- id: requirements-txt-fixer
- id: check-case-conflict
- id: check-executables-have-shebangs
# source docs: rest-api.yml and scope-table.md are autogenerated
- repo: local
hooks:
- id: update-api-and-scope-docs
name: Update rest-api.yml and scope-table.md based on scopes.py
language: python
additional_dependencies: ["pytablewriter", "ruamel.yaml"]
entry: python docs/source/rbac/generate-scope-table.py
args:
- --update
files: jupyterhub/scopes.py
pass_filenames: false

View File

@@ -35,7 +35,7 @@ help:
# - NOTE: If the pre-requisites for the html target is updated, also update the
# Read The Docs section in docs/source/conf.py.
#
html: metrics scopes
html: metrics
$(SPHINXBUILD) -b html "$(SOURCEDIR)" "$(BUILDDIR)/html" $(SPHINXOPTS)
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
@@ -44,10 +44,6 @@ metrics: source/reference/metrics.md
source/reference/metrics.md:
python3 generate-metrics.py
scopes: source/rbac/scope-table.md
source/rbac/scope-table.md:
python3 source/rbac/generate-scope-table.py
# Manually added targets - related to development
# ----------------------------------------------------------------------------
@@ -56,7 +52,7 @@ source/rbac/scope-table.md:
# - requires sphinx-autobuild, see
# https://sphinxcontrib-spelling.readthedocs.io/en/latest/
# - builds and rebuilds html on changes to source, but does not re-generate
# metrics/scopes files
# metrics files
# - starts a livereload enabled webserver and opens up a browser
devenv: html
sphinx-autobuild -b html --open-browser "$(SOURCEDIR)" "$(BUILDDIR)/html"

View File

@@ -62,8 +62,7 @@ paths:
properties:
class:
type: string
description:
The Python class currently active for JupyterHub
description: The Python class currently active for JupyterHub
Authentication
version:
type: string
@@ -73,8 +72,7 @@ paths:
properties:
class:
type: string
description:
The Python class currently active for spawning
description: The Python class currently active for spawning
single-user notebook servers
version:
type: string
@@ -258,8 +256,7 @@ paths:
parameters:
- $ref: "#/components/parameters/userName"
requestBody:
description:
Updated user info. At least one key to be updated (name or admin)
description: Updated user info. At least one key to be updated (name or admin)
is required.
content:
application/json:
@@ -268,13 +265,11 @@ paths:
properties:
name:
type: string
description:
the new name (optional, if another key is updated i.e.
description: the new name (optional, if another key is updated i.e.
admin)
admin:
type: boolean
description:
update admin (optional, if another key is updated i.e.
description: update admin (optional, if another key is updated i.e.
name)
required: true
responses:
@@ -291,8 +286,7 @@ paths:
post:
operationId: post-user-activity
summary: Notify Hub of activity for a given user
description:
Notify the Hub of activity by the user, e.g. accessing a service
description: Notify the Hub of activity by the user, e.g. accessing a service
or (more likely) actively using a server.
parameters:
- $ref: "#/components/parameters/userName"
@@ -372,8 +366,7 @@ paths:
description: The user's notebook server has started
content: {}
202:
description:
The user's notebook server has not yet started, but has been
description: The user's notebook server has not yet started, but has been
requested
content: {}
security:
@@ -387,8 +380,7 @@ paths:
- $ref: "#/components/parameters/userName"
responses:
202:
description:
The user's notebook server has not yet stopped as it is taking
description: The user's notebook server has not yet stopped as it is taking
a while to stop
content: {}
204:
@@ -420,8 +412,7 @@ paths:
description: The user's notebook named-server has started
content: {}
202:
description:
The user's notebook named-server has not yet started, but has
description: The user's notebook named-server has not yet started, but has
been requested
content: {}
security:
@@ -457,8 +448,7 @@ paths:
required: false
responses:
202:
description:
The user's notebook named-server has not yet stopped as it
description: The user's notebook named-server has not yet stopped as it
is taking a while to stop
content: {}
204:
@@ -472,8 +462,7 @@ paths:
get:
operationId: get-user-shared
summary: List servers shared with user
description:
Returns list of Shares granting the user access to servers owned
description: Returns list of Shares granting the user access to servers owned
by others (new in 5.0)
parameters:
- $ref: "#/components/parameters/userName"
@@ -587,8 +576,7 @@ paths:
expires_in:
type: number
example: 3600
description:
lifetime (in seconds) after which the requested token
description: lifetime (in seconds) after which the requested token
will expire. Omit, or specify null or 0 for no expiration.
note:
type: string
@@ -1262,8 +1250,7 @@ paths:
get:
operationId: get-proxy
summary: Get the proxy's routing table
description:
A convenience alias for getting the routing table directly from
description: A convenience alias for getting the routing table directly from
the proxy
parameters:
- $ref: "#/components/parameters/paginationOffset"
@@ -1275,8 +1262,7 @@ paths:
application/json:
schema:
type: object
description:
configurable-http-proxy routing table (see configurable-http-proxy
description: configurable-http-proxy routing table (see configurable-http-proxy
docs for details)
security:
- oauth2:
@@ -1296,8 +1282,7 @@ paths:
summary: Notify the Hub about a new proxy
description: Notifies the Hub of a new proxy to use.
requestBody:
description:
Any values that have changed for the new proxy. All keys are
description: Any values that have changed for the new proxy. All keys are
optional.
content:
application/json:
@@ -1389,8 +1374,7 @@ paths:
get:
operationId: get-auth-cookie
summary: Identify a user from a cookie
description:
Used by single-user notebook servers to hand off cookie authentication
description: Used by single-user notebook servers to hand off cookie authentication
to the Hub
parameters:
- name: cookie_name
@@ -1515,13 +1499,11 @@ paths:
properties:
proxy:
type: boolean
description:
Whether the proxy should be shutdown as well (default
description: Whether the proxy should be shutdown as well (default
from Hub config)
servers:
type: boolean
description:
Whether users' notebook servers should be shutdown
description: Whether users' notebook servers should be shutdown
as well (default from Hub config)
required: false
responses:
@@ -1666,8 +1648,7 @@ components:
type: string
server:
type: string
description:
The user's notebook server's base URL, if running; null if
description: The user's notebook server's base URL, if running; null if
not.
pending:
type: string
@@ -1699,8 +1680,7 @@ components:
properties:
name:
type: string
description:
The server's name. The user's default server has an empty name
description: The server's name. The user's default server has an empty name
('')
ready:
type: boolean
@@ -1763,15 +1743,13 @@ components:
state:
type: object
properties: {}
description:
Arbitrary internal state from this server's spawner. Only available
description: Arbitrary internal state from this server's spawner. Only available
on the hub's users list or get-user-by-name method, and only with admin:users:server_state
scope. None otherwise.
user_options:
type: object
properties: {}
description:
User specified options for the user's spawned instance of a
description: User specified options for the user's spawned instance of a
single-user server.
RequestIdentity:
description: |
@@ -1940,8 +1918,7 @@ components:
items:
type: string
group:
description:
the group being shared with (exactly one of 'user' or 'group'
description: the group being shared with (exactly one of 'user' or 'group'
will be non-null, the other will be null)
type:
- object
@@ -1950,8 +1927,7 @@ components:
name:
type: string
user:
description:
the user being shared with (exactly one of 'user' or 'group'
description: the user being shared with (exactly one of 'user' or 'group'
will be non-null, the other will be null)
type:
- object
@@ -1965,8 +1941,7 @@ components:
format: date-time
ShareCode:
description:
A single sharing code. There is at most one of these objects per
description: A single sharing code. There is at most one of these objects per
(server, user) or (server, group) combination.
type: object
properties:
@@ -2002,8 +1977,7 @@ components:
properties:
id:
type: string
description:
The id of the API token. Used for modifying or deleting the
description: The id of the API token. Used for modifying or deleting the
token.
user:
type: string
@@ -2013,22 +1987,19 @@ components:
description: The service that owns the token (undefined of owned by a user)
roles:
type: array
description:
Deprecated in JupyterHub 3, always an empty list. Tokens have
description: Deprecated in JupyterHub 3, always an empty list. Tokens have
'scopes' starting from JupyterHub 3.
items:
type: string
scopes:
type: array
description:
List of scopes this token has been assigned. New in JupyterHub
description: List of scopes this token has been assigned. New in JupyterHub
3. In JupyterHub 2.x, tokens were assigned 'roles' instead of scopes.
items:
type: string
note:
type: string
description:
A note about the token, typically describing what it was created
description: A note about the token, typically describing what it was created
for.
created:
type: string
@@ -2059,13 +2030,11 @@ components:
properties:
token:
type: string
description:
The token itself. Only present in responses to requests for
description: The token itself. Only present in responses to requests for
a new token.
id:
type: string
description:
The id of the API token. Used for modifying or deleting the
description: The id of the API token. Used for modifying or deleting the
token.
user:
type: string
@@ -2075,22 +2044,19 @@ components:
description: The service that owns the token (undefined of owned by a user)
roles:
type: array
description:
Deprecated in JupyterHub 3, always an empty list. Tokens have
description: Deprecated in JupyterHub 3, always an empty list. Tokens have
'scopes' starting from JupyterHub 3.
items:
type: string
scopes:
type: array
description:
List of scopes this token has been assigned. New in JupyterHub
description: List of scopes this token has been assigned. New in JupyterHub
3. In JupyterHub 2.x, tokens were assigned 'roles' instead of scopes.
items:
type: string
note:
type: string
description:
A note about the token, typically describing what it was created
description: A note about the token, typically describing what it was created
for.
created:
type: string
@@ -2128,27 +2094,21 @@ components:
tokenUrl: /hub/api/oauth2/token
scopes:
(no_scope): Identify the owner of the requesting entity.
self:
The users own resources _(metascope for users, resolves to (no_scope)
self: The users own resources _(metascope for users, resolves to (no_scope)
for services)_
inherit:
Everything that the token-owning entity can access _(metascope
inherit: Everything that the token-owning entity can access _(metascope
for tokens)_
admin-ui:
Access the admin page. Permission to take actions via the admin
admin-ui: Access the admin page. Permission to take actions via the admin
page granted separately.
admin:users:
Read, modify, create, and delete users and their authentication
admin:users: Read, modify, create, and delete users and their authentication
state, not including their servers or tokens. This is an extremely privileged
scope and should be considered tantamount to superuser.
admin:auth_state: Read a users authentication state.
users:
Read and write permissions to user models (excluding servers, tokens
users: Read and write permissions to user models (excluding servers, tokens
and authentication state).
delete:users: Delete users.
list:users: List users, including at least their names.
read:users:
Read user models (including the URL of the default server
read:users: Read user models (including the URL of the default server
if it is running).
read:users:name: Read names of users.
read:users:groups: Read users group membership.
@@ -2158,27 +2118,23 @@ components:
read:roles:services: Read service role assignments.
read:roles:groups: Read group role assignments.
users:activity: Update time of last user activity.
admin:servers:
Read, start, stop, create and delete user servers and their
admin:servers: Read, start, stop, create and delete user servers and their
state.
admin:server_state: Read and write users server state.
servers: Start and stop user servers.
read:servers:
Read users names and their server models (excluding the
read:servers: Read users names and their server models (excluding the
server state).
delete:servers: Stop and delete users' servers.
tokens: Read, write, create and delete user tokens.
read:tokens: Read user tokens.
admin:groups: Read and write group information, create and delete groups.
groups:
"Read and write group information, including adding/removing any
users to/from groups. Note: adding users to groups may affect permissions."
groups: 'Read and write group information, including adding/removing any
users to/from groups. Note: adding users to groups may affect permissions.'
list:groups: List groups, including at least their names.
read:groups: Read group models.
read:groups:name: Read group names.
delete:groups: Delete groups.
admin:services:
Create, read, update, delete services, not including services
admin:services: Create, read, update, delete services, not including services
defined from config files.
list:services: List services, including at least their names.
read:services: Read service models.
@@ -2192,8 +2148,7 @@ components:
read:groups:shares: Read servers shared with a group.
read:shares: Read information about shared access to servers.
shares: Manage access to shared servers.
proxy:
Read information about the proxys routing table, sync the Hub
proxy: Read information about the proxys routing table, sync the Hub
with the proxy and notify the Hub about a new proxy.
shutdown: Shutdown the hub.
read:metrics: Read prometheus metrics.

View File

@@ -14,26 +14,52 @@ The files are:
scopes descriptions are updated in it.
"""
import os
from collections import defaultdict
from pathlib import Path
from subprocess import run
from pytablewriter import MarkdownTableWriter
from ruamel.yaml import YAML
HERE = Path(__file__).parent.absolute()
DOCS = HERE / ".." / ".."
REST_API_YAML = DOCS.joinpath("source", "_static", "rest-api.yml")
SCOPE_TABLE_MD = HERE.joinpath("scope-table.md")
def _load_jupyterhub_info():
"""
The equivalent of
from jupyterhub import __version__
from jupyterhub.scopes import scope_definitions
HERE = os.path.abspath(os.path.dirname(__file__))
DOCS = Path(HERE).parent.parent.absolute()
REST_API_YAML = DOCS.joinpath("source", "_static", "rest-api.yml")
SCOPE_TABLE_MD = Path(HERE).joinpath("scope-table.md")
but without needing to install JupyterHub and dependencies
so that we can run this pre-commit
"""
root = HERE / ".." / ".." / ".."
g = {}
exec((root / "jupyterhub" / "_version.py").read_text(), g)
# To avoid parsing the whole of scope_definitions.py just pull out
# the relevant lines
scopes_file = root / "jupyterhub" / "scopes.py"
scopes_lines = []
for line in scopes_file.read_text().splitlines():
if not scopes_lines and line == "scope_definitions = {":
scopes_lines.append(line)
elif scopes_lines:
scopes_lines.append(line)
if line == "}":
break
exec("\n".join(scopes_lines), g)
return g["__version__"], g["scope_definitions"]
class ScopeTableGenerator:
def __init__(self):
self.scopes = scope_definitions
self.version, self.scopes = _load_jupyterhub_info()
@classmethod
def create_writer(cls, table_name, headers, values):
@@ -131,7 +157,7 @@ class ScopeTableGenerator:
with open(filename) as f:
content = yaml.load(f.read())
content["info"]["version"] = __version__
content["info"]["version"] = self.version
for scope in self.scopes:
description = self.scopes[scope]['description']
doc_description = self.scopes[scope].get('doc_description', '')
@@ -145,12 +171,6 @@ class ScopeTableGenerator:
with open(filename, 'w') as f:
yaml.dump(content, f)
run(
['pre-commit', 'run', 'prettier', '--files', filename],
cwd=HERE,
check=False,
)
def main():
table_generator = ScopeTableGenerator()

View File

@@ -0,0 +1,58 @@
Table 1. Available scopes and their hierarchy
| Scope | Grants permission to: |
| --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `(no_scope)` | Identify the owner of the requesting entity. |
| `self` | The users own resources _(metascope for users, resolves to (no_scope) for services)_ |
| `inherit` | Everything that the token-owning entity can access _(metascope for tokens)_ |
| `admin-ui` | Access the admin page. Permission to take actions via the admin page granted separately. |
| `admin:users` | Read, modify, create, and delete users and their authentication state, not including their servers or tokens. This is an extremely privileged scope and should be considered tantamount to superuser. |
|    `admin:auth_state` | Read a users authentication state. |
|    `users` | Read and write permissions to user models (excluding servers, tokens and authentication state). |
|       `read:users` | Read user models (including servers, tokens and authentication state). |
|          `read:users:name` | Read names of users. |
|          `read:users:groups` | Read users group membership. |
|          `read:users:activity` | Read time of last user activity. |
|       `list:users` | List users, including at least their names. |
|          `read:users:name` | Read names of users. |
|       `users:activity` | Update time of last user activity. |
|          `read:users:activity` | Read time of last user activity. |
|    `read:roles:users` | Read user role assignments. |
|    `delete:users` | Delete users. |
| `read:roles` | Read role assignments. |
|    `read:roles:users` | Read user role assignments. |
|    `read:roles:services` | Read service role assignments. |
|    `read:roles:groups` | Read group role assignments. |
| `admin:servers` | Read, start, stop, create and delete user servers and their state. |
|    `admin:server_state` | Read and write users server state. |
|    `servers` | Start and stop user servers. |
|       `read:servers` | Read users names and their server models (excluding the server state). |
|          `read:users:name` | Read names of users. |
|       `delete:servers` | Stop and delete users' servers. |
| `tokens` | Read, write, create and delete user tokens. |
|    `read:tokens` | Read user tokens. |
| `admin:groups` | Read and write group information, create and delete groups. |
|    `groups` | Read and write group information, including adding/removing any users to/from groups. Note: adding users to groups may affect permissions. |
|       `read:groups` | Read group models. |
|          `read:groups:name` | Read group names. |
|       `list:groups` | List groups, including at least their names. |
|          `read:groups:name` | Read group names. |
|    `read:roles:groups` | Read group role assignments. |
|    `delete:groups` | Delete groups. |
| `admin:services` | Create, read, update, delete services, not including services defined from config files. |
|    `list:services` | List services, including at least their names. |
|       `read:services:name` | Read service names. |
|    `read:services` | Read service models. |
|       `read:services:name` | Read service names. |
|    `read:roles:services` | Read service role assignments. |
| `read:hub` | Read detailed information about the Hub. |
| `access:services` | Access services via API or browser. |
| `shares` | Manage access to shared servers. |
|    `access:servers` | Access user servers via API or browser. |
|    `read:shares` | Read information about shared access to servers. |
|    `users:shares` | Read and revoke a user's access to shared servers. |
|       `read:users:shares` | Read servers shared with a user. |
|    `groups:shares` | Read and revoke a group's access to shared servers. |
|       `read:groups:shares` | Read servers shared with a group. |
| `proxy` | Read information about the proxys routing table, sync the Hub with the proxy and notify the Hub about a new proxy. |
| `shutdown` | Shutdown the hub. |
| `read:metrics` | Read prometheus metrics. |

View File

@@ -31,8 +31,11 @@ from tornado.log import app_log
from . import orm, roles
from ._memoize import DoNotCache, FrozenDict, lru_cache_key
"""when modifying the scope definitions, make sure that `docs/source/rbac/generate-scope-table.py` is run
so that changes are reflected in the documentation and REST API description."""
"""when modifying the scope definitions
`docs/source/rbac/generate-scope-table.py` must be run
so that changes are reflected in the documentation and REST API description.
`pre-commit run -a` should automatically take care of this.
"""
scope_definitions = {
'(no_scope)': {'description': 'Identify the owner of the requesting entity.'},
'self': {