Skip to content

Commit 27d87d7

Browse files
feat(auth): enforce API key for agent validation; propagate displayName in backend and client; remove startup agent display and defer to validation
🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
1 parent c8c0660 commit 27d87d7

File tree

3 files changed

+36
-29
lines changed

3 files changed

+36
-29
lines changed

backend/src/api/agents.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ import type {
1515
const AGENT_VALIDATION_CACHE_TTL_MS = 5 * 60 * 1000 // 5 minutes
1616

1717
type CacheEntry = {
18-
result: { valid: true; source?: string; normalizedId?: string }
18+
result: {
19+
valid: true
20+
source?: string
21+
normalizedId?: string
22+
displayName?: string
23+
}
1924
expiresAt: number
2025
}
2126

@@ -35,15 +40,11 @@ export async function validateAgentNameHandler(
3540
try {
3641
// Check for x-codebuff-api-key header for authentication
3742
const apiKey = extractAuthTokenFromHeader(req)
38-
39-
if (apiKey) {
40-
logger.debug(
41-
{
42-
hasApiKey: true,
43-
agentId: req.query.agentId,
44-
},
45-
'Agent validation request with API key authentication',
46-
)
43+
if (!apiKey) {
44+
return res.status(403).json({
45+
valid: false,
46+
message: 'API key required',
47+
})
4748
}
4849

4950
// Parse from query instead (GET)
@@ -60,11 +61,13 @@ export async function validateAgentNameHandler(
6061
}
6162

6263
// Check built-in agents first
63-
if (AGENT_PERSONAS[agentId as keyof typeof AGENT_PERSONAS]) {
64+
const persona = AGENT_PERSONAS[agentId as keyof typeof AGENT_PERSONAS]
65+
if (persona) {
6466
const result = {
6567
valid: true as const,
6668
source: 'builtin',
6769
normalizedId: agentId,
70+
displayName: persona.displayName,
6871
}
6972
agentValidationCache.set(agentId, {
7073
result,
@@ -80,6 +83,7 @@ export async function validateAgentNameHandler(
8083
valid: true as const,
8184
source: 'published',
8285
normalizedId: found.id,
86+
displayName: found.displayName,
8387
}
8488
agentValidationCache.set(agentId, {
8589
result,

npm-app/src/cli.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -633,17 +633,8 @@ export class CLI {
633633
if (client.user) {
634634
displayGreeting(this.costMode, client.user.name)
635635

636-
// Show selected agent when provided via --agent
637-
if (this.agent) {
638-
try {
639-
const localAgentInfo = await getLocalAgentInfo()
640-
const agentDisplayName = getAgentDisplayName(
641-
this.agent,
642-
localAgentInfo,
643-
)
644-
console.log(green(`\nAgent: ${bold(agentDisplayName)}`))
645-
} catch {}
646-
}
636+
// Agent name will be displayed by validateAgent when resolved
637+
// No need to display here to avoid race conditions
647638
} else {
648639
console.log(
649640
`Welcome to Codebuff! Give us a sec to get your account set up...`,

npm-app/src/index.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { type CostMode } from '@codebuff/common/constants'
44
import { AnalyticsEvent } from '@codebuff/common/constants/analytics-events'
55
import { Command, Option } from 'commander'
6-
import { red, yellow, bold } from 'picocolors'
6+
import { red, yellow, green, bold } from 'picocolors'
77

88
import { displayLoadedAgents, loadLocalAgents } from './agents/load-agents'
99
import { CLI } from './cli'
@@ -34,7 +34,7 @@ import type { CliOptions } from './types'
3434
export async function validateAgent(
3535
agent: string,
3636
localAgents?: Record<string, any>,
37-
): Promise<void> {
37+
): Promise<string | undefined> {
3838
const agents = localAgents ?? {}
3939

4040
// if local agents are loaded, they're already validated
@@ -55,9 +55,20 @@ export async function validateAgent(
5555
method: 'GET',
5656
headers,
5757
})
58-
const data: { valid?: boolean } = await resp.json().catch(() => ({}) as any)
59-
60-
if (resp.ok && data.valid) return
58+
// Include optional fields from backend, notably displayName
59+
const data: {
60+
valid?: boolean
61+
normalizedId?: string
62+
displayName?: string
63+
} = await resp.json().catch(() => ({}) as any)
64+
65+
if (resp.ok && data.valid) {
66+
// Console log the agent name immediately when resolved
67+
if (data.displayName) {
68+
console.log(green(`\nAgent: ${bold(data.displayName)}`))
69+
}
70+
return data.displayName
71+
}
6172

6273
if (resp.ok && !data.valid) {
6374
console.error(red(`\nUnknown agent: ${bold(agent)}. Exiting.`))
@@ -72,6 +83,7 @@ export async function validateAgent(
7283
} finally {
7384
Spinner.get().stop()
7485
}
86+
return undefined
7587
}
7688

7789
async function codebuff({
@@ -102,7 +114,7 @@ async function codebuff({
102114
// Ensure validation runs strictly after local agent load/display
103115
const loadAndValidatePromise: Promise<void> = loadLocalAgents({
104116
verbose: true,
105-
}).then((agents) => {
117+
}).then(async (agents) => {
106118
validateAgentDefinitionsIfAuthenticated(Object.values(agents))
107119

108120
const codebuffConfig = loadCodebuffConfig()
@@ -111,7 +123,7 @@ async function codebuff({
111123
return
112124
}
113125

114-
return validateAgent(agent, agents)
126+
await validateAgent(agent, agents)
115127
})
116128

117129
const readyPromise = Promise.all([

0 commit comments

Comments
 (0)