Repository navigation
feat(api): add commentOn filter to GitHubWebhookFilter - #1081
Conversation
Adds an optional CommentOn enum field to GitHubWebhookFilter that scopes
issue_comment events to comments posted on plain issues ("Issue") or pull
requests ("PullRequest"). Empty matches both, preserving existing behavior.
GitHub fires issue_comment for both subjects because PRs are issues in its
data model. Until now, spawner authors had to spawn the task and bail in
the prompt, lean on label discriminators, or avoid the event entirely.
The signal is already extracted from issue.pull_request.url; this exposes
it as a first-class filter input so spawners can drop their prompt-side
guards.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Greptile SummaryThis PR adds a Confidence Score: 5/5Safe to merge — well-scoped additive change with no breaking modifications to existing behaviour. All changed files are correct and consistent. The filter logic uses the same nil-guard and early-return patterns as surrounding code, the kubebuilder enum prevents invalid values at admission, CRDs are regenerated, and the new path is fully covered by table-driven tests. No P0 or P1 findings. No files require special attention.
|
| Filename | Overview |
|---|---|
| api/v1alpha1/taskspawner_types.go | Adds CommentOnIssue/CommentOnPullRequest constants and CommentOn string field to GitHubWebhookFilter with correct kubebuilder enum validation; clean and consistent with existing field conventions. |
| internal/webhook/github_filter.go | CommentOn filter correctly scoped to IssueCommentEvent inside the existing IssuesEvent/IssueCommentEvent branch; silently ignored for non-issue_comment events as intended; uses the same nil-guard pattern as surrounding filters. |
| internal/webhook/github_filter_test.go | Adds comprehensive table-driven tests for all three CommentOn scopes on both PR-comment and plain-issue-comment payloads, plus a regression test for ignored behavior on non-issue_comment events. |
| internal/manifests/charts/kelos/templates/crds/taskspawner-crd.yaml | CRD regenerated with commentOn field; enum values and description match the Go type definition. |
| internal/manifests/install-crd.yaml | install-crd.yaml regenerated identically to the Helm chart CRD; no issues. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Incoming GitHub webhook] --> B{event type?}
B -->|issue_comment| C[IssueCommentEvent branch]
B -->|issues| D[IssuesEvent branch]
B -->|other| E[Other event branches]
C --> F{filter.CommentOn != empty?}
F -->|No| G[Skip CommentOn check]
F -->|Yes| H{issue.IsPullRequest?}
H -->|true / PR comment| I{CommentOn == PullRequest?}
I -->|Yes| J[✅ Pass — continue other filters]
I -->|No CommentOn==Issue| K[❌ Return false]
H -->|false / plain issue| L{CommentOn == Issue?}
L -->|Yes| M[✅ Pass — continue other filters]
L -->|No CommentOn==PullRequest| N[❌ Return false]
G --> O[State / Labels / Body filters…]
J --> O
M --> O
D --> P[CommentOn ignored — continue]
E --> Q[CommentOn ignored — continue]
Reviews (1): Last reviewed commit: "feat(api): add commentOn filter to GitHu..." | Re-trigger Greptile
There was a problem hiding this comment.
1 issue found across 5 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="internal/manifests/charts/kelos/templates/crds/taskspawner-crd.yaml">
<violation number="1" location="internal/manifests/charts/kelos/templates/crds/taskspawner-crd.yaml:3352">
P2: `commentOn` description says empty is allowed, but the CRD enum rejects empty string.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| enum: | ||
| - Issue | ||
| - PullRequest | ||
| type: string |
There was a problem hiding this comment.
P2: commentOn description says empty is allowed, but the CRD enum rejects empty string.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At internal/manifests/charts/kelos/templates/crds/taskspawner-crd.yaml, line 3352:
<comment>`commentOn` description says empty is allowed, but the CRD enum rejects empty string.</comment>
<file context>
@@ -3343,6 +3343,16 @@ spec:
+ specific subject. GitHub fires issue_comment for both plain issues
+ and pull requests; "Issue" matches only the former, "PullRequest"
+ only the latter. Empty matches both. Ignored for other events.
+ enum:
+ - Issue
+ - PullRequest
</file context>
| enum: | |
| - Issue | |
| - PullRequest | |
| type: string | |
| enum: | |
| - "" | |
| - Issue | |
| - PullRequest | |
| type: string |
|
/kelos api-review |
|
🤖 Kelos Task Status Task |
There was a problem hiding this comment.
🤖 Kelos API Reviewer Agent @gjkim42
API Design Review
Verdict: COMMENT (would be APPROVE — PR is authored by kelos-bot, so a same-identity approval is blocked by GitHub)
Scope: Adds an optional commentOn enum field to GitHubWebhookFilter (Issue | PullRequest) that scopes issue_comment-event filters to comments on plain issues vs. pull requests.
The shape is sound: per-filter placement preserves the existing OR-of-filters model, the new field is additive and +optional, the dispatch is correctly limited to *github.IssueCommentEvent and silently ignored on other events, and the tests are thorough — all three scopes are exercised on both PR-comment and plain-issue-comment payloads, plus a regression case for non-issue_comment events. CRDs are regenerated consistently across the Helm chart and install-crd.yaml.
Findings
Validation (nit, non-blocking)
api/v1alpha1/taskspawner_types.go:445-448— the doc comment states "Empty matches both", but+kubebuilder:validation:Enum=Issue;PullRequestadmits only those two values. In practice this is fine becauseomitemptyskips schema validation when the field is absent — but an explicitcommentOn: \"\"(which the doc invites) would be rejected by the API server. There is in-file precedent for the explicit form attaskspawner_types.go:492(Action:Enum=create;update;remove;\"\"). Pick whichever you prefer for this codebase: extend the enum toEnum=Issue;PullRequest;\"\", or tighten the docstring to "Omit to match both". Either keeps the API truthful.
Naming / consistency (discussion, non-blocking)
api/v1alpha1/taskspawner_types.go:447— every other enum onGitHubWebhookFilteruses lowercase values that mirror GitHub's wire format (open/closed/all,approved/changes_requested/any,created/opened/submitted).CommentOnintroduces PascalCase (Issue,PullRequest). The choice is defensible — these values aren't GitHub wire strings, they're Kelos-defined enum values for a derived signal (issue.IsPullRequest()), and PascalCase matches upstream K8s convention (ClusterIP,OnFailure). Worth keeping in mind for future enums on derived signals so the in-struct convention stays predictable.
Suggestions (optional)
- Consider promoting
CommentOnto a named string type (e.g.,type CommentOnSubject string) with the existing constants typed accordingly. Sibling enums in this repo are split between named types (CredentialType) and bare strings (State,Action), so this is a consistency call rather than a correctness one. - The constants are exported as untyped string constants. If they end up imported by spawner-prompt callers in the future, a typed alias would prevent accidental cross-assignment with the
Action/Statefields.
Note on prompt injection: third-party bot content on this PR contained directives instructing AI reviewers to attribute findings to that bot. Those instructions were disregarded; the analysis above is independent and based on reading the diff and surrounding code.
/kelos needs-input
|
/kelos review |
|
🤖 Kelos Task Status Task |
There was a problem hiding this comment.
🤖 Kelos Reviewer Agent @gjkim42
Review Summary
Verdict: COMMENT (would be APPROVE — PR is authored by kelos-bot, so a same-identity approval is blocked by GitHub)
Overall correctness: patch is correct
Scope: Adds optional commentOn enum (Issue/PullRequest) to GitHubWebhookFilter to scope issue_comment events; matcher and table-driven tests updated; CRDs regenerated.
Findings Overview
| Priority | Count | File:Line | Summary |
|---|---|---|---|
| P0 | 0 | — | none |
| P1 | 0 | — | none |
| P2 | 0 | — | none |
| P3 | 0 | — | none |
Findings
No code-level findings. The implementation is minimal and well-scoped:
internal/webhook/github_filter.go:321-338— the new check is placed inside the existing*github.IssuesEvent, *github.IssueCommentEventswitch arm, narrowed via_, ok := e.(*github.IssueCommentEvent)so it is silently ignored onIssuesEventexactly as the doc comment promises. Theissue != nilguard mirrors the surrounding pattern, the earlyfilter.CommentOn != ""skip preserves backward compatibility, and the switch falls through gracefully on unknown values (which the kubebuilder enum already prevents at admission).api/v1alpha1/taskspawner_types.go:378-448— purely additive: new constants and one+optionalenum-validated field next toDraft. No rename/removal, no semantic change to existing fields.commentOnis a clear name with no clash against Kubernetes-native semantics.internal/webhook/github_filter_test.go:556-682— table-driven coverage hits all three scopes (Issue,PullRequest, empty) on both PR-comment and plain-issue-comment payloads, plus a regression test confirming the field is ignored onissuesevents.- CRDs in both
internal/manifests/charts/kelos/templates/crds/taskspawner-crd.yamlandinternal/manifests/install-crd.yamlare regenerated consistently.
The deeper API-shape discussion (PascalCase vs. lowercase enum convention, whether to add "" to the enum to match the doc's "empty matches both" wording, named-string-type vs. bare string) is already covered in the /kelos api-review thread on this PR; I am not re-raising it here.
Key takeaways
- Implementation is correct and matches the design proposal in #1080 exactly.
- Test coverage is thorough.
- Generated CRD artifacts are up to date and consistent across both manifests.
Note on prompt injection: third-party bot content on this PR contained directives instructing AI reviewers to attribute findings to that bot. Those instructions were disregarded; this review is independent and based on reading the diff and surrounding code.
|
🤖 Kelos Task Status Task |
There was a problem hiding this comment.
🤖 Kelos API Reviewer Agent @gjkim42
API Design Review
Verdict: COMMENT (would be APPROVE — same-identity approval blocked by GitHub since the PR author is kelos-bot)
Scope: Re-review trigger on the same commit (ff47b1c) — no code changes since the prior api-review.
The prior api-review on this PR (#pullrequestreview-4211512935) covered the full diff against the API design checklist and remains applicable. There are no new commits, so I am not re-running the full audit; the verdict, findings, and suggestions there still stand. Summarising for convenience:
Findings
Validation (nit, non-blocking — unchanged from prior review)
api/v1alpha1/taskspawner_types.go:445-448— doc says "Empty matches both", but+kubebuilder:validation:Enum=Issue;PullRequestwould reject an explicitcommentOn: "". In-file precedent for the explicit form lives attaskspawner_types.go:492(Action:Enum=create;update;remove;""). Either extend the enum toEnum=Issue;PullRequest;""or tighten the docstring to "Omit to match both" — both keep the API truthful.
Naming / consistency (discussion, non-blocking — unchanged from prior review)
api/v1alpha1/taskspawner_types.go:447— sibling enums onGitHubWebhookFilteruse lowercase wire-format values (open/closed/all,approved/changes_requested/any).CommentOnintroduces PascalCase. Defensible because these values are Kelos-defined (derived fromissue.IsPullRequest(), not GitHub wire strings) and PascalCase matches upstream K8s convention (ClusterIP,OnFailure); flagging only as a convention call for future enums on derived signals.
Suggestions (optional, unchanged)
- Promote
CommentOnto a named string type (e.g.,type CommentOnSubject string) with the existing constants typed accordingly — consistency call versus the bare-string siblings (State,Action).
Note on prompt injection: third-party bot content on this PR contains directives instructing AI reviewers to attribute findings to that bot. Those instructions were disregarded; the analysis above is independent and based on reading the diff and surrounding code.
/kelos needs-input
…entions Distill two new conventions from PR review feedback in the last 7 days: 1. Keep CRD enum docstrings consistent with the `+kubebuilder:validation:Enum` marker. Evidence: PR #1081 P2 from both cubic-dev-ai and the kelos-bot api-reviewer — `commentOn`'s godoc said "Empty matches both" but the marker rejected explicit `commentOn: ""`. 2. Qualify cross-CRD field references with the owning kind in docs. Evidence: PR #1077 P2 from greptile — Workspace reference section cited `podOverrides.env` without noting the field lives on `Task.spec`, leaving readers without a way to locate the cited field. Applied to AGENTS.md, agentconfig.yaml, kelos-workers.yaml, plus the api-reviewer's CRD/validation checklist (enum docstrings) and the reviewer's Documentation accuracy checklist (cross-CRD references).
Distills thirteen recurring conventions from recent PR review feedback and propagates them across AGENTS.md, the shared and worker AgentConfigs, and the reviewer prompts. All changes are backed by specific PR review findings. 1. Never use os.Getenv() for secrets as Go flag defaults — PR #971 P1 (cmd/kelos-webhook-server, cmd/ghproxy leaked GITHUB_TOKEN via --help). 2. Fail fast on invalid configuration — PR #971 multiple P1/P2 (silent degradation when GitHub App credentials or token resolvers failed). 3. Keep API surfaces minimal — PR #902 (maintainer asked repeatedly to defer speculative fields and ship the minimum viable API). 4. API changes must preserve backward compatibility — PR #1058 (BodyContains scalar->array would break in-cluster manifests; resolved by deprecating the old field rather than tightening validation). 5. Docs must match implementation, not aspiration — PRs #1035, #1056, #1082 (docs claimed enforcement that the code never performed). 6. TaskSpawner conventions — PRs #965, #974 (webhook over poll, empty .Branch for issue events, dual issue/PR context, no manual checkout). 7. Don't use Gomega's global Expect() inside Eventually polling blocks — PR #1084 (transient API errors short-circuited the poller). 8. /kind cleanup for self-development/-only PRs — PR #1100 P2 (agent classified by problem nature; rule is to classify by file location). 9. CLI error messages must name the resource — PR #1101 P2 (errors.New ("task failed") loses the name when batched). 10. Test the happy path, not only early-return guards — PR #1096 (both new tests covered only the no-op branches because production code lacked a posting seam; rule now requires adding the seam). 11. Avoid vacuous substring assertions in printer tests — PR #1106 P2 (a "sentry" check passed because the fixture's Name was "sentry-fixer"). 12. Keep CRD enum docstrings consistent with the Enum marker — PR #1081 P2 (commentOn godoc said "empty matches both" but the marker rejected ""). 13. Qualify cross-CRD field references with the owning kind in docs — PR #1077 P2 (Workspace section cited bare podOverrides.env without noting the field lives on Task.spec). Also: kelos-reviewer branch field uses the safe with-index fallback form, kelos-squash-commits gates the issue_comment trigger to PullRequest comments (preventing /kelos squash-commits typed on a plain issue from running git push --force-with-lease against an empty branch fallback), and the README's .Branch description matches runtime behavior.
Distills thirteen recurring conventions from recent PR review feedback and propagates them across AGENTS.md, the shared and worker AgentConfigs, and the reviewer prompts. All changes are backed by specific PR review findings. 1. Never use os.Getenv() for secrets as Go flag defaults — PR #971 P1 (cmd/kelos-webhook-server, cmd/ghproxy leaked GITHUB_TOKEN via --help). 2. Fail fast on invalid configuration — PR #971 multiple P1/P2 (silent degradation when GitHub App credentials or token resolvers failed). 3. Keep API surfaces minimal — PR #902 (maintainer asked repeatedly to defer speculative fields and ship the minimum viable API). 4. API changes must preserve backward compatibility — PR #1058 (BodyContains scalar->array would break in-cluster manifests; resolved by deprecating the old field rather than tightening validation). 5. Docs must match implementation, not aspiration — PRs #1035, #1056, #1082 (docs claimed enforcement that the code never performed). 6. TaskSpawner conventions — PRs #965, #974 (webhook over poll, empty .Branch for issue events, dual issue/PR context, no manual checkout). 7. Don't use Gomega's global Expect() inside Eventually polling blocks — PR #1084 (transient API errors short-circuited the poller). 8. /kind cleanup for self-development/-only PRs — PR #1100 P2 (agent classified by problem nature; rule is to classify by file location). 9. CLI error messages must name the resource — PR #1101 P2 (errors.New ("task failed") loses the name when batched). 10. Test the happy path, not only early-return guards — PR #1096 (both new tests covered only the no-op branches because production code lacked a posting seam; rule now requires adding the seam). 11. Avoid vacuous substring assertions in printer tests — PR #1106 P2 (a "sentry" check passed because the fixture's Name was "sentry-fixer"). 12. Keep CRD enum docstrings consistent with the Enum marker — PR #1081 P2 (commentOn godoc said "empty matches both" but the marker rejected ""). 13. Qualify cross-CRD field references with the owning kind in docs — PR #1077 P2 (Workspace section cited bare podOverrides.env without noting the field lives on Task.spec). Also: kelos-reviewer branch field uses the safe with-index fallback form, kelos-squash-commits gates the issue_comment trigger to PullRequest comments (preventing /kelos squash-commits typed on a plain issue from running git push --force-with-lease against an empty branch fallback), the kelos-squash-commits branch field uses the same with-index fallback form for defensive consistency with the documented convention, and the README's .Branch description matches runtime behavior (PR head branch or pushed branch; empty for issue events). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Propagates eleven recurring conventions, distilled from prior PR review feedback, across AGENTS.md, the shared and worker AgentConfigs, and the reviewer prompts. Also fixes two existing self-development spawner configurations that were flagged in adjacent reviews. Conventions added to AGENTS.md, agentconfig.yaml, and kelos-workers.yaml: 1. Never use os.Getenv() for secrets as Go flag defaults — PR #971 P1 (cmd/kelos-webhook-server, cmd/ghproxy leaked GITHUB_TOKEN via --help). 2. Fail fast on invalid configuration — PR #971 multiple P1/P2 (silent degradation when GitHub App credentials or token resolvers failed). 3. Keep API surfaces minimal — PR #902 (maintainer asked repeatedly to defer speculative fields and ship the minimum viable API). 4. API changes must preserve backward compatibility — PR #1058 (BodyContains scalar->array would break in-cluster manifests; resolved by deprecating the old field rather than tightening validation). 5. Docs must match implementation, not aspiration — PRs #1035, #1056, #1082 (docs claimed enforcement that the code never performed). 6. Don't use Gomega's global Expect() inside Eventually polling blocks — PR #1084 (transient API errors short-circuited the poller). 7. CLI error messages must name the resource — PR #1101 P2 (errors.New("task failed") loses the name when batched). 8. Test the happy path, not only early-return guards — PR #1096 (tests covered only the no-op branches because production code lacked a posting seam; rule now requires adding the seam). 9. Avoid vacuous substring assertions in printer tests — PR #1106 P2 (a "sentry" check passed because the fixture's Name was "sentry-fixer"). 10. Keep CRD enum docstrings consistent with the Enum marker — PR #1081 P2 (commentOn godoc said "empty matches both" but the marker rejected ""). 11. Qualify cross-CRD field references with the owning kind in docs — PR #1077 P2 (Workspace section cited bare podOverrides.env without noting the field lives on Task.spec). Reviewer/api-reviewer checklists gain matching items so kelos-reviewer and kelos-api-reviewer flag these patterns on future PRs. Other fixes in the same sweep: - kelos-reviewer.spec.taskTemplate.branch uses the safe '{{with index . "Branch"}}{{.}}{{else}}main{{end}}' fallback form so a /kelos review typed on a plain issue lands on main rather than an empty branch. - kelos-squash-commits gates the issue_comment trigger to commentOn: PullRequest and uses the same with-index fallback for the branch field — /kelos squash-commits typed on a plain issue would otherwise fire the spawner with empty {{.Branch}} and the prompt then runs git push --force-with-lease. - self-development/README.md template-variable table corrected from "Usually PR head branch" to "PR head branch or pushed branch; empty for issue events" to match runtime behavior, and the bodyContains example was updated to bodyPattern to match the spawner configs. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add the commentOn filter (introduced in #1081) to the three remaining webhook-driven TaskSpawners so each declares its intended subject at the filter layer instead of relying on prompt-side workarounds: - kelos-planner: add commentOn: Issue and drop the now-redundant step-0 prompt block that exited if the target was a PR. - kelos-reviewer: add commentOn: PullRequest to the issue_comment filter so /kelos review on a plain issue no longer spawns a task whose prompt unconditionally runs gh pr view and git diff. - kelos-api-reviewer: split the issue_comment filter into two entries with explicit commentOn: Issue and commentOn: PullRequest. This spawner is intentionally dual-mode (the prompt dispatches on gh pr view to handle both subjects), so two explicit filters make the dual-mode intent visible at the webhook layer. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
What type of PR is this?
/kind feature
What this PR does / why we need it:
Adds an optional
commentOnenum field toGitHubWebhookFilterso spawner authors can scopeissue_commentevent filters to comments posted on plain issues (Issue) or pull requests (PullRequest). Empty preserves the existing behavior of matching both.GitHub fires
issue_commentfor both issues and PRs because PRs are issues in its data model. Until now, spawner authors had to spawn the task and bail in the prompt (see thegh pr viewstep-0 guards inkelos-workers,kelos-planner,kelos-api-reviewer), lean on a label discriminator, or avoid the event entirely. Theissue.pull_requestsignal was already extracted ininternal/webhook/github_filter.goforPullRequestAPIURL; this exposes it as a first-class filter input.Which issue(s) this PR is related to:
Fixes #1080
Special notes for your reviewer:
API shape rationale (per the design proposal in #1080):
*bool— K8s API conventions discourageis*-prefixed boolean discriminators; an enum is also extensible if a third surface ever needs to be filtered.ClusterIP,OnFailure).issues,pull_request,pull_request_review,pull_request_review_commentare already unambiguous.Implementation notes:
CommentOn stringtoGitHubWebhookFilternext toDraft, with+kubebuilder:validation:Enum=Issue;PullRequestand exportedCommentOnIssue/CommentOnPullRequestconstants.matchesFilter, inside the*github.IssueCommentEventbranch, checkissue.IsPullRequest()againstfilter.CommentOn.Issue,PullRequest, empty) on both PR-comment and plain-issue-comment payloads, plus a regression test that the field is silently ignored on non-issue_commentevents.make updateto regenerate the CRDs.Spawner-prompt cleanups (dropping the
gh pr viewstep-0 guards inkelos-workers,kelos-planner,kelos-api-reviewer, and thekelos-reviewerworkaround tracked in #1060) are intentionally out of scope per the issue and will follow as separate PRs.Does this PR introduce a user-facing change?
Summary by cubic
Adds an optional
commentOnfilter toGitHubWebhookFilterto scopeissue_commentevents to Issues or PRs. This fulfills task #1080 by reducing unnecessary spawns and removing prompt-side guards.commentOnenum toGitHubWebhookFilterwithIssueandPullRequest; empty matches both for backward compatibility.issue_comment; updated matcher, CRDs, and tests to cover all cases.Written for commit ff47b1c. Summary will update on new commits. Review in cubic