mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-20 13:53:32 +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', () => {
|
it('normalizes SkillHub list items as fallback candidates with Chinese summary', () => {
|
||||||
const result = normalizeSkillHubList(SKILLHUB_TOP_SKILLS_RESPONSE)
|
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', () => {
|
it('normalizes SkillHub detail security reports', () => {
|
||||||
const detail = normalizeSkillHubDetail(SKILLHUB_DETAIL_RESPONSE)
|
const detail = normalizeSkillHubDetail(SKILLHUB_DETAIL_RESPONSE)
|
||||||
|
|
||||||
@ -141,4 +186,22 @@ describe('skill market source normalization', () => {
|
|||||||
trustSummary: '安全,无风险',
|
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
|
trustSummary?: string
|
||||||
packageSha256?: 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) {
|
if (payload.status === 'clean' && !payload.hasWarnings) {
|
||||||
return { trustState: 'clean', trustSummary: scannerSummary, packageSha256: payload.sha256 }
|
return { trustState: 'clean', trustSummary: scannerSummary, packageSha256: payload.sha256 }
|
||||||
}
|
}
|
||||||
if (payload.status === 'malicious' || payload.status === 'blocked') {
|
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) {
|
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 }
|
return { trustState: 'unknown', trustSummary: scannerSummary, packageSha256: payload.sha256 }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,6 +61,9 @@ function normalizeExternalUrl(value: string | undefined, slug: string) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const url = new URL(value)
|
const url = new URL(value)
|
||||||
|
if (url.username || url.password) {
|
||||||
|
return fallbackUrl
|
||||||
|
}
|
||||||
if (url.protocol === 'https:' && ALLOWED_EXTERNAL_URL_HOSTS.has(url.hostname)) {
|
if (url.protocol === 'https:' && ALLOWED_EXTERNAL_URL_HOSTS.has(url.hostname)) {
|
||||||
return url.toString()
|
return url.toString()
|
||||||
}
|
}
|
||||||
@ -77,7 +80,12 @@ function trustFromReports(reports?: Record<string, { status?: string; statusText
|
|||||||
} {
|
} {
|
||||||
const values = Object.values(reports ?? {})
|
const values = Object.values(reports ?? {})
|
||||||
if (values.some((report) => report.status === 'malicious' || report.status === 'blocked')) {
|
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')) {
|
if (values.length > 0 && values.every((report) => report.status === 'benign')) {
|
||||||
return { trustState: 'benign', trustSummary: values.find((report) => report.statusText)?.statusText }
|
return { trustState: 'benign', trustSummary: values.find((report) => report.statusText)?.statusText }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user