From f292dac2448954fddedc28f425306ecdc6f40597 Mon Sep 17 00:00:00 2001 From: floriandeboissieu Date: Fri, 14 Oct 2022 23:43:00 +0200 Subject: [PATCH 01/23] update object_name with current image update object_name with current image name in template --- dockerspawner/dockerspawner.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dockerspawner/dockerspawner.py b/dockerspawner/dockerspawner.py index 41ab5789..14928647 100644 --- a/dockerspawner/dockerspawner.py +++ b/dockerspawner/dockerspawner.py @@ -887,6 +887,10 @@ def template_namespace(self): def _object_name_default(self): """Render the name of our container/service using name_template""" return self._render_templates(self.name_template) + + async def _object_name_for_current_image(self): + """Render the name of our container/service using name_template""" + return self._render_templates(self.name_template) def load_state(self, state): super(DockerSpawner, self).load_state(state) @@ -1259,9 +1263,10 @@ async def start(self, image=None, extra_create_kwargs=None, extra_host_config=No if image_option: # save choice in self.image self.image = await self.check_allowed(image_option) + self.object_name = await self._object_name_for_current_image() image = self.image - await self.pull_image(image) + await self.pull_imt self._object_name_default()age(image) obj = await self.get_object() if obj and self.remove: From 3d04ee567a3b986b7c37600217ffee3407087651 Mon Sep 17 00:00:00 2001 From: floriandeboissieu Date: Fri, 14 Oct 2022 23:51:35 +0200 Subject: [PATCH 02/23] fix typo mistake fix not wanted copy/paste --- dockerspawner/dockerspawner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dockerspawner/dockerspawner.py b/dockerspawner/dockerspawner.py index 14928647..21aeac9e 100644 --- a/dockerspawner/dockerspawner.py +++ b/dockerspawner/dockerspawner.py @@ -1266,7 +1266,7 @@ async def start(self, image=None, extra_create_kwargs=None, extra_host_config=No self.object_name = await self._object_name_for_current_image() image = self.image - await self.pull_imt self._object_name_default()age(image) + await self.pull_image(image) obj = await self.get_object() if obj and self.remove: From 3a6554eecac4aa2afc6b36de22b5d4bec9700d65 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 14 Oct 2022 22:21:51 +0000 Subject: [PATCH 03/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- dockerspawner/dockerspawner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dockerspawner/dockerspawner.py b/dockerspawner/dockerspawner.py index 21aeac9e..e15eae2e 100644 --- a/dockerspawner/dockerspawner.py +++ b/dockerspawner/dockerspawner.py @@ -887,7 +887,7 @@ def template_namespace(self): def _object_name_default(self): """Render the name of our container/service using name_template""" return self._render_templates(self.name_template) - + async def _object_name_for_current_image(self): """Render the name of our container/service using name_template""" return self._render_templates(self.name_template) From 60719b14edc3b28ba1b8e9515846b6afb1c082cf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:08:28 +0000 Subject: [PATCH 04/23] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.4.0 → v3.10.1](https://github.com/asottile/pyupgrade/compare/v3.4.0...v3.10.1) - [github.com/PyCQA/autoflake: v2.1.1 → v2.2.1](https://github.com/PyCQA/autoflake/compare/v2.1.1...v2.2.1) - [github.com/psf/black: 23.3.0 → 23.7.0](https://github.com/psf/black/compare/23.3.0...23.7.0) - [github.com/pre-commit/mirrors-prettier: v3.0.0-alpha.9-for-vscode → v3.0.3](https://github.com/pre-commit/mirrors-prettier/compare/v3.0.0-alpha.9-for-vscode...v3.0.3) - [github.com/PyCQA/flake8: 6.0.0 → 6.1.0](https://github.com/PyCQA/flake8/compare/6.0.0...6.1.0) --- .pre-commit-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5572323e..3f270f44 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: # Autoformat: Python code, syntax patterns are modernized - repo: https://github.com/asottile/pyupgrade - rev: v3.4.0 + rev: v3.10.1 hooks: - id: pyupgrade args: @@ -17,7 +17,7 @@ repos: # Autoformat: Python code - repo: https://github.com/PyCQA/autoflake - rev: v2.1.1 + rev: v2.2.1 hooks: - id: autoflake # args ref: https://github.com/PyCQA/autoflake#advanced-usage @@ -32,7 +32,7 @@ repos: # Autoformat: Python - repo: https://github.com/psf/black - rev: 23.3.0 + rev: 23.7.0 hooks: - id: black @@ -44,13 +44,13 @@ repos: # Autoformat: markdown, yaml - repo: https://github.com/pre-commit/mirrors-prettier - rev: v3.0.0-alpha.9-for-vscode + rev: v3.0.3 hooks: - id: prettier # Lint: Python code - repo: https://github.com/PyCQA/flake8 - rev: "6.0.0" + rev: "6.1.0" hooks: - id: flake8 From b8f0164a745c5d0593fc8205f7aac60d542d86cc Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 18 Sep 2023 15:20:57 +0200 Subject: [PATCH 05/23] refresh object_name when image using trait observer --- dockerspawner/dockerspawner.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dockerspawner/dockerspawner.py b/dockerspawner/dockerspawner.py index e15eae2e..5ee3e086 100644 --- a/dockerspawner/dockerspawner.py +++ b/dockerspawner/dockerspawner.py @@ -888,9 +888,10 @@ def _object_name_default(self): """Render the name of our container/service using name_template""" return self._render_templates(self.name_template) - async def _object_name_for_current_image(self): - """Render the name of our container/service using name_template""" - return self._render_templates(self.name_template) + @observe("image") + def _image_changed(self, change): + # re-render object name if image changes + self.object_name = self._object_name_default() def load_state(self, state): super(DockerSpawner, self).load_state(state) @@ -1263,7 +1264,6 @@ async def start(self, image=None, extra_create_kwargs=None, extra_host_config=No if image_option: # save choice in self.image self.image = await self.check_allowed(image_option) - self.object_name = await self._object_name_for_current_image() image = self.image await self.pull_image(image) From 876dc8eed75751612e2afa8a5607d0eb39991a43 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 18 Sep 2023 15:33:49 +0200 Subject: [PATCH 06/23] Remove deprecated, broken hub_ip_connect Deprecated since JupyterHub 0.8, the CLI arg it specified has stopped working in JupyterHub 4 with the singleuser extension. Leave warning in place, but louder now, and _ignore_ the argument since it has stopped working with JupyterHub 4. --- dockerspawner/dockerspawner.py | 35 +++------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/dockerspawner/dockerspawner.py b/dockerspawner/dockerspawner.py index eca7fe4f..0eadf94f 100644 --- a/dockerspawner/dockerspawner.py +++ b/dockerspawner/dockerspawner.py @@ -654,22 +654,13 @@ def _legacy_escape(text): hub_ip_connect = Unicode( config=True, - help=dedent( - """ - If set, DockerSpawner will configure the containers to use - the specified IP to connect the hub api. This is useful - when the hub_api is bound to listen on all ports or is - running inside of a container. - """ - ), + help="DEPRECATED since JupyterHub 0.8. Use c.JupyterHub.hub_connect_ip.", ) @observe("hub_ip_connect") def _ip_connect_changed(self, change): - warnings.warn( - "DockerSpawner.hub_ip_connect is no longer needed with JupyterHub 0.8." - " Use JupyterHub.hub_connect_ip instead.", - DeprecationWarning, + self.log.warning( + f"Ignoring DockerSpawner.hub_ip_connect={change.new!r}, which has ben deprected since JupyterHub 0.8. Use c.JupyterHub.hub_connect_ip instead." ) use_internal_ip = Bool( @@ -933,30 +924,10 @@ def get_state(self): ) return state - def _public_hub_api_url(self): - proto, path = self.hub.api_url.split("://", 1) - ip, rest = path.split(":", 1) - return "{proto}://{ip}:{rest}".format( - proto=proto, ip=self.hub_ip_connect, rest=rest - ) - def _env_keep_default(self): """Don't inherit any env from the parent process""" return [] - def get_args(self): - args = super().get_args() - if self.hub_ip_connect: - # JupyterHub 0.7 specifies --hub-api-url - # on the command-line, which is hard to update - for idx, arg in enumerate(list(args)): - if arg.startswith("--hub-api-url="): - args.pop(idx) - break - - args.append("--hub-api-url=%s" % self._public_hub_api_url()) - return args - def get_env(self): env = super().get_env() env['JUPYTER_IMAGE_SPEC'] = self.image From e30c94416f4b9d4c65de8335c91073d7c31b5708 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 18 Sep 2023 16:00:31 +0200 Subject: [PATCH 07/23] allow extra_host_config and extra_create_kwargs to be callable for e.g. per-user device requests --- dockerspawner/dockerspawner.py | 60 +++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/dockerspawner/dockerspawner.py b/dockerspawner/dockerspawner.py index eca7fe4f..51f0723d 100644 --- a/dockerspawner/dockerspawner.py +++ b/dockerspawner/dockerspawner.py @@ -2,6 +2,7 @@ A Spawner for JupyterHub that runs each user's server in a separate docker container """ import asyncio +import inspect import os import string import warnings @@ -580,7 +581,8 @@ def will_resume(self): # so JupyterHub >= 0.7.1 won't cleanup our API token return not self.remove - extra_create_kwargs = Dict( + extra_create_kwargs = Union( + [Callable(), Dict()], config=True, help="""Additional args to pass for container create @@ -590,11 +592,29 @@ def will_resume(self): "user": "root" # Can also be an integer UID } - The above is equivalent to ``docker run --user root`` + The above is equivalent to ``docker run --user root``. + + If a callable, will be called with the Spawner as the only argument, + must return the same dictionary structure, and may be async. + + .. versionchanged:: 13 + + Added callable support. """, ) - extra_host_config = Dict( - config=True, help="Additional args to create_host_config for container create" + extra_host_config = Union( + [Callable(), Dict()], + config=True, + help=""" + Additional args to create_host_config for container create. + + If a callable, will be called with the Spawner as the only argument, + must return the same dictionary structure, and may be async. + + .. versionchanged:: 13 + + Added callable support. + """, ) escape = Any( @@ -1139,11 +1159,17 @@ async def create_object(self): name=self.container_name, command=(await self.get_command()), ) + extra_create_kwargs = self._eval_if_callable(self.extra_create_kwargs) + if inspect.isawaitable(extra_create_kwargs): + extra_create_kwargs = await extra_create_kwargs + extra_host_config = self._eval_if_callable(self.extra_host_config) + if inspect.isawaitable(extra_host_config): + extra_host_config = await extra_host_config # ensure internal port is exposed create_kwargs["ports"] = {"%i/tcp" % self.port: None} - create_kwargs.update(self._render_templates(self.extra_create_kwargs)) + create_kwargs.update(self._render_templates(extra_create_kwargs)) # build the dictionary of keyword arguments for host_config host_config = dict( @@ -1160,14 +1186,14 @@ async def create_object(self): # docker cpu units are in microseconds # cpu_period default is 100ms # cpu_quota is cpu_period * cpu_limit - cpu_period = host_config["cpu_period"] = self.extra_host_config.get( + cpu_period = host_config["cpu_period"] = extra_host_config.get( "cpu_period", 100_000 ) host_config["cpu_quota"] = int(self.cpu_limit * cpu_period) if not self.use_internal_ip: host_config["port_bindings"] = {self.port: (self.host_ip,)} - host_config.update(self._render_templates(self.extra_host_config)) + host_config.update(self._render_templates(extra_host_config)) host_config.setdefault("network_mode", self.network_name) self.log.debug("Starting host with config: %s", host_config) @@ -1243,31 +1269,13 @@ async def pull_image(self, image): self.log.info("pulling image %s", image) await self.docker('pull', repo, tag) - async def start(self, image=None, extra_create_kwargs=None, extra_host_config=None): + async def start(self): """Start the single-user server in a docker container. - Additional arguments to create/host config/etc. can be specified - via .extra_create_kwargs and .extra_host_config attributes. - If the container exists and ``c.DockerSpawner.remove`` is ``True``, then the container is removed first. Otherwise, the existing containers will be restarted. """ - - if image: - self.log.warning("Specifying image via .start args is deprecated") - self.image = image - if extra_create_kwargs: - self.log.warning( - "Specifying extra_create_kwargs via .start args is deprecated" - ) - self.extra_create_kwargs.update(extra_create_kwargs) - if extra_host_config: - self.log.warning( - "Specifying extra_host_config via .start args is deprecated" - ) - self.extra_host_config.update(extra_host_config) - # image priority: # 1. user options (from spawn options form) # 2. self.image from config From 94f819fa6a3fdb0d236d54fd75cfe15aebd60ded Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 18 Sep 2023 16:08:11 +0200 Subject: [PATCH 08/23] merge create_kwargs/host_config instead of clobbering --- dockerspawner/dockerspawner.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/dockerspawner/dockerspawner.py b/dockerspawner/dockerspawner.py index 51f0723d..652cbe6d 100644 --- a/dockerspawner/dockerspawner.py +++ b/dockerspawner/dockerspawner.py @@ -55,6 +55,24 @@ def validate(self, obj, value): _jupyterhub_xy = "%i.%i" % (jupyterhub.version_info[:2]) +def _deep_merge(dest, src): + """Merge dict `src` into `dest`, recursively + + Modifies `dest` in-place, returns dest + """ + for key, value in src.items(): + if key in dest: + dest_value = dest[key] + if isinstance(dest_value, dict) and isinstance(value, dict): + dest[key] = _deep_merge(dest_value, value) + else: + dest[key] = value + else: + dest[key] = value + + return dest + + class DockerSpawner(Spawner): """A Spawner for JupyterHub that runs each user's server in a separate docker container""" @@ -1162,14 +1180,16 @@ async def create_object(self): extra_create_kwargs = self._eval_if_callable(self.extra_create_kwargs) if inspect.isawaitable(extra_create_kwargs): extra_create_kwargs = await extra_create_kwargs + extra_create_kwargs = self._render_templates(extra_create_kwargs) extra_host_config = self._eval_if_callable(self.extra_host_config) if inspect.isawaitable(extra_host_config): extra_host_config = await extra_host_config + extra_host_config = self._render_templates(extra_host_config) # ensure internal port is exposed create_kwargs["ports"] = {"%i/tcp" % self.port: None} - create_kwargs.update(self._render_templates(extra_create_kwargs)) + _deep_merge(create_kwargs, extra_create_kwargs) # build the dictionary of keyword arguments for host_config host_config = dict( @@ -1193,7 +1213,7 @@ async def create_object(self): if not self.use_internal_ip: host_config["port_bindings"] = {self.port: (self.host_ip,)} - host_config.update(self._render_templates(extra_host_config)) + _deep_merge(host_config, extra_host_config) host_config.setdefault("network_mode", self.network_name) self.log.debug("Starting host with config: %s", host_config) From 8d883b32b1d76c82f4f6cf0d9a1d607756dc5d4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 05:35:29 +0000 Subject: [PATCH 09/23] Bump actions/checkout from 3 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yaml | 2 +- .github/workflows/test.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a3a7848d..0958a28a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -33,7 +33,7 @@ jobs: id-token: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: "3.11" diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index adabbf5e..5fc0138d 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -45,7 +45,7 @@ jobs: test-variation: podman steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} From d44f79e7cace15e6bd231b709eae86c568464451 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:32:58 +0000 Subject: [PATCH 10/23] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.10.1 → v3.14.0](https://github.com/asottile/pyupgrade/compare/v3.10.1...v3.14.0) - [github.com/psf/black: 23.7.0 → 23.9.1](https://github.com/psf/black/compare/23.7.0...23.9.1) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3f270f44..0500438d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: # Autoformat: Python code, syntax patterns are modernized - repo: https://github.com/asottile/pyupgrade - rev: v3.10.1 + rev: v3.14.0 hooks: - id: pyupgrade args: @@ -32,7 +32,7 @@ repos: # Autoformat: Python - repo: https://github.com/psf/black - rev: 23.7.0 + rev: 23.9.1 hooks: - id: black From ab8dcfd20fe3baccc22cabb33d577fab7171226f Mon Sep 17 00:00:00 2001 From: YuviPanda Date: Thu, 26 Oct 2023 11:28:02 +0530 Subject: [PATCH 11/23] Switch default image to quay.io Bump up a couple other versions in the Dockerfile examples as well. Ref https://github.com/jupyterhub/team-compass/issues/688 --- dockerspawner/dockerspawner.py | 4 ++-- docs/source/docker-image.md | 14 +++++++------- examples/internal-ssl/.env | 2 +- tests/conftest.py | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/dockerspawner/dockerspawner.py b/dockerspawner/dockerspawner.py index eca7fe4f..697db9f2 100644 --- a/dockerspawner/dockerspawner.py +++ b/dockerspawner/dockerspawner.py @@ -196,13 +196,13 @@ def _ip_default(self): return "0.0.0.0" container_image = Unicode( - "jupyterhub/singleuser:%s" % _jupyterhub_xy, + "quay.io/jupyterhub/singleuser:%s" % _jupyterhub_xy, help="Deprecated, use ``DockerSpawner.image``.", config=True, ) image = Unicode( - "jupyterhub/singleuser:%s" % _jupyterhub_xy, + "quay.io/jupyterhub/singleuser:%s" % _jupyterhub_xy, config=True, help="""The image to use for single-user servers. diff --git a/docs/source/docker-image.md b/docs/source/docker-image.md index 161e6af8..656e15f1 100644 --- a/docs/source/docker-image.md +++ b/docs/source/docker-image.md @@ -1,6 +1,6 @@ # Picking or building a Docker image -By default, DockerSpawner uses the `jupyterhub/singleuser` image +By default, DockerSpawner uses the `quay.io/jupyterhub/singleuser` image with the appropriate tag that pins the right version of JupyterHub, but you can also build your own image. @@ -13,7 +13,7 @@ and are encouraged as the image of choice. Make sure to pick a tag! Example: ```python -c.DockerSpawner.image = 'jupyter/scipy-notebook:67b8fb91f950' +c.DockerSpawner.image = 'quay.io/jupyter/scipy-notebook:2023-10-23' ``` The docker-stacks are moving targets with always changing versions. @@ -37,8 +37,8 @@ the appropriate JupyterHub version and the Jupyter notebook package. For instance, from the docker-stacks, pin your JupyterHub version and you are done: ```Dockerfile -FROM jupyter/scipy-notebook:67b8fb91f950 -ARG JUPYTERHUB_VERSION=1.3.0 +FROM quay.io/jupyter/scipy-notebook:67b8fb91f950 +ARG JUPYTERHUB_VERSION=4.0.2 RUN pip3 install --no-cache \ jupyterhub==$JUPYTERHUB_VERSION ``` @@ -48,10 +48,10 @@ Or for the absolute minimal JupyterHub user image starting only from the base Py **NOTE: make sure to pick the jupyterhub version you are using!** ```Dockerfile -FROM python:3.8 +FROM python:3.11 RUN pip3 install \ - 'jupyterhub==1.3.*' \ - 'notebook==6.*' + 'jupyterhub==4.*' \ + 'notebook==7.*' # create a user, since we don't want to run as root RUN useradd -m jovyan diff --git a/examples/internal-ssl/.env b/examples/internal-ssl/.env index 5a8fad4a..02d8327a 100644 --- a/examples/internal-ssl/.env +++ b/examples/internal-ssl/.env @@ -13,7 +13,7 @@ DOCKER_MACHINE_NAME=jupyterhub DOCKER_NETWORK_NAME=jupyterhub # Single-user Jupyter Notebook server container image -DOCKER_NOTEBOOK_IMAGE=jupyterhub/singleuser:4 +DOCKER_NOTEBOOK_IMAGE=quay.io/jupyterhub/singleuser:4 # Name of JupyterHub container data volume DATA_VOLUME_HOST=jupyterhub-data diff --git a/tests/conftest.py b/tests/conftest.py index adaabdb5..0db1f925 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -63,7 +63,7 @@ def app(jupyterhub_app): # noqa: F811 # If it's a prerelease e.g. (2, 0, 0, 'rc4', '') use full tag if len(jh_version_info) > 3 and jh_version_info[3]: tag = jupyterhub.__version__ - app.config.DockerSpawner.image = f"jupyterhub/singleuser:{tag}" + app.config.DockerSpawner.image = f"quay.io/jupyterhub/singleuser:{tag}" return app From a41d96cc99e528761b21e946ff00c1a2fa8dd3fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Nov 2023 05:39:07 +0000 Subject: [PATCH 12/23] Bump actions/setup-node from 3 to 4 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 5fc0138d..1e72e312 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -49,7 +49,7 @@ jobs: - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: "18" From be211e5b1d70a2b277e1b175e6e559090df7551f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 20:27:00 +0000 Subject: [PATCH 13/23] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.14.0 → v3.15.0](https://github.com/asottile/pyupgrade/compare/v3.14.0...v3.15.0) - [github.com/psf/black: 23.9.1 → 23.10.1](https://github.com/psf/black/compare/23.9.1...23.10.1) - [github.com/pre-commit/pre-commit-hooks: v4.4.0 → v4.5.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.4.0...v4.5.0) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0500438d..78c72c32 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: # Autoformat: Python code, syntax patterns are modernized - repo: https://github.com/asottile/pyupgrade - rev: v3.14.0 + rev: v3.15.0 hooks: - id: pyupgrade args: @@ -32,7 +32,7 @@ repos: # Autoformat: Python - repo: https://github.com/psf/black - rev: 23.9.1 + rev: 23.10.1 hooks: - id: black @@ -56,7 +56,7 @@ repos: # Misc autoformatting and linting - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: end-of-file-fixer - id: requirements-txt-fixer From 5b649619783c1809105a073ef8f75c1e23db6b51 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 20 Nov 2023 09:41:17 +0100 Subject: [PATCH 14/23] Changelog for 13 --- docs/source/changelog.md | 55 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/docs/source/changelog.md b/docs/source/changelog.md index fb3d68c1..95ba0eb4 100644 --- a/docs/source/changelog.md +++ b/docs/source/changelog.md @@ -6,6 +6,61 @@ command line for details. ## [Unreleased] +## 13 + +### 13.0 2023-11 + +([full changelog](https://github.com/jupyterhub/dockerspawner/compare/12.1.0...955e64222447c22df6a708b7d63d90059303337d)) + +#### API and Breaking Changes + +- Remove deprecated, broken hub_ip_connect [#499](https://github.com/jupyterhub/dockerspawner/pull/499) ([@minrk](https://github.com/minrk)) +- Require python 3.8+ and jupyterhub 2.3.1+ [#488](https://github.com/jupyterhub/dockerspawner/pull/488) ([@consideRatio](https://github.com/consideRatio), [@minrk](https://github.com/minrk)) + +#### New features added + +- Switch default image to quay.io [#504](https://github.com/jupyterhub/dockerspawner/pull/504) ([@yuvipanda](https://github.com/yuvipanda), [@minrk](https://github.com/minrk), [@manics](https://github.com/manics)) +- allow extra_host_config and extra_create_kwargs to be callable [#500](https://github.com/jupyterhub/dockerspawner/pull/500) ([@minrk](https://github.com/minrk)) + +#### Enhancements made + +- Merge host config/create_kwargs [#501](https://github.com/jupyterhub/dockerspawner/pull/501) ([@minrk](https://github.com/minrk)) + +#### Bugs fixed + +- update object_name with current image [#466](https://github.com/jupyterhub/dockerspawner/pull/466) ([@floriandeboissieu](https://github.com/floriandeboissieu), [@minrk](https://github.com/minrk)) +- Fix imagename not to include letter ':' [#464](https://github.com/jupyterhub/dockerspawner/pull/464) ([@yamaton](https://github.com/yamaton), [@minrk](https://github.com/minrk)) +- clear object_id when removing object [#447](https://github.com/jupyterhub/dockerspawner/pull/447) ([@minrk](https://github.com/minrk), [@manics](https://github.com/manics)) + +#### Maintenance and upkeep improvements + +- pre-commit: add pyupgrade and autoflake, simplify flake8 config [#489](https://github.com/jupyterhub/dockerspawner/pull/489) ([@consideRatio](https://github.com/consideRatio), [@minrk](https://github.com/minrk)) +- Require python 3.8+ and jupyterhub 2.3.1+ [#488](https://github.com/jupyterhub/dockerspawner/pull/488) ([@consideRatio](https://github.com/consideRatio), [@minrk](https://github.com/minrk)) +- Add dependabot.yaml to bump github actions [#487](https://github.com/jupyterhub/dockerspawner/pull/487) ([@consideRatio](https://github.com/consideRatio), [@minrk](https://github.com/minrk)) +- Update release workflow and RELEASE.md, set version with tbump [#486](https://github.com/jupyterhub/dockerspawner/pull/486) ([@consideRatio](https://github.com/consideRatio), [@minrk](https://github.com/minrk)) +- Refresh test workflow and associated config, accept podmain test failure for now [#485](https://github.com/jupyterhub/dockerspawner/pull/485) ([@consideRatio](https://github.com/consideRatio), [@minrk](https://github.com/minrk)) +- Use python 3.11 on RTD [#482](https://github.com/jupyterhub/dockerspawner/pull/482) ([@minrk](https://github.com/minrk)) +- Add test strategy for JupyterHub v3.1.1 [#479](https://github.com/jupyterhub/dockerspawner/pull/479) ([@Sheila-nk](https://github.com/Sheila-nk), [@GeorgianaElena](https://github.com/GeorgianaElena), [@minrk](https://github.com/minrk)) +- test options_form and escape [#468](https://github.com/jupyterhub/dockerspawner/pull/468) ([@Sheila-nk](https://github.com/Sheila-nk), [@minrk](https://github.com/minrk)) +- test callable allowed_images and host_ip [#467](https://github.com/jupyterhub/dockerspawner/pull/467) ([@Sheila-nk](https://github.com/Sheila-nk), [@minrk](https://github.com/minrk)) +- Test jupyterhub2 [#443](https://github.com/jupyterhub/dockerspawner/pull/443) ([@manics](https://github.com/manics), [@minrk](https://github.com/minrk)) + +#### Documentation improvements + +- Add extra_create_kwargs example, plus docs readability improvements [#493](https://github.com/jupyterhub/dockerspawner/pull/493) ([@matthewwiese](https://github.com/matthewwiese), [@manics](https://github.com/manics)) +- update versions in swarm example [#454](https://github.com/jupyterhub/dockerspawner/pull/454) ([@minrk](https://github.com/minrk), [@GeorgianaElena](https://github.com/GeorgianaElena)) +- add generate-certs service to internal-ssl example [#446](https://github.com/jupyterhub/dockerspawner/pull/446) ([@minrk](https://github.com/minrk), [@manics](https://github.com/manics)) +- Add Podman to docs [#444](https://github.com/jupyterhub/dockerspawner/pull/444) ([@manics](https://github.com/manics), [@minrk](https://github.com/minrk)) + +#### Contributors to this release + +The following people contributed discussions, new ideas, code and documentation contributions, and review. +See [our definition of contributors](https://github-activity.readthedocs.io/en/latest/#how-does-this-tool-define-contributions-in-the-reports). + +([GitHub contributors page for this release](https://github.com/jupyterhub/dockerspawner/graphs/contributors?from=2021-07-22&to=2023-11-20&type=c)) + +@consideRatio ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3AconsideRatio+updated%3A2021-07-22..2023-11-20&type=Issues)) | @floriandeboissieu ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3Afloriandeboissieu+updated%3A2021-07-22..2023-11-20&type=Issues)) | @gatoniel ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3Agatoniel+updated%3A2021-07-22..2023-11-20&type=Issues)) | @GeorgianaElena ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3AGeorgianaElena+updated%3A2021-07-22..2023-11-20&type=Issues)) | @manics ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3Amanics+updated%3A2021-07-22..2023-11-20&type=Issues)) | @matthewwiese ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3Amatthewwiese+updated%3A2021-07-22..2023-11-20&type=Issues)) | @minrk ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3Aminrk+updated%3A2021-07-22..2023-11-20&type=Issues)) | @Sheila-nk ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3ASheila-nk+updated%3A2021-07-22..2023-11-20&type=Issues)) | @yamaton ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3Ayamaton+updated%3A2021-07-22..2023-11-20&type=Issues)) | @yuvipanda ([activity](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3Ayuvipanda+updated%3A2021-07-22..2023-11-20&type=Issues)) + ## 12 ### [12.1] 2021-07 From 9ec4a2d3a7a96a60a2446fc2565be24db99a8179 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 20 Nov 2023 10:36:30 +0100 Subject: [PATCH 15/23] Fix 13.0 diff url Co-authored-by: Simon Li --- docs/source/changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/changelog.md b/docs/source/changelog.md index 95ba0eb4..3edb3c8b 100644 --- a/docs/source/changelog.md +++ b/docs/source/changelog.md @@ -10,7 +10,7 @@ command line for details. ### 13.0 2023-11 -([full changelog](https://github.com/jupyterhub/dockerspawner/compare/12.1.0...955e64222447c22df6a708b7d63d90059303337d)) +([full changelog](https://github.com/jupyterhub/dockerspawner/compare/12.1.0...13.0.0)) #### API and Breaking Changes From 7bab576b97efdd8a0f27db5492020bd3c20c33e8 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 21 Nov 2023 09:11:09 +0100 Subject: [PATCH 16/23] update links, dates in changelog --- docs/source/changelog.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/source/changelog.md b/docs/source/changelog.md index 3edb3c8b..685ce379 100644 --- a/docs/source/changelog.md +++ b/docs/source/changelog.md @@ -8,7 +8,7 @@ command line for details. ## 13 -### 13.0 2023-11 +### [13.0] 2023-11-21 ([full changelog](https://github.com/jupyterhub/dockerspawner/compare/12.1.0...13.0.0)) @@ -63,7 +63,7 @@ See [our definition of contributors](https://github-activity.readthedocs.io/en/l ## 12 -### [12.1] 2021-07 +### [12.1] 2021-07-22 ([full changelog](https://github.com/jupyterhub/dockerspawner/compare/12.0.0...12.1.0)) @@ -84,7 +84,7 @@ See [our definition of contributors](https://github-activity.readthedocs.io/en/l [@1kastner](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3A1kastner+updated%3A2021-03-26..2021-07-19&type=Issues) | [@manics](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3Amanics+updated%3A2021-03-26..2021-07-19&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3Aminrk+updated%3A2021-03-26..2021-07-19&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3Awelcome+updated%3A2021-03-26..2021-07-19&type=Issues) | [@zeehio](https://github.com/search?q=repo%3Ajupyterhub%2Fdockerspawner+involves%3Azeehio+updated%3A2021-03-26..2021-07-19&type=Issues) -### [12.0] 2021-03 +### [12.0] 2021-03-26 This is a big release! @@ -347,7 +347,8 @@ Some configuration has been cleaned up to be clearer and more concise: First release -[unreleased]: https://github.com/jupyterhub/dockerspawner/compare/12.1.0...HEAD +[unreleased]: https://github.com/jupyterhub/dockerspawner/compare/13.0.0...HEAD +[13.0]: https://github.com/jupyterhub/dockerspawner/compare/12.1.0...13.0.0 [12.1]: https://github.com/jupyterhub/dockerspawner/compare/12.0.0...12.1.0 [12.0]: https://github.com/jupyterhub/dockerspawner/compare/0.11.1...12.0.0 [0.11.1]: https://github.com/jupyterhub/dockerspawner/compare/0.11.0...0.11.1 From 2b5bd22b499fc9ba5cb46435bc0461afbe507aa2 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 16 Nov 2023 11:59:13 +0100 Subject: [PATCH 17/23] allow only configured image by default avoids allowing all images when no allowed_images are configured The default of an empty collection prohibits specifying the image (even if it is the allowed image). A new value `allowed_images = "*"` can be used to explicitly allow any image. --- dockerspawner/dockerspawner.py | 39 +++++--- examples/image_form/jupyterhub_config.py | 23 +---- tests/conftest.py | 1 + tests/test_dockerspawner.py | 112 ++++++++++++++++++----- 4 files changed, 119 insertions(+), 56 deletions(-) diff --git a/dockerspawner/dockerspawner.py b/dockerspawner/dockerspawner.py index 541c300f..ea377693 100644 --- a/dockerspawner/dockerspawner.py +++ b/dockerspawner/dockerspawner.py @@ -261,43 +261,56 @@ def _ip_default(self): If a callable, will be called with the Spawner instance as its only argument. The user is accessible as spawner.user. - The callable should return a dict or list as above. + The callable should return a dict or list or None as above. + + If empty (default), the value from ``image`` is used and + any attempt to specify the image via user_options will result in an error. + + .. versionchanged:: 13 + Empty allowed_images means no user-specified images are allowed. + This is the default. + Prior to 13, restricting to single image required a length-1 list, + e.g. ``allowed_images = [image]``. + + .. versionadded:: 13 + To allow any image, specify ``allowed_images = "*"``. .. versionchanged:: 12.0 ``DockerSpawner.image_whitelist`` renamed to ``allowed_images`` - """, ) @validate('allowed_images') - def _allowed_images_dict(self, proposal): + def _validate_allowed_images(self, proposal): """cast allowed_images to a dict If passing a list, cast it to a {item:item} dict where the keys and values are the same. """ - allowed_images = proposal.value - if isinstance(allowed_images, list): + allowed_images = proposal["value"] + if isinstance(allowed_images, str): + if allowed_images != "*": + raise ValueError( + f"'*' (all images) is the only accepted string value for allowed_images, got {allowed_images!r}. Use a list: `[{allowed_images!r}]` if you want to allow just one image." + ) + elif isinstance(allowed_images, list): allowed_images = {item: item for item in allowed_images} return allowed_images def _get_allowed_images(self): """Evaluate allowed_images callable - Or return the list as-is if it's already a dict + Always returns a dict or None """ if callable(self.allowed_images): allowed_images = self.allowed_images(self) - if not isinstance(allowed_images, dict): - # always return a dict - allowed_images = {item: item for item in allowed_images} - return allowed_images + return self._validate_allowed_images({"value": allowed_images}) return self.allowed_images @default('options_form') def _default_options_form(self): allowed_images = self._get_allowed_images() - if len(allowed_images) <= 1: + if allowed_images == "*" or len(allowed_images) <= 1: # default form only when there are images to choose from return '' # form derived from wrapspawner.ProfileSpawner @@ -1065,8 +1078,10 @@ async def remove_object(self): async def check_allowed(self, image): allowed_images = self._get_allowed_images() - if not allowed_images: + if allowed_images == "*": return image + elif not allowed_images: + raise web.HTTPError(400, "Specifying image to launch is not allowed") if image not in allowed_images: raise web.HTTPError( 400, diff --git a/examples/image_form/jupyterhub_config.py b/examples/image_form/jupyterhub_config.py index 34447adc..207818fc 100644 --- a/examples/image_form/jupyterhub_config.py +++ b/examples/image_form/jupyterhub_config.py @@ -13,26 +13,11 @@ def get_options_form(spawner): c.DockerSpawner.options_form = get_options_form -from dockerspawner import DockerSpawner +# specify that DockerSpawner should accept any image from user input +c.DockerSpawner.allowed_images = "*" - -class CustomDockerSpawner(DockerSpawner): - def options_from_form(self, formdata): - options = {} - image_form_list = formdata.get("image", []) - if image_form_list and image_form_list[0]: - options["image"] = image_form_list[0].strip() - self.log.info(f"User selected image: {options['image']}") - return options - - def load_user_options(self, options): - image = options.get("image") - if image: - self.log.info(f"Loading image {image}") - self.image = image - - -c.JupyterHub.spawner_class = CustomDockerSpawner +# tell JupyterHub to use DockerSpawner +c.JupyterHub.spawner_class = "docker" # the rest of the config is testing boilerplate # to make the Hub connectable from the containers diff --git a/tests/conftest.py b/tests/conftest.py index 0db1f925..b191eb77 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,6 +15,7 @@ from jupyterhub.tests.conftest import event_loop # noqa: F401 from jupyterhub.tests.conftest import io_loop # noqa: F401 from jupyterhub.tests.conftest import ssl_tmpdir # noqa: F401 +from jupyterhub.tests.conftest import user # noqa: F401 from jupyterhub.tests.mocking import MockHub from dockerspawner import DockerSpawner, SwarmSpawner, SystemUserSpawner diff --git a/tests/test_dockerspawner.py b/tests/test_dockerspawner.py index 9c970c5f..51eca880 100644 --- a/tests/test_dockerspawner.py +++ b/tests/test_dockerspawner.py @@ -84,32 +84,89 @@ async def test_start_stop(dockerspawner_configured_app, remove): def allowed_images_callable(*_): - return ["jupyterhub/singleuser:1.0", "jupyterhub/singleuser:1.1"] + return ["quay.io/jupyterhub/singleuser:4.0", "quay.io/jupyterhub/singleuser:4"] @pytest.mark.parametrize( - "allowed_images, image", + "allowed_images, image, ok", [ ( { - "1.0": "jupyterhub/singleuser:1.0", - "1.1": "jupyterhub/singleuser:1.1", + "4.0": "quay.io/jupyterhub/singleuser:4.0", + "4": "quay.io/jupyterhub/singleuser:4", }, - "1.0", + "4.0", + True, + ), + ( + { + "4.0": "quay.io/jupyterhub/singleuser:4.0", + "4": "quay.io/jupyterhub/singleuser:4", + }, + None, + True, + ), + ( + [ + "quay.io/jupyterhub/singleuser:4", + "quay.io/jupyterhub/singleuser:4.0", + ], + "not-in-list", + False, + ), + ( + [ + "quay.io/jupyterhub/singleuser:4.0", + "quay.io/jupyterhub/singleuser:4", + ], + "quay.io/jupyterhub/singleuser:4", + True, + ), + ( + allowed_images_callable, + "quay.io/jupyterhub/singleuser:4.0", + True, + ), + ( + allowed_images_callable, + "quay.io/jupyterhub/singleuser:3.0", + False, + ), + ( + None, + "DEFAULT", + False, + ), + ( + None, + None, + True, + ), + ( + # explicitly allow all + "*", + "quay.io/jupyterhub/singleuser:4", + True, ), - (["jupyterhub/singleuser:1.0", "jupyterhub/singleuser:1.1.0"], "1.1.0"), - (allowed_images_callable, "1.0"), ], ) -async def test_allowed_image(dockerspawner_configured_app, allowed_images, image): +async def test_allowed_image( + user, dockerspawner_configured_app, allowed_images, image, ok +): app = dockerspawner_configured_app - name = "checker" - add_user(app.db, app, name=name) - user = app.users[name] + name = user.name assert isinstance(user.spawner, DockerSpawner) + default_image = user.spawner.image # default value + if image == "DEFAULT": + image = default_image user.spawner.remove_containers = True - user.spawner.allowed_images = allowed_images - token = user.new_api_token() + if allowed_images is not None: + user.spawner.allowed_images = allowed_images + + if image: + request_body = json.dumps({"image": image}) + else: + request_body = b"" # start the server r = await api_request( app, @@ -117,29 +174,34 @@ async def test_allowed_image(dockerspawner_configured_app, allowed_images, image name, "server", method="post", - data=json.dumps({"image": image}), + data=request_body, ) - if image not in user.spawner._get_allowed_images(): - with pytest.raises(Exception): - r.raise_for_status() + if not ok: + assert r.status_code == 400 return + else: + r.raise_for_status() + pending = r.status_code == 202 while pending: # request again - await asyncio.sleep(2) + await asyncio.sleep(1) r = await api_request(app, "users", name) user_info = r.json() pending = user_info["servers"][""]["pending"] - url = url_path_join(public_url(app, user), "api/status") - resp = await AsyncHTTPClient().fetch( - url, headers={"Authorization": "token %s" % token} - ) - assert resp.effective_url == url - resp.rethrow() + if image is None: + expected_image = default_image + elif isinstance(allowed_images, (list, dict)): + expected_image = user.spawner._get_allowed_images()[image] + else: + expected_image = image + + assert user.spawner.image == expected_image + obj = await user.spawner.get_object() + assert obj["Config"]["Image"] == expected_image - assert resp.headers['x-jupyterhub-version'].startswith(image) r = await api_request( app, "users", From d73244e97ba9c0e6e6eadbd878ff6d4d5dce3f56 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 21 Nov 2023 09:15:37 +0100 Subject: [PATCH 18/23] Changelog note for GHSA-hfgr-h3vc-p6c2 --- docs/source/changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/source/changelog.md b/docs/source/changelog.md index 685ce379..0ccb0dcc 100644 --- a/docs/source/changelog.md +++ b/docs/source/changelog.md @@ -12,8 +12,12 @@ command line for details. ([full changelog](https://github.com/jupyterhub/dockerspawner/compare/12.1.0...13.0.0)) +13.0 Fixes security vulnerability GHSA-hfgr-h3vc-p6c2, which allowed authenticated users to spawn arbitrary images +unless `DockerSpawner.allowed_images` was specified. + #### API and Breaking Changes +- Add and require `DockerSpawner.allowed_images='*'` to allow any image to be spawned via `user_options`. (GHSA-hfgr-h3vc-p6c2) - Remove deprecated, broken hub_ip_connect [#499](https://github.com/jupyterhub/dockerspawner/pull/499) ([@minrk](https://github.com/minrk)) - Require python 3.8+ and jupyterhub 2.3.1+ [#488](https://github.com/jupyterhub/dockerspawner/pull/488) ([@consideRatio](https://github.com/consideRatio), [@minrk](https://github.com/minrk)) From e54ecf4f36e9275ec1afb8993cd9736369c1b0da Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 21 Nov 2023 15:13:28 +0100 Subject: [PATCH 19/23] Bump to 13.0.0 --- dockerspawner/_version.py | 2 +- pyproject.toml | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dockerspawner/_version.py b/dockerspawner/_version.py index d449722c..b5c46143 100644 --- a/dockerspawner/_version.py +++ b/dockerspawner/_version.py @@ -1,7 +1,7 @@ # __version__ should be updated using tbump, based on configuration in # pyproject.toml, according to instructions in RELEASE.md. # -__version__ = "12.2.0.dev" +__version__ = "13.0.0" # version_info looks like (1, 2, 3, "dev") if __version__ is 1.2.3.dev version_info = tuple(int(p) if p.isdigit() else p for p in __version__.split(".")) diff --git a/pyproject.toml b/pyproject.toml index efed1102..9e4e7cdf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,7 @@ markers = [ github_url = "https://github.com/jupyterhub/dockerspawner" [tool.tbump.version] -current = "12.2.0.dev" +current = "13.0.0" regex = ''' (?P\d+) \. diff --git a/setup.py b/setup.py index 655b6395..e4693462 100644 --- a/setup.py +++ b/setup.py @@ -46,7 +46,7 @@ def run(self): setup_args = dict( name='dockerspawner', packages=['dockerspawner'], - version="12.2.0.dev", + version="13.0.0", description="""Dockerspawner: A custom spawner for Jupyterhub.""", long_description="Spawn single-user servers with Docker.", author="Jupyter Development Team", From 749daed9094629c7df8db60b38b7a162b5f03d4c Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 21 Nov 2023 15:13:42 +0100 Subject: [PATCH 20/23] Bump to 13.1.0.dev --- dockerspawner/_version.py | 2 +- pyproject.toml | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dockerspawner/_version.py b/dockerspawner/_version.py index b5c46143..7c5ef208 100644 --- a/dockerspawner/_version.py +++ b/dockerspawner/_version.py @@ -1,7 +1,7 @@ # __version__ should be updated using tbump, based on configuration in # pyproject.toml, according to instructions in RELEASE.md. # -__version__ = "13.0.0" +__version__ = "13.1.0.dev" # version_info looks like (1, 2, 3, "dev") if __version__ is 1.2.3.dev version_info = tuple(int(p) if p.isdigit() else p for p in __version__.split(".")) diff --git a/pyproject.toml b/pyproject.toml index 9e4e7cdf..41a2d933 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,7 @@ markers = [ github_url = "https://github.com/jupyterhub/dockerspawner" [tool.tbump.version] -current = "13.0.0" +current = "13.1.0.dev" regex = ''' (?P\d+) \. diff --git a/setup.py b/setup.py index e4693462..6fde6fcc 100644 --- a/setup.py +++ b/setup.py @@ -46,7 +46,7 @@ def run(self): setup_args = dict( name='dockerspawner', packages=['dockerspawner'], - version="13.0.0", + version="13.1.0.dev", description="""Dockerspawner: A custom spawner for Jupyterhub.""", long_description="Spawn single-user servers with Docker.", author="Jupyter Development Team", From 5b99afe37559cd053befb2311767ae9200c0f1be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 06:00:04 +0000 Subject: [PATCH 21/23] Bump actions/setup-python from 4 to 5 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yaml | 2 +- .github/workflows/test.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0958a28a..f119e391 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -34,7 +34,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: "3.11" diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 1e72e312..42901e8f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -46,7 +46,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - uses: actions/setup-node@v4 From d76b525be50f8b04bd33c9be6cc1c11f68591e43 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 4 Jan 2024 10:32:10 +0100 Subject: [PATCH 22/23] temporary pin for pytest-asyncio --- dev-requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index 337b1d3d..b899b3e1 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,5 +1,6 @@ netifaces notebook<7 pytest>=3.6 -pytest-asyncio +# FIXME: unpin pytest-asyncio +pytest-asyncio>=0.17,<0.23 pytest-cov From 609dd684568194326118c4203302b6d60147179d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Feb 2024 05:32:28 +0000 Subject: [PATCH 23/23] Bump codecov/codecov-action from 3 to 4 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3 to 4. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v3...v4) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 42901e8f..3321d137 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -127,4 +127,4 @@ jobs: pytest tests/test_dockerspawner.py --cov=dockerspawner # GitHub action reference: https://github.com/codecov/codecov-action - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v4