|
107 | 107 | from airbyte_cdk.sources.declarative.models.declarative_component_schema import ( |
108 | 108 | SelectiveAuthenticator, |
109 | 109 | ) |
| 110 | +from airbyte_cdk.sources.declarative.parsers.custom_code_compiler import ( |
| 111 | + ENV_VAR_ALLOW_CUSTOM_CODE, |
| 112 | + AirbyteCustomCodeNotPermittedError, |
| 113 | +) |
110 | 114 | from airbyte_cdk.sources.declarative.parsers.manifest_component_transformer import ( |
111 | 115 | ManifestComponentTransformer, |
112 | 116 | ) |
@@ -2509,6 +2513,47 @@ def test_create_custom_components(manifest, field_name, expected_value, expected |
2509 | 2513 | assert getattr(custom_component, field_name) == expected_value |
2510 | 2514 |
|
2511 | 2515 |
|
| 2516 | +@pytest.mark.parametrize( |
| 2517 | + "class_name", |
| 2518 | + [ |
| 2519 | + pytest.param( |
| 2520 | + "unit_tests.sources.declarative.parsers.testing_components.TestingSomeComponent", |
| 2521 | + id="bundled_custom_component_class", |
| 2522 | + ), |
| 2523 | + pytest.param( |
| 2524 | + "os.getcwd", |
| 2525 | + id="arbitrary_importable_callable", |
| 2526 | + ), |
| 2527 | + ], |
| 2528 | +) |
| 2529 | +def test_create_custom_component_requires_custom_code_enabled(class_name, monkeypatch): |
| 2530 | + """A `Custom*` component must not be instantiated unless custom code execution is |
| 2531 | + explicitly enabled via `AIRBYTE_ENABLE_UNSAFE_CODE`. |
| 2532 | +
|
| 2533 | + Resolving and instantiating a component's `class_name` executes arbitrary |
| 2534 | + importable code, so it must honor the same gate as injected `components.py` code. |
| 2535 | + The gate must fire regardless of whether `class_name` points at a bundled custom |
| 2536 | + component or at an arbitrary importable callable, and it must fire before the |
| 2537 | + referenced module is imported. |
| 2538 | + """ |
| 2539 | + monkeypatch.delenv(ENV_VAR_ALLOW_CUSTOM_CODE, raising=False) |
| 2540 | + |
| 2541 | + def _fail_if_resolved(*args, **kwargs): |
| 2542 | + raise AssertionError( |
| 2543 | + "`class_name` must not be resolved or imported when custom code is disabled" |
| 2544 | + ) |
| 2545 | + |
| 2546 | + monkeypatch.setattr(factory, "_get_class_from_fully_qualified_class_name", _fail_if_resolved) |
| 2547 | + |
| 2548 | + manifest = { |
| 2549 | + "type": "CustomErrorHandler", |
| 2550 | + "class_name": class_name, |
| 2551 | + } |
| 2552 | + |
| 2553 | + with pytest.raises(AirbyteCustomCodeNotPermittedError): |
| 2554 | + factory.create_component(CustomErrorHandlerModel, manifest, input_config) |
| 2555 | + |
| 2556 | + |
2512 | 2557 | def test_custom_components_do_not_contain_extra_fields(): |
2513 | 2558 | custom_substream_partition_router_manifest = { |
2514 | 2559 | "type": "CustomPartitionRouter", |
|
0 commit comments