[Ingest] Address #59376 feedback (#59961)

* Disable create/destroy CTAs if no write capability

Use `core.application.capabilities.ingestManager.write` to test user permissions

* Add -all & -read tags for HTTP routes

* Update test .expect() to match description

* Add useCapabilities hook. Fix two issues with hiding/disabling CTA.

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
John Schulz 2020-03-12 10:48:14 -04:00 committed by GitHub
parent 27d85cf492
commit e12a8ad8a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 123 additions and 65 deletions

View file

@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
export { useCapabilities } from './use_capabilities';
export { useCore, CoreContext } from './use_core';
export { useConfig, ConfigContext } from './use_config';
export { useSetupDeps, useStartDeps, DepsContext } from './use_deps';

View file

@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { useCore } from './';
export function useCapabilities() {
const core = useCore();
return core.application.capabilities.ingestManager;
}

View file

@ -18,7 +18,7 @@ import {
} from '@elastic/eui';
import { Error } from '../../../components';
import { AGENT_CONFIG_PATH } from '../../../constants';
import { useLink } from '../../../hooks';
import { useCapabilities, useLink } from '../../../hooks';
import { AgentConfig, PackageInfo, GetAgentConfigsResponseItem } from '../../../types';
import { useGetPackageInfoByKey, useGetAgentConfigs, sendGetOneAgentConfig } from '../../../hooks';
@ -30,6 +30,7 @@ export const StepSelectConfig: React.FunctionComponent<{
cancelUrl: string;
onNext: () => void;
}> = ({ pkgkey, updatePackageInfo, agentConfig, updateAgentConfig, cancelUrl, onNext }) => {
const hasWriteCapabilites = useCapabilities().write;
// Selected config state
const [selectedConfigId, setSelectedConfigId] = useState<string | undefined>(
agentConfig ? agentConfig.id : undefined
@ -134,7 +135,12 @@ export const StepSelectConfig: React.FunctionComponent<{
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty iconType="plusInCircle" href={CREATE_NEW_CONFIG_URI} size="s">
<EuiButtonEmpty
isDisabled={!hasWriteCapabilites}
iconType="plusInCircle"
href={CREATE_NEW_CONFIG_URI}
size="s"
>
<FormattedMessage
id="xpack.ingestManager.createDatasource.StepSelectConfig.createNewConfigButtonText"
defaultMessage="Create new configuration"

View file

@ -24,7 +24,7 @@ import {
} from '@elastic/eui';
import { Props as EuiTabProps } from '@elastic/eui/src/components/tabs/tab';
import styled from 'styled-components';
import { useGetOneAgentConfig } from '../../../hooks';
import { useCapabilities, useGetOneAgentConfig } from '../../../hooks';
import { Datasource } from '../../../types';
import { Loading } from '../../../components';
import { WithHeaderLayout } from '../../../layouts';
@ -57,6 +57,7 @@ export const AgentConfigDetailsLayout: React.FunctionComponent = () => {
const {
params: { configId, tabId = '' },
} = useRouteMatch<{ configId: string; tabId?: string }>();
const hasWriteCapabilites = useCapabilities().write;
const agentConfigRequest = useGetOneAgentConfig(configId);
const agentConfig = agentConfigRequest.data ? agentConfigRequest.data.item : null;
const { isLoading, error, sendRequest: refreshAgentConfig } = agentConfigRequest;
@ -318,7 +319,12 @@ export const AgentConfigDetailsLayout: React.FunctionComponent = () => {
</h2>
}
actions={
<EuiButton fill iconType="plusInCircle" href={URI.ADD_DATASOURCE}>
<EuiButton
isDisabled={!hasWriteCapabilites}
fill
iconType="plusInCircle"
href={URI.ADD_DATASOURCE}
>
<FormattedMessage
id="xpack.ingestManager.configDetails.addDatasourceButtonText"
defaultMessage="Create data source"
@ -330,7 +336,11 @@ export const AgentConfigDetailsLayout: React.FunctionComponent = () => {
}
search={{
toolsRight: [
<EuiButton iconType="plusInCircle" href={URI.ADD_DATASOURCE}>
<EuiButton
isDisabled={!hasWriteCapabilites}
iconType="plusInCircle"
href={URI.ADD_DATASOURCE}
>
<FormattedMessage
id="xpack.ingestManager.configDetails.addDatasourceButtonText"
defaultMessage="Create data source"

View file

@ -27,7 +27,7 @@ interface Props {
}
export const CreateAgentConfigFlyout: React.FunctionComponent<Props> = ({ onClose }) => {
const { notifications } = useCore();
const { application, notifications } = useCore();
const [agentConfig, setAgentConfig] = useState<NewAgentConfig>({
name: '',
@ -93,7 +93,11 @@ export const CreateAgentConfigFlyout: React.FunctionComponent<Props> = ({ onClos
<EuiButton
fill
isLoading={isLoading}
disabled={isLoading || Object.keys(validation).length > 0}
isDisabled={
!application.capabilities.ingestManager.write ||
isLoading ||
Object.keys(validation).length > 0
}
onClick={async () => {
setIsLoading(true);
try {

View file

@ -33,6 +33,7 @@ import {
} from '../../../constants';
import { WithHeaderLayout } from '../../../layouts';
import {
useCapabilities,
useGetAgentConfigs,
usePagination,
useLink,
@ -87,6 +88,7 @@ const DangerEuiContextMenuItem = styled(EuiContextMenuItem)`
const RowActions = React.memo<{ config: AgentConfig; onDelete: () => void }>(
({ config, onDelete }) => {
const hasWriteCapabilites = useCapabilities().write;
const DETAILS_URI = useLink(`${AGENT_CONFIG_DETAILS_PATH}${config.id}`);
const ADD_DATASOURCE_URI = `${DETAILS_URI}/add-datasource`;
@ -120,6 +122,7 @@ const RowActions = React.memo<{ config: AgentConfig; onDelete: () => void }>(
</EuiContextMenuItem>,
<EuiContextMenuItem
disabled={!hasWriteCapabilites}
icon="plusInCircle"
href={ADD_DATASOURCE_URI}
key="createDataSource"
@ -130,7 +133,7 @@ const RowActions = React.memo<{ config: AgentConfig; onDelete: () => void }>(
/>
</EuiContextMenuItem>,
<EuiContextMenuItem icon="copy" disabled={true} key="copyConfig">
<EuiContextMenuItem disabled={true} icon="copy" key="copyConfig">
<FormattedMessage
id="xpack.ingestManager.agentConfigList.copyConfigActionText"
defaultMessage="Copy configuration"
@ -162,6 +165,7 @@ const RowActions = React.memo<{ config: AgentConfig; onDelete: () => void }>(
export const AgentConfigListPage: React.FunctionComponent<{}> = () => {
// Config information
const hasWriteCapabilites = useCapabilities().write;
const {
fleet: { enabled: isFleetEnabled },
} = useConfig();
@ -309,6 +313,7 @@ export const AgentConfigListPage: React.FunctionComponent<{}> = () => {
<EuiButton
fill
iconType="plusInCircle"
isDisabled={!hasWriteCapabilites}
onClick={() => setIsCreateAgentConfigFlyoutOpen(true)}
>
<FormattedMessage
@ -317,7 +322,7 @@ export const AgentConfigListPage: React.FunctionComponent<{}> = () => {
/>
</EuiButton>
),
[setIsCreateAgentConfigFlyoutOpen]
[hasWriteCapabilites, setIsCreateAgentConfigFlyoutOpen]
);
const emptyPrompt = useMemo(
@ -331,10 +336,10 @@ export const AgentConfigListPage: React.FunctionComponent<{}> = () => {
/>
</h2>
}
actions={createAgentConfigButton}
actions={hasWriteCapabilites ?? createAgentConfigButton}
/>
),
[createAgentConfigButton]
[hasWriteCapabilites, createAgentConfigButton]
);
return (

View file

@ -9,7 +9,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
import { EuiFlexGroup, EuiFlexItem, EuiPage, EuiTitle, IconType, EuiButton } from '@elastic/eui';
import { PackageInfo } from '../../../../types';
import { EPM_PATH } from '../../../../constants';
import { useLink } from '../../../../hooks';
import { useCapabilities, useLink } from '../../../../hooks';
import { IconPanel } from '../../components/icon_panel';
import { NavButtonBack } from '../../components/nav_button_back';
import { Version } from '../../components/version';
@ -34,6 +34,7 @@ type HeaderProps = PackageInfo & { iconType?: IconType };
export function Header(props: HeaderProps) {
const { iconType, name, title, version } = props;
const hasWriteCapabilites = useCapabilities().write;
const { toListView } = useLinks();
// useBreadcrumbs([{ text: PLUGIN.TITLE, href: toListView() }, { text: title }]);
@ -61,7 +62,11 @@ export function Header(props: HeaderProps) {
<RightColumn>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButton iconType="plusInCircle" href={ADD_DATASOURCE_URI}>
<EuiButton
isDisabled={!hasWriteCapabilites}
iconType="plusInCircle"
href={ADD_DATASOURCE_URI}
>
<FormattedMessage
id="xpack.ingestManager.epm.addDatasourceButtonText"
defaultMessage="Create data source"

View file

@ -6,6 +6,7 @@
import { EuiButton } from '@elastic/eui';
import React, { Fragment, useCallback, useMemo, useState } from 'react';
import { PackageInfo, InstallStatus } from '../../../../types';
import { useCapabilities } from '../../../../hooks';
import { useDeletePackage, useGetPackageInstallStatus, useInstallPackage } from '../../hooks';
import { ConfirmPackageDelete } from './confirm_package_delete';
import { ConfirmPackageInstall } from './confirm_package_install';
@ -16,6 +17,7 @@ interface InstallationButtonProps {
export function InstallationButton(props: InstallationButtonProps) {
const { assets, name, title, version } = props.package;
const hasWriteCapabilites = useCapabilities().write;
const installPackage = useInstallPackage();
const deletePackage = useDeletePackage();
const getPackageInstallStatus = useGetPackageInstallStatus();
@ -86,10 +88,10 @@ export function InstallationButton(props: InstallationButtonProps) {
/>
);
return (
return hasWriteCapabilites ? (
<Fragment>
{isInstalled ? installedButton : installButton}
{isModalVisible && (isInstalled ? deletionModal : installationModal)}
</Fragment>
);
) : null;
}

View file

@ -24,7 +24,7 @@ import { useAgentRefresh } from '../hooks';
import { AgentMetadataFlyout } from './metadata_flyout';
import { Agent } from '../../../../types';
import { AgentHealth } from '../../components/agent_health';
import { useGetOneAgentConfig } from '../../../../hooks';
import { useCapabilities, useGetOneAgentConfig } from '../../../../hooks';
import { Loading } from '../../../../components';
import { ConnectedLink } from '../../components';
import { AgentUnenrollProvider } from '../../components/agent_unenroll_provider';
@ -53,6 +53,7 @@ interface Props {
agent: Agent;
}
export const AgentDetailSection: React.FunctionComponent<Props> = ({ agent }) => {
const hasWriteCapabilites = useCapabilities().write;
const metadataFlyout = useFlyout();
const refreshAgent = useAgentRefresh();
@ -125,7 +126,7 @@ export const AgentDetailSection: React.FunctionComponent<Props> = ({ agent }) =>
<AgentUnenrollProvider>
{unenrollAgentsPrompt => (
<EuiButton
disabled={!agent.active}
disabled={!hasWriteCapabilites || !agent.active}
onClick={() => {
unenrollAgentsPrompt([agent.id], 1, refreshAgent);
}}

View file

@ -12,6 +12,7 @@ import { useEnrollmentApiKeys, useEnrollmentApiKey } from './hooks';
import { ConfirmDeleteModal } from './confirm_delete_modal';
import { CreateApiKeyForm } from './create_api_key_form';
import { EnrollmentAPIKey } from '../../../../../types';
import { useCapabilities } from '../../../../../hooks';
import { enrollmentAPIKeyRouteService } from '../../../../../services';
export { useEnrollmentApiKeys, useEnrollmentApiKey } from './hooks';
@ -98,13 +99,14 @@ export const EnrollmentApiKeysTable: React.FunctionComponent<{
export const CreateApiKeyButton: React.FunctionComponent<{ onChange: () => void }> = ({
onChange,
}) => {
const hasWriteCapabilites = useCapabilities().write;
const [isOpen, setIsOpen] = React.useState(false);
return (
<EuiPopover
ownFocus
button={
<EuiLink onClick={() => setIsOpen(true)} color="primary">
<EuiLink disabled={!hasWriteCapabilites} onClick={() => setIsOpen(true)} color="primary">
<FormattedMessage
id="xpack.ingestManager.enrollmentApiKeyList.createNewButton"
defaultMessage="Create a new key"

View file

@ -34,7 +34,7 @@ import { WithHeaderLayout } from '../../../layouts';
import { Agent } from '../../../types';
import {
usePagination,
useCore,
useCapabilities,
useGetAgentConfigs,
useGetAgents,
useUrlParams,
@ -85,6 +85,7 @@ const statusFilters = [
] as Array<{ label: string; status: string }>;
const RowActions = React.memo<{ agent: Agent; refresh: () => void }>(({ agent, refresh }) => {
const hasWriteCapabilites = useCapabilities().write;
const DETAILS_URI = useLink(FLEET_AGENT_DETAIL_PATH);
const [isOpen, setIsOpen] = useState(false);
const handleCloseMenu = useCallback(() => setIsOpen(false), [setIsOpen]);
@ -118,6 +119,7 @@ const RowActions = React.memo<{ agent: Agent; refresh: () => void }>(({ agent, r
<AgentUnenrollProvider>
{unenrollAgentsPrompt => (
<EuiContextMenuItem
disabled={!hasWriteCapabilites}
icon="cross"
onClick={() => {
unenrollAgentsPrompt([agent.id], 1, () => {
@ -140,7 +142,7 @@ const RowActions = React.memo<{ agent: Agent; refresh: () => void }>(({ agent, r
export const AgentListPage: React.FunctionComponent<{}> = () => {
const defaultKuery: string = (useUrlParams().urlParams.kuery as string) || '';
const core = useCore();
const hasWriteCapabilites = useCapabilities().write;
// Agent data states
const [showInactive, setShowInactive] = useState<boolean>(false);
@ -363,7 +365,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {
</h2>
}
actions={
core.application.capabilities.ingestManager.write ? (
hasWriteCapabilites ? (
<EuiButton fill iconType="plusInCircle" onClick={() => setIsEnrollmentFlyoutOpen(true)}>
<FormattedMessage
id="xpack.ingestManager.agentList.addButton"
@ -432,7 +434,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {
})}
/>
</EuiFlexItem>
{core.application.capabilities.ingestManager.write && (
{hasWriteCapabilites && (
<>
<EuiFlexItem grow={false}>
<Divider />

View file

@ -18,6 +18,10 @@ import { SecurityPluginSetup } from '../../security/server';
import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server';
import {
PLUGIN_ID,
OUTPUT_SAVED_OBJECT_TYPE,
AGENT_CONFIG_SAVED_OBJECT_TYPE,
DATASOURCE_SAVED_OBJECT_TYPE,
PACKAGES_SAVED_OBJECT_TYPE,
AGENT_SAVED_OBJECT_TYPE,
AGENT_EVENT_SAVED_OBJECT_TYPE,
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
@ -49,6 +53,16 @@ export interface IngestManagerAppContext {
savedObjects: SavedObjectsServiceStart;
}
const allSavedObjectTypes = [
OUTPUT_SAVED_OBJECT_TYPE,
AGENT_CONFIG_SAVED_OBJECT_TYPE,
DATASOURCE_SAVED_OBJECT_TYPE,
PACKAGES_SAVED_OBJECT_TYPE,
AGENT_SAVED_OBJECT_TYPE,
AGENT_EVENT_SAVED_OBJECT_TYPE,
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
];
export class IngestManagerPlugin implements Plugin {
private config$: Observable<IngestManagerConfigType>;
private security: SecurityPluginSetup | undefined;
@ -73,26 +87,18 @@ export class IngestManagerPlugin implements Plugin {
app: [PLUGIN_ID, 'kibana'],
privileges: {
all: {
api: [PLUGIN_ID],
api: [`${PLUGIN_ID}-read`, `${PLUGIN_ID}-all`],
savedObject: {
all: [
AGENT_SAVED_OBJECT_TYPE,
AGENT_EVENT_SAVED_OBJECT_TYPE,
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
],
all: allSavedObjectTypes,
read: [],
},
ui: ['show', 'read', 'write'],
},
read: {
api: [PLUGIN_ID],
api: [`${PLUGIN_ID}-read`],
savedObject: {
all: [],
read: [
AGENT_SAVED_OBJECT_TYPE,
AGENT_EVENT_SAVED_OBJECT_TYPE,
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
],
read: allSavedObjectTypes,
},
ui: ['show', 'read'],
},

View file

@ -42,7 +42,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: AGENT_API_ROUTES.INFO_PATTERN,
validate: GetOneAgentRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getAgentHandler
);
@ -51,7 +51,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: AGENT_API_ROUTES.UPDATE_PATTERN,
validate: UpdateAgentRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
updateAgentHandler
);
@ -60,7 +60,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: AGENT_API_ROUTES.DELETE_PATTERN,
validate: DeleteAgentRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
deleteAgentHandler
);
@ -69,7 +69,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: AGENT_API_ROUTES.LIST_PATTERN,
validate: GetAgentsRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getAgentsHandler
);
@ -108,7 +108,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: AGENT_API_ROUTES.UNENROLL_PATTERN,
validate: PostAgentUnenrollRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
postAgentsUnenrollHandler
);
@ -118,7 +118,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: AGENT_API_ROUTES.EVENTS_PATTERN,
validate: GetOneAgentEventsRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getAgentEventsHandler
);
@ -128,7 +128,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: AGENT_API_ROUTES.STATUS_PATTERN,
validate: GetAgentStatusRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getAgentStatusForConfigHandler
);

View file

@ -28,7 +28,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: AGENT_CONFIG_API_ROUTES.LIST_PATTERN,
validate: GetAgentConfigsRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getAgentConfigsHandler
);
@ -38,7 +38,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: AGENT_CONFIG_API_ROUTES.INFO_PATTERN,
validate: GetOneAgentConfigRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getOneAgentConfigHandler
);
@ -48,7 +48,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: AGENT_CONFIG_API_ROUTES.CREATE_PATTERN,
validate: CreateAgentConfigRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
createAgentConfigHandler
);
@ -58,7 +58,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: AGENT_CONFIG_API_ROUTES.UPDATE_PATTERN,
validate: UpdateAgentConfigRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
updateAgentConfigHandler
);
@ -68,7 +68,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: AGENT_CONFIG_API_ROUTES.DELETE_PATTERN,
validate: DeleteAgentConfigsRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
deleteAgentConfigsHandler
);
@ -78,7 +78,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: AGENT_CONFIG_API_ROUTES.FULL_INFO_PATTERN,
validate: GetFullAgentConfigRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getFullAgentConfig
);

View file

@ -24,7 +24,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: DATASOURCE_API_ROUTES.LIST_PATTERN,
validate: GetDatasourcesRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getDatasourcesHandler
);
@ -34,7 +34,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: DATASOURCE_API_ROUTES.INFO_PATTERN,
validate: GetOneDatasourceRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getOneDatasourceHandler
);
@ -44,7 +44,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: DATASOURCE_API_ROUTES.CREATE_PATTERN,
validate: CreateDatasourceRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
createDatasourceHandler
);
@ -54,7 +54,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: DATASOURCE_API_ROUTES.UPDATE_PATTERN,
validate: UpdateDatasourceRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
updateDatasourceHandler
);

View file

@ -23,7 +23,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: ENROLLMENT_API_KEY_ROUTES.INFO_PATTERN,
validate: GetOneEnrollmentAPIKeyRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getOneEnrollmentApiKeyHandler
);
@ -32,7 +32,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: ENROLLMENT_API_KEY_ROUTES.DELETE_PATTERN,
validate: DeleteEnrollmentAPIKeyRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
deleteEnrollmentApiKeyHandler
);
@ -41,7 +41,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: ENROLLMENT_API_KEY_ROUTES.LIST_PATTERN,
validate: GetEnrollmentAPIKeysRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getEnrollmentApiKeysHandler
);
@ -50,7 +50,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: ENROLLMENT_API_KEY_ROUTES.CREATE_PATTERN,
validate: PostEnrollmentAPIKeyRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
postEnrollmentApiKeyHandler
);

View file

@ -26,7 +26,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: EPM_API_ROUTES.CATEGORIES_PATTERN,
validate: false,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getCategoriesHandler
);
@ -35,7 +35,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: EPM_API_ROUTES.LIST_PATTERN,
validate: GetPackagesRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getListHandler
);
@ -44,7 +44,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: EPM_API_ROUTES.FILEPATH_PATTERN,
validate: GetFileRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getFileHandler
);
@ -53,7 +53,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: EPM_API_ROUTES.INFO_PATTERN,
validate: GetInfoRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getInfoHandler
);
@ -62,7 +62,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: EPM_API_ROUTES.INSTALL_PATTERN,
validate: InstallPackageRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
installPackageHandler
);
@ -71,7 +71,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: EPM_API_ROUTES.DELETE_PATTERN,
validate: DeletePackageRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
deletePackageHandler
);

View file

@ -18,7 +18,9 @@ export const registerRoutes = (router: IRouter) => {
{
path: SETUP_API_ROUTE,
validate: false,
options: { tags: [`access:${PLUGIN_ID}`] },
// if this route is set to `-all`, a read-only user get a 404 for this route
// and will see `Unable to initialize Ingest Manager` in the UI
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
ingestManagerSetupHandler
);
@ -27,7 +29,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: FLEET_SETUP_API_ROUTES.INFO_PATTERN,
validate: GetFleetSetupRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-read`] },
},
getFleetSetupHandler
);
@ -37,7 +39,7 @@ export const registerRoutes = (router: IRouter) => {
{
path: FLEET_SETUP_API_ROUTES.CREATE_PATTERN,
validate: CreateFleetSetupRequestSchema,
options: { tags: [`access:${PLUGIN_ID}`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
createFleetSetupHandler
);

View file

@ -65,7 +65,7 @@ export default function({ getService }: FtrProviderContext) {
.delete(`/api/ingest_manager/fleet/agents/agent1`)
.auth(users.fleet_user.username, users.fleet_user.password)
.set('kbn-xsrf', 'xx')
.expect(403);
.expect(404);
expect(apiResponse).not.to.eql({
success: true,