From 0dc2a2f9633e93450ec812502a84a74169c9e5f4 Mon Sep 17 00:00:00 2001 From: Emily Rockman Date: Tue, 23 Apr 2024 20:17:47 -0500 Subject: [PATCH] Add more package validation (#9986) * validate packages are not empty strings * add test * changelog * Update core/dbt/contracts/project.py * fix test message --- .../unreleased/Fixes-20240422-152244.yaml | 6 +++ core/dbt/contracts/project.py | 15 ++++++- .../dependencies/test_simple_dependency.py | 41 +++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 .changes/unreleased/Fixes-20240422-152244.yaml diff --git a/.changes/unreleased/Fixes-20240422-152244.yaml b/.changes/unreleased/Fixes-20240422-152244.yaml new file mode 100644 index 00000000000..869d152fda9 --- /dev/null +++ b/.changes/unreleased/Fixes-20240422-152244.yaml @@ -0,0 +1,6 @@ +kind: Fixes +body: Validate against empty strings in package definitions +time: 2024-04-22T15:22:44.575999-05:00 +custom: + Author: emmyoop + Issue: "9985" diff --git a/core/dbt/contracts/project.py b/core/dbt/contracts/project.py index a74b883005d..0fa0a2fabfe 100644 --- a/core/dbt/contracts/project.py +++ b/core/dbt/contracts/project.py @@ -101,13 +101,26 @@ class PackageConfig(dbtClassMixin): @classmethod def validate(cls, data): for package in data.get("packages", data): + # This can happen when the target is a variable that is not filled and results in hangs + if isinstance(package, dict): + if package.get("package") == "": + raise ValidationError( + "A hub package is missing the value. It is a required property." + ) + if package.get("local") == "": + raise ValidationError( + "A local package is missing the value. It is a required property." + ) + if package.get("git") == "": + raise ValidationError( + "A git package is missing the value. It is a required property." + ) if isinstance(package, dict) and package.get("package"): if not package["version"]: raise ValidationError( f"{package['package']} is missing the version. When installing from the Hub " "package index, version is a required property" ) - if "/" not in package["package"]: raise ValidationError( f"{package['package']} was not found in the package index. Packages on the index " diff --git a/tests/functional/dependencies/test_simple_dependency.py b/tests/functional/dependencies/test_simple_dependency.py index de06452ec30..9483400fc24 100644 --- a/tests/functional/dependencies/test_simple_dependency.py +++ b/tests/functional/dependencies/test_simple_dependency.py @@ -434,3 +434,44 @@ def test_malformed_tarball_package_causes_exception(self, project): ) as e: run_dbt(["deps"]) assert e is not None + + +class TestEmptyDependency: + def test_empty_package(self, project): + # We have to specify the bad formatted package here because if we do it + # in a `packages` fixture, the test will blow up in the setup phase, meaning + # we can't appropriately catch it with a `pytest.raises` + empty_hub_package = { + "packages": [ + { + "package": "", + "version": "1.0.0", + } + ] + } + write_config_file(empty_hub_package, "packages.yml") + with pytest.raises(DbtProjectError, match="A hub package is missing the value"): + run_dbt(["deps"]) + + empty_git_package = { + "packages": [ + { + "git": "", + "revision": "1.0.0", + } + ] + } + write_config_file(empty_git_package, "packages.yml") + with pytest.raises(DbtProjectError, match="A git package is missing the value"): + run_dbt(["deps"]) + + empty_local_package = { + "packages": [ + { + "local": "", + } + ] + } + write_config_file(empty_local_package, "packages.yml") + with pytest.raises(DbtProjectError, match="A local package is missing the value"): + run_dbt(["deps"])