From 11351b76e5ec67cd309dbd2c5ee0b0b55f1202c6 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 10 Oct 2024 14:40:45 -0700 Subject: [PATCH 01/13] fix "management: deletion" test by loading necessary archives --- .../common/reporting/management.ts | 88 ++++++++++--------- .../shared/services/svl_reporting.ts | 19 ++-- 2 files changed, 59 insertions(+), 48 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts index 62e9f4eaf8acd..ca2e33895e48a 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts @@ -16,7 +16,8 @@ const API_HEADER: [string, string] = ['kbn-xsrf', 'reporting']; const INTERNAL_HEADER: [string, string] = [X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'Kibana']; export default ({ getService }: FtrProviderContext) => { - const log = getService('log'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const reportingAPI = getService('svlReportingApi'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const svlCommonApi = getService('svlCommonApi'); @@ -24,55 +25,60 @@ export default ({ getService }: FtrProviderContext) => { let adminUser: RoleCredentials; let internalReqHeader: InternalRequestHeader; - describe('Reporting Management', function () { + const archives: Record = { + ecommerce: { + data: 'x-pack/test/functional/es_archives/reporting/ecommerce', + savedObjects: 'x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce', + }, + }; + + describe('Reporting Management: Deletion', function () { + let reportJob: ReportApiJSON; + let path: string; + before(async () => { adminUser = await svlUserManager.createM2mApiKeyWithRoleScope('admin'); internalReqHeader = svlCommonApi.getInternalRequestHeader(); - }); - after(async () => { - await svlUserManager.invalidateM2mApiKeyWithRoleScope(adminUser); - }); - describe('Deletion', () => { - let reportJob: ReportApiJSON; + await esArchiver.load(archives.ecommerce.data); + await kibanaServer.importExport.load(archives.ecommerce.savedObjects); - const createJob = async (roleAuthc: RoleCredentials): Promise => { - log.info(`request report job with ApiKey ${adminUser.apiKey.name}`); - const { job } = await reportingAPI.createReportJobInternal( - 'csv_searchsource', - { - browserTimezone: 'UTC', - objectType: 'search', - searchSource: { - index: '5193f870-d861-11e9-a311-0fa548c5f953', - query: { language: 'kuery', query: '' }, - version: true, - }, - title: 'Ecommerce Data', - version: '8.15.0', + const result = await reportingAPI.createReportJobInternal( + 'csv_searchsource', + { + browserTimezone: 'UTC', + objectType: 'search', + searchSource: { + index: '5193f870-d861-11e9-a311-0fa548c5f953', + query: { language: 'kuery', query: '' }, + version: true, }, - roleAuthc, - internalReqHeader - ); - log.info(`created report job ${job.id} with ApiKey ${adminUser.apiKey.name}`); - return job; - }; + title: 'Ecommerce Data', + version: '8.15.0', + }, + adminUser, + internalReqHeader + ); - before(async () => { - reportJob = await createJob(adminUser); - }); + path = result.path; + reportJob = result.job; + + await reportingAPI.waitForJobToFinish(path, adminUser, internalReqHeader); + }); + + after(async () => { + await svlUserManager.invalidateM2mApiKeyWithRoleScope(adminUser); + }); - it(`user can delete a report they've created`, async () => { - // for this test, we don't need to wait for the job to finish or verify the result - const response = await supertestWithoutAuth - .delete(`${INTERNAL_ROUTES.JOBS.DELETE_PREFIX}/${reportJob.id}`) - .set(...API_HEADER) - .set(...INTERNAL_HEADER) - .set(adminUser.apiKeyHeader); + it(`user can delete a report they've created`, async () => { + const response = await supertestWithoutAuth + .delete(`${INTERNAL_ROUTES.JOBS.DELETE_PREFIX}/${reportJob.id}`) + .set(...API_HEADER) + .set(...INTERNAL_HEADER) + .set(adminUser.apiKeyHeader); - expect(response.status).to.be(200); - expect(response.body).to.eql({ deleted: true }); - }); + expect(response.status).to.be(200); + expect(response.body).to.eql({ deleted: true }); }); }); }; diff --git a/x-pack/test_serverless/shared/services/svl_reporting.ts b/x-pack/test_serverless/shared/services/svl_reporting.ts index f056543e72e23..5ab4c4804e5fa 100644 --- a/x-pack/test_serverless/shared/services/svl_reporting.ts +++ b/x-pack/test_serverless/shared/services/svl_reporting.ts @@ -5,7 +5,6 @@ * 2.0. */ -import expect from '@kbn/expect'; import { INTERNAL_ROUTES } from '@kbn/reporting-common'; import type { ReportingJobResponse } from '@kbn/reporting-plugin/server/types'; import rison from '@kbn/rison'; @@ -37,22 +36,27 @@ export function SvlReportingServiceProvider({ getService }: FtrProviderContext) const requestPath = `${INTERNAL_ROUTES.GENERATE_PREFIX}/${jobType}`; log.debug(`POST request to ${requestPath}`); - const { status, body } = await supertestWithoutAuth + const { body }: { status: number; body: ReportingJobResponse } = await supertestWithoutAuth .post(requestPath) .set(internalReqHeader) .set(roleAuthc.apiKeyHeader) - .send({ jobParams: rison.encode(job) }); + .send({ jobParams: rison.encode(job) }) + .expect(200); - expect(status).to.be(200); + log.info( + `ReportingAPI.createReportJobInternal created report job` + + ` ${body.job.id} with ApiKey ${roleAuthc.apiKey.name}` + ); return { - job: (body as ReportingJobResponse).job, - path: (body as ReportingJobResponse).path, + job: body.job, + path: body.path, }; }, /* - * This function is only used in the API tests + * If a test requests a report, it must wait for the job to finish before deleting the report. + * Otherwise, report task success metrics will be affected. */ async waitForJobToFinish( downloadReportPath: string, @@ -60,6 +64,7 @@ export function SvlReportingServiceProvider({ getService }: FtrProviderContext) internalReqHeader: InternalRequestHeader, options?: { timeout?: number } ) { + log.debug(`ReportingAPI.waitForJobToFinish ${downloadReportPath}`); await retry.waitForWithTimeout( `job ${downloadReportPath} finished`, options?.timeout ?? config.get('timeouts.kibanaReportCompletion'), From a3ae98851c07452a0b3274d17bba35be307744a1 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Fri, 18 Oct 2024 09:51:23 +0200 Subject: [PATCH 02/13] use samlAuth service and cookieHeader for internal API --- .../test_suites/common/reporting/management.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts index ca2e33895e48a..fc8080c49aed6 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts @@ -20,8 +20,7 @@ export default ({ getService }: FtrProviderContext) => { const kibanaServer = getService('kibanaServer'); const reportingAPI = getService('svlReportingApi'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - const svlCommonApi = getService('svlCommonApi'); - const svlUserManager = getService('svlUserManager'); + const samlAuth = getService('samlAuth'); let adminUser: RoleCredentials; let internalReqHeader: InternalRequestHeader; @@ -37,8 +36,8 @@ export default ({ getService }: FtrProviderContext) => { let path: string; before(async () => { - adminUser = await svlUserManager.createM2mApiKeyWithRoleScope('admin'); - internalReqHeader = svlCommonApi.getInternalRequestHeader(); + adminUser = await samlAuth.createM2mApiKeyWithRoleScope('admin'); + internalReqHeader = samlAuth.getInternalRequestHeader(); await esArchiver.load(archives.ecommerce.data); await kibanaServer.importExport.load(archives.ecommerce.savedObjects); @@ -67,15 +66,16 @@ export default ({ getService }: FtrProviderContext) => { }); after(async () => { - await svlUserManager.invalidateM2mApiKeyWithRoleScope(adminUser); + await samlAuth.invalidateM2mApiKeyWithRoleScope(adminUser); }); it(`user can delete a report they've created`, async () => { + const cookieHeader = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); const response = await supertestWithoutAuth .delete(`${INTERNAL_ROUTES.JOBS.DELETE_PREFIX}/${reportJob.id}`) .set(...API_HEADER) .set(...INTERNAL_HEADER) - .set(adminUser.apiKeyHeader); + .set(cookieHeader); expect(response.status).to.be(200); expect(response.body).to.eql({ deleted: true }); From dce635b76541b71b60579fe334d5a975ba4df766 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 21 Oct 2024 14:28:26 -0700 Subject: [PATCH 03/13] unload es archive and delete saved objects after the test run --- .../api_integration/test_suites/common/reporting/management.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts index fc8080c49aed6..c505835a32d59 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts @@ -67,6 +67,9 @@ export default ({ getService }: FtrProviderContext) => { after(async () => { await samlAuth.invalidateM2mApiKeyWithRoleScope(adminUser); + + await esArchiver.unload(archives.ecommerce.data); + await kibanaServer.importExport.unload(archives.ecommerce.savedObjects); }); it(`user can delete a report they've created`, async () => { From 11a32e1adae7e9065f121590f833e6521ecce5c4 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 21 Oct 2024 14:38:46 -0700 Subject: [PATCH 04/13] Use cookie credentials for internal requests --- .../common/reporting/management.ts | 16 ++++++------- .../shared/services/svl_reporting.ts | 23 ++++++++----------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts index c505835a32d59..917af4d2c75c6 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts @@ -9,8 +9,9 @@ import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common/src/con import expect from '@kbn/expect'; import { INTERNAL_ROUTES } from '@kbn/reporting-common'; import { ReportApiJSON } from '@kbn/reporting-common/types'; +import { CookieCredentials } from '@kbn/ftr-common-functional-services'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { InternalRequestHeader, RoleCredentials } from '../../../../shared/services'; +import { InternalRequestHeader } from '../../../../shared/services'; const API_HEADER: [string, string] = ['kbn-xsrf', 'reporting']; const INTERNAL_HEADER: [string, string] = [X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'Kibana']; @@ -21,7 +22,7 @@ export default ({ getService }: FtrProviderContext) => { const reportingAPI = getService('svlReportingApi'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const samlAuth = getService('samlAuth'); - let adminUser: RoleCredentials; + let cookieCredentials: CookieCredentials; let internalReqHeader: InternalRequestHeader; const archives: Record = { @@ -36,7 +37,7 @@ export default ({ getService }: FtrProviderContext) => { let path: string; before(async () => { - adminUser = await samlAuth.createM2mApiKeyWithRoleScope('admin'); + cookieCredentials = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); internalReqHeader = samlAuth.getInternalRequestHeader(); await esArchiver.load(archives.ecommerce.data); @@ -55,30 +56,27 @@ export default ({ getService }: FtrProviderContext) => { title: 'Ecommerce Data', version: '8.15.0', }, - adminUser, + cookieCredentials, internalReqHeader ); path = result.path; reportJob = result.job; - await reportingAPI.waitForJobToFinish(path, adminUser, internalReqHeader); + await reportingAPI.waitForJobToFinish(path, cookieCredentials, internalReqHeader); }); after(async () => { - await samlAuth.invalidateM2mApiKeyWithRoleScope(adminUser); - await esArchiver.unload(archives.ecommerce.data); await kibanaServer.importExport.unload(archives.ecommerce.savedObjects); }); it(`user can delete a report they've created`, async () => { - const cookieHeader = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); const response = await supertestWithoutAuth .delete(`${INTERNAL_ROUTES.JOBS.DELETE_PREFIX}/${reportJob.id}`) .set(...API_HEADER) .set(...INTERNAL_HEADER) - .set(cookieHeader); + .set(cookieCredentials); expect(response.status).to.be(200); expect(response.body).to.eql({ deleted: true }); diff --git a/x-pack/test_serverless/shared/services/svl_reporting.ts b/x-pack/test_serverless/shared/services/svl_reporting.ts index 5ab4c4804e5fa..f5d5a15822bb9 100644 --- a/x-pack/test_serverless/shared/services/svl_reporting.ts +++ b/x-pack/test_serverless/shared/services/svl_reporting.ts @@ -8,8 +8,8 @@ import { INTERNAL_ROUTES } from '@kbn/reporting-common'; import type { ReportingJobResponse } from '@kbn/reporting-plugin/server/types'; import rison from '@kbn/rison'; +import { CookieCredentials } from '@kbn/ftr-common-functional-services'; import { FtrProviderContext } from '../../functional/ftr_provider_context'; -import { RoleCredentials } from '.'; import { InternalRequestHeader } from '.'; const API_HEADER: [string, string] = ['kbn-xsrf', 'reporting']; @@ -30,7 +30,7 @@ export function SvlReportingServiceProvider({ getService }: FtrProviderContext) async createReportJobInternal( jobType: string, job: object, - roleAuthc: RoleCredentials, + cookieCredentials: CookieCredentials, internalReqHeader: InternalRequestHeader ) { const requestPath = `${INTERNAL_ROUTES.GENERATE_PREFIX}/${jobType}`; @@ -39,14 +39,11 @@ export function SvlReportingServiceProvider({ getService }: FtrProviderContext) const { body }: { status: number; body: ReportingJobResponse } = await supertestWithoutAuth .post(requestPath) .set(internalReqHeader) - .set(roleAuthc.apiKeyHeader) + .set(cookieCredentials) .send({ jobParams: rison.encode(job) }) .expect(200); - log.info( - `ReportingAPI.createReportJobInternal created report job` + - ` ${body.job.id} with ApiKey ${roleAuthc.apiKey.name}` - ); + log.info(`ReportingAPI.createReportJobInternal created report job` + ` ${body.job.id}`); return { job: body.job, @@ -60,7 +57,7 @@ export function SvlReportingServiceProvider({ getService }: FtrProviderContext) */ async waitForJobToFinish( downloadReportPath: string, - roleAuthc: RoleCredentials, + cookieCredentials: CookieCredentials, internalReqHeader: InternalRequestHeader, options?: { timeout?: number } ) { @@ -74,7 +71,7 @@ export function SvlReportingServiceProvider({ getService }: FtrProviderContext) .responseType('blob') .set(...API_HEADER) .set(internalReqHeader) - .set(roleAuthc.apiKeyHeader); + .set(cookieCredentials); if (response.status === 500) { throw new Error(`Report at path ${downloadReportPath} has failed`); @@ -106,13 +103,13 @@ export function SvlReportingServiceProvider({ getService }: FtrProviderContext) */ async getCompletedJobOutput( downloadReportPath: string, - roleAuthc: RoleCredentials, + cookieCredentials: CookieCredentials, internalReqHeader: InternalRequestHeader ) { const response = await supertestWithoutAuth .get(`${downloadReportPath}?elasticInternalOrigin=true`) .set(internalReqHeader) - .set(roleAuthc.apiKeyHeader); + .set(cookieCredentials); return response.text as unknown; }, @@ -121,14 +118,14 @@ export function SvlReportingServiceProvider({ getService }: FtrProviderContext) */ async deleteReport( reportId: string, - roleAuthc: RoleCredentials, + cookieCredentials: CookieCredentials, internalReqHeader: InternalRequestHeader ) { log.debug(`ReportingAPI.deleteReport ${INTERNAL_ROUTES.JOBS.DELETE_PREFIX}/${reportId}`); const response = await supertestWithoutAuth .delete(INTERNAL_ROUTES.JOBS.DELETE_PREFIX + `/${reportId}`) .set(internalReqHeader) - .set(roleAuthc.apiKeyHeader) + .set(cookieCredentials) .set('kbn-xsrf', 'xxx') .expect(200); return response.text as unknown; From a5fb38a44c3f135d6d72c7c30110a4396176eb46 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 21 Oct 2024 14:51:56 -0700 Subject: [PATCH 05/13] Use cookie credentials instead of role credentials --- .../common/reporting/csv_v2_esql.ts | 19 +++-- .../common/reporting/datastream.ts | 15 ++-- .../common/reporting/generate_csv_discover.ts | 84 +++++++++---------- .../common/reporting/management.ts | 3 +- .../common/reporting/management.ts | 14 ++-- .../shared/services/svl_reporting.ts | 2 +- 6 files changed, 66 insertions(+), 71 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/csv_v2_esql.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/csv_v2_esql.ts index e74eb14ac31d7..d271b530247f4 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/csv_v2_esql.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/csv_v2_esql.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import request from 'supertest'; import { DISCOVER_APP_LOCATOR } from '@kbn/discover-plugin/common'; -import { InternalRequestHeader, RoleCredentials } from '@kbn/ftr-common-functional-services'; +import { CookieCredentials, InternalRequestHeader } from '@kbn/ftr-common-functional-services'; import type { ReportApiJSON } from '@kbn/reporting-common/types'; import type { JobParamsCsvFromSavedObject } from '@kbn/reporting-export-types-csv-common'; import { FtrProviderContext } from '../../../ftr_provider_context'; @@ -21,8 +21,8 @@ export default ({ getService }: FtrProviderContext) => { const log = getService('log'); const reportingAPI = getService('svlReportingApi'); const svlCommonApi = getService('svlCommonApi'); - const svlUserManager = getService('svlUserManager'); - let roleAuthc: RoleCredentials; + const samlAuth = getService('samlAuth'); + let cookieCredentials: CookieCredentials; let internalReqHeader: InternalRequestHeader; // Helper function @@ -38,7 +38,12 @@ export default ({ getService }: FtrProviderContext) => { }; log.info(`sending request for query: ${JSON.stringify(job.locatorParams[0].params.query)}`); - return await reportingAPI.createReportJobInternal('csv_v2', job, roleAuthc, internalReqHeader); + return await reportingAPI.createReportJobInternal( + 'csv_v2', + job, + cookieCredentials, + internalReqHeader + ); }; describe('CSV Generation from ES|QL', () => { @@ -84,7 +89,7 @@ export default ({ getService }: FtrProviderContext) => { }; before(async () => { await loadTimelessData(); - roleAuthc = await svlUserManager.createM2mApiKeyWithRoleScope('admin'); + cookieCredentials = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); internalReqHeader = svlCommonApi.getInternalRequestHeader(); }); @@ -112,7 +117,7 @@ export default ({ getService }: FtrProviderContext) => { }, ], })); - await reportingAPI.waitForJobToFinish(path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(path, cookieCredentials, internalReqHeader); response = await supertest.get(path); csvFile = response.text; }); @@ -184,7 +189,7 @@ export default ({ getService }: FtrProviderContext) => { ], title: 'Untitled discover search', })); - await reportingAPI.waitForJobToFinish(path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(path, cookieCredentials, internalReqHeader); response = await supertest.get(path); csvFile = response.text; }); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts index ce9fe313ecf88..fa1c3a25cde6c 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts @@ -6,8 +6,8 @@ */ import { expect } from 'expect'; +import { CookieCredentials, InternalRequestHeader } from '@kbn/ftr-common-functional-services'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { InternalRequestHeader, RoleCredentials } from '../../../../shared/services'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); @@ -15,8 +15,8 @@ export default function ({ getService }: FtrProviderContext) { const reportingAPI = getService('svlReportingApi'); const svlCommonApi = getService('svlCommonApi'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - const svlUserManager = getService('svlUserManager'); - let roleAuthc: RoleCredentials; + const samlAuth = getService('samlAuth'); + let cookieCredentials: CookieCredentials; let internalReqHeader: InternalRequestHeader; const archives: Record = { @@ -29,7 +29,7 @@ export default function ({ getService }: FtrProviderContext) { describe('Data Stream', function () { const generatedReports = new Set(); before(async () => { - roleAuthc = await svlUserManager.createM2mApiKeyWithRoleScope('admin'); + cookieCredentials = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); internalReqHeader = svlCommonApi.getInternalRequestHeader(); await esArchiver.load(archives.ecommerce.data); @@ -48,7 +48,7 @@ export default function ({ getService }: FtrProviderContext) { title: 'Ecommerce Data', version: '8.15.0', }, - roleAuthc, + cookieCredentials, internalReqHeader ); @@ -57,19 +57,18 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { for (const reportId of generatedReports) { - await reportingAPI.deleteReport(reportId, roleAuthc, internalReqHeader); + await reportingAPI.deleteReport(reportId, cookieCredentials, internalReqHeader); } await esArchiver.unload(archives.ecommerce.data); await kibanaServer.importExport.unload(archives.ecommerce.savedObjects); - await svlUserManager.invalidateM2mApiKeyWithRoleScope(roleAuthc); }); it('uses the datastream configuration', async () => { const { status, body } = await supertestWithoutAuth .get(`/api/index_management/data_streams/.kibana-reporting`) .set(internalReqHeader) - .set(roleAuthc.apiKeyHeader); + .set(cookieCredentials); svlCommonApi.assertResponseStatusCode(200, status, body); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/generate_csv_discover.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/generate_csv_discover.ts index dd070d9a84aa2..c654e5e307f86 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/generate_csv_discover.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/generate_csv_discover.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import type { SortDirection } from '@kbn/data-plugin/common'; import type { JobParamsCSV } from '@kbn/reporting-export-types-csv-common'; import type { Filter } from '@kbn/es-query'; -import { InternalRequestHeader, RoleCredentials } from '../../../../shared/services'; +import { CookieCredentials, InternalRequestHeader } from '@kbn/ftr-common-functional-services'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { @@ -17,8 +17,8 @@ export default function ({ getService }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const reportingAPI = getService('svlReportingApi'); const svlCommonApi = getService('svlCommonApi'); - const svlUserManager = getService('svlUserManager'); - let roleAuthc: RoleCredentials; + const samlAuth = getService('samlAuth'); + let cookieCredentials: CookieCredentials; let internalReqHeader: InternalRequestHeader; /* @@ -79,7 +79,7 @@ export default function ({ getService }: FtrProviderContext) { this.timeout(12 * 60 * 1000); before(async () => { - roleAuthc = await svlUserManager.createM2mApiKeyWithRoleScope('admin'); + cookieCredentials = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); internalReqHeader = svlCommonApi.getInternalRequestHeader(); }); @@ -90,10 +90,6 @@ export default function ({ getService }: FtrProviderContext) { }); }); - after(async () => { - await svlUserManager.invalidateM2mApiKeyWithRoleScope(roleAuthc); - }); - describe('exported CSV', () => { before(async () => { await esArchiver.load(archives.ecommerce.data); @@ -169,13 +165,13 @@ export default function ({ getService }: FtrProviderContext) { title: 'Ecommerce Data', version: '8.14.0', }), - roleAuthc, + cookieCredentials, internalReqHeader ); - await reportingAPI.waitForJobToFinish(res.path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(res.path, cookieCredentials, internalReqHeader); const csvFile = await reportingAPI.getCompletedJobOutput( res.path, - roleAuthc, + cookieCredentials, internalReqHeader ); expect((csvFile as string).length).to.be(124183); @@ -212,11 +208,11 @@ export default function ({ getService }: FtrProviderContext) { title: 'Untitled discover search', version: '8.14.0', }), - roleAuthc, + cookieCredentials, internalReqHeader ); - await reportingAPI.waitForJobToFinish(res.path, roleAuthc, internalReqHeader); - return reportingAPI.getCompletedJobOutput(res.path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(res.path, cookieCredentials, internalReqHeader); + return reportingAPI.getCompletedJobOutput(res.path, cookieCredentials, internalReqHeader); } it('includes an unmapped field to the report', async () => { @@ -359,13 +355,13 @@ export default function ({ getService }: FtrProviderContext) { }, }, }), - roleAuthc, + cookieCredentials, internalReqHeader ); - await reportingAPI.waitForJobToFinish(res.path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(res.path, cookieCredentials, internalReqHeader); const csvFile = await reportingAPI.getCompletedJobOutput( res.path, - roleAuthc, + cookieCredentials, internalReqHeader ); expect((csvFile as string).length).to.be(1270683); @@ -411,13 +407,13 @@ export default function ({ getService }: FtrProviderContext) { }, }, }), - roleAuthc, + cookieCredentials, internalReqHeader ); - await reportingAPI.waitForJobToFinish(res.path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(res.path, cookieCredentials, internalReqHeader); const csvFile = await reportingAPI.getCompletedJobOutput( res.path, - roleAuthc, + cookieCredentials, internalReqHeader ); expect((csvFile as string).length).to.be(918298); @@ -469,13 +465,13 @@ export default function ({ getService }: FtrProviderContext) { }, columns: ['@timestamp', 'clientip', 'extension'], }), - roleAuthc, + cookieCredentials, internalReqHeader ); - await reportingAPI.waitForJobToFinish(res.path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(res.path, cookieCredentials, internalReqHeader); const csvFile = await reportingAPI.getCompletedJobOutput( res.path, - roleAuthc, + cookieCredentials, internalReqHeader ); expect((csvFile as string).length).to.be(3020); @@ -515,13 +511,13 @@ export default function ({ getService }: FtrProviderContext) { }, columns: ['@timestamp', 'clientip', 'extension'], }), - roleAuthc, + cookieCredentials, internalReqHeader ); - await reportingAPI.waitForJobToFinish(res.path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(res.path, cookieCredentials, internalReqHeader); const csvFile = await reportingAPI.getCompletedJobOutput( res.path, - roleAuthc, + cookieCredentials, internalReqHeader ); expect((csvFile as string).length).to.be(3020); @@ -555,13 +551,13 @@ export default function ({ getService }: FtrProviderContext) { }, columns: ['date', 'message'], }), - roleAuthc, + cookieCredentials, internalReqHeader ); - await reportingAPI.waitForJobToFinish(res.path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(res.path, cookieCredentials, internalReqHeader); const csvFile = await reportingAPI.getCompletedJobOutput( res.path, - roleAuthc, + cookieCredentials, internalReqHeader ); expect((csvFile as string).length).to.be(103); @@ -584,13 +580,13 @@ export default function ({ getService }: FtrProviderContext) { }, columns: ['date', 'message'], }), - roleAuthc, + cookieCredentials, internalReqHeader ); - await reportingAPI.waitForJobToFinish(res.path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(res.path, cookieCredentials, internalReqHeader); const csvFile = await reportingAPI.getCompletedJobOutput( res.path, - roleAuthc, + cookieCredentials, internalReqHeader ); expect((csvFile as string).length).to.be(103); @@ -627,13 +623,13 @@ export default function ({ getService }: FtrProviderContext) { }, columns: ['date', 'message', '_id', '_index'], }), - roleAuthc, + cookieCredentials, internalReqHeader ); - await reportingAPI.waitForJobToFinish(res.path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(res.path, cookieCredentials, internalReqHeader); const csvFile = await reportingAPI.getCompletedJobOutput( res.path, - roleAuthc, + cookieCredentials, internalReqHeader ); expect((csvFile as string).length).to.be(134); @@ -659,13 +655,13 @@ export default function ({ getService }: FtrProviderContext) { }, columns: ['name', 'power'], }), - roleAuthc, + cookieCredentials, internalReqHeader ); - await reportingAPI.waitForJobToFinish(res.path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(res.path, cookieCredentials, internalReqHeader); const csvFile = await reportingAPI.getCompletedJobOutput( res.path, - roleAuthc, + cookieCredentials, internalReqHeader ); expect((csvFile as string).length).to.be(274); @@ -743,13 +739,13 @@ export default function ({ getService }: FtrProviderContext) { }, columns: [], }), - roleAuthc, + cookieCredentials, internalReqHeader ); - await reportingAPI.waitForJobToFinish(res.path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(res.path, cookieCredentials, internalReqHeader); const csvFile = await reportingAPI.getCompletedJobOutput( res.path, - roleAuthc, + cookieCredentials, internalReqHeader ); expect((csvFile as string).length).to.be(356); @@ -809,13 +805,13 @@ export default function ({ getService }: FtrProviderContext) { }, }, }), - roleAuthc, + cookieCredentials, internalReqHeader ); - await reportingAPI.waitForJobToFinish(res.path, roleAuthc, internalReqHeader); + await reportingAPI.waitForJobToFinish(res.path, cookieCredentials, internalReqHeader); const csvFile = await reportingAPI.getCompletedJobOutput( res.path, - roleAuthc, + cookieCredentials, internalReqHeader ); expect((csvFile as string).length).to.be(4845684); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts index 917af4d2c75c6..4eab7e19128f0 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts @@ -9,9 +9,8 @@ import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common/src/con import expect from '@kbn/expect'; import { INTERNAL_ROUTES } from '@kbn/reporting-common'; import { ReportApiJSON } from '@kbn/reporting-common/types'; -import { CookieCredentials } from '@kbn/ftr-common-functional-services'; +import { CookieCredentials, InternalRequestHeader } from '@kbn/ftr-common-functional-services'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { InternalRequestHeader } from '../../../../shared/services'; const API_HEADER: [string, string] = ['kbn-xsrf', 'reporting']; const INTERNAL_HEADER: [string, string] = [X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'Kibana']; diff --git a/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts b/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts index 2ea17190ee868..3be37428a0c2a 100644 --- a/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts @@ -10,8 +10,8 @@ import { CSV_REPORT_TYPE_V2, JobParamsCsvFromSavedObject, } from '@kbn/reporting-export-types-csv-common'; +import { CookieCredentials, InternalRequestHeader } from '@kbn/ftr-common-functional-services'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { InternalRequestHeader, RoleCredentials } from '../../../../shared/services'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const kibanaServer = getService('kibanaServer'); @@ -20,10 +20,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const retry = getService('retry'); const PageObjects = getPageObjects(['common', 'svlCommonPage', 'header']); const reportingAPI = getService('svlReportingApi'); - const svlUserManager = getService('svlUserManager'); const svlCommonApi = getService('svlCommonApi'); - let roleAuthc: RoleCredentials; - let roleName: string; + const samlAuth = getService('samlAuth'); + let cookieCredentials: CookieCredentials; let internalReqHeader: InternalRequestHeader; const navigateToReportingManagement = async () => { @@ -57,8 +56,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Kibana CI and MKI use different users before('initialize saved object archive', async () => { - roleName = 'admin'; - roleAuthc = await svlUserManager.createM2mApiKeyWithRoleScope(roleName); + cookieCredentials = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); internalReqHeader = svlCommonApi.getInternalRequestHeader(); // add test saved search object await kibanaServer.importExport.load(savedObjectsArchive); @@ -66,8 +64,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { after('clean up archives', async () => { await kibanaServer.importExport.unload(savedObjectsArchive); - await svlUserManager.invalidateM2mApiKeyWithRoleScope(roleAuthc); - await svlUserManager.invalidateM2mApiKeyWithRoleScope(roleAuthc); }); it(`user sees a job they've created`, async () => { @@ -76,7 +72,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { } = await reportingAPI.createReportJobInternal( CSV_REPORT_TYPE_V2, job, - roleAuthc, + cookieCredentials, internalReqHeader ); diff --git a/x-pack/test_serverless/shared/services/svl_reporting.ts b/x-pack/test_serverless/shared/services/svl_reporting.ts index f5d5a15822bb9..e87676d72409c 100644 --- a/x-pack/test_serverless/shared/services/svl_reporting.ts +++ b/x-pack/test_serverless/shared/services/svl_reporting.ts @@ -15,7 +15,7 @@ import { InternalRequestHeader } from '.'; const API_HEADER: [string, string] = ['kbn-xsrf', 'reporting']; /** - * Services to create roles and users for security testing + * Services to handle report job lifecycle phases for tests */ export function SvlReportingServiceProvider({ getService }: FtrProviderContext) { const log = getService('log'); From 0bea1a5f9fcd9479e5ffee926db24782c126d262 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Tue, 22 Oct 2024 09:54:34 -0700 Subject: [PATCH 06/13] use api key credentials for datastream management api --- .../test_suites/common/reporting/datastream.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts index fa1c3a25cde6c..bd927412f7627 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts @@ -6,7 +6,11 @@ */ import { expect } from 'expect'; -import { CookieCredentials, InternalRequestHeader } from '@kbn/ftr-common-functional-services'; +import { + CookieCredentials, + InternalRequestHeader, + RoleCredentials, +} from '@kbn/ftr-common-functional-services'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { @@ -15,6 +19,8 @@ export default function ({ getService }: FtrProviderContext) { const reportingAPI = getService('svlReportingApi'); const svlCommonApi = getService('svlCommonApi'); const supertestWithoutAuth = getService('supertestWithoutAuth'); + const svlUserManager = getService('svlUserManager'); + let roleAuthc: RoleCredentials; const samlAuth = getService('samlAuth'); let cookieCredentials: CookieCredentials; let internalReqHeader: InternalRequestHeader; @@ -29,6 +35,7 @@ export default function ({ getService }: FtrProviderContext) { describe('Data Stream', function () { const generatedReports = new Set(); before(async () => { + roleAuthc = await svlUserManager.createM2mApiKeyWithRoleScope('admin'); cookieCredentials = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); internalReqHeader = svlCommonApi.getInternalRequestHeader(); @@ -68,7 +75,7 @@ export default function ({ getService }: FtrProviderContext) { const { status, body } = await supertestWithoutAuth .get(`/api/index_management/data_streams/.kibana-reporting`) .set(internalReqHeader) - .set(cookieCredentials); + .set(roleAuthc.apiKeyHeader); // use API key since the datastream management API is a public endpoint svlCommonApi.assertResponseStatusCode(200, status, body); From db3fa484920d503d34c6e14004f8545f5cbbf833 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 23 Oct 2024 06:36:02 -0700 Subject: [PATCH 07/13] invalidate the api key in the after() block of test --- .../api_integration/test_suites/common/reporting/datastream.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts index bd927412f7627..da27a515c1195 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts @@ -69,6 +69,7 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.unload(archives.ecommerce.data); await kibanaServer.importExport.unload(archives.ecommerce.savedObjects); + await svlUserManager.invalidateM2mApiKeyWithRoleScope(roleAuthc); }); it('uses the datastream configuration', async () => { From b3f976512afae3e12842caa45339f36aa1aa3174 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 23 Oct 2024 08:51:35 -0700 Subject: [PATCH 08/13] Getting the internalReqHeader is not async --- .../test_suites/common/reporting/management.ts | 14 ++++++-------- .../test_suites/common/reporting/management.ts | 9 ++++----- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts index 4eab7e19128f0..3b7e198c8df9b 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts @@ -5,15 +5,13 @@ * 2.0. */ -import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common/src/constants'; import expect from '@kbn/expect'; import { INTERNAL_ROUTES } from '@kbn/reporting-common'; -import { ReportApiJSON } from '@kbn/reporting-common/types'; -import { CookieCredentials, InternalRequestHeader } from '@kbn/ftr-common-functional-services'; -import { FtrProviderContext } from '../../../ftr_provider_context'; +import type { ReportApiJSON } from '@kbn/reporting-common/types'; +import type { CookieCredentials } from '@kbn/ftr-common-functional-services'; +import type { FtrProviderContext } from '../../../ftr_provider_context'; const API_HEADER: [string, string] = ['kbn-xsrf', 'reporting']; -const INTERNAL_HEADER: [string, string] = [X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'Kibana']; export default ({ getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); @@ -21,8 +19,9 @@ export default ({ getService }: FtrProviderContext) => { const reportingAPI = getService('svlReportingApi'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const samlAuth = getService('samlAuth'); + const svlCommonApi = getService('svlCommonApi'); + const internalReqHeader = svlCommonApi.getInternalRequestHeader(); let cookieCredentials: CookieCredentials; - let internalReqHeader: InternalRequestHeader; const archives: Record = { ecommerce: { @@ -37,7 +36,6 @@ export default ({ getService }: FtrProviderContext) => { before(async () => { cookieCredentials = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); - internalReqHeader = samlAuth.getInternalRequestHeader(); await esArchiver.load(archives.ecommerce.data); await kibanaServer.importExport.load(archives.ecommerce.savedObjects); @@ -74,7 +72,7 @@ export default ({ getService }: FtrProviderContext) => { const response = await supertestWithoutAuth .delete(`${INTERNAL_ROUTES.JOBS.DELETE_PREFIX}/${reportJob.id}`) .set(...API_HEADER) - .set(...INTERNAL_HEADER) + .set(internalReqHeader) .set(cookieCredentials); expect(response.status).to.be(200); diff --git a/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts b/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts index 3be37428a0c2a..f045d9201cf82 100644 --- a/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts @@ -8,10 +8,10 @@ import { DISCOVER_APP_LOCATOR } from '@kbn/discover-plugin/common'; import { CSV_REPORT_TYPE_V2, - JobParamsCsvFromSavedObject, + type JobParamsCsvFromSavedObject, } from '@kbn/reporting-export-types-csv-common'; -import { CookieCredentials, InternalRequestHeader } from '@kbn/ftr-common-functional-services'; -import { FtrProviderContext } from '../../../ftr_provider_context'; +import type { CookieCredentials } from '@kbn/ftr-common-functional-services'; +import type { FtrProviderContext } from '../../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const kibanaServer = getService('kibanaServer'); @@ -22,8 +22,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const reportingAPI = getService('svlReportingApi'); const svlCommonApi = getService('svlCommonApi'); const samlAuth = getService('samlAuth'); + const internalReqHeader = svlCommonApi.getInternalRequestHeader(); let cookieCredentials: CookieCredentials; - let internalReqHeader: InternalRequestHeader; const navigateToReportingManagement = async () => { log.debug(`navigating to reporting management app`); @@ -57,7 +57,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Kibana CI and MKI use different users before('initialize saved object archive', async () => { cookieCredentials = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); - internalReqHeader = svlCommonApi.getInternalRequestHeader(); // add test saved search object await kibanaServer.importExport.load(savedObjectsArchive); }); From 5305cdd2ace4fac7c88a2fce0fc666880e7c9fec Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 23 Oct 2024 09:01:51 -0700 Subject: [PATCH 09/13] Ensure the functional test job is allowed to finish --- .../common/reporting/management.ts | 5 +-- .../common/reporting/management.ts | 32 ++++++++++++------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts index 3b7e198c8df9b..d29e2b11a8340 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts @@ -23,14 +23,14 @@ export default ({ getService }: FtrProviderContext) => { const internalReqHeader = svlCommonApi.getInternalRequestHeader(); let cookieCredentials: CookieCredentials; - const archives: Record = { + const archives = { ecommerce: { data: 'x-pack/test/functional/es_archives/reporting/ecommerce', savedObjects: 'x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce', }, }; - describe('Reporting Management: Deletion', function () { + describe('Management: Deletion', function () { let reportJob: ReportApiJSON; let path: string; @@ -40,6 +40,7 @@ export default ({ getService }: FtrProviderContext) => { await esArchiver.load(archives.ecommerce.data); await kibanaServer.importExport.load(archives.ecommerce.savedObjects); + // generate a report that can be deleted in the test const result = await reportingAPI.createReportJobInternal( 'csv_searchsource', { diff --git a/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts b/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts index f045d9201cf82..631bd1ae3d0cb 100644 --- a/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts @@ -11,6 +11,7 @@ import { type JobParamsCsvFromSavedObject, } from '@kbn/reporting-export-types-csv-common'; import type { CookieCredentials } from '@kbn/ftr-common-functional-services'; +import { ReportApiJSON } from '@kbn/reporting-common/types'; import type { FtrProviderContext } from '../../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { @@ -35,9 +36,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }; - describe('Reporting Management app', function () { + describe('Management: listing', function () { // security_exception: action [indices:admin/create] is unauthorized for user [elastic] with effective roles [superuser] on restricted indices [.reporting-2020.04.19], this action is granted by the index privileges [create_index,manage,all] this.tags('failsOnMKI'); + + let reportJob: ReportApiJSON; + let path: string; + const savedObjectsArchive = 'test/functional/fixtures/kbn_archiver/discover'; const job: JobParamsCsvFromSavedObject = { @@ -55,28 +60,31 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }; // Kibana CI and MKI use different users - before('initialize saved object archive', async () => { + before(async () => { cookieCredentials = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); // add test saved search object await kibanaServer.importExport.load(savedObjectsArchive); - }); - after('clean up archives', async () => { - await kibanaServer.importExport.unload(savedObjectsArchive); - }); - - it(`user sees a job they've created`, async () => { - const { - job: { id: jobId }, - } = await reportingAPI.createReportJobInternal( + // generate a report that can be tested to show in the listing + const result = await reportingAPI.createReportJobInternal( CSV_REPORT_TYPE_V2, job, cookieCredentials, internalReqHeader ); + path = result.path; + reportJob = result.job; + }); + + after(async () => { + await kibanaServer.importExport.unload(savedObjectsArchive); + await reportingAPI.waitForJobToFinish(path, cookieCredentials, internalReqHeader); + }); + + it(`user sees a job they've created`, async () => { await navigateToReportingManagement(); - await testSubjects.existOrFail(`viewReportingLink-${jobId}`); + await testSubjects.existOrFail(`viewReportingLink-${reportJob.id}`); }); }); }; From 631e9f18fd6058f70342ce4d953959ef7e0fd807 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 23 Oct 2024 09:19:11 -0700 Subject: [PATCH 10/13] Fix internalReqHeader --- .../test_suites/common/reporting/management.ts | 6 +++--- .../functional/test_suites/common/reporting/management.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts index d29e2b11a8340..e63479e0e7774 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { INTERNAL_ROUTES } from '@kbn/reporting-common'; import type { ReportApiJSON } from '@kbn/reporting-common/types'; -import type { CookieCredentials } from '@kbn/ftr-common-functional-services'; +import type { CookieCredentials, InternalRequestHeader } from '@kbn/ftr-common-functional-services'; import type { FtrProviderContext } from '../../../ftr_provider_context'; const API_HEADER: [string, string] = ['kbn-xsrf', 'reporting']; @@ -19,9 +19,8 @@ export default ({ getService }: FtrProviderContext) => { const reportingAPI = getService('svlReportingApi'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const samlAuth = getService('samlAuth'); - const svlCommonApi = getService('svlCommonApi'); - const internalReqHeader = svlCommonApi.getInternalRequestHeader(); let cookieCredentials: CookieCredentials; + let internalReqHeader: InternalRequestHeader; const archives = { ecommerce: { @@ -36,6 +35,7 @@ export default ({ getService }: FtrProviderContext) => { before(async () => { cookieCredentials = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); + internalReqHeader = samlAuth.getInternalRequestHeader(); await esArchiver.load(archives.ecommerce.data); await kibanaServer.importExport.load(archives.ecommerce.savedObjects); diff --git a/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts b/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts index 631bd1ae3d0cb..536b1ecaf4eb0 100644 --- a/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts @@ -10,7 +10,7 @@ import { CSV_REPORT_TYPE_V2, type JobParamsCsvFromSavedObject, } from '@kbn/reporting-export-types-csv-common'; -import type { CookieCredentials } from '@kbn/ftr-common-functional-services'; +import type { CookieCredentials, InternalRequestHeader } from '@kbn/ftr-common-functional-services'; import { ReportApiJSON } from '@kbn/reporting-common/types'; import type { FtrProviderContext } from '../../../ftr_provider_context'; @@ -21,10 +21,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const retry = getService('retry'); const PageObjects = getPageObjects(['common', 'svlCommonPage', 'header']); const reportingAPI = getService('svlReportingApi'); - const svlCommonApi = getService('svlCommonApi'); const samlAuth = getService('samlAuth'); - const internalReqHeader = svlCommonApi.getInternalRequestHeader(); let cookieCredentials: CookieCredentials; + let internalReqHeader: InternalRequestHeader; const navigateToReportingManagement = async () => { log.debug(`navigating to reporting management app`); @@ -62,6 +61,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Kibana CI and MKI use different users before(async () => { cookieCredentials = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); + internalReqHeader = samlAuth.getInternalRequestHeader(); // add test saved search object await kibanaServer.importExport.load(savedObjectsArchive); From c79544680c8bb40088eee9cb36243fe0ceeb913d Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 23 Oct 2024 09:19:31 -0700 Subject: [PATCH 11/13] Fix an instance of waiting for the job to finish --- .../api_integration/test_suites/common/reporting/datastream.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts index da27a515c1195..d004c3f11d785 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts @@ -42,7 +42,7 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.load(archives.ecommerce.data); await kibanaServer.importExport.load(archives.ecommerce.savedObjects); - const { job } = await reportingAPI.createReportJobInternal( + const { job, path } = await reportingAPI.createReportJobInternal( 'csv_searchsource', { browserTimezone: 'UTC', @@ -58,6 +58,7 @@ export default function ({ getService }: FtrProviderContext) { cookieCredentials, internalReqHeader ); + await reportingAPI.waitForJobToFinish(path, cookieCredentials, internalReqHeader); generatedReports.add(job.id); }); From dd877b2f1e4d8e707ff5601fd99673c0a8096234 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 23 Oct 2024 16:05:00 -0700 Subject: [PATCH 12/13] fix a broken test --- .../reporting/__snapshots__/csv_v2_esql.snap | 31 +++++++++++++++---- .../common/reporting/csv_v2_esql.ts | 6 ++-- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/__snapshots__/csv_v2_esql.snap b/x-pack/test_serverless/api_integration/test_suites/common/reporting/__snapshots__/csv_v2_esql.snap index 83c8c2982c4f5..e6ceffaa3b4ab 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/__snapshots__/csv_v2_esql.snap +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/__snapshots__/csv_v2_esql.snap @@ -1,21 +1,40 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Reporting CSV Generation from ES|QL export from non-timebased data view csv from es|ql csv file matches 1`] = `"{\\"statusCode\\":404,\\"error\\":\\"Not Found\\",\\"message\\":\\"Not Found\\"}"`; +exports[`Reporting CSV Generation from ES|QL export from non-timebased data view csv from es|ql csv file matches 1`] = ` +"eon,epoch,era,period +Phanerozoic,\\" Pliocene\\",Cenozoic,Neogene +Phanerozoic,\\" Holocene\\",Cenozoic,Quaternary +Phanerozoic,,Mesozoic,Cretaceous +Phanerozoic,,Mesozoic,Jurassic +Phanerozoic,,Paleozoic,Cambrian +Proterozoic,,Paleozoic,Permian +Archean,,, +Hadean,,, +" +`; exports[`Reporting CSV Generation from ES|QL export from non-timebased data view csv from es|ql job response data is correct 1`] = ` Object { - "contentDisposition": undefined, - "contentType": "application/json; charset=utf-8", + "contentDisposition": "attachment; filename=CSV%20Report.csv", + "contentType": "text/csv; charset=utf-8", "title": "CSV Report", } `; -exports[`Reporting CSV Generation from ES|QL export from timebased data view csv from es|ql export with time filter csv file matches 1`] = `"{\\"statusCode\\":404,\\"error\\":\\"Not Found\\",\\"message\\":\\"Not Found\\"}"`; +exports[`Reporting CSV Generation from ES|QL export from timebased data view csv from es|ql export with time filter csv file matches 1`] = ` +"\\"@message\\" +\\"143.84.142.7 - - [2015-09-20T00:00:00.000Z] \\"\\"GET /uploads/steven-hawley.jpg HTTP/1.1\\"\\" 200 1623 \\"\\"-\\"\\" \\"\\"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\\"\\"\\" +\\"193.164.192.47 - - [2015-09-20T00:30:34.206Z] \\"\\"GET /uploads/michael-foreman.jpg HTTP/1.1\\"\\" 200 8537 \\"\\"-\\"\\" \\"\\"Mozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\\"\\"\\" +\\"176.7.244.68 - - [2015-09-20T00:32:42.058Z] \\"\\"GET /uploads/james-pawelczyk.jpg HTTP/1.1\\"\\" 200 9196 \\"\\"-\\"\\" \\"\\"Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\\"\\"\\" +\\"237.56.90.184 - - [2015-09-20T00:35:21.445Z] \\"\\"GET /uploads/david-leestma.jpg HTTP/1.1\\"\\" 200 9790 \\"\\"-\\"\\" \\"\\"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\\"\\"\\" +\\"255.56.89.50 - - [2015-09-20T00:43:01.353Z] \\"\\"GET /uploads/michael-r-barratt.jpg HTTP/1.1\\"\\" 200 9583 \\"\\"-\\"\\" \\"\\"Mozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\\"\\"\\" +" +`; exports[`Reporting CSV Generation from ES|QL export from timebased data view csv from es|ql export with time filter job response data is correct 1`] = ` Object { - "contentDisposition": undefined, - "contentType": "application/json; charset=utf-8", + "contentDisposition": "attachment; filename=Untitled%20discover%20search.csv", + "contentType": "text/csv; charset=utf-8", "title": "Untitled discover search", } `; diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/csv_v2_esql.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/csv_v2_esql.ts index d271b530247f4..022f22a144b6e 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/csv_v2_esql.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/csv_v2_esql.ts @@ -16,7 +16,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default ({ getService }: FtrProviderContext) => { const es = getService('es'); - const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); const esArchiver = getService('esArchiver'); const log = getService('log'); const reportingAPI = getService('svlReportingApi'); @@ -118,7 +118,7 @@ export default ({ getService }: FtrProviderContext) => { ], })); await reportingAPI.waitForJobToFinish(path, cookieCredentials, internalReqHeader); - response = await supertest.get(path); + response = await supertestWithoutAuth.get(path).set(cookieCredentials); csvFile = response.text; }); @@ -190,7 +190,7 @@ export default ({ getService }: FtrProviderContext) => { title: 'Untitled discover search', })); await reportingAPI.waitForJobToFinish(path, cookieCredentials, internalReqHeader); - response = await supertest.get(path); + response = await supertestWithoutAuth.get(path).set(cookieCredentials); csvFile = response.text; }); From 8e4ee0f2ec10a065d340fd7f1c08dc13ede99532 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 23 Oct 2024 16:13:38 -0700 Subject: [PATCH 13/13] remove inessential differences --- .../test_suites/common/reporting/datastream.ts | 2 +- .../test_suites/common/reporting/management.ts | 2 +- .../functional/test_suites/common/reporting/management.ts | 6 +++--- x-pack/test_serverless/shared/services/svl_reporting.ts | 1 - 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts index d004c3f11d785..671b42f5a02a3 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts @@ -20,8 +20,8 @@ export default function ({ getService }: FtrProviderContext) { const svlCommonApi = getService('svlCommonApi'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const svlUserManager = getService('svlUserManager'); - let roleAuthc: RoleCredentials; const samlAuth = getService('samlAuth'); + let roleAuthc: RoleCredentials; let cookieCredentials: CookieCredentials; let internalReqHeader: InternalRequestHeader; diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts index e63479e0e7774..ad1088ae0ebd2 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/management.ts @@ -29,7 +29,7 @@ export default ({ getService }: FtrProviderContext) => { }, }; - describe('Management: Deletion', function () { + describe('Reporting Management', function () { let reportJob: ReportApiJSON; let path: string; diff --git a/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts b/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts index 536b1ecaf4eb0..35a1d1ec1872f 100644 --- a/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts +++ b/x-pack/test_serverless/functional/test_suites/common/reporting/management.ts @@ -35,7 +35,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }; - describe('Management: listing', function () { + describe('Reporting Management app', function () { // security_exception: action [indices:admin/create] is unauthorized for user [elastic] with effective roles [superuser] on restricted indices [.reporting-2020.04.19], this action is granted by the index privileges [create_index,manage,all] this.tags('failsOnMKI'); @@ -59,7 +59,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }; // Kibana CI and MKI use different users - before(async () => { + before('initialize saved object archive', async () => { cookieCredentials = await samlAuth.getM2MApiCookieCredentialsWithRoleScope('admin'); internalReqHeader = samlAuth.getInternalRequestHeader(); // add test saved search object @@ -77,7 +77,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { reportJob = result.job; }); - after(async () => { + after('clean up archives', async () => { await kibanaServer.importExport.unload(savedObjectsArchive); await reportingAPI.waitForJobToFinish(path, cookieCredentials, internalReqHeader); }); diff --git a/x-pack/test_serverless/shared/services/svl_reporting.ts b/x-pack/test_serverless/shared/services/svl_reporting.ts index e87676d72409c..305b308658887 100644 --- a/x-pack/test_serverless/shared/services/svl_reporting.ts +++ b/x-pack/test_serverless/shared/services/svl_reporting.ts @@ -61,7 +61,6 @@ export function SvlReportingServiceProvider({ getService }: FtrProviderContext) internalReqHeader: InternalRequestHeader, options?: { timeout?: number } ) { - log.debug(`ReportingAPI.waitForJobToFinish ${downloadReportPath}`); await retry.waitForWithTimeout( `job ${downloadReportPath} finished`, options?.timeout ?? config.get('timeouts.kibanaReportCompletion'),