22
22
from aiohttp import ClientSession
23
23
from aioresponses import aioresponses
24
24
from pydantic import ValidationError
25
+ from warnings import catch_warnings , simplefilter
25
26
26
27
from toolbox_core .protocol import ParameterSchema
27
28
from toolbox_core .tool import ToolboxTool , create_func_docstring , resolve_value
28
29
29
30
TEST_BASE_URL = "http://toolbox.example.com"
31
+ HTTPS_BASE_URL = "https://toolbox.example.com"
30
32
TEST_TOOL_NAME = "sample_tool"
31
33
32
34
@@ -195,7 +197,7 @@ async def test_tool_creation_callable_and_run(
195
197
Tests creating a ToolboxTool, checks callability, and simulates a run.
196
198
"""
197
199
tool_name = TEST_TOOL_NAME
198
- base_url = TEST_BASE_URL
200
+ base_url = HTTPS_BASE_URL
199
201
invoke_url = f"{ base_url } /api/tool/{ tool_name } /invoke"
200
202
201
203
input_args = {"message" : "hello world" , "count" : 5 }
@@ -246,7 +248,7 @@ async def test_tool_run_with_pydantic_validation_error(
246
248
due to Pydantic validation *before* making an HTTP request.
247
249
"""
248
250
tool_name = TEST_TOOL_NAME
249
- base_url = TEST_BASE_URL
251
+ base_url = HTTPS_BASE_URL
250
252
invoke_url = f"{ base_url } /api/tool/{ tool_name } /invoke"
251
253
252
254
with aioresponses () as m :
@@ -340,18 +342,23 @@ async def test_resolve_value_async_callable():
340
342
341
343
def test_tool_init_basic (http_session , sample_tool_params , sample_tool_description ):
342
344
"""Tests basic tool initialization without headers or auth."""
343
- tool_instance = ToolboxTool (
344
- session = http_session ,
345
- base_url = TEST_BASE_URL ,
346
- name = TEST_TOOL_NAME ,
347
- description = sample_tool_description ,
348
- params = sample_tool_params ,
349
- required_authn_params = {},
350
- required_authz_tokens = [],
351
- auth_service_token_getters = {},
352
- bound_params = {},
353
- client_headers = {},
354
- )
345
+ with catch_warnings (record = True ) as record :
346
+ simplefilter ("always" )
347
+
348
+ tool_instance = ToolboxTool (
349
+ session = http_session ,
350
+ base_url = HTTPS_BASE_URL ,
351
+ name = TEST_TOOL_NAME ,
352
+ description = sample_tool_description ,
353
+ params = sample_tool_params ,
354
+ required_authn_params = {},
355
+ required_authz_tokens = [],
356
+ auth_service_token_getters = {},
357
+ bound_params = {},
358
+ client_headers = {},
359
+ )
360
+ assert len (record ) == 0 , f"ToolboxTool instantiation unexpectedly warned: { [f'{ w .category .__name__ } : { w .message } ' for w in record ]} "
361
+
355
362
assert tool_instance .__name__ == TEST_TOOL_NAME
356
363
assert inspect .iscoroutinefunction (tool_instance .__call__ )
357
364
assert "message" in tool_instance .__signature__ .parameters
@@ -367,7 +374,7 @@ def test_tool_init_with_client_headers(
367
374
"""Tests tool initialization *with* client headers."""
368
375
tool_instance = ToolboxTool (
369
376
session = http_session ,
370
- base_url = TEST_BASE_URL ,
377
+ base_url = HTTPS_BASE_URL ,
371
378
name = TEST_TOOL_NAME ,
372
379
description = sample_tool_description ,
373
380
params = sample_tool_params ,
@@ -395,7 +402,7 @@ def test_tool_init_header_auth_conflict(
395
402
):
396
403
ToolboxTool (
397
404
session = http_session ,
398
- base_url = TEST_BASE_URL ,
405
+ base_url = HTTPS_BASE_URL ,
399
406
name = "auth_conflict_tool" ,
400
407
description = sample_tool_description ,
401
408
params = sample_tool_auth_params ,
@@ -418,7 +425,7 @@ def test_tool_add_auth_token_getters_conflict_with_existing_client_header(
418
425
"""
419
426
tool_instance = ToolboxTool (
420
427
session = http_session ,
421
- base_url = TEST_BASE_URL ,
428
+ base_url = HTTPS_BASE_URL ,
422
429
name = "tool_with_client_header" ,
423
430
description = sample_tool_description ,
424
431
params = sample_tool_params ,
@@ -454,7 +461,7 @@ def test_add_auth_token_getters_unused_token(
454
461
"""
455
462
tool_instance = ToolboxTool (
456
463
session = http_session ,
457
- base_url = TEST_BASE_URL ,
464
+ base_url = HTTPS_BASE_URL ,
458
465
name = TEST_TOOL_NAME ,
459
466
description = sample_tool_description ,
460
467
params = sample_tool_params ,
@@ -469,3 +476,126 @@ def test_add_auth_token_getters_unused_token(
469
476
470
477
with pytest .raises (ValueError , match = expected_error_message ):
471
478
tool_instance .add_auth_token_getters (unused_auth_getters )
479
+
480
+
481
+ # --- Test for the HTTP Warning ---
482
+ @pytest .mark .parametrize (
483
+ "trigger_condition_params" ,
484
+ [
485
+ {"client_headers" : {"X-Some-Header" : "value" }},
486
+ {"required_authn_params" : {"param1" : ["auth-service1" ]}},
487
+ {"required_authz_tokens" : ["auth-service2" ]},
488
+ {
489
+ "client_headers" : {"X-Some-Header" : "value" },
490
+ "required_authn_params" : {"param1" : ["auth-service1" ]},
491
+ },
492
+ {
493
+ "client_headers" : {"X-Some-Header" : "value" },
494
+ "required_authz_tokens" : ["auth-service2" ],
495
+ },
496
+ {
497
+ "required_authn_params" : {"param1" : ["auth-service1" ]},
498
+ "required_authz_tokens" : ["auth-service2" ],
499
+ },
500
+ {
501
+ "client_headers" : {"X-Some-Header" : "value" },
502
+ "required_authn_params" : {"param1" : ["auth-service1" ]},
503
+ "required_authz_tokens" : ["auth-service2" ],
504
+ },
505
+ ],
506
+ ids = [
507
+ "client_headers_only" ,
508
+ "authn_params_only" ,
509
+ "authz_tokens_only" ,
510
+ "headers_and_authn" ,
511
+ "headers_and_authz" ,
512
+ "authn_and_authz" ,
513
+ "all_three_conditions" ,
514
+ ],
515
+ )
516
+ def test_tool_init_http_warning_when_sensitive_info_over_http (
517
+ http_session : ClientSession ,
518
+ sample_tool_params : list [ParameterSchema ],
519
+ sample_tool_description : str ,
520
+ trigger_condition_params : dict ,
521
+ ):
522
+ """
523
+ Tests that a UserWarning is issued if client headers, auth params, or
524
+ auth tokens are present and the base_url is HTTP.
525
+ """
526
+ expected_warning_message = (
527
+ "Sending ID token over HTTP. User data may be exposed. "
528
+ "Use HTTPS for secure communication."
529
+ )
530
+
531
+ init_kwargs = {
532
+ "session" : http_session ,
533
+ "base_url" : TEST_BASE_URL ,
534
+ "name" : "http_warning_tool" ,
535
+ "description" : sample_tool_description ,
536
+ "params" : sample_tool_params ,
537
+ "required_authn_params" : {},
538
+ "required_authz_tokens" : [],
539
+ "auth_service_token_getters" : {},
540
+ "bound_params" : {},
541
+ "client_headers" : {},
542
+ }
543
+ # Apply the specific conditions for this parametrized test
544
+ init_kwargs .update (trigger_condition_params )
545
+
546
+ with pytest .warns (UserWarning , match = expected_warning_message ):
547
+ ToolboxTool (** init_kwargs )
548
+
549
+
550
+ def test_tool_init_no_http_warning_if_https (
551
+ http_session : ClientSession ,
552
+ sample_tool_params : list [ParameterSchema ],
553
+ sample_tool_description : str ,
554
+ static_client_header : dict ,
555
+ ):
556
+ """
557
+ Tests that NO UserWarning is issued if client headers are present but
558
+ the base_url is HTTPS.
559
+ """
560
+ with catch_warnings (record = True ) as record :
561
+ simplefilter ("always" )
562
+
563
+ ToolboxTool (
564
+ session = http_session ,
565
+ base_url = HTTPS_BASE_URL ,
566
+ name = "https_tool" ,
567
+ description = sample_tool_description ,
568
+ params = sample_tool_params ,
569
+ required_authn_params = {},
570
+ required_authz_tokens = [],
571
+ auth_service_token_getters = {},
572
+ bound_params = {},
573
+ client_headers = static_client_header ,
574
+ )
575
+ assert len (record ) == 0 , f"Expected no warnings, but got: { [f'{ w .category .__name__ } : { w .message } ' for w in record ]} "
576
+
577
+ def test_tool_init_no_http_warning_if_no_sensitive_info_on_http (
578
+ http_session : ClientSession ,
579
+ sample_tool_params : list [ParameterSchema ],
580
+ sample_tool_description : str ,
581
+ ):
582
+ """
583
+ Tests that NO UserWarning is issued if the URL is HTTP but there are
584
+ no client headers, auth params, or auth tokens.
585
+ """
586
+ with catch_warnings (record = True ) as record :
587
+ simplefilter ("always" )
588
+
589
+ ToolboxTool (
590
+ session = http_session ,
591
+ base_url = TEST_BASE_URL ,
592
+ name = "http_tool_no_sensitive" ,
593
+ description = sample_tool_description ,
594
+ params = sample_tool_params ,
595
+ required_authn_params = {},
596
+ required_authz_tokens = [],
597
+ auth_service_token_getters = {},
598
+ bound_params = {},
599
+ client_headers = {},
600
+ )
601
+ assert len (record ) == 0 , f"Expected no warnings, but got: { [f'{ w .category .__name__ } : { w .message } ' for w in record ]} "
0 commit comments