From 1ad34cbe2fefe460bdc8c93af14824fc264c48fe Mon Sep 17 00:00:00 2001 From: Cristina Amico Date: Thu, 10 Feb 2022 14:46:37 +0100 Subject: [PATCH 1/8] [Fleet] Improve privileges integration testing (#125102) * [Fleet] Improve privileges integration testing * Further testing --- .../apis/agents/actions.ts | 16 ++++++ .../apis/agents/delete.ts | 8 +-- .../fleet_api_integration/apis/agents/list.ts | 5 +- .../apis/agents/reassign.ts | 14 ++++++ .../apis/agents/upgrade.ts | 24 +++++++++ .../apis/enrollment_api_keys/crud.ts | 50 +++++++++++++++++++ .../apis/epm/bulk_upgrade.ts | 11 +++- .../fleet_api_integration/apis/epm/delete.ts | 12 ++++- .../fleet_api_integration/apis/epm/file.ts | 28 +++++++++++ .../fleet_api_integration/apis/epm/get.ts | 16 +++++- .../apis/epm/install_by_upload.ts | 13 ++++- .../fleet_api_integration/apis/epm/list.ts | 22 +++++++- .../fleet_api_integration/apis/test_users.ts | 41 +++++++++++++-- 13 files changed, 240 insertions(+), 20 deletions(-) diff --git a/x-pack/test/fleet_api_integration/apis/agents/actions.ts b/x-pack/test/fleet_api_integration/apis/agents/actions.ts index a701d44319a95c..00bb00eb9c68c7 100644 --- a/x-pack/test/fleet_api_integration/apis/agents/actions.ts +++ b/x-pack/test/fleet_api_integration/apis/agents/actions.ts @@ -7,11 +7,13 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; +import { testUsers } from '../test_users'; export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('fleet_agents_actions', () => { before(async () => { @@ -97,5 +99,19 @@ export default function (providerContext: FtrProviderContext) { }) .expect(404); }); + + it('should return a 403 if user lacks fleet all permissions', async () => { + await supertestWithoutAuth + .post(`/api/fleet/agents/agent1/actions`) + .set('kbn-xsrf', 'xx') + .auth(testUsers.fleet_no_access.username, testUsers.fleet_no_access.password) + .send({ + action: { + type: 'POLICY_CHANGE', + data: { data: 'action_data' }, + }, + }) + .expect(403); + }); }); } diff --git a/x-pack/test/fleet_api_integration/apis/agents/delete.ts b/x-pack/test/fleet_api_integration/apis/agents/delete.ts index 45c468e095e70e..6b05d3e66cb395 100644 --- a/x-pack/test/fleet_api_integration/apis/agents/delete.ts +++ b/x-pack/test/fleet_api_integration/apis/agents/delete.ts @@ -18,7 +18,8 @@ export default function ({ getService }: FtrProviderContext) { fleet_user: { permissions: { feature: { - fleet: ['read'], + fleet: ['all'], + fleetv2: ['none'], }, spaces: ['*'], }, @@ -26,9 +27,9 @@ export default function ({ getService }: FtrProviderContext) { password: 'changeme', }, fleet_admin: { - roles: ['superuser'], permissions: { feature: { + fleetv2: ['all'], fleet: ['all'], }, spaces: ['*'], @@ -63,8 +64,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/fleet/agents'); }); - - it('should return a 403 if user lacks fleet-write permissions', async () => { + it('should return a 403 if user lacks fleet all permissions', async () => { const { body: apiResponse } = await supertest .delete(`/api/fleet/agents/agent1`) .auth(users.fleet_user.username, users.fleet_user.password) diff --git a/x-pack/test/fleet_api_integration/apis/agents/list.ts b/x-pack/test/fleet_api_integration/apis/agents/list.ts index 0b3d8fd4e9a3ce..17316ce4086ae1 100644 --- a/x-pack/test/fleet_api_integration/apis/agents/list.ts +++ b/x-pack/test/fleet_api_integration/apis/agents/list.ts @@ -23,11 +23,10 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.unload('x-pack/test/functional/es_archives/fleet/agents'); }); - // Only superuser can access Fleet for now. it.skip('should return a 200 if a user with the fleet all try to access the list', async () => { await supertest .get(`/api/fleet/agents`) - .auth(testUsers.fleet_all.username, testUsers.fleet_all.password) + .auth(testUsers.fleet_all_only.username, testUsers.fleet_all_only.password) .expect(200); }); @@ -38,7 +37,7 @@ export default function ({ getService }: FtrProviderContext) { .expect(403); }); - it('should return the list of agents when requesting as a superuser', async () => { + it('should return the list of agents when requesting as admin', async () => { const { body: apiResponse } = await supertest.get(`/api/fleet/agents`).expect(200); expect(apiResponse).to.have.keys('page', 'total', 'items', 'list'); diff --git a/x-pack/test/fleet_api_integration/apis/agents/reassign.ts b/x-pack/test/fleet_api_integration/apis/agents/reassign.ts index a2ef226eb3d852..6ba5bbc3b965a9 100644 --- a/x-pack/test/fleet_api_integration/apis/agents/reassign.ts +++ b/x-pack/test/fleet_api_integration/apis/agents/reassign.ts @@ -8,11 +8,13 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; import { setupFleetAndAgents } from './services'; +import { testUsers } from '../test_users'; export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('reassign agent(s)', () => { before(async () => { @@ -205,6 +207,18 @@ export default function (providerContext: FtrProviderContext) { }) .expect(404); }); + + it('should return a 403 if user lacks fleet all permissions', async () => { + await supertestWithoutAuth + .post(`/api/fleet/agents/bulk_reassign`) + .auth(testUsers.fleet_no_access.username, testUsers.fleet_no_access.password) + .set('kbn-xsrf', 'xxx') + .send({ + agents: ['agent2', 'agent3'], + policy_id: 'policy2', + }) + .expect(403); + }); }); }); } diff --git a/x-pack/test/fleet_api_integration/apis/agents/upgrade.ts b/x-pack/test/fleet_api_integration/apis/agents/upgrade.ts index 57e57a6524b0ea..e84aa13475564b 100644 --- a/x-pack/test/fleet_api_integration/apis/agents/upgrade.ts +++ b/x-pack/test/fleet_api_integration/apis/agents/upgrade.ts @@ -11,6 +11,7 @@ import { FtrProviderContext } from '../../../api_integration/ftr_provider_contex import { setupFleetAndAgents } from './services'; import { skipIfNoDockerRegistry } from '../../helpers'; import { AGENTS_INDEX } from '../../../../plugins/fleet/common'; +import { testUsers } from '../test_users'; const makeSnapshotVersion = (version: string) => { return version.endsWith('-SNAPSHOT') ? version : `${version}-SNAPSHOT`; @@ -22,6 +23,7 @@ export default function (providerContext: FtrProviderContext) { const es = getService('es'); const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('fleet upgrade', () => { skipIfNoDockerRegistry(providerContext); @@ -255,6 +257,28 @@ export default function (providerContext: FtrProviderContext) { const agent1data = await supertest.get(`/api/fleet/agents/agent1`); expect(typeof agent1data.body.item.upgrade_started_at).to.be('undefined'); }); + + it('should respond 403 if user lacks fleet all permissions', async () => { + const kibanaVersion = await kibanaServer.version.get(); + await es.update({ + id: 'agent1', + refresh: 'wait_for', + index: AGENTS_INDEX, + body: { + doc: { + local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } }, + }, + }, + }); + await supertestWithoutAuth + .post(`/api/fleet/agents/agent1/upgrade`) + .set('kbn-xsrf', 'xxx') + .auth(testUsers.fleet_no_access.username, testUsers.fleet_no_access.password) + .send({ + version: kibanaVersion, + }) + .expect(403); + }); }); describe('multiple agents', () => { diff --git a/x-pack/test/fleet_api_integration/apis/enrollment_api_keys/crud.ts b/x-pack/test/fleet_api_integration/apis/enrollment_api_keys/crud.ts index d03b77153fa6bb..703621dc7f9d41 100644 --- a/x-pack/test/fleet_api_integration/apis/enrollment_api_keys/crud.ts +++ b/x-pack/test/fleet_api_integration/apis/enrollment_api_keys/crud.ts @@ -11,6 +11,8 @@ import { FtrProviderContext } from '../../../api_integration/ftr_provider_contex import { setupFleetAndAgents, getEsClientForAPIKey } from '../agents/services'; import { skipIfNoDockerRegistry } from '../../helpers'; +import { testUsers } from '../test_users'; + const ENROLLMENT_KEY_ID = 'ed22ca17-e178-4cfe-8b02-54ea29fbd6d0'; export default function (providerContext: FtrProviderContext) { @@ -18,6 +20,7 @@ export default function (providerContext: FtrProviderContext) { const esArchiver = getService('esArchiver'); const es = getService('es'); const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('fleet_enrollment_api_keys_crud', () => { before(async () => { @@ -41,6 +44,20 @@ export default function (providerContext: FtrProviderContext) { expect(apiResponse.items[0]).to.have.keys('id', 'api_key_id', 'name'); expect(apiResponse).to.have.keys('items'); }); + + it('should return 200 if the user has correct permissions', async () => { + await supertestWithoutAuth + .get(`/api/fleet/enrollment_api_keys`) + .auth(testUsers.setup.username, testUsers.setup.password) + .expect(200); + }); + + it('should return 403 if the user does not have correct permissions', async () => { + await supertestWithoutAuth + .get(`/api/fleet/enrollment_api_keys`) + .auth(testUsers.integr_all_only.username, testUsers.integr_all_only.password) + .expect(403); + }); }); describe('GET /fleet/enrollment_api_keys/{id}', async () => { @@ -51,6 +68,20 @@ export default function (providerContext: FtrProviderContext) { expect(apiResponse.item).to.have.keys('id', 'api_key_id', 'name'); }); + + it('should return 200 if the user has correct permissions', async () => { + await supertestWithoutAuth + .get(`/api/fleet/enrollment_api_keys/${ENROLLMENT_KEY_ID}`) + .auth(testUsers.setup.username, testUsers.setup.password) + .expect(200); + }); + + it('should return 403 if the user does not have correct permissions', async () => { + await supertestWithoutAuth + .get(`/api/fleet/enrollment_api_keys/${ENROLLMENT_KEY_ID}`) + .auth(testUsers.integr_all_only.username, testUsers.integr_all_only.password) + .expect(403); + }); }); describe('DELETE /fleet/enrollment_api_keys/{id}', async () => { @@ -79,6 +110,14 @@ export default function (providerContext: FtrProviderContext) { expect(apiKeys).length(1); expect(apiKeys[0].invalidated).eql(true); }); + + it('should return 403 if the user does not have correct permissions', async () => { + await supertestWithoutAuth + .delete(`/api/fleet/enrollment_api_keys/${keyId}`) + .auth(testUsers.integr_all_only.username, testUsers.integr_all_only.password) + .set('kbn-xsrf', 'xxx') + .expect(403); + }); }); describe('POST /fleet/enrollment_api_keys', () => { @@ -116,6 +155,17 @@ export default function (providerContext: FtrProviderContext) { expect(apiResponse.item).to.have.keys('id', 'api_key', 'api_key_id', 'name', 'policy_id'); }); + it('should return 403 if the user does not have correct permissions', async () => { + await supertestWithoutAuth + .post(`/api/fleet/enrollment_api_keys`) + .auth(testUsers.integr_all_only.username, testUsers.integr_all_only.password) + .set('kbn-xsrf', 'xxx') + .send({ + policy_id: 'policy1', + }) + .expect(403); + }); + it('should allow to create an enrollment api key with agent policy and unique name', async () => { const { body: noSpacesRes } = await supertest .post(`/api/fleet/enrollment_api_keys`) diff --git a/x-pack/test/fleet_api_integration/apis/epm/bulk_upgrade.ts b/x-pack/test/fleet_api_integration/apis/epm/bulk_upgrade.ts index a51ac1c9803be2..e3815150c0b660 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/bulk_upgrade.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/bulk_upgrade.ts @@ -46,10 +46,17 @@ export default function (providerContext: FtrProviderContext) { it('should return 400 if no packages are requested for upgrade', async function () { await supertest.post(`/api/fleet/epm/packages/_bulk`).set('kbn-xsrf', 'xxxx').expect(400); }); - it('should return 403 if read only user requests upgrade', async function () { + it('should return 403 if user without integrations all requests upgrade', async function () { await supertestWithoutAuth .post(`/api/fleet/epm/packages/_bulk`) - .auth(testUsers.fleet_read_only.username, testUsers.fleet_read_only.password) + .auth(testUsers.fleet_all_int_read.username, testUsers.fleet_all_int_read.password) + .set('kbn-xsrf', 'xxxx') + .expect(403); + }); + it('should return 403 if user without fleet access requests upgrade', async function () { + await supertestWithoutAuth + .post(`/api/fleet/epm/packages/_bulk`) + .auth(testUsers.integr_all_only.username, testUsers.integr_all_only.password) .set('kbn-xsrf', 'xxxx') .expect(403); }); diff --git a/x-pack/test/fleet_api_integration/apis/epm/delete.ts b/x-pack/test/fleet_api_integration/apis/epm/delete.ts index 6e988c6f0d0f77..076cc6bba4efcf 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/delete.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/delete.ts @@ -56,10 +56,18 @@ export default function (providerContext: FtrProviderContext) { .expect(200); }); - it('should return 403 for read-only users', async () => { + it('should return 403 for users without integrations all permissions', async () => { await supertestWithoutAuth .delete(`/api/fleet/epm/packages/${requiredPackage}/${pkgVersion}`) - .auth(testUsers.fleet_read_only.username, testUsers.fleet_read_only.password) + .auth(testUsers.fleet_all_int_read.username, testUsers.fleet_all_int_read.password) + .set('kbn-xsrf', 'xxxx') + .expect(403); + }); + + it('should return 403 for users without fleet all permissions', async () => { + await supertestWithoutAuth + .delete(`/api/fleet/epm/packages/${requiredPackage}/${pkgVersion}`) + .auth(testUsers.integr_all_only.username, testUsers.integr_all_only.password) .set('kbn-xsrf', 'xxxx') .expect(403); }); diff --git a/x-pack/test/fleet_api_integration/apis/epm/file.ts b/x-pack/test/fleet_api_integration/apis/epm/file.ts index 7dec9456bf5f16..2bd8161873789a 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/file.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/file.ts @@ -10,11 +10,13 @@ import path from 'path'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; import { warnAndSkipTest } from '../../helpers'; +import { testUsers } from '../test_users'; export default function ({ getService }: FtrProviderContext) { const log = getService('log'); const supertest = getService('supertest'); const dockerServers = getService('dockerServers'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); const server = dockerServers.get('registry'); describe('EPM - package file', () => { @@ -85,6 +87,32 @@ export default function ({ getService }: FtrProviderContext) { warnAndSkipTest(this, log); } }); + + it('should return 200 if the user has only integrations access', async function () { + await supertestWithoutAuth + .get('/api/fleet/epm/packages/filetest/0.1.0/kibana/search/sample_search.json') + .auth(testUsers.integr_all_only.username, testUsers.integr_all_only.password) + .set('kbn-xsrf', 'xxx') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200); + }); + + it('should return 200 if the user has only fleet access', async function () { + await supertestWithoutAuth + .get('/api/fleet/epm/packages/filetest/0.1.0/kibana/search/sample_search.json') + .auth(testUsers.fleet_all_only.username, testUsers.fleet_all_only.password) + .set('kbn-xsrf', 'xxx') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200); + }); + + it('should return 403 if the user does not have correct permissions', async function () { + await supertestWithoutAuth + .get('/api/fleet/epm/packages/filetest/0.1.0/kibana/search/sample_search.json') + .auth(testUsers.fleet_no_access.username, testUsers.fleet_no_access.password) + .set('kbn-xsrf', 'xxx') + .expect(403); + }); }); describe('it gets files from an uploaded package', () => { before(async () => { diff --git a/x-pack/test/fleet_api_integration/apis/epm/get.ts b/x-pack/test/fleet_api_integration/apis/epm/get.ts index c605adc44233a5..891bf7019eda34 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/get.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/get.ts @@ -96,10 +96,22 @@ export default function (providerContext: FtrProviderContext) { await supertest.get('/api/fleet/epm/packages/endpoint/0.1.0.1.2.3').expect(400); }); - it('allows user with only read permission to access', async () => { + it('allows user with only fleet permission to access', async () => { await supertestWithoutAuth .get(`/api/fleet/epm/packages/${testPkgName}/${testPkgVersion}`) - .auth(testUsers.fleet_read_only.username, testUsers.fleet_read_only.password) + .auth(testUsers.fleet_all_only.username, testUsers.fleet_all_only.password) + .expect(200); + }); + it('allows user with only integrations permission to access', async () => { + await supertestWithoutAuth + .get(`/api/fleet/epm/packages/${testPkgName}/${testPkgVersion}`) + .auth(testUsers.integr_all_only.username, testUsers.integr_all_only.password) + .expect(200); + }); + it('allows user with integrations read permission to access', async () => { + await supertestWithoutAuth + .get(`/api/fleet/epm/packages/${testPkgName}/${testPkgVersion}`) + .auth(testUsers.fleet_all_int_read.username, testUsers.fleet_all_int_read.password) .expect(200); }); diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_by_upload.ts b/x-pack/test/fleet_api_integration/apis/epm/install_by_upload.ts index 83ff7611ded8ea..97f0bce458791d 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_by_upload.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_by_upload.ts @@ -184,7 +184,18 @@ export default function (providerContext: FtrProviderContext) { const buf = fs.readFileSync(testPkgArchiveTgz); await supertestWithoutAuth .post(`/api/fleet/epm/packages`) - .auth(testUsers.fleet_read_only.username, testUsers.fleet_read_only.password) + .auth(testUsers.fleet_all_int_read.username, testUsers.fleet_all_int_read.password) + .set('kbn-xsrf', 'xxxx') + .type('application/gzip') + .send(buf) + .expect(403); + }); + + it('should not allow non superusers', async () => { + const buf = fs.readFileSync(testPkgArchiveTgz); + await supertestWithoutAuth + .post(`/api/fleet/epm/packages`) + .auth(testUsers.fleet_all_int_all.username, testUsers.fleet_all_int_all.password) .set('kbn-xsrf', 'xxxx') .type('application/gzip') .send(buf) diff --git a/x-pack/test/fleet_api_integration/apis/epm/list.ts b/x-pack/test/fleet_api_integration/apis/epm/list.ts index 836582d0609c41..51f003a7192d56 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/list.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/list.ts @@ -57,12 +57,30 @@ export default function (providerContext: FtrProviderContext) { expect(listResponse.items.sort()).to.eql(['endpoint'].sort()); }); - it('allows user with only read permission to access', async () => { + it('allows user with only fleet permission to access', async () => { await supertestWithoutAuth .get('/api/fleet/epm/packages') - .auth(testUsers.fleet_read_only.username, testUsers.fleet_read_only.password) + .auth(testUsers.fleet_all_only.username, testUsers.fleet_all_only.password) .expect(200); }); + it('allows user with only integrations permission to access', async () => { + await supertestWithoutAuth + .get('/api/fleet/epm/packages') + .auth(testUsers.integr_all_only.username, testUsers.integr_all_only.password) + .expect(200); + }); + it('allows user with integrations read permission to access', async () => { + await supertestWithoutAuth + .get('/api/fleet/epm/packages') + .auth(testUsers.fleet_all_int_read.username, testUsers.fleet_all_int_read.password) + .expect(200); + }); + it('does not allow user with the correct permissions', async () => { + await supertestWithoutAuth + .get('/api/fleet/epm/packages') + .auth(testUsers.fleet_no_access.username, testUsers.fleet_no_access.password) + .expect(403); + }); }); }); } diff --git a/x-pack/test/fleet_api_integration/apis/test_users.ts b/x-pack/test/fleet_api_integration/apis/test_users.ts index a1df6d3a31b71b..d27ae1c4c29ae3 100644 --- a/x-pack/test/fleet_api_integration/apis/test_users.ts +++ b/x-pack/test/fleet_api_integration/apis/test_users.ts @@ -10,6 +10,28 @@ import type { SecurityService } from '../../../../test/common/services/security/ export const testUsers: { [rollName: string]: { username: string; password: string; permissions?: any }; } = { + fleet_all_int_all: { + permissions: { + feature: { + fleetv2: ['all'], + fleet: ['all'], + }, + spaces: ['*'], + }, + username: 'fleet_all_int_all', + password: 'changeme', + }, + setup: { + permissions: { + feature: { + fleetv2: ['all', 'setup'], + fleet: ['all'], + }, + spaces: ['*'], + }, + username: 'setup', + password: 'changeme', + }, fleet_no_access: { permissions: { feature: { @@ -20,24 +42,35 @@ export const testUsers: { username: 'fleet_no_access', password: 'changeme', }, - fleet_read_only: { + fleet_all_only: { + permissions: { + feature: { + fleetv2: ['all'], + }, + spaces: ['*'], + }, + username: 'fleet_all_only', + password: 'changeme', + }, + fleet_all_int_read: { permissions: { feature: { + fleetv2: ['all'], fleet: ['read'], }, spaces: ['*'], }, - username: 'fleet_read_only', + username: 'fleet_all_int_read', password: 'changeme', }, - fleet_all: { + integr_all_only: { permissions: { feature: { fleet: ['all'], }, spaces: ['*'], }, - username: 'fleet_all', + username: 'integr_all', password: 'changeme', }, }; From 4c3f8652ee510902aef5144b1d99f083a595627c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Thu, 10 Feb 2022 14:56:10 +0100 Subject: [PATCH 2/8] Bump Backport to 7.0.0 (#125188) --- package.json | 2 +- yarn.lock | 92 ++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 86 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index d0f659ffec9f7f..d663320636d654 100644 --- a/package.json +++ b/package.json @@ -732,7 +732,7 @@ "babel-plugin-require-context-hook": "^1.0.0", "babel-plugin-styled-components": "^2.0.2", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", - "backport": "6.1.5", + "backport": "7.0.0", "callsites": "^3.1.0", "chai": "3.5.0", "chance": "1.0.18", diff --git a/yarn.lock b/yarn.lock index 7b29962a36107e..68f16c85089753 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9120,6 +9120,11 @@ async@^3.1.0, async@^3.2.0: resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== +async@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" + integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -9224,6 +9229,13 @@ axios@^0.24.0: dependencies: follow-redirects "^1.14.4" +axios@^0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.25.0.tgz#349cfbb31331a9b4453190791760a8d35b093e0a" + integrity sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g== + dependencies: + follow-redirects "^1.14.7" + axobject-query@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" @@ -9521,16 +9533,18 @@ bach@^1.0.0: async-settle "^1.0.0" now-and-later "^2.0.0" -backport@6.1.5: - version "6.1.5" - resolved "https://registry.yarnpkg.com/backport/-/backport-6.1.5.tgz#2e8da121cd7ac89a51003f33fdd7febaa0a34202" - integrity sha512-fEn50S9P8mU3odGYZXNaj4LMTpio+zB2Vwq92wlu6u/fOQmkGvSxklp78NoAwSi8UBC3+vPa7G5zFp1uFLD6jg== +backport@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/backport/-/backport-7.0.0.tgz#4eadfd5e7b7e0ae7b6d0fa951d51e7631cb4e320" + integrity sha512-jg+kGNyZTGrUdtY+YMJozw+yW3bALbB/VIpn5tChsiWEEd+H5c5/fCRo7BA7J9z1fEbnpW2oSpcrxpmkJlANWw== dependencies: "@octokit/rest" "^18.12.0" - axios "^0.24.0" + axios "^0.25.0" dedent "^0.7.0" del "^6.0.0" + dotenv "^16.0.0" find-up "^5.0.0" + graphql-tag "^2.12.6" inquirer "^8.2.0" lodash "^4.17.21" make-dir "^3.1.0" @@ -9539,8 +9553,9 @@ backport@6.1.5: strip-json-comments "^3.1.1" terminal-link "^2.1.1" utility-types "^3.10.0" - winston "^3.3.3" + winston "^3.5.1" yargs "^17.3.1" + yargs-parser "^21.0.0" bail@^1.0.0: version "1.0.2" @@ -13393,6 +13408,11 @@ dotenv-webpack@^1.8.0: dependencies: dotenv-defaults "^1.0.2" +dotenv@^16.0.0: + version "16.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.0.tgz#c619001253be89ebb638d027b609c75c26e47411" + integrity sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q== + dotenv@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064" @@ -15321,6 +15341,11 @@ follow-redirects@^1.14.4: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.6.tgz#8cfb281bbc035b3c067d6cd975b0f6ade6e855cd" integrity sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A== +follow-redirects@^1.14.7: + version "1.14.8" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" + integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== + font-awesome@4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133" @@ -16212,6 +16237,13 @@ graphlib@^2.1.8: dependencies: lodash "^4.17.15" +graphql-tag@^2.12.6: + version "2.12.6" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" + integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== + dependencies: + tslib "^2.1.0" + grid-index@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/grid-index/-/grid-index-1.1.0.tgz#97f8221edec1026c8377b86446a7c71e79522ea7" @@ -20047,6 +20079,17 @@ logform@^2.2.0: ms "^2.1.1" triple-beam "^1.3.0" +logform@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.3.2.tgz#68babe6a74ab09a1fd15a9b1e6cbc7713d41cb5b" + integrity sha512-V6JiPThZzTsbVRspNO6TmHkR99oqYTs8fivMBYQkjZj6rxW92KxtDCPE6IkAk1DNBnYKNkjm4jYBm6JDUcyhOA== + dependencies: + colors "1.4.0" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^1.1.0" + triple-beam "^1.3.0" + loglevel@^1.6.8: version "1.6.8" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171" @@ -26098,6 +26141,16 @@ safe-squel@^5.12.5: dependencies: sql-escape-string "^1.1.0" +safe-stable-stringify@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz#c8a220ab525cd94e60ebf47ddc404d610dc5d84a" + integrity sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw== + +safe-stable-stringify@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz#ab67cbe1fe7d40603ca641c5e765cb942d04fc73" + integrity sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg== + "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -28789,7 +28842,7 @@ tsd@^0.13.1: read-pkg-up "^7.0.0" update-notifier "^4.1.0" -tslib@2.3.1, tslib@^2.3.0, tslib@~2.3.1: +tslib@2.3.1, tslib@^2.1.0, tslib@^2.3.0, tslib@~2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -30749,6 +30802,15 @@ winston-transport@^4.4.0: readable-stream "^2.3.7" triple-beam "^1.2.0" +winston-transport@^4.4.2: + version "4.5.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.5.0.tgz#6e7b0dd04d393171ed5e4e4905db265f7ab384fa" + integrity sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q== + dependencies: + logform "^2.3.2" + readable-stream "^3.6.0" + triple-beam "^1.3.0" + winston@^3.0.0, winston@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170" @@ -30764,6 +30826,22 @@ winston@^3.0.0, winston@^3.3.3: triple-beam "^1.3.0" winston-transport "^4.4.0" +winston@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.5.1.tgz#b25cc899d015836dbf8c583dec8c4c4483a0da2e" + integrity sha512-tbRtVy+vsSSCLcZq/8nXZaOie/S2tPXPFt4be/Q3vI/WtYwm7rrwidxVw2GRa38FIXcJ1kUM6MOZ9Jmnk3F3UA== + dependencies: + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.3.2" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.4.2" + wkt-parser@^1.2.4: version "1.3.2" resolved "https://registry.yarnpkg.com/wkt-parser/-/wkt-parser-1.3.2.tgz#deeff04a21edc5b170a60da418e9ed1d1ab0e219" From 35f51bb96bb819993be69d12a7d6cdc6124a3965 Mon Sep 17 00:00:00 2001 From: Gil Raphaelli Date: Thu, 10 Feb 2022 08:57:33 -0500 Subject: [PATCH 3/8] sync docs with new defaults for apm searchAggregatedTransactions setting (#125165) --- docs/settings/apm-settings.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/settings/apm-settings.asciidoc b/docs/settings/apm-settings.asciidoc index 27ea7f4dc7cd00..7441621f441f91 100644 --- a/docs/settings/apm-settings.asciidoc +++ b/docs/settings/apm-settings.asciidoc @@ -74,7 +74,7 @@ Changing these settings may disable features of the APM App. | Index name where Observability annotations are stored. Defaults to `observability-annotations`. | `xpack.apm.searchAggregatedTransactions` {ess-icon} - | experimental[] Enables Transaction histogram metrics. Defaults to `never` and aggregated transactions are not used. When set to `auto`, the UI will use metric indices over transaction indices for transactions if aggregated transactions are found. When set to `always`, additional configuration in APM Server is required. + | Enables Transaction histogram metrics. Defaults to `auto` so the UI will use metric indices over transaction indices for transactions if aggregated transactions are found. When set to `always`, additional configuration in APM Server is required. When set to `never` and aggregated transactions are not used. See {apm-guide-ref}/transaction-metrics.html[Configure transaction metrics] for more information. | `xpack.apm.metricsInterval` {ess-icon} From 1a0e4a50d5d57b2ebaff4070bcc2e34906e92020 Mon Sep 17 00:00:00 2001 From: Pete Hampton Date: Thu, 10 Feb 2022 14:04:55 +0000 Subject: [PATCH 4/8] count err status codes in security telemetry (#125120) --- .../security_solution/server/lib/telemetry/sender.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts index 07c5ea408cbdf4..4079d3eb9cc8e1 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts @@ -318,6 +318,14 @@ export class TelemetryEventsSender implements ITelemetryEventsSender { this.logger.debug(`Events sent!. Response: ${resp.status} ${JSON.stringify(resp.data)}`); } catch (err) { this.logger.debug(`Error sending events: ${err}`); + const errorStatus = err?.response?.status; + if (errorStatus !== undefined && errorStatus !== null) { + this.telemetryUsageCounter?.incrementCounter({ + counterName: createUsageCounterLabel(usageLabelPrefix.concat(['payloads', channel])), + counterType: errorStatus.toString(), + incrementBy: 1, + }); + } this.telemetryUsageCounter?.incrementCounter({ counterName: createUsageCounterLabel(usageLabelPrefix.concat(['payloads', channel])), counterType: 'docs_lost', From aff7c15e70ed0218fbd60ac20c693da1650042fe Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Thu, 10 Feb 2022 15:33:07 +0100 Subject: [PATCH 5/8] [Vega] Hide outdated inspector data in vega (#125051) --- .../public/vega_inspector/vega_adapter.ts | 15 +++++++++- .../vega_inspector/vega_data_inspector.tsx | 29 +++++++++++++++++-- .../vega/public/vega_view/vega_base_view.js | 6 ++-- .../vega/public/vega_visualization.ts | 1 + 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/plugins/vis_types/vega/public/vega_inspector/vega_adapter.ts b/src/plugins/vis_types/vega/public/vega_inspector/vega_adapter.ts index def7fefd551737..59be51ca9c439a 100644 --- a/src/plugins/vis_types/vega/public/vega_inspector/vega_adapter.ts +++ b/src/plugins/vis_types/vega/public/vega_inspector/vega_adapter.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; -import { Observable, ReplaySubject, fromEventPattern, merge, timer } from 'rxjs'; +import { Observable, ReplaySubject, fromEventPattern, merge, timer, BehaviorSubject } from 'rxjs'; import { map, switchMap, filter, debounce } from 'rxjs/operators'; import type { View, Spec } from 'vega'; import type { Assign } from '@kbn/utility-types'; @@ -81,6 +81,7 @@ const serializeColumns = (item: Record, columns: string[]) => { export class VegaAdapter { private debugValuesSubject = new ReplaySubject(); + private error = new BehaviorSubject(undefined); bindInspectValues(debugValues: DebugValues) { this.debugValuesSubject.next(debugValues); @@ -159,4 +160,16 @@ export class VegaAdapter { map((debugValues) => JSON.stringify(debugValues.spec, null, 2)) ); } + + getErrorObservable() { + return this.error.asObservable(); + } + + setError(error: string) { + this.error.next(error); + } + + clearError() { + this.error.next(undefined); + } } diff --git a/src/plugins/vis_types/vega/public/vega_inspector/vega_data_inspector.tsx b/src/plugins/vis_types/vega/public/vega_inspector/vega_data_inspector.tsx index 75618df307150e..91f159c86af987 100644 --- a/src/plugins/vis_types/vega/public/vega_inspector/vega_data_inspector.tsx +++ b/src/plugins/vis_types/vega/public/vega_inspector/vega_data_inspector.tsx @@ -8,8 +8,8 @@ import './vega_data_inspector.scss'; -import React from 'react'; -import { EuiTabbedContent } from '@elastic/eui'; +import React, { useState, useEffect } from 'react'; +import { EuiTabbedContent, EuiCallOut } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { VegaInspectorAdapters } from './vega_inspector'; @@ -31,6 +31,31 @@ const specLabel = i18n.translate('visTypeVega.inspector.specLabel', { }); const VegaDataInspector = ({ adapters }: VegaDataInspectorProps) => { + const [error, setError] = useState(); + + useEffect(() => { + const subscription = adapters.vega.getErrorObservable().subscribe((data) => { + setError(data); + }); + return () => { + subscription.unsubscribe(); + }; + }, [adapters.vega]); + + if (error) { + return ( + +

{error}

+
+ ); + } + const tabs = [ { id: 'data-viewer--id', diff --git a/src/plugins/vis_types/vega/public/vega_view/vega_base_view.js b/src/plugins/vis_types/vega/public/vega_view/vega_base_view.js index 23856950e34051..25cfcdb4dde045 100644 --- a/src/plugins/vis_types/vega/public/vega_view/vega_base_view.js +++ b/src/plugins/vis_types/vega/public/vega_view/vega_base_view.js @@ -106,7 +106,7 @@ export class VegaBaseView { } if (this._parser.error) { - this._addMessage('err', this._parser.error); + this.onError(this._parser.error); return; } @@ -235,7 +235,9 @@ export class VegaBaseView { } onError() { - this._addMessage('err', Utils.formatErrorToStr(...arguments)); + const error = Utils.formatErrorToStr(...arguments); + this._addMessage('err', error); + this._parser.searchAPI.inspectorAdapters?.vega.setError(error); } onWarn() { diff --git a/src/plugins/vis_types/vega/public/vega_visualization.ts b/src/plugins/vis_types/vega/public/vega_visualization.ts index 2ab55a0358f4df..f9a18067e68865 100644 --- a/src/plugins/vis_types/vega/public/vega_visualization.ts +++ b/src/plugins/vis_types/vega/public/vega_visualization.ts @@ -64,6 +64,7 @@ export const createVegaVisualization = ( async _render(vegaParser: VegaParser) { if (vegaParser) { + vegaParser.searchAPI.inspectorAdapters?.vega.clearError(); // New data received, rebuild the graph if (this.vegaView) { await this.vegaView.destroy(); From 178e7a7e4c98e00b6ad0fbea99d25e88490590f3 Mon Sep 17 00:00:00 2001 From: Andrew Tate Date: Thu, 10 Feb 2022 08:45:21 -0600 Subject: [PATCH 6/8] [TSVB] add rison helper and URL encoding for drilldown urls (#124185) --- .gitignore | 1 + docs/user/dashboard/tsvb.asciidoc | 24 +++++++++ .../components/lib/replace_vars.ts | 52 ++++++++++++++++++- .../components/vis_types/table/vis.js | 2 +- .../components/vis_types/top_n/vis.js | 2 +- .../vis_types/timeseries/tsconfig.json | 1 + 6 files changed, 78 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 18302cebd16418..818d3a472d52c3 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,7 @@ npm-debug.log* .ci/bash_standard_lib.sh .gradle .vagrant +.envrc ## @cypress/snapshot from apm plugin /snapshots.js diff --git a/docs/user/dashboard/tsvb.asciidoc b/docs/user/dashboard/tsvb.asciidoc index a1bad870dde46a..a097e34b20911f 100644 --- a/docs/user/dashboard/tsvb.asciidoc +++ b/docs/user/dashboard/tsvb.asciidoc @@ -191,6 +191,30 @@ For example `dashboards#/view/f193ca90-c9f4-11eb-b038-dd3270053a27`. . In the toolbar, click *Save as*, then make sure *Store time with dashboard* is deselected. ==== +[discrete] +[[how-do-i-base-drilldowns-on-data]] +.*How do I base drilldown URLs on my data?* +[%collapsible] +==== + +You can build drilldown URLs dynamically with your visualization data. + +Do this by adding the `{{key}}` placeholder to your URL + +For example `https://example.org/{{key}}` + +This instructs TSVB to substitute the value from your visualization wherever it sees `{{key}}`. + +If your data contain reserved or invalid URL characters such as "#" or "&", you should apply a transform to URL-encode the key like this `{{encodeURIComponent key}}`. If you are dynamically constructing a drilldown to another location in Kibana (for example, clicking a table row takes to you a value-scoped saved search), you will likely want to Rison-encode your key as it may contain invalid Rison characters. (https://github.com/Nanonid/rison#rison---compact-data-in-uris[Rison] is the serialization format many parts of Kibana use to store information in their URL.) + +For example: `discover#/view/0ac50180-82d9-11ec-9f4a-55de56b00cc0?_a=(filters:!((query:(match_phrase:(foo.keyword:{{rison key}})))))` + +If both conditions apply, you can cover all cases by applying both transforms: `{{encodeURIComponent (rison key)}}`. + +Technical note: TSVB uses https://handlebarsjs.com/[Handlebars] to perform these interpolations. `rison` and `encodeURIComponent` are custom Handlebars helpers provided by Kibana. + +==== + [discrete] [[why-is-my-tsvb-visualiztion-missing-data]] .*Why is my TSVB visualization missing data?* diff --git a/src/plugins/vis_types/timeseries/public/application/components/lib/replace_vars.ts b/src/plugins/vis_types/timeseries/public/application/components/lib/replace_vars.ts index 2862fe933bfb75..db152932fdbe5a 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/lib/replace_vars.ts +++ b/src/plugins/vis_types/timeseries/public/application/components/lib/replace_vars.ts @@ -6,11 +6,55 @@ * Side Public License, v 1. */ -import handlebars from 'handlebars'; +import { encode, RisonValue } from 'rison-node'; +import { + create as createHandlebars, + compile as compileHandlebars, + HelperDelegate, + HelperOptions, +} from 'handlebars'; import { i18n } from '@kbn/i18n'; import { emptyLabel } from '../../../../common/empty_label'; -type CompileOptions = Parameters[1]; +type CompileOptions = Parameters[1]; + +const handlebars = createHandlebars(); + +function createSerializationHelper( + fnName: string, + serializeFn: (value: unknown) => string +): HelperDelegate { + return (...args) => { + const { hash } = args.slice(-1)[0] as HelperOptions; + const hasHash = Object.keys(hash).length > 0; + const hasValues = args.length > 1; + if (hasHash && hasValues) { + throw new Error(`[${fnName}]: both value list and hash are not supported`); + } + if (hasHash) { + if (Object.values(hash).some((v) => typeof v === 'undefined')) + throw new Error(`[${fnName}]: unknown variable`); + return serializeFn(hash); + } else { + const values = args.slice(0, -1) as unknown[]; + if (values.some((value) => typeof value === 'undefined')) + throw new Error(`[${fnName}]: unknown variable`); + if (values.length === 0) throw new Error(`[${fnName}]: unknown variable`); + if (values.length === 1) return serializeFn(values[0]); + return serializeFn(values); + } + }; +} + +handlebars.registerHelper( + 'rison', + createSerializationHelper('rison', (v) => encode(v as RisonValue)) +); + +handlebars.registerHelper('encodeURIComponent', (component: unknown) => { + const str = String(component); + return encodeURIComponent(str); +}); export function replaceVars( str: string, @@ -24,6 +68,10 @@ export function replaceVars( const template = handlebars.compile(str.split(emptyLabel).join(`[${emptyLabel}]`), { strict: true, knownHelpersOnly: true, + knownHelpers: { + rison: true, + encodeURIComponent: true, + }, ...compileOptions, }); const string = template({ diff --git a/src/plugins/vis_types/timeseries/public/application/components/vis_types/table/vis.js b/src/plugins/vis_types/timeseries/public/application/components/vis_types/table/vis.js index 8f3d44c1ea2d65..3e828a1b833bf0 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/vis_types/table/vis.js +++ b/src/plugins/vis_types/timeseries/public/application/components/vis_types/table/vis.js @@ -88,7 +88,7 @@ class TableVis extends Component { } if (model.drilldown_url) { - const url = replaceVars(model.drilldown_url, {}, { key: row.key }); + const url = replaceVars(model.drilldown_url, {}, { key: row.key }, { noEscape: true }); const handleDrilldownUrlClick = this.createDrilldownUrlClickHandler(url); rowDisplay = ( { - const url = replaceVars(model.drilldown_url, {}, { key: item.label }); + const url = replaceVars(model.drilldown_url, {}, { key: item.label }, { noEscape: true }); const validatedUrl = coreStart.http.externalUrl.validateUrl(url); if (validatedUrl) { setAccessDeniedDrilldownUrl(null); diff --git a/src/plugins/vis_types/timeseries/tsconfig.json b/src/plugins/vis_types/timeseries/tsconfig.json index 2d12f987bd1db1..4462beae8c7be4 100644 --- a/src/plugins/vis_types/timeseries/tsconfig.json +++ b/src/plugins/vis_types/timeseries/tsconfig.json @@ -10,6 +10,7 @@ "common/**/*", "public/**/*", "server/**/*", + "../../../../typings/**/*", "*.ts" ], "references": [ From 5977b83900bc72f8ca83e4a7f5bcb713dfdd45c7 Mon Sep 17 00:00:00 2001 From: Kellen <9484709+goodroot@users.noreply.github.com> Date: Thu, 10 Feb 2022 07:09:52 -0800 Subject: [PATCH 7/8] Removes builder --- .github/workflows/dev-doc-builder.yml | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 .github/workflows/dev-doc-builder.yml diff --git a/.github/workflows/dev-doc-builder.yml b/.github/workflows/dev-doc-builder.yml deleted file mode 100644 index bbc8745854e483..00000000000000 --- a/.github/workflows/dev-doc-builder.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Dev docs -on: - pull_request_target: - paths: - - '**.mdx' - - '**.docnav.json' - - '**.docapi.json' - - '**.devdocs.json' - - '**.jpg' - - '**.jpeg' - - '**.png' - - '**.gif' - types: [closed, opened, synchronize, reopened] - -jobs: - internal-docs: - uses: elastic/workflows/.github/workflows/dev-docs-builder.yml@main - secrets: - VERCEL_GITHUB_TOKEN: ${{ secrets.VERCEL_GITHUB_TOKEN }} - VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID_DOCS_DEV: ${{ secrets.VERCEL_PROJECT_ID_DOCS_DEV }} From 8ee9765190e399e40735f2ec9c3b654f36f6dd95 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Thu, 10 Feb 2022 18:14:56 +0300 Subject: [PATCH 8/8] [Timelion] Remove unused /api/timelion/validate/es route (#125231) --- .../vis_types/timelion/server/plugin.ts | 2 - .../timelion/server/routes/validate_es.ts | 71 ------------------- 2 files changed, 73 deletions(-) delete mode 100644 src/plugins/vis_types/timelion/server/routes/validate_es.ts diff --git a/src/plugins/vis_types/timelion/server/plugin.ts b/src/plugins/vis_types/timelion/server/plugin.ts index b44aad5575b19c..37308e337ef465 100644 --- a/src/plugins/vis_types/timelion/server/plugin.ts +++ b/src/plugins/vis_types/timelion/server/plugin.ts @@ -17,7 +17,6 @@ import { CoreSetup, PluginInitializerContext, Plugin } from '../../../../../src/ import { configSchema } from '../config'; import loadFunctions from './lib/load_functions'; import { functionsRoute } from './routes/functions'; -import { validateEsRoute } from './routes/validate_es'; import { runRoute } from './routes/run'; import { ConfigManager } from './lib/config_manager'; import { getUiSettings } from './ui_settings'; @@ -66,7 +65,6 @@ export class TimelionPlugin implements Plugin) { - router.get( - { - path: '/api/timelion/validate/es', - validate: false, - }, - async function (context, request, response) { - const uiSettings = await context.core.uiSettings.client.getAll(); - - const timefield = uiSettings['timelion:es.timefield']; - - const body = { - params: { - index: uiSettings['es.default_index'], - body: { - aggs: { - maxAgg: { - max: { - field: timefield, - }, - }, - minAgg: { - min: { - field: timefield, - }, - }, - }, - size: 0, - }, - }, - }; - - let resp; - try { - resp = (await context.search!.search(body, {}).toPromise()).rawResponse; - } catch (errResp) { - resp = errResp; - } - - if (_.has(resp, 'aggregations.maxAgg.value') && _.has(resp, 'aggregations.minAgg.value')) { - return response.ok({ - body: { - ok: true, - field: timefield, - min: _.get(resp, 'aggregations.minAgg.value'), - max: _.get(resp, 'aggregations.maxAgg.value'), - }, - }); - } - - return response.ok({ - body: { - ok: false, - resp, - }, - }); - } - ); -}