From f60013a4d350b89113da48dc1149071acedf02dd Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 21:29:50 +0000 Subject: [PATCH 1/4] CodeRabbit Generated Unit Tests: Add pytest tests to validate .github/dependabot.yml configuration file --- .github/tests/test_dependabot_config.py | 340 ++++++++++++++++++++++++ 1 file changed, 340 insertions(+) create mode 100644 .github/tests/test_dependabot_config.py diff --git a/.github/tests/test_dependabot_config.py b/.github/tests/test_dependabot_config.py new file mode 100644 index 0000000..4984cb3 --- /dev/null +++ b/.github/tests/test_dependabot_config.py @@ -0,0 +1,340 @@ +""" +Comprehensive unit tests for dependabot configuration validation. +Testing framework: pytest +""" + +import pytest +import yaml +import os +from pathlib import Path +from typing import Dict, List, Any + + +class TestDependabotConfig: + """Test suite for dependabot configuration validation.""" + + @pytest.fixture + def dependabot_config_path(self): + """Fixture to provide the path to the dependabot configuration file.""" + return Path(".github/dependabot.yml") + + @pytest.fixture + def dependabot_config(self, dependabot_config_path): + """Fixture to load and parse the dependabot configuration.""" + if not dependabot_config_path.exists(): + pytest.skip("Dependabot configuration file not found") + + with open(dependabot_config_path, 'r') as f: + return yaml.safe_load(f) + + def test_config_file_exists(self, dependabot_config_path): + """Test that the dependabot configuration file exists.""" + assert dependabot_config_path.exists(), "Dependabot configuration file should exist" + + def test_config_file_is_valid_yaml(self, dependabot_config_path): + """Test that the dependabot configuration file is valid YAML.""" + try: + with open(dependabot_config_path, 'r') as f: + yaml.safe_load(f) + except yaml.YAMLError as e: + pytest.fail(f"Invalid YAML syntax: {e}") + + def test_config_has_required_version_key(self, dependabot_config): + """Test that the configuration has the required 'version' key.""" + assert 'version' in dependabot_config, "Configuration must have 'version' key" + + def test_config_version_is_supported(self, dependabot_config): + """Test that the configuration uses a supported version.""" + supported_versions = [2] + version = dependabot_config.get('version') + assert version in supported_versions, f"Version {version} is not supported. Supported versions: {supported_versions}" + + def test_config_has_updates_key(self, dependabot_config): + """Test that the configuration has the 'updates' key.""" + assert 'updates' in dependabot_config, "Configuration must have 'updates' key" + + def test_updates_is_list(self, dependabot_config): + """Test that the 'updates' value is a list.""" + updates = dependabot_config.get('updates', []) + assert isinstance(updates, list), "The 'updates' value must be a list" + + def test_updates_list_not_empty(self, dependabot_config): + """Test that the updates list is not empty.""" + updates = dependabot_config.get('updates', []) + assert len(updates) > 0, "The 'updates' list should not be empty" + + def test_each_update_has_required_keys(self, dependabot_config): + """Test that each update entry has required keys.""" + required_keys = ['package-ecosystem', 'directory', 'schedule'] + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + assert isinstance(update, dict), f"Update {i} must be a dictionary" + for key in required_keys: + assert key in update, f"Update {i} missing required key: {key}" + + def test_package_ecosystem_values_are_valid(self, dependabot_config): + """Test that package-ecosystem values are valid.""" + valid_ecosystems = [ + 'bundler', 'cargo', 'composer', 'docker', 'elm', 'gitsubmodule', + 'github-actions', 'gomod', 'gradle', 'maven', 'mix', 'npm', + 'nuget', 'pip', 'swift', 'terraform' + ] + + updates = dependabot_config.get('updates', []) + for i, update in enumerate(updates): + ecosystem = update.get('package-ecosystem') + assert ecosystem in valid_ecosystems, f"Update {i} has invalid package-ecosystem: {ecosystem}" + + def test_directory_values_are_valid_paths(self, dependabot_config): + """Test that directory values are valid paths.""" + updates = dependabot_config.get('updates', []) + for i, update in enumerate(updates): + directory = update.get('directory') + assert isinstance(directory, str), f"Update {i} directory must be a string" + assert directory.startswith('/'), f"Update {i} directory must start with '/'" + + def test_schedule_has_required_interval(self, dependabot_config): + """Test that each schedule has a required interval.""" + updates = dependabot_config.get('updates', []) + for i, update in enumerate(updates): + schedule = update.get('schedule', {}) + assert isinstance(schedule, dict), f"Update {i} schedule must be a dictionary" + assert 'interval' in schedule, f"Update {i} schedule missing 'interval' key" + + def test_schedule_interval_values_are_valid(self, dependabot_config): + """Test that schedule interval values are valid.""" + valid_intervals = ['daily', 'weekly', 'monthly'] + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + schedule = update.get('schedule', {}) + interval = schedule.get('interval') + assert interval in valid_intervals, f"Update {i} has invalid schedule interval: {interval}" + + def test_schedule_day_is_valid_when_present(self, dependabot_config): + """Test that schedule day values are valid when present.""" + valid_days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'] + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + schedule = update.get('schedule', {}) + if 'day' in schedule: + day = schedule['day'] + assert day in valid_days, f"Update {i} has invalid schedule day: {day}" + + def test_schedule_time_format_is_valid_when_present(self, dependabot_config): + """Test that schedule time values are in valid format when present.""" + import re + time_pattern = re.compile(r'^([01]?[0-9]|2[0-3]):[0-5][0-9]$') + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + schedule = update.get('schedule', {}) + if 'time' in schedule: + time = schedule['time'] + assert isinstance(time, str), f"Update {i} schedule time must be a string" + assert time_pattern.match(time), f"Update {i} has invalid time format: {time}" + + def test_schedule_timezone_is_valid_when_present(self, dependabot_config): + """Test that schedule timezone values are valid when present.""" + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + schedule = update.get('schedule', {}) + if 'timezone' in schedule: + timezone = schedule['timezone'] + assert isinstance(timezone, str), f"Update {i} schedule timezone must be a string" + assert len(timezone) > 0, f"Update {i} schedule timezone cannot be empty" + + def test_open_pull_requests_limit_is_valid_when_present(self, dependabot_config): + """Test that open-pull-requests-limit values are valid when present.""" + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + if 'open-pull-requests-limit' in update: + limit = update['open-pull-requests-limit'] + assert isinstance(limit, int), f"Update {i} open-pull-requests-limit must be an integer" + assert 0 <= limit <= 20, f"Update {i} open-pull-requests-limit must be between 0 and 20" + + def test_target_branch_is_valid_when_present(self, dependabot_config): + """Test that target-branch values are valid when present.""" + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + if 'target-branch' in update: + branch = update['target-branch'] + assert isinstance(branch, str), f"Update {i} target-branch must be a string" + assert len(branch) > 0, f"Update {i} target-branch cannot be empty" + + def test_reviewers_format_is_valid_when_present(self, dependabot_config): + """Test that reviewers format is valid when present.""" + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + if 'reviewers' in update: + reviewers = update['reviewers'] + assert isinstance(reviewers, list), f"Update {i} reviewers must be a list" + for reviewer in reviewers: + assert isinstance(reviewer, str), f"Update {i} reviewer must be a string" + + def test_assignees_format_is_valid_when_present(self, dependabot_config): + """Test that assignees format is valid when present.""" + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + if 'assignees' in update: + assignees = update['assignees'] + assert isinstance(assignees, list), f"Update {i} assignees must be a list" + for assignee in assignees: + assert isinstance(assignee, str), f"Update {i} assignee must be a string" + + def test_labels_format_is_valid_when_present(self, dependabot_config): + """Test that labels format is valid when present.""" + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + if 'labels' in update: + labels = update['labels'] + assert isinstance(labels, list), f"Update {i} labels must be a list" + for label in labels: + assert isinstance(label, str), f"Update {i} label must be a string" + + def test_commit_message_format_is_valid_when_present(self, dependabot_config): + """Test that commit-message format is valid when present.""" + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + if 'commit-message' in update: + commit_message = update['commit-message'] + assert isinstance(commit_message, dict), f"Update {i} commit-message must be a dictionary" + + if 'prefix' in commit_message: + assert isinstance(commit_message['prefix'], str), f"Update {i} commit-message prefix must be a string" + + if 'include' in commit_message: + include = commit_message['include'] + assert include in ['scope'], f"Update {i} commit-message include must be 'scope'" + + def test_rebase_strategy_is_valid_when_present(self, dependabot_config): + """Test that rebase-strategy values are valid when present.""" + valid_strategies = ['auto', 'disabled'] + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + if 'rebase-strategy' in update: + strategy = update['rebase-strategy'] + assert strategy in valid_strategies, f"Update {i} has invalid rebase-strategy: {strategy}" + + def test_allow_format_is_valid_when_present(self, dependabot_config): + """Test that allow format is valid when present.""" + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + if 'allow' in update: + allow = update['allow'] + assert isinstance(allow, list), f"Update {i} allow must be a list" + + for allow_item in allow: + assert isinstance(allow_item, dict), f"Update {i} allow item must be a dictionary" + assert 'dependency-type' in allow_item, f"Update {i} allow item must have 'dependency-type'" + + dep_type = allow_item['dependency-type'] + valid_types = ['direct', 'indirect', 'all'] + assert dep_type in valid_types, f"Update {i} allow item has invalid dependency-type: {dep_type}" + + def test_ignore_format_is_valid_when_present(self, dependabot_config): + """Test that ignore format is valid when present.""" + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + if 'ignore' in update: + ignore = update['ignore'] + assert isinstance(ignore, list), f"Update {i} ignore must be a list" + + for ignore_item in ignore: + assert isinstance(ignore_item, dict), f"Update {i} ignore item must be a dictionary" + assert 'dependency-name' in ignore_item, f"Update {i} ignore item must have 'dependency-name'" + + def test_no_duplicate_package_ecosystem_directory_combinations(self, dependabot_config): + """Test that there are no duplicate package-ecosystem and directory combinations.""" + updates = dependabot_config.get('updates', []) + combinations = [] + + for update in updates: + combination = (update.get('package-ecosystem'), update.get('directory')) + assert combination not in combinations, f"Duplicate combination found: {combination}" + combinations.append(combination) + + def test_config_follows_best_practices(self, dependabot_config): + """Test that the configuration follows best practices.""" + updates = dependabot_config.get('updates', []) + + # Check for reasonable open-pull-requests-limit + for i, update in enumerate(updates): + if 'open-pull-requests-limit' in update: + limit = update['open-pull-requests-limit'] + assert limit <= 10, f"Update {i} open-pull-requests-limit should be <= 10 for better management" + + def test_config_has_security_updates_enabled(self, dependabot_config): + """Test that security updates are not explicitly disabled.""" + updates = dependabot_config.get('updates', []) + + for i, update in enumerate(updates): + if 'open-pull-requests-limit' in update: + limit = update['open-pull-requests-limit'] + assert limit > 0, f"Update {i} should allow at least one PR for security updates" + + @pytest.mark.parametrize("ecosystem,expected_files", [ + ("npm", ["package.json"]), + ("pip", ["requirements.txt", "setup.py", "pyproject.toml"]), + ("docker", ["Dockerfile"]), + ("github-actions", [".github/workflows"]), + ]) + def test_ecosystem_has_corresponding_files(self, dependabot_config, ecosystem, expected_files): + """Test that ecosystems have corresponding files in the repository.""" + updates = dependabot_config.get('updates', []) + ecosystems_in_config = [update.get('package-ecosystem') for update in updates] + + if ecosystem in ecosystems_in_config: + for expected_file in expected_files: + file_path = Path(expected_file) + assert file_path.exists() or any(Path(".").glob(f"**/{expected_file}")), \ + f"Expected file {expected_file} not found for ecosystem {ecosystem}" + + def test_config_file_permissions(self, dependabot_config_path): + """Test that the config file has appropriate permissions.""" + import stat + file_stat = os.stat(dependabot_config_path) + mode = file_stat.st_mode + + # Check that file is readable + assert mode & stat.S_IRUSR, "Config file should be readable by owner" + assert mode & stat.S_IRGRP, "Config file should be readable by group" + assert mode & stat.S_IROTH, "Config file should be readable by others" + + def test_yaml_structure_depth_is_reasonable(self, dependabot_config): + """Test that the YAML structure doesn't have excessive nesting.""" + def get_max_depth(obj, current_depth=0): + if isinstance(obj, dict): + return max([get_max_depth(v, current_depth + 1) for v in obj.values()] + [current_depth]) + elif isinstance(obj, list): + return max([get_max_depth(item, current_depth + 1) for item in obj] + [current_depth]) + else: + return current_depth + + max_depth = get_max_depth(dependabot_config) + assert max_depth <= 5, f"YAML structure is too deeply nested: {max_depth} levels" + + def test_config_contains_no_sensitive_information(self, dependabot_config_path): + """Test that the config file doesn't contain sensitive information.""" + sensitive_patterns = [ + 'password', 'secret', 'token', 'key', 'credential', + 'auth', 'login', 'passwd', 'pass' + ] + + with open(dependabot_config_path, 'r') as f: + content = f.read().lower() + + for pattern in sensitive_patterns: + assert pattern not in content, f"Potential sensitive information found: {pattern}" \ No newline at end of file From 432a1d2f8cd505e56177bf3ec245fca8dd25d76a Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 21:38:28 +0000 Subject: [PATCH 2/4] Fix UTG issues (iteration 1) --- .github/tests/test_dependabot_config.py | 534 ++++++++++++++---------- 1 file changed, 324 insertions(+), 210 deletions(-) diff --git a/.github/tests/test_dependabot_config.py b/.github/tests/test_dependabot_config.py index 4984cb3..ad9d351 100644 --- a/.github/tests/test_dependabot_config.py +++ b/.github/tests/test_dependabot_config.py @@ -3,338 +3,452 @@ Testing framework: pytest """ -import pytest -import yaml import os from pathlib import Path -from typing import Dict, List, Any +from typing import Any, Dict, List + +import pytest +import yaml class TestDependabotConfig: """Test suite for dependabot configuration validation.""" @pytest.fixture - def dependabot_config_path(self): + def dependabot_config_path(self) -> Path: """Fixture to provide the path to the dependabot configuration file.""" return Path(".github/dependabot.yml") @pytest.fixture - def dependabot_config(self, dependabot_config_path): + def dependabot_config(self, dependabot_config_path: Path) -> Dict[str, Any]: """Fixture to load and parse the dependabot configuration.""" if not dependabot_config_path.exists(): pytest.skip("Dependabot configuration file not found") - - with open(dependabot_config_path, 'r') as f: + + with dependabot_config_path.open("r") as f: return yaml.safe_load(f) - def test_config_file_exists(self, dependabot_config_path): + def test_config_file_exists(self, dependabot_config_path: Path) -> None: """Test that the dependabot configuration file exists.""" assert dependabot_config_path.exists(), "Dependabot configuration file should exist" - def test_config_file_is_valid_yaml(self, dependabot_config_path): + def test_config_file_is_valid_yaml(self, dependabot_config_path: Path) -> None: """Test that the dependabot configuration file is valid YAML.""" try: - with open(dependabot_config_path, 'r') as f: + with dependabot_config_path.open("r") as f: yaml.safe_load(f) except yaml.YAMLError as e: pytest.fail(f"Invalid YAML syntax: {e}") - def test_config_has_required_version_key(self, dependabot_config): + def test_config_has_required_version_key(self, dependabot_config: Dict[str, Any]) -> None: """Test that the configuration has the required 'version' key.""" - assert 'version' in dependabot_config, "Configuration must have 'version' key" + assert "version" in dependabot_config, "Configuration must have 'version' key" - def test_config_version_is_supported(self, dependabot_config): + def test_config_version_is_supported(self, dependabot_config: Dict[str, Any]) -> None: """Test that the configuration uses a supported version.""" supported_versions = [2] - version = dependabot_config.get('version') - assert version in supported_versions, f"Version {version} is not supported. Supported versions: {supported_versions}" + version = dependabot_config.get("version") + assert version in supported_versions, ( + f"Version {version} is not supported. Supported versions: {supported_versions}" + ) - def test_config_has_updates_key(self, dependabot_config): + def test_config_has_updates_key(self, dependabot_config: Dict[str, Any]) -> None: """Test that the configuration has the 'updates' key.""" - assert 'updates' in dependabot_config, "Configuration must have 'updates' key" + assert "updates" in dependabot_config, "Configuration must have 'updates' key" - def test_updates_is_list(self, dependabot_config): + def test_updates_is_list(self, dependabot_config: Dict[str, Any]) -> None: """Test that the 'updates' value is a list.""" - updates = dependabot_config.get('updates', []) + updates = dependabot_config.get("updates", []) assert isinstance(updates, list), "The 'updates' value must be a list" - def test_updates_list_not_empty(self, dependabot_config): + def test_updates_list_not_empty(self, dependabot_config: Dict[str, Any]) -> None: """Test that the updates list is not empty.""" - updates = dependabot_config.get('updates', []) - assert len(updates) > 0, "The 'updates' list should not be empty" + updates = dependabot_config.get("updates", []) + assert updates, "The 'updates' list should not be empty" - def test_each_update_has_required_keys(self, dependabot_config): + def test_each_update_has_required_keys(self, dependabot_config: Dict[str, Any]) -> None: """Test that each update entry has required keys.""" - required_keys = ['package-ecosystem', 'directory', 'schedule'] - updates = dependabot_config.get('updates', []) - + required_keys = ["package-ecosystem", "directory", "schedule"] + updates = dependabot_config.get("updates", []) + for i, update in enumerate(updates): assert isinstance(update, dict), f"Update {i} must be a dictionary" for key in required_keys: assert key in update, f"Update {i} missing required key: {key}" - def test_package_ecosystem_values_are_valid(self, dependabot_config): + def test_package_ecosystem_values_are_valid(self, dependabot_config: Dict[str, Any]) -> None: """Test that package-ecosystem values are valid.""" valid_ecosystems = [ - 'bundler', 'cargo', 'composer', 'docker', 'elm', 'gitsubmodule', - 'github-actions', 'gomod', 'gradle', 'maven', 'mix', 'npm', - 'nuget', 'pip', 'swift', 'terraform' + "bundler", + "cargo", + "composer", + "docker", + "elm", + "gitsubmodule", + "github-actions", + "gomod", + "gradle", + "maven", + "mix", + "npm", + "nuget", + "pip", + "swift", + "terraform", ] - - updates = dependabot_config.get('updates', []) + + updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): - ecosystem = update.get('package-ecosystem') - assert ecosystem in valid_ecosystems, f"Update {i} has invalid package-ecosystem: {ecosystem}" + ecosystem = update.get("package-ecosystem") + assert ecosystem in valid_ecosystems, ( + f"Update {i} has invalid package-ecosystem: {ecosystem}" + ) - def test_directory_values_are_valid_paths(self, dependabot_config): + def test_directory_values_are_valid_paths(self, dependabot_config: Dict[str, Any]) -> None: """Test that directory values are valid paths.""" - updates = dependabot_config.get('updates', []) + updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): - directory = update.get('directory') + directory = update.get("directory") assert isinstance(directory, str), f"Update {i} directory must be a string" - assert directory.startswith('/'), f"Update {i} directory must start with '/'" + assert directory.startswith( + "/" + ), f"Update {i} directory must start with '/'" - def test_schedule_has_required_interval(self, dependabot_config): + def test_schedule_has_required_interval(self, dependabot_config: Dict[str, Any]) -> None: """Test that each schedule has a required interval.""" - updates = dependabot_config.get('updates', []) + updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): - schedule = update.get('schedule', {}) - assert isinstance(schedule, dict), f"Update {i} schedule must be a dictionary" - assert 'interval' in schedule, f"Update {i} schedule missing 'interval' key" + schedule = update.get("schedule", {}) + assert isinstance( + schedule, dict + ), f"Update {i} schedule must be a dictionary" + assert "interval" in schedule, f"Update {i} schedule missing 'interval' key" - def test_schedule_interval_values_are_valid(self, dependabot_config): + def test_schedule_interval_values_are_valid(self, dependabot_config: Dict[str, Any]) -> None: """Test that schedule interval values are valid.""" - valid_intervals = ['daily', 'weekly', 'monthly'] - updates = dependabot_config.get('updates', []) - + valid_intervals = ["daily", "weekly", "monthly"] + updates = dependabot_config.get("updates", []) + for i, update in enumerate(updates): - schedule = update.get('schedule', {}) - interval = schedule.get('interval') - assert interval in valid_intervals, f"Update {i} has invalid schedule interval: {interval}" + interval = update.get("schedule", {}).get("interval") + assert interval in valid_intervals, ( + f"Update {i} has invalid schedule interval: {interval}" + ) - def test_schedule_day_is_valid_when_present(self, dependabot_config): + def test_schedule_day_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: """Test that schedule day values are valid when present.""" - valid_days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'] - updates = dependabot_config.get('updates', []) - + valid_days = [ + "monday", + "tuesday", + "wednesday", + "thursday", + "friday", + "saturday", + "sunday", + ] + updates = dependabot_config.get("updates", []) + for i, update in enumerate(updates): - schedule = update.get('schedule', {}) - if 'day' in schedule: - day = schedule['day'] + schedule = update.get("schedule", {}) + if "day" in schedule: + day = schedule["day"] assert day in valid_days, f"Update {i} has invalid schedule day: {day}" - def test_schedule_time_format_is_valid_when_present(self, dependabot_config): + def test_schedule_time_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: """Test that schedule time values are in valid format when present.""" import re - time_pattern = re.compile(r'^([01]?[0-9]|2[0-3]):[0-5][0-9]$') - updates = dependabot_config.get('updates', []) - - for i, update in enumerate(updates): - schedule = update.get('schedule', {}) - if 'time' in schedule: - time = schedule['time'] - assert isinstance(time, str), f"Update {i} schedule time must be a string" - assert time_pattern.match(time), f"Update {i} has invalid time format: {time}" - def test_schedule_timezone_is_valid_when_present(self, dependabot_config): - """Test that schedule timezone values are valid when present.""" - updates = dependabot_config.get('updates', []) - + time_pattern = re.compile(r"^([01]?[0-9]|2[0-3]):[0-5][0-9]$") + updates = dependabot_config.get("updates", []) + for i, update in enumerate(updates): - schedule = update.get('schedule', {}) - if 'timezone' in schedule: - timezone = schedule['timezone'] - assert isinstance(timezone, str), f"Update {i} schedule timezone must be a string" - assert len(timezone) > 0, f"Update {i} schedule timezone cannot be empty" + schedule = update.get("schedule", {}) + if "time" in schedule: + time = schedule["time"] + assert isinstance(time, str), ( + f"Update {i} schedule time must be a string" + ) + assert time_pattern.match(time), ( + f"Update {i} has invalid time format: {time}" + ) + + def test_schedule_timezone_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + """Test that schedule timezone values are valid when present.""" + updates = dependabot_config.get("updates", []) - def test_open_pull_requests_limit_is_valid_when_present(self, dependabot_config): - """Test that open-pull-requests-limit values are valid when present.""" - updates = dependabot_config.get('updates', []) - for i, update in enumerate(updates): - if 'open-pull-requests-limit' in update: - limit = update['open-pull-requests-limit'] - assert isinstance(limit, int), f"Update {i} open-pull-requests-limit must be an integer" - assert 0 <= limit <= 20, f"Update {i} open-pull-requests-limit must be between 0 and 20" + timezone = update.get("schedule", {}).get("timezone") + if timezone is not None: + assert isinstance(timezone, str), ( + f"Update {i} schedule timezone must be a string" + ) + assert timezone, ( + f"Update {i} schedule timezone cannot be empty" + ) + + def test_open_pull_requests_limit_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + """Test that open-pull-requests-limit values are valid when present.""" + updates = dependabot_config.get("updates", []) - def test_target_branch_is_valid_when_present(self, dependabot_config): - """Test that target-branch values are valid when present.""" - updates = dependabot_config.get('updates', []) - for i, update in enumerate(updates): - if 'target-branch' in update: - branch = update['target-branch'] - assert isinstance(branch, str), f"Update {i} target-branch must be a string" - assert len(branch) > 0, f"Update {i} target-branch cannot be empty" + if "open-pull-requests-limit" in update: + limit = update["open-pull-requests-limit"] + assert isinstance(limit, int), ( + f"Update {i} open-pull-requests-limit must be an integer" + ) + assert 0 <= limit <= 20, ( + f"Update {i} open-pull-requests-limit must be between 0 and 20" + ) + + def test_target_branch_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + """Test that target-branch values are valid when present.""" + updates = dependabot_config.get("updates", []) - def test_reviewers_format_is_valid_when_present(self, dependabot_config): + for i, update in enumerate(updates): + if "target-branch" in update: + branch = update["target-branch"] + assert isinstance(branch, str), ( + f"Update {i} target-branch must be a string" + ) + assert branch, f"Update {i} target-branch cannot be empty" + + def test_reviewers_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: """Test that reviewers format is valid when present.""" - updates = dependabot_config.get('updates', []) - + updates = dependabot_config.get("updates", []) + for i, update in enumerate(updates): - if 'reviewers' in update: - reviewers = update['reviewers'] - assert isinstance(reviewers, list), f"Update {i} reviewers must be a list" + reviewers = update.get("reviewers") + if reviewers is not None: + assert isinstance(reviewers, list), ( + f"Update {i} reviewers must be a list" + ) for reviewer in reviewers: - assert isinstance(reviewer, str), f"Update {i} reviewer must be a string" + assert isinstance(reviewer, str), ( + f"Update {i} reviewer must be a string" + ) - def test_assignees_format_is_valid_when_present(self, dependabot_config): + def test_assignees_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: """Test that assignees format is valid when present.""" - updates = dependabot_config.get('updates', []) - + updates = dependabot_config.get("updates", []) + for i, update in enumerate(updates): - if 'assignees' in update: - assignees = update['assignees'] - assert isinstance(assignees, list), f"Update {i} assignees must be a list" + assignees = update.get("assignees") + if assignees is not None: + assert isinstance(assignees, list), ( + f"Update {i} assignees must be a list" + ) for assignee in assignees: - assert isinstance(assignee, str), f"Update {i} assignee must be a string" + assert isinstance(assignee, str), ( + f"Update {i} assignee must be a string" + ) - def test_labels_format_is_valid_when_present(self, dependabot_config): + def test_labels_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: """Test that labels format is valid when present.""" - updates = dependabot_config.get('updates', []) - + updates = dependabot_config.get("updates", []) + for i, update in enumerate(updates): - if 'labels' in update: - labels = update['labels'] - assert isinstance(labels, list), f"Update {i} labels must be a list" + labels = update.get("labels") + if labels is not None: + assert isinstance(labels, list), ( + f"Update {i} labels must be a list" + ) for label in labels: - assert isinstance(label, str), f"Update {i} label must be a string" + assert isinstance(label, str), ( + f"Update {i} label must be a string" + ) - def test_commit_message_format_is_valid_when_present(self, dependabot_config): + def test_commit_message_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: """Test that commit-message format is valid when present.""" - updates = dependabot_config.get('updates', []) - + updates = dependabot_config.get("updates", []) + for i, update in enumerate(updates): - if 'commit-message' in update: - commit_message = update['commit-message'] - assert isinstance(commit_message, dict), f"Update {i} commit-message must be a dictionary" - - if 'prefix' in commit_message: - assert isinstance(commit_message['prefix'], str), f"Update {i} commit-message prefix must be a string" - - if 'include' in commit_message: - include = commit_message['include'] - assert include in ['scope'], f"Update {i} commit-message include must be 'scope'" - - def test_rebase_strategy_is_valid_when_present(self, dependabot_config): + commit_message = update.get("commit-message") + if commit_message is not None: + assert isinstance(commit_message, dict), ( + f"Update {i} commit-message must be a dictionary" + ) + + prefix = commit_message.get("prefix") + if prefix is not None: + assert isinstance(prefix, str), ( + f"Update {i} commit-message prefix must be a string" + ) + + include = commit_message.get("include") + if include is not None: + assert include == "scope", ( + f"Update {i} commit-message include must be 'scope'" + ) + + def test_rebase_strategy_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: """Test that rebase-strategy values are valid when present.""" - valid_strategies = ['auto', 'disabled'] - updates = dependabot_config.get('updates', []) - + valid_strategies = ["auto", "disabled"] + updates = dependabot_config.get("updates", []) + for i, update in enumerate(updates): - if 'rebase-strategy' in update: - strategy = update['rebase-strategy'] - assert strategy in valid_strategies, f"Update {i} has invalid rebase-strategy: {strategy}" + strategy = update.get("rebase-strategy") + if strategy is not None: + assert strategy in valid_strategies, ( + f"Update {i} has invalid rebase-strategy: {strategy}" + ) - def test_allow_format_is_valid_when_present(self, dependabot_config): + def test_allow_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: """Test that allow format is valid when present.""" - updates = dependabot_config.get('updates', []) - + valid_types = ["direct", "indirect", "all"] + updates = dependabot_config.get("updates", []) + for i, update in enumerate(updates): - if 'allow' in update: - allow = update['allow'] + allow = update.get("allow") + if allow is not None: assert isinstance(allow, list), f"Update {i} allow must be a list" - + for allow_item in allow: - assert isinstance(allow_item, dict), f"Update {i} allow item must be a dictionary" - assert 'dependency-type' in allow_item, f"Update {i} allow item must have 'dependency-type'" - - dep_type = allow_item['dependency-type'] - valid_types = ['direct', 'indirect', 'all'] - assert dep_type in valid_types, f"Update {i} allow item has invalid dependency-type: {dep_type}" - - def test_ignore_format_is_valid_when_present(self, dependabot_config): + assert isinstance(allow_item, dict), ( + f"Update {i} allow item must be a dictionary" + ) + dep_type = allow_item.get("dependency-type") + assert dep_type in valid_types, ( + f"Update {i} allow item has invalid dependency-type: {dep_type}" + ) + + def test_ignore_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: """Test that ignore format is valid when present.""" - updates = dependabot_config.get('updates', []) - + updates = dependabot_config.get("updates", []) + for i, update in enumerate(updates): - if 'ignore' in update: - ignore = update['ignore'] - assert isinstance(ignore, list), f"Update {i} ignore must be a list" - - for ignore_item in ignore: - assert isinstance(ignore_item, dict), f"Update {i} ignore item must be a dictionary" - assert 'dependency-name' in ignore_item, f"Update {i} ignore item must have 'dependency-name'" + ignore = update.get("ignore") + if ignore is not None: + assert isinstance(ignore, list), ( + f"Update {i} ignore must be a list" + ) - def test_no_duplicate_package_ecosystem_directory_combinations(self, dependabot_config): + for ignore_item in ignore: + assert isinstance(ignore_item, dict), ( + f"Update {i} ignore item must be a dictionary" + ) + assert "dependency-name" in ignore_item, ( + f"Update {i} ignore item must have 'dependency-name'" + ) + + def test_no_duplicate_package_ecosystem_directory_combinations( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that there are no duplicate package-ecosystem and directory combinations.""" - updates = dependabot_config.get('updates', []) - combinations = [] - - for update in updates: - combination = (update.get('package-ecosystem'), update.get('directory')) - assert combination not in combinations, f"Duplicate combination found: {combination}" - combinations.append(combination) + updates = dependabot_config.get("updates", []) + combinations: List[Any] = [] - def test_config_follows_best_practices(self, dependabot_config): + for update in updates: + combo = ( + update.get("package-ecosystem"), + update.get("directory"), + ) + assert combo not in combinations, f"Duplicate combination found: {combo}" + combinations.append(combo) + + def test_config_follows_best_practices(self, dependabot_config: Dict[str, Any]) -> None: """Test that the configuration follows best practices.""" - updates = dependabot_config.get('updates', []) - - # Check for reasonable open-pull-requests-limit - for i, update in enumerate(updates): - if 'open-pull-requests-limit' in update: - limit = update['open-pull-requests-limit'] - assert limit <= 10, f"Update {i} open-pull-requests-limit should be <= 10 for better management" + updates = dependabot_config.get("updates", []) - def test_config_has_security_updates_enabled(self, dependabot_config): + for i, update in enumerate(updates): + limit = update.get("open-pull-requests-limit") + if limit is not None: + assert limit <= 10, ( + f"Update {i} open-pull-requests-limit should be <= 10 for better " + "management" + ) + + def test_config_has_security_updates_enabled(self, dependabot_config: Dict[str, Any]) -> None: """Test that security updates are not explicitly disabled.""" - updates = dependabot_config.get('updates', []) - + updates = dependabot_config.get("updates", []) + for i, update in enumerate(updates): - if 'open-pull-requests-limit' in update: - limit = update['open-pull-requests-limit'] - assert limit > 0, f"Update {i} should allow at least one PR for security updates" - - @pytest.mark.parametrize("ecosystem,expected_files", [ - ("npm", ["package.json"]), - ("pip", ["requirements.txt", "setup.py", "pyproject.toml"]), - ("docker", ["Dockerfile"]), - ("github-actions", [".github/workflows"]), - ]) - def test_ecosystem_has_corresponding_files(self, dependabot_config, ecosystem, expected_files): + limit = update.get("open-pull-requests-limit") + if limit is not None: + assert limit > 0, ( + f"Update {i} should allow at least one PR for security updates" + ) + + @pytest.mark.parametrize( + "ecosystem,expected_files", + [ + ("npm", ["package.json"]), + ( + "pip", + [ + "requirements.txt", + "setup.py", + "pyproject.toml", + ], + ), + ("docker", ["Dockerfile"]), + ("github-actions", [".github/workflows"]), + ], + ) + def test_ecosystem_has_corresponding_files( + self, + dependabot_config: Dict[str, Any], + ecosystem: str, + expected_files: List[str], + ) -> None: """Test that ecosystems have corresponding files in the repository.""" - updates = dependabot_config.get('updates', []) - ecosystems_in_config = [update.get('package-ecosystem') for update in updates] - + updates = dependabot_config.get("updates", []) + ecosystems_in_config = [ + update.get("package-ecosystem") for update in updates + ] + if ecosystem in ecosystems_in_config: for expected_file in expected_files: file_path = Path(expected_file) - assert file_path.exists() or any(Path(".").glob(f"**/{expected_file}")), \ - f"Expected file {expected_file} not found for ecosystem {ecosystem}" + assert file_path.exists() or any( + Path(".").glob(f"**/{expected_file}") + ), f"Expected file {expected_file} not found for ecosystem {ecosystem}" - def test_config_file_permissions(self, dependabot_config_path): + def test_config_file_permissions(self, dependabot_config_path: Path) -> None: """Test that the config file has appropriate permissions.""" import stat + file_stat = os.stat(dependabot_config_path) mode = file_stat.st_mode - + # Check that file is readable assert mode & stat.S_IRUSR, "Config file should be readable by owner" assert mode & stat.S_IRGRP, "Config file should be readable by group" assert mode & stat.S_IROTH, "Config file should be readable by others" - def test_yaml_structure_depth_is_reasonable(self, dependabot_config): + def test_yaml_structure_depth_is_reasonable(self, dependabot_config: Dict[str, Any]) -> None: """Test that the YAML structure doesn't have excessive nesting.""" - def get_max_depth(obj, current_depth=0): + def get_max_depth(obj: Any, current_depth: int = 0) -> int: if isinstance(obj, dict): - return max([get_max_depth(v, current_depth + 1) for v in obj.values()] + [current_depth]) - elif isinstance(obj, list): - return max([get_max_depth(item, current_depth + 1) for item in obj] + [current_depth]) - else: - return current_depth - + return max( + [get_max_depth(v, current_depth + 1) for v in obj.values()] + + [current_depth] + ) + if isinstance(obj, list): + return max( + [get_max_depth(item, current_depth + 1) for item in obj] + + [current_depth] + ) + return current_depth + max_depth = get_max_depth(dependabot_config) assert max_depth <= 5, f"YAML structure is too deeply nested: {max_depth} levels" - def test_config_contains_no_sensitive_information(self, dependabot_config_path): + def test_config_contains_no_sensitive_information(self, dependabot_config_path: Path) -> None: """Test that the config file doesn't contain sensitive information.""" sensitive_patterns = [ - 'password', 'secret', 'token', 'key', 'credential', - 'auth', 'login', 'passwd', 'pass' + "password", + "secret", + "token", + "key", + "credential", + "auth", + "login", + "passwd", + "pass", ] - - with open(dependabot_config_path, 'r') as f: - content = f.read().lower() - + + content = dependabot_config_path.read_text().lower() for pattern in sensitive_patterns: - assert pattern not in content, f"Potential sensitive information found: {pattern}" \ No newline at end of file + assert ( + pattern not in content + ), f"Potential sensitive information found: {pattern}" \ No newline at end of file From 34dd21e1e3ce47139f3b76b2ce5abf676d22689f Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 21:48:20 +0000 Subject: [PATCH 3/4] Fix UTG issues (iteration 2) --- .github/tests/test_dependabot_config.py | 234 ++++++++++++++---------- 1 file changed, 140 insertions(+), 94 deletions(-) diff --git a/.github/tests/test_dependabot_config.py b/.github/tests/test_dependabot_config.py index ad9d351..11bd59c 100644 --- a/.github/tests/test_dependabot_config.py +++ b/.github/tests/test_dependabot_config.py @@ -30,7 +30,9 @@ def dependabot_config(self, dependabot_config_path: Path) -> Dict[str, Any]: def test_config_file_exists(self, dependabot_config_path: Path) -> None: """Test that the dependabot configuration file exists.""" - assert dependabot_config_path.exists(), "Dependabot configuration file should exist" + assert ( + dependabot_config_path.exists() + ), "Dependabot configuration file should exist" def test_config_file_is_valid_yaml(self, dependabot_config_path: Path) -> None: """Test that the dependabot configuration file is valid YAML.""" @@ -40,11 +42,15 @@ def test_config_file_is_valid_yaml(self, dependabot_config_path: Path) -> None: except yaml.YAMLError as e: pytest.fail(f"Invalid YAML syntax: {e}") - def test_config_has_required_version_key(self, dependabot_config: Dict[str, Any]) -> None: + def test_config_has_required_version_key( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that the configuration has the required 'version' key.""" assert "version" in dependabot_config, "Configuration must have 'version' key" - def test_config_version_is_supported(self, dependabot_config: Dict[str, Any]) -> None: + def test_config_version_is_supported( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that the configuration uses a supported version.""" supported_versions = [2] version = dependabot_config.get("version") @@ -66,7 +72,9 @@ def test_updates_list_not_empty(self, dependabot_config: Dict[str, Any]) -> None updates = dependabot_config.get("updates", []) assert updates, "The 'updates' list should not be empty" - def test_each_update_has_required_keys(self, dependabot_config: Dict[str, Any]) -> None: + def test_each_update_has_required_keys( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that each update entry has required keys.""" required_keys = ["package-ecosystem", "directory", "schedule"] updates = dependabot_config.get("updates", []) @@ -76,7 +84,9 @@ def test_each_update_has_required_keys(self, dependabot_config: Dict[str, Any]) for key in required_keys: assert key in update, f"Update {i} missing required key: {key}" - def test_package_ecosystem_values_are_valid(self, dependabot_config: Dict[str, Any]) -> None: + def test_package_ecosystem_values_are_valid( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that package-ecosystem values are valid.""" valid_ecosystems = [ "bundler", @@ -104,7 +114,9 @@ def test_package_ecosystem_values_are_valid(self, dependabot_config: Dict[str, A f"Update {i} has invalid package-ecosystem: {ecosystem}" ) - def test_directory_values_are_valid_paths(self, dependabot_config: Dict[str, Any]) -> None: + def test_directory_values_are_valid_paths( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that directory values are valid paths.""" updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): @@ -114,7 +126,9 @@ def test_directory_values_are_valid_paths(self, dependabot_config: Dict[str, Any "/" ), f"Update {i} directory must start with '/'" - def test_schedule_has_required_interval(self, dependabot_config: Dict[str, Any]) -> None: + def test_schedule_has_required_interval( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that each schedule has a required interval.""" updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): @@ -124,7 +138,9 @@ def test_schedule_has_required_interval(self, dependabot_config: Dict[str, Any]) ), f"Update {i} schedule must be a dictionary" assert "interval" in schedule, f"Update {i} schedule missing 'interval' key" - def test_schedule_interval_values_are_valid(self, dependabot_config: Dict[str, Any]) -> None: + def test_schedule_interval_values_are_valid( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that schedule interval values are valid.""" valid_intervals = ["daily", "weekly", "monthly"] updates = dependabot_config.get("updates", []) @@ -135,7 +151,9 @@ def test_schedule_interval_values_are_valid(self, dependabot_config: Dict[str, A f"Update {i} has invalid schedule interval: {interval}" ) - def test_schedule_day_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + def test_schedule_day_is_valid_when_present( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that schedule day values are valid when present.""" valid_days = [ "monday", @@ -154,7 +172,9 @@ def test_schedule_day_is_valid_when_present(self, dependabot_config: Dict[str, A day = schedule["day"] assert day in valid_days, f"Update {i} has invalid schedule day: {day}" - def test_schedule_time_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + def test_schedule_time_format_is_valid_when_present( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that schedule time values are in valid format when present.""" import re @@ -165,122 +185,134 @@ def test_schedule_time_format_is_valid_when_present(self, dependabot_config: Dic schedule = update.get("schedule", {}) if "time" in schedule: time = schedule["time"] - assert isinstance(time, str), ( - f"Update {i} schedule time must be a string" - ) - assert time_pattern.match(time), ( - f"Update {i} has invalid time format: {time}" - ) - - def test_schedule_timezone_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + assert isinstance( + time, str + ), f"Update {i} schedule time must be a string" + assert time_pattern.match( + time + ), f"Update {i} has invalid time format: {time}" + + def test_schedule_timezone_is_valid_when_present( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that schedule timezone values are valid when present.""" updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): timezone = update.get("schedule", {}).get("timezone") if timezone is not None: - assert isinstance(timezone, str), ( - f"Update {i} schedule timezone must be a string" - ) - assert timezone, ( - f"Update {i} schedule timezone cannot be empty" - ) + assert isinstance( + timezone, str + ), f"Update {i} schedule timezone must be a string" + assert timezone, f"Update {i} schedule timezone cannot be empty" - def test_open_pull_requests_limit_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + def test_open_pull_requests_limit_is_valid_when_present( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that open-pull-requests-limit values are valid when present.""" updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): if "open-pull-requests-limit" in update: limit = update["open-pull-requests-limit"] - assert isinstance(limit, int), ( - f"Update {i} open-pull-requests-limit must be an integer" - ) - assert 0 <= limit <= 20, ( - f"Update {i} open-pull-requests-limit must be between 0 and 20" - ) - - def test_target_branch_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + assert isinstance( + limit, int + ), f"Update {i} open-pull-requests-limit must be an integer" + assert ( + 0 <= limit <= 20 + ), f"Update {i} open-pull-requests-limit must be between 0 and 20" + + def test_target_branch_is_valid_when_present( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that target-branch values are valid when present.""" updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): if "target-branch" in update: branch = update["target-branch"] - assert isinstance(branch, str), ( - f"Update {i} target-branch must be a string" - ) + assert isinstance( + branch, str + ), f"Update {i} target-branch must be a string" assert branch, f"Update {i} target-branch cannot be empty" - def test_reviewers_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + def test_reviewers_format_is_valid_when_present( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that reviewers format is valid when present.""" updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): reviewers = update.get("reviewers") if reviewers is not None: - assert isinstance(reviewers, list), ( - f"Update {i} reviewers must be a list" - ) + assert isinstance( + reviewers, list + ), f"Update {i} reviewers must be a list" for reviewer in reviewers: - assert isinstance(reviewer, str), ( - f"Update {i} reviewer must be a string" - ) + assert isinstance( + reviewer, str + ), f"Update {i} reviewer must be a string" - def test_assignees_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + def test_assignees_format_is_valid_when_present( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that assignees format is valid when present.""" updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): assignees = update.get("assignees") if assignees is not None: - assert isinstance(assignees, list), ( - f"Update {i} assignees must be a list" - ) + assert isinstance( + assignees, list + ), f"Update {i} assignees must be a list" for assignee in assignees: - assert isinstance(assignee, str), ( - f"Update {i} assignee must be a string" - ) + assert isinstance( + assignee, str + ), f"Update {i} assignee must be a string" - def test_labels_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + def test_labels_format_is_valid_when_present( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that labels format is valid when present.""" updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): labels = update.get("labels") if labels is not None: - assert isinstance(labels, list), ( - f"Update {i} labels must be a list" - ) + assert isinstance(labels, list), f"Update {i} labels must be a list" for label in labels: - assert isinstance(label, str), ( - f"Update {i} label must be a string" - ) + assert isinstance( + label, str + ), f"Update {i} label must be a string" - def test_commit_message_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + def test_commit_message_format_is_valid_when_present( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that commit-message format is valid when present.""" updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): commit_message = update.get("commit-message") if commit_message is not None: - assert isinstance(commit_message, dict), ( - f"Update {i} commit-message must be a dictionary" - ) + assert isinstance( + commit_message, dict + ), f"Update {i} commit-message must be a dictionary" prefix = commit_message.get("prefix") if prefix is not None: - assert isinstance(prefix, str), ( - f"Update {i} commit-message prefix must be a string" - ) + assert isinstance( + prefix, str + ), f"Update {i} commit-message prefix must be a string" include = commit_message.get("include") if include is not None: - assert include == "scope", ( - f"Update {i} commit-message include must be 'scope'" - ) + assert ( + include == "scope" + ), f"Update {i} commit-message include must be 'scope'" - def test_rebase_strategy_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + def test_rebase_strategy_is_valid_when_present( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that rebase-strategy values are valid when present.""" valid_strategies = ["auto", "disabled"] updates = dependabot_config.get("updates", []) @@ -292,7 +324,9 @@ def test_rebase_strategy_is_valid_when_present(self, dependabot_config: Dict[str f"Update {i} has invalid rebase-strategy: {strategy}" ) - def test_allow_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + def test_allow_format_is_valid_when_present( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that allow format is valid when present.""" valid_types = ["direct", "indirect", "all"] updates = dependabot_config.get("updates", []) @@ -303,32 +337,34 @@ def test_allow_format_is_valid_when_present(self, dependabot_config: Dict[str, A assert isinstance(allow, list), f"Update {i} allow must be a list" for allow_item in allow: - assert isinstance(allow_item, dict), ( - f"Update {i} allow item must be a dictionary" - ) + assert isinstance( + allow_item, dict + ), f"Update {i} allow item must be a dictionary" dep_type = allow_item.get("dependency-type") assert dep_type in valid_types, ( f"Update {i} allow item has invalid dependency-type: {dep_type}" ) - def test_ignore_format_is_valid_when_present(self, dependabot_config: Dict[str, Any]) -> None: + def test_ignore_format_is_valid_when_present( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that ignore format is valid when present.""" updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): ignore = update.get("ignore") if ignore is not None: - assert isinstance(ignore, list), ( - f"Update {i} ignore must be a list" - ) + assert isinstance( + ignore, list + ), f"Update {i} ignore must be a list" for ignore_item in ignore: - assert isinstance(ignore_item, dict), ( - f"Update {i} ignore item must be a dictionary" - ) - assert "dependency-name" in ignore_item, ( - f"Update {i} ignore item must have 'dependency-name'" - ) + assert isinstance( + ignore_item, dict + ), f"Update {i} ignore item must be a dictionary" + assert ( + "dependency-name" in ignore_item + ), f"Update {i} ignore item must have 'dependency-name'" def test_no_duplicate_package_ecosystem_directory_combinations( self, dependabot_config: Dict[str, Any] @@ -345,28 +381,31 @@ def test_no_duplicate_package_ecosystem_directory_combinations( assert combo not in combinations, f"Duplicate combination found: {combo}" combinations.append(combo) - def test_config_follows_best_practices(self, dependabot_config: Dict[str, Any]) -> None: + def test_config_follows_best_practices( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that the configuration follows best practices.""" updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): limit = update.get("open-pull-requests-limit") if limit is not None: - assert limit <= 10, ( - f"Update {i} open-pull-requests-limit should be <= 10 for better " - "management" - ) + assert ( + limit <= 10 + ), f"Update {i} open-pull-requests-limit should be <= 10 for better management" - def test_config_has_security_updates_enabled(self, dependabot_config: Dict[str, Any]) -> None: + def test_config_has_security_updates_enabled( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that security updates are not explicitly disabled.""" updates = dependabot_config.get("updates", []) for i, update in enumerate(updates): limit = update.get("open-pull-requests-limit") if limit is not None: - assert limit > 0, ( - f"Update {i} should allow at least one PR for security updates" - ) + assert ( + limit > 0 + ), f"Update {i} should allow at least one PR for security updates" @pytest.mark.parametrize( "ecosystem,expected_files", @@ -415,8 +454,11 @@ def test_config_file_permissions(self, dependabot_config_path: Path) -> None: assert mode & stat.S_IRGRP, "Config file should be readable by group" assert mode & stat.S_IROTH, "Config file should be readable by others" - def test_yaml_structure_depth_is_reasonable(self, dependabot_config: Dict[str, Any]) -> None: + def test_yaml_structure_depth_is_reasonable( + self, dependabot_config: Dict[str, Any] + ) -> None: """Test that the YAML structure doesn't have excessive nesting.""" + def get_max_depth(obj: Any, current_depth: int = 0) -> int: if isinstance(obj, dict): return max( @@ -431,9 +473,13 @@ def get_max_depth(obj: Any, current_depth: int = 0) -> int: return current_depth max_depth = get_max_depth(dependabot_config) - assert max_depth <= 5, f"YAML structure is too deeply nested: {max_depth} levels" + assert ( + max_depth <= 5 + ), f"YAML structure is too deeply nested: {max_depth} levels" - def test_config_contains_no_sensitive_information(self, dependabot_config_path: Path) -> None: + def test_config_contains_no_sensitive_information( + self, dependabot_config_path: Path + ) -> None: """Test that the config file doesn't contain sensitive information.""" sensitive_patterns = [ "password", From e2b6cd4644f72aff9d125164c38309ff1cb9d2a1 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 21:58:18 +0000 Subject: [PATCH 4/4] Fix UTG issues (iteration 3) --- .github/tests/test_dependabot_config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/tests/test_dependabot_config.py b/.github/tests/test_dependabot_config.py index 11bd59c..6e12959 100644 --- a/.github/tests/test_dependabot_config.py +++ b/.github/tests/test_dependabot_config.py @@ -55,7 +55,8 @@ def test_config_version_is_supported( supported_versions = [2] version = dependabot_config.get("version") assert version in supported_versions, ( - f"Version {version} is not supported. Supported versions: {supported_versions}" + f"Version {version} is not supported. " + f"Supported versions: {supported_versions}" ) def test_config_has_updates_key(self, dependabot_config: Dict[str, Any]) -> None: