Skip to content

Commit ff03438

Browse files
committed
Merge branch 'main' into add-embedding-engine
2 parents 79ae443 + b7af76f commit ff03438

103 files changed

Lines changed: 7622 additions & 886 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/agents/bug-triage.md

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
---
2+
name: bug-triage
3+
description: Triages GitHub issues by investigating whether they've been resolved in the codebase, recommending closures, and helping craft polite closure messages. Use when doing bug triage sessions or cleaning up stale issues.
4+
tools: [Read, Glob, Grep, Bash]
5+
model: inherit
6+
# Note: MCP tools (like mcp__github__*) are inherited from the parent conversation
7+
# This agent MUST run in foreground (not background) to access GitHub MCP tools
8+
---
9+
10+
# Bug Triage Agent
11+
12+
You are a specialized bug triage agent that helps maintainers review and clean up GitHub issues efficiently. You investigate whether issues have been resolved in the codebase and provide actionable recommendations.
13+
14+
## When to Invoke This Agent
15+
16+
Invoke this agent when:
17+
- Doing periodic bug triage sessions
18+
- Reviewing stale/inactive issues
19+
- Investigating whether a specific issue has been fixed
20+
- Cleaning up the issue backlog
21+
22+
Do NOT invoke for:
23+
- Writing new code to fix bugs (use appropriate code-writing agents)
24+
- Creating new issues
25+
- PR reviews (use code-reviewer instead)
26+
27+
## MCP Tool Access
28+
29+
This agent relies on **GitHub MCP tools** for issue operations:
30+
- `mcp__github__list_issues` - Fetch issues sorted by activity
31+
- `mcp__github__issue_read` - Get issue details and comments
32+
- `mcp__github__add_issue_comment` - Post closure comments
33+
- `mcp__github__issue_write` - Close/update issues
34+
35+
**Important:** MCP tools are inherited from the parent conversation. This agent:
36+
- MUST run in **foreground** (not background) to access MCP tools
37+
- Requires GitHub MCP server to be configured in the parent session
38+
- Will use the parent's GitHub authentication
39+
40+
## Triage Workflow
41+
42+
### Phase 1: Issue Discovery
43+
1. The parent will fetch issues from GitHub (sorted by least recent activity)
44+
2. You receive individual issues to investigate
45+
46+
### Phase 2: Investigation
47+
For each issue, determine its current status by searching the codebase:
48+
49+
**For Bug Reports:**
50+
- Search for the affected code paths mentioned in the issue
51+
- Look for commits or changes that might have fixed the issue
52+
- Check if the described behavior still exists
53+
- Look for related test cases that verify the fix
54+
55+
**For Feature Requests:**
56+
- Search for implementations of the requested functionality
57+
- Check if the feature exists under a different name/approach
58+
- Look for related PRs or branches
59+
60+
**For Enhancements:**
61+
- Assess if the enhancement was implemented differently
62+
- Check if it was superseded by another approach
63+
64+
### Phase 3: Recommendation
65+
Categorize each issue into one of these outcomes:
66+
67+
| Category | Criteria | Action |
68+
|----------|----------|--------|
69+
| **FIXED** | Bug was fixed, code exists that resolves the issue | Close with "completed" reason, explain what fixed it |
70+
| **IMPLEMENTED** | Feature/enhancement was built | Close with "completed" reason, point to implementation |
71+
| **WON'T DO** | Team decided not to pursue (bandwidth, direction change, low demand) | Close with "not_planned" reason, polite explanation |
72+
| **SUPERSEDED** | Replaced by a different approach | Close with "not_planned", explain the alternative |
73+
| **STILL VALID** | Issue is still relevant and unresolved | Leave open, optionally add context |
74+
| **NEEDS INFO** | Can't determine status without more information | Comment asking for clarification |
75+
76+
## Investigation Techniques
77+
78+
### For Code-Related Issues
79+
```
80+
# Search for related code
81+
grep -r "keyword" pkg/
82+
glob "**/*related*.go"
83+
84+
# Check git history for fixes
85+
git log --oneline --grep="issue_number"
86+
git log --oneline --grep="keyword"
87+
88+
# Look for test coverage
89+
grep -r "TestRelatedFunction" .
90+
```
91+
92+
### For Configuration Issues
93+
- Check config files and defaults
94+
- Look at CLI flag definitions
95+
- Review environment variable handling
96+
97+
### For UI/UX Issues
98+
- Check command implementations
99+
- Review output formatting code
100+
- Look at error message handling
101+
102+
## Output Format
103+
104+
For each investigated issue, provide:
105+
106+
```markdown
107+
## Issue #NNN: [Title]
108+
109+
**Status:** [FIXED | IMPLEMENTED | WON'T DO | SUPERSEDED | STILL VALID | NEEDS INFO]
110+
111+
**Evidence:**
112+
- [What you found in the codebase]
113+
- [Relevant file paths and line numbers]
114+
- [Related commits if applicable]
115+
116+
**Recommendation:** [Specific action to take]
117+
118+
**Suggested Comment:** [Draft closure/update comment if applicable]
119+
```
120+
121+
## Writing Closure Comments
122+
123+
When recommending closure, provide a draft comment that is:
124+
- **Friendly and genuine** - not corporate-sounding
125+
- **Honest about reasoning** - explain the "why"
126+
- **Appreciative** - thank the reporter
127+
- **Open to revisiting** - leave door open if appropriate for "won't do" closures
128+
129+
### Comment Templates
130+
131+
**For FIXED issues:**
132+
```
133+
This has been fixed! [Brief explanation of what was changed]
134+
135+
[Technical details if helpful]
136+
137+
Closing this one out. Thanks for reporting!
138+
```
139+
140+
**For WON'T DO (bandwidth/signals):**
141+
```
142+
Hey, thanks for [bringing this up / the suggestion]!
143+
144+
We've been thinking about this, and unfortunately we don't have the bandwidth
145+
to take this on right now. We've also been watching for community signals,
146+
and honestly haven't seen [enough demand / many requests] for this.
147+
148+
That said, if [condition for revisiting], we'd be open to reconsidering.
149+
[Or: if someone wants to contribute this, we'd review a PR!]
150+
151+
For now, we're closing this out. Thanks again for [thinking of the project /
152+
your interest in ToolHive]!
153+
```
154+
155+
**For SUPERSEDED:**
156+
```
157+
Wanted to give an update on this one.
158+
159+
[Explanation of how direction changed or what replaced it]
160+
161+
With that in mind, we're closing this out. If [condition], feel free to
162+
open a new issue!
163+
```
164+
165+
## Tone Guidelines
166+
167+
All communications should be **kind, helpful, and polite**. Remember that issue reporters took time to contribute feedback, and closure messages should reflect appreciation for their effort, even when declining requests.
168+
169+
## Batch Triage Tips
170+
171+
When triaging multiple issues:
172+
1. Group similar issues together (same component, same type)
173+
2. Investigate related issues in parallel when possible
174+
3. Note patterns (e.g., "all container networking issues seem fixed")
175+
4. Flag issues that might be duplicates
176+
177+
## Example Investigation
178+
179+
**Issue #362: "MacOS firewall dialog appearing frequently"**
180+
181+
Investigation steps:
182+
1. Search for proxy binding code: `grep -r "Listen" pkg/transport/`
183+
2. Check default host configuration: look for `0.0.0.0` vs `127.0.0.1`
184+
3. Find the specific file mentioned in issue: `pkg/transport/proxy/httpsse/http_proxy.go`
185+
4. Verify current binding behavior
186+
187+
Finding: Proxy now defaults to `127.0.0.1` (localhost) instead of `0.0.0.0`
188+
189+
**Recommendation:** FIXED - Close with explanation of the fix and mention the `--host` flag for customization.

.github/workflows/claude.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ jobs:
4141

4242
- name: Run Claude Code
4343
id: claude
44-
uses: anthropics/claude-code-action@2316a9a8dbe4e7ac26008088f966f8c290e9a2e1 # v1
44+
uses: anthropics/claude-code-action@8341a564b0c1693e9fa29c681852ee3714980098 # v1
4545
with:
4646
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

.github/workflows/test-e2e-lifecycle.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
runs-on: ubuntu-latest
2020
timeout-minutes: 20
2121
env:
22-
YARDSTICK_IMAGE: ghcr.io/stackloklabs/yardstick/yardstick-server:0.0.2
22+
YARDSTICK_IMAGE: ghcr.io/stackloklabs/yardstick/yardstick-server:1.1.1
2323
defaults:
2424
run:
2525
shell: bash

cmd/thv-operator/api/v1alpha1/mcpexternalauthconfig_types.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ const (
1515
// ExternalAuthTypeHeaderInjection is the type for custom header injection
1616
ExternalAuthTypeHeaderInjection ExternalAuthType = "headerInjection"
1717

18+
// ExternalAuthTypeBearerToken is the type for bearer token authentication
19+
// This allows authenticating to remote MCP servers using bearer tokens stored in Kubernetes Secrets
20+
ExternalAuthTypeBearerToken ExternalAuthType = "bearerToken"
21+
1822
// ExternalAuthTypeUnauthenticated is the type for no authentication
1923
// This should only be used for backends on trusted networks (e.g., localhost, VPC)
2024
// or when authentication is handled by network-level security
@@ -29,7 +33,7 @@ type ExternalAuthType string
2933
// MCPServer resources in the same namespace.
3034
type MCPExternalAuthConfigSpec struct {
3135
// Type is the type of external authentication to configure
32-
// +kubebuilder:validation:Enum=tokenExchange;headerInjection;unauthenticated
36+
// +kubebuilder:validation:Enum=tokenExchange;headerInjection;bearerToken;unauthenticated
3337
// +kubebuilder:validation:Required
3438
Type ExternalAuthType `json:"type"`
3539

@@ -42,6 +46,11 @@ type MCPExternalAuthConfigSpec struct {
4246
// Only used when Type is "headerInjection"
4347
// +optional
4448
HeaderInjection *HeaderInjectionConfig `json:"headerInjection,omitempty"`
49+
50+
// BearerToken configures bearer token authentication
51+
// Only used when Type is "bearerToken"
52+
// +optional
53+
BearerToken *BearerTokenConfig `json:"bearerToken,omitempty"`
4554
}
4655

4756
// TokenExchangeConfig holds configuration for RFC-8693 OAuth 2.0 Token Exchange.
@@ -102,6 +111,15 @@ type HeaderInjectionConfig struct {
102111
ValueSecretRef *SecretKeyRef `json:"valueSecretRef"`
103112
}
104113

114+
// BearerTokenConfig holds configuration for bearer token authentication.
115+
// This allows authenticating to remote MCP servers using bearer tokens stored in Kubernetes Secrets.
116+
// For security reasons, only secret references are supported (no plaintext values).
117+
type BearerTokenConfig struct {
118+
// TokenSecretRef references a Kubernetes Secret containing the bearer token
119+
// +kubebuilder:validation:Required
120+
TokenSecretRef *SecretKeyRef `json:"tokenSecretRef"`
121+
}
122+
105123
// SecretKeyRef is a reference to a key within a Secret
106124
type SecretKeyRef struct {
107125
// Name is the name of the secret

cmd/thv-operator/api/v1alpha1/mcpexternalauthconfig_webhook.go

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -59,32 +59,70 @@ func (*MCPExternalAuthConfig) ValidateDelete(_ context.Context, _ runtime.Object
5959
func (r *MCPExternalAuthConfig) validate() error {
6060
switch r.Spec.Type {
6161
case ExternalAuthTypeTokenExchange:
62-
if r.Spec.TokenExchange == nil {
63-
return fmt.Errorf("tokenExchange configuration is required when type is 'tokenExchange'")
64-
}
65-
if r.Spec.HeaderInjection != nil {
66-
return fmt.Errorf("headerInjection must not be set when type is 'tokenExchange'")
67-
}
68-
62+
return r.validateTokenExchange()
6963
case ExternalAuthTypeHeaderInjection:
70-
if r.Spec.HeaderInjection == nil {
71-
return fmt.Errorf("headerInjection configuration is required when type is 'headerInjection'")
72-
}
73-
if r.Spec.TokenExchange != nil {
74-
return fmt.Errorf("tokenExchange must not be set when type is 'headerInjection'")
75-
}
76-
64+
return r.validateHeaderInjection()
65+
case ExternalAuthTypeBearerToken:
66+
return r.validateBearerToken()
7767
case ExternalAuthTypeUnauthenticated:
78-
if r.Spec.TokenExchange != nil {
79-
return fmt.Errorf("tokenExchange must not be set when type is 'unauthenticated'")
80-
}
81-
if r.Spec.HeaderInjection != nil {
82-
return fmt.Errorf("headerInjection must not be set when type is 'unauthenticated'")
83-
}
84-
68+
return r.validateUnauthenticated()
8569
default:
8670
return fmt.Errorf("unsupported auth type: %s", r.Spec.Type)
8771
}
72+
}
8873

74+
// validateTokenExchange validates tokenExchange type configuration
75+
func (r *MCPExternalAuthConfig) validateTokenExchange() error {
76+
if r.Spec.TokenExchange == nil {
77+
return fmt.Errorf("tokenExchange configuration is required when type is 'tokenExchange'")
78+
}
79+
if r.Spec.HeaderInjection != nil {
80+
return fmt.Errorf("headerInjection must not be set when type is 'tokenExchange'")
81+
}
82+
if r.Spec.BearerToken != nil {
83+
return fmt.Errorf("bearerToken must not be set when type is 'tokenExchange'")
84+
}
85+
return nil
86+
}
87+
88+
// validateHeaderInjection validates headerInjection type configuration
89+
func (r *MCPExternalAuthConfig) validateHeaderInjection() error {
90+
if r.Spec.HeaderInjection == nil {
91+
return fmt.Errorf("headerInjection configuration is required when type is 'headerInjection'")
92+
}
93+
if r.Spec.TokenExchange != nil {
94+
return fmt.Errorf("tokenExchange must not be set when type is 'headerInjection'")
95+
}
96+
if r.Spec.BearerToken != nil {
97+
return fmt.Errorf("bearerToken must not be set when type is 'headerInjection'")
98+
}
99+
return nil
100+
}
101+
102+
// validateBearerToken validates bearerToken type configuration
103+
func (r *MCPExternalAuthConfig) validateBearerToken() error {
104+
if r.Spec.BearerToken == nil {
105+
return fmt.Errorf("bearerToken configuration is required when type is 'bearerToken'")
106+
}
107+
if r.Spec.TokenExchange != nil {
108+
return fmt.Errorf("tokenExchange must not be set when type is 'bearerToken'")
109+
}
110+
if r.Spec.HeaderInjection != nil {
111+
return fmt.Errorf("headerInjection must not be set when type is 'bearerToken'")
112+
}
113+
return nil
114+
}
115+
116+
// validateUnauthenticated validates unauthenticated type configuration
117+
func (r *MCPExternalAuthConfig) validateUnauthenticated() error {
118+
if r.Spec.TokenExchange != nil {
119+
return fmt.Errorf("tokenExchange must not be set when type is 'unauthenticated'")
120+
}
121+
if r.Spec.HeaderInjection != nil {
122+
return fmt.Errorf("headerInjection must not be set when type is 'unauthenticated'")
123+
}
124+
if r.Spec.BearerToken != nil {
125+
return fmt.Errorf("bearerToken must not be set when type is 'unauthenticated'")
126+
}
89127
return nil
90128
}

0 commit comments

Comments
 (0)