diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_diagnostics/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_diagnostics/index.tsx index 1bb7e1ee0ad00..437051f03398f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_diagnostics/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_diagnostics/index.tsx @@ -232,32 +232,39 @@ export const AgentDiagnosticsTab: React.FunctionComponent ); }, }, - { - name: i18n.translate('xpack.fleet.requestDiagnostics.tableColumns.actionsLabelText', { - defaultMessage: 'Actions', - }), - width: '70px', - actions: [ - { - type: 'icon', - icon: 'trash', - color: 'danger', - name: i18n.translate('xpack.fleet.requestDiagnostics.tableColumns.deleteButtonText', { - defaultMessage: 'Delete', - }), - available: (item: AgentDiagnostics) => item.status === 'READY', - description: i18n.translate( - 'xpack.fleet.requestDiagnostics.tableColumns.deleteButtonDesc', - { - defaultMessage: 'Delete diagnostics file', - } - ), - onClick: (item: AgentDiagnostics) => { - deleteFile(item.id); + ...((authz.fleet.allAgents + ? [ + { + name: i18n.translate('xpack.fleet.requestDiagnostics.tableColumns.actionsLabelText', { + defaultMessage: 'Actions', + }), + width: '70px', + actions: [ + { + type: 'icon', + icon: 'trash', + color: 'danger', + name: i18n.translate( + 'xpack.fleet.requestDiagnostics.tableColumns.deleteButtonText', + { + defaultMessage: 'Delete', + } + ), + available: (item: AgentDiagnostics) => item.status === 'READY', + description: i18n.translate( + 'xpack.fleet.requestDiagnostics.tableColumns.deleteButtonDesc', + { + defaultMessage: 'Delete diagnostics file', + } + ), + onClick: (item: AgentDiagnostics) => { + deleteFile(item.id); + }, + }, + ], }, - }, - ], - }, + ] + : []) as Array>), ]; const requestDiagnosticsButton = ( diff --git a/x-pack/plugins/fleet/server/routes/agent/index.ts b/x-pack/plugins/fleet/server/routes/agent/index.ts index 640a9f69ed4d6..6c55835a1ed94 100644 --- a/x-pack/plugins/fleet/server/routes/agent/index.ts +++ b/x-pack/plugins/fleet/server/routes/agent/index.ts @@ -338,7 +338,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT .delete({ path: AGENT_API_ROUTES.DELETE_UPLOAD_FILE_PATTERN, fleetAuthz: { - fleet: { readAgents: true }, + fleet: { allAgents: true }, }, }) .addVersion( diff --git a/x-pack/test/fleet_api_integration/apis/agents/privileges.ts b/x-pack/test/fleet_api_integration/apis/agents/privileges.ts index 82999acd9f7c6..b244500a9463f 100644 --- a/x-pack/test/fleet_api_integration/apis/agents/privileges.ts +++ b/x-pack/test/fleet_api_integration/apis/agents/privileges.ts @@ -10,12 +10,18 @@ import { AGENTS_INDEX, PACKAGE_POLICY_SAVED_OBJECT_TYPE, } from '@kbn/fleet-plugin/common'; +import { + FILE_STORAGE_DATA_AGENT_INDEX, + FILE_STORAGE_METADATA_AGENT_INDEX, +} from '@kbn/fleet-plugin/server/constants'; import { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; import { generateAgent } from '../../helpers'; import { runPrivilegeTests } from '../../privileges_helpers'; import { testUsers } from '../test_users'; +const ES_INDEX_OPTIONS = { headers: { 'X-elastic-product-origin': 'fleet' } }; + export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const esArchiver = getService('esArchiver'); @@ -177,6 +183,66 @@ export default function (providerContext: FtrProviderContext) { }); }; + const createFileBeforeEach = async () => { + await es.index( + { + id: 'file1.0', + refresh: 'wait_for', + op_type: 'create', + index: FILE_STORAGE_DATA_AGENT_INDEX, + document: { + bid: 'file1', + '@timestamp': new Date().toISOString(), + last: true, + data: 'test', + }, + }, + ES_INDEX_OPTIONS + ); + + await es.index( + { + index: FILE_STORAGE_METADATA_AGENT_INDEX, + id: 'file1', + refresh: true, + op_type: 'create', + body: { + '@timestamp': new Date().toISOString(), + upload_id: 'file1', + action_id: `fleet_uploads_test-file1-action`, + agent_id: 'agent1', + file: { + ChunkSize: 4194304, + extension: 'zip', + hash: {}, + mime_type: 'application/zip', + mode: '0644', + name: `elastic-agent-diagnostics-file-name.zip`, + path: `/agent/elastic-agent-diagnostics-file-name.zip`, + size: 24917, + Status: 'READY', + type: 'file', + }, + }, + }, + ES_INDEX_OPTIONS + ); + }; + + const deleteFileAfterEach = async () => { + await es.deleteByQuery( + { + index: `${FILE_STORAGE_DATA_AGENT_INDEX},${FILE_STORAGE_METADATA_AGENT_INDEX}`, + refresh: true, + ignore_unavailable: true, + query: { + match_all: {}, + }, + }, + ES_INDEX_OPTIONS + ); + }; + const ROUTES = [ // READ scenarios { @@ -204,6 +270,13 @@ export default function (providerContext: FtrProviderContext) { path: '/api/fleet/agents/agent1/request_diagnostics', scenarios: READ_SCENARIOS, }, + { + method: 'GET', + path: '/api/fleet/agents/files/file1/elastic-agent-diagnostics-file-name.zip', + scenarios: READ_SCENARIOS, + beforeEach: createFileBeforeEach, + afterEach: deleteFileAfterEach, + }, // ALL scenarios { @@ -238,6 +311,13 @@ export default function (providerContext: FtrProviderContext) { beforeEach: updateAgentBeforeEach, afterEach: updateAgentAfterEach, }, + { + method: 'DELETE', + path: '/api/fleet/agents/files/file1', + scenarios: ALL_SCENARIOS, + beforeEach: createFileBeforeEach, + afterEach: deleteFileAfterEach, + }, ]; before(async () => { // Make agent 1 upgradeable