Skip to content

Commit

Permalink
Add a button to view access path audit events in Policy (#48892)
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanclark authored Nov 14, 2024
1 parent 8299ab5 commit 5aa9b4c
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 8 deletions.
21 changes: 13 additions & 8 deletions web/packages/teleport/src/Audit/EventList/EventList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*/

import React, { useState } from 'react';
import { ButtonBorder } from 'design';
import { ButtonBorder, Flex } from 'design';
import Table, { Cell } from 'design/DataTable';
import { dateTimeMatcher } from 'design/utils/match';

Expand All @@ -28,6 +28,8 @@ import EventDialog from '../EventDialog';

import renderTypeCell from './EventTypeCell';

import { ViewInPolicyButton } from './ViewInPolicyButton';

export default function EventList(props: Props) {
const { events = [], fetchMore, fetchStatus, pageSize = 50 } = props;
const [detailsToShow, setDetailsToShow] = useState<Event>();
Expand Down Expand Up @@ -84,13 +86,16 @@ export const renderActionCell = (
onShowDetails: (e: Event) => void
) => (
<Cell align="right">
<ButtonBorder
size="small"
onClick={() => onShowDetails(event)}
width="87px"
>
Details
</ButtonBorder>
<Flex gap={2} justifyContent="flex-end">
<ViewInPolicyButton event={event} />
<ButtonBorder
size="small"
onClick={() => onShowDetails(event)}
width="87px"
>
Details
</ButtonBorder>
</Flex>
</Cell>
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { screen } from '@testing-library/react';

import { MemoryRouter } from 'react-router';

import { render } from 'design/utils/testing';

import { ViewInPolicyButton } from 'teleport/Audit/EventList/ViewInPolicyButton';
import { RawEvents } from 'teleport/services/audit';
import cfg from 'teleport/config';

import makeEvent from '../../services/audit/makeEvent';

test('should not render if the event is not in the list of supported events', () => {
const event: RawEvents['TOK005E'] = {
code: 'TOK005E',
event: 'okta.assignment.cleanup',
name: '3x_0GLrBqnzIjqaXH2ho1G3H07_7NnneUVxPZ_q1Ji4',
source: 'user-assignment-creator',
time: '2024-11-13T13:32:11.397Z',
uid: '4b9dde0c-4f1e-45d0-9a59-d970f7d28f16',
user: 'sasha',
};

render(<ViewInPolicyButton event={makeEvent(event)} />);

expect(screen.queryByRole('link')).not.toBeInTheDocument();
});

test('should render a link for access path changes', () => {
const event: RawEvents['TAG001I'] = {
affected_resource_name: '2k6sycjspmhaib',
affected_resource_source: 'TELEPORT',
affected_resource_kind: 'server',
user: '',
change_id: 'f6be68d1-fa5d-4ff7-ad0b-5c1447e251a0',
code: 'TAG001I',
event: 'access_graph.access_path_changed',
time: '2024-11-13T13:53:29.983Z',
uid: '22c49326-2b72-4503-bd62-dac5ac610be6',
};

render(
<MemoryRouter>
<ViewInPolicyButton event={makeEvent(event)} />
</MemoryRouter>
);

const link = screen.getByRole('link');

expect(link).toBeInTheDocument();

expect(link).toHaveProperty(
'href',
`http://localhost${cfg.getAccessGraphCrownJewelAccessPathUrl(event.change_id)}`
);
});
72 changes: 72 additions & 0 deletions web/packages/teleport/src/Audit/EventList/ViewInPolicyButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import React, { useMemo } from 'react';

import { ButtonBorder } from 'design';
import { NavLink } from 'react-router-dom';

import cfg from 'teleport/config';

import {
Event,
EventCode,
eventCodes,
RawEvents,
} from 'teleport/services/audit';

const VIEW_IN_POLICY_EVENTS: EventCode[] = [
eventCodes.ACCESS_GRAPH_PATH_CHANGED,
];

function getUrlForEvent<C extends EventCode>(event: RawEvents[C]) {
switch (event.code) {
case eventCodes.ACCESS_GRAPH_PATH_CHANGED:
return cfg.getAccessGraphCrownJewelAccessPathUrl(event.change_id);
}

// eslint-disable-next-line no-console
console.warn(
'Unsupported event code for "View in Policy" button',
event.code
);
}

export function ViewInPolicyButton({ event }: { event: Event }) {
const shouldShow = VIEW_IN_POLICY_EVENTS.includes(event.code);

const url = useMemo(
() => shouldShow && getUrlForEvent(event.raw),
[shouldShow, event]
);

if (!shouldShow || !url) {
return null;
}

return (
<ButtonBorder
as={NavLink}
to={url}
size="small"
style={{ whiteSpace: 'nowrap' }}
>
View in Policy
</ButtonBorder>
);
}
10 changes: 10 additions & 0 deletions web/packages/teleport/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,12 @@ const cfg = {
oidcHandler: '/v1/webapi/oidc/*',
samlHandler: '/v1/webapi/saml/*',
githubHandler: '/v1/webapi/github/*',

// Access Graph is part of enterprise, but we need to generate links in the audit log,
// which is in OSS.
accessGraph: {
crownJewelAccessPath: '/web/accessgraph/crownjewels/access/:id',
},
},

api: {
Expand Down Expand Up @@ -1180,6 +1186,10 @@ const cfg = {
return generatePath(cfg.api.notificationStatePath, { clusterId });
},

getAccessGraphCrownJewelAccessPathUrl(id: string) {
return generatePath(cfg.routes.accessGraph.crownJewelAccessPath, { id });
},

init(backendConfig = {}) {
mergeDeep(this, backendConfig);
},
Expand Down

0 comments on commit 5aa9b4c

Please sign in to comment.