Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
if: github.ref == 'refs/heads/main' && github.repository == 'warestack/watchflow'
steps:
# Deploy to GitHub Pages
- name: "Deploy to GitHub Pages"
Expand Down
40 changes: 10 additions & 30 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,30 @@ default_stages:
- pre-commit
- pre-push

# Configuration for pre-commit hooks
repos:
# General hooks from the pre-commit-hooks repository
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
rev: v6.0.0
hooks:
- id: trailing-whitespace
# Removes any trailing whitespace from lines in text files
- id: end-of-file-fixer
# Ensures files end with a newline
- id: check-yaml
exclude: '^helm-chart/templates.*\.yaml$|^mkdocs\.yml$'
# Checks YAML files for syntax errors
- id: check-json
# Checks JSON files for syntax errors
- id: check-ast
name: "Check Python syntax (AST validation)"
# Validates that Python files have valid syntax
- id: check-added-large-files

# Ruff hooks for Python linting and formatting
# Ruff: The One Tool to Rule Them All
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.9
rev: v0.3.0
Comment on lines 17 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

latest version of ruff linter 2025 2026

💡 Result:

As of January 24, 2026:

  • Latest Ruff release (GitHub): 0.14.14, released January 22, 2026. [1]
  • Latest Ruff version on PyPI: 0.14.13, uploaded January 15, 2026. [2]

Sources: [1] [2]


Update Ruff to a current version—v0.3.0 is outdated.

The pinned version v0.3.0 is approximately two years old (from early 2024). The current latest version is v0.14.14 (released January 22, 2026). This appears to be a downgrade or typo. Update to at least v0.14.13 or v0.14.14 to benefit from bug fixes, security updates, and improvements across 11+ minor versions.

🤖 Prompt for AI Agents
In @.pre-commit-config.yaml around lines 17 - 18, The pre-commit entry for the
Ruff hook is pinned to an outdated revision (repo:
https://github.com/astral-sh/ruff-pre-commit with rev: v0.3.0); update the rev
to a current release (preferably v0.14.14, or at minimum v0.14.13) in the
.pre-commit-config.yaml and then run pre-commit autoupdate or reinstall hooks to
ensure the newer Ruff version is used.

hooks:
# First, run ruff format - won't change imports but will format them
- id: ruff-format
name: "Format code (without changing imports)"

# Then, use a single ruff pass for both import sorting and linting
# Linter (Fixes imports, modernizes syntax, checks bugs)
- id: ruff
name: "Linting and import sorting"
args: ["--fix"]

# Pyupgrade: Check and fix Python version incompatibilities and outdated syntax
- repo: https://github.com/asottile/pyupgrade
rev: v3.15.2
hooks:
- id: pyupgrade
name: "Upgrade syntax for Python 3.12+"
args: [--py312-plus]
# Auto-fixes outdated syntax to Python 3.12+ compatible code
args: [--fix, --exit-non-zero-on-fix]
# Formatter (Replaces Black)
- id: ruff-format

# Conventional pre-commit hooks for commit messages
# Convention Enforcement
- repo: https://github.com/compilerla/conventional-pre-commit
rev: v4.0.0
rev: v4.3.0
hooks:
- id: conventional-pre-commit
stages: [commit-msg]
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,11 @@ This format allows for intelligent, context-aware rule evaluation while maintain
## Contributing & Development

For instructions on running tests, local development, and contributing, see [DEVELOPMENT.md](DEVELOPMENT.md).

## Unauthenticated Analysis & Rate Limiting

- The repository analysis endpoint `/v1/rules/recommend` now supports unauthenticated access for public GitHub repositories.
- Anonymous users are limited to 5 requests per hour per IP. Authenticated users are limited to 100 requests per hour.
- Exceeding the limit returns a 429 error with a `Retry-After` header.
- For private repositories, authentication is required.
- The frontend is now fully connected to the backend and no longer uses mock data.
2 changes: 1 addition & 1 deletion docs/benchmarks.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Watchflow's agentic approach to DevOps governance has shown promising results in

### Context Dependency in Enterprise Policies

Our analysis of 70+ enterprise policies from major tech companies revealed a critical insight: **85% of real-world governance policies require context** and cannot be effectively enforced with traditional static rules.
Our analysis of 70 + enterprise policies from major tech companies revealed a critical insight: **85% of real-world governance policies require context** and cannot be effectively enforced with traditional static rules.

**Why this matters:**
- Traditional rules are binary (true/false) and miss nuanced scenarios
Expand Down
9 changes: 9 additions & 0 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,3 +276,12 @@ standards so teams can focus on building, increase trust, and move fast.
- Error rate monitoring
- Capacity planning insights
- Predictive maintenance

---

## Unauthenticated Analysis & Rate Limiting

- The repository analysis endpoint allows public repo analysis without authentication (5 requests/hour/IP for anonymous users).
- Authenticated users can analyze up to 100 repos/hour.
- Exceeding limits returns a 429 error with a Retry-After header.
- Private repo analysis requires authentication.
9 changes: 9 additions & 0 deletions linting_commands.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Run all pre-commit hooks on all files
pre-commit run --all-files

# Run ruff linter and formatter directly (if needed)
ruff check src/
ruff format src/

# Run mypy for type checking
mypy src/
221 changes: 45 additions & 176 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,91 +1,3 @@
[tool.ruff]
# Target Python version
target-version = "py312"
# Line length - restored from old config
line-length = 120
# Indent width
indent-width = 4

# Exclude common directories - restored from old config
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".ipynb_checkpoints",
".mypy_cache",
".nox",
".pants.d",
".pyenv",
".pytest_cache",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
".vscode",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"site-packages",
"venv",
]

[tool.ruff.lint]
# Select a comprehensive set of rules
# Based on recommended practices from Ruff documentation
select = [
"E", # pycodestyle errors
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]

# Common ignores for web development
ignore = [
"E501", # line too long (handled by formatter)
"B008", # do not perform function calls in argument defaults (common in FastAPI)
]

# Allow fixing all enabled rules
fixable = ["ALL"]

# Allow unused variables when underscore-prefixed - restored from old config
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"

[tool.ruff.format]
# Modern formatting options
quote-style = "double"
indent-style = "space"
# Format docstring code blocks
docstring-code-format = true
# Restored from old config
skip-magic-trailing-comma = false
line-ending = "auto"

[tool.ruff.lint.isort]
# Enhanced isort configuration
known-first-party = ["src"]
# Make sure we correctly order the import sections
section-order = [
"future",
"standard-library",
"third-party",
"first-party",
"local-folder",
]
# Add a trailing comma to imports split across multiple lines
split-on-trailing-comma = true
# Combine import statements for the same module
combine-as-imports = true

[project]
name = "watchflow"
version = "0.1.0"
Expand All @@ -96,17 +8,6 @@ license = {text = "Apache Software License 2.0"}
authors = [
{name = "Dimitris Kargatzis", email = "[email protected]"},
]
keywords = ["github", "governance", "ai", "protection", "rules", "enforcement", "collaboration"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Quality Assurance",
]

dependencies = [
"fastapi[standard]>=0.104.0",
"uvicorn[standard]>=0.24.0",
Expand All @@ -124,127 +25,95 @@ dependencies = [
"boto3>=1.40.43",
"anthropic[vertex]>=0.69.0",
"langchain-google-vertexai>=2.1.2",
"giturlparse>=0.1.0",
"structlog>=24.1.0",
"gql[all]>=3.4.0",
]

[project.optional-dependencies]
dev = [
"pytest>=7.4.0",
"pytest-asyncio>=0.21.0",
"pytest-cov>=4.1.0",
"black>=23.0.0",
"isort>=5.12.0",
"flake8>=6.0.0",
"respx>=0.20.0",
"mypy>=1.7.0",
"pre-commit>=3.5.0",
"ruff>=0.1.0", # Replaces black, isort, flake8
]

docs = [
"mkdocs>=1.5.0",
"mkdocs-material>=9.5.0",
"mkdocs-git-revision-date-localized-plugin>=1.2.0",
"mkdocs-minify-plugin>=0.7.0",
"pymdown-extensions>=10.0",
"mkdocs-minify-plugin>=0.8.0",
]

[project.urls]
Homepage = "https://github.com/warestack/watchflow"
Documentation = "https://docs.watchflow.dev"
Repository = "https://github.com/warestack/watchflow"
Issues = "https://github.com/warestack/watchflow/issues"

[project.scripts]
watchflow = "src.main:app"

[tool.black]
line-length = 88
target-version = ['py312']
include = '\.pyi?$'
extend-exclude = '''
/(
# directories
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| build
| dist
)/
'''
# --- RUFF CONFIGURATION (The Enforcer) ---
[tool.ruff]
target-version = "py312"
line-length = 120
indent-width = 4
exclude = [
".git", ".mypy_cache", ".pytest_cache", ".ruff_cache", ".venv", "venv", "__pypackages__",
]

[tool.ruff.lint]
# E/F: Core Python errors
# I: Import sorting (isort replacement)
# B: Bugbear (catches common bugs)
# UP: Pyupgrade (modernizes syntax)
# C4: Comprehensions
# SIM: Simplify (suggests pythonic refactors)
# TCH: Type Checking (enforces specific typing blocks)
select = ["E", "F", "I", "B", "UP", "C4", "SIM", "TCH"]
ignore = [
"E501", # Line too long (handled by formatter)
"B008", # Do not perform function calls in argument defaults (FastAPI Dependency Pattern)
]
fixable = ["ALL"]

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"
docstring-code-format = true

[tool.isort]
profile = "black"
multi_line_output = 3
line_length = 88
known_first_party = ["src"]
[tool.ruff.lint.isort]
known-first-party = ["src"]
combine-as-imports = true

# --- MYPY CONFIGURATION (The Type Cop) ---
[tool.mypy]
python_version = "3.12"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
disallow_untyped_defs = true # No dynamic functions allowed
disallow_incomplete_defs = true # Must type all args
check_untyped_defs = true
disallow_untyped_decorators = true
disallow_untyped_decorators = false # Allow untyped decorators (needed for FastAPI/LangChain)
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true

# --- PYTEST CONFIGURATION ---
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"--strict-config",
"--cov=src",
"--cov-report=term-missing",
"--cov-report=html",
"--cov-report=xml",
]
asyncio_mode = "auto"


[tool.coverage.run]
source = ["src"]
omit = [
"*/tests/*",
"*/test_*",
"*/__pycache__/*",
"*/migrations/*",
]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]

[tool.uv]
dev-dependencies = [
"pytest>=7.4.0",
"pytest-asyncio>=0.21.0",
"pytest-cov>=4.1.0",
"black>=23.0.0",
"isort>=5.12.0",
"flake8>=6.0.0",
"mypy>=1.7.0",
"pre-commit>=3.5.0",
"mkdocs-material>=9.5.0",
"mkdocs-git-revision-date-localized-plugin>=1.2.0",
"mkdocs-minify-plugin>=0.7.0",
"pymdown-extensions>=10.0",
"ruff>=0.1.0",
]
Loading
Loading