edited ci file
This commit is contained in:
@@ -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)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -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'] })
|
||||
},
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user