Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support PII on the dashboard #326

Merged
merged 11 commits into from
Feb 17, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -40,56 +40,42 @@ test('shows correct count of all packages', async () => {
})
})

test('shows correct count of malicious packages', async () => {
server.use(
http.get(mswEndpoint('/api/v1/workspaces/:workspace_name/messages'), () => {
return HttpResponse.json(
Array.from({ length: 13 }).map(() =>
mockConversation({
alertsConfig: {
type: 'malicious',
numAlerts: 1,
},
})
)
const filteredCases = [
{ tabLabel: /malicious/i, alertType: 'malicious' as const, count: 13 },
{ tabLabel: /secrets/i, alertType: 'secret' as const, count: 10 },
{ tabLabel: /pii/i, alertType: 'pii' as const, count: 9 },
]

filteredCases.forEach(({ tabLabel, alertType, count }) => {
test(`shows correct count of ${alertType} packages`, async () => {
server.use(
http.get(
mswEndpoint('/api/v1/workspaces/:workspace_name/messages'),
() => {
return HttpResponse.json(
Array.from({ length: count }).map(() =>
mockConversation({
alertsConfig: {
type: alertType,
numAlerts: 1,
},
})
)
)
}
)
})
)
)

const { getByRole } = render(
<TabsMessages>
<div>foo</div>
</TabsMessages>
)
const { getByRole } = render(
<TabsMessages>
<div>foo</div>
</TabsMessages>
)

await waitFor(() => {
expect(getByRole('tab', { name: /malicious/i })).toHaveTextContent('13')
})
})

test('shows correct count of secret packages', async () => {
server.use(
http.get(mswEndpoint('/api/v1/workspaces/:workspace_name/messages'), () => {
return HttpResponse.json(
Array.from({ length: 13 }).map(() =>
mockConversation({
alertsConfig: {
type: 'secret',
numAlerts: 1,
},
})
)
await waitFor(() => {
expect(getByRole('tab', { name: tabLabel })).toHaveTextContent(
String(count)
)
})
)

const { getByRole } = render(
<TabsMessages>
<div>foo</div>
</TabsMessages>
)

await waitFor(() => {
expect(getByRole('tab', { name: /secrets/i })).toHaveTextContent('13')
})
})
6 changes: 6 additions & 0 deletions src/features/dashboard-messages/components/tabs-messages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ import {
import { SearchFieldMessages } from './search-field-messages'
import { tv } from 'tailwind-variants'
import { useQueryGetWorkspaceMessages } from '@/hooks/use-query-get-workspace-messages'
import { isConversationWithPII } from '@/lib/is-alert-pii'

type AlertsCount = {
all: number
malicious: number
secrets: number
pii: number
}

function select(data: V1GetWorkspaceMessagesResponse): AlertsCount {
Expand All @@ -36,10 +38,13 @@ function select(data: V1GetWorkspaceMessagesResponse): AlertsCount {
isConversationWithSecretAlerts,
]).length

const pii: number = multiFilter(data, [isConversationWithPII]).length

return {
all,
malicious,
secrets,
pii,
}
}

Expand Down Expand Up @@ -103,6 +108,7 @@ export function TabsMessages({ children }: { children: React.ReactNode }) {
count={data?.secrets ?? 0}
id={AlertsFilterView.SECRETS}
/>
<Tab title="PII" count={data?.pii ?? 0} id={AlertsFilterView.PII} />
</TabList>

<SearchFieldMessages className="ml-auto" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum AlertsFilterView {
ALL = 'all',
MALICIOUS = 'malicious',
SECRETS = 'secrets',
PII = 'pii',
}

const alertsFilterSchema = z.object({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { isConversationWithMaliciousAlerts } from '../../../lib/is-alert-malicio
import { isConversationWithSecretAlerts } from '../../../lib/is-alert-secret'
import { filterMessagesBySubstring } from '../lib/filter-messages-by-substring'
import { useQueryGetWorkspaceMessages } from '@/hooks/use-query-get-workspace-messages'
import { isConversationWithPII } from '@/lib/is-alert-pii'

const FILTER: Record<
AlertsFilterView,
Expand All @@ -17,6 +18,7 @@ const FILTER: Record<
all: () => true,
malicious: isConversationWithMaliciousAlerts,
secrets: isConversationWithSecretAlerts,
pii: isConversationWithPII,
}

export function useQueryGetWorkspaceMessagesTable() {
Expand Down
14 changes: 14 additions & 0 deletions src/lib/is-alert-pii.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Alert, AlertConversation, Conversation } from '@/api/generated'

export function isConversationWithPII(
conversation: Conversation | null
): boolean {
return conversation?.alerts?.some(isAlertPii) ?? false
}

export function isAlertPii(alert: Alert | AlertConversation | null) {
return (
alert?.trigger_category === 'critical' &&
alert.trigger_type === 'codegate-pii'
)
}
19 changes: 16 additions & 3 deletions src/mocks/msw/mockers/alert.mock.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { Alert, AlertSeverity } from "@/api/generated";
import { faker } from "@faker-js/faker";
import { Alert, AlertSeverity } from '@/api/generated'
import { faker } from '@faker-js/faker'

const ALERT_SECRET_FIELDS = {
trigger_string: 'foo',
trigger_type: 'codegate-secrets',
} satisfies Pick<Alert, 'trigger_string' | 'trigger_type'>

const ALERT_PII_FIELDS = {
trigger_string: '[email protected]',
trigger_type: 'codegate-pii',
} satisfies Pick<Alert, 'trigger_string' | 'trigger_type'>

const ALERT_MALICIOUS_FIELDS = {
trigger_string: {
name: 'invokehttp',
Expand All @@ -31,7 +36,7 @@ const getBaseAlert = ({
export const mockAlert = ({
type,
}: {
type: 'secret' | 'malicious'
type: 'secret' | 'malicious' | 'pii'
}): Alert => {
const timestamp = faker.date.recent().toISOString()

Expand All @@ -54,6 +59,14 @@ export const mockAlert = ({
...ALERT_SECRET_FIELDS,
}

return result
}
case 'pii': {
const result: Alert = {
...base,
...ALERT_PII_FIELDS,
}

return result
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/mocks/msw/mockers/conversation.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function mockConversation({
withTokenUsage?: boolean
alertsConfig?: {
numAlerts?: number
type?: 'secret' | 'malicious' | 'any'
type?: 'secret' | 'malicious' | 'any' | 'pii'
}
} = {}) {
const timestamp = faker.date.recent().toISOString()
Expand Down
Loading