Skip to content

Commit c2d0f35

Browse files
authored
Merge branch 'jupyterhub:main' into main
2 parents 400f7de + a6696e9 commit c2d0f35

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+749
-321
lines changed

.github/dependabot.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,15 @@ updates:
1515
interval: monthly
1616
time: "05:00"
1717
timezone: Etc/UTC
18+
- package-ecosystem: pip
19+
directory: /images/hub/unfrozen
20+
labels: [breaking]
21+
groups:
22+
major-versions:
23+
update-types: [major]
24+
exclude-patterns:
25+
- jupyterhub # bumped by other automation
26+
schedule:
27+
interval: daily
28+
time: "05:00"
29+
timezone: Etc/UTC

.github/workflows/test-chart.yaml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,14 @@ jobs:
137137
--set hub.image.name=quay.io/jupyterhub/k8s-hub-slim
138138
--set prePuller.hook.enabled=true
139139
--set prePuller.hook.pullOnlyOnChanges=true
140-
- k3s-channel: v1.29 # also test hub.existingSecret
140+
- k3s-channel: v1.31 # also test hub.existingSecret and subdomain_host
141141
test: install
142142
local-chart-extra-args: >-
143143
--set hub.existingSecret=test-hub-existing-secret
144144
--set proxy.secretToken=aaaa1111
145145
--set hub.cookieSecret=bbbb2222
146146
--set hub.config.CryptKeeper.keys[0]=cccc3333
147+
--set hub.config.JupyterHub.subdomain_host=jupyterhub.example.org
147148
create-k8s-test-resources: true
148149

149150
# We run three upgrade tests where we first install an already released
@@ -160,7 +161,7 @@ jobs:
160161
# information from
161162
# https://hub.jupyter.org/helm-chart/info.json
162163
#
163-
- k3s-channel: v1.28
164+
- k3s-channel: v1.30
164165
test: upgrade
165166
upgrade-from: stable
166167
upgrade-from-extra-args: >-
@@ -173,7 +174,7 @@ jobs:
173174
--set hub.db.type=sqlite-pvc
174175
--set singleuser.storage.type=dynamic
175176
create-k8s-test-resources: true
176-
- k3s-channel: v1.27
177+
- k3s-channel: v1.29
177178
test: upgrade
178179
upgrade-from: dev
179180
upgrade-from-extra-args: >-
@@ -183,7 +184,7 @@ jobs:
183184
local-chart-extra-args: >-
184185
--set hub.db.type=sqlite-pvc
185186
--set singleuser.storage.type=dynamic
186-
- k3s-channel: v1.26
187+
- k3s-channel: v1.28
187188
test: upgrade
188189
# We're testing hub.db.upgrade with PostgreSQL so this version must be old
189190
# enough to require a DB upgrade
@@ -203,7 +204,7 @@ jobs:
203204
create-k8s-test-resources: true
204205
# https://artifacthub.io/packages/helm/bitnami/postgresql
205206
setup-postgresql-args: >-
206-
--version=11.6.13
207+
--version=16.0.5
207208
--set auth.enablePostgresUser=true
208209
--set auth.postgresPassword=postgres
209210
--set auth.database=jupyterhub
@@ -368,6 +369,9 @@ jobs:
368369
continue-on-error: ${{ matrix.accept-failure == true }}
369370
run: |
370371
. ./ci/common
372+
if [ "${{ contains(matrix.local-chart-extra-args, 'subdomain_host') }}" = "true" ]; then
373+
export CI_SUBDOMAIN_HOST=jupyterhub.example.org
374+
fi
371375
# If you have problems with the tests add '--capture=no' to show stdout
372376
pytest --verbose --maxfail=2 --color=yes ./tests
373377

.github/workflows/vuln-scan.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ jobs:
8787
# Action reference: https://github.com/aquasecurity/trivy-action
8888
- name: Scan latest published image
8989
id: scan_1
90-
uses: aquasecurity/trivy-action@fd25fed6972e341ff0007ddb61f77e88103953c2
90+
uses: aquasecurity/trivy-action@6e7b7d1fd3e4fef0c5fa8cce1229c54b2c9bd0d8
9191
with:
9292
image-ref: ${{ steps.image.outputs.spec }}
9393
format: json # ref: https://github.com/aquasecurity/trivy#save-the-results-as-json
@@ -112,7 +112,7 @@ jobs:
112112
- name: Scan rebuilt image
113113
id: scan_2
114114
if: steps.rebuild.outcome == 'success'
115-
uses: aquasecurity/trivy-action@fd25fed6972e341ff0007ddb61f77e88103953c2
115+
uses: aquasecurity/trivy-action@6e7b7d1fd3e4fef0c5fa8cce1229c54b2c9bd0d8
116116
with:
117117
image-ref: rebuilt-image
118118
format: json # ref: https://github.com/aquasecurity/trivy#save-the-results-as-json
@@ -171,7 +171,7 @@ jobs:
171171
172172
- name: Describe vulnerabilities
173173
if: steps.rebuild.outcome == 'success'
174-
uses: aquasecurity/trivy-action@fd25fed6972e341ff0007ddb61f77e88103953c2
174+
uses: aquasecurity/trivy-action@6e7b7d1fd3e4fef0c5fa8cce1229c54b2c9bd0d8
175175
with:
176176
image-ref: rebuilt-image
177177
format: table
@@ -205,7 +205,7 @@ jobs:
205205
# ref: https://github.com/peter-evans/create-pull-request
206206
- name: Create or update a PR
207207
if: steps.analyze.outputs.proceed == 'yes' && github.event_name != 'pull_request'
208-
uses: peter-evans/create-pull-request@v6
208+
uses: peter-evans/create-pull-request@v7
209209
with:
210210
token: "${{ secrets.jupyterhub_bot_pat }}"
211211
author: JupterHub Bot Account <[email protected]>

.github/workflows/watch-dependencies.yaml

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# - Watch multiple images tags referenced in values.yaml to match the latest
55
# image tag.
66
#
7-
# - Watch the jupyterhub pinning in images/*/requirements.in to match the
7+
# - Watch the jupyterhub pinning in images/*/unfrozen/requirements.txt to match the
88
# latest jupyterhub version available on PyPI, and if doing this, also
99
# refreeze images/*/requirements.txt.
1010
#
@@ -20,7 +20,7 @@ name: Watch dependencies
2020
on:
2121
push:
2222
paths:
23-
- "images/*/requirements.in"
23+
- "images/*/unfrozen/requirements.txt"
2424
- ".github/workflows/watch-dependencies.yaml"
2525
branches: ["main"]
2626
schedule:
@@ -68,7 +68,7 @@ jobs:
6868
registry: registry.k8s.io
6969
repository: kube-scheduler
7070
values_path: scheduling.userScheduler.image.tag
71-
version_startswith: "v1.28"
71+
version_startswith: "v1.30"
7272
version_patch_regexp_group_suffix: ""
7373

7474
- name: pause
@@ -114,13 +114,13 @@ jobs:
114114
# ref: https://github.com/peter-evans/create-pull-request
115115
- name: Create a PR
116116
if: steps.local.outputs.tag != steps.latest.outputs.tag
117-
uses: peter-evans/create-pull-request@v6
117+
uses: peter-evans/create-pull-request@v7
118118
with:
119119
token: "${{ secrets.jupyterhub_bot_pat }}"
120120
author: JupterHub Bot Account <[email protected]>
121121
committer: JupterHub Bot Account <[email protected]>
122122
branch: update-image-${{ matrix.name }}
123-
labels: maintenance,dependencies
123+
labels: dependencies
124124
commit-message: Update ${{ matrix.repository }} version from ${{ steps.local.outputs.tag }} to ${{ steps.latest.outputs.tag }}
125125
title: Update ${{ matrix.repository }} version from ${{ steps.local.outputs.tag }} to ${{ steps.latest.outputs.tag }}
126126
body: >-
@@ -142,10 +142,10 @@ jobs:
142142
- name: Install Python dependencies
143143
run: pip install packaging requests
144144

145-
- name: Get images/hub/requirements.in pinned version of jupyterhub
145+
- name: Get images/hub/unfrozen/requirements.txt pinned version of jupyterhub
146146
id: local
147147
run: |
148-
local_version=$(cat images/hub/requirements.in | grep 'jupyterhub==' | sed 's/jupyterhub==//')
148+
local_version=$(cat images/hub/unfrozen/requirements.txt | grep 'jupyterhub==' | sed 's/jupyterhub==//')
149149
echo "version=$local_version" >> $GITHUB_OUTPUT
150150
151151
- name: Get latest version of jupyterhub
@@ -168,11 +168,11 @@ jobs:
168168
if: steps.local.outputs.version != steps.latest.outputs.version
169169
run: |
170170
for img in hub singleuser-sample; do
171-
sed --in-place 's/jupyterhub==${{ steps.local.outputs.version }}/jupyterhub==${{ steps.latest.outputs.version }}/g' images/$img/requirements.in
171+
sed --in-place 's/jupyterhub==${{ steps.local.outputs.version }}/jupyterhub==${{ steps.latest.outputs.version }}/g' images/$img/unfrozen/requirements.txt
172172
done
173173
sed --in-place 's/appVersion: "${{ steps.local.outputs.version }}"/appVersion: "${{ steps.latest.outputs.version }}"/g' jupyterhub/Chart.yaml
174174
175-
- name: Refreeze images/*/requirements.txt based on images/*/requirements.in
175+
- name: Refreeze images/*/requirements.txt based on images/*/unfrozen/requirements.txt
176176
if: steps.local.outputs.version != steps.latest.outputs.version
177177
run: ci/refreeze
178178

@@ -183,13 +183,13 @@ jobs:
183183
# ref: https://github.com/peter-evans/create-pull-request
184184
- name: Create a PR
185185
if: steps.local.outputs.version != steps.latest.outputs.version
186-
uses: peter-evans/create-pull-request@v6
186+
uses: peter-evans/create-pull-request@v7
187187
with:
188188
token: "${{ secrets.jupyterhub_bot_pat }}"
189189
author: JupterHub Bot Account <[email protected]>
190190
committer: JupterHub Bot Account <[email protected]>
191191
branch: update-jupyterhub
192-
labels: maintenance,dependencies
192+
labels: dependencies
193193
commit-message: Update jupyterhub from ${{ steps.local.outputs.version }} to ${{ steps.latest.outputs.version }}
194194
title: Update jupyterhub from ${{ steps.local.outputs.version }} to ${{ steps.latest.outputs.version }}
195195
body: >-
@@ -208,15 +208,15 @@ jobs:
208208
steps:
209209
- uses: actions/checkout@v4
210210

211-
- name: Refreeze images/*/requirements.txt based on images/*/requirements.in
211+
- name: Refreeze images/*/requirements.txt based on images/*/unfrozen/requirements.txt
212212
run: ci/refreeze
213213

214214
- name: git diff
215215
run: git --no-pager diff --color=always
216216

217217
# ref: https://github.com/peter-evans/create-pull-request
218218
- name: Create a PR
219-
uses: peter-evans/create-pull-request@v6
219+
uses: peter-evans/create-pull-request@v7
220220
with:
221221
token: "${{ secrets.jupyterhub_bot_pat }}"
222222
author: JupyterHub Bot Account <[email protected]>
@@ -227,4 +227,4 @@ jobs:
227227
title: "hub image: refreeze requirements.txt"
228228
body: >-
229229
The hub image's requirements.txt has been refrozen based on
230-
requirements.in.
230+
unfrozen/requirements.txt.

.pre-commit-config.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@
2121
repos:
2222
# Autoformat: Python code, syntax patterns are modernized
2323
- repo: https://github.com/asottile/pyupgrade
24-
rev: v3.15.2
24+
rev: v3.19.0
2525
hooks:
2626
- id: pyupgrade
2727
args:
2828
- --py38-plus
2929

3030
# Autoformat: Python code
3131
- repo: https://github.com/psf/black
32-
rev: 24.4.2
32+
rev: 24.10.0
3333
hooks:
3434
- id: black
3535
args:
@@ -67,12 +67,12 @@ repos:
6767

6868
# Linting: Python code (see the file .flake8)
6969
- repo: https://github.com/PyCQA/flake8
70-
rev: "7.0.0"
70+
rev: "7.1.1"
7171
hooks:
7272
- id: flake8
7373

7474
- repo: https://github.com/gruntwork-io/pre-commit
75-
rev: v0.1.23
75+
rev: v0.1.24
7676
hooks:
7777
# This requires shellcheck to be installed manually so is disabled by default
7878
- id: shellcheck

chartpress.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ charts:
2020
#
2121
# baseVersion should be managed via tbump, see RELEASE.md for details
2222
#
23-
baseVersion: "4.0.0-0.dev"
23+
baseVersion: "4.0.1-0.dev"
2424
repo:
2525
git: jupyterhub/helm-chart
2626
published: https://jupyterhub.github.io/helm-chart

ci/refreeze

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ for img in ${IMAGES}; do
1313
--volume="$PWD:/io" \
1414
--workdir=/io \
1515
--user=root \
16-
python:3.11-bullseye \
17-
sh -c 'pip install pip-tools==6.* && pip-compile --resolver=backtracking --upgrade'
16+
python:3.12-bookworm \
17+
sh -c 'pip install pip-tools==7.* && pip-compile --allow-unsafe --strip-extras --upgrade --output-file=requirements.txt unfrozen/requirements.txt'
1818
popd
1919
done

docs/source/administrator/authentication.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -444,11 +444,9 @@ hub:
444444
username_claim: preferred_username
445445
userdata_params:
446446
state: state
447-
# In order to use keycloak client's roles as authorization layer
448-
claim_groups_key: roles
449-
allowed_groups:
450-
- user
451-
admin_groups:
447+
# Allow all Keycloak users
448+
allow_all: true
449+
admin_users:
452450
- admin
453451
JupyterHub:
454452
authenticator_class: generic-oauth

docs/source/administrator/debug.md

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -74,19 +74,6 @@ settings for the pod. The final section you'll see is a list of recent
7474
events. These can be particularly informative, as often an error will
7575
show up in this section.
7676

77-
**Real world scenario:** In our case, one of the lines in the events page
78-
displays an error:
79-
80-
```
81-
$ kubectl describe pod jupyter-choldgraf --namespace <k8s-namespace>
82-
...
83-
2m 52s 4 kubelet, gke-jhubtest-default-pool-52c36683-jv6r spec.containers{notebook} Warning Failed Failed to pull image "jupyter/scipy-notebook:v0.4": rpc error: code = 2 desc = Error response from daemon: {"message":"manifest for jupyter/scipy-notebook:v0.4 not found"}
84-
...
85-
```
86-
87-
It seems there is indeed something wrong with the Docker image. Let's confirm
88-
this by getting another view on the events that have transpired in the pod.
89-
9077
### `kubectl logs`
9178

9279
If you only want to see the latest logs for a pod, use the following command:
@@ -99,37 +86,7 @@ This will show you the logs from the pod, which often contain useful
9986
information about what is going wrong. Parse these logs
10087
to see if something is generating an error.
10188

102-
**Real world scenario:** In our case, we get this line back:
103-
104-
```
105-
$ kubectl logs jupyter-choldgraf --namespace <k8s-namespace>
106-
Error from server (BadRequest): container "notebook" in pod "jupyter-choldgraf" is waiting to start: trying and failing to pull image
107-
```
108-
109-
Now we are sure that something is wrong with our Dockerfile. Let's check
110-
our `config.yaml` file for the section where we specify the user's
111-
Docker image. Here we see our problem:
112-
113-
```yaml
114-
singleuser:
115-
image:
116-
name: jupyter/scipy-notebook
117-
```
118-
119-
We haven't specified a `tag` for our Docker image! Not specifying a tag
120-
will cause it to default to `v0.4`, which isn't what we want and is causing
121-
the pod to fail.
122-
123-
To fix this, let's add a tag to our `config.yaml` file:
124-
125-
```yaml
126-
singleuser:
127-
image:
128-
name: jupyter/scipy-notebook
129-
tag: ae885c0a6226
130-
```
131-
132-
Then run a helm upgrade:
89+
When you have identified the error edit your `config.yaml` if necessary, then run a helm upgrade:
13390

13491
```
13592
helm upgrade --cleanup-on-fail jhub jupyterhub/jupyterhub --version=<chart-version> -f config.yaml

docs/source/administrator/security.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,3 +489,44 @@ proxy:
489489
```
490490
491491
This would restrict the access to only two IP addresses: `111.111.111.111` and `222.222.222.222`.
492+
493+
(jupyterhub_subdomains)=
494+
495+
## Host user servers on a subdomain
496+
497+
You can reduce the chance of cross-origin attacks by giving each user
498+
their own subdomain `<user>.jupyter.example.org`.
499+
This requires setting [`subdomain_host`](schema_hub.config.JupyterHub.subdomain_host), creating a wildcard DNS record `*.jupyter.example.org`, and creating a wildcard SSL certificate.
500+
501+
```yaml
502+
hub:
503+
config:
504+
JupyterHub:
505+
subdomain_host: jupyter.example.org
506+
```
507+
508+
If you are using a Kubernetes ingress this must include hosts
509+
`jupyter.example.org` and `*.jupyter.example.org`.
510+
For example:
511+
512+
```yaml
513+
ingress:
514+
enabled: true
515+
hosts:
516+
- jupyter.example.org
517+
- "*.jupyter.example.org"
518+
tls:
519+
- hosts:
520+
- jupyter.example.org
521+
- "*.jupyter.example.org"
522+
secretName: example-tls
523+
```
524+
525+
where `example-tls` is the name of a Kubernetes secret containing the wildcard certificate and key.
526+
527+
The chart does not support the automatic creation of wildcard HTTPS certificates.
528+
You must obtain a certificate from an external source,
529+
for example by using an ACME client such as [cert-manager with the DNS-01 challenge](https://cert-manager.io/docs/configuration/acme/dns01/),
530+
and ensure the certificate and key are stored in the secret.
531+
532+
See {ref}`jupyterhub:subdomains` in the JupyterHub documentation for more information.

0 commit comments

Comments
 (0)