Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
0e08dfc
feat: refactor CODEOWNERS integration to fetch dynamically from API
dkargatzis Feb 27, 2026
9656ffd
feat: implement DiffPatternCondition and SecurityPatternCondition
dkargatzis Feb 27, 2026
f2c19a4
style: fix pre-commit issues with line lengths and whitespace
dkargatzis Feb 27, 2026
84d4566
feat: implement UnresolvedCommentsCondition via GraphQL reviewThreads…
dkargatzis Feb 27, 2026
5a699ca
refactor: consolidate GraphQL clients and enforce strong typing with …
dkargatzis Feb 27, 2026
61d5721
feat: implement TestCoverageCondition to enforce test inclusion on so…
dkargatzis Feb 27, 2026
042db61
feat: implement CommentResponseTimeCondition for SLAs
dkargatzis Feb 27, 2026
cba1dfd
feat: add pull_request_review webhook handlers and fix mypy type errors
dkargatzis Feb 27, 2026
5c5da29
docs: add enterprise rules roadmap
dkargatzis Feb 27, 2026
7240244
feat: implement enterprise compliance conditions (Changelog and Signe…
dkargatzis Feb 27, 2026
985a325
feat: implement advanced access control rules for enterprise environm…
dkargatzis Feb 27, 2026
3c93e41
fix: resolve mypy errors and complete missing tests for enterprise rules
dkargatzis Feb 27, 2026
797e531
docs: enhance enterprise rules roadmap with github ecosystem and OSS …
dkargatzis Feb 28, 2026
981a2f2
fix: resolve import errors in webhook handlers and add test coverage
dkargatzis Feb 28, 2026
6d93e65
fix: resolve CI failures and address CodeRabbit review feedback
dkargatzis Mar 1, 2026
1991986
feat: wire enterprise conditions into rule evaluation pipeline
dkargatzis Mar 1, 2026
92140b4
docs: add CHANGELOG and update all docs with complete ruleset reference
dkargatzis Mar 1, 2026
b74bd5a
fix: paginate PR files and reviews API calls to fetch complete data
dkargatzis Mar 1, 2026
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
276 changes: 276 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased] -- PR #59

### Added

- **Diff pattern scanning** -- `DiffPatternCondition` checks added lines in PR
diffs against user-defined restricted regex patterns (e.g. `console\.log`,
`TODO:`). Violations include the filename and matched patterns.
- **Security pattern detection** -- `SecurityPatternCondition` flags hardcoded
secrets, API keys, and sensitive data in PR diffs with CRITICAL severity.
Both conditions share a new `_PatchPatternCondition` base class to eliminate
duplication.
- **Unresolved review comments gate** -- `UnresolvedCommentsCondition` blocks
PR merges when unresolved (non-outdated) review comment threads exist,
using GraphQL `reviewThreads` data from the enricher.
- **Test coverage enforcement** -- `TestCoverageCondition` requires that PRs
modifying source files also touch test files matching a configurable regex
pattern (`test_file_pattern`).
- **Comment response time SLA** -- `CommentResponseTimeCondition` flags
unresolved review threads that have exceeded a configurable hour-based SLA
(`max_comment_response_time_hours`).
- **Signed commits verification** -- `SignedCommitsCondition` ensures all
commits in a PR are cryptographically signed (GPG/SSH/S/MIME), for
regulated environments that require commit provenance.
- **Changelog requirement** -- `ChangelogRequiredCondition` blocks PRs that
modify source code without a corresponding `CHANGELOG` or `.changeset`
update.
- **Self-approval prevention** -- `NoSelfApprovalCondition` enforces
separation of duties by preventing PR authors from approving their own
code (CRITICAL severity).
- **Cross-team approval** -- `CrossTeamApprovalCondition` requires approvals
from members of specified GitHub teams before merge. Uses a simplified
`requested_teams` check (full team-membership resolution via GraphQL is
tracked for a future iteration).
- **Diff parsing utilities** -- New `src/rules/utils/diff.py` module with
`extract_added_lines`, `extract_removed_lines`, and
`match_patterns_in_patch` for reusable patch analysis.
- **CODEOWNERS parser** -- New `src/rules/utils/codeowners.py` with
`CodeOwnersParser` class supporting glob-to-regex conversion, owner
lookup, and critical-file detection. CODEOWNERS content is now fetched
dynamically from the GitHub API instead of reading from disk.
- **Webhook handlers for review events** -- `PullRequestReviewEventHandler`
and `PullRequestReviewThreadEventHandler` re-evaluate PR rules when
reviews are submitted/dismissed or threads are resolved/unresolved.
- **Review thread enrichment** -- `PullRequestEnricher` now fetches
`reviewThreads` via GraphQL and attaches them to the event context,
enabling `UnresolvedCommentsCondition` and `CommentResponseTimeCondition`.
- **Full rule evaluation wiring** -- All new conditions are registered in
`ConditionRegistry` (`AVAILABLE_CONDITIONS`, `RULE_ID_TO_CONDITION`) with
corresponding `RuleID` enum values, violation-text mappings, and
human-readable descriptions so they are routed through the fast
condition-class evaluation path and support acknowledgment workflows.

### Changed

- **GraphQL client consolidation** -- Removed the standalone
`graphql_client.py` module; all GraphQL operations now go through the
unified `GitHubAPI` class with Pydantic-typed response models.
- **CODEOWNERS fetched from API** -- `PathHasCodeOwnerCondition` and
`RequireCodeOwnerReviewersCondition` now receive CODEOWNERS content via
the event context (fetched by the enricher) rather than reading from the
local filesystem.
- **`_PatchPatternCondition` base class** -- `DiffPatternCondition` and
`SecurityPatternCondition` now share a common abstract base, reducing
~60 lines of duplicated iteration/matching logic.
- **Removed redundant `validate()` overrides** -- Conditions in
`compliance.py` and `access_control_advanced.py` that simply delegated to
`evaluate()` now rely on `BaseCondition.validate()` which does the same
thing.

### Fixed

- **Fail-closed on invalid regex** -- `TestCoverageCondition` now returns a
violation (and `validate()` returns `False`) when `test_file_pattern` is
an invalid regex, instead of silently passing.
- **Consistent file-extension filtering** -- `TestCoverageCondition.validate()`
now ignores `.txt` and `.json` files, matching the behavior of `evaluate()`.
- **`max_hours=0` edge case** -- `CommentResponseTimeCondition` now uses
`if max_hours is None` instead of `if not max_hours`, so a 0-hour SLA
(immediate response required) is correctly enforced.
- **Overly generic violation mapping key** -- Changed the
`COMMENT_RESPONSE_TIME` acknowledgment mapping from `"exceeded the"` to
`"response SLA"` to avoid false matches against unrelated violation text.

## [2026-02-27] -- PRs #54, #58

### Added

- **Disabled rule filtering** -- Rules with `enabled: false` in
`rules.yaml` are now skipped during loading.
- **CodeRabbit-style PR comments** -- Collapsible `<details>` sections for
violations, acknowledgment summaries, and check run output.
- **Watchflow footer** -- Branded footer appended to PR comments.
- **Severity grouping fix** -- `INFO` severity rules are now grouped
correctly instead of falling back to `LOW`.

### Changed

- **Default rules aligned with watchflow.dev** -- Canonical rule set updated
to match the published documentation examples.
- **`max_pr_loc` parameter alias** -- `MaxPrLocCondition` now accepts
`max_pr_loc` and `max_changed_lines` in addition to `max_lines`.
- **CODEOWNERS reviewer exclusion** -- PR author is excluded from the
required code-owner reviewers list.
- **Legacy rule ID references removed** -- Generated PR comments and error
messages no longer expose internal `RuleID` strings.

### Fixed

- **Acknowledgment text matching** -- Violation text keys updated to
exactly match the messages emitted by conditions.
- **GitHub App auth env vars** -- Standardized to `APP_CLIENT_ID_GITHUB`
and `APP_CLIENT_SECRET_GITHUB`.

## [2026-02-26] -- PRs #43 (cont.), event filtering

### Added

- **Event filtering** -- Irrelevant GitHub events (e.g. bot-only,
label-only) are now dropped before reaching the rule engine, reducing
noise and unnecessary LLM calls.

### Fixed

- **Deployment status blocking** -- Resolved an issue where deployment
status events could block without a clear reason.
- **Deployment approval gating** -- Addressed CodeRabbit feedback on
retry logic, falsy checks, and callback URL handling.

## [2026-01-31] -- PR #43

### Added

- **Core event processing infrastructure** -- `PullRequestProcessor`,
`PushEventProcessor`, `DeploymentProcessor`, and `CheckRunProcessor`
with enrichment, rule evaluation, and GitHub reporting pipeline.
- **Task queue with deduplication** -- Async `TaskQueue` for enqueuing
webhook processing with delivery-ID-based dedup.
- **Rule engine agent (LangGraph)** -- `RuleEngineAgent` with a multi-node
workflow: analyze rules, select strategy (condition class vs LLM
reasoning vs hybrid), execute, and validate.
- **Acknowledgment agent** -- `AcknowledgmentAgent` parses `@watchflow ack`
comments and maps violations to `RuleID` enum values.
- **Webhook dispatcher and handlers** -- Modular handler registry for
`pull_request`, `push`, `check_run`, `deployment`, `deployment_status`,
`deployment_protection_rule`, `deployment_review`, and `issue_comment`
events.
- **Condition-based rule evaluation** -- `BaseCondition` ABC with
`evaluate()` (returns `list[Violation]`) and `validate()` (legacy bool
interface). Initial conditions: `TitlePatternCondition`,
`MinDescriptionLengthCondition`, `RequiredLabelsCondition`,
`MinApprovalsCondition`, `RequireLinkedIssueCondition`,
`MaxFileSizeCondition`, `MaxPrLocCondition`, `FilePatternCondition`,
`PathHasCodeOwnerCondition`, `RequireCodeOwnerReviewersCondition`,
`CodeOwnersCondition`, `ProtectedBranchesCondition`,
`NoForcePushCondition`, `AuthorTeamCondition`, `AllowedHoursCondition`,
`DaysCondition`, `WeekendCondition`, `WorkflowDurationCondition`.
- **Condition registry** -- `ConditionRegistry` with parameter-pattern
matching to automatically wire YAML rule parameters to condition classes.
- **`RuleID` enum and acknowledgment system** -- Type-safe rule
identifiers, violation-text-to-rule mapping, and acknowledgment comment
parsing.
- **Webhook auth** -- HMAC-SHA256 signature verification for GitHub
webhooks.

### Changed

- **Architectural modernization** -- Migrated from monolithic processor to
modular event-processor / agent / handler architecture with Pydantic
models throughout.
- **Documentation overhaul** -- All docs aligned with the rule engine
architecture, description-based rule format, and supported validation
logic.

### Fixed

- **Dead code removal** -- Cleaned up unused webhook and PR processing code.
- **JSON parse errors** -- Webhook handler now returns proper error
responses on malformed payloads.
- **WebhookResponse status normalization** -- Consistent status field
values across all handlers.

## [2025-12-01] -- PRs #27-35

### Added

- **Repository Analysis Agent** -- `RepositoryAnalysisAgent` with LangGraph
workflow analyzing PR history, contributing guidelines, and repository
hygiene. Includes Pydantic models, LLM prompt templates, and API
endpoints for rule recommendations.
- **Diff-aware validators** -- `diff_pattern`, `related_tests`, and
`required_field_in_diff` validators with normalized diff metadata and
LLM-friendly summaries for PR files.
- **Feasibility agent validator selection** -- `FeasibilityAgent` now
dynamically chooses validators from a catalog.
- **AI Immune System metrics** -- Repository health scoring with hygiene
metrics and structured API responses.
- **PR automation** -- Automated PR creation from repository analysis
recommendations.

### Changed

- **Diff-aware rule presets** -- Default rule bundles updated to use the
new diff-aware parameters and threading guardrails.

### Fixed

- **PR creation 404 prevention** -- Proper error handling for `create_git_ref`
422 responses and repository analysis caching.
- **Repository analysis reliability** -- Improved logging, formatting, and
content checks in analysis nodes.

## [2025-10-01] -- PRs #18-21

### Added

- **Multi-provider AI abstraction** -- Provider-agnostic `get_chat_model()`
factory supporting OpenAI, AWS Bedrock, and Google Vertex AI (Model
Garden). Registry pattern for provider selection.
- **Python version compatibility checks** -- Pre-commit hook validates
syntax against target Python version.

### Changed

- **Provider-agnostic LLM usage** -- Replaced direct `ChatOpenAI`
instantiation with the `get_chat_model()` abstraction throughout.
- **Module restructuring** -- Reorganized package layout and updated
configuration.

## [2025-08-05] -- PRs #10-13

### Added

- **CODEOWNERS integration** -- Initial CODEOWNERS file parsing and
contributor analysis.
- **Agent architecture enhancements** -- Improved consistency and
reliability for `FeasibilityAgent` and `RuleEngineAgent`.
- **Structured output for FeasibilityAgent** -- LLM responses parsed into
Pydantic models.
- **Testing framework** -- Coverage reporting, CI test pipeline, and
mocking infrastructure for agents and LLM clients.
- **GitHub Pages documentation** -- MkDocs site deployed via GitHub
Actions.

### Changed

- **FastAPI lifespan** -- Replaced deprecated `on_event` handlers with
lifespan context manager.
- **Description-based rule format** -- Rules in YAML now use natural
language descriptions matched to conditions.

### Fixed

- **CI pipeline** -- Python setup, coverage reporting, Codecov auth,
MkDocs dependencies.
- **Test isolation** -- Proper mocking of agent creation, config
validation, and LLM client initialization.

## [2025-07-18] -- Initial release

### Added

- **Watchflow AI governance engine** -- First open-source release.
LangGraph-based rule evaluation for GitHub webhook events
(pull requests, pushes, deployments).
- **EKS deployment** -- Helm chart, Kubernetes manifests, and GitHub
Actions workflow for AWS EKS.
- **Pre-commit hooks** -- Ruff linting and formatting, YAML checks,
trailing whitespace, large file detection.
- **Development tooling** -- `uv` package management, development guides,
contributor guidelines.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

GitHub governance that runs where you already work. No new dashboards, no “AI-powered” fluff—just rules in YAML, evaluated on every PR and push, with check runs and comments that maintainers actually read.

Watchflow is the governance layer for your repo: it enforces the policies you define (CODEOWNERS, approvals, linked issues, PR size, title patterns, branch protection) so you don’t have to chase reviewers or guess what’s allowed. Built for teams that still care about traceability and review quality.
Watchflow is the governance layer for your repo: it enforces the policies you define (CODEOWNERS, approvals, linked issues, PR size, title patterns, branch protection, diff scanning, review thread SLAs, signed commits, and more) so you don’t have to chase reviewers or guess what’s allowed. Built for teams that still care about traceability and review quality.

---

Expand Down Expand Up @@ -46,11 +46,19 @@ Rules are **description + event_types + parameters**. The engine matches paramet
| **PR** | `critical_owners: []` / code owners | pull_request | Changes to critical paths require code-owner review. |
| **PR** | `require_path_has_code_owner: true` | pull_request | Every changed path must have an owner in CODEOWNERS. |
| **PR** | `protected_branches: ["main"]` | pull_request | Block direct targets to these branches. |
| **PR** | `diff_restricted_patterns: ["console\\.log", "TODO:"]` | pull_request | Flag restricted regex patterns in PR diff added lines. |
| **PR** | `security_patterns: ["api_key", "secret"]` | pull_request | Detect hardcoded secrets or sensitive data in diffs (critical). |
| **PR** | `block_on_unresolved_comments: true` | pull_request | Block merge when unresolved review threads exist. |
| **PR** | `require_tests: true` | pull_request | Source changes must include corresponding test file changes. |
| **PR** | `max_comment_response_time_hours: 24` | pull_request | Review threads must be addressed within SLA. |
| **PR** | `require_signed_commits: true` | pull_request | All commits must be cryptographically signed (GPG/SSH). |
| **PR** | `require_changelog_update: true` | pull_request | Source changes must include a CHANGELOG or .changeset update. |
| **PR** | `block_self_approval: true` | pull_request | PR authors cannot approve their own code. |
| **PR** | `required_team_approvals: ["backend", "security"]` | pull_request | Require approvals from specified GitHub teams. |
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Clarify team-approval behavior to avoid overstating enforcement.

The current text says approvals are required “from specified GitHub teams,” but current CrossTeamApprovalCondition logic (in src/rules/conditions/access_control_advanced.py) does not verify approver team membership per team; it relies on requested teams plus overall approval presence. Please adjust wording here (and the matching line in docs/features.md) to reflect the current implementation.

✏️ Suggested wording update
-| **PR** | `required_team_approvals: ["backend", "security"]` | pull_request | Require approvals from specified GitHub teams. |
+| **PR** | `required_team_approvals: ["backend", "security"]` | pull_request | Require specified teams to be requested and approvals to be present (full per-team membership verification is planned). |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| **PR** | `required_team_approvals: ["backend", "security"]` | pull_request | Require approvals from specified GitHub teams. |
| **PR** | `required_team_approvals: ["backend", "security"]` | pull_request | Require specified teams to be requested and approvals to be present (full per-team membership verification is planned). |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` at line 57, Update the README and docs/features.md wording to
avoid implying strict per-team enforcement: change the description for
`required_team_approvals: ["backend", "security"]` to state that the rule uses
the `CrossTeamApprovalCondition` logic which checks that approvals are present
for the requested teams collectively (i.e., approvals associated with the
requested teams are considered) but does not verify individual approvers’
membership in each specified GitHub team; reference `CrossTeamApprovalCondition`
and `required_team_approvals` in the text so readers know the behavior matches
the current implementation.

| **Push** | `no_force_push: true` | push | Reject force pushes. |
| **Files** | `max_file_size_mb: 1` | pull_request | No single file > N MB. |
| **Files** | `pattern` + `condition_type: "files_match_pattern"` | pull_request | Changed files must (or must not) match glob/regex. |
| **Time** | `allowed_hours`, `days`, weekend | deployment / workflow | Restrict when actions can run. |
| **Deploy** | `environment`, approvals | deployment | Deployment protection. |

Rules are read from the **default branch** (e.g. `main`). Each webhook delivery is deduplicated by `X-GitHub-Delivery` so handler and processor both run; comments and check runs stay in sync.

Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ graph TD
### Condition registry

- Maps parameter names to condition classes (e.g. `require_linked_issue` → `RequireLinkedIssueCondition`, `max_lines` → `MaxPrLocCondition`, `require_code_owner_reviewers` → `RequireCodeOwnerReviewersCondition`).
- Supported conditions: linked issue, title pattern, description length, labels, approvals, PR size (lines), CODEOWNERS (path has owner, require owners as reviewers), protected branches, no force push, file size, file pattern, time/deploy rules. See [Configuration](../getting-started/configuration.md).
- Supported conditions: linked issue, title pattern, description length, labels, approvals, PR size (lines), CODEOWNERS (path has owner, require owners as reviewers), protected branches, no force push, file size, file pattern, diff pattern scanning, security pattern detection, unresolved comments, test coverage, comment response SLA, signed commits, changelog required, self-approval prevention, cross-team approval, time/deploy rules. See [Configuration](../getting-started/configuration.md).

### PR enricher

Expand Down
Loading