-
Notifications
You must be signed in to change notification settings - Fork 26
feat: issue 24 diff and codeowners #59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 13 commits
0e08dfc
9656ffd
f2c19a4
84d4566
5a699ca
61d5721
042db61
cba1dfd
5c5da29
7240244
985a325
3c93e41
797e531
981a2f2
6d93e65
1991986
92140b4
b74bd5a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| # Enterprise & Regulated Industry Guardrails | ||
|
|
||
| To level up Watchflow for large engineering teams and highly regulated industries (FinTech, HealthTech, Enterprise SaaS), we should expand our rule engine to support strict compliance, auditability, and advanced access control. | ||
|
|
||
| ## 1. Compliance & Security Verification Rules | ||
|
|
||
| ### `SignedCommitsCondition` | ||
| **Purpose:** Ensure all commits in a PR are signed (GPG/SSH/S/MIME). | ||
| **Why:** Required by SOC2, FedRAMP, and most enterprise security teams to prevent impersonation. | ||
| **Parameters:** `require_signed_commits: true` | ||
|
|
||
| ### `SecretScanningCondition` (Enhanced) | ||
| **Purpose:** Integrate with GitHub Advanced Security or detect specific sensitive file extensions. | ||
| **Why:** Catching hardcoded secrets before they merge is a massive pain point. We built regex parsing, but we can add native hooks to check if GitHub's native secret scanner triggered alerts on the branch. | ||
| **Parameters:** `block_on_secret_alerts: true` | ||
|
|
||
| ### `BannedDependenciesCondition` | ||
| **Purpose:** Parse `package.json`, `requirements.txt`, or `go.mod` diffs to block banned licenses (e.g., AGPL) or deprecated libraries. | ||
| **Why:** Open-source license compliance and CVE prevention. | ||
| **Parameters:** `banned_licenses: ["AGPL", "GPL"]`, `banned_packages: ["requests<2.0.0"]` | ||
|
|
||
| ## 2. Advanced Access Control (Separation of Duties) | ||
|
|
||
| ### `CrossTeamApprovalCondition` | ||
| **Purpose:** Require approvals from at least two different GitHub Teams. | ||
| **Why:** Regulated environments require "Separation of Duties" (e.g., a dev from `backend-team` and a dev from `qa-team` must both approve). | ||
| **Parameters:** `required_team_approvals: ["@org/backend", "@org/qa"]` | ||
|
|
||
| ### `NoSelfApprovalCondition` | ||
| **Purpose:** Explicitly block PR authors from approving their own PRs (or using a secondary admin account to do so). | ||
| **Why:** Strict SOX/SOC2 requirement. | ||
| **Parameters:** `block_self_approval: true` | ||
|
|
||
| ## 3. Operations & Reliability | ||
|
|
||
| ### `MigrationSafetyCondition` | ||
| **Purpose:** If a PR modifies database schemas/migrations (e.g., `alembic/`, `prisma/migrations/`), enforce that it does *not* contain destructive operations like `DROP TABLE` or `DROP COLUMN`. | ||
| **Why:** Prevents junior devs from accidentally wiping production data. | ||
| **Parameters:** `safe_migrations_only: true` | ||
|
|
||
| ### `FeatureFlagRequiredCondition` | ||
| **Purpose:** If a PR exceeds a certain size or modifies core routing, ensure a feature flag is added. | ||
| **Why:** Enables safe rollbacks and trunk-based development. | ||
| **Parameters:** `require_feature_flags_for_large_prs: true` | ||
|
|
||
| ## 4. Documentation & Traceability | ||
|
|
||
| ### `JiraTicketStatusCondition` | ||
| **Purpose:** Instead of just checking if a Jira ticket *exists* in the title, make an API call to Jira to ensure the ticket is in the "In Progress" or "In Review" state. | ||
| **Why:** Prevents devs from linking to closed, backlog, or fake tickets just to bypass the basic `RequireLinkedIssue` rule. | ||
| **Parameters:** `require_active_jira_ticket: true` | ||
|
|
||
| ### `ChangelogRequiredCondition` | ||
| **Purpose:** If `src/` files change, require an addition to `CHANGELOG.md` or a `.changeset/` file. | ||
| **Why:** Maintains release notes for compliance audits automatically. | ||
| **Parameters:** `require_changelog_update: true` | ||
|
|
||
| ## 5. Potential GitHub Ecosystem Integrations | ||
|
|
||
| To make Watchflow a true "single pane of glass" for governance, we can build custom condition handlers that hook directly into GitHub's native ecosystem. | ||
|
|
||
| ### `CodeQLAnalysisCondition` | ||
| **Purpose:** Block merges if CodeQL (or other static analysis tools) has detected critical vulnerabilities in the PR diff. | ||
| **How to build:** Call the GitHub `code-scanning/alerts` API for the current `head_sha`. | ||
| **Why:** Instead of developers having to check multiple tabs, Watchflow summarizes the CodeQL alerts and makes them enforceable via YAML. | ||
| **Parameters:** `block_on_critical_codeql: true` | ||
|
|
||
| ### `DependabotAlertsCondition` | ||
| **Purpose:** Ensure developers do not merge PRs that introduce new dependencies with known CVEs. | ||
| **How to build:** Hook into the `dependabot/alerts` REST API for the repository, filtering by the PR's branch. | ||
| **Why:** Shifting security left. | ||
| **Parameters:** `max_dependabot_severity: "high"` | ||
|
|
||
| ## 6. Open-Source Ecosystem Integrations | ||
|
|
||
| We can leverage popular open-source Python SDKs directly within our rule engine to parse specific file types during the event evaluation. | ||
|
|
||
| ### Open Policy Agent (OPA) / Rego Validation | ||
| **Purpose:** If a PR modifies `.rego` files or Kubernetes manifests, validate them against the OPA engine. | ||
| **How to build:** Embed the `opa` CLI or use the `PyOPA` library to evaluate the diff. | ||
| **Why:** Infrastructure-as-Code (IaC) teams need a way to ensure PRs don't introduce misconfigurations. | ||
|
|
||
| ### Pydantic Schema Breakage Detection | ||
| **Purpose:** Detect backward-incompatible changes to REST API models. | ||
| **How to build:** If `models.py` changes, parse the old and new AST (Abstract Syntax Tree) to see if a required field was deleted or changed types. | ||
| **Why:** Breaking API contracts is a massive incident vector in enterprise microservices. | ||
|
|
||
| ### Ruff / Black / ESLint Override Detection | ||
| **Purpose:** Flag PRs that introduce new `# noqa`, `# type: ignore`, or `// eslint-disable` comments. | ||
| **How to build:** Use our existing diff/patch parser to explicitly hunt for suppression comments in the added lines. | ||
| **Why:** Keeps technical debt from quietly slipping into the codebase. | ||
| **Parameters:** `allow_linter_suppressions: false` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -498,6 +498,62 @@ async def get_pull_request_reviews(self, repo: str, pr_number: int, installation | |
| logger.error(f"Error getting reviews for PR #{pr_number} in {repo}: {e}") | ||
| return [] | ||
|
|
||
| async def get_pull_request_review_threads( | ||
| self, repo: str, pr_number: int, installation_id: int | ||
| ) -> list[dict[str, Any]]: | ||
| """Get review threads for a pull request using the GraphQL API.""" | ||
| try: | ||
| token = await self.get_installation_access_token(installation_id) | ||
| if not token: | ||
| logger.error(f"Failed to get installation token for {installation_id}") | ||
| return [] | ||
|
|
||
| from src.integrations.github.graphql import GitHubGraphQLClient | ||
|
|
||
| client = GitHubGraphQLClient(token) | ||
|
|
||
| owner, repo_name = repo.split("/", 1) | ||
| query = """ | ||
| query PRReviewThreads($owner: String!, $repo: String!, $pr_number: Int!) { | ||
| repository(owner: $owner, name: $repo) { | ||
| pullRequest(number: $pr_number) { | ||
| reviewThreads(first: 50) { | ||
| nodes { | ||
| isResolved | ||
| isOutdated | ||
| comments(first: 10) { | ||
| nodes { | ||
| body | ||
| createdAt | ||
| author { | ||
| login | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| """ | ||
|
Comment on lines
+534
to
+556
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hardcoded pagination limits may truncate data on large PRs. The GraphQL query uses This could cause Consider either:
🔧 Quick fix to increase limits query = """
query PRReviewThreads($owner: String!, $repo: String!, $pr_number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr_number) {
- reviewThreads(first: 50) {
+ reviewThreads(first: 100) {
nodes {
isResolved
isOutdated
- comments(first: 10) {
+ comments(first: 50) {
nodes {
body
createdAt🤖 Prompt for AI Agents |
||
| variables = {"owner": owner, "repo": repo_name, "pr_number": pr_number} | ||
| response_model = await client.execute_query_typed(query, variables) | ||
|
|
||
| if response_model.errors: | ||
| logger.error("GraphQL query failed", errors=response_model.errors) | ||
| return [] | ||
|
|
||
| repo_node = response_model.data.repository | ||
| if not repo_node or not repo_node.pull_request or not repo_node.pull_request.review_threads: | ||
| return [] | ||
|
|
||
| threads = [thread.model_dump() for thread in repo_node.pull_request.review_threads.nodes] | ||
| logger.info(f"Retrieved {len(threads)} review threads for PR #{pr_number} in {repo}") | ||
| return threads | ||
| except Exception as e: | ||
| logger.error(f"Error getting review threads for PR #{pr_number} in {repo}: {e}") | ||
| return [] | ||
|
|
||
| async def get_pull_request_files(self, repo: str, pr_number: int, installation_id: int) -> list[dict[str, Any]]: | ||
| """Get files changed in a pull request.""" | ||
| try: | ||
|
|
@@ -1314,7 +1370,7 @@ async def fetch_pr_hygiene_stats( | |
| # Check if it's a rate limit error - check both message and status code | ||
| is_rate_limit = "rate limit" in error_str or "403" in error_str | ||
| # Also check if it's an aiohttp ClientResponseError with status 403 | ||
| if hasattr(e, "status") and e.status == 403: | ||
| if getattr(e, "status", None) == 403: | ||
| is_rate_limit = True | ||
| has_auth = user_token is not None or installation_id is not None | ||
|
|
||
|
|
||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add runnable rule examples and migration cross-links.
This roadmap is useful, but for user-facing rule additions it should include at least a few executable YAML examples and links to the canonical README/docs sections describing migration/usage.
As per coding guidelines, "docs/**: Update
READMEanddocsfor user-visible changes and migrations" and "Provide runnable examples for new/changed rules; keep cross-links current".🤖 Prompt for AI Agents