@@ -16,6 +16,12 @@ def test_cli_args(container, http_client):
16
16
resp .raise_for_status ()
17
17
logs = c .logs (stdout = True ).decode ("utf-8" )
18
18
LOGGER .debug (logs )
19
+ assert "ERROR" not in logs
20
+ warnings = [
21
+ warning for warning in logs .split ("\n " ) if warning .startswith ("WARNING" )
22
+ ]
23
+ assert len (warnings ) == 1
24
+ assert warnings [0 ].startswith ("WARNING: Jupyter Notebook deprecation notice" )
19
25
assert "login_submit" not in resp .text
20
26
21
27
@@ -24,7 +30,7 @@ def test_unsigned_ssl(container, http_client):
24
30
"""Container should generate a self-signed SSL certificate
25
31
and notebook server should use it to enable HTTPS.
26
32
"""
27
- container .run (environment = ["GEN_CERT=yes" ])
33
+ c = container .run (environment = ["GEN_CERT=yes" ])
28
34
# NOTE: The requests.Session backing the http_client fixture does not retry
29
35
# properly while the server is booting up. An SSL handshake error seems to
30
36
# abort the retry logic. Forcing a long sleep for the moment until I have
@@ -33,6 +39,13 @@ def test_unsigned_ssl(container, http_client):
33
39
resp = http_client .get ("https://localhost:8888" , verify = False )
34
40
resp .raise_for_status ()
35
41
assert "login_submit" in resp .text
42
+ logs = c .logs (stdout = True ).decode ("utf-8" )
43
+ assert "ERROR" not in logs
44
+ warnings = [
45
+ warning for warning in logs .split ("\n " ) if warning .startswith ("WARNING" )
46
+ ]
47
+ assert len (warnings ) == 1
48
+ assert warnings [0 ].startswith ("WARNING: Jupyter Notebook deprecation notice" )
36
49
37
50
38
51
def test_uid_change (container ):
@@ -45,6 +58,9 @@ def test_uid_change(container):
45
58
)
46
59
# usermod is slow so give it some time
47
60
rv = c .wait (timeout = 120 )
61
+ logs = c .logs (stdout = True ).decode ("utf-8" )
62
+ assert "ERROR" not in logs
63
+ assert "WARNING" not in logs
48
64
assert rv == 0 or rv ["StatusCode" ] == 0
49
65
assert "uid=1010(jovyan)" in c .logs (stdout = True ).decode ("utf-8" )
50
66
@@ -60,6 +76,8 @@ def test_gid_change(container):
60
76
rv = c .wait (timeout = 10 )
61
77
assert rv == 0 or rv ["StatusCode" ] == 0
62
78
logs = c .logs (stdout = True ).decode ("utf-8" )
79
+ assert "ERROR" not in logs
80
+ assert "WARNING" not in logs
63
81
assert "gid=110(jovyan)" in logs
64
82
assert "groups=110(jovyan),100(users)" in logs
65
83
@@ -79,6 +97,8 @@ def test_nb_user_change(container):
79
97
time .sleep (10 )
80
98
LOGGER .info (f"Checking if the user is changed to { nb_user } by the start script ..." )
81
99
output = running_container .logs (stdout = True ).decode ("utf-8" )
100
+ assert "ERROR" not in output
101
+ assert "WARNING" not in output
82
102
assert (
83
103
f"username: jovyan -> { nb_user } " in output
84
104
), f"User is not changed to { nb_user } "
@@ -134,6 +154,8 @@ def test_chown_extra(container):
134
154
rv = c .wait (timeout = 120 )
135
155
assert rv == 0 or rv ["StatusCode" ] == 0
136
156
logs = c .logs (stdout = True ).decode ("utf-8" )
157
+ assert "ERROR" not in logs
158
+ assert "WARNING" not in logs
137
159
assert "/home/jovyan/.bashrc:1010:101" in logs
138
160
assert "/opt/conda/bin/jupyter:1010:101" in logs
139
161
@@ -156,6 +178,8 @@ def test_chown_home(container):
156
178
rv = c .wait (timeout = 120 )
157
179
assert rv == 0 or rv ["StatusCode" ] == 0
158
180
logs = c .logs (stdout = True ).decode ("utf-8" )
181
+ assert "ERROR" not in logs
182
+ assert "WARNING" not in logs
159
183
assert "/home/kitten/.bashrc:1010:101" in logs
160
184
161
185
@@ -169,7 +193,10 @@ def test_sudo(container):
169
193
)
170
194
rv = c .wait (timeout = 10 )
171
195
assert rv == 0 or rv ["StatusCode" ] == 0
172
- assert "uid=0(root)" in c .logs (stdout = True ).decode ("utf-8" )
196
+ logs = c .logs (stdout = True ).decode ("utf-8" )
197
+ assert "ERROR" not in logs
198
+ assert "WARNING" not in logs
199
+ assert "uid=0(root)" in logs
173
200
174
201
175
202
def test_sudo_path (container ):
@@ -183,6 +210,8 @@ def test_sudo_path(container):
183
210
rv = c .wait (timeout = 10 )
184
211
assert rv == 0 or rv ["StatusCode" ] == 0
185
212
logs = c .logs (stdout = True ).decode ("utf-8" )
213
+ assert "ERROR" not in logs
214
+ assert "WARNING" not in logs
186
215
assert logs .rstrip ().endswith ("/opt/conda/bin/jupyter" )
187
216
188
217
@@ -196,24 +225,75 @@ def test_sudo_path_without_grant(container):
196
225
rv = c .wait (timeout = 10 )
197
226
assert rv == 0 or rv ["StatusCode" ] == 0
198
227
logs = c .logs (stdout = True ).decode ("utf-8" )
228
+ assert "ERROR" not in logs
229
+ assert "WARNING" not in logs
199
230
assert logs .rstrip ().endswith ("/opt/conda/bin/jupyter" )
200
231
201
232
202
- def test_group_add (container , tmpdir ):
233
+ def test_group_add (container ):
203
234
"""Container should run with the specified uid, gid, and secondary
204
- group.
235
+ group. It won't be possible to modify /etc/passwd since gid is nonzero, so
236
+ additionally verify that setting gid=0 is suggested in a warning.
205
237
"""
206
238
c = container .run (
207
239
user = "1010:1010" ,
208
- group_add = ["users" ],
240
+ group_add = ["users" ], # Ensures write access to /home/jovyan
209
241
command = ["start.sh" , "id" ],
210
242
)
211
243
rv = c .wait (timeout = 5 )
212
244
assert rv == 0 or rv ["StatusCode" ] == 0
213
245
logs = c .logs (stdout = True ).decode ("utf-8" )
246
+ assert "ERROR" not in logs
247
+ warnings = [
248
+ warning for warning in logs .split ("\n " ) if warning .startswith ("WARNING" )
249
+ ]
250
+ assert len (warnings ) == 1
251
+ assert "Try setting gid=0" in warnings [0 ]
214
252
assert "uid=1010 gid=1010 groups=1010,100(users)" in logs
215
253
216
254
255
+ def test_set_uid (container ):
256
+ """Container should run with the specified uid and NB_USER.
257
+ The /home/jovyan directory will not be writable since it's owned by 1000:users.
258
+ Additionally verify that "--group-add=users" is suggested in a warning to restore
259
+ write access.
260
+ """
261
+ c = container .run (
262
+ user = "1010" ,
263
+ command = ["start.sh" , "id" ],
264
+ )
265
+ rv = c .wait (timeout = 5 )
266
+ assert rv == 0 or rv ["StatusCode" ] == 0
267
+ logs = c .logs (stdout = True ).decode ("utf-8" )
268
+ assert "ERROR" not in logs
269
+ assert "uid=1010(jovyan) gid=0(root)" in logs
270
+ warnings = [
271
+ warning for warning in logs .split ("\n " ) if warning .startswith ("WARNING" )
272
+ ]
273
+ assert len (warnings ) == 1
274
+ assert "--group-add=users" in warnings [0 ]
275
+
276
+
277
+ def test_set_uid_and_nb_user (container ):
278
+ """Container should run with the specified uid and NB_USER."""
279
+ c = container .run (
280
+ user = "1010" ,
281
+ environment = ["NB_USER=kitten" ],
282
+ group_add = ["users" ], # Ensures write access to /home/jovyan
283
+ command = ["start.sh" , "id" ],
284
+ )
285
+ rv = c .wait (timeout = 5 )
286
+ assert rv == 0 or rv ["StatusCode" ] == 0
287
+ logs = c .logs (stdout = True ).decode ("utf-8" )
288
+ assert "ERROR" not in logs
289
+ assert "uid=1010(kitten) gid=0(root)" in logs
290
+ warnings = [
291
+ warning for warning in logs .split ("\n " ) if warning .startswith ("WARNING" )
292
+ ]
293
+ assert len (warnings ) == 1
294
+ assert "user is kitten but home is /home/jovyan" in warnings [0 ]
295
+
296
+
217
297
def test_container_not_delete_bind_mount (container , tmp_path ):
218
298
"""Container should not delete host system files when using the (docker)
219
299
-v bind mount flag and mapping to /home/jovyan.
@@ -235,6 +315,9 @@ def test_container_not_delete_bind_mount(container, tmp_path):
235
315
command = ["start.sh" , "ls" ],
236
316
)
237
317
rv = c .wait (timeout = 5 )
318
+ logs = c .logs (stdout = True ).decode ("utf-8" )
319
+ assert "ERROR" not in logs
320
+ assert "WARNING" not in logs
238
321
assert rv == 0 or rv ["StatusCode" ] == 0
239
322
assert p .read_text () == "some-content"
240
323
assert len (list (tmp_path .iterdir ())) == 1
@@ -264,4 +347,6 @@ def test_jupyter_env_vars_to_unset_as_root(container, enable_root):
264
347
rv = c .wait (timeout = 10 )
265
348
assert rv == 0 or rv ["StatusCode" ] == 0
266
349
logs = c .logs (stdout = True ).decode ("utf-8" )
350
+ assert "ERROR" not in logs
351
+ assert "WARNING" not in logs
267
352
assert "I like bananas and stuff, and love to keep secrets!" in logs
0 commit comments