mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
fix: align skill market security summaries
This commit is contained in:
parent
26b3322fb7
commit
c744213aae
@ -57,6 +57,19 @@ describe('skill market source normalization', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('uses malicious ClawHub scanner summaries for malicious scans', () => {
|
||||
expect(normalizeClawHubScan({
|
||||
status: 'malicious',
|
||||
scanners: {
|
||||
metadata: { status: 'clean', summary: 'No dangerous patterns detected.' },
|
||||
staticAnalysis: { status: 'malicious', summary: 'Credential exfiltration detected.' },
|
||||
},
|
||||
})).toMatchObject({
|
||||
trustState: 'blocked',
|
||||
trustSummary: 'Credential exfiltration detected.',
|
||||
})
|
||||
})
|
||||
|
||||
it('normalizes SkillHub list items as fallback candidates with Chinese summary', () => {
|
||||
const result = normalizeSkillHubList(SKILLHUB_TOP_SKILLS_RESPONSE)
|
||||
|
||||
@ -130,6 +143,38 @@ describe('skill market source normalization', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('rejects SkillHub external URLs with userinfo', () => {
|
||||
const list = normalizeSkillHubList({
|
||||
code: 0,
|
||||
data: {
|
||||
skills: [
|
||||
{
|
||||
slug: 'skill-vetter',
|
||||
name: 'Skill Vetter',
|
||||
upstream_url: 'https://evil.test@github.com/path',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
expect(list.items[0]).toMatchObject({
|
||||
canonicalUrl: 'https://skillhub.cn/skills/skill-vetter',
|
||||
upstreamUrl: 'https://skillhub.cn/skills/skill-vetter',
|
||||
})
|
||||
|
||||
const detail = normalizeSkillHubDetail({
|
||||
skill: {
|
||||
slug: 'skill-vetter',
|
||||
displayName: 'Skill Vetter',
|
||||
sourceUrl: 'https://user:password@github.com/path',
|
||||
},
|
||||
})
|
||||
|
||||
expect(detail).toMatchObject({
|
||||
canonicalUrl: 'https://skillhub.cn/skills/skill-vetter',
|
||||
})
|
||||
})
|
||||
|
||||
it('normalizes SkillHub detail security reports', () => {
|
||||
const detail = normalizeSkillHubDetail(SKILLHUB_DETAIL_RESPONSE)
|
||||
|
||||
@ -141,4 +186,22 @@ describe('skill market source normalization', () => {
|
||||
trustSummary: '安全,无风险',
|
||||
})
|
||||
})
|
||||
|
||||
it('uses malicious SkillHub report summaries for blocked details', () => {
|
||||
const detail = normalizeSkillHubDetail({
|
||||
securityReports: {
|
||||
community: { status: 'benign', statusText: 'safe' },
|
||||
staticAnalysis: { status: 'malicious', statusText: 'Credential exfiltration detected.' },
|
||||
},
|
||||
skill: {
|
||||
slug: 'skill-vetter',
|
||||
displayName: 'Skill Vetter',
|
||||
},
|
||||
})
|
||||
|
||||
expect(detail).toMatchObject({
|
||||
trustState: 'blocked',
|
||||
trustSummary: 'Credential exfiltration detected.',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -56,15 +56,27 @@ export function normalizeClawHubScan(payload: ClawHubScanResponse): {
|
||||
trustSummary?: string
|
||||
packageSha256?: string
|
||||
} {
|
||||
const scannerSummary = Object.values(payload.scanners ?? {}).find((entry) => entry.summary)?.summary
|
||||
const scannerEntries = Object.values(payload.scanners ?? {})
|
||||
const scannerSummary = scannerEntries.find((entry) => entry.summary)?.summary
|
||||
const scannerSummaryForStatuses = (statuses: string[]) =>
|
||||
scannerEntries.find((entry) => entry.summary && entry.status && statuses.includes(entry.status))?.summary
|
||||
|
||||
if (payload.status === 'clean' && !payload.hasWarnings) {
|
||||
return { trustState: 'clean', trustSummary: scannerSummary, packageSha256: payload.sha256 }
|
||||
}
|
||||
if (payload.status === 'malicious' || payload.status === 'blocked') {
|
||||
return { trustState: 'blocked', trustSummary: scannerSummary, packageSha256: payload.sha256 }
|
||||
return {
|
||||
trustState: 'blocked',
|
||||
trustSummary: scannerSummaryForStatuses(['malicious', 'blocked']) ?? scannerSummary,
|
||||
packageSha256: payload.sha256,
|
||||
}
|
||||
}
|
||||
if (payload.status === 'suspicious' || payload.hasWarnings) {
|
||||
return { trustState: 'warning', trustSummary: scannerSummary, packageSha256: payload.sha256 }
|
||||
return {
|
||||
trustState: 'warning',
|
||||
trustSummary: scannerSummaryForStatuses(['suspicious', 'warning']) ?? scannerSummary,
|
||||
packageSha256: payload.sha256,
|
||||
}
|
||||
}
|
||||
return { trustState: 'unknown', trustSummary: scannerSummary, packageSha256: payload.sha256 }
|
||||
}
|
||||
|
||||
@ -61,6 +61,9 @@ function normalizeExternalUrl(value: string | undefined, slug: string) {
|
||||
|
||||
try {
|
||||
const url = new URL(value)
|
||||
if (url.username || url.password) {
|
||||
return fallbackUrl
|
||||
}
|
||||
if (url.protocol === 'https:' && ALLOWED_EXTERNAL_URL_HOSTS.has(url.hostname)) {
|
||||
return url.toString()
|
||||
}
|
||||
@ -77,7 +80,12 @@ function trustFromReports(reports?: Record<string, { status?: string; statusText
|
||||
} {
|
||||
const values = Object.values(reports ?? {})
|
||||
if (values.some((report) => report.status === 'malicious' || report.status === 'blocked')) {
|
||||
return { trustState: 'blocked', trustSummary: values.find((report) => report.statusText)?.statusText }
|
||||
return {
|
||||
trustState: 'blocked',
|
||||
trustSummary: values.find((report) =>
|
||||
(report.status === 'malicious' || report.status === 'blocked') && report.statusText
|
||||
)?.statusText,
|
||||
}
|
||||
}
|
||||
if (values.length > 0 && values.every((report) => report.status === 'benign')) {
|
||||
return { trustState: 'benign', trustSummary: values.find((report) => report.statusText)?.statusText }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user