Skip to content

Commit

Permalink
Further remove editability from site, made display nicer
Browse files Browse the repository at this point in the history
  • Loading branch information
dakota002 committed Nov 19, 2024
1 parent b48b2d3 commit 1791830
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 359 deletions.
119 changes: 0 additions & 119 deletions app/lib/kafka.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { tables } from '@architect/functions'
import { paginateScan } from '@aws-sdk/lib-dynamodb'

Check warning on line 9 in app/lib/kafka.server.ts

View check run for this annotation

Codecov / codecov/patch

app/lib/kafka.server.ts#L8-L9

Added lines #L8 - L9 were not covered by tests
import type { DynamoDBDocument } from '@aws-sdk/lib-dynamodb'
import crypto from 'crypto'

Check warning on line 11 in app/lib/kafka.server.ts

View check run for this annotation

Codecov / codecov/patch

app/lib/kafka.server.ts#L11

Added line #L11 was not covered by tests
import type { AclFilter } from 'gcn-kafka'
import { Kafka } from 'gcn-kafka'
import type { AclEntry } from 'kafkajs'
import {

Check warning on line 14 in app/lib/kafka.server.ts

View check run for this annotation

Codecov / codecov/patch

app/lib/kafka.server.ts#L14

Added line #L14 was not covered by tests
Expand Down Expand Up @@ -113,101 +112,6 @@ function validateUser(user: User) {
throw new Response(null, { status: 403 })

Check warning on line 112 in app/lib/kafka.server.ts

View check run for this annotation

Codecov / codecov/patch

app/lib/kafka.server.ts#L112

Added line #L112 was not covered by tests
}

export async function createKafkaACL(
user: User,
userClientType: UserClientType,
resourceName: string,
group: string,
permissionType: number,
resourceType: number,
includePrefixed: boolean
) {
const acls: KafkaACL[] =
userClientType == 'consumer'
? consumerOperations.map((operation) => {
return {
resourceName,
principal: `User:${group}`,
host: '*',
operation,
permissionType,
resourcePatternType: 3,
resourceType,
}
})
: producerOperations.map((operation) => {
return {
resourceName,
principal: `User:${group}`,
host: '*',
operation,
permissionType,
resourcePatternType: 3,
resourceType,
}
})

if (includePrefixed) {
const prefixedAcls =
userClientType === 'consumer'
? consumerOperations.map((operation) => {
return {
resourceName,
principal: `User:${group}`,
host: '*',
operation,
permissionType,
resourcePatternType: 4,
resourceType,
}
})
: producerOperations.map((operation) => {
return {
resourceName,
principal: `User:${group}`,
host: '*',
operation,
permissionType,
resourcePatternType: 4,
resourceType,
}
})
acls.push(...prefixedAcls)
}

await createKafkaACLInternal(user, acls)
}

async function createKafkaACLInternal(user: User, acls: KafkaACL[]) {
validateUser(user)
// Save to db
const db = await tables()
await Promise.all(
acls.map((acl) => db.kafka_acls.put({ ...acl, aclId: crypto.randomUUID() }))
)

// Add to Kafka
const adminClient = adminKafka.admin()
await adminClient.connect()
if (acls.some((acl) => acl.resourceType === AclResourceTypes.TOPIC))
await Promise.all(
acls
.filter((acl) => acl.resourceType === AclResourceTypes.TOPIC)
.map((acl) =>
adminClient.createTopics({
topics: [
{
topic: acl.resourceName,
},
],
})
)
)

await adminClient.createAcls({ acl: acls })
await adminClient.disconnect()
}

export async function getKafkaACLsFromDynamoDB(user: User, filter?: string) {
validateUser(user)
const db = await tables()
Expand Down Expand Up @@ -250,8 +154,6 @@ export async function getAclsFromBrokers() {

const results: KafkaACL[] = []
for (const item of acls.resources) {
console.log('Item:', item)

results.push(
...item.acls.map((acl) => {
return {

Check warning on line 159 in app/lib/kafka.server.ts

View check run for this annotation

Codecov / codecov/patch

app/lib/kafka.server.ts#L155-L159

Added lines #L155 - L159 were not covered by tests
Expand All @@ -267,27 +169,6 @@ export async function getAclsFromBrokers() {
return results

Check warning on line 169 in app/lib/kafka.server.ts

View check run for this annotation

Codecov / codecov/patch

app/lib/kafka.server.ts#L169

Added line #L169 was not covered by tests
}

export async function deleteKafkaACL(user: User, aclIds: string[]) {
validateUser(user)
const db = await tables()
const acls: KafkaACL[] = await Promise.all(
aclIds.map((aclId) => db.kafka_acls.get({ aclId }))
)

const adminClient = adminKafka.admin()
await adminClient.connect()
await adminClient.deleteAcls({ filters: acls as AclFilter[] })
await adminClient.disconnect()

await Promise.all(
acls.map((acl) =>
db.kafka_acls.delete({
aclId: acl.aclId,
})
)
)
}

export async function updateDbFromBrokers(user: User) {
const kafkaDefinedAcls = await getAclsFromBrokers()
const db = await tables()
Expand Down
164 changes: 28 additions & 136 deletions app/routes/admin.kafka._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,17 @@
*/
import type { ActionFunctionArgs, LoaderFunctionArgs } from '@remix-run/node'
import { useFetcher, useLoaderData } from '@remix-run/react'
import type { ModalRef } from '@trussworks/react-uswds'
import {
Button,
Grid,
Icon,
Label,
Modal,
ModalFooter,
ModalHeading,
ModalToggleButton,
TextInput,
} from '@trussworks/react-uswds'
import { Button, Label, Table, TextInput } from '@trussworks/react-uswds'
import { groupBy, sortBy } from 'lodash'
import { useEffect, useRef, useState } from 'react'
import { useEffect, useState } from 'react'

Check warning on line 12 in app/routes/admin.kafka._index.tsx

View check run for this annotation

Codecov / codecov/patch

app/routes/admin.kafka._index.tsx#L9-L12

Added lines #L9 - L12 were not covered by tests

import { getUser } from './_auth/user.server'
import HeadingWithAddButton from '~/components/HeadingWithAddButton'
import SegmentedCards from '~/components/SegmentedCards'
import Spinner from '~/components/Spinner'
import TimeAgo from '~/components/TimeAgo'

Check warning on line 17 in app/routes/admin.kafka._index.tsx

View check run for this annotation

Codecov / codecov/patch

app/routes/admin.kafka._index.tsx#L14-L17

Added lines #L14 - L17 were not covered by tests
import type { KafkaACL, UserClientType } from '~/lib/kafka.server'
import type { KafkaACL } from '~/lib/kafka.server'
import {

Check warning on line 19 in app/routes/admin.kafka._index.tsx

View check run for this annotation

Codecov / codecov/patch

app/routes/admin.kafka._index.tsx#L19

Added line #L19 was not covered by tests
adminGroup,
createKafkaACL,
deleteKafkaACL,
getKafkaACLsFromDynamoDB,
getLastSyncDate,
updateDbFromBrokers,
Expand Down Expand Up @@ -63,58 +49,7 @@ export async function action({ request }: ActionFunctionArgs) {

if (intent === 'migrateFromBroker') {
await updateDbFromBrokers(user)

Check warning on line 51 in app/routes/admin.kafka._index.tsx

View check run for this annotation

Codecov / codecov/patch

app/routes/admin.kafka._index.tsx#L51

Added line #L51 was not covered by tests
return null
}

const promises = []

switch (intent) {
case 'delete':
const aclId = getFormDataString(data, 'aclId')
if (!aclId) throw new Response(null, { status: 400 })
promises.push(deleteKafkaACL(user, [aclId]))
break
case 'create':
const resourceName = getFormDataString(data, 'resourceName')
const userClientType = getFormDataString(
data,
'userClientType'
) as UserClientType
const group = getFormDataString(data, 'group')
const permissionTypeString = getFormDataString(data, 'permissionType')
const includePrefixed = getFormDataString(data, 'includePrefixed')
const resourceTypeString = getFormDataString(data, 'resourceType')

if (
!resourceName ||
!userClientType ||
!group ||
!permissionTypeString ||
!resourceTypeString
)
throw new Response(null, { status: 400 })

const permissionType = parseInt(permissionTypeString) // Allow, deny
const resourceType = parseInt(resourceTypeString)

promises.push(
createKafkaACL(
user,
userClientType,
resourceName,
group,
permissionType,
resourceType,
Boolean(includePrefixed)
)
)

break
default:
break
}
await Promise.all(promises)

return null

Check warning on line 53 in app/routes/admin.kafka._index.tsx

View check run for this annotation

Codecov / codecov/patch

app/routes/admin.kafka._index.tsx#L53

Added line #L53 was not covered by tests
}

Expand All @@ -131,7 +66,7 @@ export default function Index() {

return (

Check warning on line 67 in app/routes/admin.kafka._index.tsx

View check run for this annotation

Codecov / codecov/patch

app/routes/admin.kafka._index.tsx#L67

Added line #L67 was not covered by tests
<>
<HeadingWithAddButton headingLevel={1}>Kafka</HeadingWithAddButton>
<h1>Kafka</h1>
<h2>Kafka ACLs</h2>
<p className="usa-paragraph">
Kafka Access Control Lists (ACLs) are a security mechanism used to
Expand Down Expand Up @@ -198,10 +133,24 @@ export default function Index() {
.sort((a, b) => a.localeCompare(b))
.flatMap((key) => (
<span key={key}>

Check warning on line 135 in app/routes/admin.kafka._index.tsx

View check run for this annotation

Codecov / codecov/patch

app/routes/admin.kafka._index.tsx#L133-L135

Added lines #L133 - L135 were not covered by tests
<h3>Resource: {key}</h3>
{aclData[key].map((acl, index) => (
<KafkaAclCard key={`${key}-${index}`} acl={acl} />
))}
<div className="position-sticky top-0 bg-white z-100 padding-y-2">
<h3 className="margin-y-0">Resource: {key}</h3>
</div>
<Table>
<thead>
<tr>
<th>Type</th>
<th>Group</th>
<th>Permission</th>
<th>Operation</th>
</tr>
</thead>
<tbody>
{aclData[key].map((acl, index) => (
<KafkaAclCard key={`${key}-${index}`} acl={acl} />

Check warning on line 150 in app/routes/admin.kafka._index.tsx

View check run for this annotation

Codecov / codecov/patch

app/routes/admin.kafka._index.tsx#L149-L150

Added lines #L149 - L150 were not covered by tests
))}
</tbody>
</Table>
</span>
))}
</SegmentedCards>
Expand All @@ -212,10 +161,6 @@ export default function Index() {
}

function KafkaAclCard({ acl }: { acl: KafkaACL }) {

Check warning on line 163 in app/routes/admin.kafka._index.tsx

View check run for this annotation

Codecov / codecov/patch

app/routes/admin.kafka._index.tsx#L163

Added line #L163 was not covered by tests
const ref = useRef<ModalRef>(null)
const fetcher = useFetcher()
const disabled = fetcher.state !== 'idle'

// TODO: These maps can probably be refactored, since they are
// just inverting the enum from kafka, but importing them
// directly here causes some errors. Same for mapping them to
Expand Down Expand Up @@ -252,64 +197,11 @@ function KafkaAclCard({ acl }: { acl: KafkaACL }) {
}

return (

Check warning on line 199 in app/routes/admin.kafka._index.tsx

View check run for this annotation

Codecov / codecov/patch

app/routes/admin.kafka._index.tsx#L199

Added line #L199 was not covered by tests
<>
<Grid row style={disabled ? { opacity: '50%' } : undefined}>
<div className="tablet:grid-col flex-fill margin-y-1">
<div>
<strong>Type:</strong> {resourceTypeMap[acl.resourceType]}
</div>
<div>
<strong>Group:</strong> {acl.principal}
</div>
<div>
<strong>Permission:</strong> {permissionMap[acl.permissionType]}
</div>
<div>
<strong>Operation:</strong> {operationMap[acl.operation]}
</div>
</div>
<div className="tablet:grid-col flex-auto margin-y-auto">
<ModalToggleButton
opener
disabled={disabled}
modalRef={ref}
type="button"
className="usa-button--secondary"
>
<Icon.Delete
role="presentation"
className="bottom-aligned margin-right-05"
/>
Delete
</ModalToggleButton>
</div>
</Grid>
<Modal
id="modal-delete"
ref={ref}
aria-labelledby="modal-delete-heading"
aria-describedby="modal-delete-description"
renderToPortal={false}
>
<fetcher.Form method="POST" action="/admin/kafka">
<input type="hidden" name="aclId" value={acl.aclId} />
<ModalHeading id="modal-delete-heading">
Delete Kafka ACL
</ModalHeading>
<p id="modal-delete-description">
This will delete the DynamoDB entry and remove the ACL from the
broker. Do you wish to continue?
</p>
<ModalFooter>
<ModalToggleButton modalRef={ref} closer outline>
Cancel
</ModalToggleButton>
<Button data-close-modal type="submit" name="intent" value="delete">
Delete
</Button>
</ModalFooter>
</fetcher.Form>
</Modal>
</>
<tr className="tablet:grid-col flex-fill margin-y-1">
<td>{resourceTypeMap[acl.resourceType]}</td>
<td>{acl.principal}</td>
<td>{permissionMap[acl.permissionType]}</td>
<td>{operationMap[acl.operation]}</td>
</tr>
)
}
Loading

0 comments on commit 1791830

Please sign in to comment.