edited ci file

This commit is contained in:
2026-05-13 00:55:28 +02:00
parent f99f0e0fc5
commit 77268e2302
17 changed files with 684 additions and 29 deletions
+76
View File
@@ -0,0 +1,76 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { z } from 'zod'
import { api, ApiError } from '../client'
import type { SBOMReport } from '../../types/api'
const sbomReportSchema = z.object({
id: z.number(),
repoId: z.number(),
runId: z.number(),
sha: z.string(),
format: z.string(),
componentCount: z.number(),
generatedAt: z.string(),
})
/** SBOM metadata for a specific pipeline run. */
export function useRunSBOM(owner: string, repo: string, runId: number) {
return useQuery<SBOMReport | null>({
queryKey: ['repos', owner, repo, 'runs', runId, 'sbom'],
queryFn: async () => {
try {
return await api.get<SBOMReport>(
`/api/v1/repos/${owner}/${repo}/runs/${runId}/sbom`,
sbomReportSchema,
)
} catch (err) {
if (err instanceof ApiError && err.status === 404) return null
throw err
}
},
enabled: Boolean(owner && repo && runId),
retry: false,
})
}
/** Latest SBOM metadata for a repo. */
export function useLatestSBOM(owner: string, repo: string) {
return useQuery({
queryKey: ['repos', owner, repo, 'sbom'],
queryFn: () =>
api.get<SBOMReport>(
`/api/v1/repos/${owner}/${repo}/sbom`,
sbomReportSchema,
),
enabled: Boolean(owner && repo),
retry: false,
})
}
/** Download SBOM document URL for a specific run. */
export function getRunSBOMDocumentURL(owner: string, repo: string, runId: number): string {
return `/api/v1/repos/${owner}/${repo}/runs/${runId}/sbom/document`
}
/** Download latest SBOM document URL. */
export function getLatestSBOMDocumentURL(owner: string, repo: string): string {
return `/api/v1/repos/${owner}/${repo}/sbom/document`
}
/** Trigger on-demand SBOM generation. */
export function useGenerateSBOM(owner: string, repo: string) {
const qc = useQueryClient()
return useMutation({
mutationFn: ({ ref, runId }: { ref: string; runId?: number }) => {
let url = `/api/v1/repos/${owner}/${repo}/sbom/generate?ref=${encodeURIComponent(ref)}`
if (runId) url += `&runID=${runId}`
return api.post<SBOMReport>(url, sbomReportSchema, undefined)
},
onSuccess: (data, { runId }) => {
qc.setQueryData(['repos', owner, repo, 'sbom'], data)
if (runId) {
qc.setQueryData(['repos', owner, repo, 'runs', runId, 'sbom'], data)
}
},
})
}
+117
View File
@@ -0,0 +1,117 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { z } from 'zod'
import { api } from '../client'
import type { SecretLeak, VulnerabilityFinding } from '../../types/api'
// ── Zod schemas ───────────────────────────────────────────────────────────────
const secretLeakSchema = z.object({
id: z.number(),
repoId: z.number(),
commitSha: z.string(),
ref: z.string(),
patternName: z.string(),
description: z.string(),
severity: z.string(),
matchSample: z.string(),
dismissed: z.boolean(),
dismissedBy: z.string().optional(),
dismissedAt: z.string().nullable().optional(),
detectedAt: z.string(),
})
const vulnerabilityFindingSchema = z.object({
id: z.number(),
repoId: z.number(),
vulnId: z.string(),
purl: z.string(),
version: z.string(),
summary: z.string(),
details: z.string().optional(),
cvssScore: z.number(),
fixedVersion: z.string(),
dismissed: z.boolean(),
dismissedBy: z.string().optional(),
dismissedAt: z.string().nullable().optional(),
detectedAt: z.string(),
})
// ── Secret Leak queries ───────────────────────────────────────────────────────
/** Active secret leaks for a repo. */
export function useSecretLeaks(owner: string, repo: string) {
return useQuery({
queryKey: ['repos', owner, repo, 'secrets', 'leaks'],
queryFn: () =>
api.get<SecretLeak[]>(
`/api/v1/repos/${owner}/${repo}/secrets/leaks`,
z.array(secretLeakSchema),
),
enabled: Boolean(owner && repo),
refetchInterval: 30_000,
})
}
/** Dismiss a secret leak. */
export function useDismissSecretLeak(owner: string, repo: string) {
const qc = useQueryClient()
return useMutation({
mutationFn: (leakId: number) =>
api.post(
`/api/v1/repos/${owner}/${repo}/secrets/leaks/${leakId}/dismiss`,
z.unknown(),
undefined,
),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'secrets', 'leaks'] })
},
})
}
// ── Vulnerability queries ─────────────────────────────────────────────────────
/** Active vulnerability findings for a repo. */
export function useVulnerabilities(owner: string, repo: string) {
return useQuery({
queryKey: ['repos', owner, repo, 'vulnerabilities'],
queryFn: () =>
api.get<VulnerabilityFinding[]>(
`/api/v1/repos/${owner}/${repo}/vulnerabilities`,
z.array(vulnerabilityFindingSchema),
),
enabled: Boolean(owner && repo),
refetchInterval: 30_000,
})
}
/** Trigger a vulnerability scan. */
export function useScanVulnerabilities(owner: string, repo: string) {
const qc = useQueryClient()
return useMutation({
mutationFn: () =>
api.post<VulnerabilityFinding[]>(
`/api/v1/repos/${owner}/${repo}/vulnerabilities/scan`,
z.array(vulnerabilityFindingSchema),
undefined,
),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'vulnerabilities'] })
},
})
}
/** Dismiss a vulnerability finding. */
export function useDismissVulnerability(owner: string, repo: string) {
const qc = useQueryClient()
return useMutation({
mutationFn: (findingId: number) =>
api.post(
`/api/v1/repos/${owner}/${repo}/vulnerabilities/${findingId}/dismiss`,
z.unknown(),
undefined,
),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'vulnerabilities'] })
},
})
}