diff --git a/.ci/Jenkinsfile_coverage b/.ci/Jenkinsfile_coverage index 01c18b10d0804..6b8dc31bab34e 100644 --- a/.ci/Jenkinsfile_coverage +++ b/.ci/Jenkinsfile_coverage @@ -3,110 +3,91 @@ library 'kibana-pipeline-library' kibanaLibrary.load() // load from the Jenkins instance -stage("Kibana Pipeline") { // This stage is just here to help the BlueOcean UI a little bit - timeout(time: 180, unit: 'MINUTES') { - timestamps { - ansiColor('xterm') { - catchError { +kibanaPipeline(timeoutMinutes: 180) { + catchErrors { + withEnv([ + 'CODE_COVERAGE=1', // Needed for multiple ci scripts, such as remote.ts, test/scripts/*.sh, schema.js, etc. + ]) { + parallel([ + 'kibana-intake-agent': workers.intake('kibana-intake', './test/scripts/jenkins_unit.sh'), + 'x-pack-intake-agent': { withEnv([ - 'CODE_COVERAGE=1', // Needed for multiple ci scripts, such as remote.ts, test/scripts/*.sh, schema.js, etc. + 'NODE_ENV=test' // Needed for jest tests only ]) { - parallel([ - 'kibana-intake-agent': { - withEnv([ - 'NODE_ENV=test' // Needed for jest tests only - ]) { - kibanaPipeline.intakeWorker('kibana-intake', './test/scripts/jenkins_unit.sh')() - } - }, - 'x-pack-intake-agent': { - withEnv([ - 'NODE_ENV=test' // Needed for jest tests only - ]) { - kibanaPipeline.intakeWorker('x-pack-intake', './test/scripts/jenkins_xpack.sh')() - } - }, - 'kibana-oss-agent': kibanaPipeline.withWorkers('kibana-oss-tests', { kibanaPipeline.buildOss() }, [ - 'oss-ciGroup1': kibanaPipeline.getOssCiGroupWorker(1), - 'oss-ciGroup2': kibanaPipeline.getOssCiGroupWorker(2), - 'oss-ciGroup3': kibanaPipeline.getOssCiGroupWorker(3), - 'oss-ciGroup4': kibanaPipeline.getOssCiGroupWorker(4), - 'oss-ciGroup5': kibanaPipeline.getOssCiGroupWorker(5), - 'oss-ciGroup6': kibanaPipeline.getOssCiGroupWorker(6), - 'oss-ciGroup7': kibanaPipeline.getOssCiGroupWorker(7), - 'oss-ciGroup8': kibanaPipeline.getOssCiGroupWorker(8), - 'oss-ciGroup9': kibanaPipeline.getOssCiGroupWorker(9), - 'oss-ciGroup10': kibanaPipeline.getOssCiGroupWorker(10), - 'oss-ciGroup11': kibanaPipeline.getOssCiGroupWorker(11), - 'oss-ciGroup12': kibanaPipeline.getOssCiGroupWorker(12), - ]), - 'kibana-xpack-agent-1': kibanaPipeline.withWorkers('kibana-xpack-tests-1', { kibanaPipeline.buildXpack() }, [ - 'xpack-ciGroup1': kibanaPipeline.getXpackCiGroupWorker(1), - 'xpack-ciGroup2': kibanaPipeline.getXpackCiGroupWorker(2), - ]), - 'kibana-xpack-agent-2': kibanaPipeline.withWorkers('kibana-xpack-tests-2', { kibanaPipeline.buildXpack() }, [ - 'xpack-ciGroup3': kibanaPipeline.getXpackCiGroupWorker(3), - 'xpack-ciGroup4': kibanaPipeline.getXpackCiGroupWorker(4), - ]), - - 'kibana-xpack-agent-3': kibanaPipeline.withWorkers('kibana-xpack-tests-3', { kibanaPipeline.buildXpack() }, [ - 'xpack-ciGroup5': kibanaPipeline.getXpackCiGroupWorker(5), - 'xpack-ciGroup6': kibanaPipeline.getXpackCiGroupWorker(6), - 'xpack-ciGroup7': kibanaPipeline.getXpackCiGroupWorker(7), - 'xpack-ciGroup8': kibanaPipeline.getXpackCiGroupWorker(8), - 'xpack-ciGroup9': kibanaPipeline.getXpackCiGroupWorker(9), - 'xpack-ciGroup10': kibanaPipeline.getXpackCiGroupWorker(10), - ]), - ]) - kibanaPipeline.jobRunner('tests-l', false) { - kibanaPipeline.downloadCoverageArtifacts() - kibanaPipeline.bash( - ''' - # bootstrap from x-pack folder - source src/dev/ci_setup/setup_env.sh - cd x-pack - yarn kbn bootstrap --prefer-offline - cd .. - # extract archives - mkdir -p /tmp/extracted_coverage - echo extracting intakes - tar -xzf /tmp/downloaded_coverage/coverage/kibana-intake/kibana-coverage.tar.gz -C /tmp/extracted_coverage - tar -xzf /tmp/downloaded_coverage/coverage/x-pack-intake/kibana-coverage.tar.gz -C /tmp/extracted_coverage - echo extracting kibana-oss-tests - tar -xzf /tmp/downloaded_coverage/coverage/kibana-oss-tests/kibana-coverage.tar.gz -C /tmp/extracted_coverage - echo extracting kibana-xpack-tests - for i in {1..3}; do - tar -xzf /tmp/downloaded_coverage/coverage/kibana-xpack-tests-${i}/kibana-coverage.tar.gz -C /tmp/extracted_coverage - done - # replace path in json files to have valid html report - pwd=$(pwd) - du -sh /tmp/extracted_coverage/target/kibana-coverage/ - echo replacing path in json files - for i in {1..9}; do - sed -i "s|/dev/shm/workspace/kibana|$pwd|g" /tmp/extracted_coverage/target/kibana-coverage/functional/${i}*.json & - done - wait - # merge oss & x-pack reports - echo merging coverage reports - yarn nyc report --temp-dir /tmp/extracted_coverage/target/kibana-coverage/jest --report-dir target/kibana-coverage/jest-combined --reporter=html --reporter=json-summary - yarn nyc report --temp-dir /tmp/extracted_coverage/target/kibana-coverage/functional --report-dir target/kibana-coverage/functional-combined --reporter=html --reporter=json-summary - echo copy mocha reports - mkdir -p target/kibana-coverage/mocha-combined - cp -r /tmp/extracted_coverage/target/kibana-coverage/mocha target/kibana-coverage/mocha-combined - ''', - "run `yarn kbn bootstrap && merge coverage`" - ) - sh 'tar -czf kibana-jest-coverage.tar.gz target/kibana-coverage/jest-combined/*' - kibanaPipeline.uploadCoverageArtifacts("coverage/jest-combined", 'kibana-jest-coverage.tar.gz') - sh 'tar -czf kibana-functional-coverage.tar.gz target/kibana-coverage/functional-combined/*' - kibanaPipeline.uploadCoverageArtifacts("coverage/functional-combined", 'kibana-functional-coverage.tar.gz') - sh 'tar -czf kibana-mocha-coverage.tar.gz target/kibana-coverage/mocha-combined/*' - kibanaPipeline.uploadCoverageArtifacts("coverage/mocha-combined", 'kibana-mocha-coverage.tar.gz') - } + workers.intake('x-pack-intake', './test/scripts/jenkins_xpack.sh')() } - } - kibanaPipeline.sendMail() + }, + 'kibana-oss-agent': workers.functional('kibana-oss-tests', { kibanaPipeline.buildOss() }, [ + 'oss-ciGroup1': kibanaPipeline.ossCiGroupProcess(1), + 'oss-ciGroup2': kibanaPipeline.ossCiGroupProcess(2), + 'oss-ciGroup3': kibanaPipeline.ossCiGroupProcess(3), + 'oss-ciGroup4': kibanaPipeline.ossCiGroupProcess(4), + 'oss-ciGroup5': kibanaPipeline.ossCiGroupProcess(5), + 'oss-ciGroup6': kibanaPipeline.ossCiGroupProcess(6), + 'oss-ciGroup7': kibanaPipeline.ossCiGroupProcess(7), + 'oss-ciGroup8': kibanaPipeline.ossCiGroupProcess(8), + 'oss-ciGroup9': kibanaPipeline.ossCiGroupProcess(9), + 'oss-ciGroup10': kibanaPipeline.ossCiGroupProcess(10), + 'oss-ciGroup11': kibanaPipeline.ossCiGroupProcess(11), + 'oss-ciGroup12': kibanaPipeline.ossCiGroupProcess(12), + ]), + 'kibana-xpack-agent': workers.functional('kibana-xpack-tests', { kibanaPipeline.buildXpack() }, [ + 'xpack-ciGroup1': kibanaPipeline.xpackCiGroupProcess(1), + 'xpack-ciGroup2': kibanaPipeline.xpackCiGroupProcess(2), + 'xpack-ciGroup3': kibanaPipeline.xpackCiGroupProcess(3), + 'xpack-ciGroup4': kibanaPipeline.xpackCiGroupProcess(4), + 'xpack-ciGroup5': kibanaPipeline.xpackCiGroupProcess(5), + 'xpack-ciGroup6': kibanaPipeline.xpackCiGroupProcess(6), + 'xpack-ciGroup7': kibanaPipeline.xpackCiGroupProcess(7), + 'xpack-ciGroup8': kibanaPipeline.xpackCiGroupProcess(8), + 'xpack-ciGroup9': kibanaPipeline.xpackCiGroupProcess(9), + 'xpack-ciGroup10': kibanaPipeline.xpackCiGroupProcess(10), + ]), + ]) + workers.base(name: 'coverage-worker', label: 'tests-l', ramDisk: false, bootstrapped: false) { + kibanaPipeline.downloadCoverageArtifacts() + kibanaPipeline.bash( + ''' + # bootstrap from x-pack folder + source src/dev/ci_setup/setup_env.sh + cd x-pack + yarn kbn bootstrap --prefer-offline + cd .. + # extract archives + mkdir -p /tmp/extracted_coverage + echo extracting intakes + tar -xzf /tmp/downloaded_coverage/coverage/kibana-intake/kibana-coverage.tar.gz -C /tmp/extracted_coverage + tar -xzf /tmp/downloaded_coverage/coverage/x-pack-intake/kibana-coverage.tar.gz -C /tmp/extracted_coverage + echo extracting kibana-oss-tests + tar -xzf /tmp/downloaded_coverage/coverage/kibana-oss-tests/kibana-coverage.tar.gz -C /tmp/extracted_coverage + echo extracting kibana-xpack-tests + tar -xzf /tmp/downloaded_coverage/coverage/kibana-xpack-tests/kibana-coverage.tar.gz -C /tmp/extracted_coverage + # replace path in json files to have valid html report + pwd=$(pwd) + du -sh /tmp/extracted_coverage/target/kibana-coverage/ + echo replacing path in json files + for i in {1..9}; do + sed -i "s|/dev/shm/workspace/kibana|$pwd|g" /tmp/extracted_coverage/target/kibana-coverage/functional/${i}*.json & + done + wait + # merge oss & x-pack reports + echo merging coverage reports + yarn nyc report --temp-dir /tmp/extracted_coverage/target/kibana-coverage/jest --report-dir target/kibana-coverage/jest-combined --reporter=html --reporter=json-summary + yarn nyc report --temp-dir /tmp/extracted_coverage/target/kibana-coverage/functional --report-dir target/kibana-coverage/functional-combined --reporter=html --reporter=json-summary + echo copy mocha reports + mkdir -p target/kibana-coverage/mocha-combined + cp -r /tmp/extracted_coverage/target/kibana-coverage/mocha target/kibana-coverage/mocha-combined + ''', + "run `yarn kbn bootstrap && merge coverage`" + ) + sh 'tar -czf kibana-jest-coverage.tar.gz target/kibana-coverage/jest-combined/*' + kibanaPipeline.uploadCoverageArtifacts("coverage/jest-combined", 'kibana-jest-coverage.tar.gz') + sh 'tar -czf kibana-functional-coverage.tar.gz target/kibana-coverage/functional-combined/*' + kibanaPipeline.uploadCoverageArtifacts("coverage/functional-combined", 'kibana-functional-coverage.tar.gz') + sh 'tar -czf kibana-mocha-coverage.tar.gz target/kibana-coverage/mocha-combined/*' + kibanaPipeline.uploadCoverageArtifacts("coverage/mocha-combined", 'kibana-mocha-coverage.tar.gz') } } } + kibanaPipeline.sendMail() } diff --git a/.ci/Jenkinsfile_flaky b/.ci/Jenkinsfile_flaky index f702405aad69e..befb8d259b5b6 100644 --- a/.ci/Jenkinsfile_flaky +++ b/.ci/Jenkinsfile_flaky @@ -21,53 +21,47 @@ def workerFailures = [] currentBuild.displayName += trunc(" ${params.GITHUB_OWNER}:${params.branch_specifier}", 24) currentBuild.description = "${params.CI_GROUP}
Agents: ${AGENT_COUNT}
Executions: ${params.NUMBER_EXECUTIONS}" -stage("Kibana Pipeline") { - timeout(time: 180, unit: 'MINUTES') { - timestamps { - ansiColor('xterm') { - def agents = [:] - for(def agentNumber = 1; agentNumber <= AGENT_COUNT; agentNumber++) { - def agentNumberInside = agentNumber - def agentExecutions = floor(EXECUTIONS/AGENT_COUNT) + (agentNumber <= EXECUTIONS%AGENT_COUNT ? 1 : 0) - agents["agent-${agentNumber}"] = { - catchError { - print "Agent ${agentNumberInside} - ${agentExecutions} executions" - - kibanaPipeline.withWorkers('flaky-test-runner', { - if (NEED_BUILD) { - if (!IS_XPACK) { - kibanaPipeline.buildOss() - if (CI_GROUP == '1') { - runbld("./test/scripts/jenkins_build_kbn_tp_sample_panel_action.sh", "Build kbn tp sample panel action for ciGroup1") - } - } else { - kibanaPipeline.buildXpack() - } - } - }, getWorkerMap(agentNumberInside, agentExecutions, worker, workerFailures))() +kibanaPipeline(timeoutMinutes: 180) { + def agents = [:] + for(def agentNumber = 1; agentNumber <= AGENT_COUNT; agentNumber++) { + def agentNumberInside = agentNumber + def agentExecutions = floor(EXECUTIONS/AGENT_COUNT) + (agentNumber <= EXECUTIONS%AGENT_COUNT ? 1 : 0) + agents["agent-${agentNumber}"] = { + catchErrors { + print "Agent ${agentNumberInside} - ${agentExecutions} executions" + + workers.functional('flaky-test-runner', { + if (NEED_BUILD) { + if (!IS_XPACK) { + kibanaPipeline.buildOss() + if (CI_GROUP == '1') { + runbld("./test/scripts/jenkins_build_kbn_tp_sample_panel_action.sh", "Build kbn tp sample panel action for ciGroup1") + } + } else { + kibanaPipeline.buildXpack() } } - } + }, getWorkerMap(agentNumberInside, agentExecutions, worker, workerFailures))() + } + } + } - parallel(agents) + parallel(agents) - currentBuild.description += ", Failures: ${workerFailures.size()}" + currentBuild.description += ", Failures: ${workerFailures.size()}" - if (workerFailures.size() > 0) { - print "There were ${workerFailures.size()} test suite failures." - print "The executions that failed were:" - print workerFailures.join("\n") - print "Please check 'Test Result' and 'Pipeline Steps' pages for more info" - } - } - } + if (workerFailures.size() > 0) { + print "There were ${workerFailures.size()} test suite failures." + print "The executions that failed were:" + print workerFailures.join("\n") + print "Please check 'Test Result' and 'Pipeline Steps' pages for more info" } } def getWorkerFromParams(isXpack, job, ciGroup) { if (!isXpack) { if (job == 'serverMocha') { - return kibanaPipeline.getPostBuildWorker('serverMocha', { + return kibanaPipeline.functionalTestProcess('serverMocha', { kibanaPipeline.bash( """ source src/dev/ci_setup/setup_env.sh @@ -77,20 +71,20 @@ def getWorkerFromParams(isXpack, job, ciGroup) { ) }) } else if (job == 'firefoxSmoke') { - return kibanaPipeline.getPostBuildWorker('firefoxSmoke', { runbld('./test/scripts/jenkins_firefox_smoke.sh', 'Execute kibana-firefoxSmoke') }) + return kibanaPipeline.functionalTestProcess('firefoxSmoke', './test/scripts/jenkins_firefox_smoke.sh') } else if(job == 'visualRegression') { - return kibanaPipeline.getPostBuildWorker('visualRegression', { runbld('./test/scripts/jenkins_visual_regression.sh', 'Execute kibana-visualRegression') }) + return kibanaPipeline.functionalTestProcess('visualRegression', './test/scripts/jenkins_visual_regression.sh') } else { - return kibanaPipeline.getOssCiGroupWorker(ciGroup) + return kibanaPipeline.ossCiGroupProcess(ciGroup) } } if (job == 'firefoxSmoke') { - return kibanaPipeline.getPostBuildWorker('xpack-firefoxSmoke', { runbld('./test/scripts/jenkins_xpack_firefox_smoke.sh', 'Execute xpack-firefoxSmoke') }) + return kibanaPipeline.functionalTestProcess('xpack-firefoxSmoke', './test/scripts/jenkins_xpack_firefox_smoke.sh') } else if(job == 'visualRegression') { - return kibanaPipeline.getPostBuildWorker('xpack-visualRegression', { runbld('./test/scripts/jenkins_xpack_visual_regression.sh', 'Execute xpack-visualRegression') }) + return kibanaPipeline.functionalTestProcess('xpack-visualRegression', './test/scripts/jenkins_xpack_visual_regression.sh') } else { - return kibanaPipeline.getXpackCiGroupWorker(ciGroup) + return kibanaPipeline.xpackCiGroupProcess(ciGroup) } } @@ -105,10 +99,9 @@ def getWorkerMap(agentNumber, numberOfExecutions, worker, workerFailures, maxWor for(def j = 0; j < workerExecutions; j++) { print "Execute agent-${agentNumber} worker-${workerNumber}: ${j}" withEnv([ - "JOB=agent-${agentNumber}-worker-${workerNumber}-${j}", "REMOVE_KIBANA_INSTALL_DIR=1", ]) { - catchError { + catchErrors { try { worker(workerNumber) } catch (ex) { diff --git a/.ci/es-snapshots/Jenkinsfile_build_es b/.ci/es-snapshots/Jenkinsfile_build_es index ad0ad54275e12..a00bcb3bbc946 100644 --- a/.ci/es-snapshots/Jenkinsfile_build_es +++ b/.ci/es-snapshots/Jenkinsfile_build_es @@ -26,7 +26,7 @@ timeout(time: 120, unit: 'MINUTES') { timestamps { ansiColor('xterm') { node('linux && immutable') { - catchError { + catchErrors { def VERSION def SNAPSHOT_ID def DESTINATION diff --git a/.ci/es-snapshots/Jenkinsfile_verify_es b/.ci/es-snapshots/Jenkinsfile_verify_es index 30d52a56547bd..ce472a404c053 100644 --- a/.ci/es-snapshots/Jenkinsfile_verify_es +++ b/.ci/es-snapshots/Jenkinsfile_verify_es @@ -19,50 +19,45 @@ currentBuild.description = "ES: ${SNAPSHOT_VERSION}
Kibana: ${params.branch def SNAPSHOT_MANIFEST = "https://storage.googleapis.com/kibana-ci-es-snapshots-daily/${SNAPSHOT_VERSION}/archives/${SNAPSHOT_ID}/manifest.json" -timeout(time: 120, unit: 'MINUTES') { - timestamps { - ansiColor('xterm') { - catchError { - withEnv(["ES_SNAPSHOT_MANIFEST=${SNAPSHOT_MANIFEST}"]) { - parallel([ - // TODO we just need to run integration tests from intake? - 'kibana-intake-agent': kibanaPipeline.intakeWorker('kibana-intake', './test/scripts/jenkins_unit.sh'), - 'x-pack-intake-agent': kibanaPipeline.intakeWorker('x-pack-intake', './test/scripts/jenkins_xpack.sh'), - 'kibana-oss-agent': kibanaPipeline.withWorkers('kibana-oss-tests', { kibanaPipeline.buildOss() }, [ - 'oss-ciGroup1': kibanaPipeline.getOssCiGroupWorker(1), - 'oss-ciGroup2': kibanaPipeline.getOssCiGroupWorker(2), - 'oss-ciGroup3': kibanaPipeline.getOssCiGroupWorker(3), - 'oss-ciGroup4': kibanaPipeline.getOssCiGroupWorker(4), - 'oss-ciGroup5': kibanaPipeline.getOssCiGroupWorker(5), - 'oss-ciGroup6': kibanaPipeline.getOssCiGroupWorker(6), - 'oss-ciGroup7': kibanaPipeline.getOssCiGroupWorker(7), - 'oss-ciGroup8': kibanaPipeline.getOssCiGroupWorker(8), - 'oss-ciGroup9': kibanaPipeline.getOssCiGroupWorker(9), - 'oss-ciGroup10': kibanaPipeline.getOssCiGroupWorker(10), - 'oss-ciGroup11': kibanaPipeline.getOssCiGroupWorker(11), - 'oss-ciGroup12': kibanaPipeline.getOssCiGroupWorker(12), - ]), - 'kibana-xpack-agent': kibanaPipeline.withWorkers('kibana-xpack-tests', { kibanaPipeline.buildXpack() }, [ - 'xpack-ciGroup1': kibanaPipeline.getXpackCiGroupWorker(1), - 'xpack-ciGroup2': kibanaPipeline.getXpackCiGroupWorker(2), - 'xpack-ciGroup3': kibanaPipeline.getXpackCiGroupWorker(3), - 'xpack-ciGroup4': kibanaPipeline.getXpackCiGroupWorker(4), - 'xpack-ciGroup5': kibanaPipeline.getXpackCiGroupWorker(5), - 'xpack-ciGroup6': kibanaPipeline.getXpackCiGroupWorker(6), - 'xpack-ciGroup7': kibanaPipeline.getXpackCiGroupWorker(7), - 'xpack-ciGroup8': kibanaPipeline.getXpackCiGroupWorker(8), - 'xpack-ciGroup9': kibanaPipeline.getXpackCiGroupWorker(9), - 'xpack-ciGroup10': kibanaPipeline.getXpackCiGroupWorker(10), - ]), - ]) - } - - promoteSnapshot(SNAPSHOT_VERSION, SNAPSHOT_ID) - } - - kibanaPipeline.sendMail() +kibanaPipeline(timeoutMinutes: 120) { + catchErrors { + withEnv(["ES_SNAPSHOT_MANIFEST=${SNAPSHOT_MANIFEST}"]) { + parallel([ + 'kibana-intake-agent': workers.intake('kibana-intake', './test/scripts/jenkins_unit.sh'), + 'x-pack-intake-agent': workers.intake('x-pack-intake', './test/scripts/jenkins_xpack.sh'), + 'kibana-oss-agent': workers.functional('kibana-oss-tests', { kibanaPipeline.buildOss() }, [ + 'oss-ciGroup1': kibanaPipeline.ossCiGroupProcess(1), + 'oss-ciGroup2': kibanaPipeline.ossCiGroupProcess(2), + 'oss-ciGroup3': kibanaPipeline.ossCiGroupProcess(3), + 'oss-ciGroup4': kibanaPipeline.ossCiGroupProcess(4), + 'oss-ciGroup5': kibanaPipeline.ossCiGroupProcess(5), + 'oss-ciGroup6': kibanaPipeline.ossCiGroupProcess(6), + 'oss-ciGroup7': kibanaPipeline.ossCiGroupProcess(7), + 'oss-ciGroup8': kibanaPipeline.ossCiGroupProcess(8), + 'oss-ciGroup9': kibanaPipeline.ossCiGroupProcess(9), + 'oss-ciGroup10': kibanaPipeline.ossCiGroupProcess(10), + 'oss-ciGroup11': kibanaPipeline.ossCiGroupProcess(11), + 'oss-ciGroup12': kibanaPipeline.ossCiGroupProcess(12), + ]), + 'kibana-xpack-agent': workers.functional('kibana-xpack-tests', { kibanaPipeline.buildXpack() }, [ + 'xpack-ciGroup1': kibanaPipeline.xpackCiGroupProcess(1), + 'xpack-ciGroup2': kibanaPipeline.xpackCiGroupProcess(2), + 'xpack-ciGroup3': kibanaPipeline.xpackCiGroupProcess(3), + 'xpack-ciGroup4': kibanaPipeline.xpackCiGroupProcess(4), + 'xpack-ciGroup5': kibanaPipeline.xpackCiGroupProcess(5), + 'xpack-ciGroup6': kibanaPipeline.xpackCiGroupProcess(6), + 'xpack-ciGroup7': kibanaPipeline.xpackCiGroupProcess(7), + 'xpack-ciGroup8': kibanaPipeline.xpackCiGroupProcess(8), + 'xpack-ciGroup9': kibanaPipeline.xpackCiGroupProcess(9), + 'xpack-ciGroup10': kibanaPipeline.xpackCiGroupProcess(10), + ]), + ]) } + + promoteSnapshot(SNAPSHOT_VERSION, SNAPSHOT_ID) } + + kibanaPipeline.sendMail() } def promoteSnapshot(snapshotVersion, snapshotId) { diff --git a/Jenkinsfile b/Jenkinsfile index 0602f0417c629..85502369b07be 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -3,71 +3,49 @@ library 'kibana-pipeline-library' kibanaLibrary.load() -stage("Kibana Pipeline") { // This stage is just here to help the BlueOcean UI a little bit - timeout(time: 135, unit: 'MINUTES') { - timestamps { - ansiColor('xterm') { - githubPr.withDefaultPrComments { - catchError { - retryable.enable() - parallel([ - 'kibana-intake-agent': kibanaPipeline.intakeWorker('kibana-intake', './test/scripts/jenkins_unit.sh'), - 'x-pack-intake-agent': kibanaPipeline.intakeWorker('x-pack-intake', './test/scripts/jenkins_xpack.sh'), - 'kibana-oss-agent': kibanaPipeline.withWorkers('kibana-oss-tests', { kibanaPipeline.buildOss() }, [ - // 'oss-firefoxSmoke': kibanaPipeline.getPostBuildWorker('firefoxSmoke', { - // retryable('kibana-firefoxSmoke') { - // runbld('./test/scripts/jenkins_firefox_smoke.sh', 'Execute kibana-firefoxSmoke') - // } - // }), - 'oss-ciGroup1': kibanaPipeline.getOssCiGroupWorker(1), - 'oss-ciGroup2': kibanaPipeline.getOssCiGroupWorker(2), - 'oss-ciGroup3': kibanaPipeline.getOssCiGroupWorker(3), - 'oss-ciGroup4': kibanaPipeline.getOssCiGroupWorker(4), - 'oss-ciGroup5': kibanaPipeline.getOssCiGroupWorker(5), - 'oss-ciGroup6': kibanaPipeline.getOssCiGroupWorker(6), - 'oss-ciGroup7': kibanaPipeline.getOssCiGroupWorker(7), - 'oss-ciGroup8': kibanaPipeline.getOssCiGroupWorker(8), - 'oss-ciGroup9': kibanaPipeline.getOssCiGroupWorker(9), - 'oss-ciGroup10': kibanaPipeline.getOssCiGroupWorker(10), - 'oss-ciGroup11': kibanaPipeline.getOssCiGroupWorker(11), - 'oss-ciGroup12': kibanaPipeline.getOssCiGroupWorker(12), - 'oss-accessibility': kibanaPipeline.getPostBuildWorker('accessibility', { - retryable('kibana-accessibility') { - runbld('./test/scripts/jenkins_accessibility.sh', 'Execute accessibility tests') - } - }), - // 'oss-visualRegression': kibanaPipeline.getPostBuildWorker('visualRegression', { runbld('./test/scripts/jenkins_visual_regression.sh', 'Execute kibana-visualRegression') }), - ]), - 'kibana-xpack-agent': kibanaPipeline.withWorkers('kibana-xpack-tests', { kibanaPipeline.buildXpack() }, [ - // 'xpack-firefoxSmoke': kibanaPipeline.getPostBuildWorker('xpack-firefoxSmoke', { - // retryable('xpack-firefoxSmoke') { - // runbld('./test/scripts/jenkins_xpack_firefox_smoke.sh', 'Execute xpack-firefoxSmoke') - // } - // }), - 'xpack-ciGroup1': kibanaPipeline.getXpackCiGroupWorker(1), - 'xpack-ciGroup2': kibanaPipeline.getXpackCiGroupWorker(2), - 'xpack-ciGroup3': kibanaPipeline.getXpackCiGroupWorker(3), - 'xpack-ciGroup4': kibanaPipeline.getXpackCiGroupWorker(4), - 'xpack-ciGroup5': kibanaPipeline.getXpackCiGroupWorker(5), - 'xpack-ciGroup6': kibanaPipeline.getXpackCiGroupWorker(6), - 'xpack-ciGroup7': kibanaPipeline.getXpackCiGroupWorker(7), - 'xpack-ciGroup8': kibanaPipeline.getXpackCiGroupWorker(8), - 'xpack-ciGroup9': kibanaPipeline.getXpackCiGroupWorker(9), - 'xpack-ciGroup10': kibanaPipeline.getXpackCiGroupWorker(10), - 'xpack-accessibility': kibanaPipeline.getPostBuildWorker('xpack-accessibility', { - retryable('xpack-accessibility') { - runbld('./test/scripts/jenkins_xpack_accessibility.sh', 'Execute xpack-accessibility tests') - } - }), - // 'xpack-visualRegression': kibanaPipeline.getPostBuildWorker('xpack-visualRegression', { runbld('./test/scripts/jenkins_xpack_visual_regression.sh', 'Execute xpack-visualRegression') }), - ]), - ]) - } - } - - retryable.printFlakyFailures() - kibanaPipeline.sendMail() - } +kibanaPipeline(timeoutMinutes: 135) { + githubPr.withDefaultPrComments { + catchError { + retryable.enable() + parallel([ + 'kibana-intake-agent': workers.intake('kibana-intake', './test/scripts/jenkins_unit.sh'), + 'x-pack-intake-agent': workers.intake('x-pack-intake', './test/scripts/jenkins_xpack.sh'), + 'kibana-oss-agent': workers.functional('kibana-oss-tests', { kibanaPipeline.buildOss() }, [ + // 'oss-firefoxSmoke': kibanaPipeline.functionalTestProcess('kibana-firefoxSmoke', './test/scripts/jenkins_firefox_smoke.sh'), + 'oss-ciGroup1': kibanaPipeline.ossCiGroupProcess(1), + 'oss-ciGroup2': kibanaPipeline.ossCiGroupProcess(2), + 'oss-ciGroup3': kibanaPipeline.ossCiGroupProcess(3), + 'oss-ciGroup4': kibanaPipeline.ossCiGroupProcess(4), + 'oss-ciGroup5': kibanaPipeline.ossCiGroupProcess(5), + 'oss-ciGroup6': kibanaPipeline.ossCiGroupProcess(6), + 'oss-ciGroup7': kibanaPipeline.ossCiGroupProcess(7), + 'oss-ciGroup8': kibanaPipeline.ossCiGroupProcess(8), + 'oss-ciGroup9': kibanaPipeline.ossCiGroupProcess(9), + 'oss-ciGroup10': kibanaPipeline.ossCiGroupProcess(10), + 'oss-ciGroup11': kibanaPipeline.ossCiGroupProcess(11), + 'oss-ciGroup12': kibanaPipeline.ossCiGroupProcess(12), + 'oss-accessibility': kibanaPipeline.functionalTestProcess('kibana-accessibility', './test/scripts/jenkins_accessibility.sh'), + // 'oss-visualRegression': kibanaPipeline.functionalTestProcess('visualRegression', './test/scripts/jenkins_visual_regression.sh'), + ]), + 'kibana-xpack-agent': workers.functional('kibana-xpack-tests', { kibanaPipeline.buildXpack() }, [ + // 'xpack-firefoxSmoke': kibanaPipeline.functionalTestProcess('xpack-firefoxSmoke', './test/scripts/jenkins_xpack_firefox_smoke.sh'), + 'xpack-ciGroup1': kibanaPipeline.xpackCiGroupProcess(1), + 'xpack-ciGroup2': kibanaPipeline.xpackCiGroupProcess(2), + 'xpack-ciGroup3': kibanaPipeline.xpackCiGroupProcess(3), + 'xpack-ciGroup4': kibanaPipeline.xpackCiGroupProcess(4), + 'xpack-ciGroup5': kibanaPipeline.xpackCiGroupProcess(5), + 'xpack-ciGroup6': kibanaPipeline.xpackCiGroupProcess(6), + 'xpack-ciGroup7': kibanaPipeline.xpackCiGroupProcess(7), + 'xpack-ciGroup8': kibanaPipeline.xpackCiGroupProcess(8), + 'xpack-ciGroup9': kibanaPipeline.xpackCiGroupProcess(9), + 'xpack-ciGroup10': kibanaPipeline.xpackCiGroupProcess(10), + 'xpack-accessibility': kibanaPipeline.functionalTestProcess('xpack-accessibility', './test/scripts/jenkins_xpack_accessibility.sh'), + // 'xpack-visualRegression': kibanaPipeline.functionalTestProcess('xpack-visualRegression', './test/scripts/jenkins_xpack_visual_regression.sh'), + ]), + ]) } } + + retryable.printFlakyFailures() + kibanaPipeline.sendMail() } diff --git a/docs/images/visualize_coordinate_map_example.png b/docs/images/visualize_coordinate_map_example.png new file mode 100644 index 0000000000000..24f03376adade Binary files /dev/null and b/docs/images/visualize_coordinate_map_example.png differ diff --git a/docs/images/visualize_heat_map_example.png b/docs/images/visualize_heat_map_example.png new file mode 100644 index 0000000000000..2522e91f4dbc7 Binary files /dev/null and b/docs/images/visualize_heat_map_example.png differ diff --git a/docs/images/visualize_region_map_example.png b/docs/images/visualize_region_map_example.png new file mode 100644 index 0000000000000..cf89e92625ece Binary files /dev/null and b/docs/images/visualize_region_map_example.png differ diff --git a/docs/redirects.asciidoc b/docs/redirects.asciidoc index efe50985e8a3a..f6da4953c3dee 100644 --- a/docs/redirects.asciidoc +++ b/docs/redirects.asciidoc @@ -59,7 +59,7 @@ This page was deleted. See <> and <>. [role="exclude",id="xpack-dashboard-only-mode"] == Dashboard-only mode -Using the `kibana_dashboard_only_user` role is deprecated. +Using the `kibana_dashboard_only_user` role is deprecated. Use <> instead. [role="exclude",id="pdf-layout-modes"] @@ -72,4 +72,12 @@ This page has moved. Please see <>. This page has moved. Please see <>. +[role="exclude",id="add-sample-data"] +== Add sample data +This page has moved. Please see <>. + +[role="exclude",id="tilemap"] +== Coordinate map + +This page has moved. Please see <>. diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index b8302898d580e..54f8c907eb09e 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -1,7 +1,7 @@ [[settings]] -== Configuring Kibana +== Configuring {kib} -The Kibana server reads properties from the `kibana.yml` file on startup. The +The {kib} server reads properties from the `kibana.yml` file on startup. The location of this file differs depending on how you installed {kib}. For example, if you installed {kib} from an archive distribution (`.tar.gz` or `.zip`), by default it is in `$KIBANA_HOME/config`. By default, with package distributions @@ -26,16 +26,16 @@ in a manner that is inconsistent with `/proc/self/cgroup` `csp.rules:`:: A template https://w3c.github.io/webappsec-csp/[content-security-policy] that disables certain unnecessary and potentially insecure capabilities in the browser. We -strongly recommend that you keep the default CSP rules that ship with Kibana. +strongly recommend that you keep the default CSP rules that ship with {kib}. -`csp.strict:`:: *Default: `false`* Blocks access to Kibana to any browser that +`csp.strict:`:: *Default: `false`* Blocks access to {kib} to any browser that does not enforce even rudimentary CSP rules. In practice, this will disable support for older, less safe browsers like Internet Explorer. See <> for more information. `csp.warnLegacyBrowsers:`:: *Default: `true`* Shows a warning message after -loading Kibana to any browser that does not enforce even rudimentary CSP rules, -though Kibana is still accessible. This configuration is effectively ignored +loading {kib} to any browser that does not enforce even rudimentary CSP rules, +though {kib} is still accessible. This configuration is effectively ignored when `csp.strict` is enabled. `elasticsearch.customHeaders:`:: *Default: `{}`* Header names and values to send @@ -54,34 +54,34 @@ inspector, for example Timelion and Monitoring. `elasticsearch.pingTimeout:`:: *Default: the value of the `elasticsearch.requestTimeout` setting* Time in -milliseconds to wait for Elasticsearch to respond to pings. +milliseconds to wait for {es} to respond to pings. `elasticsearch.preserveHost:`:: *Default: true* When this setting’s value is -true, Kibana uses the hostname specified in the `server.host` setting. When the -value of this setting is `false`, Kibana uses the hostname of the host that -connects to this Kibana instance. +true, {kib} uses the hostname specified in the `server.host` setting. When the +value of this setting is `false`, {kib} uses the hostname of the host that +connects to this {kib} instance. `elasticsearch.requestHeadersWhitelist:`:: *Default: `[ 'authorization' ]`* List -of Kibana client-side headers to send to Elasticsearch. To send *no* client-side +of {kib} client-side headers to send to {es}. To send *no* client-side headers, set this value to [] (an empty list). Removing the `authorization` header from being whitelisted means that you cannot -use <> in Kibana. +use <> in {kib}. `elasticsearch.requestTimeout:`:: *Default: 30000* Time in milliseconds to wait -for responses from the back end or Elasticsearch. This value must be a positive +for responses from the back end or {es}. This value must be a positive integer. `elasticsearch.shardTimeout:`:: *Default: 30000* Time in milliseconds for -Elasticsearch to wait for responses from shards. Set to 0 to disable. +{es} to wait for responses from shards. Set to 0 to disable. `elasticsearch.sniffInterval:`:: *Default: false* Time in milliseconds between -requests to check Elasticsearch for an updated list of nodes. +requests to check {es} for an updated list of nodes. `elasticsearch.sniffOnConnectionFault:`:: *Default: false* Update the list of -Elasticsearch nodes immediately following a connection fault. +{es} nodes immediately following a connection fault. `elasticsearch.sniffOnStart:`:: *Default: false* Attempt to find other -Elasticsearch nodes on startup. +{es} nodes on startup. `elasticsearch.ssl.alwaysPresentCertificate:`:: *Default: false* Controls {kib}'s behavior in regard to presenting a client certificate when requested by {es}. This setting applies to all outbound SSL/TLS connections to {es}, including requests that are proxied for end users. @@ -138,40 +138,40 @@ making an outbound SSL/TLS connection to {es}. Valid values are `"full"`, `"cert hostname verification, using `"certificate"` will skip hostname verification, and using `"none"` will skip verification entirely. `elasticsearch.startupTimeout:`:: *Default: 5000* Time in milliseconds to wait -for Elasticsearch at Kibana startup before retrying. +for {es} at {kib} startup before retrying. -`elasticsearch.username:` and `elasticsearch.password:`:: If your Elasticsearch +`elasticsearch.username:` and `elasticsearch.password:`:: When {es} is protected with basic authentication, these settings provide the username and -password that the Kibana server uses to perform maintenance on the Kibana index -at startup. Your Kibana users still need to authenticate with Elasticsearch, -which is proxied through the Kibana server. +password that the {kib} server uses to perform maintenance on the {kib} index +at startup. Your {kib} users still need to authenticate with {es}, +which is proxied through the {kib} server. `interpreter.enableInVisualize`:: *Default: true* Enables use of interpreter in Visualize. `kibana.defaultAppId:`:: *Default: "home"* The default application to load. -`kibana.index:`:: *Default: ".kibana"* Kibana uses an index in Elasticsearch to -store saved searches, visualizations, and dashboards. Kibana creates a new index +`kibana.index:`:: *Default: ".kibana"* {kib} uses an index in {es} to +store saved searches, visualizations, and dashboards. {kib} creates a new index if the index doesn’t already exist. If you configure a custom index, the name must be lowercase, and conform to {es} {ref}/indices-create-index.html[index name limitations]. + -When running multiple tenants of {kib} by changing the `kibana.index` in your `kibana.yml`, -you cannot use the `kibana_user` or `kibana_dashboard_only_user` roles -to grant access to {kib}. -You must create custom roles that authorize the user for that specific tenant. -Although multi-tenant installations are supported, the recommended approach +When running multiple tenants of {kib} by changing the `kibana.index` in your `kibana.yml`, +you cannot use the `kibana_user` or `kibana_dashboard_only_user` roles +to grant access to {kib}. +You must create custom roles that authorize the user for that specific tenant. +Although multi-tenant installations are supported, the recommended approach to securing access to {kib} segments is to grant users access to specific spaces. `kibana.autocompleteTimeout:`:: *Default: "1000"* Time in milliseconds to wait -for autocomplete suggestions from Elasticsearch. This value must be a whole number +for autocomplete suggestions from {es}. This value must be a whole number greater than zero. `kibana.autocompleteTerminateAfter:`:: *Default: "100000"* Maximum number of documents loaded by each shard to generate autocomplete suggestions. This value must be a whole number greater than zero. -`logging.dest:`:: *Default: `stdout`* Enables you specify a file where Kibana +`logging.dest:`:: *Default: `stdout`* Enables you specify a file where {kib} stores log output. `logging.json:`:: *Default: false* Logs output as JSON. When set to `true`, the @@ -225,23 +225,23 @@ setting to `true` to log all events, including system usage information and all requests. Supported on {ece}. `map.includeElasticMapsService:`:: *Default: true* -Set to false to disable connections to Elastic Maps Service. -When `includeElasticMapsService` is turned off, only the vector layers configured by `map.regionmap` -and the tile layer configured by `map.tilemap.url` will be available in the <>, -<>, and <>. +To disable connections to Elastic Maps Service, set to `false`. +When `includeElasticMapsService` is turned off, only the vector layers configured by `map.regionmap`, +and the tile layer configured by `map.tilemap.url`, are available in the <>, +<>, and <>. `map.proxyElasticMapsServiceInMaps:`:: *Default: false* -Set to true to proxy all <> Elastic Maps Service requests through the Kibana server. -This setting does not impact <> and <>. +Set to true to proxy all <> Elastic Maps Service requests through the {kib} server. +This setting does not impact <> and <>. [[regionmap-settings]] `map.regionmap:`:: Specifies additional vector layers for -use in <> visualizations. Supported on {ece}. Each layer +use in <> visualizations. Supported on {ece}. Each layer object points to an external vector file that contains a geojson FeatureCollection. The file must use the https://en.wikipedia.org/wiki/World_Geodetic_System[WGS84 coordinate reference system (ESPG:4326)] and only include polygons. If the file is hosted on a separate domain from -Kibana, the server needs to be CORS-enabled so Kibana can download the file. The -following example shows a valid regionmap configuration. +{kib}, the server needs to be CORS-enabled so {kib} can download the file. The +following example shows a valid region map configuration. + -- map @@ -258,11 +258,10 @@ following example shows a valid regionmap configuration. description: "INSEE numeric identifier" -- -[[regionmap-ES-map]]`map.includeElasticMapsService:`:: Turns on or off -whether layers from the Elastic Maps Service should be included in the vector -layer option list. Supported on {ece}. By turning this off, only the layers that -are configured here will be included. The default is `true`. -This also affects whether tile-service from the Elastic Maps Service will be available. +[[regionmap-ES-map]]`map.includeElasticMapsService:`:: Specifies +the option to include layers from the Elastic Maps Service in the vector +layer option list. Supported on {ece}. When off, only the configured layers are included. +The default is `true`. This option also specifies if the tile-service from the Elastic Maps Service is available. [[regionmap-attribution]]`map.regionmap.layers[].attribution:`:: Optional. References the originating source of the geojson file. Supported on {ece}. @@ -278,9 +277,9 @@ building the Region Map visualization. Supported on {ece}. [[regionmap-field-name]]`map.regionmap.layers[].fields[].name:`:: Mandatory. This value is used to do an inner-join between the document stored in -Elasticsearch and the geojson file. For example, if the field in the geojson is -called `Location` and has city names, there must be a field in Elasticsearch -that holds the same values that Kibana can then use to lookup for the geoshape +{es} and the geojson file. For example, if the field in the geojson is +called `Location` and has city names, there must be a field in {es} +that holds the same values that {kib} can then use to lookup for the geoshape data. Supported on {ece}. [[regionmap-name]]`map.regionmap.layers[].name:`:: Mandatory. A description of @@ -303,9 +302,9 @@ zoom level. Supported on {ece}. used by the tile service. Specify the position of the subdomain the URL with the token `{s}`. Supported on {ece}. -[[tilemap-url]]`map.tilemap.url:`:: The URL to the tileservice that Kibana uses +[[tilemap-url]]`map.tilemap.url:`:: The URL to the tileservice that {kib} uses to display map tiles in tilemap visualizations. Supported on {ece}. By default, -Kibana reads this url from an external metadata service, but users can still +{kib} reads this url from an external metadata service, but users can still override this parameter to use their own Tile Map Service. For example: `"https://tiles.elastic.co/v2/default/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana"` @@ -313,22 +312,22 @@ override this parameter to use their own Tile Map Service. For example: system and process performance metrics. The minimum value is 100. `newsfeed.enabled:` :: *Default: `true`* Controls whether to enable the newsfeed -system for the Kibana UI notification center. Set to `false` to disable the +system for the {kib} UI notification center. Set to `false` to disable the newsfeed system. -`path.data:`:: *Default: `data`* The path where Kibana stores persistent data -not saved in Elasticsearch. +`path.data:`:: *Default: `data`* The path where {kib} stores persistent data +not saved in {es}. -`pid.file:`:: Specifies the path where Kibana creates the process ID file. +`pid.file:`:: Specifies the path where {kib} creates the process ID file. -`server.basePath:`:: Enables you to specify a path to mount Kibana at if you are -running behind a proxy. Use the `server.rewriteBasePath` setting to tell Kibana +`server.basePath:`:: Enables you to specify a path to mount {kib} at if you are +running behind a proxy. Use the `server.rewriteBasePath` setting to tell {kib} if it should remove the basePath from requests it receives, and to prevent a deprecation warning at startup. This setting cannot end in a slash (`/`). [[server-compression]]`server.compression.enabled:`:: *Default: `true`* Set to `false` to disable HTTP compression for all responses. -`server.compression.referrerWhitelist:`:: *Default: none* Specifies an array of trusted hostnames, such as the Kibana host, or a reverse +`server.compression.referrerWhitelist:`:: *Default: none* Specifies an array of trusted hostnames, such as the {kib} host, or a reverse proxy sitting in front of it. This determines whether HTTP compression may be used for responses, based on the request's `Referer` header. This setting may not be used when `server.compression.enabled` is set to `false`. @@ -337,7 +336,7 @@ This setting may not be used when `server.compression.enabled` is set to `false` `server.cors.origin:`:: *Default: none* Specifies origins. “origin” must be an array. To use this setting, you must set `server.cors` to `true`. To accept all origins, use `server.cors.origin: ["*"]`. `server.customResponseHeaders:`:: *Default: `{}`* Header names and values to - send on all responses to the client from the Kibana server. + send on all responses to the client from the {kib} server. `server.host:`:: *Default: "localhost"* This setting specifies the host of the back end server. To allow remote users to connect, set the value to the IP address or DNS name of the {kib} server. @@ -349,12 +348,12 @@ the `server.socketTimeout` counter. for incoming server requests. `server.name:`:: *Default: "your-hostname"* A human-readable display name that -identifies this Kibana instance. +identifies this {kib} instance. -`server.port:`:: *Default: 5601* Kibana is served by a back end server. This +`server.port:`:: *Default: 5601* {kib} is served by a back end server. This setting specifies the port to use. -`server.rewriteBasePath:`:: *Default: false* Deprecated setting that specifies if Kibana should +`server.rewriteBasePath:`:: *Default: false* Deprecated setting that specifies if {kib} should rewrite requests that are prefixed with `server.basePath`, or require that they are rewritten by your reverse proxy. @@ -414,7 +413,7 @@ In addition to this setting, trusted certificates may be specified via `server.s `server.ssl.truststore.password:`:: The password that will be used to decrypt the trust store specified via `server.ssl.truststore.path`. If the trust store has no password, leave this unset. If the trust store has an empty password, set this to `""`. -`server.ssl.redirectHttpFromPort:`:: Kibana will bind to this port and redirect +`server.ssl.redirectHttpFromPort:`:: {kib} binds to this port and redirects all http requests to https over the port configured as `server.port`. `server.ssl.supportedProtocols:`:: *Default: TLSv1.1, TLSv1.2* An array of @@ -433,7 +432,7 @@ The `server.xsrf.whitelist` setting requires the following format: ---- `status.allowAnonymous:`:: *Default: false* If authentication is enabled, -setting this to `true` enables unauthenticated users to access the Kibana server +setting this to `true` enables unauthenticated users to access the {kib} server status API and status page. `telemetry.allowChangingOptInStatus`:: *Default: true*. If `true`, @@ -453,7 +452,7 @@ us improve your user experience. Your data is never shared with anyone. Set to `false` to disable telemetry capabilities entirely. You can alternatively opt out through the *Advanced Settings* in {kib}. -`vis_type_vega.enableExternalUrls:`:: *Default: false* Set this value to true to allow Vega to use any URL to access external data sources and images. If false, Vega can only get data from Elasticsearch. +`vis_type_vega.enableExternalUrls:`:: *Default: false* Set this value to true to allow Vega to use any URL to access external data sources and images. If false, Vega can only get data from {es}. `xpack.license_management.enabled`:: *Default: true* Set this value to false to disable the License Management user interface. @@ -461,7 +460,7 @@ disable the License Management user interface. `xpack.rollup.enabled:`:: *Default: true* Set this value to false to disable the Rollup user interface. -`i18n.locale`:: *Default: en* Set this value to change the Kibana interface language. Valid locales are: `en`, `zh-CN`, `ja-JP`. +`i18n.locale`:: *Default: en* Set this value to change the {kib} interface language. Valid locales are: `en`, `zh-CN`, `ja-JP`. include::{docdir}/settings/alert-action-settings.asciidoc[] include::{docdir}/settings/apm-settings.asciidoc[] diff --git a/docs/user/getting-started.asciidoc b/docs/user/getting-started.asciidoc index c6fe5b5b92d69..d426ec111351c 100644 --- a/docs/user/getting-started.asciidoc +++ b/docs/user/getting-started.asciidoc @@ -1,54 +1,65 @@ [[getting-started]] -= Getting Started += Get started [partintro] -- -You’re new to Kibana and want to give it a try. {kib} has sample data sets and -tutorials to help you get started. +Ready to try out {kib} and see what it can do? To quickest way to get started with {kib} is to set up on Cloud, then add a sample data set that helps you get a handle on the full range of {kib} features. [float] -=== Sample data +[[cloud-set-up]] +== Set up on Cloud -You can use the <> to take {kib} for a test ride without having -to go through the process of loading data yourself. With one click, -you can install a sample data set and start interacting with -{kib} visualizations in seconds. You can access the sample data -from the {kib} home page. +To access {kib} in a single click, run our hosted Elasticsearch Service on Elastic Cloud. -[float] +. Log into the link:https://cloud.elastic.co/[Elasticsearch Service Console]. +If you need an account, register for a link:https://www.elastic.co/cloud/elasticsearch-service/signup[free 14-day trial]. + +. Click *Create deployment*, then give your deployment a name. -=== Add data tutorials -{kib} has built-in *Add Data* tutorials to help you set up -data flows in the Elastic Stack. These tutorials are available -from the Kibana home page. In *Add Data to Kibana*, find the data type -you’re interested in, and click its button to view a list of available tutorials. +. To use the default options, click *Create deployment*. You can modify the other deployment options, but the default options are great to get started. + +Be sure to copy down the password for the `elastic` user and Cloud ID information. You'll need that later. [float] -=== Hands-on experience +[[get-data-in]] +== Get data into {kib} + +The easiest way to get data into {kib} is to add a sample data set. + +{kib} has several sample data sets that you can use before loading your own data: + +* *Sample eCommerce orders* includes visualizations for tracking product-related information, +such as cost, revenue, and price. + +* *Sample flight data* includes visualizations for monitoring flight routes. -The following tutorials walk you through searching, analyzing, -and visualizing data. +* *Sample web logs* includes visualizations for monitoring website traffic. -* <>. You'll -learn to filter and query data, edit visualizations, and interact with dashboards. +To use the sample data sets: -* <>. You'll manually load a data set and build -your own visualizations and dashboard. +. Go to the {kib} home page. + +. Click *Load a data set and a {kib} dashboard*. + +. Click *View data* and view the prepackaged dashboards, maps, and more. + +[role="screenshot"] +image::images/add-sample-data.png[] + +NOTE: The timestamps in the sample data sets are relative to when they are installed. +If you uninstall and reinstall a data set, the timestamps change to reflect the most recent installation. [float] -=== Before you begin +[[getting-started-next-steps]] +== Next steps -Make sure you've <> and established -a <>. +* To get a hands-on experience creating visualizations, follow the <> tutorial. -If you are running our hosted Elasticsearch Service on Elastic Cloud, you access Kibana with a single click. (You can {ess-trial}[sign up for a free trial] and start exploring data in minutes.) +* If you're ready to load an actual data set and build a dashboard, follow the <> tutorial. -- -include::{kib-repo-dir}/getting-started/add-sample-data.asciidoc[] - include::{kib-repo-dir}/getting-started/tutorial-sample-data.asciidoc[] include::{kib-repo-dir}/getting-started/tutorial-full-experience.asciidoc[] @@ -60,4 +71,3 @@ include::{kib-repo-dir}/getting-started/tutorial-discovering.asciidoc[] include::{kib-repo-dir}/getting-started/tutorial-visualizing.asciidoc[] include::{kib-repo-dir}/getting-started/tutorial-dashboard.asciidoc[] - diff --git a/docs/user/index.asciidoc b/docs/user/index.asciidoc index 2bd087b3eae57..94034bdaea0f9 100644 --- a/docs/user/index.asciidoc +++ b/docs/user/index.asciidoc @@ -1,13 +1,13 @@ include::introduction.asciidoc[] +include::getting-started.asciidoc[] + include::setup.asciidoc[] include::monitoring/configuring-monitoring.asciidoc[] include::security/securing-kibana.asciidoc[] -include::getting-started.asciidoc[] - include::discover.asciidoc[] include::visualize.asciidoc[] diff --git a/docs/user/monitoring/elasticsearch-details.asciidoc b/docs/user/monitoring/elasticsearch-details.asciidoc index 2990e965be03c..c0e804672d298 100644 --- a/docs/user/monitoring/elasticsearch-details.asciidoc +++ b/docs/user/monitoring/elasticsearch-details.asciidoc @@ -14,7 +14,7 @@ the <>, <>, [role="screenshot"] image::user/monitoring/images/monitoring-elasticsearch.jpg["Monitoring clusters"] -See also {ref}/es-monitoring.html[Monitoring {es}]. +See also {ref}/monitor-elasticsearch-cluster.html[Monitor a cluster]. [float] [[cluster-overview-page]] diff --git a/docs/user/visualize.asciidoc b/docs/user/visualize.asciidoc index 1bcbd51a9629a..a78b4604ed1e6 100644 --- a/docs/user/visualize.asciidoc +++ b/docs/user/visualize.asciidoc @@ -45,11 +45,11 @@ data sets. [horizontal] <>:: The most powerful way of visualizing map data in {kib}. -<>:: Displays points on a map using a geohash aggregation. +<>:: Displays points on a map using a geohash aggregation. -<>:: Merge any structured map data onto a shape. +<>:: Merge any structured map data onto a shape. -<>:: Display shaded cells within a matrix. +<>:: Display shaded cells within a matrix. * *<>* [horizontal] @@ -136,8 +136,6 @@ include::{kib-repo-dir}/visualize/tsvb.asciidoc[] include::{kib-repo-dir}/visualize/timelion.asciidoc[] include::{kib-repo-dir}/visualize/tilemap.asciidoc[] -include::{kib-repo-dir}/visualize/regionmap.asciidoc[] -include::{kib-repo-dir}/visualize/heatmap.asciidoc[] include::{kib-repo-dir}/visualize/for-dashboard.asciidoc[] diff --git a/docs/visualize/heatmap.asciidoc b/docs/visualize/heatmap.asciidoc deleted file mode 100644 index 18c4018213390..0000000000000 --- a/docs/visualize/heatmap.asciidoc +++ /dev/null @@ -1,40 +0,0 @@ -[[heatmap]] -== Heat map - -Heat maps are graphical representations of data where the individual values are represented as colors. - -NOTE: Heat map has been replaced with <>, which offers more functionality and is easier to use. - -[float] -[[heatmap-aggregation]] -=== Supported aggregations - -Heat maps support the following aggregations: - -* <> - -* <> - -* <> - -* <> - -[float] -[[navigate-heatmap]] -=== Change the color ranges - -When only one color displays on the heat map, you might need to change the color ranges. - -To specify the number of color ranges: - -. Click *Options*. - -. Enter the *Number of colors* to display. - -To specify custom ranges: - -. Click *Options*. - -. Select *Use custom ranges*. - -. Enter the ranges to display. diff --git a/docs/visualize/metric.asciidoc b/docs/visualize/metric.asciidoc deleted file mode 100644 index ddcf5fe3b73bd..0000000000000 --- a/docs/visualize/metric.asciidoc +++ /dev/null @@ -1,16 +0,0 @@ -[[metric-chart]] -=== Metric - -Click the *Options* tab to display the font size slider. - -[float] -[[metric-aggregation]] -==== Supported aggregations - -Metric support the following aggregations: - -* <> - -* <> - -* <> diff --git a/docs/visualize/regionmap.asciidoc b/docs/visualize/regionmap.asciidoc deleted file mode 100644 index accabd16e5fcd..0000000000000 --- a/docs/visualize/regionmap.asciidoc +++ /dev/null @@ -1,53 +0,0 @@ -[[regionmap]] -== Region Maps - -Region maps are thematic maps in which boundary vector shapes are colored using a gradient: -higher intensity colors indicate larger values, and lower intensity colors indicate smaller values. -These are also known as choropleth maps. - -Kibana’s out-of-the-box settings do not show a region map in the New Visualization menu. Use <> instead, which offers more functionality and is easier to use. -If you want to create new region map visualizations, set `xpack.maps.showMapVisualizationTypes` to `true`. - -image::images/regionmap.png[] - -[float] -[[regionmap-configuration]] -=== Configuration - -To create a region map, you configure an inner join that joins the result of an Elasticsearch terms aggregation -and a reference vector file based on a shared key. - -[float] -[[region-map-aggregation]] -=== Supported aggregations - -Region maps support the following aggregations: - -* <> - -* <> - -* <> - -Use the _key_ term to join the results to the vector data on the map. - -[float] -==== Options - -[float] -===== Layer Settings -- *Vector map*: select from a list of vector maps. This list includes the maps that are hosted by the © https://www.elastic.co/elastic-maps-service[Elastic Maps Service], -as well as your self-hosted layers that are configured in the *config/kibana.yml* file. To learn more about how to configure Kibana -to make self-hosted layers available, see the <> documentation. You can also explore and preview vector layers available in Elastic Maps Service at https://maps.elastic.co[https://maps.elastic.co]. -- *Join field*: this is the property from the selected vector map that will be used to join on the terms in your terms-aggregation. -When terms cannot be joined to any of the shapes in the vector layer because there is no exact match in the vector layer, Kibana will display a warning. -To turn of these warnings, go to *Management/Kibana/Advanced Settings* and set `visualization:regionmap:showWarnings` to `false`. - -[float] -===== Style Settings -- *Color Schema*: the color range used to color the shapes. - -[float] -===== Basic Settings -- *Legend Position*: the location on the screen where the legend should be rendered. -- *Show Tooltip*: indicates whether a tooltip should be displayed when hovering over a shape.. diff --git a/docs/visualize/tilemap.asciidoc b/docs/visualize/tilemap.asciidoc index 08cf666345e34..349fa681a9777 100644 --- a/docs/visualize/tilemap.asciidoc +++ b/docs/visualize/tilemap.asciidoc @@ -1,47 +1,142 @@ -[[tilemap]] -== Coordinate map +[[visualize-maps]] +== Maps -Coordinate maps display geographic areas overlaid with circles keyed to the data determined by the buckets you specify. To use coordinate maps, you plot latitude and longitude coordinates. +To tell a story and answer questions about your geographical data, you can create several types of interactive maps with Visualize. -NOTE: Coordinate maps have been replaced with <>, which offers more functionality and is easier to use. +Visualize supports the following maps: -To create coordinate maps in Visualize: +* *Coordinate* — Display latitude and longitude coordinates that are associated to the specified bucket aggregation. -* Set `xpack.maps.showMapVisualizationTypes` to `true`. +* *Region* — Display colored boundary vector shapes using a gradient. Darker colors indicate larger values, and lighter colors indicate smaller values. + +* *Heat* — Display graphical representations of data where the individual values are represented by colors. -* To display map tiles, {kib} uses the https://www.elastic.co/elastic-maps-service[Elastic Maps Service]. -To use other tile service providers, configure the <> -in `kibana.yml`. +NOTE: The maps in Visualize have been replaced with <>, which offers more functionality. [float] -[[coordinate-map-aggregation]] -=== Supported aggregations +[[coordinate-map]] +=== Coordinate map + +Use a coordinate map when your data set includes latitude and longitude values. For example, use a coordinate map to see the varying popularity of destination airports using the sample flight data. + +[role="screenshot"] +image::images/visualize_coordinate_map_example.png[] + +[float] +[[build-coordinate-map]] +==== Build a coordinate map + +Configure the `kibana.yml` settings and add the aggregations. -Coordinate maps support the following aggregations: +. Configure the following `kibana.yml` settings: + +* Set `xpack.maps.showMapVisualizationTypes` to `true`. + +* To use a tile service provider for coordinate maps other than https://www.elastic.co/elastic-maps-service[Elastic Maps Service], configure the <>. + +. To display your data on the coordinate map, use the following aggregations: * <> -* <> +* <> -When you deselect *Change precision on map zoom*, the *Precision* slider appears. The *Precision* slider determines the granularity of the results displayed on the map. For details on the area specified by each precision level, refer to {ref}/search-aggregations-bucket-geohashgrid-aggregation.html#_cell_dimensions_at_the_equator[geohash grid]. +. Specify the geohash bucket aggregation options: +* *Precision* slider — Determines the granularity of the results displayed on the map. To show the *Precision* slider, deselect *Change precision on map zoom*. For information on the area specified by each precision level, refer to {ref}/search-aggregations-bucket-geohashgrid-aggregation.html#_cell_dimensions_at_the_equator[geohash grid]. ++ NOTE: Higher precisions increase memory usage for the browser that displays {kib} and the underlying {es} cluster. -When you select *Place markers off grid (use {ref}/search-aggregations-metrics-geocentroid-aggregation.html[geocentroid])*, the markers are -placed in the center of all documents in the bucket, and a more accurate visualization is created. -NOTE: When you have multiple values in the geo_point, the coordinate map is unable to accurately calculate the geo_centroid. - -When you deselect *Place markers off grid (use {ref}/search-aggregations-metrics-geocentroid-aggregation.html[geocentroid])*, the markers are placed in the center +* *Place markers off grid (use {ref}/search-aggregations-metrics-geocentroid-aggregation.html[geocentroid])* — When you selected, the markers are +placed in the center of all documents in the bucket, and a more accurate visualization is created. When deselected, the markers are placed in the center of the geohash grid cell. ++ +NOTE: When you have multiple values in the geo_point, the coordinate map is unable to accurately calculate the geo_centroid. [float] -[[navigate-map]] -=== Navigate the coordinate map +[[navigate-coordinate-map]] +==== Navigate the coordinate map -Use the following navigation options: +To navigate the coordinate map, use the navigation options. * To move the map center, click and hold anywhere on the map and move the cursor. + * To change the zoom level, click *Zoom In* or *Zoom out* image:images/viz-zoom.png[]. + * To automatically crop the map boundaries to the geohash buckets that have at least one result, click *Fit Data Bounds* image:images/viz-fit-bounds.png[]. + +[float] +[[region-map]] +=== Region map + +Use region maps when you want to show statistical data on a geographic area, such as a county, country, province, or state. For example, use a region map if you want to see the average sales for each country with the sample eCommerce order data. + +[role="screenshot"] +image::images/visualize_region_map_example.png[] + +[float] +[[build-region-maps]] +==== Build a region map + +Configure the `kibana.yml` settings and add the aggregations. + +. In `kibana.yml`, set `xpack.maps.showMapVisualizationTypes` to `true`. + +. To display your data on the region map, use the following aggregations: + +* <> +* <> +* <> + +[float] +[[navigate-region-map]] +==== Navigate the region map + +To navigate the region map, use the navigation options. + +* To change the zoom level, click *Zoom In* or *Zoom out* image:images/viz-zoom.png[]. + +* To automatically crop the map boundaries, click *Fit Data Bounds* image:images/viz-fit-bounds.png[]. + +[float] +[[heat-map]] +=== Heat map + +Use heat maps when your data set includes categorical data. For example, use a heat map to see the flights of origin countries compared to destination countries using the sample flight data. + +[role="screenshot"] +image::images/visualize_heat_map_example.png[] + +[float] +[[build-heat-map]] +==== Build a heat map + +To display your data on the heat map, use the supported aggregations. + +Heat maps support the following aggregations: + +* <> +* <> +* <> +* <> + +[float] +[[navigate-heatmap]] +==== Change the color ranges + +When only one color displays on the heat map, you might need to change the color ranges. + +To specify the number of color ranges: + +. Click *Options*. + +. Enter the *Number of colors* to display. + +To specify custom ranges: + +. Click *Options*. + +. Select *Use custom ranges*. + +. Enter the ranges to display. diff --git a/package.json b/package.json index 017ae8d755e9b..6c44c34996c64 100644 --- a/package.json +++ b/package.json @@ -351,6 +351,7 @@ "@types/mustache": "^0.8.31", "@types/node": "^10.12.27", "@types/node-forge": "^0.9.0", + "@types/normalize-path": "^3.0.0", "@types/numeral": "^0.0.26", "@types/opn": "^5.1.0", "@types/pegjs": "^0.10.1", diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/index.ts b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/index.ts index 66fa55479f3b9..817c4796562e8 100644 --- a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/index.ts +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/index.ts @@ -17,6 +17,7 @@ * under the License. */ +import './legacy/styles.scss'; import { fooLibFn } from '../../foo/public/index'; export * from './lib'; export { fooLibFn }; diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss new file mode 100644 index 0000000000000..e71a2d485a2f8 --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss @@ -0,0 +1,4 @@ +body { + width: $globalStyleConstant; + background-image: url("ui/icon.svg"); +} diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/icon.svg b/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/icon.svg new file mode 100644 index 0000000000000..ae7d5b958bbad --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/styles/_styling_constants.scss b/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/styles/_styling_constants.scss new file mode 100644 index 0000000000000..83995ca65211b --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/styles/_styling_constants.scss @@ -0,0 +1 @@ +$globalStyleConstant: 10; diff --git a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap index 706f79978beee..1a974d3e81092 100644 --- a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap +++ b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap @@ -5,553 +5,56 @@ OptimizerConfig { "bundles": Array [ Bundle { "cache": BundleCache { - "path": /plugins/bar/target/public/.kbn-optimizer-cache, + "path": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/target/public/.kbn-optimizer-cache, "state": undefined, }, - "contextDir": /plugins/bar, + "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar, "entry": "./public/index", "id": "bar", - "outputDir": /plugins/bar/target/public, - "sourceRoot": , + "outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/target/public, + "sourceRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, "type": "plugin", }, Bundle { "cache": BundleCache { - "path": /plugins/foo/target/public/.kbn-optimizer-cache, + "path": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/target/public/.kbn-optimizer-cache, "state": undefined, }, - "contextDir": /plugins/foo, + "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo, "entry": "./public/index", "id": "foo", - "outputDir": /plugins/foo/target/public, - "sourceRoot": , + "outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/target/public, + "sourceRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, "type": "plugin", }, ], "cache": true, - "dist": false, + "dist": true, "inspectWorkers": false, "maxWorkerCount": 1, "plugins": Array [ Object { - "directory": /plugins/bar, + "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar, "id": "bar", "isUiPlugin": true, }, Object { - "directory": /plugins/baz, + "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/baz, "id": "baz", "isUiPlugin": false, }, Object { - "directory": /plugins/foo, + "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo, "id": "foo", "isUiPlugin": true, }, ], "profileWebpack": false, - "repoRoot": , + "repoRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, "watch": false, } `; -exports[`builds expected bundles, saves bundle counts to metadata: bar bundle 1`] = ` -"var __kbnBundles__ = typeof __kbnBundles__ === \\"object\\" ? __kbnBundles__ : {}; __kbnBundles__[\\"plugin/bar\\"] = -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __webpack_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 8|1: behave like require -/******/ __webpack_require__.t = function(value, mode) { -/******/ if(mode & 1) value = __webpack_require__(value); -/******/ if(mode & 8) return value; -/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; -/******/ var ns = Object.create(null); -/******/ __webpack_require__.r(ns); -/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); -/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); -/******/ return ns; -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = \\"__REPLACE_WITH_PUBLIC_PATH__\\"; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = \\"./public/index.ts\\"); -/******/ }) -/************************************************************************/ -/******/ ({ +exports[`builds expected bundles, saves bundle counts to metadata: bar bundle 1`] = `"var __kbnBundles__=typeof __kbnBundles__===\\"object\\"?__kbnBundles__:{};__kbnBundles__[\\"plugin/bar\\"]=function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId]){return installedModules[moduleId].exports}var module=installedModules[moduleId]={i:moduleId,l:false,exports:{}};modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);module.l=true;return module.exports}__webpack_require__.m=modules;__webpack_require__.c=installedModules;__webpack_require__.d=function(exports,name,getter){if(!__webpack_require__.o(exports,name)){Object.defineProperty(exports,name,{enumerable:true,get:getter})}};__webpack_require__.r=function(exports){if(typeof Symbol!==\\"undefined\\"&&Symbol.toStringTag){Object.defineProperty(exports,Symbol.toStringTag,{value:\\"Module\\"})}Object.defineProperty(exports,\\"__esModule\\",{value:true})};__webpack_require__.t=function(value,mode){if(mode&1)value=__webpack_require__(value);if(mode&8)return value;if(mode&4&&typeof value===\\"object\\"&&value&&value.__esModule)return value;var ns=Object.create(null);__webpack_require__.r(ns);Object.defineProperty(ns,\\"default\\",{enumerable:true,value:value});if(mode&2&&typeof value!=\\"string\\")for(var key in value)__webpack_require__.d(ns,key,function(key){return value[key]}.bind(null,key));return ns};__webpack_require__.n=function(module){var getter=module&&module.__esModule?function getDefault(){return module[\\"default\\"]}:function getModuleExports(){return module};__webpack_require__.d(getter,\\"a\\",getter);return getter};__webpack_require__.o=function(object,property){return Object.prototype.hasOwnProperty.call(object,property)};__webpack_require__.p=\\"__REPLACE_WITH_PUBLIC_PATH__\\";return __webpack_require__(__webpack_require__.s=4)}([function(module,exports,__webpack_require__){\\"use strict\\";var isOldIE=function isOldIE(){var memo;return function memorize(){if(typeof memo===\\"undefined\\"){memo=Boolean(window&&document&&document.all&&!window.atob)}return memo}}();var getTarget=function getTarget(){var memo={};return function memorize(target){if(typeof memo[target]===\\"undefined\\"){var styleTarget=document.querySelector(target);if(window.HTMLIFrameElement&&styleTarget instanceof window.HTMLIFrameElement){try{styleTarget=styleTarget.contentDocument.head}catch(e){styleTarget=null}}memo[target]=styleTarget}return memo[target]}}();var stylesInDom=[];function getIndexByIdentifier(identifier){var result=-1;for(var i=0;i { await del(TMP_DIR); @@ -50,20 +50,25 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { repoRoot: MOCK_REPO_DIR, pluginScanDirs: [Path.resolve(MOCK_REPO_DIR, 'plugins')], maxWorkerCount: 1, + dist: true, }); expect(config).toMatchSnapshot('OptimizerConfig'); - const msgs = await runOptimizer(config) - .pipe( - tap(state => { - if (state.event?.type === 'worker stdio') { - // eslint-disable-next-line no-console - console.log('worker', state.event.stream, state.event.chunk.toString('utf8')); + const log = new ToolingLog({ + level: 'error', + writeTo: { + write(chunk) { + if (chunk.endsWith('\n')) { + chunk = chunk.slice(0, -1); } - }), - toArray() - ) + // eslint-disable-next-line no-console + console.error(chunk); + }, + }, + }); + const msgs = await runOptimizer(config) + .pipe(logOptimizerState(log, config), toArray()) .toPromise(); const assert = (statement: string, truth: boolean, altStates?: OptimizerUpdate[]) => { @@ -132,23 +137,31 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { expect(foo.cache.getModuleCount()).toBe(3); expect(foo.cache.getReferencedFiles()).toMatchInlineSnapshot(` Array [ - /plugins/foo/public/ext.ts, - /plugins/foo/public/index.ts, - /plugins/foo/public/lib.ts, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/ext.ts, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/index.ts, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/lib.ts, ] `); const bar = config.bundles.find(b => b.id === 'bar')!; expect(bar).toBeTruthy(); bar.cache.refresh(); - expect(bar.cache.getModuleCount()).toBe(5); + expect(bar.cache.getModuleCount()).toBe( + // code + styles + style/css-loader runtime + 14 + ); + expect(bar.cache.getReferencedFiles()).toMatchInlineSnapshot(` Array [ - /plugins/foo/public/ext.ts, - /plugins/foo/public/index.ts, - /plugins/foo/public/lib.ts, - /plugins/bar/public/index.ts, - /plugins/bar/public/lib.ts, + /node_modules/css-loader/package.json, + /node_modules/style-loader/package.json, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/index.ts, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/legacy/styles.scss, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/lib.ts, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/ext.ts, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/index.ts, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/lib.ts, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/src/legacy/ui/public/icon.svg, ] `); }); @@ -158,6 +171,7 @@ it('uses cache on second run and exist cleanly', async () => { repoRoot: MOCK_REPO_DIR, pluginScanDirs: [Path.resolve(MOCK_REPO_DIR, 'plugins')], maxWorkerCount: 1, + dist: true, }); const msgs = await runOptimizer(config) diff --git a/packages/kbn-optimizer/src/worker/__snapshots__/parse_path.test.ts.snap b/packages/kbn-optimizer/src/worker/__snapshots__/parse_path.test.ts.snap new file mode 100644 index 0000000000000..2973ac116d6bd --- /dev/null +++ b/packages/kbn-optimizer/src/worker/__snapshots__/parse_path.test.ts.snap @@ -0,0 +1,156 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`parseDirPath() parses / 1`] = ` +Object { + "dirs": Array [], + "filename": undefined, + "root": "/", +} +`; + +exports[`parseDirPath() parses /foo 1`] = ` +Object { + "dirs": Array [ + "foo", + ], + "filename": undefined, + "root": "/", +} +`; + +exports[`parseDirPath() parses /foo/bar/baz 1`] = ` +Object { + "dirs": Array [ + "foo", + "bar", + "baz", + ], + "filename": undefined, + "root": "/", +} +`; + +exports[`parseDirPath() parses /foo/bar/baz/ 1`] = ` +Object { + "dirs": Array [ + "foo", + "bar", + "baz", + ], + "filename": undefined, + "root": "/", +} +`; + +exports[`parseDirPath() parses c:\\ 1`] = ` +Object { + "dirs": Array [], + "filename": undefined, + "root": "c:", +} +`; + +exports[`parseDirPath() parses c:\\foo 1`] = ` +Object { + "dirs": Array [ + "foo", + ], + "filename": undefined, + "root": "c:", +} +`; + +exports[`parseDirPath() parses c:\\foo\\bar\\baz 1`] = ` +Object { + "dirs": Array [ + "foo", + "bar", + "baz", + ], + "filename": undefined, + "root": "c:", +} +`; + +exports[`parseDirPath() parses c:\\foo\\bar\\baz\\ 1`] = ` +Object { + "dirs": Array [ + "foo", + "bar", + "baz", + ], + "filename": undefined, + "root": "c:", +} +`; + +exports[`parseFilePath() parses /foo 1`] = ` +Object { + "dirs": Array [], + "filename": "foo", + "root": "/", +} +`; + +exports[`parseFilePath() parses /foo/bar/baz 1`] = ` +Object { + "dirs": Array [ + "foo", + "bar", + ], + "filename": "baz", + "root": "/", +} +`; + +exports[`parseFilePath() parses /foo/bar/baz.json 1`] = ` +Object { + "dirs": Array [ + "foo", + "bar", + ], + "filename": "baz.json", + "root": "/", +} +`; + +exports[`parseFilePath() parses c:/foo/bar/baz.json 1`] = ` +Object { + "dirs": Array [ + "foo", + "bar", + ], + "filename": "baz.json", + "root": "c:", +} +`; + +exports[`parseFilePath() parses c:\\foo 1`] = ` +Object { + "dirs": Array [], + "filename": "foo", + "root": "c:", +} +`; + +exports[`parseFilePath() parses c:\\foo\\bar\\baz 1`] = ` +Object { + "dirs": Array [ + "foo", + "bar", + ], + "filename": "baz", + "root": "c:", +} +`; + +exports[`parseFilePath() parses c:\\foo\\bar\\baz.json 1`] = ` +Object { + "dirs": Array [ + "foo", + "bar", + ], + "filename": "baz.json", + "root": "c:", +} +`; diff --git a/packages/kbn-optimizer/src/worker/parse_path.test.ts b/packages/kbn-optimizer/src/worker/parse_path.test.ts new file mode 100644 index 0000000000000..72197e8c8fb07 --- /dev/null +++ b/packages/kbn-optimizer/src/worker/parse_path.test.ts @@ -0,0 +1,36 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { parseFilePath, parseDirPath } from './parse_path'; + +const DIRS = ['/', '/foo/bar/baz/', 'c:\\', 'c:\\foo\\bar\\baz\\']; +const AMBIGUOUS = ['/foo', '/foo/bar/baz', 'c:\\foo', 'c:\\foo\\bar\\baz']; +const FILES = ['/foo/bar/baz.json', 'c:/foo/bar/baz.json', 'c:\\foo\\bar\\baz.json']; + +describe('parseFilePath()', () => { + it.each([...FILES, ...AMBIGUOUS])('parses %s', path => { + expect(parseFilePath(path)).toMatchSnapshot(); + }); +}); + +describe('parseDirPath()', () => { + it.each([...DIRS, ...AMBIGUOUS])('parses %s', path => { + expect(parseDirPath(path)).toMatchSnapshot(); + }); +}); diff --git a/packages/kbn-optimizer/src/worker/parse_path.ts b/packages/kbn-optimizer/src/worker/parse_path.ts new file mode 100644 index 0000000000000..88152df55b84f --- /dev/null +++ b/packages/kbn-optimizer/src/worker/parse_path.ts @@ -0,0 +1,43 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import normalizePath from 'normalize-path'; + +/** + * Parse an absolute path, supporting normalized paths from webpack, + * into a list of directories and root + */ +export function parseDirPath(path: string) { + const filePath = parseFilePath(path); + return { + ...filePath, + dirs: [...filePath.dirs, ...(filePath.filename ? [filePath.filename] : [])], + filename: undefined, + }; +} + +export function parseFilePath(path: string) { + const normalized = normalizePath(path); + const [root, ...others] = normalized.split('/'); + return { + root: root === '' ? '/' : root, + dirs: others.slice(0, -1), + filename: others[others.length - 1] || undefined, + }; +} diff --git a/packages/kbn-optimizer/src/worker/run_compilers.ts b/packages/kbn-optimizer/src/worker/run_compilers.ts index 7dcce8a0fae8d..7a8097fd2b2c7 100644 --- a/packages/kbn-optimizer/src/worker/run_compilers.ts +++ b/packages/kbn-optimizer/src/worker/run_compilers.ts @@ -27,9 +27,10 @@ import webpack, { Stats } from 'webpack'; import * as Rx from 'rxjs'; import { mergeMap, map, mapTo, takeUntil } from 'rxjs/operators'; -import { CompilerMsgs, CompilerMsg, maybeMap, Bundle, WorkerConfig } from '../common'; +import { CompilerMsgs, CompilerMsg, maybeMap, Bundle, WorkerConfig, ascending } from '../common'; import { getWebpackConfig } from './webpack.config'; import { isFailureStats, failedStatsToErrorMessage } from './webpack_helpers'; +import { parseFilePath } from './parse_path'; import { isExternalModule, isNormalModule, @@ -108,20 +109,19 @@ const observeCompiler = ( for (const module of normalModules) { const path = getModulePath(module); + const parsedPath = parseFilePath(path); - const parsedPath = Path.parse(path); - const dirSegments = parsedPath.dir.split(Path.sep); - if (!dirSegments.includes('node_modules')) { + if (!parsedPath.dirs.includes('node_modules')) { referencedFiles.add(path); continue; } - const nmIndex = dirSegments.lastIndexOf('node_modules'); - const isScoped = dirSegments[nmIndex + 1].startsWith('@'); + const nmIndex = parsedPath.dirs.lastIndexOf('node_modules'); + const isScoped = parsedPath.dirs[nmIndex + 1].startsWith('@'); referencedFiles.add( Path.join( parsedPath.root, - ...dirSegments.slice(0, nmIndex + 1 + (isScoped ? 2 : 1)), + ...parsedPath.dirs.slice(0, nmIndex + 1 + (isScoped ? 2 : 1)), 'package.json' ) ); @@ -146,7 +146,7 @@ const observeCompiler = ( optimizerCacheKey: workerConfig.optimizerCacheKey, cacheKey: bundle.createCacheKey(files, mtimes), moduleCount: normalModules.length, - files, + files: files.sort(ascending(f => f)), }); return compilerMsgs.compilerSuccess({ diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index f7fa32870c428..9493ea612d9f5 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -30,6 +30,7 @@ import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import * as SharedDeps from '@kbn/ui-shared-deps'; import { Bundle, WorkerConfig } from '../common'; +import { parseDirPath } from './parse_path'; const PUBLIC_PATH_PLACEHOLDER = '__REPLACE_WITH_PUBLIC_PATH__'; const BABEL_PRESET_PATH = require.resolve('@kbn/babel-preset/webpack_preset'); @@ -133,7 +134,7 @@ export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) { } // manually force ui/* urls in legacy styles to resolve to ui/legacy/public - if (uri.startsWith('ui/') && base.split(Path.sep).includes('legacy')) { + if (uri.startsWith('ui/') && parseDirPath(base).dirs.includes('legacy')) { return Path.resolve( worker.repoRoot, 'src/legacy/ui/public', @@ -148,7 +149,9 @@ export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) { { loader: 'sass-loader', options: { - sourceMap: !worker.dist, + // must always be enabled as long as we're using the `resolve-url-loader` to + // rewrite `ui/*` urls. They're dropped by subsequent loaders though + sourceMap: true, prependData(loaderContext: webpack.loader.LoaderContext) { return `@import ${stringifyRequest( loaderContext, diff --git a/packages/kbn-plugin-generator/integration_tests/generate_plugin.test.js b/packages/kbn-plugin-generator/integration_tests/generate_plugin.test.js index 771bf43c4020a..d7d4dc14519c3 100644 --- a/packages/kbn-plugin-generator/integration_tests/generate_plugin.test.js +++ b/packages/kbn-plugin-generator/integration_tests/generate_plugin.test.js @@ -102,6 +102,7 @@ describe(`running the plugin-generator via 'node scripts/generate_plugin.js plug 'start', '--optimize.enabled=false', '--logging.json=false', + '--logging.verbose=true', '--migrations.skip=true', ], cwd: generatedPath, diff --git a/packages/kbn-test/src/junit_report_path.ts b/packages/kbn-test/src/junit_report_path.ts index 11eaf3d2b14a5..d46c9455dcff0 100644 --- a/packages/kbn-test/src/junit_report_path.ts +++ b/packages/kbn-test/src/junit_report_path.ts @@ -20,7 +20,9 @@ import { resolve } from 'path'; const job = process.env.JOB ? `job-${process.env.JOB}-` : ''; -const num = process.env.CI_WORKER_NUMBER ? `worker-${process.env.CI_WORKER_NUMBER}-` : ''; +const num = process.env.CI_PARALLEL_PROCESS_NUMBER + ? `worker-${process.env.CI_PARALLEL_PROCESS_NUMBER}-` + : ''; export function makeJunitReportPath(rootDirectory: string, reportName: string) { return resolve( diff --git a/src/core/server/elasticsearch/retry_call_cluster.test.ts b/src/core/server/elasticsearch/retry_call_cluster.test.ts index b5a5185ab39d9..4f391f0aba34b 100644 --- a/src/core/server/elasticsearch/retry_call_cluster.test.ts +++ b/src/core/server/elasticsearch/retry_call_cluster.test.ts @@ -89,6 +89,19 @@ describe('migrationsRetryCallCluster', () => { }); }); + it('retries ES API calls that rejects with snapshot_in_progress_exception', () => { + expect.assertions(1); + const callEsApi = jest.fn(); + let i = 0; + callEsApi.mockImplementation(() => { + return i++ <= 2 + ? Promise.reject({ body: { error: { type: 'snapshot_in_progress_exception' } } }) + : Promise.resolve('success'); + }); + const retried = migrationsRetryCallCluster(callEsApi, mockLogger.get('mock log'), 1); + return expect(retried('endpoint')).resolves.toMatchInlineSnapshot(`"success"`); + }); + it('rejects when ES API calls reject with other errors', async () => { expect.assertions(3); const callEsApi = jest.fn(); diff --git a/src/core/server/elasticsearch/retry_call_cluster.ts b/src/core/server/elasticsearch/retry_call_cluster.ts index ea3cc0b90c077..901b801159cb6 100644 --- a/src/core/server/elasticsearch/retry_call_cluster.ts +++ b/src/core/server/elasticsearch/retry_call_cluster.ts @@ -64,7 +64,8 @@ export function migrationsRetryCallCluster( error instanceof esErrors.AuthenticationException || error instanceof esErrors.AuthorizationException || // @ts-ignore - error instanceof esErrors.Gone + error instanceof esErrors.Gone || + error?.body?.error?.type === 'snapshot_in_progress_exception' ); }, timer(delay), @@ -85,15 +86,7 @@ export function migrationsRetryCallCluster( * * @param apiCaller */ - -// TODO: Replace with APICaller from './scoped_cluster_client' once #46668 is merged -export function retryCallCluster( - apiCaller: ( - endpoint: string, - clientParams: Record, - options?: CallAPIOptions - ) => Promise -) { +export function retryCallCluster(apiCaller: APICaller) { return (endpoint: string, clientParams: Record = {}, options?: CallAPIOptions) => { return defer(() => apiCaller(endpoint, clientParams, options)) .pipe( diff --git a/src/core/server/plugins/plugin.ts b/src/core/server/plugins/plugin.ts index d6c774f6fc41c..b372874264eb5 100644 --- a/src/core/server/plugins/plugin.ts +++ b/src/core/server/plugins/plugin.ts @@ -95,7 +95,7 @@ export class PluginWrapper< public async setup(setupContext: CoreSetup, plugins: TPluginsSetup) { this.instance = this.createPluginInstance(); - this.log.info('Setting up plugin'); + this.log.debug('Setting up plugin'); return this.instance.setup(setupContext, plugins); } @@ -112,6 +112,8 @@ export class PluginWrapper< throw new Error(`Plugin "${this.name}" can't be started since it isn't set up.`); } + this.log.debug('Starting plugin'); + const startContract = await this.instance.start(startContext, plugins); this.startDependencies$.next([startContext, plugins]); return startContract; diff --git a/src/core/server/uuid/resolve_uuid.test.ts b/src/core/server/uuid/resolve_uuid.test.ts index d1332daa02057..efc90c07c1fa6 100644 --- a/src/core/server/uuid/resolve_uuid.test.ts +++ b/src/core/server/uuid/resolve_uuid.test.ts @@ -19,7 +19,7 @@ import { join } from 'path'; import { readFile, writeFile } from './fs'; -import { resolveInstanceUuid } from './resolve_uuid'; +import { resolveInstanceUuid, UUID_7_6_0_BUG } from './resolve_uuid'; import { configServiceMock } from '../config/config_service.mock'; import { loggingServiceMock } from '../logging/logging_service.mock'; import { BehaviorSubject } from 'rxjs'; @@ -97,58 +97,96 @@ describe('resolveInstanceUuid', () => { }); describe('when file is present and config property is set', () => { - it('writes to file and returns the config uuid if they mismatch', async () => { - const uuid = await resolveInstanceUuid(configService, logger); - expect(uuid).toEqual(DEFAULT_CONFIG_UUID); - expect(writeFile).toHaveBeenCalledWith( - join('data-folder', 'uuid'), - DEFAULT_CONFIG_UUID, - expect.any(Object) - ); - expect(logger.debug).toHaveBeenCalledTimes(1); - expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "Updating Kibana instance UUID to: CONFIG_UUID (was: FILE_UUID)", - ] - `); + describe('when they mismatch', () => { + describe('when syncToFile is true', () => { + it('writes to file and returns the config uuid', async () => { + const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); + expect(uuid).toEqual(DEFAULT_CONFIG_UUID); + expect(writeFile).toHaveBeenCalledWith( + join('data-folder', 'uuid'), + DEFAULT_CONFIG_UUID, + expect.any(Object) + ); + expect(logger.debug).toHaveBeenCalledTimes(1); + expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "Updating Kibana instance UUID to: CONFIG_UUID (was: FILE_UUID)", + ] + `); + }); + }); + + describe('when syncTofile is false', () => { + it('does not write to file and returns the config uuid', async () => { + const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: false }); + expect(uuid).toEqual(DEFAULT_CONFIG_UUID); + expect(writeFile).not.toHaveBeenCalled(); + expect(logger.debug).toHaveBeenCalledTimes(1); + expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "Updating Kibana instance UUID to: CONFIG_UUID (was: FILE_UUID)", + ] + `); + }); + }); }); - it('does not write to file if they match', async () => { - mockReadFile({ uuid: DEFAULT_CONFIG_UUID }); - const uuid = await resolveInstanceUuid(configService, logger); - expect(uuid).toEqual(DEFAULT_CONFIG_UUID); - expect(writeFile).not.toHaveBeenCalled(); - expect(logger.debug).toHaveBeenCalledTimes(1); - expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "Kibana instance UUID: CONFIG_UUID", - ] - `); + + describe('when they match', () => { + it('does not write to file', async () => { + mockReadFile({ uuid: DEFAULT_CONFIG_UUID }); + const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); + expect(uuid).toEqual(DEFAULT_CONFIG_UUID); + expect(writeFile).not.toHaveBeenCalled(); + expect(logger.debug).toHaveBeenCalledTimes(1); + expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "Kibana instance UUID: CONFIG_UUID", + ] + `); + }); }); }); describe('when file is not present and config property is set', () => { - it('writes the uuid to file and returns the config uuid', async () => { - mockReadFile({ error: fileNotFoundError }); - const uuid = await resolveInstanceUuid(configService, logger); - expect(uuid).toEqual(DEFAULT_CONFIG_UUID); - expect(writeFile).toHaveBeenCalledWith( - join('data-folder', 'uuid'), - DEFAULT_CONFIG_UUID, - expect.any(Object) - ); - expect(logger.debug).toHaveBeenCalledTimes(1); - expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "Setting new Kibana instance UUID: CONFIG_UUID", - ] - `); + describe('when syncToFile is true', () => { + it('writes the uuid to file and returns the config uuid', async () => { + mockReadFile({ error: fileNotFoundError }); + const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); + expect(uuid).toEqual(DEFAULT_CONFIG_UUID); + expect(writeFile).toHaveBeenCalledWith( + join('data-folder', 'uuid'), + DEFAULT_CONFIG_UUID, + expect.any(Object) + ); + expect(logger.debug).toHaveBeenCalledTimes(1); + expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "Setting new Kibana instance UUID: CONFIG_UUID", + ] + `); + }); + }); + + describe('when syncToFile is false', () => { + it('does not write the uuid to file and returns the config uuid', async () => { + mockReadFile({ error: fileNotFoundError }); + const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: false }); + expect(uuid).toEqual(DEFAULT_CONFIG_UUID); + expect(writeFile).not.toHaveBeenCalled(); + expect(logger.debug).toHaveBeenCalledTimes(1); + expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "Setting new Kibana instance UUID: CONFIG_UUID", + ] + `); + }); }); }); describe('when file is present and config property is not set', () => { it('does not write to file and returns the file uuid', async () => { configService = getConfigService(undefined); - const uuid = await resolveInstanceUuid(configService, logger); + const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); expect(uuid).toEqual(DEFAULT_FILE_UUID); expect(writeFile).not.toHaveBeenCalled(); expect(logger.debug).toHaveBeenCalledTimes(1); @@ -160,23 +198,95 @@ describe('resolveInstanceUuid', () => { }); }); + describe('when file is present with 7.6.0 UUID', () => { + describe('when config property is not set', () => { + it('writes new uuid to file and returns new uuid', async () => { + mockReadFile({ uuid: UUID_7_6_0_BUG }); + configService = getConfigService(undefined); + const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); + expect(uuid).not.toEqual(UUID_7_6_0_BUG); + expect(uuid).toEqual('NEW_UUID'); + expect(writeFile).toHaveBeenCalledWith( + join('data-folder', 'uuid'), + 'NEW_UUID', + expect.any(Object) + ); + expect(logger.debug).toHaveBeenCalledTimes(2); + expect(logger.debug.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "UUID from 7.6.0 bug detected, ignoring file UUID", + ], + Array [ + "Setting new Kibana instance UUID: NEW_UUID", + ], + ] + `); + }); + }); + + describe('when config property is set', () => { + it('writes config uuid to file and returns config uuid', async () => { + mockReadFile({ uuid: UUID_7_6_0_BUG }); + configService = getConfigService(DEFAULT_CONFIG_UUID); + const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); + expect(uuid).not.toEqual(UUID_7_6_0_BUG); + expect(uuid).toEqual(DEFAULT_CONFIG_UUID); + expect(writeFile).toHaveBeenCalledWith( + join('data-folder', 'uuid'), + DEFAULT_CONFIG_UUID, + expect.any(Object) + ); + expect(logger.debug).toHaveBeenCalledTimes(2); + expect(logger.debug.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "UUID from 7.6.0 bug detected, ignoring file UUID", + ], + Array [ + "Setting new Kibana instance UUID: CONFIG_UUID", + ], + ] + `); + }); + }); + }); + describe('when file is not present and config property is not set', () => { - it('generates a new uuid and write it to file', async () => { - configService = getConfigService(undefined); - mockReadFile({ error: fileNotFoundError }); - const uuid = await resolveInstanceUuid(configService, logger); - expect(uuid).toEqual('NEW_UUID'); - expect(writeFile).toHaveBeenCalledWith( - join('data-folder', 'uuid'), - 'NEW_UUID', - expect.any(Object) - ); - expect(logger.debug).toHaveBeenCalledTimes(1); - expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "Setting new Kibana instance UUID: NEW_UUID", - ] - `); + describe('when syncToFile is true', () => { + it('generates a new uuid and write it to file', async () => { + configService = getConfigService(undefined); + mockReadFile({ error: fileNotFoundError }); + const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); + expect(uuid).toEqual('NEW_UUID'); + expect(writeFile).toHaveBeenCalledWith( + join('data-folder', 'uuid'), + 'NEW_UUID', + expect.any(Object) + ); + expect(logger.debug).toHaveBeenCalledTimes(1); + expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "Setting new Kibana instance UUID: NEW_UUID", + ] + `); + }); + }); + + describe('when syncToFile is false', () => { + it('generates a new uuid and does not write it to file', async () => { + configService = getConfigService(undefined); + mockReadFile({ error: fileNotFoundError }); + const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: false }); + expect(uuid).toEqual('NEW_UUID'); + expect(writeFile).not.toHaveBeenCalled(); + expect(logger.debug).toHaveBeenCalledTimes(1); + expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "Setting new Kibana instance UUID: NEW_UUID", + ] + `); + }); }); }); @@ -184,7 +294,7 @@ describe('resolveInstanceUuid', () => { it('throws an explicit error for file read errors', async () => { mockReadFile({ error: permissionError }); await expect( - resolveInstanceUuid(configService, logger) + resolveInstanceUuid({ configService, logger, syncToFile: true }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Unable to read Kibana UUID file, please check the uuid.server configuration value in kibana.yml and ensure Kibana has sufficient permissions to read / write to this file. Error was: EACCES"` ); @@ -192,7 +302,7 @@ describe('resolveInstanceUuid', () => { it('throws an explicit error for file write errors', async () => { mockWriteFile(isDirectoryError); await expect( - resolveInstanceUuid(configService, logger) + resolveInstanceUuid({ configService, logger, syncToFile: true }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Unable to write Kibana UUID file, please check the uuid.server configuration value in kibana.yml and ensure Kibana has sufficient permissions to read / write to this file. Error was: EISDIR"` ); diff --git a/src/core/server/uuid/resolve_uuid.ts b/src/core/server/uuid/resolve_uuid.ts index 3f5bdc7387392..516357e10d3f7 100644 --- a/src/core/server/uuid/resolve_uuid.ts +++ b/src/core/server/uuid/resolve_uuid.ts @@ -28,11 +28,21 @@ import { Logger } from '../logging'; const FILE_ENCODING = 'utf8'; const FILE_NAME = 'uuid'; +/** + * This UUID was inadvertantly shipped in the 7.6.0 distributable and should be deleted if found. + * See https://github.com/elastic/kibana/issues/57673 for more info. + */ +export const UUID_7_6_0_BUG = `ce42b997-a913-4d58-be46-bb1937feedd6`; -export async function resolveInstanceUuid( - configService: IConfigService, - logger: Logger -): Promise { +export async function resolveInstanceUuid({ + configService, + syncToFile, + logger, +}: { + configService: IConfigService; + syncToFile: boolean; + logger: Logger; +}): Promise { const [pathConfig, serverConfig] = await Promise.all([ configService .atPath(pathConfigDef.path) @@ -46,7 +56,7 @@ export async function resolveInstanceUuid( const uuidFilePath = join(pathConfig.data, FILE_NAME); - const uuidFromFile = await readUuidFromFile(uuidFilePath); + const uuidFromFile = await readUuidFromFile(uuidFilePath, logger); const uuidFromConfig = serverConfig.uuid; if (uuidFromConfig) { @@ -61,7 +71,7 @@ export async function resolveInstanceUuid( } else { logger.debug(`Updating Kibana instance UUID to: ${uuidFromConfig} (was: ${uuidFromFile})`); } - await writeUuidToFile(uuidFilePath, uuidFromConfig); + await writeUuidToFile(uuidFilePath, uuidFromConfig, syncToFile); return uuidFromConfig; } } @@ -69,7 +79,7 @@ export async function resolveInstanceUuid( const newUuid = uuid.v4(); // no uuid either in config or file, we need to generate and write it. logger.debug(`Setting new Kibana instance UUID: ${newUuid}`); - await writeUuidToFile(uuidFilePath, newUuid); + await writeUuidToFile(uuidFilePath, newUuid, syncToFile); return newUuid; } @@ -77,10 +87,17 @@ export async function resolveInstanceUuid( return uuidFromFile; } -async function readUuidFromFile(filepath: string): Promise { +async function readUuidFromFile(filepath: string, logger: Logger): Promise { try { const content = await readFile(filepath); - return content.toString(FILE_ENCODING); + const decoded = content.toString(FILE_ENCODING); + + if (decoded === UUID_7_6_0_BUG) { + logger.debug(`UUID from 7.6.0 bug detected, ignoring file UUID`); + return undefined; + } else { + return decoded; + } } catch (e) { if (e.code === 'ENOENT') { // non-existent uuid file is ok, we will create it. @@ -94,7 +111,11 @@ async function readUuidFromFile(filepath: string): Promise { } } -async function writeUuidToFile(filepath: string, uuidValue: string) { +async function writeUuidToFile(filepath: string, uuidValue: string, syncToFile: boolean) { + if (!syncToFile) { + return; + } + try { return await writeFile(filepath, uuidValue, { encoding: FILE_ENCODING }); } catch (e) { diff --git a/src/core/server/uuid/uuid_service.test.ts b/src/core/server/uuid/uuid_service.test.ts index 315df7af8aa19..a61061ff84263 100644 --- a/src/core/server/uuid/uuid_service.test.ts +++ b/src/core/server/uuid/uuid_service.test.ts @@ -23,6 +23,8 @@ import { CoreContext } from '../core_context'; import { loggingServiceMock } from '../logging/logging_service.mock'; import { mockCoreContext } from '../core_context.mock'; +import { Env } from '../config'; +import { getEnvOptions } from '../config/__mocks__/env'; jest.mock('./resolve_uuid', () => ({ resolveInstanceUuid: jest.fn().mockResolvedValue('SOME_UUID'), @@ -31,26 +33,44 @@ jest.mock('./resolve_uuid', () => ({ describe('UuidService', () => { let logger: ReturnType; let coreContext: CoreContext; - let service: UuidService; beforeEach(() => { jest.clearAllMocks(); logger = loggingServiceMock.create(); coreContext = mockCoreContext.create({ logger }); - service = new UuidService(coreContext); }); describe('#setup()', () => { - it('calls manageInstanceUuid with core configuration service', async () => { + it('calls resolveInstanceUuid with core configuration service', async () => { + const service = new UuidService(coreContext); await service.setup(); expect(resolveInstanceUuid).toHaveBeenCalledTimes(1); - expect(resolveInstanceUuid).toHaveBeenCalledWith( - coreContext.configService, - logger.get('uuid') - ); + expect(resolveInstanceUuid).toHaveBeenCalledWith({ + configService: coreContext.configService, + syncToFile: true, + logger: logger.get('uuid'), + }); }); - it('returns the uuid resolved from manageInstanceUuid', async () => { + describe('when cliArgs.optimize is true', () => { + it('calls resolveInstanceUuid with syncToFile: false', async () => { + coreContext = mockCoreContext.create({ + logger, + env: Env.createDefault(getEnvOptions({ cliArgs: { optimize: true } })), + }); + const service = new UuidService(coreContext); + await service.setup(); + expect(resolveInstanceUuid).toHaveBeenCalledTimes(1); + expect(resolveInstanceUuid).toHaveBeenCalledWith({ + configService: coreContext.configService, + syncToFile: false, + logger: logger.get('uuid'), + }); + }); + }); + + it('returns the uuid resolved from resolveInstanceUuid', async () => { + const service = new UuidService(coreContext); const setup = await service.setup(); expect(setup.getInstanceUuid()).toEqual('SOME_UUID'); }); diff --git a/src/core/server/uuid/uuid_service.ts b/src/core/server/uuid/uuid_service.ts index 10104fa704936..62ed4a19edf5a 100644 --- a/src/core/server/uuid/uuid_service.ts +++ b/src/core/server/uuid/uuid_service.ts @@ -20,7 +20,7 @@ import { resolveInstanceUuid } from './resolve_uuid'; import { CoreContext } from '../core_context'; import { Logger } from '../logging'; -import { IConfigService } from '../config'; +import { IConfigService, CliArgs } from '../config'; /** * APIs to access the application's instance uuid. @@ -38,15 +38,21 @@ export interface UuidServiceSetup { export class UuidService { private readonly log: Logger; private readonly configService: IConfigService; + private readonly cliArgs: CliArgs; private uuid: string = ''; constructor(core: CoreContext) { this.log = core.logger.get('uuid'); this.configService = core.configService; + this.cliArgs = core.env.cliArgs; } public async setup() { - this.uuid = await resolveInstanceUuid(this.configService, this.log); + this.uuid = await resolveInstanceUuid({ + configService: this.configService, + syncToFile: !this.cliArgs.optimize, + logger: this.log, + }); return { getInstanceUuid: () => this.uuid, diff --git a/src/core/utils/merge.test.ts b/src/core/utils/merge.test.ts index c857e980dec21..7ef07a83399ac 100644 --- a/src/core/utils/merge.test.ts +++ b/src/core/utils/merge.test.ts @@ -17,6 +17,7 @@ * under the License. */ +// eslint-disable-next-line max-classes-per-file import { merge } from './merge'; describe('merge', () => { @@ -62,6 +63,29 @@ describe('merge', () => { expect(merge({ a: 0 }, { a: 1 }, {})).toEqual({ a: 1 }); }); + test('does not merge class instances', () => { + class Folder { + constructor(public readonly path: string) {} + getPath() { + return this.path; + } + } + class File { + constructor(public readonly content: string) {} + getContent() { + return this.content; + } + } + const folder = new Folder('/etc'); + const file = new File('yolo'); + + const result = merge({}, { content: folder }, { content: file }); + expect(result).toStrictEqual({ + content: file, + }); + expect(result.content.getContent()).toBe('yolo'); + }); + test(`doesn't pollute prototypes`, () => { merge({}, JSON.parse('{ "__proto__": { "foo": "bar" } }')); merge({}, JSON.parse('{ "constructor": { "prototype": { "foo": "bar" } } }')); diff --git a/src/core/utils/merge.ts b/src/core/utils/merge.ts index 8e5d9f4860d95..43878c27b1e19 100644 --- a/src/core/utils/merge.ts +++ b/src/core/utils/merge.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import { isPlainObject } from 'lodash'; /** * Deeply merges two objects, omitting undefined values, and not deeply merging Arrays. * @@ -60,7 +60,7 @@ export function merge>( ) as TReturn; } -const isMergable = (obj: any) => typeof obj === 'object' && obj !== null && !Array.isArray(obj); +const isMergable = (obj: any) => isPlainObject(obj); const mergeObjects = , U extends Record>( baseObj: T, diff --git a/src/dev/build/build_distributables.js b/src/dev/build/build_distributables.js index c4f9d7f56554c..6c2efeebc60c3 100644 --- a/src/dev/build/build_distributables.js +++ b/src/dev/build/build_distributables.js @@ -54,6 +54,7 @@ import { VerifyExistingNodeBuildsTask, PathLengthTask, WriteShaSumsTask, + UuidVerificationTask, } from './tasks'; export async function buildDistributables(options) { @@ -136,6 +137,7 @@ export async function buildDistributables(options) { await run(CleanNodeBuildsTask); await run(PathLengthTask); + await run(UuidVerificationTask); /** * package platform-specific builds into archives diff --git a/src/dev/build/tasks/index.js b/src/dev/build/tasks/index.js index 56e813111279d..8105fa8a7d5d4 100644 --- a/src/dev/build/tasks/index.js +++ b/src/dev/build/tasks/index.js @@ -38,3 +38,4 @@ export * from './verify_env_task'; export * from './write_sha_sums_task'; export * from './path_length_task'; export * from './build_kibana_platform_plugins'; +export * from './uuid_verification_task'; diff --git a/typings/normalize_path/index.d.ts b/src/dev/build/tasks/uuid_verification_task.js similarity index 61% rename from typings/normalize_path/index.d.ts rename to src/dev/build/tasks/uuid_verification_task.js index 31e064ca63d90..32c9e73dba988 100644 --- a/typings/normalize_path/index.d.ts +++ b/src/dev/build/tasks/uuid_verification_task.js @@ -17,8 +17,22 @@ * under the License. */ -declare function NormalizePath(path: string, stripTrailing?: boolean): string; +import { read } from '../lib'; -declare module 'normalize-path' { - export = NormalizePath; -} +export const UuidVerificationTask = { + description: 'Verify that no UUID file is baked into the build', + + async run(config, log, build) { + const uuidFilePath = build.resolvePath('data', 'uuid'); + await read(uuidFilePath).then( + function success() { + throw new Error(`UUID file should not exist at [${uuidFilePath}]`); + }, + function error(err) { + if (err.code !== 'ENOENT') { + throw err; + } + } + ); + }, +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js b/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts similarity index 54% rename from src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js rename to src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts index 749dad377f2e2..976ab57c00b63 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/__tests__/buckets/_terms_other_bucket_helper.js +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts @@ -17,39 +17,73 @@ * under the License. */ -import expect from '@kbn/expect'; -import ngMock from 'ng_mock'; import { buildOtherBucketAgg, mergeOtherBucketAggResponse, updateMissingBucket, -} from '../../buckets/_terms_other_bucket_helper'; -import { start as visualizationsStart } from '../../../../../../../core_plugins/visualizations/public/np_ready/public/legacy'; -import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; +} from './_terms_other_bucket_helper'; +import { AggConfigs, CreateAggConfigParams } from '../agg_configs'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { IBucketAggConfig } from './_bucket_agg_type'; +import { mockDataServices, mockAggTypesRegistry } from '../test_helpers'; -const visConfigSingleTerm = { - type: 'pie', +const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: [ + { + name: 'field', + }, + ], +} as any; + +const singleTerm = { aggs: [ { - type: 'terms', - schema: 'segment', - params: { field: 'machine.os.raw', otherBucket: true, missingBucket: true }, + id: '1', + type: BUCKET_TYPES.TERMS, + params: { + field: { + name: 'machine.os.raw', + indexPattern, + filterable: true, + }, + otherBucket: true, + missingBucket: true, + }, }, ], }; -const visConfigNestedTerm = { - type: 'pie', +const nestedTerm = { aggs: [ { - type: 'terms', - schema: 'segment', - params: { field: 'geo.src', size: 2, otherBucket: false, missingBucket: false }, + id: '1', + type: BUCKET_TYPES.TERMS, + params: { + field: { + name: 'geo.src', + indexPattern, + filterable: true, + }, + size: 2, + otherBucket: false, + missingBucket: false, + }, }, { - type: 'terms', - schema: 'segment', - params: { field: 'machine.os.raw', size: 2, otherBucket: true, missingBucket: true }, + id: '2', + type: BUCKET_TYPES.TERMS, + params: { + field: { + name: 'machine.os.raw', + indexPattern, + filterable: true, + }, + size: 2, + otherBucket: true, + missingBucket: true, + }, }, ], }; @@ -183,28 +217,36 @@ const nestedOtherResponse = { status: 200, }; -describe('Terms Agg Other bucket helper', () => { - let vis; +jest.mock('ui/new_platform'); - function init(aggConfig) { - ngMock.module('kibana'); - ngMock.inject(Private => { - const indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider); +describe('Terms Agg Other bucket helper', () => { + const typesRegistry = mockAggTypesRegistry(); + const getAggConfigs = (aggs: CreateAggConfigParams[] = []) => { + return new AggConfigs(indexPattern, [...aggs], { typesRegistry }); + }; - vis = new visualizationsStart.Vis(indexPattern, aggConfig); - }); - } + beforeEach(() => { + mockDataServices(); + }); describe('buildOtherBucketAgg', () => { - it('returns a function', () => { - init(visConfigSingleTerm); - const agg = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[0], singleTermResponse); - expect(agg).to.be.a('function'); + test('returns a function', () => { + const aggConfigs = getAggConfigs(singleTerm.aggs); + const agg = buildOtherBucketAgg( + aggConfigs, + aggConfigs.aggs[0] as IBucketAggConfig, + singleTermResponse + ); + expect(typeof agg).toBe('function'); }); - it('correctly builds query with single terms agg', () => { - init(visConfigSingleTerm); - const agg = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[0], singleTermResponse)(); + test('correctly builds query with single terms agg', () => { + const aggConfigs = getAggConfigs(singleTerm.aggs); + const agg = buildOtherBucketAgg( + aggConfigs, + aggConfigs.aggs[0] as IBucketAggConfig, + singleTermResponse + ); const expectedResponse = { aggs: undefined, filters: { @@ -223,13 +265,19 @@ describe('Terms Agg Other bucket helper', () => { }, }, }; - - expect(agg['other-filter']).to.eql(expectedResponse); + expect(agg).toBeDefined(); + if (agg) { + expect(agg()['other-filter']).toEqual(expectedResponse); + } }); - it('correctly builds query for nested terms agg', () => { - init(visConfigNestedTerm); - const agg = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[1], nestedTermResponse)(); + test('correctly builds query for nested terms agg', () => { + const aggConfigs = getAggConfigs(nestedTerm.aggs); + const agg = buildOtherBucketAgg( + aggConfigs, + aggConfigs.aggs[1] as IBucketAggConfig, + nestedTermResponse + ); const expectedResponse = { 'other-filter': { aggs: undefined, @@ -267,54 +315,84 @@ describe('Terms Agg Other bucket helper', () => { }, }, }; - - expect(agg).to.eql(expectedResponse); + expect(agg).toBeDefined(); + if (agg) { + expect(agg()).toEqual(expectedResponse); + } }); - it('returns false when nested terms agg has no buckets', () => { - init(visConfigNestedTerm); - const agg = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[1], nestedTermResponseNoResults); - expect(agg).to.eql(false); + test('returns false when nested terms agg has no buckets', () => { + const aggConfigs = getAggConfigs(nestedTerm.aggs); + const agg = buildOtherBucketAgg( + aggConfigs, + aggConfigs.aggs[1] as IBucketAggConfig, + nestedTermResponseNoResults + ); + + expect(agg).toEqual(false); }); }); describe('mergeOtherBucketAggResponse', () => { - it('correctly merges other bucket with single terms agg', () => { - init(visConfigSingleTerm); - const otherAggConfig = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[0], singleTermResponse)(); - const mergedResponse = mergeOtherBucketAggResponse( - vis.aggs, - singleTermResponse, - singleOtherResponse, - vis.aggs.aggs[0], - otherAggConfig + test('correctly merges other bucket with single terms agg', () => { + const aggConfigs = getAggConfigs(singleTerm.aggs); + const otherAggConfig = buildOtherBucketAgg( + aggConfigs, + aggConfigs.aggs[0] as IBucketAggConfig, + singleTermResponse ); - expect(mergedResponse.aggregations['1'].buckets[3].key).to.equal('__other__'); + expect(otherAggConfig).toBeDefined(); + if (otherAggConfig) { + const mergedResponse = mergeOtherBucketAggResponse( + aggConfigs, + singleTermResponse, + singleOtherResponse, + aggConfigs.aggs[0] as IBucketAggConfig, + otherAggConfig() + ); + expect(mergedResponse.aggregations['1'].buckets[3].key).toEqual('__other__'); + } }); - it('correctly merges other bucket with nested terms agg', () => { - init(visConfigNestedTerm); - const otherAggConfig = buildOtherBucketAgg(vis.aggs, vis.aggs.aggs[1], nestedTermResponse)(); - const mergedResponse = mergeOtherBucketAggResponse( - vis.aggs, - nestedTermResponse, - nestedOtherResponse, - vis.aggs.aggs[1], - otherAggConfig + test('correctly merges other bucket with nested terms agg', () => { + const aggConfigs = getAggConfigs(nestedTerm.aggs); + const otherAggConfig = buildOtherBucketAgg( + aggConfigs, + aggConfigs.aggs[1] as IBucketAggConfig, + nestedTermResponse ); - expect(mergedResponse.aggregations['1'].buckets[1]['2'].buckets[3].key).to.equal('__other__'); + expect(otherAggConfig).toBeDefined(); + if (otherAggConfig) { + const mergedResponse = mergeOtherBucketAggResponse( + aggConfigs, + nestedTermResponse, + nestedOtherResponse, + aggConfigs.aggs[1] as IBucketAggConfig, + otherAggConfig() + ); + + expect(mergedResponse.aggregations['1'].buckets[1]['2'].buckets[3].key).toEqual( + '__other__' + ); + } }); }); describe('updateMissingBucket', () => { - it('correctly updates missing bucket key', () => { - init(visConfigNestedTerm); - const updatedResponse = updateMissingBucket(singleTermResponse, vis.aggs, vis.aggs.aggs[0]); + test('correctly updates missing bucket key', () => { + const aggConfigs = getAggConfigs(nestedTerm.aggs); + const updatedResponse = updateMissingBucket( + singleTermResponse, + aggConfigs, + aggConfigs.aggs[0] as IBucketAggConfig + ); expect( - updatedResponse.aggregations['1'].buckets.find(bucket => bucket.key === '__missing__') - ).to.not.be('undefined'); + updatedResponse.aggregations['1'].buckets.find( + (bucket: Record) => bucket.key === '__missing__' + ) + ).toBeDefined(); }); }); }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js b/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts similarity index 65% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js rename to src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts index ddab360161744..42db37c81eadd 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.js +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts @@ -17,21 +17,24 @@ * under the License. */ -import _ from 'lodash'; +import { isNumber, keys, values, find, each, cloneDeep, flatten } from 'lodash'; import { esFilters, esQuery } from '../../../../../../../plugins/data/public'; import { AggGroupNames } from '../agg_groups'; +import { IAggConfigs } from '../agg_configs'; +import { IBucketAggConfig } from './_bucket_agg_type'; /** * walks the aggregation DSL and returns DSL starting at aggregation with id of startFromAggId * @param aggNestedDsl: aggregation config DSL (top level) * @param startFromId: id of an aggregation from where we want to get the nested DSL */ -const getNestedAggDSL = (aggNestedDsl, startFromAggId) => { +const getNestedAggDSL = (aggNestedDsl: Record, startFromAggId: string): any => { if (aggNestedDsl[startFromAggId]) { return aggNestedDsl[startFromAggId]; } - const nestedAggs = _.values(aggNestedDsl); + const nestedAggs: Array> = values(aggNestedDsl); let aggs; + for (let i = 0; i < nestedAggs.length; i++) { if (nestedAggs[i].aggs && (aggs = getNestedAggDSL(nestedAggs[i].aggs, startFromAggId))) { return aggs; @@ -46,27 +49,34 @@ const getNestedAggDSL = (aggNestedDsl, startFromAggId) => { * @param aggWithOtherBucket: AggConfig of the aggregation with other bucket enabled * @param key: key from the other bucket request for a specific other bucket */ -const getAggResultBuckets = (aggConfigs, response, aggWithOtherBucket, key) => { +const getAggResultBuckets = ( + aggConfigs: IAggConfigs, + response: any, + aggWithOtherBucket: IBucketAggConfig, + key: string +) => { const keyParts = key.split('-'); let responseAgg = response; for (const i in keyParts) { if (keyParts[i]) { - const responseAggs = _.values(responseAgg); + const responseAggs: Array> = values(responseAgg); // If you have multi aggs, we cannot just assume the first one is the `other` bucket, // so we need to loop over each agg until we find it. for (let aggId = 0; aggId < responseAggs.length; aggId++) { - const agg = responseAggs[aggId]; - const aggKey = _.keys(responseAgg)[aggId]; - const aggConfig = _.find(aggConfigs.aggs, agg => agg.id === aggKey); - const bucket = _.find(agg.buckets, (bucket, bucketObjKey) => { - const bucketKey = aggConfig - .getKey(bucket, Number.isInteger(bucketObjKey) ? null : bucketObjKey) - .toString(); - return bucketKey === keyParts[i]; - }); - if (bucket) { - responseAgg = bucket; - break; + const aggById = responseAggs[aggId]; + const aggKey = keys(responseAgg)[aggId]; + const aggConfig = find(aggConfigs.aggs, agg => agg.id === aggKey); + if (aggConfig) { + const aggResultBucket = find(aggById.buckets, (bucket, bucketObjKey) => { + const bucketKey = aggConfig + .getKey(bucket, isNumber(bucketObjKey) ? undefined : bucketObjKey) + .toString(); + return bucketKey === keyParts[i]; + }); + if (aggResultBucket) { + responseAgg = aggResultBucket; + break; + } } } } @@ -82,21 +92,20 @@ const getAggResultBuckets = (aggConfigs, response, aggWithOtherBucket, key) => { * @param responseAggs: array of aggregations from response * @param aggId: id of the aggregation with missing bucket */ -const getAggConfigResultMissingBuckets = (responseAggs, aggId) => { +const getAggConfigResultMissingBuckets = (responseAggs: any, aggId: string) => { const missingKey = '__missing__'; - let resultBuckets = []; + let resultBuckets: Array> = []; if (responseAggs[aggId]) { - const matchingBucket = responseAggs[aggId].buckets.find(bucket => bucket.key === missingKey); + const matchingBucket = responseAggs[aggId].buckets.find( + (bucket: Record) => bucket.key === missingKey + ); if (matchingBucket) resultBuckets.push(matchingBucket); return resultBuckets; } - _.each(responseAggs, agg => { + each(responseAggs, agg => { if (agg.buckets) { - _.each(agg.buckets, bucket => { - resultBuckets = [ - ...resultBuckets, - ...getAggConfigResultMissingBuckets(bucket, aggId, missingKey), - ]; + each(agg.buckets, bucket => { + resultBuckets = [...resultBuckets, ...getAggConfigResultMissingBuckets(bucket, aggId)]; }); } }); @@ -110,13 +119,24 @@ const getAggConfigResultMissingBuckets = (responseAggs, aggId) => { * @param key: the key for this specific other bucket * @param otherAgg: AggConfig of the aggregation with other bucket */ -const getOtherAggTerms = (requestAgg, key, otherAgg) => { +const getOtherAggTerms = ( + requestAgg: Record, + key: string, + otherAgg: IBucketAggConfig +) => { return requestAgg['other-filter'].filters.filters[key].bool.must_not - .filter(filter => filter.match_phrase && filter.match_phrase[otherAgg.params.field.name]) - .map(filter => filter.match_phrase[otherAgg.params.field.name]); + .filter( + (filter: Record) => + filter.match_phrase && filter.match_phrase[otherAgg.params.field.name] + ) + .map((filter: Record) => filter.match_phrase[otherAgg.params.field.name]); }; -export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) => { +export const buildOtherBucketAgg = ( + aggConfigs: IAggConfigs, + aggWithOtherBucket: IBucketAggConfig, + response: any +) => { const bucketAggs = aggConfigs.aggs.filter(agg => agg.type.type === AggGroupNames.Buckets); const index = bucketAggs.findIndex(agg => agg.id === aggWithOtherBucket.id); const aggs = aggConfigs.toDsl(); @@ -130,6 +150,7 @@ export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) => params: { filters: [], }, + enabled: false, }, { addToAggConfigs: false, @@ -145,25 +166,31 @@ export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) => let noAggBucketResults = false; // recursively create filters for all parent aggregation buckets - const walkBucketTree = (aggIndex, aggs, aggId, filters, key) => { + const walkBucketTree = ( + aggIndex: number, + aggregations: any, + aggId: string, + filters: any[], + key: string + ) => { // make sure there are actually results for the buckets - if (aggs[aggId].buckets.length < 1) { + if (aggregations[aggId].buckets.length < 1) { noAggBucketResults = true; return; } - const agg = aggs[aggId]; + const agg = aggregations[aggId]; const newAggIndex = aggIndex + 1; const newAgg = bucketAggs[newAggIndex]; const currentAgg = bucketAggs[aggIndex]; if (aggIndex < index) { - _.each(agg.buckets, (bucket, bucketObjKey) => { + each(agg.buckets, (bucket: any, bucketObjKey) => { const bucketKey = currentAgg.getKey( bucket, - Number.isInteger(bucketObjKey) ? null : bucketObjKey + isNumber(bucketObjKey) ? undefined : bucketObjKey ); - const filter = _.cloneDeep(bucket.filters) || currentAgg.createFilter(bucketKey); - const newFilters = _.flatten([...filters, filter]); + const filter = cloneDeep(bucket.filters) || currentAgg.createFilter(bucketKey); + const newFilters = flatten([...filters, filter]); walkBucketTree( newAggIndex, bucket, @@ -177,7 +204,7 @@ export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) => if ( !aggWithOtherBucket.params.missingBucket || - agg.buckets.some(bucket => bucket.key === '__missing__') + agg.buckets.some((bucket: { key: string }) => bucket.key === '__missing__') ) { filters.push( esFilters.buildExistsFilter( @@ -188,7 +215,7 @@ export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) => } // create not filters for all the buckets - _.each(agg.buckets, bucket => { + each(agg.buckets, bucket => { if (bucket.key === '__missing__') return; const filter = currentAgg.createFilter(bucket.key); filter.meta.negate = true; @@ -214,15 +241,15 @@ export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) => }; export const mergeOtherBucketAggResponse = ( - aggsConfig, - response, - otherResponse, - otherAgg, - requestAgg + aggsConfig: IAggConfigs, + response: any, + otherResponse: any, + otherAgg: IBucketAggConfig, + requestAgg: Record ) => { - const updatedResponse = _.cloneDeep(response); - _.each(otherResponse.aggregations['other-filter'].buckets, (bucket, key) => { - if (!bucket.doc_count) return; + const updatedResponse = cloneDeep(response); + each(otherResponse.aggregations['other-filter'].buckets, (bucket, key) => { + if (!bucket.doc_count || key === undefined) return; const bucketKey = key.replace(/^-/, ''); const aggResultBuckets = getAggResultBuckets( aggsConfig, @@ -241,7 +268,11 @@ export const mergeOtherBucketAggResponse = ( bucket.filters = [phraseFilter]; bucket.key = '__other__'; - if (aggResultBuckets.some(bucket => bucket.key === '__missing__')) { + if ( + aggResultBuckets.some( + (aggResultBucket: Record) => aggResultBucket.key === '__missing__' + ) + ) { bucket.filters.push( esFilters.buildExistsFilter(otherAgg.params.field, otherAgg.params.field.indexPattern) ); @@ -251,8 +282,12 @@ export const mergeOtherBucketAggResponse = ( return updatedResponse; }; -export const updateMissingBucket = (response, aggConfigs, agg) => { - const updatedResponse = _.cloneDeep(response); +export const updateMissingBucket = ( + response: any, + aggConfigs: IAggConfigs, + agg: IBucketAggConfig +) => { + const updatedResponse = cloneDeep(response); const aggResultBuckets = getAggConfigResultMissingBuckets(updatedResponse.aggregations, agg.id); aggResultBuckets.forEach(bucket => { bucket.key = '__missing__'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts index 0ed44aa876744..8fd95c86d8476 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts @@ -39,7 +39,6 @@ import { buildOtherBucketAgg, mergeOtherBucketAggResponse, updateMissingBucket, - // @ts-ignore } from './_terms_other_bucket_helper'; import { Schemas } from '../schemas'; import { AggGroupNames } from '../agg_groups'; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.ts index 8fb6140d55e31..bf185f78941de 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.ts +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.ts @@ -24,9 +24,9 @@ import { syncStates, BaseStateContainer, } from '../../../../../../../plugins/kibana_utils/public'; -import { esFilters, FilterManager, Filter } from '../../../../../../../plugins/data/public'; +import { esFilters, FilterManager, Filter, Query } from '../../../../../../../plugins/data/public'; -interface AppState { +export interface AppState { /** * Columns displayed in the table, cannot be changed by UI, just in discover's main app */ @@ -47,6 +47,7 @@ interface AppState { * Number of records to be fetched after the anchor records (older records) */ successorCount: number; + query?: Query; } interface GlobalState { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/field_chooser.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/field_chooser.js index a175a1aebebdf..df970ab5f2584 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/field_chooser.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/field_chooser.js @@ -24,7 +24,11 @@ import './discover_field'; import './discover_field_search_directive'; import './discover_index_pattern_directive'; import fieldChooserTemplate from './field_chooser.html'; -import { IndexPatternFieldList } from '../../../../../../../../plugins/data/public'; +import { + IndexPatternFieldList, + KBN_FIELD_TYPES, +} from '../../../../../../../../plugins/data/public'; +import { getMapsAppUrl, isFieldVisualizable, isMapsAppRegistered } from './lib/visualize_url_utils'; export function createFieldChooserDirective($location, config, $route) { return { @@ -186,8 +190,15 @@ export function createFieldChooserDirective($location, config, $route) { return ''; } + if ( + (field.type === KBN_FIELD_TYPES.GEO_POINT || field.type === KBN_FIELD_TYPES.GEO_SHAPE) && + isMapsAppRegistered() + ) { + return getMapsAppUrl(field, $scope.indexPattern, $scope.state, $scope.columns); + } + let agg = {}; - const isGeoPoint = field.type === 'geo_point'; + const isGeoPoint = field.type === KBN_FIELD_TYPES.GEO_POINT; const type = isGeoPoint ? 'tile_map' : 'histogram'; // If we're visualizing a date field, and our index is time based (and thus has a time filter), // then run a date histogram @@ -243,7 +254,7 @@ export function createFieldChooserDirective($location, config, $route) { $scope.computeDetails = function(field, recompute) { if (_.isUndefined(field.details) || recompute) { field.details = { - visualizeUrl: field.visualizable ? getVisualizeUrl(field) : null, + visualizeUrl: isFieldVisualizable(field) ? getVisualizeUrl(field) : null, ...fieldCalculator.getFieldValueCounts({ hits: $scope.hits, field: field, diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/lib/detail_views/string.html b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/lib/detail_views/string.html index 5d134911fc91b..333dc472e956d 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/lib/detail_views/string.html +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/lib/detail_views/string.html @@ -79,7 +79,7 @@ @@ -87,7 +87,7 @@ diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/lib/visualize_url_utils.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/lib/visualize_url_utils.ts new file mode 100644 index 0000000000000..8dbf3cd79ccb1 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/lib/visualize_url_utils.ts @@ -0,0 +1,108 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import uuid from 'uuid/v4'; +// @ts-ignore +import rison from 'rison-node'; +import { + IFieldType, + IIndexPattern, + KBN_FIELD_TYPES, +} from '../../../../../../../../../plugins/data/public'; +import { AppState } from '../../../angular/context_state'; +import { getServices } from '../../../../kibana_services'; + +function getMapsAppBaseUrl() { + const mapsAppVisAlias = getServices() + .visualizations.types.getAliases() + .find(({ name }) => { + return name === 'maps'; + }); + return mapsAppVisAlias ? mapsAppVisAlias.aliasUrl : null; +} + +export function isMapsAppRegistered() { + return getServices() + .visualizations.types.getAliases() + .some(({ name }) => { + return name === 'maps'; + }); +} + +export function isFieldVisualizable(field: IFieldType) { + if ( + (field.type === KBN_FIELD_TYPES.GEO_POINT || field.type === KBN_FIELD_TYPES.GEO_SHAPE) && + isMapsAppRegistered() + ) { + return true; + } + return field.visualizable; +} + +export function getMapsAppUrl( + field: IFieldType, + indexPattern: IIndexPattern, + appState: AppState, + columns: string[] +) { + const mapAppParams = new URLSearchParams(); + + // Copy global state + const locationSplit = window.location.href.split('discover?'); + if (locationSplit.length > 1) { + const discoverParams = new URLSearchParams(locationSplit[1]); + const globalStateUrlValue = discoverParams.get('_g'); + if (globalStateUrlValue) { + mapAppParams.set('_g', globalStateUrlValue); + } + } + + // Copy filters and query in app state + const mapsAppState: any = { + filters: appState.filters || [], + }; + if (appState.query) { + mapsAppState.query = appState.query; + } + // @ts-ignore + mapAppParams.set('_a', rison.encode(mapsAppState)); + + // create initial layer descriptor + const hasColumns = columns && columns.length && columns[0] !== '_source'; + mapAppParams.set( + 'initialLayers', + // @ts-ignore + rison.encode_array([ + { + id: uuid(), + label: indexPattern.title, + sourceDescriptor: { + id: uuid(), + type: 'ES_SEARCH', + geoField: field.name, + tooltipProperties: hasColumns ? columns : [], + indexPatternId: indexPattern.id, + }, + visible: true, + type: 'VECTOR', + }, + ]) + ); + + return getServices().addBasePath(`${getMapsAppBaseUrl()}?${mapAppParams.toString()}`); +} diff --git a/src/legacy/core_plugins/kibana/public/kibana.js b/src/legacy/core_plugins/kibana/public/kibana.js index a83d1176a7197..a9f32949628e9 100644 --- a/src/legacy/core_plugins/kibana/public/kibana.js +++ b/src/legacy/core_plugins/kibana/public/kibana.js @@ -26,8 +26,6 @@ import { npSetup } from 'ui/new_platform'; // import the uiExports that we want to "use" import 'uiExports/home'; -import 'uiExports/visTypes'; - import 'uiExports/visualize'; import 'uiExports/savedObjectTypes'; import 'uiExports/fieldFormatEditors'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js index 415949f88e9d1..2137e413451d2 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js @@ -382,7 +382,7 @@ function VisualizeAppController( $scope.showQueryBarTimePicker = () => { // tsvb loads without an indexPattern initially (TODO investigate). // hide timefilter only if timeFieldName is explicitly undefined. - const hasTimeField = $scope.indexPattern ? !!$scope.indexPattern.timeFieldName : true; + const hasTimeField = vis.indexPattern ? !!vis.indexPattern.timeFieldName : true; return vis.type.options.showTimePicker && hasTimeField; }; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_select.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_select.tsx index a2cec61b122ef..9a408c2d98b22 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_select.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_select.tsx @@ -17,7 +17,7 @@ * under the License. */ import { get, has } from 'lodash'; -import React, { useEffect, useCallback } from 'react'; +import React, { useEffect, useCallback, useState } from 'react'; import { EuiComboBox, EuiComboBoxOptionProps, EuiFormRow, EuiLink, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -52,6 +52,7 @@ function DefaultEditorAggSelect({ isSubAggregation, onChangeAggType, }: DefaultEditorAggSelectProps) { + const [isDirty, setIsDirty] = useState(false); const { services } = useKibana(); const selectedOptions: ComboBoxGroupedOptions = value ? [{ label: value.title, target: value }] @@ -100,7 +101,7 @@ function DefaultEditorAggSelect({ ); } - const isValid = !!value && !errors.length; + const isValid = !!value && !errors.length && !isDirty; const onChange = useCallback( (options: EuiComboBoxOptionProps[]) => { @@ -111,6 +112,7 @@ function DefaultEditorAggSelect({ }, [setValue] ); + const onSearchChange = useCallback(searchValue => setIsDirty(Boolean(searchValue)), []); const setTouched = useCallback( () => onChangeAggType({ type: AGG_TYPE_ACTION_KEYS.TOUCHED, payload: true }), @@ -151,6 +153,7 @@ function DefaultEditorAggSelect({ singleSelection={{ asPlainText: true }} onBlur={setTouched} onChange={onChange} + onSearchChange={onSearchChange} data-test-subj="defaultEditorAggSelect" isClearable={false} isInvalid={showValidation ? !isValid : false} diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx index 8bf7bc384b07a..d605fb203f4d3 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.tsx @@ -18,7 +18,7 @@ */ import { get } from 'lodash'; -import React, { useEffect } from 'react'; +import React, { useEffect, useState, useCallback } from 'react'; import { EuiComboBox, EuiComboBoxOptionProps, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -50,6 +50,7 @@ function FieldParamEditor({ setValidity, setValue, }: FieldParamEditorProps) { + const [isDirty, setIsDirty] = useState(false); const selectedOptions: ComboBoxGroupedOptions = value ? [{ label: value.displayName || value.name, target: value }] : []; @@ -79,7 +80,7 @@ function FieldParamEditor({ ); } - const isValid = !!value && !errors.length; + const isValid = !!value && !errors.length && !isDirty; useValidation(setValidity, isValid); @@ -98,6 +99,8 @@ function FieldParamEditor({ } }, []); + const onSearchChange = useCallback(searchValue => setIsDirty(Boolean(searchValue)), []); + return ( diff --git a/src/plugins/advanced_settings/public/management_app/advanced_settings.scss b/src/plugins/advanced_settings/public/management_app/advanced_settings.scss index 016edb2817da8..66ae9cca3f83b 100644 --- a/src/plugins/advanced_settings/public/management_app/advanced_settings.scss +++ b/src/plugins/advanced_settings/public/management_app/advanced_settings.scss @@ -22,40 +22,42 @@ margin-top: $euiSize; } + .mgtAdvancedSettings__fieldTitle { + padding-left: $euiSizeS; + margin-left: -$euiSizeS; + } - padding-left: $euiSizeS; - margin-left: -$euiSizeS; - &--unsaved { + &--unsaved .mgtAdvancedSettings__fieldTitle { // Simulates a left side border without shifting content - box-shadow: -$euiSizeXS 0px $euiColorSecondary; + box-shadow: -$euiSizeXS 0px $euiColorWarning; } - &--invalid { + &--invalid .mgtAdvancedSettings__fieldTitle { // Simulates a left side border without shifting content box-shadow: -$euiSizeXS 0px $euiColorDanger; } - @include internetExplorerOnly() { - min-height: 1px; - } - &Row { - padding-left: $euiSizeS; - } @include internetExplorerOnly { + min-height: 1px; + &Row { min-height: 1px; } } } +.mgtAdvancedSettings__fieldTitleUnsavedIcon { + margin-left: $euiSizeS; +} + .mgtAdvancedSettingsForm__unsavedCount { - @include euiBreakpoint('xs', 's') { + @include euiBreakpoint('xs') { display: none; } } -.mgtAdvancedSettingsForm__unsavedCountMessage{ +.mgtAdvancedSettingsForm__unsavedCountMessage { // Simulates a left side border without shifting content - box-shadow: -$euiSizeXS 0px $euiColorSecondary; + box-shadow: -$euiSizeXS 0px $euiColorWarning; padding-left: $euiSizeS; } diff --git a/src/plugins/advanced_settings/public/management_app/components/field/__snapshots__/field.test.tsx.snap b/src/plugins/advanced_settings/public/management_app/components/field/__snapshots__/field.test.tsx.snap index 2f4d806e60244..dba1678339f24 100644 --- a/src/plugins/advanced_settings/public/management_app/components/field/__snapshots__/field.test.tsx.snap +++ b/src/plugins/advanced_settings/public/management_app/components/field/__snapshots__/field.test.tsx.snap @@ -17,7 +17,12 @@ exports[`Field for array setting should render as read only if saving is disable fullWidth={true} title={

- Array test setting + + Array test setting + +

} @@ -84,7 +89,12 @@ exports[`Field for array setting should render as read only with help text if ov fullWidth={true} title={

- Array test setting + + Array test setting + +

} @@ -139,7 +149,11 @@ exports[`Field for array setting should render custom setting icon if it is cust fullWidth={true} title={

- Array test setting + + Array test setting + +

} > @@ -195,7 +210,12 @@ exports[`Field for array setting should render default value if there is no user fullWidth={true} title={

- Array test setting + + Array test setting + +

} @@ -240,7 +260,11 @@ exports[`Field for array setting should render unsaved value if there are unsave fullWidth={true} title={

- Array test setting + + Array test setting + +

} > @@ -330,7 +361,12 @@ exports[`Field for array setting should render user value if there is user value fullWidth={true} title={

- Array test setting + + Array test setting + +

} @@ -392,7 +428,12 @@ exports[`Field for boolean setting should render as read only if saving is disab fullWidth={true} title={

- Boolean test setting + + Boolean test setting + +

} @@ -465,7 +506,12 @@ exports[`Field for boolean setting should render as read only with help text if fullWidth={true} title={

- Boolean test setting + + Boolean test setting + +

} @@ -526,7 +572,11 @@ exports[`Field for boolean setting should render custom setting icon if it is cu fullWidth={true} title={

- Boolean test setting + + Boolean test setting + +

} > @@ -588,7 +639,12 @@ exports[`Field for boolean setting should render default value if there is no us fullWidth={true} title={

- Boolean test setting + + Boolean test setting + +

} @@ -639,7 +695,11 @@ exports[`Field for boolean setting should render unsaved value if there are unsa fullWidth={true} title={

- Boolean test setting + + Boolean test setting + +

} > @@ -731,7 +798,12 @@ exports[`Field for boolean setting should render user value if there is user val fullWidth={true} title={

- Boolean test setting + + Boolean test setting + +

} @@ -799,7 +871,12 @@ exports[`Field for image setting should render as read only if saving is disable fullWidth={true} title={

- Image test setting + + Image test setting + +

} @@ -868,7 +945,12 @@ exports[`Field for image setting should render as read only with help text if ov fullWidth={true} title={

- Image test setting + + Image test setting + +

} @@ -921,7 +1003,11 @@ exports[`Field for image setting should render custom setting icon if it is cust fullWidth={true} title={

- Image test setting + + Image test setting + +

} > @@ -979,7 +1066,12 @@ exports[`Field for image setting should render default value if there is no user fullWidth={true} title={

- Image test setting + + Image test setting + +

} @@ -1026,7 +1118,11 @@ exports[`Field for image setting should render unsaved value if there are unsave fullWidth={true} title={

- Image test setting + + Image test setting + +

} > @@ -1113,7 +1216,12 @@ exports[`Field for image setting should render user value if there is user value fullWidth={true} title={

- Image test setting + + Image test setting + +

} @@ -1211,7 +1319,12 @@ exports[`Field for json setting should render as read only if saving is disabled fullWidth={true} title={

- Json test setting + + Json test setting + +

} @@ -1302,7 +1415,12 @@ exports[`Field for json setting should render as read only with help text if ove fullWidth={true} title={

- Json test setting + + Json test setting + +

} @@ -1378,7 +1496,11 @@ exports[`Field for json setting should render custom setting icon if it is custo fullWidth={true} title={

- Json test setting + + Json test setting + +

} > @@ -1480,7 +1603,12 @@ exports[`Field for json setting should render default value if there is no user fullWidth={true} title={

- Json test setting + + Json test setting + +

} @@ -1563,7 +1691,11 @@ exports[`Field for json setting should render unsaved value if there are unsaved fullWidth={true} title={

- Json test setting + + Json test setting + +

} > @@ -1677,7 +1816,12 @@ exports[`Field for json setting should render user value if there is user value fullWidth={true} title={

- Json test setting + + Json test setting + +

} @@ -1760,7 +1904,12 @@ exports[`Field for markdown setting should render as read only if saving is disa fullWidth={true} title={

- Markdown test setting + + Markdown test setting + +

} @@ -1848,7 +1997,12 @@ exports[`Field for markdown setting should render as read only with help text if fullWidth={true} title={

- Markdown test setting + + Markdown test setting + +

} @@ -1924,7 +2078,11 @@ exports[`Field for markdown setting should render custom setting icon if it is c fullWidth={true} title={

- Markdown test setting + + Markdown test setting + +

} > @@ -2001,7 +2160,12 @@ exports[`Field for markdown setting should render default value if there is no u fullWidth={true} title={

- Markdown test setting + + Markdown test setting + +

} @@ -2067,7 +2231,11 @@ exports[`Field for markdown setting should render unsaved value if there are uns fullWidth={true} title={

- Markdown test setting + + Markdown test setting + +

} > @@ -2174,7 +2349,12 @@ exports[`Field for markdown setting should render user value if there is user va fullWidth={true} title={

- Markdown test setting + + Markdown test setting + +

} @@ -2257,7 +2437,12 @@ exports[`Field for number setting should render as read only if saving is disabl fullWidth={true} title={

- Number test setting + + Number test setting + +

} @@ -2324,7 +2509,12 @@ exports[`Field for number setting should render as read only with help text if o fullWidth={true} title={

- Number test setting + + Number test setting + +

} @@ -2379,7 +2569,11 @@ exports[`Field for number setting should render custom setting icon if it is cus fullWidth={true} title={

- Number test setting + + Number test setting + +

} > @@ -2435,7 +2630,12 @@ exports[`Field for number setting should render default value if there is no use fullWidth={true} title={

- Number test setting + + Number test setting + +

} @@ -2480,7 +2680,11 @@ exports[`Field for number setting should render unsaved value if there are unsav fullWidth={true} title={

- Number test setting + + Number test setting + +

} > @@ -2566,7 +2777,12 @@ exports[`Field for number setting should render user value if there is user valu fullWidth={true} title={

- Number test setting + + Number test setting + +

} @@ -2628,7 +2844,12 @@ exports[`Field for select setting should render as read only if saving is disabl fullWidth={true} title={

- Select test setting + + Select test setting + +

} @@ -2711,7 +2932,12 @@ exports[`Field for select setting should render as read only with help text if o fullWidth={true} title={

- Select test setting + + Select test setting + +

} @@ -2782,7 +3008,11 @@ exports[`Field for select setting should render custom setting icon if it is cus fullWidth={true} title={

- Select test setting + + Select test setting + +

} > @@ -2854,7 +3085,12 @@ exports[`Field for select setting should render default value if there is no use fullWidth={true} title={

- Select test setting + + Select test setting + +

} @@ -2915,7 +3151,11 @@ exports[`Field for select setting should render unsaved value if there are unsav fullWidth={true} title={

- Select test setting + + Select test setting + +

} > @@ -3017,7 +3264,12 @@ exports[`Field for select setting should render user value if there is user valu fullWidth={true} title={

- Select test setting + + Select test setting + +

} @@ -3095,7 +3347,12 @@ exports[`Field for string setting should render as read only if saving is disabl fullWidth={true} title={

- String test setting + + String test setting + +

} @@ -3162,7 +3419,12 @@ exports[`Field for string setting should render as read only with help text if o fullWidth={true} title={

- String test setting + + String test setting + +

} @@ -3217,7 +3479,11 @@ exports[`Field for string setting should render custom setting icon if it is cus fullWidth={true} title={

- String test setting + + String test setting + +

} > @@ -3273,7 +3540,12 @@ exports[`Field for string setting should render default value if there is no use fullWidth={true} title={

- String test setting + + String test setting + +

} @@ -3318,7 +3590,11 @@ exports[`Field for string setting should render unsaved value if there are unsav fullWidth={true} title={

- String test setting + + String test setting + +

} > @@ -3404,7 +3687,12 @@ exports[`Field for string setting should render user value if there is user valu fullWidth={true} title={

- String test setting + + String test setting + +

} @@ -3466,7 +3754,12 @@ exports[`Field for stringWithValidation setting should render as read only if sa fullWidth={true} title={

- String test validation setting + + String test validation setting + +

} @@ -3533,7 +3826,12 @@ exports[`Field for stringWithValidation setting should render as read only with fullWidth={true} title={

- String test validation setting + + String test validation setting + +

} @@ -3588,7 +3886,11 @@ exports[`Field for stringWithValidation setting should render custom setting ico fullWidth={true} title={

- String test validation setting + + String test validation setting + +

} > @@ -3644,7 +3947,12 @@ exports[`Field for stringWithValidation setting should render default value if t fullWidth={true} title={

- String test validation setting + + String test validation setting + +

} @@ -3689,7 +3997,11 @@ exports[`Field for stringWithValidation setting should render unsaved value if t fullWidth={true} title={

- String test validation setting + + String test validation setting + +

} > @@ -3775,7 +4094,12 @@ exports[`Field for stringWithValidation setting should render user value if ther fullWidth={true} title={

- String test validation setting + + String test validation setting + +

} diff --git a/src/plugins/advanced_settings/public/management_app/components/field/field.tsx b/src/plugins/advanced_settings/public/management_app/components/field/field.tsx index d9c3752d1c0a5..18a1a365709d1 100644 --- a/src/plugins/advanced_settings/public/management_app/components/field/field.tsx +++ b/src/plugins/advanced_settings/public/management_app/components/field/field.tsx @@ -450,9 +450,24 @@ export class Field extends PureComponent { } renderTitle(setting: FieldSetting) { + const { unsavedChanges } = this.props; + const isInvalid = unsavedChanges?.isInvalid; + + const unsavedIconLabel = unsavedChanges + ? isInvalid + ? i18n.translate('advancedSettings.field.invalidIconLabel', { + defaultMessage: 'Invalid', + }) + : i18n.translate('advancedSettings.field.unsavedIconLabel', { + defaultMessage: 'Unsaved', + }) + : undefined; + return (

- {setting.displayName || setting.name} + + {setting.displayName || setting.name} + {setting.isCustom ? ( { ) : ( '' )} + + {unsavedChanges ? ( + + ) : ( + '' + )}

); } diff --git a/src/plugins/advanced_settings/public/management_app/components/form/form.tsx b/src/plugins/advanced_settings/public/management_app/components/form/form.tsx index ef433dd990d33..c859e8fdd7136 100644 --- a/src/plugins/advanced_settings/public/management_app/components/form/form.tsx +++ b/src/plugins/advanced_settings/public/management_app/components/form/form.tsx @@ -331,54 +331,56 @@ export class Form extends PureComponent { }); return ( - +

{this.renderCountOfUnsaved()}

+ - - - - {i18n.translate('advancedSettings.form.cancelButtonLabel', { - defaultMessage: 'Cancel changes', - })} - - - - - - {i18n.translate('advancedSettings.form.saveButtonLabel', { - defaultMessage: 'Save changes', - })} - - - - + + {i18n.translate('advancedSettings.form.cancelButtonLabel', { + defaultMessage: 'Cancel changes', + })} + + + + + + {i18n.translate('advancedSettings.form.saveButtonLabel', { + defaultMessage: 'Save changes', + })} + +
diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 020c3c4c1192d..b7ec02871306c 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -57,6 +57,7 @@ import { fromKueryExpression, toElasticsearchQuery, buildEsQuery, + buildQueryFromFilters, getEsQueryConfig, } from '../common'; @@ -67,6 +68,7 @@ export const esKuery = { }; export const esQuery = { + buildQueryFromFilters, getEsQueryConfig, buildEsQuery, }; diff --git a/src/plugins/kibana_react/public/code_editor/editor_theme.ts b/src/plugins/kibana_react/public/code_editor/editor_theme.ts index 6e30135686797..586b4a568c348 100644 --- a/src/plugins/kibana_react/public/code_editor/editor_theme.ts +++ b/src/plugins/kibana_react/public/code_editor/editor_theme.ts @@ -101,6 +101,11 @@ export function createTheme( 'editor.selectionBackground': selectionBackgroundColor, 'editorWidget.border': euiTheme.euiColorLightShade, 'editorWidget.background': euiTheme.euiColorLightestShade, + 'editorCursor.foreground': euiTheme.euiColorDarkestShade, + 'editorSuggestWidget.selectedBackground': euiTheme.euiColorLightShade, + 'list.hoverBackground': euiTheme.euiColorLightShade, + 'list.highlightForeground': euiTheme.euiColorPrimary, + 'editor.lineHighlightBorder': euiTheme.euiColorLightestShade, }, }; } diff --git a/src/plugins/share/public/components/url_panel_content.tsx b/src/plugins/share/public/components/url_panel_content.tsx index d0d4ce55dc1ac..2b77b6f4592a8 100644 --- a/src/plugins/share/public/components/url_panel_content.tsx +++ b/src/plugins/share/public/components/url_panel_content.tsx @@ -183,7 +183,11 @@ export class UrlPanelContent extends Component { }; private getSnapshotUrl = () => { - return this.props.shareableUrl || window.location.href; + let url = this.props.shareableUrl || window.location.href; + if (this.props.isEmbedded) { + url = this.makeUrlEmbeddable(url); + } + return url; }; private makeUrlEmbeddable = (url: string) => { @@ -200,8 +204,7 @@ export class UrlPanelContent extends Component { return; } - const embeddableUrl = this.makeUrlEmbeddable(url); - return ``; + return ``; }; private setUrl = () => { diff --git a/test/functional/apps/context/_filters.js b/test/functional/apps/context/_filters.js index c9499f5a805ab..721f8a50d0e46 100644 --- a/test/functional/apps/context/_filters.js +++ b/test/functional/apps/context/_filters.js @@ -64,7 +64,7 @@ export default function({ getService, getPageObjects }) { await filterBar.toggleFilterEnabled(TEST_ANCHOR_FILTER_FIELD); await PageObjects.context.waitUntilContextLoadingHasFinished(); - retry.try(async () => { + await retry.try(async () => { expect( await filterBar.hasFilter(TEST_ANCHOR_FILTER_FIELD, TEST_ANCHOR_FILTER_VALUE, false) ).to.be(true); diff --git a/test/functional/apps/dashboard/panel_expand_toggle.js b/test/functional/apps/dashboard/panel_expand_toggle.js index 930445a67aa20..5e7d55706968d 100644 --- a/test/functional/apps/dashboard/panel_expand_toggle.js +++ b/test/functional/apps/dashboard/panel_expand_toggle.js @@ -56,7 +56,7 @@ export default function({ getService, getPageObjects }) { // Add a retry to fix https://github.com/elastic/kibana/issues/14574. Perhaps the recent changes to this // being a CSS update is causing the UI to change slower than grabbing the panels? - retry.try(async () => { + await retry.try(async () => { const panelCountAfterMaxThenMinimize = await PageObjects.dashboard.getPanelCount(); expect(panelCountAfterMaxThenMinimize).to.be(panelCount); }); diff --git a/test/functional/apps/visualize/_tsvb_markdown.ts b/test/functional/apps/visualize/_tsvb_markdown.ts index b7307ac9c6cab..d37404a3d60cb 100644 --- a/test/functional/apps/visualize/_tsvb_markdown.ts +++ b/test/functional/apps/visualize/_tsvb_markdown.ts @@ -121,7 +121,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { await visualBuilder.markdownSwitchSubTab('data'); await visualBuilder.cloneSeries(); - retry.try(async function seriesCountCheck() { + await retry.try(async function seriesCountCheck() { const seriesLength = (await visualBuilder.getSeries()).length; expect(seriesLength).to.be.equal(2); }); @@ -131,7 +131,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { await visualBuilder.markdownSwitchSubTab('data'); await visualBuilder.createNewAgg(); - retry.try(async function aggregationCountCheck() { + await retry.try(async function aggregationCountCheck() { const aggregationLength = await visualBuilder.getAggregationCount(); expect(aggregationLength).to.be.equal(2); }); diff --git a/test/functional/page_objects/discover_page.js b/test/functional/page_objects/discover_page.js index 5ccc5625849d2..080b8c8ee753f 100644 --- a/test/functional/page_objects/discover_page.js +++ b/test/functional/page_objects/discover_page.js @@ -206,12 +206,6 @@ export function DiscoverPageProvider({ getService, getPageObjects }) { return await testSubjects.getVisibleText('discoverQueryHits'); } - async query(queryString) { - await find.setValue('input[aria-label="Search input"]', queryString); - await find.clickByCssSelector('button[aria-label="Search"]'); - await PageObjects.header.waitUntilLoadingHasFinished(); - } - async getDocHeader() { const header = await find.byCssSelector('thead > tr:nth-child(1)'); return await header.getVisibleText(); diff --git a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/public/legacy.ts b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/public/legacy.ts index 39ce2b3077c96..a7cd313038d69 100644 --- a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/public/legacy.ts +++ b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/public/legacy.ts @@ -28,8 +28,6 @@ import 'ui/autoload/all'; // Used to run esaggs queries import 'uiExports/fieldFormats'; import 'uiExports/search'; -import 'uiExports/visRequestHandlers'; -import 'uiExports/visResponseHandlers'; // Used for kibana_context function import 'uiExports/savedObjectTypes'; diff --git a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/index.js b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/index.js index e15da9daa3cd7..b2497a824ba2b 100644 --- a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/index.js +++ b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/index.js @@ -20,7 +20,7 @@ export default function(kibana) { return new kibana.Plugin({ uiExports: { - visTypes: ['plugins/kbn_tp_custom_visualizations/self_changing_vis/self_changing_vis'], + hacks: ['plugins/kbn_tp_custom_visualizations/self_changing_vis/self_changing_vis'], }, }); } diff --git a/test/scripts/jenkins_test_setup_oss.sh b/test/scripts/jenkins_test_setup_oss.sh index 9e68272053221..7bbb867526384 100644 --- a/test/scripts/jenkins_test_setup_oss.sh +++ b/test/scripts/jenkins_test_setup_oss.sh @@ -4,7 +4,7 @@ source test/scripts/jenkins_test_setup.sh if [[ -z "$CODE_COVERAGE" ]] ; then installDir="$(realpath $PARENT_DIR/kibana/build/oss/kibana-*-SNAPSHOT-linux-x86_64)" - destDir=${installDir}-${CI_WORKER_NUMBER} + destDir=${installDir}-${CI_PARALLEL_PROCESS_NUMBER} cp -R "$installDir" "$destDir" export KIBANA_INSTALL_DIR="$destDir" diff --git a/test/scripts/jenkins_test_setup_xpack.sh b/test/scripts/jenkins_test_setup_xpack.sh index 76fc7cfe6c876..a72e9749ebbd5 100644 --- a/test/scripts/jenkins_test_setup_xpack.sh +++ b/test/scripts/jenkins_test_setup_xpack.sh @@ -4,7 +4,7 @@ source test/scripts/jenkins_test_setup.sh if [[ -z "$CODE_COVERAGE" ]]; then installDir="$PARENT_DIR/install/kibana" - destDir="${installDir}-${CI_WORKER_NUMBER}" + destDir="${installDir}-${CI_PARALLEL_PROCESS_NUMBER}" cp -R "$installDir" "$destDir" export KIBANA_INSTALL_DIR="$destDir" diff --git a/vars/agentInfo.groovy b/vars/agentInfo.groovy index b53ed23f81ff0..166a86c169261 100644 --- a/vars/agentInfo.groovy +++ b/vars/agentInfo.groovy @@ -1,5 +1,5 @@ def print() { - try { + catchError(catchInterruptions: false, buildResult: null) { def startTime = sh(script: "date -d '-3 minutes' -Iseconds | sed s/+/%2B/", returnStdout: true).trim() def endTime = sh(script: "date -d '+1 hour 30 minutes' -Iseconds | sed s/+/%2B/", returnStdout: true).trim() @@ -34,8 +34,6 @@ def print() { echo 'SSH Command:' echo "ssh -F ssh_config \$(hostname --ip-address)" """, label: "Worker/Agent/Node debug links" - } catch(ex) { - print ex.toString() } } diff --git a/vars/catchErrors.groovy b/vars/catchErrors.groovy new file mode 100644 index 0000000000000..460a90b8ec0c0 --- /dev/null +++ b/vars/catchErrors.groovy @@ -0,0 +1,8 @@ +// Basically, this is a shortcut for catchError(catchInterruptions: false) {} +// By default, catchError will swallow aborts/timeouts, which we almost never want +def call(Map params = [:], Closure closure) { + params.catchInterruptions = false + return catchError(params, closure) +} + +return this diff --git a/vars/githubPr.groovy b/vars/githubPr.groovy index 91a4a76894d94..7759edbbf5bfc 100644 --- a/vars/githubPr.groovy +++ b/vars/githubPr.groovy @@ -14,8 +14,8 @@ So, there is only ever one build status comment on a PR at any given time, the most recent one. */ def withDefaultPrComments(closure) { - catchError { - catchError { + catchErrors { + catchErrors { closure() } diff --git a/vars/kibanaPipeline.groovy b/vars/kibanaPipeline.groovy index feb0977589fae..f7194859c6bd9 100644 --- a/vars/kibanaPipeline.groovy +++ b/vars/kibanaPipeline.groovy @@ -1,92 +1,36 @@ -def withWorkers(machineName, preWorkerClosure = {}, workerClosures = [:]) { - return { - jobRunner('tests-xl', true) { - withGcsArtifactUpload(machineName, { - withPostBuildReporting { - doSetup() - preWorkerClosure() - - def nextWorker = 1 - def worker = { workerClosure -> - def workerNumber = nextWorker - nextWorker++ - - return { - // This delay helps smooth out CPU load caused by ES/Kibana instances starting up at the same time - def delay = (workerNumber-1)*20 - sleep(delay) - - workerClosure(workerNumber) - } - } - - def workers = [:] - workerClosures.each { workerName, workerClosure -> - workers[workerName] = worker(workerClosure) - } - - parallel(workers) - } - }) - } - } -} - -def withWorker(machineName, label, Closure closure) { - return { - jobRunner(label, false) { - withGcsArtifactUpload(machineName) { - withPostBuildReporting { - doSetup() - closure() - } - } - } - } -} - -def intakeWorker(jobName, String script) { - return withWorker(jobName, 'linux && immutable') { - withEnv([ - "JOB=${jobName}", - ]) { - runbld(script, "Execute ${jobName}") - } - } -} - def withPostBuildReporting(Closure closure) { try { closure() } finally { - catchError { + catchErrors { runErrorReporter() } - catchError { + catchErrors { runbld.junit() } - catchError { + catchErrors { publishJunit() } } } -def getPostBuildWorker(name, closure) { - return { workerNumber -> - def kibanaPort = "61${workerNumber}1" - def esPort = "61${workerNumber}2" - def esTransportPort = "61${workerNumber}3" +def functionalTestProcess(String name, Closure closure) { + return { processNumber -> + def kibanaPort = "61${processNumber}1" + def esPort = "61${processNumber}2" + def esTransportPort = "61${processNumber}3" withEnv([ - "CI_WORKER_NUMBER=${workerNumber}", + "CI_PARALLEL_PROCESS_NUMBER=${processNumber}", "TEST_KIBANA_HOST=localhost", "TEST_KIBANA_PORT=${kibanaPort}", "TEST_KIBANA_URL=http://elastic:changeme@localhost:${kibanaPort}", "TEST_ES_URL=http://elastic:changeme@localhost:${esPort}", "TEST_ES_TRANSPORT_PORT=${esTransportPort}", "IS_PIPELINE_JOB=1", + "JOB=${name}", "KBN_NP_PLUGINS_BUILT=true", ]) { closure() @@ -94,8 +38,16 @@ def getPostBuildWorker(name, closure) { } } -def getOssCiGroupWorker(ciGroup) { - return getPostBuildWorker("ciGroup" + ciGroup, { +def functionalTestProcess(String name, String script) { + return functionalTestProcess(name) { + retryable(name) { + runbld(script, "Execute ${name}") + } + } +} + +def ossCiGroupProcess(ciGroup) { + return functionalTestProcess("ciGroup" + ciGroup) { withEnv([ "CI_GROUP=${ciGroup}", "JOB=kibana-ciGroup${ciGroup}", @@ -104,11 +56,11 @@ def getOssCiGroupWorker(ciGroup) { runbld("./test/scripts/jenkins_ci_group.sh", "Execute kibana-ciGroup${ciGroup}") } } - }) + } } -def getXpackCiGroupWorker(ciGroup) { - return getPostBuildWorker("xpack-ciGroup" + ciGroup, { +def xpackCiGroupProcess(ciGroup) { + return functionalTestProcess("xpack-ciGroup" + ciGroup) { withEnv([ "CI_GROUP=${ciGroup}", "JOB=xpack-kibana-ciGroup${ciGroup}", @@ -117,56 +69,6 @@ def getXpackCiGroupWorker(ciGroup) { runbld("./test/scripts/jenkins_xpack_ci_group.sh", "Execute xpack-kibana-ciGroup${ciGroup}") } } - }) -} - -def jobRunner(label, useRamDisk, closure) { - node(label) { - agentInfo.print() - - if (useRamDisk) { - // Move to a temporary workspace, so that we can symlink the real workspace into /dev/shm - def originalWorkspace = env.WORKSPACE - ws('/tmp/workspace') { - sh( - script: """ - mkdir -p /dev/shm/workspace - mkdir -p '${originalWorkspace}' # create all of the directories leading up to the workspace, if they don't exist - rm --preserve-root -rf '${originalWorkspace}' # then remove just the workspace, just in case there's stuff in it - ln -s /dev/shm/workspace '${originalWorkspace}' - """, - label: "Move workspace to RAM - /dev/shm/workspace" - ) - } - } - - def scmVars - - // Try to clone from Github up to 8 times, waiting 15 secs between attempts - retryWithDelay(8, 15) { - scmVars = checkout scm - } - - withEnv([ - "CI=true", - "HOME=${env.JENKINS_HOME}", - "PR_SOURCE_BRANCH=${env.ghprbSourceBranch ?: ''}", - "PR_TARGET_BRANCH=${env.ghprbTargetBranch ?: ''}", - "PR_AUTHOR=${env.ghprbPullAuthorLogin ?: ''}", - "TEST_BROWSER_HEADLESS=1", - "GIT_BRANCH=${scmVars.GIT_BRANCH}", - ]) { - withCredentials([ - string(credentialsId: 'vault-addr', variable: 'VAULT_ADDR'), - string(credentialsId: 'vault-role-id', variable: 'VAULT_ROLE_ID'), - string(credentialsId: 'vault-secret-id', variable: 'VAULT_SECRET_ID'), - ]) { - // scm is configured to check out to the ./kibana directory - dir('kibana') { - closure() - } - } - } } } @@ -198,7 +100,7 @@ def withGcsArtifactUpload(workerName, closure) { try { closure() } finally { - catchError { + catchErrors { ARTIFACT_PATTERNS.each { pattern -> uploadGcsArtifact(uploadPrefix, pattern) } @@ -226,7 +128,7 @@ def sendMail() { } def sendInfraMail() { - catchError { + catchErrors { step([ $class: 'Mailer', notifyEveryUnstableBuild: true, @@ -237,7 +139,7 @@ def sendInfraMail() { } def sendKibanaMail() { - catchError { + catchErrors { def buildStatus = buildUtils.getBuildStatus() if(params.NOTIFY_ON_FAILURE && buildStatus != 'SUCCESS' && buildStatus != 'ABORTED') { emailext( @@ -282,4 +184,18 @@ def runErrorReporter() { ) } +def call(Map params = [:], Closure closure) { + def config = [timeoutMinutes: 135] + params + + stage("Kibana Pipeline") { + timeout(time: config.timeoutMinutes, unit: 'MINUTES') { + timestamps { + ansiColor('xterm') { + closure() + } + } + } + } +} + return this diff --git a/vars/retryWithDelay.groovy b/vars/retryWithDelay.groovy index 70d6f86a63ab2..83fd94c6f2b1e 100644 --- a/vars/retryWithDelay.groovy +++ b/vars/retryWithDelay.groovy @@ -2,7 +2,9 @@ def call(retryTimes, delaySecs, closure) { retry(retryTimes) { try { closure() - } catch (ex) { + } catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException ex) { + throw ex // Immediately re-throw build abort exceptions, don't sleep first + } catch (Exception ex) { sleep delaySecs throw ex } diff --git a/vars/retryable.groovy b/vars/retryable.groovy index cc34024958aed..ed84a00ece49d 100644 --- a/vars/retryable.groovy +++ b/vars/retryable.groovy @@ -27,7 +27,7 @@ def getFlakyFailures() { } def printFlakyFailures() { - catchError { + catchErrors { def failures = getFlakyFailures() if (failures && failures.size() > 0) { diff --git a/vars/workers.groovy b/vars/workers.groovy new file mode 100644 index 0000000000000..c5638f2624fe5 --- /dev/null +++ b/vars/workers.groovy @@ -0,0 +1,147 @@ +// "Workers" in this file will spin up an instance, do some setup etc depending on the configuration, and then execute some work that you define +// e.g. workers.base(name: 'my-worker') { sh "echo 'ready to execute some kibana scripts'" } + +/* + The base worker that all of the others use. Will clone the scm (assumed to be kibana), and run kibana bootstrap processes by default. + + Parameters: + label - gobld/agent label to use, e.g. 'linux && immutable' + ramDisk - Should the workspace be mounted in memory? Default: true + bootstrapped - If true, download kibana dependencies, run kbn bootstrap, etc. Default: true + name - Name of the worker for display purposes, filenames, etc. + scm - Jenkins scm configuration for checking out code. Use `null` to disable checkout. Default: inherited from job +*/ +def base(Map params, Closure closure) { + def config = [label: '', ramDisk: true, bootstrapped: true, name: 'unnamed-worker', scm: scm] + params + if (!config.label) { + error "You must specify an agent label, such as 'tests-xl' or 'linux && immutable', when using workers.base()" + } + + node(config.label) { + agentInfo.print() + + if (config.ramDisk) { + // Move to a temporary workspace, so that we can symlink the real workspace into /dev/shm + def originalWorkspace = env.WORKSPACE + ws('/tmp/workspace') { + sh( + script: """ + mkdir -p /dev/shm/workspace + mkdir -p '${originalWorkspace}' # create all of the directories leading up to the workspace, if they don't exist + rm --preserve-root -rf '${originalWorkspace}' # then remove just the workspace, just in case there's stuff in it + ln -s /dev/shm/workspace '${originalWorkspace}' + """, + label: "Move workspace to RAM - /dev/shm/workspace" + ) + } + } + + def scmVars = [:] + + if (config.scm) { + // Try to clone from Github up to 8 times, waiting 15 secs between attempts + retryWithDelay(8, 15) { + scmVars = checkout scm + } + } + + withEnv([ + "CI=true", + "HOME=${env.JENKINS_HOME}", + "PR_SOURCE_BRANCH=${env.ghprbSourceBranch ?: ''}", + "PR_TARGET_BRANCH=${env.ghprbTargetBranch ?: ''}", + "PR_AUTHOR=${env.ghprbPullAuthorLogin ?: ''}", + "TEST_BROWSER_HEADLESS=1", + "GIT_BRANCH=${scmVars.GIT_BRANCH ?: ''}", + ]) { + withCredentials([ + string(credentialsId: 'vault-addr', variable: 'VAULT_ADDR'), + string(credentialsId: 'vault-role-id', variable: 'VAULT_ROLE_ID'), + string(credentialsId: 'vault-secret-id', variable: 'VAULT_SECRET_ID'), + ]) { + // scm is configured to check out to the ./kibana directory + dir('kibana') { + if (config.bootstrapped) { + kibanaPipeline.doSetup() + } + + closure() + } + } + } + } +} + +// Worker for ci processes. Extends the base worker and adds GCS artifact upload, error reporting, junit processing +def ci(Map params, Closure closure) { + def config = [ramDisk: true, bootstrapped: true] + params + + return base(config) { + kibanaPipeline.withGcsArtifactUpload(config.name) { + kibanaPipeline.withPostBuildReporting { + closure() + } + } + } +} + +// Worker for running the current intake jobs. Just runs a single script after bootstrap. +def intake(jobName, String script) { + return { + ci(name: jobName, label: 'linux && immutable', ramDisk: false) { + withEnv(["JOB=${jobName}"]) { + runbld(script, "Execute ${jobName}") + } + } + } +} + +// Worker for running functional tests. Runs a setup process (e.g. the kibana build) then executes a map of closures in parallel (e.g. one for each ciGroup) +def functional(name, Closure setup, Map processes) { + return { + parallelProcesses(name: name, setup: setup, processes: processes, delayBetweenProcesses: 20, label: 'tests-xl') + } +} + +/* + Creates a ci worker that can run a setup process, followed by a group of processes in parallel. + + Parameters: + name: Name of the worker for display purposes, filenames, etc. + setup: Closure to execute after the agent is bootstrapped, before starting the parallel work + processes: Map of closures that will execute in parallel after setup. Each closure is passed a unique number. + delayBetweenProcesses: Number of seconds to wait between starting the parallel processes. Useful to spread the load of heavy init processes, e.g. Elasticsearch starting up. Default: 0 + label: gobld/agent label to use, e.g. 'linux && immutable'. Default: 'tests-xl', a 32 CPU machine used for running many functional test suites in parallel +*/ +def parallelProcesses(Map params) { + def config = [name: 'parallel-worker', setup: {}, processes: [:], delayBetweenProcesses: 0, label: 'tests-xl'] + params + + ci(label: config.label, name: config.name) { + config.setup() + + def nextProcessNumber = 1 + def process = { processName, processClosure -> + def processNumber = nextProcessNumber + nextProcessNumber++ + + return { + if (config.delayBetweenProcesses && config.delayBetweenProcesses > 0) { + // This delay helps smooth out CPU load caused by ES/Kibana instances starting up at the same time + def delay = (processNumber-1)*config.delayBetweenProcesses + sleep(delay) + } + + processClosure(processNumber) + } + } + + def processes = [:] + config.processes.each { processName, processClosure -> + processes[processName] = process(processName, processClosure) + } + + parallel(processes) + } +} + +return this diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 51099815ec938..8f5a5ea4f10e4 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -39,7 +39,7 @@ "xpack.snapshotRestore": "legacy/plugins/snapshot_restore", "xpack.spaces": ["legacy/plugins/spaces", "plugins/spaces"], "xpack.taskManager": "legacy/plugins/task_manager", - "xpack.transform": "legacy/plugins/transform", + "xpack.transform": ["legacy/plugins/transform", "plugins/transform"], "xpack.triggersActionsUI": "plugins/triggers_actions_ui", "xpack.upgradeAssistant": "plugins/upgrade_assistant", "xpack.uptime": "legacy/plugins/uptime", diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx index 731555694bff7..52941391ca364 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx @@ -4,51 +4,52 @@ * you may not use this file except in compliance with the Elastic License. */ +import { EuiCard, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { storiesOf } from '@storybook/react'; import cytoscape from 'cytoscape'; import React from 'react'; import { Cytoscape } from './Cytoscape'; - -const elements: cytoscape.ElementDefinition[] = [ - { - data: { - id: 'opbeans-python', - label: 'opbeans-python', - agentName: 'python', - type: 'service' - } - }, - { - data: { - id: 'opbeans-node', - label: 'opbeans-node', - agentName: 'nodejs', - type: 'service' - } - }, - { - data: { - id: 'opbeans-ruby', - label: 'opbeans-ruby', - agentName: 'ruby', - type: 'service' - } - }, - { data: { source: 'opbeans-python', target: 'opbeans-node' } }, - { - data: { - bidirectional: true, - source: 'opbeans-python', - target: 'opbeans-ruby' - } - } -]; -const height = 300; -const serviceName = 'opbeans-python'; +import { iconForNode } from './icons'; storiesOf('app/ServiceMap/Cytoscape', module).add( 'example', () => { + const elements: cytoscape.ElementDefinition[] = [ + { + data: { + id: 'opbeans-python', + label: 'opbeans-python', + agentName: 'python', + type: 'service' + } + }, + { + data: { + id: 'opbeans-node', + label: 'opbeans-node', + agentName: 'nodejs', + type: 'service' + } + }, + { + data: { + id: 'opbeans-ruby', + label: 'opbeans-ruby', + agentName: 'ruby', + type: 'service' + } + }, + { data: { source: 'opbeans-python', target: 'opbeans-node' } }, + { + data: { + bidirectional: true, + source: 'opbeans-python', + target: 'opbeans-ruby' + } + } + ]; + const height = 300; + const serviceName = 'opbeans-python'; return ( { + const cy = cytoscape(); + const elements = [ + { data: { id: 'default', label: 'default', type: undefined } }, + { data: { id: 'cache', label: 'cache', type: 'cache' } }, + { data: { id: 'database', label: 'database', type: 'database' } }, + { data: { id: 'external', label: 'external', type: 'external' } }, + { data: { id: 'messaging', label: 'messaging', type: 'messaging' } }, + + { + data: { + id: 'dotnet', + label: 'dotnet service', + type: 'service', + agentName: 'dotnet' + } + }, + { + data: { + id: 'go', + label: 'go service', + type: 'service', + agentName: 'go' + } + }, + { + data: { + id: 'java', + label: 'java service', + type: 'service', + agentName: 'java' + } + }, + { + data: { + id: 'js-base', + label: 'js-base service', + type: 'service', + agentName: 'js-base' + } + }, + { + data: { + id: 'nodejs', + label: 'nodejs service', + type: 'service', + agentName: 'nodejs' + } + }, + { + data: { + id: 'php', + label: 'php service', + type: 'service', + agentName: 'php' + } + }, + { + data: { + id: 'python', + label: 'python service', + type: 'service', + agentName: 'python' + } + }, + { + data: { + id: 'ruby', + label: 'ruby service', + type: 'service', + agentName: 'ruby' + } + } + ]; + cy.add(elements); + + return ( + + {cy.nodes().map(node => ( + + + agentName: {node.data('agentName') || 'undefined'}, type:{' '} + {node.data('type') || 'undefined'} + + } + icon={ + {node.data('label')} + } + title={node.data('label')} + /> + + ))} + + ); + }, + { + info: { + propTables: false, source: false } } diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx index f1c53673c8755..405bd855898b7 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx @@ -35,6 +35,7 @@ export function Contents({ onFocusClick, selectedNodeServiceName }: ContentsProps) { + const frameworkName = selectedNodeData.frameworkName; return ( {isService ? ( - + ) : ( )} diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Popover.stories.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Popover.stories.tsx index e5962afd76eb8..23e9e737be9a6 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Popover.stories.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Popover.stories.tsx @@ -16,6 +16,7 @@ storiesOf('app/ServiceMap/Popover/ServiceMetricList', module) avgRequestsPerMinute={164.47222031860858} avgCpuUsage={0.32809666568309237} avgMemoryUsage={0.5504868173242986} + frameworkName="Spring" numInstances={2} isLoading={false} /> diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx index b0a5e892b5a7e..697aa6a1b652b 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx @@ -11,10 +11,12 @@ import { useUrlParams } from '../../../../hooks/useUrlParams'; import { ServiceMetricList } from './ServiceMetricList'; interface ServiceMetricFetcherProps { + frameworkName?: string; serviceName: string; } export function ServiceMetricFetcher({ + frameworkName, serviceName }: ServiceMetricFetcherProps) { const { @@ -37,5 +39,11 @@ export function ServiceMetricFetcher({ ); const isLoading = status === 'loading'; - return ; + return ( + + ); } diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx index 3a6b4c5ebcaac..056af68cc8173 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx @@ -30,6 +30,10 @@ function LoadingSpinner() { ); } +const BadgeRow = styled(EuiFlexItem)` + padding-bottom: ${lightTheme.gutterTypes.gutterSmall}; +`; + const ItemRow = styled('tr')` line-height: 2; `; @@ -44,6 +48,7 @@ const ItemDescription = styled('td')` `; interface ServiceMetricListProps extends ServiceNodeMetrics { + frameworkName?: string; isLoading: boolean; } @@ -53,6 +58,7 @@ export function ServiceMetricList({ avgErrorsPerMinute, avgCpuUsage, avgMemoryUsage, + frameworkName, numInstances, isLoading }: ServiceMetricListProps) { @@ -106,23 +112,27 @@ export function ServiceMetricList({ : null } ]; + const showBadgeRow = frameworkName || numInstances > 1; + return isLoading ? ( ) : ( <> - {numInstances && numInstances > 1 && ( - -
- - {i18n.translate('xpack.apm.serviceMap.numInstancesMetric', { - values: { numInstances }, - defaultMessage: '{numInstances} instances' - })} - -
-
+ {showBadgeRow && ( + + + {frameworkName && {frameworkName}} + {numInstances > 1 && ( + + {i18n.translate('xpack.apm.serviceMap.numInstancesMetric', { + values: { numInstances }, + defaultMessage: '{numInstances} instances' + })} + + )} + + )} - {listItems.map( diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts index af5bd17f71ca4..8411169dbc944 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts @@ -42,19 +42,23 @@ const style: cytoscape.Stylesheet[] = [ 'background-image': (el: cytoscape.NodeSingular) => iconForNode(el) ?? defaultIcon, 'background-height': (el: cytoscape.NodeSingular) => - isService(el) ? '85%' : '40%', + isService(el) ? '60%' : '40%', 'background-width': (el: cytoscape.NodeSingular) => - isService(el) ? '85%' : '40%', + isService(el) ? '60%' : '40%', 'border-color': (el: cytoscape.NodeSingular) => el.hasClass('primary') || el.selected() ? theme.euiColorPrimary : theme.euiColorMediumShade, - 'border-width': 1, + 'border-width': 2, color: theme.textColors.default, // theme.euiFontFamily doesn't work here for some reason, so we're just // specifying a subset of the fonts for the label text. 'font-family': 'Inter UI, Segoe UI, Helvetica, Arial, sans-serif', 'font-size': theme.euiFontSizeXS, + ghost: 'yes', + 'ghost-offset-x': 0, + 'ghost-offset-y': 2, + 'ghost-opacity': 0.15, height: nodeHeight, label: 'data(label)', 'min-zoomed-font-size': theme.euiSizeL, diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/get_cytoscape_elements.ts b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/get_cytoscape_elements.ts index 2403ed047cbc0..bc619b1ecdfe5 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/get_cytoscape_elements.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/get_cytoscape_elements.ts @@ -105,7 +105,8 @@ export function getCytoscapeElements( `/services/${node['service.name']}/service-map`, search ), - agentName: node['agent.name'] || node['agent.name'], + agentName: node['agent.name'], + frameworkName: node['service.framework.name'], type: 'service' }; } diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts index c637d145639ce..1b57cd52082d8 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts @@ -4,26 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -import theme from '@elastic/eui/dist/eui_theme_light.json'; import cytoscape from 'cytoscape'; import databaseIcon from './icons/database.svg'; import documentsIcon from './icons/documents.svg'; +import dotNetIcon from './icons/dot-net.svg'; import globeIcon from './icons/globe.svg'; +import goIcon from './icons/go.svg'; +import javaIcon from './icons/java.svg'; +import nodeJsIcon from './icons/nodejs.svg'; +import phpIcon from './icons/php.svg'; +import pythonIcon from './icons/python.svg'; +import rubyIcon from './icons/ruby.svg'; +import rumJsIcon from './icons/rumjs.svg'; +import defaultIconImport from './icons/default.svg'; -function getAvatarIcon( - text = '', - backgroundColor = 'transparent', - foregroundColor = 'white' -) { - return ( - 'data:image/svg+xml;utf8,' + - encodeURIComponent(` - - ${text} - -`) - ); -} +export const defaultIcon = defaultIconImport; // The colors here are taken from the logos of the corresponding technologies const icons: { [key: string]: string } = { @@ -34,18 +29,17 @@ const icons: { [key: string]: string } = { resource: globeIcon }; -const serviceAbbreviations: { [key: string]: string } = { - dotnet: '.N', - go: 'Go', - java: 'Jv', - 'js-base': 'JS', - nodejs: 'No', - python: 'Py', - ruby: 'Rb' +const serviceIcons: { [key: string]: string } = { + dotnet: dotNetIcon, + go: goIcon, + java: javaIcon, + 'js-base': rumJsIcon, + nodejs: nodeJsIcon, + php: phpIcon, + python: pythonIcon, + ruby: rubyIcon }; -export const defaultIcon = getAvatarIcon(); - // IE 11 does not properly load some SVGs, which causes a runtime error and the // map to not work at all. We would prefer to do some kind of feature detection // rather than browser detection, but IE 11 does support SVG, just not well @@ -61,15 +55,12 @@ export function iconForNode(node: cytoscape.NodeSingular) { const type = node.data('type'); if (type === 'service') { - return getAvatarIcon( - serviceAbbreviations[node.data('agentName') as string], - node.selected() || node.hasClass('primary') - ? theme.euiColorPrimary - : theme.euiColorDarkestShade - ); + return serviceIcons[node.data('agentName') as string]; } else if (isIE11) { return defaultIcon; - } else { + } else if (icons[type]) { return icons[type]; + } else { + return defaultIcon; } } diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/default.svg b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/default.svg new file mode 100644 index 0000000000000..08bc5331e083b --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/default.svg @@ -0,0 +1,3 @@ + + + diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/dot-net.svg b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/dot-net.svg new file mode 100644 index 0000000000000..9f7427f0e1001 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/dot-net.svg @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/go.svg b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/go.svg new file mode 100644 index 0000000000000..fb171e2813fac --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/go.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/java.svg b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/java.svg new file mode 100644 index 0000000000000..52a410e2eaa1a --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/java.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/nodejs.svg b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/nodejs.svg new file mode 100644 index 0000000000000..d327b1ba65ad2 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/nodejs.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/php.svg b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/php.svg new file mode 100644 index 0000000000000..c8af5dc331269 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/php.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/python.svg b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/python.svg new file mode 100644 index 0000000000000..9b8d0a2836c28 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/python.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/ruby.svg b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/ruby.svg new file mode 100644 index 0000000000000..fdc54b91f9c29 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/ruby.svg @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/rumjs.svg b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/rumjs.svg new file mode 100644 index 0000000000000..87043159ed8c3 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/rumjs.svg @@ -0,0 +1,3 @@ + + + diff --git a/x-pack/legacy/plugins/canvas/public/legacy_start.ts b/x-pack/legacy/plugins/canvas/public/legacy_start.ts index 21bf5aaa6d818..d7d1a940d3b43 100644 --- a/x-pack/legacy/plugins/canvas/public/legacy_start.ts +++ b/x-pack/legacy/plugins/canvas/public/legacy_start.ts @@ -8,9 +8,6 @@ // Import the uiExports that the application uses // These will go away as these plugins are converted to NP import 'ui/autoload/all'; -import 'uiExports/visTypes'; -import 'uiExports/visResponseHandlers'; -import 'uiExports/visRequestHandlers'; import 'uiExports/savedObjectTypes'; import 'uiExports/spyModes'; import 'uiExports/embeddableFactories'; diff --git a/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js b/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js index e76a204a6f27d..62cd253ff24d9 100644 --- a/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js +++ b/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js @@ -15,9 +15,7 @@ import { uiModules } from 'ui/modules'; // import the uiExports that we want to "use" import 'uiExports/contextMenuActions'; -import 'uiExports/visTypes'; -import 'uiExports/visResponseHandlers'; -import 'uiExports/visRequestHandlers'; + import 'uiExports/inspectorViews'; import 'uiExports/interpreter'; import 'uiExports/savedObjectTypes'; diff --git a/x-pack/legacy/plugins/graph/public/app.js b/x-pack/legacy/plugins/graph/public/app.js index 7010e1fa773ea..df968681a38e2 100644 --- a/x-pack/legacy/plugins/graph/public/app.js +++ b/x-pack/legacy/plugins/graph/public/app.js @@ -132,14 +132,20 @@ export function initGraphApp(angularModule, deps) { template: appTemplate, badge: getReadonlyBadge, resolve: { - savedWorkspace: function($route) { + savedWorkspace: function($rootScope, $route, $location) { return $route.current.params.id - ? savedWorkspaceLoader.get($route.current.params.id).catch(function() { - toastNotifications.addDanger( - i18n.translate('xpack.graph.missingWorkspaceErrorMessage', { - defaultMessage: 'Missing workspace', - }) - ); + ? savedWorkspaceLoader.get($route.current.params.id).catch(function(e) { + toastNotifications.addError(e, { + title: i18n.translate('xpack.graph.missingWorkspaceErrorMessage', { + defaultMessage: "Couldn't load graph with ID", + }), + }); + $rootScope.$eval(() => { + $location.path('/home'); + $location.replace(); + }); + // return promise that never returns to prevent the controller from loading + return new Promise(); }) : savedWorkspaceLoader.get(); }, diff --git a/x-pack/legacy/plugins/lens/index.ts b/x-pack/legacy/plugins/lens/index.ts index bb0bf9b67ee2c..5eda6c4b4ff7a 100644 --- a/x-pack/legacy/plugins/lens/index.ts +++ b/x-pack/legacy/plugins/lens/index.ts @@ -33,7 +33,6 @@ export const lens: LegacyPluginInitializer = kibana => { embeddableFactories: [`plugins/${PLUGIN_ID}/legacy`], styleSheetPaths: resolve(__dirname, 'public/index.scss'), mappings, - visTypes: ['plugins/lens/register_vis_type_alias'], savedObjectsManagement: { lens: { defaultSearchField: 'title', diff --git a/x-pack/legacy/plugins/lens/public/legacy.ts b/x-pack/legacy/plugins/lens/public/legacy.ts index 8023bad34de66..1cfd3e198547d 100644 --- a/x-pack/legacy/plugins/lens/public/legacy.ts +++ b/x-pack/legacy/plugins/lens/public/legacy.ts @@ -5,12 +5,15 @@ */ import { npSetup, npStart } from 'ui/new_platform'; -import { getFormat } from './legacy_imports'; +import { getFormat, visualizations } from './legacy_imports'; export * from './types'; import { plugin } from './index'; const pluginInstance = plugin(); -pluginInstance.setup(npSetup.core, { ...npSetup.plugins, __LEGACY: { formatFactory: getFormat } }); +pluginInstance.setup(npSetup.core, { + ...npSetup.plugins, + __LEGACY: { formatFactory: getFormat, visualizations }, +}); pluginInstance.start(npStart.core, npStart.plugins); diff --git a/x-pack/legacy/plugins/lens/public/legacy_imports.ts b/x-pack/legacy/plugins/lens/public/legacy_imports.ts index 9dcc22ddb1bb7..88f189fe3db5a 100644 --- a/x-pack/legacy/plugins/lens/public/legacy_imports.ts +++ b/x-pack/legacy/plugins/lens/public/legacy_imports.ts @@ -5,3 +5,5 @@ */ export { getFormat, FormatFactory } from 'ui/visualize/loader/pipeline_helpers/utilities'; +export { setup as visualizations } from '../../../../../src/legacy/core_plugins/visualizations/public/np_ready/public/legacy'; +export { VisualizationsSetup } from '../../../../../src/legacy/core_plugins/visualizations/public'; diff --git a/x-pack/legacy/plugins/lens/public/plugin.tsx b/x-pack/legacy/plugins/lens/public/plugin.tsx index 634d227559835..7f96268fc2e8c 100644 --- a/x-pack/legacy/plugins/lens/public/plugin.tsx +++ b/x-pack/legacy/plugins/lens/public/plugin.tsx @@ -38,6 +38,8 @@ import { import { FormatFactory } from './legacy_imports'; import { IEmbeddableSetup, IEmbeddableStart } from '../../../../../src/plugins/embeddable/public'; import { EditorFrameStart } from './types'; +import { getLensAliasConfig } from './vis_type_alias'; +import { VisualizationsSetup } from './legacy_imports'; export interface LensPluginSetupDependencies { kibanaLegacy: KibanaLegacySetup; @@ -46,6 +48,7 @@ export interface LensPluginSetupDependencies { embeddable: IEmbeddableSetup; __LEGACY: { formatFactory: FormatFactory; + visualizations: VisualizationsSetup; }; } @@ -81,7 +84,7 @@ export class LensPlugin { expressions, data, embeddable, - __LEGACY: { formatFactory }, + __LEGACY: { formatFactory, visualizations }, }: LensPluginSetupDependencies ) { const editorFrameSetupInterface = this.editorFrameService.setup(core, { @@ -100,6 +103,8 @@ export class LensPlugin { this.datatableVisualization.setup(core, dependencies); this.metricVisualization.setup(core, dependencies); + visualizations.types.registerAlias(getLensAliasConfig()); + kibanaLegacy.registerLegacyApp({ id: 'lens', title: NOT_INTERNATIONALIZED_PRODUCT_NAME, diff --git a/x-pack/legacy/plugins/lens/public/register_vis_type_alias.ts b/x-pack/legacy/plugins/lens/public/vis_type_alias.ts similarity index 89% rename from x-pack/legacy/plugins/lens/public/register_vis_type_alias.ts rename to x-pack/legacy/plugins/lens/public/vis_type_alias.ts index f71796268065b..c4e0a20110c81 100644 --- a/x-pack/legacy/plugins/lens/public/register_vis_type_alias.ts +++ b/x-pack/legacy/plugins/lens/public/vis_type_alias.ts @@ -5,10 +5,10 @@ */ import { i18n } from '@kbn/i18n'; -import { setup as visualizations } from '../../../../../src/legacy/core_plugins/visualizations/public/np_ready/public/legacy'; import { getBasePath, getEditPath } from '../../../../plugins/lens/common'; +import { VisTypeAlias } from '../../../../../src/legacy/core_plugins/visualizations/public/np_ready/public/vis_types'; -visualizations.types.registerAlias({ +export const getLensAliasConfig = (): VisTypeAlias => ({ aliasUrl: getBasePath(), name: 'lens', promotion: { diff --git a/x-pack/legacy/plugins/maps/index.js b/x-pack/legacy/plugins/maps/index.js index 5cd5a8731a703..8048c21fe9333 100644 --- a/x-pack/legacy/plugins/maps/index.js +++ b/x-pack/legacy/plugins/maps/index.js @@ -78,7 +78,7 @@ export function maps(kibana) { }, mappings, migrations, - visTypes: ['plugins/maps/register_vis_type_alias'], + hacks: ['plugins/maps/register_vis_type_alias'], }, config(Joi) { return Joi.object({ diff --git a/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.js b/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.js index 45ee441716769..3cae75231d28e 100644 --- a/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.js +++ b/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.js @@ -9,7 +9,7 @@ import { EMSTMSSource } from '../layers/sources/ems_tms_source'; import chrome from 'ui/chrome'; import { getKibanaTileMap } from '../meta'; -export function getInitialLayers(layerListJSON) { +export function getInitialLayers(layerListJSON, initialLayers = []) { if (layerListJSON) { return JSON.parse(layerListJSON); } @@ -19,7 +19,7 @@ export function getInitialLayers(layerListJSON) { const sourceDescriptor = KibanaTilemapSource.createDescriptor(); const source = new KibanaTilemapSource(sourceDescriptor); const layer = source.createDefaultLayer(); - return [layer.toLayerDescriptor()]; + return [layer.toLayerDescriptor(), ...initialLayers]; } const isEmsEnabled = chrome.getInjected('isEmsEnabled', true); @@ -27,8 +27,8 @@ export function getInitialLayers(layerListJSON) { const descriptor = EMSTMSSource.createDescriptor({ isAutoSelect: true }); const source = new EMSTMSSource(descriptor); const layer = source.createDefaultLayer(); - return [layer.toLayerDescriptor()]; + return [layer.toLayerDescriptor(), ...initialLayers]; } - return []; + return initialLayers; } diff --git a/x-pack/legacy/plugins/maps/public/angular/map_controller.js b/x-pack/legacy/plugins/maps/public/angular/map_controller.js index 95c8ff975b1d6..a8e9ae46a3b9a 100644 --- a/x-pack/legacy/plugins/maps/public/angular/map_controller.js +++ b/x-pack/legacy/plugins/maps/public/angular/map_controller.js @@ -6,6 +6,7 @@ import _ from 'lodash'; import chrome from 'ui/chrome'; +import rison from 'rison-node'; import 'ui/directives/listen'; import 'ui/directives/storage'; import React from 'react'; @@ -66,6 +67,32 @@ const REACT_ANCHOR_DOM_ELEMENT_ID = 'react-maps-root'; const app = uiModules.get(MAP_APP_PATH, []); +function getInitialLayersFromUrlParam() { + const locationSplit = window.location.href.split('?'); + if (locationSplit.length <= 1) { + return []; + } + const mapAppParams = new URLSearchParams(locationSplit[1]); + if (!mapAppParams.has('initialLayers')) { + return []; + } + + try { + return rison.decode_array(mapAppParams.get('initialLayers')); + } catch (e) { + toastNotifications.addWarning({ + title: i18n.translate('xpack.maps.initialLayers.unableToParseTitle', { + defaultMessage: `Inital layers not added to map`, + }), + text: i18n.translate('xpack.maps.initialLayers.unableToParseMessage', { + defaultMessage: `Unable to parse contents of 'initialLayers' parameter. Error: {errorMsg}`, + values: { errorMsg: e.message }, + }), + }); + return []; + } +} + app.controller( 'GisMapController', ($scope, $route, kbnUrl, localStorage, AppState, globalState) => { @@ -333,7 +360,7 @@ app.controller( store.dispatch(setOpenTOCDetails(_.get(uiState, 'openTOCDetails', []))); } - const layerList = getInitialLayers(savedMap.layerListJSON); + const layerList = getInitialLayers(savedMap.layerListJSON, getInitialLayersFromUrlParam()); initialLayerListConfig = copyPersistentState(layerList); store.dispatch(replaceLayerList(layerList)); store.dispatch(setRefreshConfig($scope.refreshConfig)); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/eql_adobe_hijack_persistence.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/eql_adobe_hijack_persistence.json index 387726168cb10..8b8c510093260 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/eql_adobe_hijack_persistence.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/eql_adobe_hijack_persistence.json @@ -6,7 +6,7 @@ "language": "kuery", "max_signals": 100, "name": "Adobe Hijack Persistence", - "query": "file.path:(\"C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\AcroCEF\\RdrCEF.exe\" or \"C:\\Program Files\\Adobe\\Acrobat Reader DC\\Reader\\AcroCEF\\RdrCEF.exe\") and event.action:\"File created (rule: FileCreate)\" and not process.name:msiexeec.exe", + "query": "file.path:(\"C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\AcroCEF\\RdrCEF.exe\" or \"C:\\Program Files\\Adobe\\Acrobat Reader DC\\Reader\\AcroCEF\\RdrCEF.exe\") and event.action:\"File created (rule: FileCreate)\" and not process.name:msiexec.exe", "risk_score": 21, "rule_id": "2bf78aa2-9c56-48de-b139-f169bf99cf86", "severity": "low", @@ -32,5 +32,5 @@ } ], "type": "query", - "version": 1 + "version": 2 } diff --git a/x-pack/legacy/plugins/transform/index.ts b/x-pack/legacy/plugins/transform/index.ts index d0799f46cbd25..10f4732152c43 100644 --- a/x-pack/legacy/plugins/transform/index.ts +++ b/x-pack/legacy/plugins/transform/index.ts @@ -4,11 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Legacy } from 'kibana'; import { resolve } from 'path'; + import { PLUGIN } from './common/constants'; -import { Plugin as TransformPlugin } from './server/plugin'; -import { createServerShim } from './server/shim'; export function transform(kibana: any) { return new kibana.Plugin({ @@ -20,20 +18,5 @@ export function transform(kibana: any) { styleSheetPaths: resolve(__dirname, 'public/app/index.scss'), managementSections: ['plugins/transform'], }, - init(server: Legacy.Server) { - const { core, plugins } = createServerShim(server, PLUGIN.ID); - const transformPlugin = new TransformPlugin(); - - // Start plugin - transformPlugin.start(core, plugins); - - // Register license checker - plugins.license.registerLicenseChecker( - server, - PLUGIN.ID, - PLUGIN.getI18nName(), - PLUGIN.MINIMUM_LICENSE_REQUIRED - ); - }, }); } diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx index 3adb74e4704dc..bde832894632c 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx @@ -404,6 +404,10 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange xJson: advancedEditorConfig, } = useXJsonMode(stringifiedPivotConfig); + useEffect(() => { + setAdvancedEditorConfig(stringifiedPivotConfig); + }, [setAdvancedEditorConfig, stringifiedPivotConfig]); + // source config const stringifiedSourceConfig = JSON.stringify(previewRequest.source.query, null, 2); const [ @@ -797,6 +801,7 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange > - Object.keys(privilegesObject).reduce((privileges: string[], privilegeName: string): string[] => { - if (!privilegesObject[privilegeName]) { - privileges.push(privilegeName); - } - return privileges; - }, []); - -export const getPrivilegesHandler: RouterRouteHandler = async ( - req, - callWithRequest -): Promise => { - const xpackInfo = getXpackMainPlugin() && getXpackMainPlugin().info; - if (!xpackInfo) { - // xpackInfo is updated via poll, so it may not be available until polling has begun. - // In this rare situation, tell the client the service is temporarily unavailable. - throw wrapCustomError(new Error('Security info unavailable'), 503); - } - - const privilegesResult: Privileges = { - hasAllPrivileges: true, - missingPrivileges: { - cluster: [], - index: [], - }, - }; - - const securityInfo = xpackInfo && xpackInfo.isAvailable() && xpackInfo.feature('security'); - if (!securityInfo || !securityInfo.isAvailable() || !securityInfo.isEnabled()) { - // If security isn't enabled, let the user use app. - return privilegesResult; - } - - // Get cluster priviliges - const { has_all_requested: hasAllPrivileges, cluster } = await callWithRequest( - 'transport.request', - { - path: '/_security/user/_has_privileges', - method: 'POST', - body: { - cluster: APP_CLUSTER_PRIVILEGES, - }, - } - ); - - // Find missing cluster privileges and set overall app privileges - privilegesResult.missingPrivileges.cluster = extractMissingPrivileges(cluster); - privilegesResult.hasAllPrivileges = hasAllPrivileges; - - // Get all index privileges the user has - const { indices } = await callWithRequest('transport.request', { - path: '/_security/user/_privileges', - method: 'GET', - }); - - // Check if they have all the required index privileges for at least one index - const oneIndexWithAllPrivileges = indices.find(({ privileges }: { privileges: string[] }) => { - if (privileges.includes('all')) { - return true; - } - - const indexHasAllPrivileges = APP_INDEX_PRIVILEGES.every(privilege => - privileges.includes(privilege) - ); - - return indexHasAllPrivileges; - }); - - // If they don't, return list of required index privileges - if (!oneIndexWithAllPrivileges) { - privilegesResult.missingPrivileges.index = [...APP_INDEX_PRIVILEGES]; - } - - return privilegesResult; -}; diff --git a/x-pack/legacy/plugins/transform/server/routes/api/register_routes.ts b/x-pack/legacy/plugins/transform/server/routes/api/register_routes.ts deleted file mode 100644 index c01647c598d86..0000000000000 --- a/x-pack/legacy/plugins/transform/server/routes/api/register_routes.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { Router } from '../../../../../server/lib/create_router'; -import { Plugins } from '../../shim'; -import { registerAppRoutes } from './app'; -import { registerTransformsRoutes } from './transforms'; - -export const registerRoutes = (router: Router, plugins: Plugins): void => { - registerAppRoutes(router, plugins); - registerTransformsRoutes(router, plugins); -}; diff --git a/x-pack/legacy/plugins/transform/server/routes/api/transform_audit_messages.ts b/x-pack/legacy/plugins/transform/server/routes/api/transform_audit_messages.ts deleted file mode 100644 index c4b5fbd4d3b60..0000000000000 --- a/x-pack/legacy/plugins/transform/server/routes/api/transform_audit_messages.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; - -import { AuditMessage } from '../../../common/types/messages'; - -const ML_DF_NOTIFICATION_INDEX_PATTERN = '.transform-notifications-read'; -const SIZE = 500; - -interface BoolQuery { - bool: { [key: string]: any }; -} - -export function transformAuditMessagesProvider(callWithRequest: CallCluster) { - // search for audit messages, - // transformId is optional. without it, all transforms will be listed. - async function getTransformAuditMessages(transformId: string) { - const query: BoolQuery = { - bool: { - filter: [ - { - bool: { - must_not: { - term: { - level: 'activity', - }, - }, - }, - }, - ], - }, - }; - - // if no transformId specified, load all of the messages - if (transformId !== undefined) { - query.bool.filter.push({ - bool: { - should: [ - { - term: { - transform_id: '', // catch system messages - }, - }, - { - term: { - transform_id: transformId, // messages for specified transformId - }, - }, - ], - }, - }); - } - - try { - const resp = await callWithRequest('search', { - index: ML_DF_NOTIFICATION_INDEX_PATTERN, - ignore_unavailable: true, - rest_total_hits_as_int: true, - size: SIZE, - body: { - sort: [{ timestamp: { order: 'desc' } }, { transform_id: { order: 'asc' } }], - query, - }, - }); - - let messages = []; - if (resp.hits.total !== 0) { - messages = resp.hits.hits.map((hit: AuditMessage) => hit._source); - messages.reverse(); - } - return messages; - } catch (e) { - throw e; - } - } - - return { - getTransformAuditMessages, - }; -} diff --git a/x-pack/legacy/plugins/transform/server/routes/api/transforms.ts b/x-pack/legacy/plugins/transform/server/routes/api/transforms.ts deleted file mode 100644 index 6e833854a24c9..0000000000000 --- a/x-pack/legacy/plugins/transform/server/routes/api/transforms.ts +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; -import { Router, RouterRouteHandler } from '../../../../../server/lib/create_router'; -import { wrapEsError } from '../../../../../server/lib/create_router/error_wrappers'; -import { Plugins } from '../../shim'; -import { TRANSFORM_STATE } from '../../../public/app/common'; -import { - TransformEndpointRequest, - TransformEndpointResult, -} from '../../../public/app/hooks/use_api_types'; -import { TransformId } from '../../../public/app/common/transform'; -import { isRequestTimeout, fillResultsWithTimeouts } from './error_utils'; -import { transformAuditMessagesProvider } from './transform_audit_messages'; - -enum TRANSFORM_ACTIONS { - STOP = 'stop', - START = 'start', - DELETE = 'delete', -} - -interface StartOptions { - transformId: TransformId; -} - -interface StopOptions { - transformId: TransformId; - force: boolean; - waitForCompletion?: boolean; -} - -export function registerTransformsRoutes(router: Router, plugins: Plugins) { - router.get('transforms', getTransformHandler); - router.get('transforms/{transformId}', getTransformHandler); - router.get('transforms/_stats', getTransformStatsHandler); - router.get('transforms/{transformId}/_stats', getTransformStatsHandler); - router.get('transforms/{transformId}/messages', getTransformMessagesHandler); - router.put('transforms/{transformId}', putTransformHandler); - router.post('delete_transforms', deleteTransformsHandler); - router.post('transforms/_preview', previewTransformHandler); - router.post('start_transforms', startTransformsHandler); - router.post('stop_transforms', stopTransformsHandler); - router.post('es_search', esSearchHandler); -} - -const getTransformHandler: RouterRouteHandler = async (req, callWithRequest) => { - const { transformId } = req.params; - const options = { - ...(transformId !== undefined ? { transformId } : {}), - }; - - try { - return await callWithRequest('transform.getTransforms', options); - } catch (e) { - return { error: wrapEsError(e) }; - } -}; - -const getTransformStatsHandler: RouterRouteHandler = async (req, callWithRequest) => { - const { transformId } = req.params; - const options = { - ...(transformId !== undefined ? { transformId } : {}), - }; - - try { - return await callWithRequest('transform.getTransformsStats', options); - } catch (e) { - return { error: wrapEsError(e) }; - } -}; - -const deleteTransformsHandler: RouterRouteHandler = async (req, callWithRequest) => { - const transformsInfo = req.payload as TransformEndpointRequest[]; - - try { - return await deleteTransforms(transformsInfo, callWithRequest); - } catch (e) { - return { error: wrapEsError(e) }; - } -}; - -const putTransformHandler: RouterRouteHandler = async (req, callWithRequest) => { - const { transformId } = req.params; - - const response: { - transformsCreated: Array<{ transform: string }>; - errors: any[]; - } = { - transformsCreated: [], - errors: [], - }; - - await callWithRequest('transform.createTransform', { body: req.payload, transformId }) - .then(() => response.transformsCreated.push({ transform: transformId })) - .catch(e => - response.errors.push({ - id: transformId, - error: wrapEsError(e), - }) - ); - - return response; -}; - -async function deleteTransforms( - transformsInfo: TransformEndpointRequest[], - callWithRequest: CallCluster -) { - const results: TransformEndpointResult = {}; - - for (const transformInfo of transformsInfo) { - const transformId = transformInfo.id; - try { - if (transformInfo.state === TRANSFORM_STATE.FAILED) { - try { - await callWithRequest('transform.stopTransform', { - transformId, - force: true, - waitForCompletion: true, - } as StopOptions); - } catch (e) { - if (isRequestTimeout(e)) { - return fillResultsWithTimeouts({ - results, - id: transformId, - items: transformsInfo, - action: TRANSFORM_ACTIONS.DELETE, - }); - } - } - } - - await callWithRequest('transform.deleteTransform', { transformId }); - results[transformId] = { success: true }; - } catch (e) { - if (isRequestTimeout(e)) { - return fillResultsWithTimeouts({ - results, - id: transformInfo.id, - items: transformsInfo, - action: TRANSFORM_ACTIONS.DELETE, - }); - } - results[transformId] = { success: false, error: JSON.stringify(e) }; - } - } - return results; -} - -const previewTransformHandler: RouterRouteHandler = async (req, callWithRequest) => { - try { - return await callWithRequest('transform.getTransformsPreview', { body: req.payload }); - } catch (e) { - return wrapEsError(e); - } -}; - -const startTransformsHandler: RouterRouteHandler = async (req, callWithRequest) => { - const { transformsInfo } = req.payload as { - transformsInfo: TransformEndpointRequest[]; - }; - - try { - return await startTransforms(transformsInfo, callWithRequest); - } catch (e) { - return wrapEsError(e); - } -}; - -async function startTransforms( - transformsInfo: TransformEndpointRequest[], - callWithRequest: CallCluster -) { - const results: TransformEndpointResult = {}; - - for (const transformInfo of transformsInfo) { - const transformId = transformInfo.id; - try { - await callWithRequest('transform.startTransform', { transformId } as StartOptions); - results[transformId] = { success: true }; - } catch (e) { - if (isRequestTimeout(e)) { - return fillResultsWithTimeouts({ - results, - id: transformId, - items: transformsInfo, - action: TRANSFORM_ACTIONS.START, - }); - } - results[transformId] = { success: false, error: JSON.stringify(e) }; - } - } - return results; -} - -const stopTransformsHandler: RouterRouteHandler = async (req, callWithRequest) => { - const { transformsInfo } = req.payload as { - transformsInfo: TransformEndpointRequest[]; - }; - - try { - return await stopTransforms(transformsInfo, callWithRequest); - } catch (e) { - return wrapEsError(e); - } -}; - -async function stopTransforms( - transformsInfo: TransformEndpointRequest[], - callWithRequest: CallCluster -) { - const results: TransformEndpointResult = {}; - - for (const transformInfo of transformsInfo) { - const transformId = transformInfo.id; - try { - await callWithRequest('transform.stopTransform', { - transformId, - force: - transformInfo.state !== undefined - ? transformInfo.state === TRANSFORM_STATE.FAILED - : false, - waitForCompletion: true, - } as StopOptions); - results[transformId] = { success: true }; - } catch (e) { - if (isRequestTimeout(e)) { - return fillResultsWithTimeouts({ - results, - id: transformId, - items: transformsInfo, - action: TRANSFORM_ACTIONS.STOP, - }); - } - results[transformId] = { success: false, error: JSON.stringify(e) }; - } - } - return results; -} - -const getTransformMessagesHandler: RouterRouteHandler = async (req, callWithRequest) => { - const { getTransformAuditMessages } = transformAuditMessagesProvider(callWithRequest); - const { transformId } = req.params; - - try { - return await getTransformAuditMessages(transformId); - } catch (e) { - return wrapEsError(e); - } -}; - -const esSearchHandler: RouterRouteHandler = async (req, callWithRequest) => { - try { - return await callWithRequest('search', req.payload); - } catch (e) { - return { error: wrapEsError(e) }; - } -}; diff --git a/x-pack/legacy/plugins/transform/server/shim.ts b/x-pack/legacy/plugins/transform/server/shim.ts deleted file mode 100644 index 8f477d86441f4..0000000000000 --- a/x-pack/legacy/plugins/transform/server/shim.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Legacy } from 'kibana'; -import { createRouter, Router } from '../../../server/lib/create_router'; -import { registerLicenseChecker } from '../../../server/lib/register_license_checker'; -import { elasticsearchJsPlugin } from './client/elasticsearch_transform'; -export interface Core { - http: { - createRouter(basePath: string): Router; - }; -} - -export interface Plugins { - license: { - registerLicenseChecker: typeof registerLicenseChecker; - }; - xpack_main: any; - elasticsearch: any; -} - -export function createServerShim( - server: Legacy.Server, - pluginId: string -): { core: Core; plugins: Plugins } { - return { - core: { - http: { - createRouter: (basePath: string) => - createRouter(server, pluginId, basePath, { - plugins: [elasticsearchJsPlugin], - }), - }, - }, - plugins: { - license: { - registerLicenseChecker, - }, - xpack_main: server.plugins.xpack_main, - elasticsearch: server.plugins.elasticsearch, - }, - }; -} diff --git a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap index 8f87b3473b2e4..b4b4e7866e9b7 100644 --- a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap +++ b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap @@ -66,6 +66,8 @@ exports[`Error SERVICE_AGENT_NAME 1`] = `"java"`; exports[`Error SERVICE_ENVIRONMENT 1`] = `undefined`; +exports[`Error SERVICE_FRAMEWORK_NAME 1`] = `undefined`; + exports[`Error SERVICE_NAME 1`] = `"service name"`; exports[`Error SERVICE_NODE_NAME 1`] = `undefined`; @@ -176,6 +178,8 @@ exports[`Span SERVICE_AGENT_NAME 1`] = `"java"`; exports[`Span SERVICE_ENVIRONMENT 1`] = `undefined`; +exports[`Span SERVICE_FRAMEWORK_NAME 1`] = `undefined`; + exports[`Span SERVICE_NAME 1`] = `"service name"`; exports[`Span SERVICE_NODE_NAME 1`] = `undefined`; @@ -286,6 +290,8 @@ exports[`Transaction SERVICE_AGENT_NAME 1`] = `"java"`; exports[`Transaction SERVICE_ENVIRONMENT 1`] = `undefined`; +exports[`Transaction SERVICE_FRAMEWORK_NAME 1`] = `undefined`; + exports[`Transaction SERVICE_NAME 1`] = `"service name"`; exports[`Transaction SERVICE_NODE_NAME 1`] = `undefined`; diff --git a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts index ce2db4964a412..14233aad0f53c 100644 --- a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts +++ b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts @@ -7,6 +7,7 @@ export const SERVICE_NAME = 'service.name'; export const SERVICE_ENVIRONMENT = 'service.environment'; export const SERVICE_AGENT_NAME = 'agent.name'; +export const SERVICE_FRAMEWORK_NAME = 'service.framework.name'; export const SERVICE_NODE_NAME = 'service.node.name'; export const SERVICE_VERSION = 'service.version'; export const URL_FULL = 'url.full'; diff --git a/x-pack/plugins/apm/common/service_map.ts b/x-pack/plugins/apm/common/service_map.ts index 548b29346e483..f4354baa97655 100644 --- a/x-pack/plugins/apm/common/service_map.ts +++ b/x-pack/plugins/apm/common/service_map.ts @@ -10,6 +10,7 @@ import { ILicense } from '../../licensing/public'; export interface ServiceConnectionNode { 'service.name': string; 'service.environment': string | null; + 'service.framework.name': string | null; 'agent.name': string; } export interface ExternalConnectionNode { diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts index 04e2a43a4b8f1..85d71784b55c7 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts @@ -16,7 +16,8 @@ import { getServicesProjection } from '../../../common/projections/services'; import { mergeProjection } from '../../../common/projections/util/merge_projection'; import { SERVICE_AGENT_NAME, - SERVICE_NAME + SERVICE_NAME, + SERVICE_FRAMEWORK_NAME } from '../../../common/elasticsearch_fieldnames'; export interface IEnvOptions { @@ -92,6 +93,11 @@ async function getServicesData(options: IEnvOptions) { terms: { field: SERVICE_AGENT_NAME } + }, + service_framework_name: { + terms: { + field: SERVICE_FRAMEWORK_NAME + } } } } @@ -109,7 +115,11 @@ async function getServicesData(options: IEnvOptions) { 'service.name': bucket.key as string, 'agent.name': (bucket.agent_name.buckets[0]?.key as string | undefined) || '', - 'service.environment': options.environment || null + 'service.environment': options.environment || null, + 'service.framework.name': + (bucket.service_framework_name.buckets[0]?.key as + | string + | undefined) || null }; }) || [] ); diff --git a/x-pack/plugins/apm/server/lib/services/map.ts b/x-pack/plugins/apm/server/lib/services/map.ts deleted file mode 100644 index 97bb925674e26..0000000000000 --- a/x-pack/plugins/apm/server/lib/services/map.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import cytoscape from 'cytoscape'; -import { PromiseReturnType } from '../../../typings/common'; - -// This response right now just returns experimental data. -export type ServiceMapResponse = PromiseReturnType; -export async function getServiceMap(): Promise { - return [ - { data: { id: 'client', agentName: 'js-base' } }, - { data: { id: 'opbeans-node', agentName: 'nodejs' } }, - { data: { id: 'opbeans-python', agentName: 'python' } }, - { data: { id: 'opbeans-java', agentName: 'java' } }, - { data: { id: 'opbeans-ruby', agentName: 'ruby' } }, - { data: { id: 'opbeans-go', agentName: 'go' } }, - { data: { id: 'opbeans-go-2', agentName: 'go' } }, - { data: { id: 'opbeans-dotnet', agentName: 'dotnet' } }, - { data: { id: 'database', agentName: 'database' } }, - { data: { id: 'external API', agentName: 'external' } }, - - { - data: { - id: 'opbeans-client~opbeans-node', - source: 'client', - target: 'opbeans-node' - } - }, - { - data: { - id: 'opbeans-client~opbeans-python', - source: 'client', - target: 'opbeans-python' - } - }, - { - data: { - id: 'opbeans-python~opbeans-go', - source: 'opbeans-python', - target: 'opbeans-go' - } - }, - { - data: { - id: 'opbeans-python~opbeans-go-2', - source: 'opbeans-python', - target: 'opbeans-go-2' - } - }, - { - data: { - id: 'opbeans-python~opbeans-dotnet', - source: 'opbeans-python', - target: 'opbeans-dotnet' - } - }, - { - data: { - id: 'opbeans-node~opbeans-java', - source: 'opbeans-node', - target: 'opbeans-java' - } - }, - { - data: { - id: 'opbeans-node~database', - source: 'opbeans-node', - target: 'database' - } - }, - { - data: { - id: 'opbeans-go-2~opbeans-ruby', - source: 'opbeans-go-2', - target: 'opbeans-ruby' - } - }, - { - data: { - id: 'opbeans-go-2~external API', - source: 'opbeans-go-2', - target: 'external API' - } - } - ]; -} diff --git a/x-pack/plugins/console_extensions/server/spec/generated/monitoring.bulk.json b/x-pack/plugins/console_extensions/server/spec/generated/monitoring.bulk.json index 2b27950e7b097..26a9078f73ce8 100644 --- a/x-pack/plugins/console_extensions/server/spec/generated/monitoring.bulk.json +++ b/x-pack/plugins/console_extensions/server/spec/generated/monitoring.bulk.json @@ -12,6 +12,6 @@ "patterns": [ "_monitoring/bulk" ], - "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/master/es-monitoring.html" + "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/master/monitor-elasticsearch-cluster.html" } } diff --git a/x-pack/plugins/endpoint/common/types.ts b/x-pack/plugins/endpoint/common/types.ts index 4c319127e6399..fd7df65f98c64 100644 --- a/x-pack/plugins/endpoint/common/types.ts +++ b/x-pack/plugins/endpoint/common/types.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import { SearchResponse } from 'elasticsearch'; + /** * A deep readonly type that will make all children of a given object readonly recursively */ @@ -22,14 +24,28 @@ export type ImmutableMap = ReadonlyMap, Immutable>; export type ImmutableSet = ReadonlySet>; export type ImmutableObject = { readonly [K in keyof T]: Immutable }; +export enum Direction { + asc = 'asc', + desc = 'desc', +} + export class EndpointAppConstants { + static BASE_API_URL = '/api/endpoint'; static ALERT_INDEX_NAME = 'my-index'; static ENDPOINT_INDEX_NAME = 'endpoint-agent*'; static EVENT_INDEX_NAME = 'endpoint-events-*'; + static DEFAULT_TOTAL_HITS = 10000; /** * Legacy events are stored in indices with endgame-* prefix */ static LEGACY_EVENT_INDEX_NAME = 'endgame-*'; + + /** + * Alerts + **/ + static ALERT_LIST_DEFAULT_PAGE_SIZE = 10; + static ALERT_LIST_DEFAULT_SORT = '@timestamp'; + static ALERT_LIST_DEFAULT_ORDER = Direction.desc; } export interface AlertResultList { @@ -51,12 +67,22 @@ export interface AlertResultList { /** * The index of the requested page, starting at 0. */ - request_page_index: number; + request_page_index?: number; /** * The offset of the requested page, starting at 0. */ - result_from_index: number; + result_from_index?: number; + + /** + * A cursor-based URL for the next page. + */ + next: string | null; + + /** + * A cursor-based URL for the previous page. + */ + prev: string | null; } export interface EndpointResultList { @@ -70,13 +96,18 @@ export interface EndpointResultList { request_page_index: number; } -export interface AlertData { - '@timestamp': string; +/** + * Describes an Alert Event. + * Should be in line with ECS schema. + */ +export type AlertEvent = Immutable<{ + '@timestamp': number; agent: { id: string; version: string; }; event: { + id: string; action: string; }; file_classification: { @@ -91,9 +122,28 @@ export interface AlertData { name: string; }; }; + process: { + pid: number; + }; thread: {}; +}>; + +/** + * Metadata associated with an alert event. + */ +interface AlertMetadata { + id: string; + + // Alert Details Pagination + next: string | null; + prev: string | null; } +/** + * Union of alert data and metadata. + */ +export type AlertData = AlertEvent & AlertMetadata; + export interface EndpointMetadata { event: { created: Date; @@ -120,6 +170,19 @@ export interface EndpointMetadata { }; } +/** + * Represents `total` response from Elasticsearch after ES 7.0. + */ +export interface ESTotal { + value: number; + relation: string; +} + +/** + * `Hits` array in responses from ES search API. + */ +export type AlertHits = SearchResponse['hits']['hits']; + export interface LegacyEndpointEvent { '@timestamp': Date; endgame: { diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/components/header_nav.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/components/header_nav.tsx new file mode 100644 index 0000000000000..84570fe82ed44 --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/components/header_nav.tsx @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { MouseEvent } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiTabs, EuiTab } from '@elastic/eui'; +import { useHistory, useLocation } from 'react-router-dom'; + +export interface NavTabs { + name: string; + id: string; + href: string; +} + +export const navTabs: NavTabs[] = [ + { + id: 'home', + name: i18n.translate('xpack.endpoint.headerNav.home', { + defaultMessage: 'Home', + }), + href: '/', + }, + { + id: 'management', + name: i18n.translate('xpack.endpoint.headerNav.management', { + defaultMessage: 'Management', + }), + href: '/management', + }, + { + id: 'alerts', + name: i18n.translate('xpack.endpoint.headerNav.alerts', { + defaultMessage: 'Alerts', + }), + href: '/alerts', + }, + { + id: 'policies', + name: i18n.translate('xpack.endpoint.headerNav.policies', { + defaultMessage: 'Policies', + }), + href: '/policy', + }, +]; + +export const HeaderNavigation: React.FunctionComponent<{ basename: string }> = React.memo( + ({ basename }) => { + const history = useHistory(); + const location = useLocation(); + + function renderNavTabs(tabs: NavTabs[]) { + return tabs.map((tab, index) => { + return ( + { + event.preventDefault(); + history.push(tab.href); + }} + isSelected={tab.href === location.pathname} + > + {tab.name} + + ); + }); + } + + return {renderNavTabs(navTabs)}; + } +); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx index c6c032c273543..7ab66817a0888 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx @@ -16,6 +16,7 @@ import { appStoreFactory } from './store'; import { AlertIndex } from './view/alerts'; import { ManagementList } from './view/managing'; import { PolicyList } from './view/policy'; +import { HeaderNavigation } from './components/header_nav'; /** * This module will be loaded asynchronously to reduce the bundle size of your plugin's main bundle. @@ -41,6 +42,7 @@ const AppRoot: React.FunctionComponent = React.memo(({ basename, st + { return { alerts: [], - request_page_size: 10, - request_page_index: 0, - result_from_index: 0, + pageSize: 10, + pageIndex: 0, total: 0, location: undefined, }; @@ -24,9 +23,20 @@ export const alertListReducer: Reducer = ( action ) => { if (action.type === 'serverReturnedAlertsData') { + const { + alerts, + request_page_size: pageSize, + request_page_index: pageIndex, + total, + } = action.payload; return { ...state, - ...action.payload, + alerts, + pageSize, + // request_page_index is optional because right now we support both + // simple and cursor based pagination. + pageIndex: pageIndex || 0, + total, }; } else if (action.type === 'userChangedUrl') { return { diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/selectors.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/selectors.ts index 3a0461e06538f..54add85f0fe04 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/selectors.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/selectors.ts @@ -27,9 +27,8 @@ export const alertListData = (state: AlertListState) => state.alerts; * Returns the alert list pagination data from state */ export const alertListPagination = createStructuredSelector({ - pageIndex: (state: AlertListState) => state.request_page_index, - pageSize: (state: AlertListState) => state.request_page_size, - resultFromIndex: (state: AlertListState) => state.result_from_index, + pageIndex: (state: AlertListState) => state.pageIndex, + pageSize: (state: AlertListState) => state.pageSize, total: (state: AlertListState) => state.total, }); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts index bd4838419891d..6498462a8fc06 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts @@ -6,9 +6,14 @@ import { Dispatch, MiddlewareAPI } from 'redux'; import { CoreStart } from 'kibana/public'; -import { EndpointMetadata } from '../../../common/types'; +import { + EndpointMetadata, + AlertData, + AlertResultList, + Immutable, + ImmutableArray, +} from '../../../common/types'; import { AppAction } from './store/action'; -import { AlertResultList, Immutable } from '../../../common/types'; export { AppAction }; export type MiddlewareFactory = ( @@ -85,9 +90,23 @@ export interface EndpointAppLocation { } export type AlertListData = AlertResultList; -export type AlertListState = Immutable & { + +export interface AlertListState { + /** Array of alert items. */ + alerts: ImmutableArray; + + /** The total number of alerts on the page. */ + total: number; + + /** Number of alerts per page. */ + pageSize: number; + + /** Page number, starting at 0. */ + pageIndex: number; + + /** Current location object from React Router history. */ readonly location?: Immutable; -}; +} /** * Gotten by parsing the URL from the browser. Used to calculate the new URL when changing views. diff --git a/x-pack/plugins/endpoint/server/config.ts b/x-pack/plugins/endpoint/server/config.ts index 7ce5ebcf4eba9..908e14468c5c7 100644 --- a/x-pack/plugins/endpoint/server/config.ts +++ b/x-pack/plugins/endpoint/server/config.ts @@ -13,10 +13,20 @@ export type EndpointConfigType = ReturnType extends Observ export const EndpointConfigSchema = schema.object({ enabled: schema.boolean({ defaultValue: false }), + + /** + * Host Configuration + */ endpointResultListDefaultFirstPageIndex: schema.number({ defaultValue: 0 }), endpointResultListDefaultPageSize: schema.number({ defaultValue: 10 }), - alertResultListDefaultFirstPageIndex: schema.number({ defaultValue: 0 }), - alertResultListDefaultPageSize: schema.number({ defaultValue: 10 }), + + /** + * Alert Configuration + */ + alertResultListDefaultDateRange: schema.object({ + from: schema.string({ defaultValue: 'now-15m' }), + to: schema.string({ defaultValue: 'now' }), + }), }); export function createConfig$(context: PluginInitializerContext) { diff --git a/x-pack/plugins/endpoint/server/routes/alerts.test.ts b/x-pack/plugins/endpoint/server/routes/alerts.test.ts deleted file mode 100644 index e6bd9b8888ef7..0000000000000 --- a/x-pack/plugins/endpoint/server/routes/alerts.test.ts +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { - IClusterClient, - IRouter, - IScopedClusterClient, - KibanaResponseFactory, - RequestHandler, - RequestHandlerContext, - RouteConfig, -} from 'kibana/server'; -import { - elasticsearchServiceMock, - httpServerMock, - httpServiceMock, - loggingServiceMock, -} from '../../../../../src/core/server/mocks'; -import { AlertData, AlertResultList } from '../../common/types'; -import { SearchResponse } from 'elasticsearch'; -import { reqSchema, registerAlertRoutes } from './alerts'; -import { EndpointConfigSchema } from '../config'; -import * as data from '../test_data/all_alerts_data.json'; -import * as dataLegacy from '../test_data/all_alerts_data_legacy.json'; - -describe('test alerts route', () => { - let routerMock: jest.Mocked; - let mockResponse: jest.Mocked; - let mockClusterClient: jest.Mocked; - let mockScopedClient: jest.Mocked; - let routeHandler: RequestHandler; - let routeConfig: RouteConfig; - - beforeEach(() => { - mockClusterClient = elasticsearchServiceMock.createClusterClient(); - mockScopedClient = elasticsearchServiceMock.createScopedClusterClient(); - mockClusterClient.asScoped.mockReturnValue(mockScopedClient); - routerMock = httpServiceMock.createRouter(); - mockResponse = httpServerMock.createResponseFactory(); - registerAlertRoutes(routerMock, { - logFactory: loggingServiceMock.create(), - config: () => Promise.resolve(EndpointConfigSchema.validate({})), - }); - }); - - it('should correctly calculate legacy alert total', async () => { - const mockRequest = httpServerMock.createKibanaRequest({}); - - const response: SearchResponse = (dataLegacy as unknown) as SearchResponse< - AlertData - >; - mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(response)); - [routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) => - path.startsWith('/api/endpoint/alerts') - )!; - - await routeHandler( - ({ - core: { - elasticsearch: { - dataClient: mockScopedClient, - }, - }, - } as unknown) as RequestHandlerContext, - mockRequest, - mockResponse - ); - - expect(mockScopedClient.callAsCurrentUser).toBeCalled(); - expect(routeConfig.options).toEqual({ authRequired: true }); - expect(mockResponse.ok).toBeCalled(); - const alertResultList = mockResponse.ok.mock.calls[0][0]?.body as AlertResultList; - expect(alertResultList.total).toEqual(21); - expect(alertResultList.request_page_index).toEqual(0); - expect(alertResultList.result_from_index).toEqual(0); - expect(alertResultList.request_page_size).toEqual(10); - }); - - it('should return the latest of all alerts', async () => { - const mockRequest = httpServerMock.createKibanaRequest({}); - - const response: SearchResponse = (data as unknown) as SearchResponse; - mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(response)); - [routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) => - path.startsWith('/api/endpoint/alerts') - )!; - - await routeHandler( - ({ - core: { - elasticsearch: { - dataClient: mockScopedClient, - }, - }, - } as unknown) as RequestHandlerContext, - mockRequest, - mockResponse - ); - - expect(mockScopedClient.callAsCurrentUser).toBeCalled(); - expect(routeConfig.options).toEqual({ authRequired: true }); - expect(mockResponse.ok).toBeCalled(); - const alertResultList = mockResponse.ok.mock.calls[0][0]?.body as AlertResultList; - expect(alertResultList.total).toEqual(21); - expect(alertResultList.request_page_index).toEqual(0); - expect(alertResultList.result_from_index).toEqual(0); - expect(alertResultList.request_page_size).toEqual(10); - }); - - it('should return alert results according to pagination params -- POST', async () => { - const mockRequest = httpServerMock.createKibanaRequest({ - method: 'post', - body: { - page_size: 6, - page_index: 3, - }, - }); - mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(data)); - [routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) => - path.startsWith('/api/endpoint/alerts') - )!; - - await routeHandler( - ({ - core: { - elasticsearch: { - dataClient: mockScopedClient, - }, - }, - } as unknown) as RequestHandlerContext, - mockRequest, - mockResponse - ); - - expect(mockScopedClient.callAsCurrentUser).toBeCalled(); - expect(routeConfig.options).toEqual({ authRequired: true }); - expect(mockResponse.ok).toBeCalled(); - const alertResultList = mockResponse.ok.mock.calls[0][0]?.body as AlertResultList; - expect(alertResultList.total).toEqual(21); - expect(alertResultList.request_page_index).toEqual(3); - expect(alertResultList.result_from_index).toEqual(18); - expect(alertResultList.request_page_size).toEqual(6); - }); - - it('should return alert results according to pagination params -- GET', async () => { - const mockRequest = httpServerMock.createKibanaRequest({ - path: '/api/endpoint/alerts', - query: { - page_size: 3, - page_index: 2, - }, - }); - mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(data)); - [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => - path.startsWith('/api/endpoint/alerts') - )!; - - await routeHandler( - ({ - core: { - elasticsearch: { - dataClient: mockScopedClient, - }, - }, - } as unknown) as RequestHandlerContext, - mockRequest, - mockResponse - ); - - expect(mockScopedClient.callAsCurrentUser).toBeCalled(); - expect(routeConfig.options).toEqual({ authRequired: true }); - expect(mockResponse.ok).toBeCalled(); - const alertResultList = mockResponse.ok.mock.calls[0][0]?.body as AlertResultList; - expect(alertResultList.total).toEqual(21); - expect(alertResultList.request_page_index).toEqual(2); - expect(alertResultList.result_from_index).toEqual(6); - expect(alertResultList.request_page_size).toEqual(3); - }); - - it('should correctly validate params', async () => { - const validate = () => { - reqSchema.validate({ - page_size: 'abc', - page_index: 0, - }); - }; - expect(validate).toThrow(); - }); -}); diff --git a/x-pack/plugins/endpoint/server/routes/alerts.ts b/x-pack/plugins/endpoint/server/routes/alerts.ts deleted file mode 100644 index 541cf4af52769..0000000000000 --- a/x-pack/plugins/endpoint/server/routes/alerts.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { IRouter, KibanaRequest, RequestHandler } from 'kibana/server'; -import { SearchResponse } from 'elasticsearch'; -import { schema } from '@kbn/config-schema'; - -import { - getPagingProperties, - buildAlertListESQuery, -} from '../services/endpoint/alert_query_builders'; - -import { AlertData, AlertResultList } from '../../common/types'; -import { AlertRequestParams, EndpointAppContext } from '../types'; - -const ALERTS_ROUTE = '/api/endpoint/alerts'; - -export const reqSchema = schema.object({ - page_size: schema.number({ defaultValue: 10, min: 1, max: 10000 }), - page_index: schema.number({ defaultValue: 0, min: 0 }), -}); - -export function registerAlertRoutes(router: IRouter, endpointAppContext: EndpointAppContext) { - const alertsHandler: RequestHandler = async (ctx, req, res) => { - try { - const queryParams = await getPagingProperties( - req as KibanaRequest, - endpointAppContext - ); - const reqBody = await buildAlertListESQuery(queryParams); - const response = (await ctx.core.elasticsearch.dataClient.callAsCurrentUser( - 'search', - reqBody - )) as SearchResponse; - return res.ok({ body: mapToAlertResultList(endpointAppContext, queryParams, response) }); - } catch (err) { - return res.internalError({ body: err }); - } - }; - - router.get( - { - path: ALERTS_ROUTE, - validate: { - query: reqSchema, - }, - options: { authRequired: true }, - }, - alertsHandler - ); - - router.post( - { - path: ALERTS_ROUTE, - validate: { - body: reqSchema, - }, - options: { authRequired: true }, - }, - alertsHandler - ); -} - -function mapToAlertResultList( - endpointAppContext: EndpointAppContext, - queryParams: Record, - searchResponse: SearchResponse -): AlertResultList { - interface Total { - value: number; - relation: string; - } - - let totalNumberOfAlerts: number = 0; - let totalIsLowerBound: boolean = false; - - // We handle 2 separate schemas for the response below, due to: https://github.com/elastic/kibana/issues/56694 - if (typeof searchResponse?.hits?.total === 'object') { - const total: Total = searchResponse?.hits?.total as Total; - totalNumberOfAlerts = total?.value || 0; - totalIsLowerBound = total?.relation === 'gte' || false; - } else { - totalNumberOfAlerts = searchResponse?.hits?.total || 0; - } - - if (totalIsLowerBound) { - // This shouldn't happen, as we always try to fetch enough hits to satisfy the current request and the next page. - endpointAppContext.logFactory - .get('endpoint') - .warn('Total hits not counted accurately. Pagination numbers may be inaccurate.'); - } - - return { - request_page_size: queryParams.pageSize, - request_page_index: queryParams.pageIndex, - result_from_index: queryParams.fromIndex, - alerts: searchResponse?.hits?.hits?.map(entry => entry._source), - total: totalNumberOfAlerts, - }; -} diff --git a/x-pack/plugins/endpoint/server/routes/alerts/alerts.test.ts b/x-pack/plugins/endpoint/server/routes/alerts/alerts.test.ts new file mode 100644 index 0000000000000..adf686381f967 --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/alerts.test.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { IClusterClient, IRouter, IScopedClusterClient } from 'kibana/server'; +import { + elasticsearchServiceMock, + httpServiceMock, + loggingServiceMock, +} from '../../../../../../src/core/server/mocks'; +import { alertListReqSchema } from './list/schemas'; +import { registerAlertRoutes } from './index'; +import { EndpointConfigSchema } from '../../config'; + +describe('test alerts route', () => { + let routerMock: jest.Mocked; + let mockClusterClient: jest.Mocked; + let mockScopedClient: jest.Mocked; + + beforeEach(() => { + mockClusterClient = elasticsearchServiceMock.createClusterClient(); + mockScopedClient = elasticsearchServiceMock.createScopedClusterClient(); + mockClusterClient.asScoped.mockReturnValue(mockScopedClient); + routerMock = httpServiceMock.createRouter(); + registerAlertRoutes(routerMock, { + logFactory: loggingServiceMock.create(), + config: () => Promise.resolve(EndpointConfigSchema.validate({})), + }); + }); + + it('should fail to validate when `page_size` is not a number', async () => { + const validate = () => { + alertListReqSchema.validate({ + page_size: 'abc', + }); + }; + expect(validate).toThrow(); + }); + + it('should validate when `page_size` is a number', async () => { + const validate = () => { + alertListReqSchema.validate({ + page_size: 25, + }); + }; + expect(validate).not.toThrow(); + }); + + it('should validate when `page_size` can be converted to a number', async () => { + const validate = () => { + alertListReqSchema.validate({ + page_size: '50', + }); + }; + expect(validate).not.toThrow(); + }); + + it('should allow either `page_index` or `after`, but not both', async () => { + const validate = () => { + alertListReqSchema.validate({ + page_index: 1, + after: [123, 345], + }); + }; + expect(validate).toThrow(); + }); + + it('should allow either `page_index` or `before`, but not both', async () => { + const validate = () => { + alertListReqSchema.validate({ + page_index: 1, + before: 'abc', + }); + }; + expect(validate).toThrow(); + }); + + it('should allow either `before` or `after`, but not both', async () => { + const validate = () => { + alertListReqSchema.validate({ + before: ['abc', 'def'], + after: [123, 345], + }); + }; + expect(validate).toThrow(); + }); +}); diff --git a/x-pack/plugins/endpoint/server/routes/alerts/details/handlers.ts b/x-pack/plugins/endpoint/server/routes/alerts/details/handlers.ts new file mode 100644 index 0000000000000..3497573918fac --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/details/handlers.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { GetResponse } from 'elasticsearch'; +import { KibanaRequest, RequestHandler } from 'kibana/server'; +import { AlertEvent, EndpointAppConstants } from '../../../../common/types'; +import { EndpointAppContext } from '../../../types'; +import { AlertDetailsRequestParams } from '../types'; +import { AlertDetailsPagination } from './lib'; + +export const alertDetailsHandlerWrapper = function( + endpointAppContext: EndpointAppContext +): RequestHandler { + const alertDetailsHandler: RequestHandler = async ( + ctx, + req: KibanaRequest, + res + ) => { + try { + const alertId = req.params.id; + const response = (await ctx.core.elasticsearch.dataClient.callAsCurrentUser('get', { + index: EndpointAppConstants.ALERT_INDEX_NAME, + id: alertId, + })) as GetResponse; + + const config = await endpointAppContext.config(); + const pagination: AlertDetailsPagination = new AlertDetailsPagination( + config, + ctx, + req.params, + response + ); + + return res.ok({ + body: { + id: response._id, + ...response._source, + next: await pagination.getNextUrl(), + prev: await pagination.getPrevUrl(), + }, + }); + } catch (err) { + if (err.status === 404) { + return res.notFound({ body: err }); + } + return res.internalError({ body: err }); + } + }; + + return alertDetailsHandler; +}; diff --git a/x-pack/plugins/endpoint/server/routes/alerts/details/index.ts b/x-pack/plugins/endpoint/server/routes/alerts/details/index.ts new file mode 100644 index 0000000000000..3939594fe465c --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/details/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { alertDetailsReqSchema } from './schemas'; +export { alertDetailsHandlerWrapper } from './handlers'; diff --git a/x-pack/plugins/endpoint/server/routes/alerts/details/lib/index.ts b/x-pack/plugins/endpoint/server/routes/alerts/details/lib/index.ts new file mode 100644 index 0000000000000..20ae25f7aa849 --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/details/lib/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { AlertDetailsPagination } from './pagination'; diff --git a/x-pack/plugins/endpoint/server/routes/alerts/details/lib/pagination.ts b/x-pack/plugins/endpoint/server/routes/alerts/details/lib/pagination.ts new file mode 100644 index 0000000000000..94aff64e75f01 --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/details/lib/pagination.ts @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { GetResponse, SearchResponse } from 'elasticsearch'; +import { RequestHandlerContext } from 'src/core/server'; +import { + AlertEvent, + AlertHits, + Direction, + EndpointAppConstants, +} from '../../../../../common/types'; +import { EndpointConfigType } from '../../../../config'; +import { searchESForAlerts, Pagination } from '../../lib'; +import { AlertSearchQuery, SearchCursor, AlertDetailsRequestParams } from '../../types'; +import { BASE_ALERTS_ROUTE } from '../..'; + +/** + * Pagination class for alert details. + */ +export class AlertDetailsPagination extends Pagination< + AlertDetailsRequestParams, + GetResponse +> { + constructor( + config: EndpointConfigType, + requestContext: RequestHandlerContext, + state: AlertDetailsRequestParams, + data: GetResponse + ) { + super(config, requestContext, state, data); + } + + protected async doSearch( + direction: Direction, + cursor: SearchCursor + ): Promise> { + const reqData: AlertSearchQuery = { + pageSize: 1, + sort: EndpointAppConstants.ALERT_LIST_DEFAULT_SORT, + order: EndpointAppConstants.ALERT_LIST_DEFAULT_ORDER, + }; + + if (direction === Direction.asc) { + reqData.searchAfter = cursor; + } else { + reqData.searchBefore = cursor; + } + + const response = await searchESForAlerts( + this.requestContext.core.elasticsearch.dataClient, + reqData + ); + return response; + } + + protected getUrlFromHits(hits: AlertHits): string | null { + if (hits.length > 0) { + return `${BASE_ALERTS_ROUTE}/${hits[0]._id}`; + } + return null; + } + + /** + * Gets the next alert after this one. + */ + async getNextUrl(): Promise { + const response = await this.doSearch(Direction.asc, [ + this.data._source['@timestamp'].toString(), + this.data._source.event.id, + ]); + return this.getUrlFromHits(response.hits.hits); + } + + /** + * Gets the alert before this one. + */ + async getPrevUrl(): Promise { + const response = await this.doSearch(Direction.desc, [ + this.data._source['@timestamp'].toString(), + this.data._source.event.id, + ]); + return this.getUrlFromHits(response.hits.hits); + } +} diff --git a/x-pack/plugins/endpoint/server/routes/alerts/details/schemas.ts b/x-pack/plugins/endpoint/server/routes/alerts/details/schemas.ts new file mode 100644 index 0000000000000..18dc5f703b412 --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/details/schemas.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { schema } from '@kbn/config-schema'; + +export const alertDetailsReqSchema = schema.object({ + id: schema.string(), +}); diff --git a/x-pack/plugins/endpoint/server/routes/alerts/index.ts b/x-pack/plugins/endpoint/server/routes/alerts/index.ts new file mode 100644 index 0000000000000..2a4a127fb41bc --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/index.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { IRouter } from 'kibana/server'; +import { EndpointAppContext } from '../../types'; +import { EndpointAppConstants } from '../../../common/types'; +import { alertListHandlerWrapper, alertListReqSchema } from './list'; +import { alertDetailsHandlerWrapper, alertDetailsReqSchema } from './details'; + +export const BASE_ALERTS_ROUTE = `${EndpointAppConstants.BASE_API_URL}/alerts`; + +export function registerAlertRoutes(router: IRouter, endpointAppContext: EndpointAppContext) { + router.get( + { + path: BASE_ALERTS_ROUTE, + validate: { + query: alertListReqSchema, + }, + options: { authRequired: true }, + }, + alertListHandlerWrapper(endpointAppContext) + ); + + router.get( + { + path: `${BASE_ALERTS_ROUTE}/{id}`, + validate: { + params: alertDetailsReqSchema, + }, + options: { authRequired: true }, + }, + alertDetailsHandlerWrapper(endpointAppContext) + ); +} diff --git a/x-pack/plugins/endpoint/server/routes/alerts/lib/index.ts b/x-pack/plugins/endpoint/server/routes/alerts/lib/index.ts new file mode 100644 index 0000000000000..ff5b33a978b2c --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/lib/index.ts @@ -0,0 +1,164 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { SearchResponse } from 'elasticsearch'; +import { IScopedClusterClient } from 'kibana/server'; +import { JsonObject } from '../../../../../../../src/plugins/kibana_utils/public'; +import { esKuery, esQuery } from '../../../../../../../src/plugins/data/server'; +import { AlertEvent, Direction, EndpointAppConstants } from '../../../../common/types'; +import { + AlertSearchQuery, + AlertSearchRequest, + AlertSearchRequestWrapper, + AlertSort, +} from '../types'; + +export { Pagination } from './pagination'; + +function reverseSortDirection(order: Direction): Direction { + if (order === Direction.asc) { + return Direction.desc; + } + return Direction.asc; +} + +function buildQuery(query: AlertSearchQuery): JsonObject { + const queries: JsonObject[] = []; + + // only alerts + queries.push({ + term: { + 'event.kind': { + value: 'alert', + }, + }, + }); + + if (query.filters !== undefined && query.filters.length > 0) { + const filtersQuery = esQuery.buildQueryFromFilters(query.filters, undefined); + queries.push((filtersQuery.filter as unknown) as JsonObject); + } + + if (query.query) { + queries.push(esKuery.toElasticsearchQuery(esKuery.fromKueryExpression(query.query))); + } + + if (query.dateRange) { + const dateRangeFilter: JsonObject = { + range: { + ['@timestamp']: { + gte: query.dateRange.from, + lte: query.dateRange.to, + }, + }, + }; + + queries.push(dateRangeFilter); + } + + // Optimize + if (queries.length > 1) { + return { + bool: { + must: queries, + }, + }; + } else if (queries.length === 1) { + return queries[0]; + } + + return { + match_all: {}, + }; +} + +function buildSort(query: AlertSearchQuery): AlertSort { + const sort: AlertSort = [ + // User-defined primary sort, with default to `@timestamp` + { + [query.sort]: { + order: query.order, + }, + }, + // Secondary sort for tie-breaking + { + 'event.id': { + order: query.order, + }, + }, + ]; + + if (query.searchBefore) { + // Reverse sort order for search_before functionality + const newDirection = reverseSortDirection(query.order); + sort[0][query.sort].order = newDirection; + sort[1]['event.id'].order = newDirection; + } + + return sort; +} + +/** + * Builds a request body for Elasticsearch, given a set of query params. + **/ +const buildAlertSearchQuery = async ( + query: AlertSearchQuery +): Promise => { + let totalHitsMin: number = EndpointAppConstants.DEFAULT_TOTAL_HITS; + + // Calculate minimum total hits set to indicate there's a next page + if (query.fromIndex) { + totalHitsMin = Math.max( + query.fromIndex + query.pageSize * 2, + EndpointAppConstants.DEFAULT_TOTAL_HITS + ); + } + + const reqBody: AlertSearchRequest = { + track_total_hits: totalHitsMin, + query: buildQuery(query), + sort: buildSort(query), + }; + + if (query.searchAfter) { + reqBody.search_after = query.searchAfter; + } + + if (query.searchBefore) { + reqBody.search_after = query.searchBefore; + } + + const reqWrapper: AlertSearchRequestWrapper = { + size: query.pageSize, + index: EndpointAppConstants.ALERT_INDEX_NAME, + body: reqBody, + }; + + if (query.fromIndex) { + reqWrapper.from = query.fromIndex; + } + + return reqWrapper; +}; + +/** + * Makes a request to Elasticsearch, given an `AlertSearchRequestWrapper`. + **/ +export const searchESForAlerts = async ( + dataClient: IScopedClusterClient, + query: AlertSearchQuery +): Promise> => { + const reqWrapper = await buildAlertSearchQuery(query); + const response = (await dataClient.callAsCurrentUser('search', reqWrapper)) as SearchResponse< + AlertEvent + >; + + if (query.searchBefore !== undefined) { + // Reverse the hits when using `search_before`. + response.hits.hits.reverse(); + } + + return response; +}; diff --git a/x-pack/plugins/endpoint/server/routes/alerts/lib/pagination.ts b/x-pack/plugins/endpoint/server/routes/alerts/lib/pagination.ts new file mode 100644 index 0000000000000..e8218fcfb0ed2 --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/lib/pagination.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { RequestHandlerContext } from 'src/core/server'; +import { EndpointConfigType } from '../../../config'; + +/** + * Abstract Pagination class for determining next/prev urls, + * among other things. + */ +export abstract class Pagination { + constructor( + protected config: EndpointConfigType, + protected requestContext: RequestHandlerContext, + protected state: T, + protected data: Z + ) {} + abstract async getNextUrl(): Promise; + abstract async getPrevUrl(): Promise; +} diff --git a/x-pack/plugins/endpoint/server/routes/alerts/list/handlers.ts b/x-pack/plugins/endpoint/server/routes/alerts/list/handlers.ts new file mode 100644 index 0000000000000..4fece65a65bfe --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/list/handlers.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { KibanaRequest, RequestHandler } from 'kibana/server'; +import { EndpointAppContext } from '../../../types'; +import { searchESForAlerts } from '../lib'; +import { getRequestData, mapToAlertResultList } from './lib'; +import { AlertListRequestQuery } from '../types'; + +export const alertListHandlerWrapper = function( + endpointAppContext: EndpointAppContext +): RequestHandler { + const alertListHandler: RequestHandler = async ( + ctx, + req: KibanaRequest, + res + ) => { + try { + const reqData = await getRequestData(req, endpointAppContext); + const response = await searchESForAlerts(ctx.core.elasticsearch.dataClient, reqData); + const mappedBody = await mapToAlertResultList(ctx, endpointAppContext, reqData, response); + return res.ok({ body: mappedBody }); + } catch (err) { + return res.internalError({ body: err }); + } + }; + + return alertListHandler; +}; diff --git a/x-pack/plugins/endpoint/server/routes/alerts/list/index.ts b/x-pack/plugins/endpoint/server/routes/alerts/list/index.ts new file mode 100644 index 0000000000000..43a0745365c9b --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/list/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { alertListReqSchema } from './schemas'; +export { alertListHandlerWrapper } from './handlers'; diff --git a/x-pack/plugins/endpoint/server/routes/alerts/list/lib/index.ts b/x-pack/plugins/endpoint/server/routes/alerts/list/lib/index.ts new file mode 100644 index 0000000000000..fa08322910091 --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/list/lib/index.ts @@ -0,0 +1,104 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { decode } from 'rison-node'; +import { SearchResponse } from 'elasticsearch'; +import { KibanaRequest } from 'kibana/server'; +import { RequestHandlerContext } from 'src/core/server'; +import { Filter, TimeRange } from '../../../../../../../../src/plugins/data/server'; +import { + AlertEvent, + AlertData, + AlertResultList, + AlertHits, + EndpointAppConstants, + ESTotal, +} from '../../../../../common/types'; +import { EndpointAppContext } from '../../../../types'; +import { AlertSearchQuery, AlertListRequestQuery } from '../../types'; +import { AlertListPagination } from './pagination'; + +export const getRequestData = async ( + request: KibanaRequest, + endpointAppContext: EndpointAppContext +): Promise => { + const config = await endpointAppContext.config(); + const reqData: AlertSearchQuery = { + // Defaults not enforced by schema + pageSize: request.query.page_size || EndpointAppConstants.ALERT_LIST_DEFAULT_PAGE_SIZE, + sort: request.query.sort || EndpointAppConstants.ALERT_LIST_DEFAULT_SORT, + order: request.query.order || EndpointAppConstants.ALERT_LIST_DEFAULT_ORDER, + dateRange: ((request.query.date_range !== undefined + ? decode(request.query.date_range) + : config.alertResultListDefaultDateRange) as unknown) as TimeRange, + + // Filtering + query: request.query.query, + filters: + request.query.filters !== undefined + ? ((decode(request.query.filters) as unknown) as Filter[]) + : ([] as Filter[]), + + // Paging + pageIndex: request.query.page_index, + searchAfter: request.query.after, + searchBefore: request.query.before, + }; + + if (reqData.searchAfter === undefined && reqData.searchBefore === undefined) { + // simple pagination + if (reqData.pageIndex === undefined) { + reqData.pageIndex = 0; + } + reqData.fromIndex = reqData.pageIndex * reqData.pageSize; + } + + return reqData; +}; + +export async function mapToAlertResultList( + reqCtx: RequestHandlerContext, + endpointAppContext: EndpointAppContext, + reqData: AlertSearchQuery, + searchResponse: SearchResponse +): Promise { + let totalNumberOfAlerts: number = 0; + let totalIsLowerBound: boolean = false; + + // The cast below is due to: https://github.com/elastic/kibana/issues/56694 + const total: ESTotal = (searchResponse.hits.total as unknown) as ESTotal; + totalNumberOfAlerts = total.value || 0; + totalIsLowerBound = total.relation === 'gte' || false; + + if (totalIsLowerBound) { + // This shouldn't happen, as we always try to fetch enough hits to satisfy the current request and the next page. + endpointAppContext.logFactory + .get('alerts') + .warn('Total hits not counted accurately. Pagination numbers may be inaccurate.'); + } + + const config = await endpointAppContext.config(); + const hits = searchResponse.hits.hits; + const pagination: AlertListPagination = new AlertListPagination(config, reqCtx, reqData, hits); + + function mapHit(entry: AlertHits[0]): AlertData { + return { + id: entry._id, + ...entry._source, + prev: null, + next: null, + }; + } + + return { + request_page_size: reqData.pageSize, + request_page_index: reqData.pageIndex, + result_from_index: reqData.fromIndex, + next: await pagination.getNextUrl(), + prev: await pagination.getPrevUrl(), + alerts: hits.map(mapHit), + total: totalNumberOfAlerts, + }; +} diff --git a/x-pack/plugins/endpoint/server/routes/alerts/list/lib/pagination.ts b/x-pack/plugins/endpoint/server/routes/alerts/list/lib/pagination.ts new file mode 100644 index 0000000000000..f1161540b95e4 --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/list/lib/pagination.ts @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { get } from 'lodash'; +import { RisonValue, encode } from 'rison-node'; +import { RequestHandlerContext } from 'src/core/server'; +import { AlertHits } from '../../../../../common/types'; +import { EndpointConfigType } from '../../../../config'; +import { AlertSearchQuery } from '../../types'; +import { Pagination } from '../../lib'; +import { BASE_ALERTS_ROUTE } from '../..'; + +/** + * Pagination class for alert list. + */ +export class AlertListPagination extends Pagination { + protected hitLen: number; + + constructor( + config: EndpointConfigType, + requestContext: RequestHandlerContext, + state: AlertSearchQuery, + data: AlertHits + ) { + super(config, requestContext, state, data); + this.hitLen = data.length; + } + + protected getBasePaginationParams(): string { + let pageParams: string = ''; + if (this.state.query) { + pageParams += `query=${this.state.query}&`; + } + + if (this.state.filters !== undefined && this.state.filters.length > 0) { + pageParams += `filters=${encode((this.state.filters as unknown) as RisonValue)}&`; + } + + pageParams += `date_range=${encode((this.state.dateRange as unknown) as RisonValue)}&`; + + if (this.state.sort !== undefined) { + pageParams += `sort=${this.state.sort}&`; + } + + if (this.state.order !== undefined) { + pageParams += `order=${this.state.order}&`; + } + + pageParams += `page_size=${this.state.pageSize}&`; + + // NOTE: `search_after` and `search_before` are appended later. + return pageParams.slice(0, -1); // strip trailing `&` + } + + /** + * Gets the next set of alerts after this one. + */ + async getNextUrl(): Promise { + let url = null; + if (this.hitLen > 0 && this.hitLen <= this.state.pageSize) { + const lastCustomSortValue: string = get( + this.data[this.hitLen - 1]._source, + this.state.sort + ) as string; + const lastEventId: string = this.data[this.hitLen - 1]._source.event.id; + url = `${BASE_ALERTS_ROUTE}?${this.getBasePaginationParams()}&after=${lastCustomSortValue}&after=${lastEventId}`; + } + return url; + } + + /** + * Gets the previous set of alerts before this one. + */ + async getPrevUrl(): Promise { + let url = null; + if (this.hitLen > 0) { + const firstCustomSortValue: string = get(this.data[0]._source, this.state.sort) as string; + const firstEventId: string = this.data[0]._source.event.id; + url = `${BASE_ALERTS_ROUTE}?${this.getBasePaginationParams()}&before=${firstCustomSortValue}&before=${firstEventId}`; + } + return url; + } +} diff --git a/x-pack/plugins/endpoint/server/routes/alerts/list/schemas.ts b/x-pack/plugins/endpoint/server/routes/alerts/list/schemas.ts new file mode 100644 index 0000000000000..ce2163ac96dd1 --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/list/schemas.ts @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { decode } from 'rison-node'; +import { i18n } from '@kbn/i18n'; +import { schema } from '@kbn/config-schema'; +import { esKuery } from '../../../../../../../src/plugins/data/server'; +import { EndpointAppConstants } from '../../../../common/types'; + +export const alertListReqSchema = schema.object( + { + page_size: schema.maybe( + schema.number({ + min: 1, + max: 100, + }) + ), + page_index: schema.maybe( + schema.number({ + min: 0, + }) + ), + after: schema.maybe( + schema.arrayOf(schema.string(), { + minSize: 2, + maxSize: 2, + }) + ), + before: schema.maybe( + schema.arrayOf(schema.string(), { + minSize: 2, + maxSize: 2, + }) + ), + sort: schema.maybe(schema.string()), + order: schema.maybe( + schema.string({ + validate(value) { + if (value !== 'asc' && value !== 'desc') { + return i18n.translate('xpack.endpoint.alerts.errors.bad_sort_direction', { + defaultMessage: 'must be `asc` or `desc`', + }); + } + }, + }) + ), + query: schema.maybe( + schema.string({ + validate(value) { + try { + esKuery.fromKueryExpression(value); + } catch (err) { + return i18n.translate('xpack.endpoint.alerts.errors.bad_kql', { + defaultMessage: 'must be valid KQL', + }); + } + }, + }) + ), + + // rison-encoded string + filters: schema.maybe( + schema.string({ + validate(value) { + try { + decode(value); + } catch (err) { + return i18n.translate('xpack.endpoint.alerts.errors.bad_rison', { + defaultMessage: 'must be a valid rison-encoded string', + }); + } + }, + }) + ), + + // rison-encoded string + date_range: schema.maybe( + schema.string({ + validate(value) { + try { + decode(value); + } catch (err) { + return i18n.translate('xpack.endpoint.alerts.errors.bad_rison', { + defaultMessage: 'must be a valid rison-encoded string', + }); + } + }, + }) + ), + }, + { + validate(value) { + if (value.after !== undefined && value.page_index !== undefined) { + return i18n.translate('xpack.endpoint.alerts.errors.page_index_cannot_be_used_with_after', { + defaultMessage: '[page_index] cannot be used with [after]', + }); + } + if (value.before !== undefined && value.page_index !== undefined) { + return i18n.translate( + 'xpack.endpoint.alerts.errors.page_index_cannot_be_used_with_before', + { + defaultMessage: '[page_index] cannot be used with [before]', + } + ); + } + if (value.before !== undefined && value.after !== undefined) { + return i18n.translate('xpack.endpoint.alerts.errors.before_cannot_be_used_with_after', { + defaultMessage: '[before] cannot be used with [after]', + }); + } + if ( + value.before !== undefined && + value.sort !== undefined && + value.sort !== EndpointAppConstants.ALERT_LIST_DEFAULT_SORT + ) { + return i18n.translate( + 'xpack.endpoint.alerts.errors.before_cannot_be_used_with_custom_sort', + { + defaultMessage: '[before] cannot be used with custom sort', + } + ); + } + }, + } +); diff --git a/x-pack/plugins/endpoint/server/routes/alerts/types.ts b/x-pack/plugins/endpoint/server/routes/alerts/types.ts new file mode 100644 index 0000000000000..ae1f4e4cf5d55 --- /dev/null +++ b/x-pack/plugins/endpoint/server/routes/alerts/types.ts @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { Filter, TimeRange } from '../../../../../../src/plugins/data/server'; +import { JsonObject } from '../../../../../../src/plugins/kibana_utils/public'; +import { Direction } from '../../../common/types'; + +/** + * Sort parameters for alerts in ES. + */ +export interface AlertSortParam { + [key: string]: { + order: Direction; + }; +} + +/** + * Sort array for alerts. + */ +export type AlertSort = [AlertSortParam, AlertSortParam]; + +/** + * Cursor-based pagination params. + */ +export type SearchCursor = [string, string]; + +/** + * Request metadata used in searching alerts. + */ +export interface AlertSearchQuery { + pageSize: number; + pageIndex?: number; + fromIndex?: number; + query?: string; + filters?: Filter[]; + dateRange?: TimeRange; + sort: string; + order: Direction; + searchAfter?: SearchCursor; + searchBefore?: SearchCursor; +} + +/** + * ES request body for alerts. + */ +export interface AlertSearchRequest { + track_total_hits: number; + query: JsonObject; + sort: AlertSort; + search_after?: SearchCursor; +} + +/** + * Request for alerts. + */ +export interface AlertSearchRequestWrapper { + index: string; + size: number; + from?: number; + body: AlertSearchRequest; +} + +/** + * Request params for alert details. + */ +export interface AlertDetailsRequestParams { + id: string; +} + +/** + * Request params for alert queries. + * + * Must match exactly the values that the API receives. + */ +export interface AlertListRequestQuery { + page_index?: number; + page_size: number; + query?: string; + filters?: string; + date_range: string; + sort: string; + order: Direction; + after?: SearchCursor; + before?: SearchCursor; +} diff --git a/x-pack/plugins/endpoint/server/routes/index.ts b/x-pack/plugins/endpoint/server/routes/index.ts index 8eab6cd384765..8b0476ea7b229 100644 --- a/x-pack/plugins/endpoint/server/routes/index.ts +++ b/x-pack/plugins/endpoint/server/routes/index.ts @@ -3,7 +3,6 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - import { IRouter } from 'kibana/server'; export function addRoutes(router: IRouter) { diff --git a/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.test.ts b/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.test.ts deleted file mode 100644 index 3ef1142b9ce46..0000000000000 --- a/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { httpServerMock, loggingServiceMock } from 'src/core/server/mocks'; -import { EndpointConfigSchema } from '../../config'; -import { getPagingProperties, buildAlertListESQuery } from './alert_query_builders'; - -describe('test query builder', () => { - describe('test query builder request processing', () => { - it('should execute the correct Elasticsearch query for a default request', async () => { - const mockRequest = httpServerMock.createKibanaRequest({}); - const mockCtx = { - logFactory: loggingServiceMock.create(), - config: () => Promise.resolve(EndpointConfigSchema.validate({})), - }; - const queryParams = await getPagingProperties(mockRequest, mockCtx); - const query = buildAlertListESQuery(queryParams); - - expect(query).toMatchInlineSnapshot(` - Object { - "body": Object { - "query": Object { - "bool": Object { - "must": Array [ - Object { - "match": Object { - "event.kind": "alert", - }, - }, - ], - }, - }, - "sort": Array [ - Object { - "@timestamp": Object { - "order": "desc", - }, - }, - ], - "track_total_hits": 10000, - }, - "from": 0, - "index": "my-index", - "size": 10, - } - `); - }); - it('should adjust track_total_hits for deep pagination', async () => { - const mockRequest = httpServerMock.createKibanaRequest({ - query: { - page_index: 10, - page_size: 1000, - }, - }); - const mockCtx = { - logFactory: loggingServiceMock.create(), - config: () => Promise.resolve(EndpointConfigSchema.validate({})), - }; - const queryParams = await getPagingProperties(mockRequest, mockCtx); - const query = buildAlertListESQuery(queryParams); - - expect(query).toMatchInlineSnapshot(` - Object { - "body": Object { - "query": Object { - "bool": Object { - "must": Array [ - Object { - "match": Object { - "event.kind": "alert", - }, - }, - ], - }, - }, - "sort": Array [ - Object { - "@timestamp": Object { - "order": "desc", - }, - }, - ], - "track_total_hits": 12000, - }, - "from": 10000, - "index": "my-index", - "size": 1000, - } - `); - }); - }); -}); diff --git a/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.ts b/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.ts deleted file mode 100644 index e56ae43ef5c76..0000000000000 --- a/x-pack/plugins/endpoint/server/services/endpoint/alert_query_builders.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { KibanaRequest } from 'kibana/server'; -import { EndpointAppConstants } from '../../../common/types'; -import { EndpointAppContext, AlertRequestParams, JSONish } from '../../types'; - -export const buildAlertListESQuery: ( - pagingProperties: Record -) => JSONish = pagingProperties => { - const DEFAULT_TOTAL_HITS = 10000; - - // Calculate minimum total hits set to indicate there's a next page - const totalHitsMin = Math.max( - pagingProperties.fromIndex + pagingProperties.pageSize * 2, - DEFAULT_TOTAL_HITS - ); - - return { - body: { - track_total_hits: totalHitsMin, - query: { - bool: { - must: [ - { - match: { - 'event.kind': 'alert', - }, - }, - ], - }, - }, - sort: [ - { - '@timestamp': { - order: 'desc', - }, - }, - ], - }, - from: pagingProperties.fromIndex, - size: pagingProperties.pageSize, - index: EndpointAppConstants.ALERT_INDEX_NAME, - }; -}; - -export const getPagingProperties = async ( - request: KibanaRequest, - endpointAppContext: EndpointAppContext -): Promise> => { - const config = await endpointAppContext.config(); - const pagingProperties: { page_size?: number; page_index?: number } = {}; - - if (request?.route?.method === 'get') { - pagingProperties.page_index = request.query?.page_index; - pagingProperties.page_size = request.query?.page_size; - } else { - pagingProperties.page_index = request.body?.page_index; - pagingProperties.page_size = request.body?.page_size; - } - - const pageSize = pagingProperties.page_size || config.alertResultListDefaultPageSize; - const pageIndex = pagingProperties.page_index || config.alertResultListDefaultFirstPageIndex; - const fromIndex = pageIndex * pageSize; - - return { pageSize, pageIndex, fromIndex }; -}; diff --git a/x-pack/plugins/endpoint/server/test_data/all_alerts_data.json b/x-pack/plugins/endpoint/server/test_data/all_alerts_data.json deleted file mode 100644 index 128592f0f01df..0000000000000 --- a/x-pack/plugins/endpoint/server/test_data/all_alerts_data.json +++ /dev/null @@ -1,5471 +0,0 @@ -{ - "_shards": { - "failed": 0, - "skipped": 0, - "successful": 1, - "total": 1 - }, - "hits": { - "hits": [ - { - "_id": "mguP_G8BsHRXKE0Yiz15", - "_index": "my-index", - "_score": 1.0, - "_source": { - "@timestamp": 1542341895000, - "agent": { - "id": "ced9c68e-b94a-4d66-bb4c-6106514f0a2f", - "type": "endpoint", - "version": "3.0.0" - }, - "ecs": { - "version": "1.1.0" - }, - "event": { - "action": "open", - "category": "malware", - "dataset": "endpoint", - "kind": "alert", - "module": "endpoint", - "type": "access" - }, - "file": { - "accessed": 1542341100, - "created": 1542341100, - "hash": { - "imphash": "835d619dfdf3cc727cebd91300ab3462", - "md5": "4ace3baaa509d08510405e1b169e325b", - "sha1": "27fb21cf5db95ffca43b234affa99becc4023b9d", - "sha256": "6ed1c836dbf099be7845bdab7671def2c157643761b52251e04e9b6ee109ec75" - }, - "mtime": 1542341100, - "owner": "Administrators", - "path": "C:\\Users\\Administrator\\Downloads\\endpointpe-blacklist-test.exe", - "size": 188416 - }, - "file_classification": { - "captured_file": false, - "is_signature_trusted": false, - "malware_classification": { - "compressed_malware_features": { - "data_buffer": "eAHtnU1oHHUUwHsQ7MGDiIIUD4sH8WBBxJtopiLoUY0pYo2ZTbJJ0yQ17m4+ms/NRzeVWpuUWCL4sWlEYvFQ8KJQ6NCTEA8eRD30sIo3PdSriLi7837Pko3LbHZ2M5m+XObHm/d/X////83O7jCZvzacHBpPplNdfalkdjSdyty674Ft59dN71Dpb9v5eKh8LMEHjsCF2wIfVlRKsHROYPGkQO5+gY2vBSYYdWZFYGwEO/cITHMqkxPYnBBY+07gtCuQ9gSGigJ5lPPYGXcE+jA4z3Ad1ZtAUiDUyrEEPYzqRnIKgxd/Rgc7gygPo5wn95PouN7OeEYJ1UXiJgRmvscgp/LOziIkkSyT+xRVnXhZ4DKh5goCkzidRHkGO4uvCyw9LDDtCay8ILCAzrJOJaGuZwUuvSewivJVIPsklq8JbL4qMJsTSCcExrGs83WKU295ZFo5lr2TaZbcUw5FeJy8tgTeLpCy2iGeS67ABXzlgbEi1UC5FxcZnA4y/CLK82Qxi847FGGZRTLsCUxR1aWEwOp1AmOjDRYYzgwusL9WfqBiGJxnVAanixTq7Dp22LBdlWMJzlOx8wmBK2Rx5WmBLJIRwtAijOQE+ooCb2B5xBOYRtlfNeXpLpA7oyZRTqHzGenkmIJPnhBIMrzTwSA6H93CO5l+c1NA99f6IwLH8fUKdjTmDpTbgS50+gGVnECnE4PpooC2guPoaPADSHrcncNHmEHtAFkq3+EI+A37zsrrTvH3WTkvJLoOTyBp10wx2JcgVCRahA4NrICE4a+hrMXsA3qAHItW188E8ejO7XV3eh/KCYwxlamEwCgL8lN2wTntfrhY/U0g/5KAdvUpT+AszWqBdqH7VLeeZrExK9Cv1UgIDKA8g/cx7QAEP+AhAfRaMKB2HOJh+BSFSqKjSytNGBlc6PrpxvK7lCVDxbSG3Z7AhCMwx6gelwgLAltXBXJUTH29j+U1LHdipx/QprfKfGnF0sBpdBYxmEQyTzW0h6/0khcuhhJYRufym+i4VKMocJMs/KvfoW3/UJb4PeZOSZVONThZz4djP/75TAXa/CVfOvX3RgVLIDreLPN1pP1osW7lGmHsEhjBOzf+EPBE4vndvWz5xb/cChxGcv1LAb+tluALKnZ47isf1MXvz1ZMlsCXbXtPceqhrcp1ps6YHwQeBXLEPCf7q23tl9uJui0bGBgYRAccv7uXr/g5Af+2oNTrpgTa/vnpjBvpLAwM4gRBPvIZGBgYGBgYGBgYGBgYGBgYGBgYGBgYNAOc9oMXs4GBgYFBcNBnww5QzDXgRtPSaZ5lg/itsRaslgZ3bnWEEVnhMetIBwiiVnlbCbWrEftrt11zdwWnseFW1QO63w1is3ptD1pV9xG0t+zvfUrzrvh380qwXWAVCw6h78GIfG7ZlzltXu6hd+y92fECRFhjuH3bXG8N43oXEHperdzvUbteaDxhVTUeq25fqhG1X6Ai8mtF6BDXz2wR+dzSgg4Qsxls5T11XMG+82y8GkG+b7kL69xg7mF1SFvhBgYGsYH/Xi7HE+PVkiB2jt1bNZxT+k4558jR53ydz5//1m1KOgYGBgYGBgYGEQfnsYaG2z1sdPJS79XQSu91ndobOAHCaN5vNzUk1bceQVzUpbw3iOuT+UFmR18bHrp3gyhDC56lCd1y85w2+HSNUwVhhdGC7blLf+bV/fqtvhMg1NDjCcugB1QXswbs8ekj/v1BgzFHBIIsyP+HfwFdMpzu", - "decompressed_size": 27831, - "encoding": "zlib" - }, - "identifier": "endpointpe", - "prevention_threshold": 0.66, - "score": 1, - "threshold": 0.66, - "version": "3.0.33" - }, - "signature_signer": "", - "temp_file_path": "C:\\Windows\\TEMP\\581ac9e2-e9ea-499e-8ec6-d7eed985b6c3", - "user_blacklisted": false - }, - "host": { - "hostname": "HD-c15-bc09190a", - "ip": "10.179.244.14", - "name": "HD-c15-bc09190a", - "os": { - "name": "Windows", - "platform": "windows", - "version": "6.1" - } - }, - "process": { - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "command_line": "C:\\Windows\\Explorer.EXE", - "domain": "WIN-Q3DOP1UKA81", - "executable": "C:\\Windows\\explorer.exe", - "file_hash": { - "md5": "ac4c51eb24aa95b77f705ab159189e24", - "sha1": "4583daf9442880204730fb2c8a060430640494b1", - "sha256": "6a671b92a69755de6fd063fcbe4ba926d83b49f78c42dbaeed8cdb6bbc57576a" - }, - "hash": { - "imphash": "6422e341c67ba0880e012f8c7c634c21", - "md5": "ac4c51eb24aa95b77f705ab159189e24", - "sha1": "4583daf9442880204730fb2c8a060430640494b1", - "sha256": "6a671b92a69755de6fd063fcbe4ba926d83b49f78c42dbaeed8cdb6bbc57576a" - }, - "is_endpoint": false, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "modules": [ - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290248516, - "hash": { - "imphash": "6422e341c67ba0880e012f8c7c634c21", - "md5": "ac4c51eb24aa95b77f705ab159189e24", - "sha1": "4583daf9442880204730fb2c8a060430640494b1", - "sha256": "6a671b92a69755de6fd063fcbe4ba926d83b49f78c42dbaeed8cdb6bbc57576a" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 4278845440, - "mapped_size": 0, - "path": "C:\\Windows\\Explorer.EXE", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 b3 f5 00 00 00 00 00 0d ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 05:28" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258681, - "hash": { - "imphash": "d41d8cd98f00b204e9800998ecf8427e", - "md5": "3556d5a8bf2cc508bdab51dec38d7c61", - "sha1": "92015f7bbdb9dad35e41c533d2c5b85f1cd63d85", - "sha256": "91e3d98ad3119e8addf8d2aa1dd6795162842fff7101e4c70c5137e847b4ff50" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 2007891968, - "mapped_size": 0, - "path": "C:\\Windows\\SYSTEM32\\ntdll.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258315, - "hash": { - "imphash": "9165b02c931d76a9b666d8d42128111b", - "md5": "7a6326d96d53048fdec542df23d875a0", - "sha1": "5c02af0206c299f5bcab8da4237cfc92e3e93495", - "sha256": "182351570856cd6eedd9df7e2fb8ab76bd4d8fc70be11ad5de6484cfd70c21c6" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 2006712320, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\kernel32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258316, - "hash": { - "imphash": "3f7fb1504bb73a54888bf1c3650fe4cf", - "md5": "da68c291b4ef2dec9c5963266bcae454", - "sha1": "5696e8c68fcf64104499e20e7cd5452b58b4f4ba", - "sha256": "21aa4779fc21e762178517268c95467238c92851ad9160bffc36b2379c58337f" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791760175104, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\KERNELBASE.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534699, - "hash": { - "imphash": "e1ee2d71958d21e0e1bf887dfe76af7f", - "md5": "6df46d2bd74e3da1b45f08f10d172732", - "sha1": "3491f8f9a73c00b158e43a530210d67a4f0598ae", - "sha256": "2dc945f6f2c4a82189bc7da2fcbb7d9a0e2588a909539249e55ba82468e0c677" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791763779584, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\ADVAPI32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535038, - "hash": { - "imphash": "8c99b1c0f6cf68b07336751f460f1dba", - "md5": "7319bb10fa1f86e49e3dcf4136f6c957", - "sha1": "3eea5ee8bafb2b9975b236c5c5655df6f4b42aa1", - "sha256": "60de43ab267fd41c9804369b569139add30ed4e295c425f44fc04d3fcc95fca2" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791790780416, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\msvcrt.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535198, - "hash": { - "imphash": "b8ba136689cdc8d8b25fc04902f39a22", - "md5": "83404dcbce4925b6a5a77c5170f46d86", - "sha1": "22bda6b9da4fcf492b4dd16554b0c0e27e1b8667", - "sha256": "d669614d0b4461db244ad99fbe1ba92ceb9b4ed5ec8e987e23764e77d9ac7074" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791793074176, - "mapped_size": 0, - "path": "C:\\Windows\\SYSTEM32\\sechost.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258798, - "hash": { - "imphash": "46876e4adb924a616ddbbb1992d61257", - "md5": "0611473c1ad9e2d991cd9482068417f7", - "sha1": "c4a3fa902dedad5d448e1d8b2d113cae1dcf2f7a", - "sha256": "90afcc2a60350ece27e75e76459132ef0fa28ef283ce88fced4b82735a93ecda" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791762403328, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\RPCRT4.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258001, - "hash": { - "imphash": "51945fdf9aaf56aeb9d6fa1f21b638ce", - "md5": "1084aa52ccc324ea54c7121fa24c2221", - "sha1": "b13ef924708fa88577931ed0337000e90adcdf5b", - "sha256": "6e972cf624f7c0de8190434b3b30279a01c551713109f97b9ebb77fac9364754" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791792615424, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\GDI32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258929, - "hash": { - "imphash": "2cb501375ed127591bf5cfee7f1e52fe", - "md5": "fe70103391a64039a921dbfff9c7ab1b", - "sha1": "e0019d9442aeebd3bb42a24c38aa2fae4c6bd4f5", - "sha256": "f7d219d75037bc98f6c69143b00ab6000a31f8b5e211e0af514f4f4b681522a0" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 2005663744, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\USER32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534943, - "hash": { - "imphash": "919110853c18aa198ad129945337b1dd", - "md5": "d202223587518b13d72d68937b7e3f70", - "sha1": "916a3ce858f074f57dd9dac01be5cd4649f19887", - "sha256": "9db971b866d058adbb518dd99b87c5db8dd1e7c9073755b989ae7e9fb62901e8" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791763714048, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\LPK.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258933, - "hash": { - "imphash": "17bf46cf6bf6c8cae48be5b75615a353", - "md5": "2f8b1e3ee3545d3b5a8d56fa1ae07b65", - "sha1": "66310680ee38904b2852717af13028e53b4e8b8e", - "sha256": "2a3ec01f3bafe7d7d656886437f7ffecce440c0d3f3467804769ab4bf1ff7a99" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791782522880, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\USP10.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258859, - "hash": { - "imphash": "4b37cbf60127ea0550ec30e0b1c52984", - "md5": "eaf32cb8c1f810e4715b4dfbe785c7ff", - "sha1": "3b099b193abb9064e6937101d0c309f04d713882", - "sha256": "db6ad07fded42433e669508ab73faff6daff04575d6f1d016fe3eb6ecec4dd5d" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791792091136, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\SHLWAPI.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258854, - "hash": { - "imphash": "9c631776d86c9b15258c3cc2a6a7891d", - "md5": "26e716ed95dc48cf6e5ac046089366af", - "sha1": "2bd96b8ae5ae3ad14c16d2a98a91a9a9f26d179d", - "sha256": "f686d557b7ac1688efc7cb48311290d713d3db2e9e61e947098a7c80e3a1b9e9" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791765811200, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\SHELL32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258732, - "hash": { - "imphash": "faad2d5bf5c0ca9639e07a49e8c5d8ae", - "md5": "6c60b5aca7442efb794082cdacfc001c", - "sha1": "aae17944782b25f41f7b3a756532b4923f4ae817", - "sha256": "fc1d9124856a70ff232ef3057d66bee803295847624ce23b4d0217f23af52c75" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791783374848, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\ole32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258736, - "hash": { - "imphash": "774fed8966de60d3af2dd9070df5be6f", - "md5": "42f05f980f164e084db65b2e8cd8430f", - "sha1": "86498b3c5bbc240b9de0a10f2cb4185e754de6d7", - "sha256": "0813749847b08f6577791d18ad9eca6dff5b41c2f727ab5ee9e5bf9602ed50cb" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791785537536, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\OLEAUT32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258088, - "hash": { - "imphash": "ec96d3f694248151f968633563d10a36", - "md5": "eed05d42d91835064703e2318552ed25", - "sha1": "aa7e817ccad26070bce1161894f97e10aaa56fb9", - "sha256": "e9ee1e2253445b207b76f5d3073c612ed979a982522c1515e0fe8fa9641ae568" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791634935808, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\EXPLORERFRAME.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534886, - "hash": { - "imphash": "c0e1a4a34891e5dd2a6cbaa0895a8d38", - "md5": "8ccde014a4cdf84564e03ace064ca753", - "sha1": "957e29e029fe60b8ff43ff732463c39230b78226", - "sha256": "dd663029b2eb7b12fdb00fce403d8326141e540e3b9ce84cd5871473d3e2e2cf" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791735599104, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\DUser.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534885, - "hash": { - "imphash": "9353143c2b77b94cc82ab55c5fecf99c", - "md5": "3cb6a7286422c72c34dab54a5dff1a34", - "sha1": "5b93896a6abb36c2b8957973e3ce1860c1059367", - "sha256": "98d21efff511e407336a226420701e82554da01fa05661303836b6860d63749d" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791721181184, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\DUI70.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534912, - "hash": { - "imphash": "d76d7be0b8ac9aafe17d2cc7deb32b29", - "md5": "aa2c08ce85653b1a0d2e4ab407fa176c", - "sha1": "0119c23d88292a0e4fec04d5cf8629005a44e37c", - "sha256": "83dfd0c119b20aedb07114c9d1cf9ce2dfa938d0f1070256b0591a9e2c3997fa" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791793205248, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\IMM32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535018, - "hash": { - "imphash": "b523fff180cb22465ccf191b827e9923", - "md5": "c431eaf5caa1c82cac2534a2eab348a3", - "sha1": "e425577ccfc9b92efbbcb760d21fcaa478d3e51a", - "sha256": "addf850128dc675e67faba9a3d0d27e684f01f733962ca22927bb94503549e44" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791764697088, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\MSCTF.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535251, - "hash": { - "imphash": "56e651a119cdb899aadd2df3832bbcd1", - "md5": "d29e998e8277666982b4f0303bf4e7af", - "sha1": "e803b0af61ea2ddcd58b5a63b1cfbb73266318ea", - "sha256": "4f19ab5dc173e278ebe45832f6ceaa40e2df6a2eddc81b2828122442fe5d376c" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791742480384, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\UxTheme.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535202, - "hash": { - "imphash": "1c419f7cfacebfcd8e903e6be290407e", - "md5": "716175021bda290504ce434273f666bc", - "sha1": "4f00fbf4e9a88fae9e6682989032831b3d2eba86", - "sha256": "fa18ca2d8a5f4335e051e2933147d3c1e7308f7d446e2aeb6596cdef6e2afc88" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791718690816, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\POWRPROF.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258850, - "hash": { - "imphash": "a7a25e8b145e75fdeb21026d3895033a", - "md5": "5d8e6c95156ed1f79a63d1eade6f9ed5", - "sha1": "cadd211d74385550c5e055d3312303f4d64fdebc", - "sha256": "12130837d7f89a2c7e9d25747a8e5b9001e0a38d545178b49b450c23ae62664a" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791788814336, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\SETUPAPI.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290257756, - "hash": { - "imphash": "5cd9d6761799e2ff681533ef1ffbb31d", - "md5": "2477a28081bdaee622cf045acf8ee124", - "sha1": "304c5f29fa847fbd994ad7a0471214198b928c14", - "sha256": "00a09caf9129e84feea98fa03ce9012c9f961b64fee15c4f268822c0f82acc3c" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791760633856, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\CFGMGR32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534817, - "hash": { - "imphash": "2dbdaadf7e151289a49662379e253dfd", - "md5": "06fec9e8117103bb1141a560e98077da", - "sha1": "a8922793a930d602409b62be5ff01d5baec60000", - "sha256": "c5e61b11ddbbbbba3d9488970524f0975ea5fbdf16e2fa31f579f8bfa48353b1" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791760044032, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\DEVOBJ.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534887, - "hash": { - "imphash": "e7f2585307f1db90e7e5e48c40dc7134", - "md5": "da1b7075260f3872585bfcdd668c648b", - "sha1": "f2bd334006d728422721b7c639145a6ec59a459b", - "sha256": "3e10ef6e1a5c341b478322cb78a0ab7bfc70ad8023779b8b4542a7cb4ca756ab" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791742873600, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\dwmapi.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535203, - "hash": { - "imphash": "6a5a31c99a1562b9e5e10f4b4445be95", - "md5": "be097f5bb10f9079fceb2dc4e7e20f02", - "sha1": "dd572bac50bc4718126389c628d56a83d5c4d88a", - "sha256": "90a88986c8c5f30fb153ec803feda6572b2c2630a6c9578fcc017800692694d5" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791732256768, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\slc.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290257495, - "hash": { - "imphash": "fd8a6a2046d9572b7f8f4288ae251c61", - "md5": "497bfeddaf3950dd909c3b0c5558a25d", - "sha1": "5d55bdc156372f51eb126f7bc2a8af161a1ef254", - "sha256": "980ea189929d95eb36e35980fff0c81f7b78de9422771fde8f4ac7a779f5bd89" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791732453376, - "mapped_size": 0, - "path": "C:\\Windows\\WinSxS\\amd64_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.7601.17514_none_2b24536c71ed437a\\gdiplus.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258848, - "hash": { - "imphash": "cc4d63ca30fdbb90048e549782d2116a", - "md5": "858df0795cb5b4bace0f33708925a414", - "sha1": "e629ed78e6e1829263890974760dad8a431edf69", - "sha256": "a9063af8d5c73a722bd269d144d8a65c98db4cfdd9f626e3a8283754e22c8c9c" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791754801152, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\Secur32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258927, - "hash": { - "imphash": "b32250da0d30f7782b5b900d4d9c519a", - "md5": "2a86e54b441ad41557f75dc5609b9793", - "sha1": "83ddcf8a1a0ca423bf8417f5e59b5c431bf50c43", - "sha256": "8fede6909413c0fa5b63d58d39affd0f6c3beeaf19b7b2f8674913abfd79a912" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791756701696, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\SSPICLI.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258762, - "hash": { - "imphash": "26c2856b9813d8990c01c5a711b5063a", - "md5": "f06bb4e336ea57511fdbafafcc47de62", - "sha1": "bfee1b9d2269d26d99c8e462825ee8399c8bd4ec", - "sha256": "be43ec62548e9ff89a9495a1722e22dbb76eec3764f86e64057b636f27d15765" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791728259072, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\PROPSYS.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534993, - "hash": { - "imphash": "f0c6fd6831905d958b05645b680db89f", - "md5": "784fa3df338e2e8f5f0389d6fac428af", - "sha1": "6d32c67c91c6d374854e907c6719db2538540867", - "sha256": "9c8aa0cfdeb9e38aaf8eb08626070e0f0364f4f8a793cfe3532ec6c007980c34" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791757291520, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\CRYPTBASE.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290257499, - "hash": { - "imphash": "cd11f800bc54ae45ead9d98c96048145", - "md5": "7fa8fdc2c2a27817fd0f624e78d3b50c", - "sha1": "b4aa8e16396b1882eb75c28dfbec9949608afdde", - "sha256": "7b63f6aa2cd6d4d07ea3c595b868b1a0749bb11620027a2bd9b935e3055481e4" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791736123392, - "mapped_size": 0, - "path": "C:\\Windows\\WinSxS\\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_fa396087175ac9ac\\comctl32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258974, - "hash": { - "imphash": "b03f7d8315f3384d06c11e961e6fee07", - "md5": "26b73a85855681500bcc25c7cd9ff5b1", - "sha1": "393ed9ebbe380c77935df6d0eda2047cdd2224fe", - "sha256": "94d134a6af53ad629a4505b8b0ea37f61bb43af4db71874e7e87853163a9282a" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791724851200, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\WindowsCodecs.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535135, - "hash": { - "imphash": "ff720e05e534d67b814b8562265058f5", - "md5": "2c942733a5983dd4502219ff37c7ebc7", - "sha1": "263e8fbf77c0ceead0c9bca56394bffa4a664361", - "sha256": "34b20b6b0d7274e4b5b783f1d2345bc3dd9888964d5c2c65712f041a00cf5b45" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791758143488, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\profapi.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290257558, - "hash": { - "imphash": "6af6d846a78a6532fcb989d0d8aeb17d", - "md5": "90499f3163a9f815cf196a205ea3cd5d", - "sha1": "f97ff54dc4b132756fcf7041e55d645163f19851", - "sha256": "29b4ed3795cec1177eb367132914ce21c194cdec5db9dc923fd928c85e94d821" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791756898304, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\apphelp.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534778, - "hash": { - "imphash": "37afbae3e0f359c3718e379261f7ccfc", - "md5": "25983de69b57142039ac8d95e71cd9c9", - "sha1": "01691e3b0bfa569e64bdb7dc3d637a867ed2dc08", - "sha256": "a677da7ebcbcb6073d27e8a38809f51e971e83ed379bc599aaad6ef4216348da" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791787700224, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\CLBCatQ.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 ca 69 00 00 00 00 00 08 ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534842, - "hash": { - "imphash": "cbda3eb1c9c46a2121362e9775f60b47", - "md5": "024352feec9042260bb4cfb4d79a206b", - "sha1": "79c23ce566219f87ade8e55a292aaaabe4a639ec", - "sha256": "60cb39086e10c5b66ebc15e4df219620b344b4358d2918ab6bb3448a0ac8be36" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791731994624, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\EhStorShell.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258701, - "hash": { - "imphash": "37dad3873d5388f07576532bc042f677", - "md5": "7bbf670114373ce6a203fa155a9e0d0a", - "sha1": "104d89dde030b661d05c4c63a03fae1f46ab52d2", - "sha256": "36ef0a36c679e53b1b169289bd3c05d7c2839dc20c8c87bf520b633911fde198" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791647518720, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\ntshrui.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258920, - "hash": { - "imphash": "2d37f2d4b3c246f361ca150fc7ebf8d4", - "md5": "3a9c9baf610b0dd4967086040b3b62a9", - "sha1": "3207ac7f895eab34623d994548d7810e54be3e79", - "sha256": "e8e9a0f42b1ee7806edceed08aa024d037215d06ca317e3678bd5364ad513d23" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791753228288, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\srvcli.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258010, - "hash": { - "imphash": "2ba777561101c3b07566cc50db3a564c", - "md5": "1bf0cb861a48feb1638228760750f3cb", - "sha1": "fbc77224c1b444a6ec25e99f995f2f355e4d1d26", - "sha256": "37c781a8c546ead8b4d28bd7d730b9ac78eb799599ad69dad9054b6f9f1dd6bd" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791649091584, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\cscapi.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:35" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1247534897, - "hash": { - "imphash": "5bf52e420b6d5991bdcce16ada0828dc", - "md5": "1d63f4366288b8a7595397e27010fd44", - "sha1": "e459e1227083e4eabd19ee20e13754560fc7e02d", - "sha256": "99ea4ddd88d9c4a4cc9b238f533cb4d2c062d46239173997e8594d8a75811a01" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791735533568, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\IconCodecService.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534998, - "hash": { - "imphash": "77870f98ca4d25a823c74d7404a64bfd", - "md5": "d0c2fbb6d97416b0166478fc7ae2b212", - "sha1": "e290bdf2312ac30a4e9f2a96d7c84714eee84899", - "sha256": "7eab6c37f0a845e645ca44cc060ac6c56e386c7ef7a64716c6786c9602ad8c9d" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791750606848, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\CRYPTSP.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 ca 69 00 00 00 00 00 08 ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 17:43" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1247535161, - "hash": { - "imphash": "b8c20a01e4d94df61ee21f5350389f9c", - "md5": "5d8874a8c11dddde29e12de0e2013493", - "sha1": "a1c8e3e6ee44dcb68752d44b3b6f4ecce89c388d", - "sha256": "3e9a57137bf622af83e3e4d58971e2c0200559cca7545d16cf263aa03ee9c7d2" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791747461120, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\rsaenh.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258799, - "hash": { - "imphash": "a198edd0f73abd7cdbb54eef82ab1fc6", - "md5": "c2a8cb1275ecb85d246a9ecc02a728e3", - "sha1": "4417207821fc8f5c72ff531683f183caef297882", - "sha256": "3603fadca0060bd201148f9d59e4e2627f024609a6463ab525b5d1ad17bdcd10" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791758012416, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\RpcRtRemote.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258895, - "hash": { - "imphash": "4fe9beaa9bd4aa01f5063a7352325c89", - "md5": "d7f1ef374a90709b31591823b002f918", - "sha1": "336ac44b8ee88a6af3f3eaf461b8bdf94fa657ff", - "sha256": "05fd2837c9b03d14bb2a969c1ad77caef047d93dc5d0f6c2acbf0888e8f7b359" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791730683904, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\SndVolSSO.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 ca 69 00 00 00 00 00 08 ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534873, - "hash": { - "imphash": "0a90384377303e2a2625725018566a89", - "md5": "896f15a6434d93edb42519d5e18e6b50", - "sha1": "b91a3512a80c4201c3fcfaf62abace894fbba328", - "sha256": "9263f0cec58d45ebe3fb9c3061fb9392c55a7933b84b4592e6ee13cfc86d5a50" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791731929088, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\HID.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534952, - "hash": { - "imphash": "98a24f570dbcd3a092d95b3bd4e51a53", - "md5": "227e2c382a1e02f8d4965e664d3bbe43", - "sha1": "c4971ba9c1e4fdf0106c7cfab626a3d8737bbd07", - "sha256": "1cff20a8bf87ace4fa4935ebeed72bfb1a1fe902a754899e2f50798d67df5642" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791729504256, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\MMDevApi.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258898, - "hash": { - "imphash": "e99757a4c1beee1b5bf8b7b33b444dcc", - "md5": "1fcb1a72bf5c784f7358e6bef38e4571", - "sha1": "ef944a320de79bf05f0e30f54f3f8b2ba2e82c4a", - "sha256": "12da4240f8c964eda6223257bd9723fd9372e63ae86f00509163b1de12a5f6c5" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791637426176, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\timedate.cpl", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534704, - "hash": { - "imphash": "d6de6fde05f96ac848accdb1aef473e4", - "md5": "58775492ffd419248b08325e583c527f", - "sha1": "b0e9ca05d46cb53049c4ca33fe04bd08989a78f9", - "sha256": "dbb013971f5894f25c222c2d4d50a29db6df3c413792ee9ccc1a9e6d85469093" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791732322304, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\ATL.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 ca 69 00 00 00 00 00 08 ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535266, - "hash": { - "imphash": "fa1e670045065ff088a4ac664f9ac3d7", - "md5": "9f2bacd5e1776a4bb7cc0ec3c3a4f96d", - "sha1": "ad8c7ec85d532e5725b8535830f27c1abcf139b4", - "sha256": "19959d18601712901f03b83150d15e34ebcab355bb4692c9a28511a72f57fc66" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791730618368, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\WINBRAND.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290257498, - "hash": { - "imphash": "53f2c3eaeaa6e619e0ccd6e671e96145", - "md5": "e6f0f82788e8bd0f7a616350efa0761c", - "sha1": "9aa4aafda89325853ffa66169e697529164a23a2", - "sha256": "13091dcb3e3f4f52c3ff210e93aaf1dce142cfc09f671aeac5b922393b23e67b" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791633952768, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\actxprxy.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535165, - "hash": { - "imphash": "ae5e5f76641aadaf99f0ca29d2e1cadd", - "md5": "1f4492fe41767cdb8b89d17655847cdd", - "sha1": "c836a5e65d56900b6658fdaa3df8579bdd07ec69", - "sha256": "184547fac0c3d7148faa3f601929a7089de393bd19929a137dad743331dd3f77" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791719739392, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\ntmarta.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290259030, - "hash": { - "imphash": "f792b6ec2e11bc79d8eb1bb1bcb79a91", - "md5": "4e4ffb09d895aa000dd56d1404f69a7e", - "sha1": "40f5c1890f6de5284f6c897255e6907b0272349a", - "sha256": "d999e04bb35780088480eab322176570591a21e311d204bdcab010a63b34d24c" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791794974720, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\WLDAP32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258853, - "hash": { - "imphash": "2507624727988c72eb2a628a990000fd", - "md5": "c4f40f6cacd796a8e16671d0e9a2f319", - "sha1": "0881ae2a2fd3c5f03654410c474e5a25317942b2", - "sha256": "44853c645915d910ed0cc6d38f68b6c222528ec5fcbe990e238010f41204e682" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791729897472, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\shdocvw.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 ca 69 00 00 00 00 00 08 ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534923, - "hash": { - "imphash": "e52a872655c57d1b906101b6d5449bbf", - "md5": "a0a65d306a5490d2eb8e7de66898ecfd", - "sha1": "880ac520eb1d38ebb591707a26e6dd300df40643", - "sha256": "ce5da408f4edd5e81ce0925867f03c9a35172cf1571fe4c4c052e45ab69822bb" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791729831936, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\LINKINFO.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258932, - "hash": { - "imphash": "0e8a67fa12ce3d22a9e1d18bda5c3260", - "md5": "7a17485dc7d8a7ac81321a42cd034519", - "sha1": "83d1722a35eb16b010d8c9f72c627e97d4642101", - "sha256": "88d8705fa901793fc8c1cfd0175e49a6502bf0fc94a066ba573d2fd13aa5f04a" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791745036288, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\USERENV.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258852, - "hash": { - "imphash": "8b5c65294bec1cf89e97325a24b8cfc5", - "md5": "4e9c2db10f7e6ae91bf761139d4b745b", - "sha1": "6e8e6a53269ca8acc8c2456c80cd3a56d8deb98d", - "sha256": "8f63f78294f5585d599a114af449dcc447ccb239d0f0b490bfe6b34a2146e730" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791704207360, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\shacct.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535152, - "hash": { - "imphash": "44b39e98ae2946f304f4dbadcfffa307", - "md5": "5b3ebfc3da142324b388ddcc4465e1ff", - "sha1": "86e20ebf70fd35723eb635c4f3684891a2547a7b", - "sha256": "5d58642305311f9bc9b779c9598bfc4e7433b3ea58404bf1ff9466838a2328c7" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791716069376, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\SAMLIB.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258793, - "hash": { - "imphash": "7fec5787890bfedd3b3aa4082f53a08e", - "md5": "fc51229c7d4afa0d6f186133728b95ab", - "sha1": "f7a2f224356e68b612ecce4512c99f5b9c264d7d", - "sha256": "37e58c8e1c8437d1981725a5dcdaca7316cefbb570370cefc8d122f523b96ac0" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791714168832, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\samcli.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258588, - "hash": { - "imphash": "96f28fef38c977afbf3f6e8f39c0d6b9", - "md5": "6ceca4c6a489c9b2e6073afdaae3f607", - "sha1": "b228f6208642cb99e5bcdf2d3ebda2b8bc4fb020", - "sha256": "127506d1db38275614cbeb047c133718ef9d03266ba9c98be55ec7847cfc9c3d" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791722426368, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\netutils.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 ca 69 00 00 00 00 00 08 ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535084, - "hash": { - "imphash": "14bd8d9a93b98b2479e1f6cd57b7c790", - "md5": "7cb3acb163de051169095dc6507b8977", - "sha1": "b891ebebb25655157f7c612d5763e995c86009a2", - "sha256": "45d4deb0695440d8b5e959945b3f7a773e02e2ab305e316123a1064fc1905402" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791703945216, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\msls31.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290257535, - "hash": { - "imphash": "bf738a2fc0ab0601eea36f35e4cbcd27", - "md5": "0bee002c68e28ce6da161dcf1376d7d7", - "sha1": "d5cc3bec12c801e11217acc6927e1e6e401fe208", - "sha256": "1d4ee0b9ce22d139478008d5591b8c9f027c235cba601f95a96547cf98159d4b" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791631134720, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\authui.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258007, - "hash": { - "imphash": "76801e47683b36a4115dbe046717edbe", - "md5": "b3bfbd758506ecb50c5804aaa76318f9", - "sha1": "bf6c922467347a6690eb19c5e82be09b3295778b", - "sha256": "34e079a6ab2d41d1e0b3887b6ae31c43941061b7176fff2801c3f465c2c89578" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791630020608, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\CRYPTUI.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290257999, - "hash": { - "imphash": "04534d8dae5ab230b9bee9b1b0b2829d", - "md5": "3f9f2afa135f0663946a006dd5ffd897", - "sha1": "ea6456859b04b68af8dcd453381dd168af53fc5e", - "sha256": "276d1c9c78c529625c2ef3d77079324628686ea184767971901a1de93681c133" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791760896000, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\CRYPT32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258373, - "hash": { - "imphash": "2e50bc5d9fe777770c8a6b2cfaf6b2e9", - "md5": "884415bd4269c02eaf8e2613bf85500d", - "sha1": "c3a64f05c210b38c69d8f1fc1d74a71b56ada30c", - "sha256": "efe771709ec942694fd206ac8d0a48ed7dcd35036f074268e4aecd68ac982cea" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791759060992, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\MSASN1.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258922, - "hash": { - "imphash": "75124ca243f494ff6127697f3ebc418a", - "md5": "5fada8b707318e1bd63a7e2b81e6c8cb", - "sha1": "c5ad1c9bbc2f565237a144b9cf44711dfcf65ea5", - "sha256": "2590e88cab52fcc1b24cb262d293131c6280a5f234e0c130e77aa8697efa3b5f" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791793401856, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\urlmon.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258980, - "hash": { - "imphash": "248b27a31ddf696c2e3bfe6aed9c3eba", - "md5": "f6c5302e1f4813d552f41a0ac82455e5", - "sha1": "f0ec3ad7e90f559d1bc9b8849cf5668cafba2031", - "sha256": "e3ebf44621efc6381baae0f0efc13c356dcb6ee31bb258137edb3cc3e18549b5" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791786455040, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\WININET.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258097, - "hash": { - "imphash": "f6db6123d8a383f58cf318d00d2e7d1d", - "md5": "5180380d353277d395d3b36d790aa93e", - "sha1": "d5622ec5d922233867422d1e143969e226bb9a1c", - "sha256": "89b894eccf65704d00d30ea3bd45b184bfab8345b779f9ae2be66b9fc7226f72" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791780032512, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\iertutil.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535234, - "hash": { - "imphash": "13ecfa3a285149680a7a4b174c8b8f5b", - "md5": "94e026870a55aaeaff7853c1754091e9", - "sha1": "a4f845318e095d841b05e1400747ee4c28e1f28e", - "sha256": "b2f5d5629d12bdfa98dbed3898368f37d9009c7531b6909c7285a2c11c9a0f93" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791743004672, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\VERSION.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290259004, - "hash": { - "imphash": "da0bcac0c5f9dc653d00eecd5fb1c801", - "md5": "0d9764d58c5efd672b7184854b152e5e", - "sha1": "99d78db040987c69b6a70a42af86641ba0413956", - "sha256": "9827b43dabbec39ab2e2294408d9c5304ef27a684903c5234c6070387723d49e" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791758209024, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\WINSTA.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535280, - "hash": { - "imphash": "af1203c1d6d810c97729856780869b12", - "md5": "ef2ae43bcd46abb13fc3e5b2b1935c73", - "sha1": "c53e005cd04d99331ce3114ac119256133202313", - "sha256": "81fc06f306f620845d7dd8d06e706309e70bc89b589c81f3478302a3f5f73431" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791683301376, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\WINMM.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258936, - "hash": { - "imphash": "7e9874f9ecf2191b91f9a4dfa37f2ba1", - "md5": "1473768973453de50dc738c2955fc4dd", - "sha1": "7b046f6070844e3bc7deae115a1dfe5825030513", - "sha256": "14bc5da2442cb726acc1f277ddbeccf5d61e3a0a3e083a55a0bb610191e35220" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791648239616, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\wdmaud.drv", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535081, - "hash": { - "imphash": "086996ef0b01a463f114deb5244861b9", - "md5": "8560fffc8eb3a806dcd4f82252cfc8c6", - "sha1": "7562bbb63b0db6e4986ebdb86495c4fe284a1eaa", - "sha256": "cc27bc092369a89d6147b16568fedeb68b584d5738cd686c31f7fae22ed17b3b" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 1968373760, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\ksuser.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534742, - "hash": { - "imphash": "690cce63d22e22d9aa225c4a9290b2c4", - "md5": "78a1e65207484b7f8d3217507745f47c", - "sha1": "3542a591e9c97b48739f69e2a193dff461ea097c", - "sha256": "35f413adb9d157f3666dd15dd58104d629cd9143198a1ab914b73a4a3c9903dd" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791718625280, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\AVRT.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290257517, - "hash": { - "imphash": "64661addcde8896487dcc7cd32a4eda9", - "md5": "dc220ae6f64819099f7ebd6f137e32e7", - "sha1": "5707f15b666c7d3b07dfce9dac665a2e45c39113", - "sha256": "b8fe13b859fa83500dd95637fa6d4a5b8392c2a363e41d014d3b5374f636e1de" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791659118592, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\AUDIOSES.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 ca 69 00 00 00 00 00 08 ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534992, - "hash": { - "imphash": "3bf8d3fd03f9d07b7821df4b1da2be9d", - "md5": "1b7c3a37362c7b2890168c5fc61c8d9b", - "sha1": "78ba8d596c0ac4c38acb498416957891570a2a1d", - "sha256": "03727930e5bb5f9d91bab901fc9a2e3b795d68e2aee6a2cc3477f356c45a9c54" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791728062464, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\msacm32.drv", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534991, - "hash": { - "imphash": "9611d7fd4fe3c571fbf1db3d718ba82c", - "md5": "10ac5ce9f78dc281a1bbd9b8cc587b8a", - "sha1": "207582f9d9bec00a932fba886d575ee5b6502d42", - "sha256": "72288c0a88916d3c3828dbd948dbdb0928f26106319f8e60102d6c9004514d60" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791716659200, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\MSACM32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 ca 69 00 00 00 00 00 08 ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535038, - "hash": { - "imphash": "5a8ee2f48e79ef6ac4b33366d6642b50", - "md5": "ca2a0750ed830678997695ff61b04c30", - "sha1": "a27df990dde73e72bb02105f8af689a1ac324e59", - "sha256": "e84860cd97aa3c4565abb2d5d406a5c42b1ad2d8ba1b8cf81fe564d91f15f976" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791727996928, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\midimap.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 b3 f5 00 00 00 00 00 0d ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 07:10" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1247535256, - "hash": { - "imphash": "04a5e982c134477b1914ebcd7b6436d0", - "md5": "d6f630c1fd7f436316093ae500363b19", - "sha1": "197897b74f411040ba7df41a5bd3c1030661b904", - "sha256": "73a94b4938430396ea4240b1a6676b4e6c19cfaf8c52efb9a69b4b2175a86307" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791727734784, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\XmlLite.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258889, - "hash": { - "imphash": "8181b1ef70ff3d29984db497f92a2662", - "md5": "c3761661c17c2248a9379a8fb89e3de1", - "sha1": "d2ea41e02bbaa77f8b93b09277596a34cdae8853", - "sha256": "ce3477fa2b4058eb80739e0161fe957545f13cf86d313f6422732901d35f75f2" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791617568768, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\stobject.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290257641, - "hash": { - "imphash": "fbe995ff97475c5aa2777a4bc493d4b1", - "md5": "f832eeea97cdda1af577e721f652a0d1", - "sha1": "48f227a1e10d49edf56e3559e05c871bc285c199", - "sha256": "ebbb7ca199ba4df231123922bd310d43de0104c6185b70fe0281b938d5336f2e" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791616782336, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\BatMeter.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535260, - "hash": { - "imphash": "5d8fff13bf206e589cae241fc7f4d464", - "md5": "bd3674be7fc9d8d3732c83e8499576ed", - "sha1": "cb96190d6366e11dd6e6b48f4cdc4332015cfa67", - "sha256": "e6716a5895d629263a4d21959f48840429ab6f4b55a5fa2663ee5e86c9ca2bf1" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791727538176, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\WTSAPI32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290259008, - "hash": { - "imphash": "b2ecd39ae0055d9e1b8aa5bc78942cba", - "md5": "eb3f9c2de1236b5d46b2291d82970e43", - "sha1": "0ce9ddc1063256ab571b916389321fd7f572ddc0", - "sha256": "8a43d335f3d573bed98af54bb51e82546c2acc025da8a48d801213eb14e9d5d4" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791759781888, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\WINTRUST.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 ca 69 00 00 00 00 00 08 ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534970, - "hash": { - "imphash": "8accd78cb7feca81ac448f0485be30dc", - "md5": "4166f82be4d24938977dd1746be9b8a0", - "sha1": "5174036d781677f5444d9a23079baf18f4bbda44", - "sha256": "24121751b7306225ad1c808442d7b030def377e9316aa0a3c5c7460e87317881" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791730159616, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\es.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290257970, - "hash": { - "imphash": "8c20d7b93902b8c193a7fc1b4b58e9aa", - "md5": "42a9cb6906d9a8bedc83b57163e62924", - "sha1": "50e5592460d91205e912d55f60a2dd3cc4da4329", - "sha256": "e18522d3137653140757829efbfce624a5baa5842e2bba10b9e5ab6c84be49e1" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791614619648, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\dxp.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258826, - "hash": { - "imphash": "1df61af51096e9bbbdc1834405984e4c", - "md5": "2d2a6ec8ead30ec3ace2fd6fb1b3e122", - "sha1": "1e77948378474e155307d290b998994f720206bf", - "sha256": "e7ea375a3bde8fc764cb09524344370b9ee25f98ad6c83e6f37a569eb8d277d6" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791614160896, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\prnfldr.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290259000, - "hash": { - "imphash": "2f59265cb3df847423b60921203365be", - "md5": "0015acfbbdd164a8a730009908868ca7", - "sha1": "671c084513461900550bd49d3dccb58bdbe05adf", - "sha256": "e1ff243ad2cf959fab81efe701592414991c03416ff296adc93906e76b707c4d" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791654924288, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\WINSPOOL.DRV", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 ca 69 00 00 00 00 00 08 ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535225, - "hash": { - "imphash": "3d49b728c9125f451e7f2f215e9d3bbb", - "md5": "2bc7c9fd0a9f2c9afc373f3ad1ee3891", - "sha1": "1b7c6960a72509d1f408022d791c6a65acb2a75d", - "sha256": "0a82a475301202791a7c10f978f952eab7db146a702d4ea67e24e2c98bc19638" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791648108544, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\Syncreg.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258789, - "hash": { - "imphash": "c5c69e7d20ca382ddbc49947d651a8e7", - "md5": "10f815be90a66aafc6c713d1bd626064", - "sha1": "3e21f173a6bcdf629c442d89abadc48137c61bb2", - "sha256": "01139fc04bc53594296f6a0e16b8d20b940f64bc8119fe7705c03c4947958f39" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791612325888, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\pnidui.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258791, - "hash": { - "imphash": "6437e4761b1278fdecf142a679216f7b", - "md5": "b9f0a4020aa98b7a20287bf7fe99a1fd", - "sha1": "1f28ac7493ce972b45de191780a190504d1d0c44", - "sha256": "21138f161eeea46198890c7a2d073f2c82829e15676131bdad9f237edc7477cd" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791612194816, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\QUtil.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535239, - "hash": { - "imphash": "deeb658dae29d8df1c8dbb08f06801b0", - "md5": "3c073b0c596a0af84933e7406766b040", - "sha1": "06185554c38353211430f5f075c490558e46fb3d", - "sha256": "4698bba678f553e15ad4b07ad7fb236281f872defee97bfd637114476c8f97b3" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791752769536, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\wevtapi.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258586, - "hash": { - "imphash": "97bb6eee9e1ea3e5751077b655b54de5", - "md5": "a42f2c1eb3b66c54fb3c7b79d30c1a6d", - "sha1": "cee705de8d3dfcc9e2a14e0249d6be61fcd54a18", - "sha256": "a63836db3b01835dc1311526a95198d6ebccb1dc9ddafbc38ec36c128cdb98b9" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791609507840, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\netshell.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258138, - "hash": { - "imphash": "0bc508389b6b5577cf3cca214ca523a7", - "md5": "2b81776da02017a37fe26c662827470e", - "sha1": "8c85389640bea73a009d83079f8b4c963697035f", - "sha256": "a656353c50ee08422145d00db9cfd9f6d3e664753b3c454b171e2a56a8aa94dc" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791727210496, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\IPHLPAPI.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535145, - "hash": { - "imphash": "579f52f57e43aa6ff0d07e88af5d0ff5", - "md5": "044fe45ffd6ad40e3bbbe60b7f41babe", - "sha1": "94233c0d4169c02c85514adb1f05cd3298c87f43", - "sha256": "a1688a5e6e0f7037c850699462c2655006a7d873c97f9ab406c59d81749b6f09" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791763648512, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\NSI.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535281, - "hash": { - "imphash": "e710d6d30f2346e7cd91c89ec3b602d9", - "md5": "4c9210e8f4e052f6a4eb87716da0c24c", - "sha1": "d4fa50aded12eb162478d7606f1270b78dd1a44b", - "sha256": "460f7990bdadb7d58d6dc95b094d30a2efdc4ceed444b18a2f36e8d9076fb8b9" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791726948352, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\WINNSI.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258583, - "hash": { - "imphash": "7e01da4b2a8806d2944a3ff2e271958f", - "md5": "2df36f15b2bc1571a6a542a3c2107920", - "sha1": "660a44b660d8e57ef7d7efbbc006ac390a7901fa", - "sha256": "a918f1ee95269df973421af2f5713deeaf15ef0f77baa7e8c515ffb69896fb7a" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791735992320, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\nlaapi.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534791, - "hash": { - "imphash": "59b31e42f8fae7b5809ba7fcae732e0c", - "md5": "4cbcc37856ea2039c27a2fb661dda0e5", - "sha1": "cc666108d34168420a1d1942dda1e090154c7296", - "sha256": "74cbfab3092a9564bddfcb84db3e3f8bcfd1492938adf187423d3355d73d21c6" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791723999232, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\dhcpcsvc6.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258981, - "hash": { - "imphash": "1ec347d133df2fe4da3e5f8944caeae8", - "md5": "4bbfa57f594f7e8a8edc8f377184c3f0", - "sha1": "d48aafa576b40a5e386e609bba1010472551154a", - "sha256": "9f3ac5dea5a6250c3dbb97af79c81c0a48429486521f807355a1d7d3d861b75f" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791788486656, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\WS2_32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:35" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290257492, - "hash": { - "imphash": "f5d0254c5435291634c8b7357aa536bd", - "md5": "92dbf0a4c9239169010fc6e07859c82e", - "sha1": "634d8c12de82c422dfeba8f9a5fa84d03b7bcd35", - "sha256": "00fb2cf4420f0ffef519afe732a708cf249640121e2a891caa164313abd7f804" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791608655872, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\Actioncenter.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534790, - "hash": { - "imphash": "f17020f0f66b64fbdf51c75b43f3729d", - "md5": "f568f7c08458d69e4fcd8675bbb107e4", - "sha1": "c1e05f0255a6f386711044b11e2d04dfd328b26a", - "sha256": "a5fa25ecf248999a68ccecfbb508bfa1add18a23e20a9a9081a87c41caaa36c0" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791723868160, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\dhcpcsvc.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290257996, - "hash": { - "imphash": "eb1c8dd21e1f92a8be35a76b165ce8da", - "md5": "52d3d5e3586988d4d9e34acaac33105c", - "sha1": "2c20246d2c45fb6e8976b37ad62465f5f4255f2b", - "sha256": "c61b60ba962b25b8334f0941c3535ea4aca1cc060b8a196e396ca3e11ceef8a1" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791746412544, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\credssp.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258110, - "hash": { - "imphash": "9ba63732839305b29ebe539451171b45", - "md5": "8130391f82d52d36c0441f714136957f", - "sha1": "e2bb102565986a42d0a43bd3f337f94dbe54eead", - "sha256": "1fd4fee7caf63e450f27729e07ea2a2f09288629fd872dbb6e8710b16d8dbd5d" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791608131584, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\imapi2.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258038, - "hash": { - "imphash": "e070eff3751fea77ccd424469a9a07e6", - "md5": "6a5c1a8ac0b572679361026d0e900420", - "sha1": "fd9241fdda4b9d08ff1e205f9d5f78923ab884d8", - "sha256": "b5e693b48b462e97738a3d4e58b60846159649eb15f4d11074b4bc107cc88562" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791607345152, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\hgcpl.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 ca 69 00 00 00 00 00 08 ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535139, - "hash": { - "imphash": "1e00eab90042e5099339cb82841b434a", - "md5": "f7073c962c4fb7c415565dde109de49f", - "sha1": "671c2e910ff954700b3a1f80608423697895c0a9", - "sha256": "781e7088dcefbc34a808c3e7da41a56112b3f23abe9f54b5ef4d5cd9cd016b1d" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791680090112, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\npmproxy.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258777, - "hash": { - "imphash": "d402ebf00a5cffa66b6682780c262457", - "md5": "6b851e682a36453e1b1ee297ffb6e2ab", - "sha1": "3dc85ba13d1f720e8039865817bcc65dc0f1d35b", - "sha256": "a641d3fd9463c4788b45b8b5584ea4489c1f63a71b4b595ae85ff3482cd5eda6" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791606099968, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\QAgent.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534818, - "hash": { - "imphash": "09bf801b36364c598a2a8fdff079932c", - "md5": "cd1b5ad07e5f7fef30e055dcc9e96180", - "sha1": "4e835fdadd0c67fde44e385f69a1014d6ad11f4f", - "sha256": "63c58551f32b0b09377f64a6ae1fa81af93b8a707a57a8c18722086906ad3046" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791745167360, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\DEVRTL.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258413, - "hash": { - "imphash": "08a9b8e4e42e5520be662b4663289747", - "md5": "1eac1a8ca6874bf5b15e2efb9a9a7b86", - "sha1": "30cff16f17833aa042d8b6cc32d86c4a39c77c67", - "sha256": "e15ed4fefc3010c213694331ddfdc03767682325c898d773ab243e2dc8b08461" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791633100800, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\MsftEdit.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258939, - "hash": { - "imphash": "6ac24d44010fe2db4d5e9e0651b7a3cf", - "md5": "f9959237f106f2b2609e61a290c0652e", - "sha1": "7f7c92c4fe8244a7deac7fed4d5576042bfba29e", - "sha256": "fccc12e5aae1773bf87b1c4bce71d017db1a5a7ac189559058ea1ecc72075a82" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791628709888, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\werconcpl.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535233, - "hash": { - "imphash": "cce75846cdf9d74f85e44fc728ee8440", - "md5": "9689a9c7f7c2a1a423cda2c3b43fff65", - "sha1": "ebe6b3066634239a4f62780a8a6e27f33b0afc87", - "sha256": "914ad22d98975578bc14d821f72e8dfce24f2092f9c299d24ebbaf5408fe8b8b" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791646994432, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\wer.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290257998, - "hash": { - "imphash": "6e52c6bdbfd3d257064382284bd4f59c", - "md5": "1484b9ebf567346582de571b0e164ae0", - "sha1": "6b87eb7005fe659f976732307fe12b96747dfc8d", - "sha256": "9862bf22b2e32dabe7a82acee5b4ea1f0a93bdc3c71b20a6a4e568cccd76a7a6" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791628382208, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\framedynos.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 ca 69 00 00 00 00 00 08 ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535235, - "hash": { - "imphash": "64b92457c7762d63f903189058d583ca", - "md5": "7e591867422dc788b9e5bd337a669a08", - "sha1": "3bd1b2a2271d6756351d9b4876193efd8a845da0", - "sha256": "484e6bccdf7adce9a1aacad1bc7c7d7694b9e40fa90d94b14d80c607784f6c75" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791628251136, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\wercplsupport.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258497, - "hash": { - "imphash": "2814c7c81c59e8a913c288a8c72a9c1c", - "md5": "5c29199c9f0ede64f17f268084ec4392", - "sha1": "a767e893427f9b24fe06cbb3a155dd54162a402a", - "sha256": "ea9fd588a8c89399dd287399a912b356a4234cfe418239b227d255749f5ddde2" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791652564992, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\msxml6.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:35" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1247534858, - "hash": { - "imphash": "2ab209fb6a68c8e15483324a442c1c4c", - "md5": "809ae7d4ace06bbcf621e5c504bf6fc8", - "sha1": "c0e2202d99db67a9efa6c67226410ad3c7b657a6", - "sha256": "0baab89fb57468f27446947d75cbd6ddfc92d9b8f040144a12656803b2f7bf65" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791722491904, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\hcproviders.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 b3 f5 00 00 00 00 00 0d ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:36" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258095, - "hash": { - "imphash": "328b1cd6b239c7c01904019379bede4b", - "md5": "77a8a1791145710c7efe76ea82bf0763", - "sha1": "e421318d7b6d66c9214722c736f5b3d4207acf74", - "sha256": "9488b96e065299d273f9dcc82aa1203b48f0038d4f27324da19e9bfd925ca737" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791627726848, - "mapped_size": 0, - "path": "C:\\Program Files\\Internet Explorer\\ieproxy.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258892, - "hash": { - "imphash": "ec50511b4e46da8b1a467667a84f8047", - "md5": "9cead32e79a62150fe9f8557e58e008b", - "sha1": "4cbd17b96209b5e2da683382e05cef55f48d6107", - "sha256": "afe4c1725ee94d7de0749ae1495a4e5cc33c369f29b2a589da66ffe27ff9777e" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791757357056, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\SXS.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258896, - "hash": { - "imphash": "d75a096a9c47b1fd385a268e9c6f2f68", - "md5": "24f4b480f335a6c724af352253c5d98b", - "sha1": "a388cc90338cec7b5eec66e921599de0cc275a2b", - "sha256": "011413b236cad7b78ce0a0eec3e3085d48c7576a3205d025ba6ebfdf590538e4" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791660232704, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\thumbcache.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247527581, - "hash": { - "imphash": "be693a67b5b884d7609eaf574ba00955", - "md5": "d87e1e59c73c1f98d5ded5b3850c40f5", - "sha1": "141c0ebecdd2733b90431f18b188ee0b64456268", - "sha256": "536419bff9f877d4314b5d0c045d9a6e729489c389863fadf07e382050bc84fd" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 2009726976, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\PSAPI.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 b3 f5 00 00 00 00 00 0d ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:36" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258093, - "hash": { - "imphash": "39d5c5468a8e87803234025334b9dc09", - "md5": "f1115299b9f4c983bc4523b33e3a506c", - "sha1": "639946c23b630798284a92117882990ea31d702e", - "sha256": "01a1d8b3e5cf727f92f4a43d5c5f81022127d58a850d29d3f084ad411efbc9dd" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791578836992, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\ieframe.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535131, - "hash": { - "imphash": "84786d42c8a896b9a971b3c9eb8feb4c", - "md5": "9869a4a10b90546dbd56947839fb4b87", - "sha1": "5d9642f314d62dc5834cbd7950230bad3f85d982", - "sha256": "66c84dcf39d9f6896d55b1623184a028891a0a98abe6044de1d4bad60c3c8d72" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791591157760, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\OLEACC.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258887, - "hash": { - "imphash": "e6c083bfcedd032db2c66cd04f74c620", - "md5": "4e81439902079c348b61d7ff027fe147", - "sha1": "4386a5580b459aa4a0701addb753c3f9bf3da6f7", - "sha256": "e652c9ec77745504689532b3c394959f9b5bc29e9c008cb9ee09cda818514fa9" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791658594304, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\StructuredQuery.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258589, - "hash": { - "imphash": "45badcf3f18f69f9f72af5245898d1cb", - "md5": "405f4d32d2185f1f1bd753d8eeaffb3a", - "sha1": "68bc45bac1e1584c789a6b3134bee5a2540f3e56", - "sha256": "cac42c3e09c43be96592b670d70821386014db22d8239a9cfb9e33e54fb5c3d5" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791656890368, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\NetworkExplorer.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258495, - "hash": { - "imphash": "cdb39fb77293fb1bb86c2d5980ea8e88", - "md5": "022b05cee68d7826a93aedb4f1eb369e", - "sha1": "e7055d6cacb8c3fae06dc10ad480c8e6b8b7b592", - "sha256": "3b864d1471ed0949b02f1fa251b987185abeaddcbecd44efdbb6a7b7f03ca8bc" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791625760768, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\msxml3.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258914, - "hash": { - "imphash": "6b6c83729fa36b04c301494d1eb07752", - "md5": "bb074f35b49eb2ea416962b596281e1e", - "sha1": "355fdb9e66ffad42144b1b6ec4d8eb357ed05d52", - "sha256": "e07208204b9616027e5144e2f3ef1ba81168365b7d2a761210b0fbc65b97871e" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791623598080, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\systemcpl.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258594, - "hash": { - "imphash": "2bd8f9f72a13c2803ac3d34b805130b9", - "md5": "764908fe1fa96f93c95b1b67a0fced29", - "sha1": "88d0027e5d10158e3678d9eb2326779fef8a64d1", - "sha256": "26ef25ab307903c5e806a8cc3b750a491049e5d1225ceddfce64dd51aa6f592b" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791722557440, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\NETAPI32.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290259010, - "hash": { - "imphash": "6ad99a405bde55d6a18debafd3f5e5c5", - "md5": "3c91392d448f6e5d525a85b7550d8ba9", - "sha1": "b62eaf7d80617e136a8f3c9161c23464e6f2a171", - "sha256": "6fd0dc73dbe7519e2c643554c2a7f8fbe4f9a678c4241bb54b3c6e65d2abcf3a" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791722295296, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\wkscli.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247534877, - "hash": { - "imphash": "3e340766bf7f54e3e9746a945d4dcb71", - "md5": "a77be7cb3222b4fb0ac6c71d1c2698d4", - "sha1": "e68b4e0058fb130c765e5aa98af36e26563809db", - "sha256": "73566223914bf670df6b5931fa213e546713531b10391ed65b5256bbd7abde7f" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791735926784, - "mapped_size": 0, - "path": "C:\\Windows\\System32\\DSROLE.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258758, - "hash": { - "imphash": "c888173aa662e52d4b6194ed15819a13", - "md5": "db76db15efc6e4d1153a6c5bc895948d", - "sha1": "00dc6172c4507def32e4a269c08e76ab09abc3fe", - "sha256": "71ddf02c7ee2df66a08f1a2a08da39802c354624880a2be93a706ea7476422a3" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791690641408, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\SPPC.DLL", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 b3 f5 00 00 00 00 00 0d ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 07:10" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1247535243, - "hash": { - "imphash": "9484a9d0a0e3ef20592c9f66412400a6", - "md5": "666a60f6f5e719856ff6254e0966eff7", - "sha1": "10258e708443bd21997e7a977b5ee36bd758e368", - "sha256": "58c072e7e215991e19c1ca062c476081982f7b9f039714539ae7feb4981c200f" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791716200448, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\wbem\\wbemprox.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 b3 f5 00 00 00 00 00 0d ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 07:10" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258938, - "hash": { - "imphash": "03a62984ba62616e18740e69949df533", - "md5": "7db5aa22a8a8e5c2d335f44853c1f6de", - "sha1": "add6f6e2b6df5f571d06db724de5c7badad4e775", - "sha256": "a734a20357026c42950394682a52cbc3af956d09f1949e1b4e95467e999bc428" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791690051584, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\wbemcomn.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 ca 69 00 00 00 00 00 08 ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535244, - "hash": { - "imphash": "6178a249d43f815225b0a9205f1f4f70", - "md5": "718b6f51ab7f6fe2988a36868f9ad3ab", - "sha1": "7cc84a20d6597f58eebabea5489d72239c6e746b", - "sha256": "76141b4e94c2766e2c34cef523092948771a7893212efadbe88d2171b85ff012" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791683170304, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\wbem\\wbemsvc.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 04 b3 f5 00 00 00 00 00 0d ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 07:10" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1247534846, - "hash": { - "imphash": "c93ca8ec08e734d1b95c2a2d28884c47", - "md5": "a3f5e8ec1316c3e2562b82694a251c9e", - "sha1": "f0cdc2b44e609950ee97d9967c7459055a2af1a8", - "sha256": "f3dc6aa6a9d3b5bbc730668fc52c1d4bb5d515d404578bddd3d4869a7ed58822" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791688675328, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\wbem\\fastprox.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 01 c6 c1 00 00 00 00 00 07 ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "07/13/2009 19:17" - }, - "more_info_link": "http://www.microsoft.com/windows", - "program_name": "Windows System Catalog", - "publisher_link": "" - }, - "compile_time": 1247535150, - "hash": { - "imphash": "29f9ce11d25836037034b49be93790c6", - "md5": "ee26d130808d16c0e417bbbed0451b34", - "sha1": "962d52fb4d8f9965c5fc11a98f2f9048a2a5d918", - "sha256": "4886dce4faef146a40babd492a8000a2022fea542a6135a9bafd4cd09297b4e5" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791688478720, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\NTDSAPI.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - }, - { - "architecture": "x64", - "authenticode": { - "cert_signer": { - "issuer_name": "Microsoft Windows Verification PCA", - "serial_number": "61 15 23 0f 00 00 00 00 00 0a ", - "subject_name": "Microsoft Windows" - }, - "cert_timestamp": { - "issuer_name": "Microsoft Time-Stamp PCA", - "serial_number": "61 03 dc f6 00 00 00 00 00 0c ", - "subject_name": "Microsoft Time-Stamp Service", - "timestamp_string": "11/20/2010 11:37" - }, - "more_info_link": "http://www.microsoft.com", - "program_name": "Microsoft Windows", - "publisher_link": "" - }, - "compile_time": 1290258103, - "hash": { - "imphash": "ba45ab39c8fb40e4076d27cf8e0f4180", - "md5": "b8509dcfcfd577f568be4026bfd982c0", - "sha1": "1923c5995faf94d9b1767aca04e3134a5cedc07a", - "sha256": "e3608e6de15c400fa437349e7295fef10a1a0213ca3b532a58964b8c89749110" - }, - "malware_classification": { - "identifier": "Whitelisted", - "score": 0, - "threshold": 0, - "version": "3.0.0" - }, - "mapped_address": 8791788355584, - "mapped_size": 0, - "path": "C:\\Windows\\system32\\imagehlp.dll", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted" - } - ], - "name": "explorer.exe", - "parent": { - "executable": "", - "name": "" - }, - "pid": 784, - "ppid": 704, - "sid": "S-1-5-21-2016385190-3414718578-1263322444-500", - "signature_signer": "Microsoft Windows", - "signature_status": "trusted", - "start": 1542341500, - "threads": [ - { - "entrypoint": 4279023504, - "id": 1920, - "start": 1542341500, - "uptime": 437 - }, - { - "entrypoint": 2008002240, - "id": 1812, - "start": 1542341500, - "uptime": 437 - }, - { - "entrypoint": 8791783440744, - "id": 2472, - "start": 1542341500, - "uptime": 436 - }, - { - "entrypoint": 8791792141832, - "id": 2468, - "start": 1542341500, - "uptime": 436 - }, - { - "entrypoint": 8791790810108, - "id": 2464, - "start": 1542341500, - "uptime": 436 - }, - { - "entrypoint": 8791792141832, - "id": 2476, - "start": 1542341500, - "uptime": 435 - }, - { - "entrypoint": 2008021952, - "id": 1800, - "start": 1542341500, - "uptime": 434 - }, - { - "entrypoint": 2008021952, - "id": 2516, - "start": 1542341500, - "uptime": 433 - }, - { - "entrypoint": 8791792141832, - "id": 2500, - "start": 1542341500, - "uptime": 433 - }, - { - "entrypoint": 8791792141832, - "id": 1068, - "start": 1542341500, - "uptime": 432 - }, - { - "entrypoint": 8791792141832, - "id": 2676, - "start": 1542341500, - "uptime": 428 - }, - { - "entrypoint": 8791792141832, - "id": 2660, - "start": 1542341500, - "uptime": 428 - }, - { - "entrypoint": 8791792141832, - "id": 2748, - "start": 1542341500, - "uptime": 428 - }, - { - "entrypoint": 8791729529348, - "id": 2636, - "start": 1542341500, - "uptime": 428 - }, - { - "entrypoint": 8791792141832, - "id": 2732, - "start": 1542341500, - "uptime": 424 - }, - { - "entrypoint": 8791783440744, - "id": 1472, - "start": 1542341500, - "uptime": 419 - }, - { - "entrypoint": 2008021952, - "id": 2220, - "start": 1542341500, - "uptime": 415 - }, - { - "entrypoint": 2008021952, - "id": 2332, - "start": 1542341800, - "uptime": 104 - }, - { - "entrypoint": 2008021952, - "id": 3712, - "start": 1542341800, - "uptime": 99 - }, - { - "entrypoint": 8791792141832, - "id": 2080, - "start": 1542341800, - "uptime": 85 - }, - { - "entrypoint": 2008021952, - "id": 4012, - "start": 1542341800, - "uptime": 81 - }, - { - "entrypoint": 2008021952, - "id": 4060, - "start": 1542341800, - "uptime": 81 - }, - { - "entrypoint": 2008021952, - "id": 520, - "start": 1542341800, - "uptime": 77 - }, - { - "entrypoint": 2008021952, - "id": 3236, - "start": 1542341800, - "uptime": 74 - }, - { - "entrypoint": 2008021952, - "id": 3260, - "start": 1542341800, - "uptime": 72 - }, - { - "entrypoint": 8791792141832, - "id": 3680, - "start": 1542341900, - "uptime": 56 - }, - { - "entrypoint": 2008021952, - "id": 3708, - "start": 1542341900, - "uptime": 55 - }, - { - "entrypoint": 2008021952, - "id": 2512, - "start": 1542341900, - "uptime": 55 - }, - { - "entrypoint": 8791792141832, - "id": 3748, - "start": 1542341900, - "uptime": 54 - }, - { - "entrypoint": 8791690668104, - "id": 3872, - "start": 1542341900, - "uptime": 51 - }, - { - "entrypoint": 8791683305488, - "id": 1016, - "start": 1542341900, - "uptime": 26 - }, - { - "entrypoint": 2008021952, - "id": 3520, - "start": 1542341900, - "uptime": 26 - }, - { - "entrypoint": 8791792141832, - "id": 3992, - "start": 1542341900, - "uptime": 13 - }, - { - "entrypoint": 8791760904360, - "id": 3604, - "start": 1542341900, - "uptime": 12 - } - ], - "token": { - "domain": "WIN-Q3DOP1UKA81", - "integrity_level": 12288, - "integrity_level_name": "high", - "privileges": [ - { - "description": "Adjust memory quotas for a process", - "enabled": false, - "name": "SeIncreaseQuotaPrivilege" - }, - { - "description": "Manage auditing and security log", - "enabled": false, - "name": "SeSecurityPrivilege" - }, - { - "description": "Take ownership of files or other objects", - "enabled": false, - "name": "SeTakeOwnershipPrivilege" - }, - { - "description": "Load and unload device drivers", - "enabled": false, - "name": "SeLoadDriverPrivilege" - }, - { - "description": "Profile system performance", - "enabled": false, - "name": "SeSystemProfilePrivilege" - }, - { - "description": "Change the system time", - "enabled": false, - "name": "SeSystemtimePrivilege" - }, - { - "description": "Profile single process", - "enabled": false, - "name": "SeProfileSingleProcessPrivilege" - }, - { - "description": "Increase scheduling priority", - "enabled": false, - "name": "SeIncreaseBasePriorityPrivilege" - }, - { - "description": "Create a pagefile", - "enabled": false, - "name": "SeCreatePagefilePrivilege" - }, - { - "description": "Back up files and directories", - "enabled": false, - "name": "SeBackupPrivilege" - }, - { - "description": "Restore files and directories", - "enabled": false, - "name": "SeRestorePrivilege" - }, - { - "description": "Shut down the system", - "enabled": false, - "name": "SeShutdownPrivilege" - }, - { - "description": "Debug programs", - "enabled": false, - "name": "SeDebugPrivilege" - }, - { - "description": "Modify firmware environment values", - "enabled": false, - "name": "SeSystemEnvironmentPrivilege" - }, - { - "description": "Bypass traverse checking", - "enabled": true, - "name": "SeChangeNotifyPrivilege" - }, - { - "description": "Force shutdown from a remote system", - "enabled": false, - "name": "SeRemoteShutdownPrivilege" - }, - { - "description": "Remove computer from docking station", - "enabled": false, - "name": "SeUndockPrivilege" - }, - { - "description": "Perform volume maintenance tasks", - "enabled": false, - "name": "SeManageVolumePrivilege" - }, - { - "description": "Impersonate a client after authentication", - "enabled": true, - "name": "SeImpersonatePrivilege" - }, - { - "description": "Create global objects", - "enabled": true, - "name": "SeCreateGlobalPrivilege" - }, - { - "description": "Increase a process working set", - "enabled": false, - "name": "SeIncreaseWorkingSetPrivilege" - }, - { - "description": "Change the time zone", - "enabled": false, - "name": "SeTimeZonePrivilege" - }, - { - "description": "Create symbolic links", - "enabled": false, - "name": "SeCreateSymbolicLinkPrivilege" - } - ], - "sid": "S-1-5-21-2016385190-3414718578-1263322444-500", - "type": "tokenPrimary", - "user": "Administrator" - }, - "unique_pid": 35, - "unique_ppid": 0, - "uptime": 437, - "user": "Administrator" - }, - "user": { - "group": {} - } - } - } - ], - "max_score": 1.0, - "total": { - "relation": "eq", - "value": 21 - } - }, - "timed_out": false, - "took": 2 -} diff --git a/x-pack/plugins/endpoint/server/test_data/all_alerts_data_legacy.json b/x-pack/plugins/endpoint/server/test_data/all_alerts_data_legacy.json deleted file mode 100644 index 3863baed387aa..0000000000000 --- a/x-pack/plugins/endpoint/server/test_data/all_alerts_data_legacy.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "_shards": { - "failed": 0, - "skipped": 0, - "successful": 1, - "total": 1 - }, - "hits": { - "hits": [], - "max_score": 1.0, - "total": 21 - }, - "timed_out": false, - "took": 2 -} diff --git a/x-pack/plugins/endpoint/server/types.ts b/x-pack/plugins/endpoint/server/types.ts index a0c9cd4b90266..6dc128bd3d61e 100644 --- a/x-pack/plugins/endpoint/server/types.ts +++ b/x-pack/plugins/endpoint/server/types.ts @@ -6,13 +6,6 @@ import { LoggerFactory } from 'kibana/server'; import { EndpointConfigType } from './config'; -/** - * A JSON-like structure. - */ -export interface JSONish { - [key: string]: number | string | null | undefined | JSONish | JSONish[]; -} - /** * The context for Endpoint apps. */ @@ -20,11 +13,3 @@ export interface EndpointAppContext { logFactory: LoggerFactory; config(): Promise; } - -/** - * Request params for alert queries. - */ -export interface AlertRequestParams { - page_index?: number; - page_size?: number; -} diff --git a/x-pack/plugins/infra/common/inventory_models/pod/metrics/snapshot/cpu.ts b/x-pack/plugins/infra/common/inventory_models/pod/metrics/snapshot/cpu.ts index f25dd8179aa1a..d5979d455f0bf 100644 --- a/x-pack/plugins/infra/common/inventory_models/pod/metrics/snapshot/cpu.ts +++ b/x-pack/plugins/infra/common/inventory_models/pod/metrics/snapshot/cpu.ts @@ -7,9 +7,27 @@ import { SnapshotModel } from '../../../types'; export const cpu: SnapshotModel = { - cpu: { + cpu_with_limit: { + avg: { + field: 'kubernetes.pod.cpu.usage.limit.pct', + }, + }, + cpu_without_limit: { avg: { field: 'kubernetes.pod.cpu.usage.node.pct', }, }, + cpu: { + bucket_script: { + buckets_path: { + with_limit: 'cpu_with_limit', + without_limit: 'cpu_without_limit', + }, + script: { + source: 'params.with_limit > 0.0 ? params.with_limit : params.without_limit', + lang: 'painless', + }, + gap_policy: 'skip', + }, + }, }; diff --git a/x-pack/plugins/infra/common/inventory_models/pod/metrics/tsvb/pod_cpu_usage.ts b/x-pack/plugins/infra/common/inventory_models/pod/metrics/tsvb/pod_cpu_usage.ts index 1d778d11e0725..52d48c6329e51 100644 --- a/x-pack/plugins/infra/common/inventory_models/pod/metrics/tsvb/pod_cpu_usage.ts +++ b/x-pack/plugins/infra/common/inventory_models/pod/metrics/tsvb/pod_cpu_usage.ts @@ -24,9 +24,23 @@ export const podCpuUsage: TSVBMetricModelCreator = ( metrics: [ { field: 'kubernetes.pod.cpu.usage.node.pct', - id: 'avg-cpu-usage', + id: 'avg-cpu-without', type: 'avg', }, + { + field: 'kubernetes.pod.cpu.usage.limit.pct', + id: 'avg-cpu-with', + type: 'avg', + }, + { + id: 'cpu-usage', + type: 'calculation', + variables: [ + { id: 'cpu_with', name: 'with_limit', field: 'avg-cpu-with' }, + { id: 'cpu_without', name: 'without_limit', field: 'avg-cpu-without' }, + ], + script: 'params.with_limit > 0.0 ? params.with_limit : params.without_limit', + }, ], }, ], diff --git a/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts b/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts index 6f036475a1e1c..cf2b1e59b2a22 100644 --- a/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts +++ b/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts @@ -21,7 +21,7 @@ export const createTimeRangeWithInterval = async ( ): Promise => { const aggregations = getMetricsAggregations(options); const modules = await aggregationsToModules(framework, requestContext, aggregations, options); - const interval = + const interval = Math.max( (await calculateMetricInterval( framework, requestContext, @@ -32,7 +32,9 @@ export const createTimeRangeWithInterval = async ( }, modules, options.nodeType - )) || 60000; + )) || 60, + 60 + ); return { interval: `${interval}s`, from: options.timerange.to - interval * 5000, // We need at least 5 buckets worth of data diff --git a/x-pack/plugins/transform/kibana.json b/x-pack/plugins/transform/kibana.json new file mode 100644 index 0000000000000..87e38f83ef640 --- /dev/null +++ b/x-pack/plugins/transform/kibana.json @@ -0,0 +1,15 @@ +{ + "id": "transform", + "version": "kibana", + "server": true, + "ui": false, + "requiredPlugins": [ + "home", + "licensing", + "management" + ], + "optionalPlugins": [ + "usageCollection" + ], + "configPath": ["xpack", "transform"] +} diff --git a/x-pack/legacy/plugins/transform/server/client/elasticsearch_transform.ts b/x-pack/plugins/transform/server/client/elasticsearch_transform.ts similarity index 100% rename from x-pack/legacy/plugins/transform/server/client/elasticsearch_transform.ts rename to x-pack/plugins/transform/server/client/elasticsearch_transform.ts diff --git a/x-pack/plugins/transform/server/index.ts b/x-pack/plugins/transform/server/index.ts new file mode 100644 index 0000000000000..7b7cf3ee44fb5 --- /dev/null +++ b/x-pack/plugins/transform/server/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { PluginInitializerContext } from 'src/core/server'; + +import { TransformServerPlugin } from './plugin'; + +export const plugin = (ctx: PluginInitializerContext) => new TransformServerPlugin(ctx); diff --git a/x-pack/plugins/transform/server/plugin.ts b/x-pack/plugins/transform/server/plugin.ts new file mode 100644 index 0000000000000..7da991bc02b37 --- /dev/null +++ b/x-pack/plugins/transform/server/plugin.ts @@ -0,0 +1,89 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { i18n } from '@kbn/i18n'; +import { + CoreSetup, + Plugin, + IScopedClusterClient, + Logger, + PluginInitializerContext, +} from 'src/core/server'; + +import { LicenseType } from '../../licensing/common/types'; + +import { elasticsearchJsPlugin } from './client/elasticsearch_transform'; +import { Dependencies } from './types'; +import { ApiRoutes } from './routes'; +import { License } from './services'; + +declare module 'kibana/server' { + interface RequestHandlerContext { + transform?: { + dataClient: IScopedClusterClient; + }; + } +} + +const basicLicense: LicenseType = 'basic'; + +const PLUGIN = { + id: 'transform', + minimumLicenseType: basicLicense, + getI18nName: (): string => + i18n.translate('xpack.transform.appTitle', { + defaultMessage: 'Transforms', + }), +}; + +export class TransformServerPlugin implements Plugin<{}, void, any, any> { + private readonly apiRoutes: ApiRoutes; + private readonly license: License; + private readonly logger: Logger; + + constructor(initContext: PluginInitializerContext) { + this.logger = initContext.logger.get(); + this.apiRoutes = new ApiRoutes(); + this.license = new License(); + } + + setup({ elasticsearch, http }: CoreSetup, { licensing }: Dependencies): {} { + const router = http.createRouter(); + + this.license.setup( + { + pluginId: PLUGIN.id, + minimumLicenseType: PLUGIN.minimumLicenseType, + defaultErrorMessage: i18n.translate('xpack.transform.licenseCheckErrorMessage', { + defaultMessage: 'License check failed', + }), + }, + { + licensing, + logger: this.logger, + } + ); + + this.apiRoutes.setup({ + router, + license: this.license, + }); + + // Can access via new platform router's handler function 'context' parameter - context.transform.client + const transformClient = elasticsearch.createClient('transform', { + plugins: [elasticsearchJsPlugin], + }); + http.registerRouteHandlerContext('transform', (context, request) => { + return { + dataClient: transformClient.asScoped(request), + }; + }); + + return {}; + } + + start() {} + stop() {} +} diff --git a/x-pack/legacy/plugins/transform/server/routes/api/error_utils.ts b/x-pack/plugins/transform/server/routes/api/error_utils.ts similarity index 80% rename from x-pack/legacy/plugins/transform/server/routes/api/error_utils.ts rename to x-pack/plugins/transform/server/routes/api/error_utils.ts index 094c0308ff20f..d09152bf1a603 100644 --- a/x-pack/legacy/plugins/transform/server/routes/api/error_utils.ts +++ b/x-pack/plugins/transform/server/routes/api/error_utils.ts @@ -4,11 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ +import { boomify, isBoom } from 'boom'; + import { i18n } from '@kbn/i18n'; + +import { ResponseError, CustomHttpResponseOptions } from 'src/core/server'; + import { TransformEndpointRequest, TransformEndpointResult, -} from '../../../public/app/hooks/use_api_types'; +} from '../../../../../legacy/plugins/transform/public/app/hooks/use_api_types'; const REQUEST_TIMEOUT = 'RequestTimeout'; @@ -71,3 +76,12 @@ export function fillResultsWithTimeouts({ results, id, items, action }: Params) return accumResults; }, newResults); } + +export function wrapError(error: any): CustomHttpResponseOptions { + const boom = isBoom(error) ? error : boomify(error, { statusCode: error.status }); + return { + body: boom, + headers: boom.output.headers, + statusCode: boom.output.statusCode, + }; +} diff --git a/x-pack/plugins/transform/server/routes/api/privileges.ts b/x-pack/plugins/transform/server/routes/api/privileges.ts new file mode 100644 index 0000000000000..6003a88ffa40c --- /dev/null +++ b/x-pack/plugins/transform/server/routes/api/privileges.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { + APP_CLUSTER_PRIVILEGES, + APP_INDEX_PRIVILEGES, +} from '../../../../../legacy/plugins/transform/common/constants'; +// NOTE: now we import it from our "public" folder, but when the Authorisation lib +// will move to the "es_ui_shared" plugin, it will be imported from its "static" folder +import { Privileges } from '../../../../../legacy/plugins/transform/public/app/lib/authorization'; + +import { RouteDependencies } from '../../types'; +import { addBasePath } from '../index'; + +export function registerPrivilegesRoute({ router, license }: RouteDependencies) { + router.get( + { path: addBasePath('privileges'), validate: {} }, + license.guardApiRoute(async (ctx, req, res) => { + const privilegesResult: Privileges = { + hasAllPrivileges: true, + missingPrivileges: { + cluster: [], + index: [], + }, + }; + + if (license.getStatus().isSecurityEnabled === false) { + // If security isn't enabled, let the user use app. + return res.ok({ body: privilegesResult }); + } + + // Get cluster priviliges + const { + has_all_requested: hasAllPrivileges, + cluster, + } = await ctx.transform!.dataClient.callAsCurrentUser('transport.request', { + path: '/_security/user/_has_privileges', + method: 'POST', + body: { + cluster: APP_CLUSTER_PRIVILEGES, + }, + }); + + // Find missing cluster privileges and set overall app privileges + privilegesResult.missingPrivileges.cluster = extractMissingPrivileges(cluster); + privilegesResult.hasAllPrivileges = hasAllPrivileges; + + // Get all index privileges the user has + const { indices } = await ctx.transform!.dataClient.callAsCurrentUser('transport.request', { + path: '/_security/user/_privileges', + method: 'GET', + }); + + // Check if they have all the required index privileges for at least one index + const oneIndexWithAllPrivileges = indices.find(({ privileges }: { privileges: string[] }) => { + if (privileges.includes('all')) { + return true; + } + + const indexHasAllPrivileges = APP_INDEX_PRIVILEGES.every(privilege => + privileges.includes(privilege) + ); + + return indexHasAllPrivileges; + }); + + // If they don't, return list of required index privileges + if (!oneIndexWithAllPrivileges) { + privilegesResult.missingPrivileges.index = [...APP_INDEX_PRIVILEGES]; + } + + return res.ok({ body: privilegesResult }); + }) + ); +} + +const extractMissingPrivileges = (privilegesObject: { [key: string]: boolean } = {}): string[] => + Object.keys(privilegesObject).reduce((privileges: string[], privilegeName: string): string[] => { + if (!privilegesObject[privilegeName]) { + privileges.push(privilegeName); + } + return privileges; + }, []); diff --git a/x-pack/plugins/transform/server/routes/api/schema.ts b/x-pack/plugins/transform/server/routes/api/schema.ts new file mode 100644 index 0000000000000..0b994406d324d --- /dev/null +++ b/x-pack/plugins/transform/server/routes/api/schema.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { schema } from '@kbn/config-schema'; + +export const schemaTransformId = { + params: schema.object({ + transformId: schema.string(), + }), +}; + +export interface SchemaTransformId { + transformId: string; +} diff --git a/x-pack/plugins/transform/server/routes/api/transforms.ts b/x-pack/plugins/transform/server/routes/api/transforms.ts new file mode 100644 index 0000000000000..7aaae1f1c7039 --- /dev/null +++ b/x-pack/plugins/transform/server/routes/api/transforms.ts @@ -0,0 +1,360 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { schema } from '@kbn/config-schema'; + +import { RequestHandler } from 'kibana/server'; +import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; +import { wrapEsError } from '../../../../../legacy/server/lib/create_router/error_wrappers'; + +import { TRANSFORM_STATE } from '../../../../../legacy/plugins/transform/public/app/common'; +import { + TransformEndpointRequest, + TransformEndpointResult, +} from '../../../../../legacy/plugins/transform/public/app/hooks/use_api_types'; +import { TransformId } from '../../../../../legacy/plugins/transform/public/app/common/transform'; + +import { RouteDependencies } from '../../types'; + +import { addBasePath } from '../index'; + +import { isRequestTimeout, fillResultsWithTimeouts, wrapError } from './error_utils'; +import { schemaTransformId, SchemaTransformId } from './schema'; +import { registerTransformsAuditMessagesRoutes } from './transforms_audit_messages'; + +enum TRANSFORM_ACTIONS { + STOP = 'stop', + START = 'start', + DELETE = 'delete', +} + +interface StopOptions { + transformId: TransformId; + force: boolean; + waitForCompletion?: boolean; +} + +export function registerTransformsRoutes(routeDependencies: RouteDependencies) { + const { router, license } = routeDependencies; + router.get( + { path: addBasePath('transforms'), validate: false }, + license.guardApiRoute(async (ctx, req, res) => { + const options = {}; + try { + const transforms = await getTransforms( + options, + ctx.transform!.dataClient.callAsCurrentUser + ); + return res.ok({ body: transforms }); + } catch (e) { + return res.customError(wrapError(wrapEsError(e))); + } + }) + ); + router.get( + { + path: addBasePath('transforms/{transformId}'), + validate: schemaTransformId, + }, + license.guardApiRoute(async (ctx, req, res) => { + const { transformId } = req.params as SchemaTransformId; + const options = { + ...(transformId !== undefined ? { transformId } : {}), + }; + try { + const transforms = await getTransforms( + options, + ctx.transform!.dataClient.callAsCurrentUser + ); + return res.ok({ body: transforms }); + } catch (e) { + return res.customError(wrapError(wrapEsError(e))); + } + }) + ); + router.get( + { path: addBasePath('transforms/_stats'), validate: false }, + license.guardApiRoute(async (ctx, req, res) => { + const options = {}; + try { + const stats = await ctx.transform!.dataClient.callAsCurrentUser( + 'transform.getTransformsStats', + options + ); + return res.ok({ body: stats }); + } catch (e) { + return res.customError(wrapError(wrapEsError(e))); + } + }) + ); + router.get( + { + path: addBasePath('transforms/{transformId}/_stats'), + validate: schemaTransformId, + }, + license.guardApiRoute(async (ctx, req, res) => { + const { transformId } = req.params as SchemaTransformId; + const options = { + ...(transformId !== undefined ? { transformId } : {}), + }; + try { + const stats = await ctx.transform!.dataClient.callAsCurrentUser( + 'transform.getTransformsStats', + options + ); + return res.ok({ body: stats }); + } catch (e) { + return res.customError(wrapError(wrapEsError(e))); + } + }) + ); + registerTransformsAuditMessagesRoutes(routeDependencies); + router.put( + { + path: addBasePath('transforms/{transformId}'), + validate: { + ...schemaTransformId, + body: schema.maybe(schema.any()), + }, + }, + license.guardApiRoute(async (ctx, req, res) => { + const { transformId } = req.params as SchemaTransformId; + + const response: { + transformsCreated: Array<{ transform: string }>; + errors: any[]; + } = { + transformsCreated: [], + errors: [], + }; + + await ctx + .transform!.dataClient.callAsCurrentUser('transform.createTransform', { + body: req.body, + transformId, + }) + .then(() => response.transformsCreated.push({ transform: transformId })) + .catch(e => + response.errors.push({ + id: transformId, + error: wrapEsError(e), + }) + ); + + return res.ok({ body: response }); + }) + ); + router.post( + { + path: addBasePath('delete_transforms'), + validate: { + body: schema.maybe(schema.any()), + }, + }, + license.guardApiRoute(async (ctx, req, res) => { + const transformsInfo = req.body as TransformEndpointRequest[]; + + try { + return res.ok({ + body: await deleteTransforms(transformsInfo, ctx.transform!.dataClient.callAsCurrentUser), + }); + } catch (e) { + return res.customError(wrapError(wrapEsError(e))); + } + }) + ); + router.post( + { + path: addBasePath('transforms/_preview'), + validate: { + body: schema.maybe(schema.any()), + }, + }, + license.guardApiRoute(previewTransformHandler) + ); + router.post( + { + path: addBasePath('start_transforms'), + validate: { + body: schema.maybe(schema.any()), + }, + }, + license.guardApiRoute(startTransformsHandler) + ); + router.post( + { + path: addBasePath('stop_transforms'), + validate: { + body: schema.maybe(schema.any()), + }, + }, + license.guardApiRoute(stopTransformsHandler) + ); + router.post( + { + path: addBasePath('es_search'), + validate: { + body: schema.maybe(schema.any()), + }, + }, + license.guardApiRoute(async (ctx, req, res) => { + try { + return res.ok({ + body: await ctx.transform!.dataClient.callAsCurrentUser('search', req.body), + }); + } catch (e) { + return res.customError(wrapError(wrapEsError(e))); + } + }) + ); +} + +const getTransforms = async (options: { transformId?: string }, callAsCurrentUser: CallCluster) => { + return await callAsCurrentUser('transform.getTransforms', options); +}; + +async function deleteTransforms( + transformsInfo: TransformEndpointRequest[], + callAsCurrentUser: CallCluster +) { + const results: TransformEndpointResult = {}; + + for (const transformInfo of transformsInfo) { + const transformId = transformInfo.id; + try { + if (transformInfo.state === TRANSFORM_STATE.FAILED) { + try { + await callAsCurrentUser('transform.stopTransform', { + transformId, + force: true, + waitForCompletion: true, + } as StopOptions); + } catch (e) { + if (isRequestTimeout(e)) { + return fillResultsWithTimeouts({ + results, + id: transformId, + items: transformsInfo, + action: TRANSFORM_ACTIONS.DELETE, + }); + } + } + } + + await callAsCurrentUser('transform.deleteTransform', { transformId }); + results[transformId] = { success: true }; + } catch (e) { + if (isRequestTimeout(e)) { + return fillResultsWithTimeouts({ + results, + id: transformInfo.id, + items: transformsInfo, + action: TRANSFORM_ACTIONS.DELETE, + }); + } + results[transformId] = { success: false, error: JSON.stringify(e) }; + } + } + return results; +} + +const previewTransformHandler: RequestHandler = async (ctx, req, res) => { + try { + return res.ok({ + body: await ctx.transform!.dataClient.callAsCurrentUser('transform.getTransformsPreview', { + body: req.body, + }), + }); + } catch (e) { + return res.customError(wrapError(wrapEsError(e))); + } +}; + +const startTransformsHandler: RequestHandler = async (ctx, req, res) => { + const { transformsInfo } = req.body as { + transformsInfo: TransformEndpointRequest[]; + }; + + try { + return res.ok({ + body: await startTransforms(transformsInfo, ctx.transform!.dataClient.callAsCurrentUser), + }); + } catch (e) { + return res.customError(wrapError(wrapEsError(e))); + } +}; + +async function startTransforms( + transformsInfo: TransformEndpointRequest[], + callAsCurrentUser: CallCluster +) { + const results: TransformEndpointResult = {}; + + for (const transformInfo of transformsInfo) { + const transformId = transformInfo.id; + try { + await callAsCurrentUser('transform.startTransform', { transformId } as SchemaTransformId); + results[transformId] = { success: true }; + } catch (e) { + if (isRequestTimeout(e)) { + return fillResultsWithTimeouts({ + results, + id: transformId, + items: transformsInfo, + action: TRANSFORM_ACTIONS.START, + }); + } + results[transformId] = { success: false, error: JSON.stringify(e) }; + } + } + return results; +} + +const stopTransformsHandler: RequestHandler = async (ctx, req, res) => { + const { transformsInfo } = req.body as { + transformsInfo: TransformEndpointRequest[]; + }; + + try { + return res.ok({ + body: await stopTransforms(transformsInfo, ctx.transform!.dataClient.callAsCurrentUser), + }); + } catch (e) { + return res.customError(wrapError(wrapEsError(e))); + } +}; + +async function stopTransforms( + transformsInfo: TransformEndpointRequest[], + callAsCurrentUser: CallCluster +) { + const results: TransformEndpointResult = {}; + + for (const transformInfo of transformsInfo) { + const transformId = transformInfo.id; + try { + await callAsCurrentUser('transform.stopTransform', { + transformId, + force: + transformInfo.state !== undefined + ? transformInfo.state === TRANSFORM_STATE.FAILED + : false, + waitForCompletion: true, + } as StopOptions); + results[transformId] = { success: true }; + } catch (e) { + if (isRequestTimeout(e)) { + return fillResultsWithTimeouts({ + results, + id: transformId, + items: transformsInfo, + action: TRANSFORM_ACTIONS.STOP, + }); + } + results[transformId] = { success: false, error: JSON.stringify(e) }; + } + } + return results; +} diff --git a/x-pack/plugins/transform/server/routes/api/transforms_audit_messages.ts b/x-pack/plugins/transform/server/routes/api/transforms_audit_messages.ts new file mode 100644 index 0000000000000..422fdec7ab77e --- /dev/null +++ b/x-pack/plugins/transform/server/routes/api/transforms_audit_messages.ts @@ -0,0 +1,91 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { AuditMessage } from '../../../../../legacy/plugins/transform/common/types/messages'; +import { wrapEsError } from '../../../../../legacy/server/lib/create_router/error_wrappers'; + +import { RouteDependencies } from '../../types'; + +import { addBasePath } from '../index'; + +import { wrapError } from './error_utils'; +import { schemaTransformId, SchemaTransformId } from './schema'; + +const ML_DF_NOTIFICATION_INDEX_PATTERN = '.transform-notifications-read'; +const SIZE = 500; + +interface BoolQuery { + bool: { [key: string]: any }; +} + +export function registerTransformsAuditMessagesRoutes({ router, license }: RouteDependencies) { + router.get( + { path: addBasePath('transforms/{transformId}/messages'), validate: schemaTransformId }, + license.guardApiRoute(async (ctx, req, res) => { + const { transformId } = req.params as SchemaTransformId; + + // search for audit messages, + // transformId is optional. without it, all transforms will be listed. + const query: BoolQuery = { + bool: { + filter: [ + { + bool: { + must_not: { + term: { + level: 'activity', + }, + }, + }, + }, + ], + }, + }; + + // if no transformId specified, load all of the messages + if (transformId !== undefined) { + query.bool.filter.push({ + bool: { + should: [ + { + term: { + transform_id: '', // catch system messages + }, + }, + { + term: { + transform_id: transformId, // messages for specified transformId + }, + }, + ], + }, + }); + } + + try { + const resp = await ctx.transform!.dataClient.callAsCurrentUser('search', { + index: ML_DF_NOTIFICATION_INDEX_PATTERN, + ignore_unavailable: true, + rest_total_hits_as_int: true, + size: SIZE, + body: { + sort: [{ timestamp: { order: 'desc' } }, { transform_id: { order: 'asc' } }], + query, + }, + }); + + let messages = []; + if (resp.hits.total !== 0) { + messages = resp.hits.hits.map((hit: AuditMessage) => hit._source); + messages.reverse(); + } + return res.ok({ body: messages }); + } catch (e) { + return res.customError(wrapError(wrapEsError(e))); + } + }) + ); +} diff --git a/x-pack/plugins/transform/server/routes/index.ts b/x-pack/plugins/transform/server/routes/index.ts new file mode 100644 index 0000000000000..953490920cbcb --- /dev/null +++ b/x-pack/plugins/transform/server/routes/index.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { RouteDependencies } from '../types'; + +import { registerPrivilegesRoute } from './api/privileges'; +import { registerTransformsRoutes } from './api/transforms'; + +import { API_BASE_PATH } from '../../../../legacy/plugins/transform/common/constants'; + +export const addBasePath = (uri: string): string => `${API_BASE_PATH}${uri}`; + +export class ApiRoutes { + setup(dependencies: RouteDependencies) { + registerPrivilegesRoute(dependencies); + registerTransformsRoutes(dependencies); + } + + start() {} + stop() {} +} diff --git a/x-pack/plugins/transform/server/services/index.ts b/x-pack/plugins/transform/server/services/index.ts new file mode 100644 index 0000000000000..b7a45e59549eb --- /dev/null +++ b/x-pack/plugins/transform/server/services/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { License } from './license'; diff --git a/x-pack/plugins/transform/server/services/license.ts b/x-pack/plugins/transform/server/services/license.ts new file mode 100644 index 0000000000000..93346160c6f44 --- /dev/null +++ b/x-pack/plugins/transform/server/services/license.ts @@ -0,0 +1,91 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { Logger } from 'src/core/server'; +import { + IKibanaResponse, + KibanaRequest, + KibanaResponseFactory, + RequestHandler, + RequestHandlerContext, +} from 'kibana/server'; + +import { LicensingPluginSetup, LicenseType, LICENSE_CHECK_STATE } from '../../../licensing/server'; + +export interface LicenseStatus { + isValid: boolean; + isSecurityEnabled: boolean; + message?: string; +} + +interface SetupSettings { + pluginId: string; + minimumLicenseType: LicenseType; + defaultErrorMessage: string; +} + +export class License { + private licenseStatus: LicenseStatus = { + isValid: false, + isSecurityEnabled: false, + message: 'Invalid License', + }; + + setup( + { pluginId, minimumLicenseType, defaultErrorMessage }: SetupSettings, + { licensing, logger }: { licensing: LicensingPluginSetup; logger: Logger } + ) { + licensing.license$.subscribe(license => { + const { state, message } = license.check(pluginId, minimumLicenseType); + const hasRequiredLicense = state === LICENSE_CHECK_STATE.Valid; + + const securityFeature = license.getFeature('security'); + const isSecurityEnabled = + securityFeature !== undefined && + securityFeature.isAvailable === true && + securityFeature.isEnabled === true; + + if (hasRequiredLicense) { + this.licenseStatus = { isValid: true, isSecurityEnabled }; + } else { + this.licenseStatus = { + isValid: false, + isSecurityEnabled, + message: message || defaultErrorMessage, + }; + if (message) { + logger.info(message); + } + } + }); + } + + guardApiRoute(handler: RequestHandler) { + const license = this; + + return function licenseCheck( + ctx: RequestHandlerContext, + request: KibanaRequest, + response: KibanaResponseFactory + ): IKibanaResponse | Promise> { + const licenseStatus = license.getStatus(); + + if (!licenseStatus.isValid) { + return response.customError({ + body: { + message: licenseStatus.message || '', + }, + statusCode: 403, + }); + } + + return handler(ctx, request, response); + }; + } + + getStatus() { + return this.licenseStatus; + } +} diff --git a/x-pack/plugins/transform/server/types.ts b/x-pack/plugins/transform/server/types.ts new file mode 100644 index 0000000000000..5fcc23a6d9f48 --- /dev/null +++ b/x-pack/plugins/transform/server/types.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IRouter } from 'src/core/server'; +import { LicensingPluginSetup } from '../../licensing/server'; +import { License } from './services'; + +export interface Dependencies { + licensing: LicensingPluginSetup; +} + +export interface RouteDependencies { + router: IRouter; + license: License; +} diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 2429ad5b4f03c..0b4e652dc1132 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5734,7 +5734,6 @@ "xpack.graph.listing.table.entityNamePlural": "グラフ", "xpack.graph.listing.table.titleColumnName": "タイトル", "xpack.graph.loadWorkspace.missingIndexPatternErrorMessage": "インデックスパターンが見つかりませんでした", - "xpack.graph.missingWorkspaceErrorMessage": "ワークスペースがありません", "xpack.graph.newGraphTitle": "保存されていないグラフ", "xpack.graph.noDataSourceNotificationMessageText": "データソースが見つかりませんでした。{managementIndexPatternsLink} に移動して Elasticsearch インデックスのインデックスパターンを作成してください。", "xpack.graph.noDataSourceNotificationMessageText.managementIndexPatternLinkText": "管理>インデックスパターン", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index cf3a7d1c7a0ba..ebb982e9940de 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5734,7 +5734,6 @@ "xpack.graph.listing.table.entityNamePlural": "图表", "xpack.graph.listing.table.titleColumnName": "标题", "xpack.graph.loadWorkspace.missingIndexPatternErrorMessage": "未找到索引模式", - "xpack.graph.missingWorkspaceErrorMessage": "缺少工作空间", "xpack.graph.newGraphTitle": "未保存图表", "xpack.graph.noDataSourceNotificationMessageText": "未找到数据源。前往 {managementIndexPatternsLink},为您的 Elasticsearch 索引创建索引模式。", "xpack.graph.noDataSourceNotificationMessageText.managementIndexPatternLinkText": "管理 > 索引模式", diff --git a/x-pack/test/api_integration/apis/endpoint/alerts.ts b/x-pack/test/api_integration/apis/endpoint/alerts.ts index c08d17e96b180..45ae2b5438e18 100644 --- a/x-pack/test/api_integration/apis/endpoint/alerts.ts +++ b/x-pack/test/api_integration/apis/endpoint/alerts.ts @@ -9,15 +9,30 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + + const nextPrevPrefixDateRange = "date_range=(from:'2018-01-10T00:00:00.000Z',to:now)"; + const nextPrevPrefixSort = 'sort=@timestamp'; + const nextPrevPrefixOrder = 'order=desc'; + const nextPrevPrefixPageSize = 'page_size=10'; + const nextPrevPrefix = `${nextPrevPrefixDateRange}&${nextPrevPrefixSort}&${nextPrevPrefixOrder}&${nextPrevPrefixPageSize}`; + describe('test alerts api', () => { describe('Tests for alerts API', () => { before(() => esArchiver.load('endpoint/alerts/api_feature')); after(() => esArchiver.unload('endpoint/alerts/api_feature')); + + it('alerts api should not support post', async () => { + await supertest + .post('/api/endpoint/alerts') + .send({}) + .set('kbn-xsrf', 'xxx') + .expect(404); + }); + it('alerts api should return one entry for each alert with default paging', async () => { const { body } = await supertest - .post('/api/endpoint/alerts') + .get('/api/endpoint/alerts') .set('kbn-xsrf', 'xxx') - .send({}) .expect(200); expect(body.total).to.eql(132); expect(body.alerts.length).to.eql(10); @@ -28,12 +43,8 @@ export default function({ getService }: FtrProviderContext) { it('alerts api should return page based on paging properties passed.', async () => { const { body } = await supertest - .post('/api/endpoint/alerts') + .get('/api/endpoint/alerts?page_size=1&page_index=1') .set('kbn-xsrf', 'xxx') - .send({ - page_size: 1, - page_index: 1, - }) .expect(200); expect(body.total).to.eql(132); expect(body.alerts.length).to.eql(1); @@ -61,6 +72,127 @@ export default function({ getService }: FtrProviderContext) { .expect(400); expect(body.message).to.contain('Value is [0] but it must be equal to or greater than [1]'); }); + + it('alerts api should return links to the next and previous pages using cursor-based pagination', async () => { + const { body } = await supertest + .get('/api/endpoint/alerts?page_index=0') + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(body.alerts.length).to.eql(10); + const lastTimestampFirstPage = body.alerts[9]['@timestamp']; + const lastEventIdFirstPage = body.alerts[9].event.id; + expect(body.next).to.eql( + `/api/endpoint/alerts?${nextPrevPrefix}&after=${lastTimestampFirstPage}&after=${lastEventIdFirstPage}` + ); + }); + + it('alerts api should return data using `next` link', async () => { + const { body } = await supertest + .get( + `/api/endpoint/alerts?${nextPrevPrefix}&after=1542789412000&after=c710bf2d-8686-4038-a2a1-43bdecc06b2a` + ) + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(body.alerts.length).to.eql(10); + const firstTimestampNextPage = body.alerts[0]['@timestamp']; + const firstEventIdNextPage = body.alerts[0].event.id; + expect(body.prev).to.eql( + `/api/endpoint/alerts?${nextPrevPrefix}&before=${firstTimestampNextPage}&before=${firstEventIdNextPage}` + ); + }); + + it('alerts api should return data using `prev` link', async () => { + const { body } = await supertest + .get( + `/api/endpoint/alerts?${nextPrevPrefix}&before=1542789412000&before=823d814d-fa0c-4e53-a94c-f6b296bb965b` + ) + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(body.alerts.length).to.eql(10); + }); + + it('alerts api should return no results when `before` is requested past beginning of first page', async () => { + const { body } = await supertest + .get( + `/api/endpoint/alerts?${nextPrevPrefix}&before=1542789473000&before=ffae628e-6236-45ce-ba24-7351e0af219e` + ) + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(body.alerts.length).to.eql(0); + }); + + it('alerts api should return no results when `after` is requested past end of last page', async () => { + const { body } = await supertest + .get( + `/api/endpoint/alerts?${nextPrevPrefix}&after=1542341895000&after=01911945-48aa-478e-9712-f49c92a15f20` + ) + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(body.alerts.length).to.eql(0); + }); + + it('alerts api should return 400 when using `before` by custom sort parameter', async () => { + await supertest + .get( + `/api/endpoint/alerts?${nextPrevPrefixDateRange}&${nextPrevPrefixPageSize}&${nextPrevPrefixOrder}&sort=thread.id&before=2180&before=8362fcde-0b10-476f-97a8-8d6a43865226` + ) + .set('kbn-xsrf', 'xxx') + .expect(400); + }); + + it('alerts api should return data using `after` by custom sort parameter', async () => { + const { body } = await supertest + .get( + `/api/endpoint/alerts?${nextPrevPrefixDateRange}&${nextPrevPrefixPageSize}&${nextPrevPrefixOrder}&sort=thread.id&after=2180&after=8362fcde-0b10-476f-97a8-8d6a43865226` + ) + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(body.alerts.length).to.eql(10); + expect(body.alerts[0].thread.id).to.eql(1912); + }); + + it('alerts api should filter results of alert data using rison-encoded filters', async () => { + const { body } = await supertest + .get( + `/api/endpoint/alerts?filters=!((%27%24state%27%3A(store%3AappState)%2Cmeta%3A(alias%3A!n%2Cdisabled%3A!f%2Ckey%3Ahost.hostname%2Cnegate%3A!f%2Cparams%3A(query%3AHD-m3z-4c803698)%2Ctype%3Aphrase)%2Cquery%3A(match_phrase%3A(host.hostname%3AHD-m3z-4c803698))))` + ) + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(body.total).to.eql(72); + expect(body.alerts.length).to.eql(10); + expect(body.request_page_size).to.eql(10); + expect(body.request_page_index).to.eql(0); + expect(body.result_from_index).to.eql(0); + }); + + it('alerts api should filter results of alert data using KQL', async () => { + const { body } = await supertest + .get(`/api/endpoint/alerts?query=agent.id:c89dc040-2350-4d59-baea-9ff2e369136f`) + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(body.total).to.eql(72); + expect(body.alerts.length).to.eql(10); + expect(body.request_page_size).to.eql(10); + expect(body.request_page_index).to.eql(0); + expect(body.result_from_index).to.eql(0); + }); + + it('alerts api should return alert details by id', async () => { + const { body } = await supertest + .get('/api/endpoint/alerts/YjUYMHABAJk0XnHd6bqU') + .set('kbn-xsrf', 'xxx') + .expect(200); + expect(body.id).to.eql('YjUYMHABAJk0XnHd6bqU'); + expect(body.next).to.eql(null); // last alert, no more beyond this + expect(body.prev).to.eql('/api/endpoint/alerts/XjUYMHABAJk0XnHd6boX'); + }); + + it('alerts api should return 404 when alert is not found', async () => { + await supertest + .get('/api/endpoint/alerts/does-not-exist') + .set('kbn-xsrf', 'xxx') + .expect(404); + }); }); }); } diff --git a/x-pack/test/api_integration/apis/infra/waffle.ts b/x-pack/test/api_integration/apis/infra/waffle.ts index 3413fc283556c..26d8c9d265a6a 100644 --- a/x-pack/test/api_integration/apis/infra/waffle.ts +++ b/x-pack/test/api_integration/apis/infra/waffle.ts @@ -192,9 +192,9 @@ export default function({ getService }: FtrProviderContext) { expect(firstNode).to.have.property('metric'); expect(firstNode.metric).to.eql({ name: 'cpu', - value: 0.009285714285714286, - max: 0.009285714285714286, - avg: 0.0015476190476190477, + value: 0.0032, + max: 0.0038333333333333336, + avg: 0.0027944444444444444, }); } }); @@ -231,9 +231,9 @@ export default function({ getService }: FtrProviderContext) { expect(firstNode).to.have.property('metric'); expect(firstNode.metric).to.eql({ name: 'custom', - value: 0.0041964285714285714, - max: 0.0041964285714285714, - avg: 0.0006994047619047619, + value: 0.0016, + max: 0.0018333333333333333, + avg: 0.0013666666666666669, }); } }); @@ -320,9 +320,9 @@ export default function({ getService }: FtrProviderContext) { expect(firstNode).to.have.property('metric'); expect(firstNode.metric).to.eql({ name: 'cpu', - value: 0.009285714285714286, - max: 0.009285714285714286, - avg: 0.0015476190476190477, + value: 0.0032, + max: 0.0038333333333333336, + avg: 0.0027944444444444444, }); const secondNode = nodes[1]; expect(secondNode).to.have.property('path'); @@ -332,9 +332,9 @@ export default function({ getService }: FtrProviderContext) { expect(secondNode).to.have.property('metric'); expect(secondNode.metric).to.eql({ name: 'cpu', - value: 0.009285714285714286, - max: 0.009285714285714286, - avg: 0.0015476190476190477, + value: 0.0032, + max: 0.0038333333333333336, + avg: 0.0027944444444444444, }); } }); diff --git a/x-pack/test/api_integration/config.js b/x-pack/test/api_integration/config.js index 6e35a6f31d79b..70a7763bca6c5 100644 --- a/x-pack/test/api_integration/config.js +++ b/x-pack/test/api_integration/config.js @@ -26,6 +26,7 @@ export async function getApiIntegrationConfig({ readConfigFile }) { '--xpack.security.session.idleTimeout=3600000', // 1 hour '--optimize.enabled=false', '--xpack.endpoint.enabled=true', + '--xpack.endpoint.alertResultListDefaultDateRange.from=2018-01-10T00:00:00.000Z', ], }, esTestCluster: { diff --git a/x-pack/test/functional/apps/endpoint/header_nav.ts b/x-pack/test/functional/apps/endpoint/header_nav.ts new file mode 100644 index 0000000000000..2368ad077cf64 --- /dev/null +++ b/x-pack/test/functional/apps/endpoint/header_nav.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const pageObjects = getPageObjects(['common', 'endpoint']); + const testSubjects = getService('testSubjects'); + + describe('Header nav', function() { + this.tags('ciGroup7'); + before(async () => { + await pageObjects.common.navigateToApp('endpoint'); + }); + + it('renders the tabs when the app loads', async () => { + const homeTabText = await testSubjects.getVisibleText('homeEndpointTab'); + const managementTabText = await testSubjects.getVisibleText('managementEndpointTab'); + const alertsTabText = await testSubjects.getVisibleText('alertsEndpointTab'); + const policiesTabText = await testSubjects.getVisibleText('policiesEndpointTab'); + + expect(homeTabText.trim()).to.be('Home'); + expect(managementTabText.trim()).to.be('Management'); + expect(alertsTabText.trim()).to.be('Alerts'); + expect(policiesTabText.trim()).to.be('Policies'); + }); + + it('renders the management page when the Management tab is selected', async () => { + await (await testSubjects.find('managementEndpointTab')).click(); + await testSubjects.existOrFail('managementViewTitle'); + }); + + it('renders the alerts page when the Alerts tab is selected', async () => { + await (await testSubjects.find('alertsEndpointTab')).click(); + await testSubjects.existOrFail('alertListPage'); + }); + + it('renders the policy page when Policy tab is selected', async () => { + await (await testSubjects.find('policiesEndpointTab')).click(); + await testSubjects.existOrFail('policyViewTitle'); + }); + + it('renders the home page when Home tab is selected after selecting another tab', async () => { + await (await testSubjects.find('managementEndpointTab')).click(); + await testSubjects.existOrFail('managementViewTitle'); + + await (await testSubjects.find('homeEndpointTab')).click(); + await testSubjects.existOrFail('welcomeTitle'); + }); + }); +}; diff --git a/x-pack/test/functional/apps/endpoint/index.ts b/x-pack/test/functional/apps/endpoint/index.ts index 818c040f824d9..0c9179c23ea6c 100644 --- a/x-pack/test/functional/apps/endpoint/index.ts +++ b/x-pack/test/functional/apps/endpoint/index.ts @@ -11,6 +11,7 @@ export default function({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./landing_page')); + loadTestFile(require.resolve('./header_nav')); loadTestFile(require.resolve('./management')); loadTestFile(require.resolve('./policy_list')); loadTestFile(require.resolve('./alert_list')); diff --git a/x-pack/test/functional/apps/endpoint/management.ts b/x-pack/test/functional/apps/endpoint/management.ts index 500185182f0d8..4925fa7678ab0 100644 --- a/x-pack/test/functional/apps/endpoint/management.ts +++ b/x-pack/test/functional/apps/endpoint/management.ts @@ -25,19 +25,61 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('displays table data', async () => { - const data = await pageObjects.endpoint.getManagementTableData(); - [ - 'Hostnamecadmann-4.example.com', - 'PolicyPolicy Name', - 'Policy StatusPolicy Status', - 'Alerts0', - 'Operating Systemwindows 10.0', - 'IP Address10.192.213.130, 10.70.28.129', - 'Sensor Versionversion', - 'Last Activexxxx', - ].forEach((cellValue, index) => { - expect(data[1][index]).to.equal(cellValue); - }); + const expectedData = [ + [ + 'Hostname', + 'Policy', + 'Policy Status', + 'Alerts', + 'Operating System', + 'IP Address', + 'Sensor Version', + 'Last Active', + ], + [ + 'cadmann-4.example.com', + 'Policy Name', + 'Policy Status', + '0', + 'windows 10.0', + '10.192.213.130, 10.70.28.129', + 'version', + 'xxxx', + ], + [ + 'thurlow-9.example.com', + 'Policy Name', + 'Policy Status', + '0', + 'windows 10.0', + '10.46.229.234', + 'version', + 'xxxx', + ], + [ + 'rezzani-7.example.com', + 'Policy Name', + 'Policy Status', + '0', + 'windows 10.0', + '10.101.149.26, 2606:a000:ffc0:39:11ef:37b9:3371:578c', + 'version', + 'xxxx', + ], + ]; + const tableData = await pageObjects.endpoint.getEndpointAppTableData('managementListTable'); + expect(tableData).to.eql(expectedData); + }); + + it('displays no items found', async () => { + // clear out the data and reload the page + await esArchiver.unload('endpoint/metadata/api_feature'); + await pageObjects.common.navigateToUrlWithBrowserHistory('endpoint', '/management'); + // get the table data and verify no entries appear + const tableData = await pageObjects.endpoint.getEndpointAppTableData('managementListTable'); + expect(tableData[1][0]).to.equal('No items found'); + // reload the data so the other tests continue to pass + await esArchiver.load('endpoint/metadata/api_feature'); }); after(async () => { diff --git a/x-pack/test/functional/apps/maps/discover.js b/x-pack/test/functional/apps/maps/discover.js new file mode 100644 index 0000000000000..ce33596476755 --- /dev/null +++ b/x-pack/test/functional/apps/maps/discover.js @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +export default function({ getService, getPageObjects }) { + const queryBar = getService('queryBar'); + const PageObjects = getPageObjects(['common', 'discover', 'header', 'maps', 'timePicker']); + + describe('discover visualize button', () => { + beforeEach(async () => { + await PageObjects.common.navigateToApp('discover'); + }); + + it('should link geo_shape fields to Maps application', async () => { + await PageObjects.discover.selectIndexPattern('geo_shapes*'); + await PageObjects.discover.clickFieldListItem('geometry'); + await PageObjects.discover.clickFieldListItemVisualize('geometry'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.maps.waitForLayersToLoad(); + const doesLayerExist = await PageObjects.maps.doesLayerExist('geo_shapes*'); + expect(doesLayerExist).to.equal(true); + const hits = await PageObjects.maps.getHits(); + expect(hits).to.equal('4'); + }); + + it('should link geo_point fields to Maps application with time and query context', async () => { + await PageObjects.discover.selectIndexPattern('logstash-*'); + await PageObjects.timePicker.setAbsoluteRange( + 'Sep 22, 2015 @ 00:00:00.000', + 'Sep 22, 2015 @ 04:00:00.000' + ); + await queryBar.setQuery('machine.os.raw : "ios"'); + await queryBar.submitQuery(); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await PageObjects.discover.clickFieldListItem('geo.coordinates'); + await PageObjects.discover.clickFieldListItemVisualize('geo.coordinates'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.maps.waitForLayersToLoad(); + const doesLayerExist = await PageObjects.maps.doesLayerExist('logstash-*'); + expect(doesLayerExist).to.equal(true); + const hits = await PageObjects.maps.getHits(); + expect(hits).to.equal('7'); + }); + }); +} diff --git a/x-pack/test/functional/apps/maps/index.js b/x-pack/test/functional/apps/maps/index.js index 0545fcd1b6453..e8a9d7ba54bc5 100644 --- a/x-pack/test/functional/apps/maps/index.js +++ b/x-pack/test/functional/apps/maps/index.js @@ -45,6 +45,7 @@ export default function({ loadTestFile, getService }) { loadTestFile(require.resolve('./import_geojson')); loadTestFile(require.resolve('./layer_errors')); loadTestFile(require.resolve('./embeddable')); + loadTestFile(require.resolve('./discover')); }); }); } diff --git a/x-pack/test/functional/apps/transform/creation_index_pattern.ts b/x-pack/test/functional/apps/transform/creation_index_pattern.ts index 6e35b0c1a81ca..5b54bfdafdbdb 100644 --- a/x-pack/test/functional/apps/transform/creation_index_pattern.ts +++ b/x-pack/test/functional/apps/transform/creation_index_pattern.ts @@ -57,6 +57,28 @@ export default function({ getService }: FtrProviderContext) { return `user-${this.transformId}`; }, expected: { + pivotAdvancedEditorValue: { + group_by: { + 'category.keyword': { + terms: { + field: 'category.keyword', + }, + }, + order_date: { + date_histogram: { + field: 'order_date', + calendar_interval: '1m', + }, + }, + }, + aggregations: { + 'products.base_price.avg': { + avg: { + field: 'products.base_price', + }, + }, + }, + }, pivotPreview: { column: 0, values: [`Men's Accessories`], @@ -152,6 +174,13 @@ export default function({ getService }: FtrProviderContext) { await transform.wizard.assertAdvancedPivotEditorSwitchCheckState(false); }); + it('displays the advanced configuration', async () => { + await transform.wizard.enabledAdvancedPivotEditor(); + await transform.wizard.assertAdvancedPivotEditorContent( + testData.expected.pivotAdvancedEditorValue + ); + }); + it('loads the pivot preview', async () => { await transform.wizard.assertPivotPreviewLoaded(); }); diff --git a/x-pack/test/functional/es_archives/endpoint/alerts/api_feature/data.json.gz b/x-pack/test/functional/es_archives/endpoint/alerts/api_feature/data.json.gz index 8d3c9fe5fd233..dd8f719305bb9 100644 Binary files a/x-pack/test/functional/es_archives/endpoint/alerts/api_feature/data.json.gz and b/x-pack/test/functional/es_archives/endpoint/alerts/api_feature/data.json.gz differ diff --git a/x-pack/test/functional/page_objects/endpoint_page.ts b/x-pack/test/functional/page_objects/endpoint_page.ts index 54f537dd0e8c3..185b95b00527d 100644 --- a/x-pack/test/functional/page_objects/endpoint_page.ts +++ b/x-pack/test/functional/page_objects/endpoint_page.ts @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ +import { WebElementWrapper } from 'test/functional/services/lib/web_element_wrapper'; import { FtrProviderContext } from '../ftr_provider_context'; export function EndpointPageProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); - const table = getService('table'); return { /** @@ -34,8 +34,29 @@ export function EndpointPageProvider({ getService }: FtrProviderContext) { return await testSubjects.getVisibleText('welcomeTitle'); }, - async getManagementTableData() { - return await table.getDataFromTestSubj('managementListTable'); + /** + * Finds a table and returns the data in a nested array with row 0 is the headers if they exist. + * It uses euiTableCellContent to avoid poluting the array data with the euiTableRowCell__mobileHeader data. + * @param dataTestSubj + * @returns Promise + */ + async getEndpointAppTableData(dataTestSubj: string) { + await testSubjects.exists(dataTestSubj); + const hostTable: WebElementWrapper = await testSubjects.find(dataTestSubj); + const $ = await hostTable.parseDomContent(); + return $('tr') + .toArray() + .map(row => + $(row) + .find('.euiTableCellContent') + .toArray() + .map(cell => + $(cell) + .text() + .replace(/ /g, '') + .trim() + ) + ); }, }; } diff --git a/x-pack/test/functional/page_objects/uptime_page.ts b/x-pack/test/functional/page_objects/uptime_page.ts index a5bd4cc480287..f6e93cd14e497 100644 --- a/x-pack/test/functional/page_objects/uptime_page.ts +++ b/x-pack/test/functional/page_objects/uptime_page.ts @@ -57,7 +57,7 @@ export function UptimePageProvider({ getPageObjects, getService }: FtrProviderCo } public async pageUrlContains(value: string, expected: boolean = true) { - retry.try(async () => { + await retry.try(async () => { expect(await uptimeService.urlContains(value)).to.eql(expected); }); } diff --git a/x-pack/test/functional/services/transform_ui/wizard.ts b/x-pack/test/functional/services/transform_ui/wizard.ts index e823117ad7016..aca08f7083aa8 100644 --- a/x-pack/test/functional/services/transform_ui/wizard.ts +++ b/x-pack/test/functional/services/transform_ui/wizard.ts @@ -8,6 +8,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; export function TransformWizardProvider({ getService }: FtrProviderContext) { + const aceEditor = getService('aceEditor'); const testSubjects = getService('testSubjects'); const comboBox = getService('comboBox'); const retry = getService('retry'); @@ -273,6 +274,12 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { await this.assertAggregationEntryExists(index, expectedLabel); }, + async assertAdvancedPivotEditorContent(expectedValue: Record) { + const advancedEditorString = await aceEditor.getValue('transformAdvancedPivotEditor'); + const advancedEditorValue = JSON.parse(advancedEditorString); + expect(advancedEditorValue).to.eql(expectedValue); + }, + async assertAdvancedPivotEditorSwitchExists() { await testSubjects.existOrFail(`transformAdvancedPivotEditorSwitch`, { allowHidden: true }); }, @@ -287,6 +294,13 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { ); }, + async enabledAdvancedPivotEditor() { + await this.assertAdvancedPivotEditorSwitchCheckState(false); + await testSubjects.click('transformAdvancedPivotEditorSwitch'); + await this.assertAdvancedPivotEditorSwitchCheckState(true); + await testSubjects.existOrFail('transformAdvancedPivotEditor'); + }, + async assertTransformIdInputExists() { await testSubjects.existOrFail('transformIdInput'); }, diff --git a/yarn.lock b/yarn.lock index d45aa6d704afd..fc6d6eb2df796 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5715,6 +5715,11 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== +"@types/normalize-path@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/normalize-path/-/normalize-path-3.0.0.tgz#bb5c46cab77b93350b4cf8d7ff1153f47189ae31" + integrity sha512-Nd8y/5t/7CRakPYiyPzr/IAfYusy1FkcZYFEAcoMZkwpJv2n4Wm+olW+e7xBdHEXhOnWdG9ddbar0gqZWS4x5Q== + "@types/numeral@^0.0.25": version "0.0.25" resolved "https://registry.yarnpkg.com/@types/numeral/-/numeral-0.0.25.tgz#b6f55062827a4787fe4ab151cf3412a468e65271"