Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f83ee53b6e | |||
| 9fff3c883d | |||
| 583229af05 | |||
| 9ab1455dbb | |||
| 209c628c5f | |||
| 7f7f5b8228 | |||
| 1f92dad033 | |||
| cf9a21278d | |||
| 605d0403ed | |||
| 75769927ae | |||
| ff9f397618 | |||
| 50c135b336 | |||
| ecaab5ba3a | |||
| 575fae1b3b | |||
| 04aceae6b2 | |||
| 5b32e78a63 | |||
| b28a802403 | |||
| 644c3ac03c | |||
| 47898c7ddb | |||
| 3058a53097 | |||
| fc3803cfe7 | |||
| 981d4e5ae8 | |||
| 748e779740 | |||
| 5a12112c96 | |||
| d9cbeaf66e | |||
| f6b9bfda13 | |||
| 003ca3c52b | |||
| efdc09af01 | |||
| ee81f14f34 | |||
| 492062f5de | |||
| 5748f919f7 | |||
| 9b1f71d7c4 | |||
| 538cd82400 | |||
| 1a940442ba | |||
| 3da939a38d | |||
| 6882dab217 | |||
| fb9cabcd02 | |||
| b5f0cc5837 | |||
| 1006c7c4f6 | |||
| a09213a46f | |||
| ecc88227fe | |||
| 7a740c1906 | |||
| ab094b87d7 | |||
| 23fef7df19 | |||
| 5be61d84ac | |||
| 817cd9b835 | |||
| ff3110225f |
@@ -20,38 +20,10 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -e ".[dev]"
|
||||
pip install -e .
|
||||
|
||||
- name: Run tests
|
||||
run: pytest tests/ -v --cov=config_auditor
|
||||
|
||||
- name: Run linting
|
||||
run: ruff check config_auditor/ tests/
|
||||
|
||||
build:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
cache: 'pip'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip install --upgrade pip
|
||||
pip install .
|
||||
|
||||
- name: Build package
|
||||
run: |
|
||||
pip install build
|
||||
python -m build
|
||||
|
||||
- name: Upload package
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: dist
|
||||
path: dist/
|
||||
run: ruff check .
|
||||
|
||||
101
.gitignore
vendored
101
.gitignore
vendored
@@ -1,11 +1,94 @@
|
||||
*.pyc
|
||||
__pycache__/
|
||||
venv/
|
||||
# =============================================================================
|
||||
# 7000%AUTO .gitignore
|
||||
# =============================================================================
|
||||
|
||||
# Environment
|
||||
.env
|
||||
*.egg-info/
|
||||
.coverage
|
||||
.pytest_cache/
|
||||
.mypy_cache/
|
||||
.ruff_cache/
|
||||
.dist/
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# Virtual environments
|
||||
venv/
|
||||
ENV/
|
||||
env/
|
||||
.venv/
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.project
|
||||
.pydevproject
|
||||
.settings/
|
||||
|
||||
# Testing
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
htmlcov/
|
||||
.pytest_cache/
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
|
||||
# Logs
|
||||
logs/
|
||||
*.log
|
||||
|
||||
# Database
|
||||
data/
|
||||
*.db
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
|
||||
# Workspace (generated projects)
|
||||
workspace/
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# Docker
|
||||
.docker/
|
||||
|
||||
# Temporary files
|
||||
tmp/
|
||||
temp/
|
||||
*.tmp
|
||||
*.temp
|
||||
|
||||
# Secrets
|
||||
*.pem
|
||||
*.key
|
||||
secrets/
|
||||
|
||||
13
app/MANIFEST.in
Normal file
13
app/MANIFEST.in
Normal file
@@ -0,0 +1,13 @@
|
||||
include README.md
|
||||
include LICENSE
|
||||
include pyproject.toml
|
||||
include setup.py
|
||||
|
||||
exclude tests/*
|
||||
exclude fixtures/*
|
||||
exclude database/*
|
||||
exclude depnav/*
|
||||
exclude gitignore_generator/*
|
||||
exclude mcp_servers/*
|
||||
exclude orchestrator/*
|
||||
exclude web/*
|
||||
60
app/pyproject.toml
Normal file
60
app/pyproject.toml
Normal file
@@ -0,0 +1,60 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=61.0", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "config_auditor"
|
||||
version = "1.0.0"
|
||||
description = "A CLI tool that scans project configuration files and detects issues"
|
||||
readme = "README.md"
|
||||
license = {text = "MIT"}
|
||||
requires-python = ">=3.9"
|
||||
authors = [
|
||||
{name = "Config Auditor Team", email = "dev@example.com"}
|
||||
]
|
||||
keywords = ["config", "cli", "audit", "scanner"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Environment :: Console",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
]
|
||||
dependencies = [
|
||||
"click>=8.0.0",
|
||||
"PyYAML>=6.0",
|
||||
"toml>=0.10.0",
|
||||
"requests>=2.31.0",
|
||||
"semver>=3.0.0",
|
||||
"packaging>=23.0",
|
||||
"ollama>=0.1.41",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
config-auditor = "config_auditor.cli:main"
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"pytest>=7.0.0",
|
||||
"pytest-cov>=4.0.0",
|
||||
"pytest-mock>=3.10.0",
|
||||
"ruff>=0.1.0",
|
||||
"mypy>=1.0.0",
|
||||
"types-requests>=2.25.0",
|
||||
]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["."]
|
||||
include = ["config_auditor"]
|
||||
exclude = ["tests", "fixtures"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
python_files = ["test_*.py"]
|
||||
python_classes = ["Test*"]
|
||||
python_functions = ["test_*"]
|
||||
addopts = "-v --cov=config_auditor --cov-report=term-missing"
|
||||
@@ -1,6 +1,4 @@
|
||||
import sys
|
||||
import click
|
||||
from pathlib import Path
|
||||
|
||||
from config_auditor.cli import cli
|
||||
|
||||
|
||||
@@ -201,10 +201,8 @@ def generate(ctx: click.Context, template: Optional[str]):
|
||||
|
||||
@cli.command()
|
||||
@click.pass_context
|
||||
def config(ctx: click Context):
|
||||
def config(ctx: click.Context):
|
||||
"""Show current configuration."""
|
||||
import yaml
|
||||
|
||||
config_path = Path("config.yaml")
|
||||
if config_path.exists():
|
||||
content = config_path.read_text()
|
||||
|
||||
@@ -2,7 +2,6 @@ from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, List, Optional
|
||||
import json
|
||||
import shutil
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Dict, Optional
|
||||
import json
|
||||
import requests
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
from packaging import version
|
||||
|
||||
58
pyproject.toml
Normal file
58
pyproject.toml
Normal file
@@ -0,0 +1,58 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=61.0", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "config_auditor"
|
||||
version = "1.0.0"
|
||||
description = "A CLI tool that scans project configuration files and detects issues"
|
||||
readme = "README.md"
|
||||
license = {text = "MIT"}
|
||||
requires-python = ">=3.9"
|
||||
authors = [
|
||||
{name = "Config Auditor Team", email = "dev@example.com"}
|
||||
]
|
||||
keywords = ["config", "cli", "audit", "scanner"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Environment :: Console",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
]
|
||||
dependencies = [
|
||||
"click>=8.0.0",
|
||||
"PyYAML>=6.0",
|
||||
"toml>=0.10.0",
|
||||
"requests>=2.31.0",
|
||||
"semver>=3.0.0",
|
||||
"packaging>=23.0",
|
||||
"ollama>=0.1.41",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
config-auditor = "config_auditor.cli:main"
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"pytest>=7.0.0",
|
||||
"pytest-cov>=4.0.0",
|
||||
"pytest-mock>=3.10.0",
|
||||
"ruff>=0.1.0",
|
||||
"mypy>=1.0.0",
|
||||
"types-requests>=2.25.0",
|
||||
]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["."]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
python_files = ["test_*.py"]
|
||||
python_classes = ["Test*"]
|
||||
python_functions = ["test_*"]
|
||||
addopts = "-v --cov=config_auditor --cov-report=term-missing"
|
||||
@@ -1,6 +1,4 @@
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import pytest
|
||||
from click.testing import CliRunner
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
from config_auditor.fixes import (
|
||||
Fixer,
|
||||
@@ -84,7 +82,7 @@ class TestFixer:
|
||||
config_path.write_text(content)
|
||||
|
||||
fixer = Fixer(dry_run=True)
|
||||
fix_count = fixer.fix_config(config_path, "json", content)
|
||||
fixer.fix_config(config_path, "json", content)
|
||||
|
||||
actual_content = config_path.read_text()
|
||||
assert actual_content == content
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import json
|
||||
import pytest
|
||||
|
||||
from config_auditor.generate import ConfigGenerator
|
||||
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import pytest
|
||||
import os
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
from unittest.mock import Mock, patch, MagicMock
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from config_auditor.llm import (
|
||||
LLMClient,
|
||||
OllamaClient,
|
||||
FallbackClient,
|
||||
LLMProvider,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
from config_auditor.discovery import ConfigDiscovery
|
||||
from config_auditor.parsers import ParserFactory, JsonParser, YamlParser, TomlParser
|
||||
@@ -10,7 +8,6 @@ from config_auditor.rules import (
|
||||
DeprecatedPackageRule,
|
||||
OutdatedVersionRule,
|
||||
MissingTypeCheckingRule,
|
||||
SecurityVulnerabilityRule,
|
||||
MissingScriptsRule,
|
||||
PythonProjectMetaRule,
|
||||
)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
|
||||
from config_auditor.report import ReportGenerator
|
||||
from config_auditor.rules import Issue
|
||||
|
||||
@@ -1,64 +1,59 @@
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
|
||||
from config_auditor.utils import (
|
||||
find_config_file,
|
||||
get_exit_code,
|
||||
format_severity,
|
||||
validate_path,
|
||||
)
|
||||
|
||||
|
||||
class TestUtils:
|
||||
def test_find_config_file_exists(self):
|
||||
class TestFindConfigFile:
|
||||
def test_finds_config_in_current_directory(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
(Path(tmpdir) / "package.json").write_text("{}")
|
||||
config_path = Path(tmpdir) / "config.yaml"
|
||||
config_path.write_text("key: value")
|
||||
|
||||
result = find_config_file(Path(tmpdir), ["package.json"])
|
||||
result = find_config_file(Path(tmpdir), ["config.yaml"])
|
||||
|
||||
assert result is not None
|
||||
assert result.name == "package.json"
|
||||
assert result == config_path
|
||||
|
||||
def test_find_config_file_not_exists(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
result = find_config_file(Path(tmpdir), ["nonexistent.json"])
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_find_config_file_in_parent(self):
|
||||
def test_finds_config_in_parent_directory(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
subdir = Path(tmpdir) / "subdir"
|
||||
subdir.mkdir()
|
||||
(Path(tmpdir) / "package.json").write_text("{}")
|
||||
|
||||
result = find_config_file(subdir, ["package.json"])
|
||||
config_path = Path(tmpdir) / "config.yaml"
|
||||
config_path.write_text("key: value")
|
||||
|
||||
assert result is not None
|
||||
result = find_config_file(subdir, ["config.yaml"])
|
||||
|
||||
def test_get_exit_code_no_issues(self):
|
||||
result = get_exit_code(0, 0)
|
||||
assert result == 0
|
||||
assert result == config_path
|
||||
|
||||
def test_get_exit_code_has_issues(self):
|
||||
result = get_exit_code(5, 0)
|
||||
assert result == 4
|
||||
|
||||
def test_get_exit_code_critical(self):
|
||||
result = get_exit_code(3, 2)
|
||||
assert result == 4
|
||||
|
||||
def test_validate_path_exists(self):
|
||||
def test_returns_none_when_not_found(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
result = validate_path(tmpdir)
|
||||
assert result.exists()
|
||||
result = find_config_file(Path(tmpdir), ["nonexistent.yaml"])
|
||||
|
||||
def test_validate_path_not_exists(self):
|
||||
with pytest.raises(SystemExit) as excinfo:
|
||||
validate_path("/nonexistent/path")
|
||||
assert excinfo.value.code == 2
|
||||
assert result is None
|
||||
|
||||
def test_validate_path_is_file(self):
|
||||
with tempfile.NamedTemporaryFile() as f:
|
||||
with pytest.raises(SystemExit) as excinfo:
|
||||
validate_path(f.name)
|
||||
assert excinfo.value.code == 2
|
||||
|
||||
class TestGetExitCode:
|
||||
def test_returns_4_for_critical_issues(self):
|
||||
assert get_exit_code(1, 1) == 4
|
||||
|
||||
def test_returns_4_for_warnings_without_critical(self):
|
||||
assert get_exit_code(3, 0) == 4
|
||||
|
||||
def test_returns_0_for_no_issues(self):
|
||||
assert get_exit_code(0, 0) == 0
|
||||
|
||||
|
||||
class TestFormatSeverity:
|
||||
def test_format_severity_colors(self):
|
||||
assert format_severity("critical") == "red"
|
||||
assert format_severity("warning") == "yellow"
|
||||
assert format_severity("info") == "blue"
|
||||
|
||||
def test_format_severity_default(self):
|
||||
assert format_severity("unknown") == "white"
|
||||
|
||||
Reference in New Issue
Block a user