Skip to content

Commit 3121917

Browse files
authored
Merge pull request #200 from dbt-labs/fix/validate-identifier-special-chars
2 parents cb9c521 + 174de7f commit 3121917

3 files changed

Lines changed: 40 additions & 8 deletions

File tree

src/dbt_jobs_as_code/loader/load.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from ruamel.yaml import YAML
99

1010
from dbt_jobs_as_code.schemas.config import Config
11+
from dbt_jobs_as_code.schemas.job import VALID_IDENTIFIER_RE
1112

1213

1314
class LoadingJobsYAMLError(Exception):
@@ -49,22 +50,26 @@ def load_job_configuration(config_files: List[str], vars_file: Optional[List[str
4950

5051

5152
def _validate_job_identifiers(jobs: dict) -> None:
52-
"""Validate that job identifiers don't contain spaces.
53+
"""Validate that job identifiers only contain allowed characters.
54+
55+
Identifiers are embedded as [[identifier]] in job names and extracted via regex,
56+
so they must only contain letters, digits, underscores, and hyphens.
5357
5458
Args:
5559
jobs: Dictionary of jobs with identifiers as keys
5660
5761
Raises:
58-
LoadingJobsYAMLError: If any job identifier contains spaces
62+
LoadingJobsYAMLError: If any job identifier contains invalid characters
5963
"""
6064
invalid_identifiers = []
6165
for identifier in jobs.keys():
62-
if " " in identifier:
66+
if not VALID_IDENTIFIER_RE.match(identifier):
6367
invalid_identifiers.append(identifier)
6468

6569
if invalid_identifiers:
6670
raise LoadingJobsYAMLError(
67-
f"Job identifiers cannot contain spaces. Invalid identifiers: {', '.join(invalid_identifiers)}"
71+
f"Job identifiers can only contain letters, digits, underscores, and hyphens. "
72+
f"Invalid identifiers: {', '.join(invalid_identifiers)}"
6873
)
6974

7075

src/dbt_jobs_as_code/schemas/job.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222

2323
JOB_TYPES_WITHOUT_SCHEDULE = ["ci", "merge"]
2424

25+
# Characters allowed in a YAML identifier key (embedded as [[identifier]] in job names).
26+
# Must match the character class used when extracting identifiers from job names.
27+
VALID_IDENTIFIER_RE = re.compile(r"^[a-zA-Z0-9_-]+$")
28+
2529

2630
@dataclass
2731
class IdentifierInfo:

tests/loader/test_loader.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ def test_load_job_configuration_identifier_with_spaces_error(
7373
with pytest.raises(LoadingJobsYAMLError) as exc_info:
7474
load_job_configuration([str(config_file)], None)
7575

76-
assert "Job identifiers cannot contain spaces" in str(exc_info.value)
76+
assert "Job identifiers can only contain letters, digits, underscores, and hyphens" in str(
77+
exc_info.value
78+
)
7779
assert "job with spaces" in str(exc_info.value)
7880

7981
def test_load_job_configuration_multiple_identifiers_with_spaces_error(
@@ -86,7 +88,9 @@ def test_load_job_configuration_multiple_identifiers_with_spaces_error(
8688
with pytest.raises(LoadingJobsYAMLError) as exc_info:
8789
load_job_configuration([str(config_file)], None)
8890

89-
assert "Job identifiers cannot contain spaces" in str(exc_info.value)
91+
assert "Job identifiers can only contain letters, digits, underscores, and hyphens" in str(
92+
exc_info.value
93+
)
9094
assert "job with spaces" in str(exc_info.value)
9195
assert "another invalid job" in str(exc_info.value)
9296

@@ -124,7 +128,9 @@ def test_validate_job_identifiers_with_spaces(self):
124128
with pytest.raises(LoadingJobsYAMLError) as exc_info:
125129
_validate_job_identifiers(jobs)
126130

127-
assert "Job identifiers cannot contain spaces" in str(exc_info.value)
131+
assert "Job identifiers can only contain letters, digits, underscores, and hyphens" in str(
132+
exc_info.value
133+
)
128134
assert "job with spaces" in str(exc_info.value)
129135
assert "another job" in str(exc_info.value)
130136

@@ -139,9 +145,26 @@ def test_validate_job_identifiers_mixed_valid_invalid(self):
139145
with pytest.raises(LoadingJobsYAMLError) as exc_info:
140146
_validate_job_identifiers(jobs)
141147

142-
assert "Job identifiers cannot contain spaces" in str(exc_info.value)
148+
assert "Job identifiers can only contain letters, digits, underscores, and hyphens" in str(
149+
exc_info.value
150+
)
143151
assert "job with spaces" in str(exc_info.value)
144152

153+
def test_validate_job_identifiers_with_special_chars(self):
154+
"""Test that identifiers with special characters (e.g. &, @, .) are rejected."""
155+
jobs = {
156+
"job&name": {},
157+
"job@name": {},
158+
}
159+
160+
with pytest.raises(LoadingJobsYAMLError) as exc_info:
161+
_validate_job_identifiers(jobs)
162+
163+
assert "Job identifiers can only contain letters, digits, underscores, and hyphens" in str(
164+
exc_info.value
165+
)
166+
assert "job&name" in str(exc_info.value)
167+
145168
def test_validate_job_identifiers_empty_dict(self):
146169
"""Test that validation passes for empty jobs dictionary."""
147170
jobs = {}

0 commit comments

Comments
 (0)