mirror of
https://github.com/stablyai/orca.git
synced 2026-10-24 16:03:45 +00:00
fix(ssh): validate Linear issue row fields
This commit is contained in:
@@ -96,4 +96,38 @@ describe('formatRemoteCli', () => {
|
||||
stderr: ''
|
||||
})
|
||||
})
|
||||
|
||||
it('falls back to JSON for malformed Linear issue row fields', () => {
|
||||
const response: RpcResponse = {
|
||||
id: 'rpc-1',
|
||||
ok: true,
|
||||
_meta: meta,
|
||||
result: {
|
||||
issues: [
|
||||
{
|
||||
id: 'issue-1',
|
||||
identifier: 'ENG-1',
|
||||
title: 'Broken state',
|
||||
url: 'https://linear.app/acme/issue/ENG-1',
|
||||
labels: [],
|
||||
state: { name: 42 },
|
||||
workspace: { id: 'workspace-1', name: 'Acme' }
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
limit: null,
|
||||
returned: 1,
|
||||
hasMore: false,
|
||||
orderBy: 'updatedAt',
|
||||
partial: false,
|
||||
workspaceErrors: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(formatRemoteCli(response)).toEqual({
|
||||
stdout: `${JSON.stringify(response.result)}\n`,
|
||||
stderr: ''
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -47,10 +47,48 @@ function isLinearMcpIssue(issue: unknown): boolean {
|
||||
typeof issue.title === 'string' &&
|
||||
typeof issue.url === 'string' &&
|
||||
Array.isArray(issue.labels) &&
|
||||
issue.labels.every(isLinearNamedEntity) &&
|
||||
isOptionalLinearNamedEntity(issue.state) &&
|
||||
isOptionalLinearNamedEntity(issue.team) &&
|
||||
isOptionalLinearNamedEntity(issue.project) &&
|
||||
isOptionalLinearNamedEntity(issue.cycle) &&
|
||||
isOptionalLinearUser(issue.assignee) &&
|
||||
(issue.priority === undefined ||
|
||||
issue.priority === null ||
|
||||
typeof issue.priority === 'number') &&
|
||||
isLinearWorkspaceCandidate(issue.workspace)
|
||||
)
|
||||
}
|
||||
|
||||
function isOptionalLinearNamedEntity(value: unknown): boolean {
|
||||
return value === undefined || value === null || isLinearNamedEntity(value)
|
||||
}
|
||||
|
||||
function isLinearNamedEntity(value: unknown): boolean {
|
||||
return (
|
||||
isRecord(value) &&
|
||||
(value.id === undefined || value.id === null || typeof value.id === 'string') &&
|
||||
(value.name === undefined || value.name === null || typeof value.name === 'string') &&
|
||||
(value.color === undefined || value.color === null || typeof value.color === 'string') &&
|
||||
(value.type === undefined || value.type === null || typeof value.type === 'string')
|
||||
)
|
||||
}
|
||||
|
||||
function isOptionalLinearUser(value: unknown): boolean {
|
||||
return (
|
||||
value === undefined ||
|
||||
value === null ||
|
||||
(isRecord(value) &&
|
||||
(value.id === undefined || value.id === null || typeof value.id === 'string') &&
|
||||
(value.displayName === undefined ||
|
||||
value.displayName === null ||
|
||||
typeof value.displayName === 'string') &&
|
||||
(value.avatarUrl === undefined ||
|
||||
value.avatarUrl === null ||
|
||||
typeof value.avatarUrl === 'string'))
|
||||
)
|
||||
}
|
||||
|
||||
function isLinearWorkspaceCandidate(workspace: unknown): boolean {
|
||||
return (
|
||||
isRecord(workspace) && typeof workspace.id === 'string' && typeof workspace.name === 'string'
|
||||
|
||||
Reference in New Issue
Block a user