From a9a2832243b357f348b894c0eaca99f69ef0cd55 Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Fri, 26 Oct 2018 18:25:33 -0400 Subject: [PATCH] Secops structure code (#24652) * add basic structure for secops application * finalize skeleton for secops * fix type issue and hapi new version * remove route home, not needed for now * Add configuration + delete noise * prepend elastic license to generated file --- x-pack/.gitignore | 1 + x-pack/index.js | 2 + x-pack/package.json | 7 +- .../secops/common/graphql/introspection.json | 981 ++++++++++++++++++ .../secops/common/graphql/root/index.ts | 7 + .../secops/common/graphql/root/schema.gql.ts | 18 + .../secops/common/graphql/typed_resolvers.ts | 77 ++ x-pack/plugins/secops/common/graphql/types.ts | 163 +++ x-pack/plugins/secops/index.ts | 48 + x-pack/plugins/secops/package.json | 16 + x-pack/plugins/secops/public/app.ts | 7 + .../plugins/secops/public/apps/kibana_app.ts | 12 + .../plugins/secops/public/apps/start_app.tsx | 31 + .../plugins/secops/public/apps/testing_app.ts | 10 + .../plugins/secops/public/components/page.tsx | 26 + .../framework/kibana_framework_adapter.ts | 182 ++++ .../framework/testing_framework_adapter.ts | 29 + .../observable_api/kibana_observable_api.ts | 41 + .../public/lib/compose/kibana_compose.ts | 69 ++ .../public/lib/compose/testing_compose.ts | 59 ++ x-pack/plugins/secops/public/lib/lib.ts | 70 ++ x-pack/plugins/secops/public/pages/404.tsx | 10 + .../secops/public/pages/home/index.tsx | 16 + .../plugins/secops/public/register_feature.ts | 22 + x-pack/plugins/secops/public/routes.tsx | 26 + .../plugins/secops/scripts/combined_schema.ts | 16 + .../scripts/generate_types_from_graphql.js | 49 + x-pack/plugins/secops/scripts/gql_gen.json | 20 + x-pack/plugins/secops/server/graphql/index.ts | 10 + .../secops/server/graphql/sources/index.ts | 8 + .../server/graphql/sources/resolvers.ts | 56 + .../server/graphql/sources/schema.gql.ts | 45 + x-pack/plugins/secops/server/init_server.ts | 19 + x-pack/plugins/secops/server/kibana.index.ts | 39 + .../secops/server/lib/compose/kibana.ts | 32 + .../server/lib/configuration/adapter_types.ts | 9 + .../secops/server/lib/configuration/index.ts | 7 + .../inmemory_configuration_adapter.ts | 16 + .../kibana_configuration_adapter.test.ts | 40 + .../kibana_configuration_adapter.ts | 75 ++ .../server/lib/framework/adapter_types.ts | 30 + .../lib/framework/apollo_server_hapi.ts | 117 +++ .../secops/server/lib/framework/index.ts | 7 + .../lib/framework/kibana_framework_adapter.ts | 87 ++ .../server/lib/sources/adapter_types.ts | 21 + .../configuration_sources_adapter.test.ts | 111 ++ .../sources/configuration_sources_adapter.ts | 63 ++ .../secops/server/lib/sources/index.ts | 45 + x-pack/plugins/secops/server/lib/types.ts | 32 + x-pack/plugins/secops/yarn.lock | 37 + x-pack/yarn.lock | 518 ++++++--- 51 files changed, 3295 insertions(+), 144 deletions(-) create mode 100644 x-pack/plugins/secops/common/graphql/introspection.json create mode 100644 x-pack/plugins/secops/common/graphql/root/index.ts create mode 100644 x-pack/plugins/secops/common/graphql/root/schema.gql.ts create mode 100644 x-pack/plugins/secops/common/graphql/typed_resolvers.ts create mode 100644 x-pack/plugins/secops/common/graphql/types.ts create mode 100644 x-pack/plugins/secops/index.ts create mode 100644 x-pack/plugins/secops/package.json create mode 100644 x-pack/plugins/secops/public/app.ts create mode 100644 x-pack/plugins/secops/public/apps/kibana_app.ts create mode 100644 x-pack/plugins/secops/public/apps/start_app.tsx create mode 100644 x-pack/plugins/secops/public/apps/testing_app.ts create mode 100644 x-pack/plugins/secops/public/components/page.tsx create mode 100644 x-pack/plugins/secops/public/lib/adapters/framework/kibana_framework_adapter.ts create mode 100644 x-pack/plugins/secops/public/lib/adapters/framework/testing_framework_adapter.ts create mode 100644 x-pack/plugins/secops/public/lib/adapters/observable_api/kibana_observable_api.ts create mode 100644 x-pack/plugins/secops/public/lib/compose/kibana_compose.ts create mode 100644 x-pack/plugins/secops/public/lib/compose/testing_compose.ts create mode 100644 x-pack/plugins/secops/public/lib/lib.ts create mode 100644 x-pack/plugins/secops/public/pages/404.tsx create mode 100644 x-pack/plugins/secops/public/pages/home/index.tsx create mode 100644 x-pack/plugins/secops/public/register_feature.ts create mode 100644 x-pack/plugins/secops/public/routes.tsx create mode 100644 x-pack/plugins/secops/scripts/combined_schema.ts create mode 100644 x-pack/plugins/secops/scripts/generate_types_from_graphql.js create mode 100644 x-pack/plugins/secops/scripts/gql_gen.json create mode 100644 x-pack/plugins/secops/server/graphql/index.ts create mode 100644 x-pack/plugins/secops/server/graphql/sources/index.ts create mode 100644 x-pack/plugins/secops/server/graphql/sources/resolvers.ts create mode 100644 x-pack/plugins/secops/server/graphql/sources/schema.gql.ts create mode 100644 x-pack/plugins/secops/server/init_server.ts create mode 100644 x-pack/plugins/secops/server/kibana.index.ts create mode 100644 x-pack/plugins/secops/server/lib/compose/kibana.ts create mode 100644 x-pack/plugins/secops/server/lib/configuration/adapter_types.ts create mode 100644 x-pack/plugins/secops/server/lib/configuration/index.ts create mode 100644 x-pack/plugins/secops/server/lib/configuration/inmemory_configuration_adapter.ts create mode 100644 x-pack/plugins/secops/server/lib/configuration/kibana_configuration_adapter.test.ts create mode 100644 x-pack/plugins/secops/server/lib/configuration/kibana_configuration_adapter.ts create mode 100644 x-pack/plugins/secops/server/lib/framework/adapter_types.ts create mode 100644 x-pack/plugins/secops/server/lib/framework/apollo_server_hapi.ts create mode 100644 x-pack/plugins/secops/server/lib/framework/index.ts create mode 100644 x-pack/plugins/secops/server/lib/framework/kibana_framework_adapter.ts create mode 100644 x-pack/plugins/secops/server/lib/sources/adapter_types.ts create mode 100644 x-pack/plugins/secops/server/lib/sources/configuration_sources_adapter.test.ts create mode 100644 x-pack/plugins/secops/server/lib/sources/configuration_sources_adapter.ts create mode 100644 x-pack/plugins/secops/server/lib/sources/index.ts create mode 100644 x-pack/plugins/secops/server/lib/types.ts create mode 100644 x-pack/plugins/secops/yarn.lock diff --git a/x-pack/.gitignore b/x-pack/.gitignore index eb1aec466bbfa..f9d4d71829fa5 100644 --- a/x-pack/.gitignore +++ b/x-pack/.gitignore @@ -10,3 +10,4 @@ /.env /.kibana-plugin-helpers.dev.* !/plugins/infra/**/target +!/plugins/secops/**/target diff --git a/x-pack/index.js b/x-pack/index.js index 374cef7d26b66..5aa5eaa95c9d7 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -28,6 +28,7 @@ import { kueryAutocomplete } from './plugins/kuery_autocomplete'; import { canvas } from './plugins/canvas'; import { infra } from './plugins/infra'; import { rollup } from './plugins/rollup'; +import { secops } from './plugins/secops'; module.exports = function (kibana) { return [ @@ -55,5 +56,6 @@ module.exports = function (kibana) { kueryAutocomplete(kibana), infra(kibana), rollup(kibana), + secops(kibana), ]; }; diff --git a/x-pack/package.json b/x-pack/package.json index 636cad0bc31a4..30224ee04204e 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -54,6 +54,7 @@ "@types/react-dom": "^16.0.5", "@types/react-redux": "^6.0.6", "@types/react-router-dom": "^4.3.1", + "@types/recompose": "^0.26.0", "@types/reduce-reducers": "^0.1.3", "@types/sinon": "^5.0.1", "@types/supertest": "^2.0.5", @@ -82,9 +83,9 @@ "expect.js": "0.3.1", "fancy-log": "^1.3.2", "fetch-mock": "^5.13.1", - "graphql-code-generator": "^0.10.1", - "graphql-codegen-introspection-template": "^0.10.5", - "graphql-codegen-typescript-template": "^0.10.1", + "graphql-code-generator": "^0.12.6", + "graphql-codegen-introspection-template": "^0.12.6", + "graphql-codegen-typescript-template": "^0.12.6", "gulp": "3.9.1", "gulp-mocha": "^6.0.0", "gulp-multi-process": "^1.3.1", diff --git a/x-pack/plugins/secops/common/graphql/introspection.json b/x-pack/plugins/secops/common/graphql/introspection.json new file mode 100644 index 0000000000000..7a54bdae896c1 --- /dev/null +++ b/x-pack/plugins/secops/common/graphql/introspection.json @@ -0,0 +1,981 @@ +{ + "__schema": { + "queryType": { "name": "Query" }, + "mutationType": null, + "subscriptionType": null, + "types": [ + { + "kind": "OBJECT", + "name": "Query", + "description": "", + "fields": [ + { + "name": "source", + "description": "Get a security data source by id", + "args": [ + { + "name": "id", + "description": "The id of the source", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } + }, + "defaultValue": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "Source", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "allSources", + "description": "Get a list of all security data sources", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "Source", "ofType": null } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "ID", + "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Source", + "description": "", + "fields": [ + { + "name": "id", + "description": "The id of the source", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "configuration", + "description": "The raw configuration of the source", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "SourceConfiguration", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "SourceConfiguration", + "description": "A set of configuration options for a security data source", + "fields": [ + { + "name": "fields", + "description": "The field mapping to use for this source", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "SourceFields", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "SourceFields", + "description": "A mapping of semantic fields to their document counterparts", + "fields": [ + { + "name": "container", + "description": "The field to identify a container by", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "host", + "description": "The fields to identify a host by", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "message", + "description": "The fields that may contain the log event message. The first field found win.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "pod", + "description": "The field to identify a pod by", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "tiebreaker", + "description": "The field to use as a tiebreaker for log events that have identical timestamps", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "timestamp", + "description": "The field to use as a timestamp for metrics and logs", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "String", + "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Schema", + "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", + "fields": [ + { + "name": "types", + "description": "A list of all types supported by this server.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "queryType", + "description": "The type that query operations will be rooted at.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "mutationType", + "description": "If this server supports mutation, the type that mutation operations will be rooted at.", + "args": [], + "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subscriptionType", + "description": "If this server support subscription, the type that subscription operations will be rooted at.", + "args": [], + "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "directives", + "description": "A list of all directives supported by this server.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "__Directive", "ofType": null } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Type", + "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", + "fields": [ + { + "name": "kind", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "ENUM", "name": "__TypeKind", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": null, + "args": [], + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fields", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "__Field", "ofType": null } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "interfaces", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "possibleTypes", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "enumValues", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "__EnumValue", "ofType": null } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "inputFields", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ofType", + "description": null, + "args": [], + "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__TypeKind", + "description": "An enum describing what kind of type a given `__Type` is.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "SCALAR", + "description": "Indicates this type is a scalar.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "OBJECT", + "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INTERFACE", + "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "UNION", + "description": "Indicates this type is a union. `possibleTypes` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM", + "description": "Indicates this type is an enum. `enumValues` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_OBJECT", + "description": "Indicates this type is an input object. `inputFields` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "LIST", + "description": "Indicates this type is a list. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "NON_NULL", + "description": "Indicates this type is a non-null. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Boolean", + "description": "The `Boolean` scalar type represents `true` or `false`.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Field", + "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [], + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__InputValue", + "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "defaultValue", + "description": "A GraphQL-formatted string representing the default value for this input value.", + "args": [], + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__EnumValue", + "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [], + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Directive", + "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "locations", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "ENUM", "name": "__DirectiveLocation", "ofType": null } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "onOperation", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + }, + { + "name": "onFragment", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + }, + { + "name": "onField", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__DirectiveLocation", + "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "QUERY", + "description": "Location adjacent to a query operation.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "MUTATION", + "description": "Location adjacent to a mutation operation.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "SUBSCRIPTION", + "description": "Location adjacent to a subscription operation.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FIELD", + "description": "Location adjacent to a field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_DEFINITION", + "description": "Location adjacent to a fragment definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_SPREAD", + "description": "Location adjacent to a fragment spread.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INLINE_FRAGMENT", + "description": "Location adjacent to an inline fragment.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "SCHEMA", + "description": "Location adjacent to a schema definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "SCALAR", + "description": "Location adjacent to a scalar definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "OBJECT", + "description": "Location adjacent to an object type definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FIELD_DEFINITION", + "description": "Location adjacent to a field definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ARGUMENT_DEFINITION", + "description": "Location adjacent to an argument definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INTERFACE", + "description": "Location adjacent to an interface definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "UNION", + "description": "Location adjacent to a union definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM", + "description": "Location adjacent to an enum definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM_VALUE", + "description": "Location adjacent to an enum value definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_OBJECT", + "description": "Location adjacent to an input object type definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_FIELD_DEFINITION", + "description": "Location adjacent to an input object field definition.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + } + ], + "directives": [ + { + "name": "skip", + "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", + "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], + "args": [ + { + "name": "if", + "description": "Skipped when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } + }, + "defaultValue": null + } + ] + }, + { + "name": "include", + "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", + "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], + "args": [ + { + "name": "if", + "description": "Included when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } + }, + "defaultValue": null + } + ] + }, + { + "name": "deprecated", + "description": "Marks an element of a GraphQL schema as no longer supported.", + "locations": ["FIELD_DEFINITION", "ENUM_VALUE"], + "args": [ + { + "name": "reason", + "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).", + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "defaultValue": "\"No longer supported\"" + } + ] + } + ] + } +} diff --git a/x-pack/plugins/secops/common/graphql/root/index.ts b/x-pack/plugins/secops/common/graphql/root/index.ts new file mode 100644 index 0000000000000..47417b6376307 --- /dev/null +++ b/x-pack/plugins/secops/common/graphql/root/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 { rootSchema } from './schema.gql'; diff --git a/x-pack/plugins/secops/common/graphql/root/schema.gql.ts b/x-pack/plugins/secops/common/graphql/root/schema.gql.ts new file mode 100644 index 0000000000000..0819f2e2808b8 --- /dev/null +++ b/x-pack/plugins/secops/common/graphql/root/schema.gql.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 gql from 'graphql-tag'; + +export const rootSchema = gql` + schema { + query: Query + #mutation: Mutation + } + + type Query + + #type Mutation +`; diff --git a/x-pack/plugins/secops/common/graphql/typed_resolvers.ts b/x-pack/plugins/secops/common/graphql/typed_resolvers.ts new file mode 100644 index 0000000000000..b3c4274f7f1e1 --- /dev/null +++ b/x-pack/plugins/secops/common/graphql/typed_resolvers.ts @@ -0,0 +1,77 @@ +/* + * 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 { GraphQLResolveInfo } from 'graphql'; + +type BasicResolver = ( + parent: any, + args: Args, + context: any, + info: GraphQLResolveInfo +) => Promise | Result; + +type AppResolverResult = + | Promise + | Promise<{ [P in keyof R]: () => Promise }> + | { [P in keyof R]: () => Promise } + | { [P in keyof R]: () => R[P] } + | R; + +export type AppResolvedResult = Resolver extends AppResolver + ? Result + : never; + +export type SubsetResolverWithFields = R extends BasicResolver< + Array, + infer ArgsInArray +> + ? BasicResolver< + Array>>, + ArgsInArray + > + : R extends BasicResolver + ? BasicResolver>, Args> + : never; + +export type SubsetResolverWithoutFields = R extends BasicResolver< + Array, + infer ArgsInArray +> + ? BasicResolver< + Array>>, + ArgsInArray + > + : R extends BasicResolver + ? BasicResolver>, Args> + : never; + +export type AppResolver = ( + parent: Parent, + args: Args, + context: Context, + info: GraphQLResolveInfo +) => AppResolverResult; + +export type AppResolverOf = Resolver extends BasicResolver< + infer Result, + infer Args +> + ? AppResolver + : never; + +export type AppResolverWithFields< + Resolver, + Parent, + Context, + IncludedFields extends string +> = AppResolverOf, Parent, Context>; + +export type AppResolverWithoutFields< + Resolver, + Parent, + Context, + ExcludedFields extends string +> = AppResolverOf, Parent, Context>; diff --git a/x-pack/plugins/secops/common/graphql/types.ts b/x-pack/plugins/secops/common/graphql/types.ts new file mode 100644 index 0000000000000..ed44e8d5e4b53 --- /dev/null +++ b/x-pack/plugins/secops/common/graphql/types.ts @@ -0,0 +1,163 @@ +/* tslint:disable */ +/* + * 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 { GraphQLResolveInfo } from 'graphql'; + +export type Resolver = ( + parent: Parent, + args: Args, + context: Context, + info: GraphQLResolveInfo +) => Promise | Result; + +export type SubscriptionResolver = { + subscribe( + parent: P, + args: Args, + context: Context, + info: GraphQLResolveInfo + ): AsyncIterator; + resolve?( + parent: P, + args: Args, + context: Context, + info: GraphQLResolveInfo + ): R | Result | Promise; +}; + +export interface Query { + source: Source /** Get a security data source by id */; + allSources: Source[] /** Get a list of all security data sources */; +} + +export interface Source { + id: string /** The id of the source */; + configuration: SourceConfiguration /** The raw configuration of the source */; +} +/** A set of configuration options for a security data source */ +export interface SourceConfiguration { + fields: SourceFields /** The field mapping to use for this source */; +} +/** A mapping of semantic fields to their document counterparts */ +export interface SourceFields { + container: string /** The field to identify a container by */; + host: string /** The fields to identify a host by */; + message: string[] /** The fields that may contain the log event message. The first field found win. */; + pod: string /** The field to identify a pod by */; + tiebreaker: string /** The field to use as a tiebreaker for log events that have identical timestamps */; + timestamp: string /** The field to use as a timestamp for metrics and logs */; +} +export interface SourceQueryArgs { + id: string /** The id of the source */; +} + +export namespace QueryResolvers { + export interface Resolvers { + source?: SourceResolver /** Get a security data source by id */; + allSources?: AllSourcesResolver< + Source[], + any, + Context + > /** Get a list of all security data sources */; + } + + export type SourceResolver = Resolver< + R, + Parent, + Context, + SourceArgs + >; + export interface SourceArgs { + id: string /** The id of the source */; + } + + export type AllSourcesResolver = Resolver< + R, + Parent, + Context + >; +} + +export namespace SourceResolvers { + export interface Resolvers { + id?: IdResolver /** The id of the source */; + configuration?: ConfigurationResolver< + SourceConfiguration, + any, + Context + > /** The raw configuration of the source */; + } + + export type IdResolver = Resolver; + export type ConfigurationResolver< + R = SourceConfiguration, + Parent = any, + Context = any + > = Resolver; +} +/** A set of configuration options for a security data source */ +export namespace SourceConfigurationResolvers { + export interface Resolvers { + fields?: FieldsResolver< + SourceFields, + any, + Context + > /** The field mapping to use for this source */; + } + + export type FieldsResolver = Resolver< + R, + Parent, + Context + >; +} +/** A mapping of semantic fields to their document counterparts */ +export namespace SourceFieldsResolvers { + export interface Resolvers { + container?: ContainerResolver /** The field to identify a container by */; + host?: HostResolver /** The fields to identify a host by */; + message?: MessageResolver< + string[], + any, + Context + > /** The fields that may contain the log event message. The first field found win. */; + pod?: PodResolver /** The field to identify a pod by */; + tiebreaker?: TiebreakerResolver< + string, + any, + Context + > /** The field to use as a tiebreaker for log events that have identical timestamps */; + timestamp?: TimestampResolver< + string, + any, + Context + > /** The field to use as a timestamp for metrics and logs */; + } + + export type ContainerResolver = Resolver< + R, + Parent, + Context + >; + export type HostResolver = Resolver; + export type MessageResolver = Resolver< + R, + Parent, + Context + >; + export type PodResolver = Resolver; + export type TiebreakerResolver = Resolver< + R, + Parent, + Context + >; + export type TimestampResolver = Resolver< + R, + Parent, + Context + >; +} diff --git a/x-pack/plugins/secops/index.ts b/x-pack/plugins/secops/index.ts new file mode 100644 index 0000000000000..10779b6db54be --- /dev/null +++ b/x-pack/plugins/secops/index.ts @@ -0,0 +1,48 @@ +/* + * 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 JoiNamespace from 'joi'; +import { resolve } from 'path'; + +import { getConfigSchema, initServerWithKibana, KbnServer } from './server/kibana.index'; + +const APP_ID = 'secops'; + +export function secops(kibana: any) { + return new kibana.Plugin({ + id: APP_ID, + configPrefix: 'xpack.secops', + publicDir: resolve(__dirname, 'public'), + require: ['kibana', 'elasticsearch'], + uiExports: { + app: { + description: 'Explore your security operations', + main: 'plugins/secops/app', + euiIconType: 'securityApp', + title: 'Sec Ops', + listed: false, + url: `/app/${APP_ID}`, + }, + home: ['plugins/secops/register_feature'], + links: [ + { + description: 'Explore your security operations', + euiIconType: 'securityApp', + id: 'secops', + order: 9000, + title: 'Sec Ops', + url: `/app/${APP_ID}`, + }, + ], + }, + config(Joi: typeof JoiNamespace) { + return getConfigSchema(Joi); + }, + init(server: KbnServer) { + initServerWithKibana(server); + }, + }); +} diff --git a/x-pack/plugins/secops/package.json b/x-pack/plugins/secops/package.json new file mode 100644 index 0000000000000..ced3d1d97cf2c --- /dev/null +++ b/x-pack/plugins/secops/package.json @@ -0,0 +1,16 @@ +{ + "author": "Elastic", + "name": "sec-ops", + "version": "7.0.0-alpha1", + "scripts": { + "build-graphql-types": "node scripts/generate_types_from_graphql.js" + }, + "devDependencies": { + "@types/boom": "^7.2.0", + "@types/color": "^3.0.0", + "@types/lodash": "^4.14.110" + }, + "dependencies": { + "lodash": "^4.17.10" + } +} diff --git a/x-pack/plugins/secops/public/app.ts b/x-pack/plugins/secops/public/app.ts new file mode 100644 index 0000000000000..255c51c9e48ce --- /dev/null +++ b/x-pack/plugins/secops/public/app.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. + */ + +import './apps/kibana_app'; diff --git a/x-pack/plugins/secops/public/apps/kibana_app.ts b/x-pack/plugins/secops/public/apps/kibana_app.ts new file mode 100644 index 0000000000000..292b02c243e0e --- /dev/null +++ b/x-pack/plugins/secops/public/apps/kibana_app.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import 'uiExports/autocompleteProviders'; + +import { compose } from '../lib/compose/kibana_compose'; +import { startApp } from './start_app'; + +startApp(compose()); diff --git a/x-pack/plugins/secops/public/apps/start_app.tsx b/x-pack/plugins/secops/public/apps/start_app.tsx new file mode 100644 index 0000000000000..36f0a83289f9e --- /dev/null +++ b/x-pack/plugins/secops/public/apps/start_app.tsx @@ -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 { createHashHistory } from 'history'; +import React from 'react'; +import { ApolloProvider } from 'react-apollo'; +import { ThemeProvider } from 'styled-components'; + +// TODO use theme provided from parentApp when kibana supports it +import { EuiErrorBoundary } from '@elastic/eui'; +import * as euiVars from '@elastic/eui/dist/eui_theme_k6_light.json'; + +import { AppFrontendLibs } from '../lib/lib'; +import { PageRouter } from '../routes'; + +export const startApp = async (libs: AppFrontendLibs) => { + const history = createHashHistory(); + + libs.framework.render( + + + + + + + + ); +}; diff --git a/x-pack/plugins/secops/public/apps/testing_app.ts b/x-pack/plugins/secops/public/apps/testing_app.ts new file mode 100644 index 0000000000000..0fd944d3f45d6 --- /dev/null +++ b/x-pack/plugins/secops/public/apps/testing_app.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 { compose } from '../lib/compose/testing_compose'; +import { startApp } from './start_app'; + +startApp(compose()); diff --git a/x-pack/plugins/secops/public/components/page.tsx b/x-pack/plugins/secops/public/components/page.tsx new file mode 100644 index 0000000000000..04d69fdb1d9e8 --- /dev/null +++ b/x-pack/plugins/secops/public/components/page.tsx @@ -0,0 +1,26 @@ +/* + * 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 { EuiPage } from '@elastic/eui'; +import styled from 'styled-components'; + +export const ColumnarPage = styled.div` + display: flex; + flex-direction: column; + align-items: stretch; + flex: 1 0 0; +`; + +export const PageContent = styled.div` + flex: 1 0 0; + display: flex; + flex-direction: row; + background-color: ${props => props.theme.eui.euiColorEmptyShade}; +`; + +export const FlexPage = styled(EuiPage)` + flex: 1 0 0; +`; diff --git a/x-pack/plugins/secops/public/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/secops/public/lib/adapters/framework/kibana_framework_adapter.ts new file mode 100644 index 0000000000000..d2e745245680b --- /dev/null +++ b/x-pack/plugins/secops/public/lib/adapters/framework/kibana_framework_adapter.ts @@ -0,0 +1,182 @@ +/* + * 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 { IModule, IScope } from 'angular'; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; + +import { UIRoutes as KibanaUIRoutes } from 'ui/routes'; + +import { + AppBufferedKibanaServiceCall, + AppFrameworkAdapter, + AppKibanaAdapterServiceRefs, + AppKibanaUIConfig, + AppTimezoneProvider, + AppUiKibanaAdapterScope, +} from '../../lib'; + +const ROOT_ELEMENT_ID = 'react-secops-root'; +const BREADCRUMBS_ELEMENT_ID = 'react-secops-breadcrumbs'; + +export class AppKibanaFrameworkAdapter implements AppFrameworkAdapter { + public dateFormat?: string; + public kbnVersion?: string; + public scaledDateFormat?: string; + public timezone?: string; + + private adapterService: KibanaAdapterServiceProvider; + private timezoneProvider: AppTimezoneProvider; + private rootComponent: React.ReactElement | null = null; + private breadcrumbsComponent: React.ReactElement | null = null; + + constructor(uiModule: IModule, uiRoutes: KibanaUIRoutes, timezoneProvider: AppTimezoneProvider) { + this.adapterService = new KibanaAdapterServiceProvider(); + this.timezoneProvider = timezoneProvider; + this.register(uiModule, uiRoutes); + } + + public setUISettings = (key: string, value: any) => { + this.adapterService.callOrBuffer(({ config }) => { + config.set(key, value); + }); + }; + + public render = (component: React.ReactElement) => { + this.adapterService.callOrBuffer(() => (this.rootComponent = component)); + }; + + public renderBreadcrumbs = (component: React.ReactElement) => { + this.adapterService.callOrBuffer(() => (this.breadcrumbsComponent = component)); + }; + + private register = (adapterModule: IModule, uiRoutes: KibanaUIRoutes) => { + adapterModule.provider('kibanaAdapter', this.adapterService); + + adapterModule.directive('appUiKibanaAdapter', () => ({ + controller: ($scope: AppUiKibanaAdapterScope, $element: JQLite) => ({ + $onDestroy: () => { + const targetRootElement = $element[0].querySelector(`#${ROOT_ELEMENT_ID}`); + const targetBreadcrumbsElement = $element[0].querySelector(`#${ROOT_ELEMENT_ID}`); + + if (targetRootElement) { + ReactDOM.unmountComponentAtNode(targetRootElement); + } + + if (targetBreadcrumbsElement) { + ReactDOM.unmountComponentAtNode(targetBreadcrumbsElement); + } + }, + $onInit: () => { + $scope.topNavMenu = []; + }, + $postLink: () => { + $scope.$watchGroup( + [ + () => this.breadcrumbsComponent, + () => $element[0].querySelector(`#${BREADCRUMBS_ELEMENT_ID}`), + ], + ([breadcrumbsComponent, targetElement]) => { + if (!targetElement) { + return; + } + + if (breadcrumbsComponent) { + ReactDOM.render(breadcrumbsComponent, targetElement); + } else { + ReactDOM.unmountComponentAtNode(targetElement); + } + } + ); + $scope.$watchGroup( + [() => this.rootComponent, () => $element[0].querySelector(`#${ROOT_ELEMENT_ID}`)], + ([rootComponent, targetElement]) => { + if (!targetElement) { + return; + } + + if (rootComponent) { + ReactDOM.render(rootComponent, targetElement); + } else { + ReactDOM.unmountComponentAtNode(targetElement); + } + } + ); + }, + }), + scope: true, + template: ` +
+ `, + })); + + adapterModule.run(( + config: AppKibanaUIConfig, + kbnVersion: string, + Private: (provider: Provider) => Provider, + // @ts-ignore: inject kibanaAdapter to force eager instaliation + kibanaAdapter: any + ) => { + this.timezone = Private(this.timezoneProvider)(); + this.kbnVersion = kbnVersion; + this.dateFormat = config.get('dateFormat'); + this.scaledDateFormat = config.get('dateFormat:scaled'); + }); + + uiRoutes.enable(); + + uiRoutes.otherwise({ + reloadOnSearch: false, + template: + '', + }); + }; +} + +// tslint:disable-next-line: max-classes-per-file +class KibanaAdapterServiceProvider { + public serviceRefs: AppKibanaAdapterServiceRefs | null = null; + public bufferedCalls: Array> = []; + + public $get($rootScope: IScope, config: AppKibanaUIConfig) { + this.serviceRefs = { + config, + rootScope: $rootScope, + }; + + this.applyBufferedCalls(this.bufferedCalls); + + return this; + } + + public callOrBuffer(serviceCall: (serviceRefs: AppKibanaAdapterServiceRefs) => void) { + if (this.serviceRefs !== null) { + this.applyBufferedCalls([serviceCall]); + } else { + this.bufferedCalls.push(serviceCall); + } + } + + public applyBufferedCalls( + bufferedCalls: Array> + ) { + if (!this.serviceRefs) { + return; + } + + this.serviceRefs.rootScope.$apply(() => { + bufferedCalls.forEach(serviceCall => { + if (!this.serviceRefs) { + return; + } + return serviceCall(this.serviceRefs); + }); + }); + } +} diff --git a/x-pack/plugins/secops/public/lib/adapters/framework/testing_framework_adapter.ts b/x-pack/plugins/secops/public/lib/adapters/framework/testing_framework_adapter.ts new file mode 100644 index 0000000000000..c829e1d26e6a4 --- /dev/null +++ b/x-pack/plugins/secops/public/lib/adapters/framework/testing_framework_adapter.ts @@ -0,0 +1,29 @@ +/* + * 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 { AppFrameworkAdapter } from '../../lib'; + +export class AppTestingFrameworkAdapter implements AppFrameworkAdapter { + public appState?: object; + public dateFormat?: string; + public kbnVersion?: string; + public scaledDateFormat?: string; + public timezone?: string; + + constructor() { + this.appState = {}; + } + + public render() { + return; + } + public renderBreadcrumbs() { + return; + } + public setUISettings() { + return; + } +} diff --git a/x-pack/plugins/secops/public/lib/adapters/observable_api/kibana_observable_api.ts b/x-pack/plugins/secops/public/lib/adapters/observable_api/kibana_observable_api.ts new file mode 100644 index 0000000000000..5a8a7c3a4e89e --- /dev/null +++ b/x-pack/plugins/secops/public/lib/adapters/observable_api/kibana_observable_api.ts @@ -0,0 +1,41 @@ +/* + * 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 { ajax } from 'rxjs/ajax'; +import { map } from 'rxjs/operators'; + +import { AppObservableApi, AppObservableApiPostParams, AppObservableApiResponse } from '../../lib'; + +export class AppKibanaObservableApiAdapter implements AppObservableApi { + private basePath: string; + private defaultHeaders: { + [headerName: string]: string; + }; + + constructor({ basePath, xsrfToken }: { basePath: string; xsrfToken: string }) { + this.basePath = basePath; + this.defaultHeaders = { + 'kbn-version': xsrfToken, + }; + } + + public post = ({ + url, + body, + }: AppObservableApiPostParams): AppObservableApiResponse => + ajax({ + body: body ? JSON.stringify(body) : undefined, + headers: { + ...this.defaultHeaders, + 'Content-Type': 'application/json', + }, + method: 'POST', + responseType: 'json', + timeout: 30000, + url: `${this.basePath}/api/${url}`, + withCredentials: true, + }).pipe(map(({ response, status }) => ({ response, status }))); +} diff --git a/x-pack/plugins/secops/public/lib/compose/kibana_compose.ts b/x-pack/plugins/secops/public/lib/compose/kibana_compose.ts new file mode 100644 index 0000000000000..5aa9c3c220666 --- /dev/null +++ b/x-pack/plugins/secops/public/lib/compose/kibana_compose.ts @@ -0,0 +1,69 @@ +/* + * 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 'ui/autoload/all'; +// @ts-ignore: path dynamic for kibana +import chrome from 'ui/chrome'; +// @ts-ignore: path dynamic for kibana +import { uiModules } from 'ui/modules'; +import uiRoutes from 'ui/routes'; +// @ts-ignore: path dynamic for kibana +import { timezoneProvider } from 'ui/vis/lib/timezone'; + +import { AppKibanaObservableApiAdapter } from '../adapters/observable_api/kibana_observable_api'; + +import introspectionQueryResultData from '../../../common/graphql/introspection.json'; +import { AppKibanaFrameworkAdapter } from '../adapters/framework/kibana_framework_adapter'; +import { AppFrontendLibs } from '../lib'; + +import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; +import ApolloClient from 'apollo-client'; +import { ApolloLink } from 'apollo-link'; +import { HttpLink } from 'apollo-link-http'; +import { withClientState } from 'apollo-link-state'; + +export function compose(): AppFrontendLibs { + const cache = new InMemoryCache({ + fragmentMatcher: new IntrospectionFragmentMatcher({ + introspectionQueryResultData, + }), + }); + + const observableApi = new AppKibanaObservableApiAdapter({ + basePath: chrome.getBasePath(), + xsrfToken: chrome.getXsrfToken(), + }); + + const graphQLOptions = { + cache, + link: ApolloLink.from([ + withClientState({ + cache, + resolvers: {}, + }), + new HttpLink({ + credentials: 'same-origin', + headers: { + 'kbn-xsrf': chrome.getXsrfToken(), + }, + uri: `${chrome.getBasePath()}/api/secops/graphql`, + }), + ]), + }; + + const apolloClient = new ApolloClient(graphQLOptions); + + const appModule = uiModules.get('app/secops'); + + const framework = new AppKibanaFrameworkAdapter(appModule, uiRoutes, timezoneProvider); + + const libs: AppFrontendLibs = { + apolloClient, + framework, + observableApi, + }; + return libs; +} diff --git a/x-pack/plugins/secops/public/lib/compose/testing_compose.ts b/x-pack/plugins/secops/public/lib/compose/testing_compose.ts new file mode 100644 index 0000000000000..2dd320c88cbc4 --- /dev/null +++ b/x-pack/plugins/secops/public/lib/compose/testing_compose.ts @@ -0,0 +1,59 @@ +/* + * 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 'ui/autoload/all'; +// @ts-ignore: path dynamic for kibana +import chrome from 'ui/chrome'; +// @ts-ignore: path dynamic for kibana +import { uiModules } from 'ui/modules'; +import uiRoutes from 'ui/routes'; +// @ts-ignore: path dynamic for kibana +import { timezoneProvider } from 'ui/vis/lib/timezone'; + +import { InMemoryCache } from 'apollo-cache-inmemory'; +import ApolloClient from 'apollo-client'; +import { SchemaLink } from 'apollo-link-schema'; +import { addMockFunctionsToSchema, makeExecutableSchema } from 'graphql-tools'; +import { AppKibanaFrameworkAdapter } from '../adapters/framework/kibana_framework_adapter'; +import { AppKibanaObservableApiAdapter } from '../adapters/observable_api/kibana_observable_api'; +import { AppFrontendLibs } from '../lib'; + +export function compose(): AppFrontendLibs { + const appModule = uiModules.get('app/secops'); + const observableApi = new AppKibanaObservableApiAdapter({ + basePath: chrome.getBasePath(), + xsrfToken: chrome.getXsrfToken(), + }); + const framework = new AppKibanaFrameworkAdapter(appModule, uiRoutes, timezoneProvider); + const typeDefs = ` + Query {} +`; + + const mocks = { + Mutation: () => undefined, + Query: () => undefined, + }; + + const schema = makeExecutableSchema({ typeDefs }); + addMockFunctionsToSchema({ + mocks, + schema, + }); + + const cache = new InMemoryCache((window as any).__APOLLO_CLIENT__); + + const apolloClient = new ApolloClient({ + cache, + link: new SchemaLink({ schema }), + }); + + const libs: AppFrontendLibs = { + apolloClient, + framework, + observableApi, + }; + return libs; +} diff --git a/x-pack/plugins/secops/public/lib/lib.ts b/x-pack/plugins/secops/public/lib/lib.ts new file mode 100644 index 0000000000000..5246d4c1e1f80 --- /dev/null +++ b/x-pack/plugins/secops/public/lib/lib.ts @@ -0,0 +1,70 @@ +/* + * 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 { IModule, IScope } from 'angular'; +import { NormalizedCacheObject } from 'apollo-cache-inmemory'; +import ApolloClient from 'apollo-client'; +import React from 'react'; +import { Observable } from 'rxjs'; + +export interface AppFrontendLibs { + framework: AppFrameworkAdapter; + apolloClient: AppApolloClient; + observableApi: AppObservableApi; +} + +export type AppTimezoneProvider = () => string; + +export type AppApolloClient = ApolloClient; + +export interface AppFrameworkAdapter { + appState?: object; + dateFormat?: string; + kbnVersion?: string; + scaledDateFormat?: string; + timezone?: string; + + setUISettings(key: string, value: any): void; + render(component: React.ReactElement): void; + renderBreadcrumbs(component: React.ReactElement): void; +} + +export interface AppFrameworkAdapterConstructible { + new (uiModule: IModule, timezoneProvider: AppTimezoneProvider): AppFrameworkAdapter; +} + +export interface AppObservableApiPostParams { + url: string; + body?: RequestBody; +} + +export type AppObservableApiResponse = Observable<{ + status: number; + response: BodyType; +}>; + +export interface AppObservableApi { + post( + params: AppObservableApiPostParams + ): AppObservableApiResponse; +} + +export interface AppUiKibanaAdapterScope extends IScope { + breadcrumbs: any[]; + topNavMenu: any[]; +} + +export interface AppKibanaUIConfig { + get(key: string): any; + set(key: string, value: any): Promise; +} + +export interface AppKibanaAdapterServiceRefs { + config: AppKibanaUIConfig; + rootScope: IScope; +} + +export type AppBufferedKibanaServiceCall = (serviceRefs: ServiceRefs) => void; diff --git a/x-pack/plugins/secops/public/pages/404.tsx b/x-pack/plugins/secops/public/pages/404.tsx new file mode 100644 index 0000000000000..a025f3ace88b3 --- /dev/null +++ b/x-pack/plugins/secops/public/pages/404.tsx @@ -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 React from 'react'; +import { pure } from 'recompose'; + +export const NotFoundPage = pure(() =>
No content found
); diff --git a/x-pack/plugins/secops/public/pages/home/index.tsx b/x-pack/plugins/secops/public/pages/home/index.tsx new file mode 100644 index 0000000000000..9d646390b9c69 --- /dev/null +++ b/x-pack/plugins/secops/public/pages/home/index.tsx @@ -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 * as React from 'react'; +import { pure } from 'recompose'; + +import { ColumnarPage } from '../../components/page'; + +export const HomePage = pure(() => ( + +

Hello Sec Ops

+
+)); diff --git a/x-pack/plugins/secops/public/register_feature.ts b/x-pack/plugins/secops/public/register_feature.ts new file mode 100644 index 0000000000000..29357a6167e04 --- /dev/null +++ b/x-pack/plugins/secops/public/register_feature.ts @@ -0,0 +1,22 @@ +/* + * 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 { + FeatureCatalogueCategory, + FeatureCatalogueRegistryProvider, +} from 'ui/registry/feature_catalogue'; + +const APP_ID = 'secops'; + +FeatureCatalogueRegistryProvider.register(() => ({ + id: 'secops', + title: 'Sec Ops', + description: 'Explore security metrics and logs for events and alerts', + icon: 'securityApp', + path: `/app/${APP_ID}`, + showOnHomePage: true, + category: FeatureCatalogueCategory.DATA, +})); diff --git a/x-pack/plugins/secops/public/routes.tsx b/x-pack/plugins/secops/public/routes.tsx new file mode 100644 index 0000000000000..ad16e1b4d6176 --- /dev/null +++ b/x-pack/plugins/secops/public/routes.tsx @@ -0,0 +1,26 @@ +/* + * 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 { History } from 'history'; +import React from 'react'; +import { Route, Router, Switch } from 'react-router-dom'; +import { pure } from 'recompose'; + +import { NotFoundPage } from './pages/404'; +import { HomePage } from './pages/home'; + +interface RouterProps { + history: History; +} + +export const PageRouter = pure(({ history }) => ( + + + + + + +)); diff --git a/x-pack/plugins/secops/scripts/combined_schema.ts b/x-pack/plugins/secops/scripts/combined_schema.ts new file mode 100644 index 0000000000000..ec3628b2632c9 --- /dev/null +++ b/x-pack/plugins/secops/scripts/combined_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 { buildSchemaFromTypeDefinitions } from 'graphql-tools'; + +import { schemas as serverSchemas } from '../server/graphql'; + +export const schemas = [...serverSchemas]; + +// this default export is used to feed the combined types to the gql-gen tool +// which generates the corresponding typescript types +// tslint:disable-next-line:no-default-export +export default buildSchemaFromTypeDefinitions(schemas); diff --git a/x-pack/plugins/secops/scripts/generate_types_from_graphql.js b/x-pack/plugins/secops/scripts/generate_types_from_graphql.js new file mode 100644 index 0000000000000..f36979c159376 --- /dev/null +++ b/x-pack/plugins/secops/scripts/generate_types_from_graphql.js @@ -0,0 +1,49 @@ +/* + * 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. + */ + +const { join, resolve } = require('path'); +// eslint-disable-next-line import/no-extraneous-dependencies, import/no-unresolved +const { generate } = require('graphql-code-generator'); + +const GRAPHQL_GLOBS = [ + join('public', 'containers', '**', '*.gql_query.ts{,x}'), + join('public', 'store', '**', '*.gql_query.ts{,x}'), + join('common', 'graphql', '**', '*.gql_query.ts{,x}'), +]; +const CONFIG_PATH = resolve(__dirname, 'gql_gen.json'); +const OUTPUT_INTROSPECTION_PATH = resolve('common', 'graphql', 'introspection.json'); +const OUTPUT_TYPES_PATH = resolve('common', 'graphql', 'types.ts'); +const SCHEMA_PATH = resolve(__dirname, 'combined_schema.ts'); + +async function main() { + await generate( + { + args: GRAPHQL_GLOBS, + config: CONFIG_PATH, + out: OUTPUT_INTROSPECTION_PATH, + overwrite: true, + require: ['ts-node/register'], + schema: SCHEMA_PATH, + template: 'graphql-codegen-introspection-template', + }, + true + ); + await generate( + { + args: GRAPHQL_GLOBS, + config: CONFIG_PATH, + out: OUTPUT_TYPES_PATH, + overwrite: true, + schema: SCHEMA_PATH, + template: 'graphql-codegen-typescript-template', + }, + true + ); +} + +if (require.main === module) { + main(); +} diff --git a/x-pack/plugins/secops/scripts/gql_gen.json b/x-pack/plugins/secops/scripts/gql_gen.json new file mode 100644 index 0000000000000..ecfeb9f9e124b --- /dev/null +++ b/x-pack/plugins/secops/scripts/gql_gen.json @@ -0,0 +1,20 @@ +{ + "flattenTypes": true, + "generatorConfig": { + "prepend": [ + "/*", + " * 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.", + " */", + "" + ] + }, + "primitives": { + "String": "string", + "Int": "number", + "Float": "number", + "Boolean": "boolean", + "ID": "string" + } +} diff --git a/x-pack/plugins/secops/server/graphql/index.ts b/x-pack/plugins/secops/server/graphql/index.ts new file mode 100644 index 0000000000000..8cf5394a91a6c --- /dev/null +++ b/x-pack/plugins/secops/server/graphql/index.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 { rootSchema } from '../../common/graphql/root/schema.gql'; +import { sourcesSchema } from './sources/schema.gql'; + +export const schemas = [rootSchema, sourcesSchema]; diff --git a/x-pack/plugins/secops/server/graphql/sources/index.ts b/x-pack/plugins/secops/server/graphql/sources/index.ts new file mode 100644 index 0000000000000..ee187d8c31bec --- /dev/null +++ b/x-pack/plugins/secops/server/graphql/sources/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 { createSourcesResolvers } from './resolvers'; +export { sourcesSchema } from './schema.gql'; diff --git a/x-pack/plugins/secops/server/graphql/sources/resolvers.ts b/x-pack/plugins/secops/server/graphql/sources/resolvers.ts new file mode 100644 index 0000000000000..1748e5f5092d2 --- /dev/null +++ b/x-pack/plugins/secops/server/graphql/sources/resolvers.ts @@ -0,0 +1,56 @@ +/* + * 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 { QueryResolvers } from '../../../common/graphql/types'; +import { AppResolverWithFields } from '../../lib/framework'; +import { Sources } from '../../lib/sources'; +import { Context } from '../../lib/types'; + +export type QuerySourceResolver = AppResolverWithFields< + QueryResolvers.SourceResolver, + null, + Context, + 'id' | 'configuration' +>; + +export type QueryAllSourcesResolver = AppResolverWithFields< + QueryResolvers.AllSourcesResolver, + null, + Context, + 'id' | 'configuration' +>; + +interface SourcesResolversDeps { + sources: Sources; +} + +export const createSourcesResolvers = ( + libs: SourcesResolversDeps +): { + Query: { + source: QuerySourceResolver; + allSources: QueryAllSourcesResolver; + }; +} => ({ + Query: { + async source(root, args) { + const requestedSourceConfiguration = await libs.sources.getConfiguration(args.id); + + return { + id: args.id, + configuration: requestedSourceConfiguration, + }; + }, + async allSources() { + const sourceConfigurations = await libs.sources.getAllConfigurations(); + + return Object.entries(sourceConfigurations).map(([sourceName, sourceConfiguration]) => ({ + id: sourceName, + configuration: sourceConfiguration, + })); + }, + }, +}); diff --git a/x-pack/plugins/secops/server/graphql/sources/schema.gql.ts b/x-pack/plugins/secops/server/graphql/sources/schema.gql.ts new file mode 100644 index 0000000000000..f9de01dd0ddce --- /dev/null +++ b/x-pack/plugins/secops/server/graphql/sources/schema.gql.ts @@ -0,0 +1,45 @@ +/* + * 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 gql from 'graphql-tag'; + +export const sourcesSchema = gql` + extend type Query { + "Get a security data source by id" + source("The id of the source" id: ID!): Source! + "Get a list of all security data sources" + allSources: [Source!]! + } + + type Source { + "The id of the source" + id: ID! + "The raw configuration of the source" + configuration: SourceConfiguration! + } + + "A set of configuration options for a security data source" + type SourceConfiguration { + "The field mapping to use for this source" + fields: SourceFields! + } + + "A mapping of semantic fields to their document counterparts" + type SourceFields { + "The field to identify a container by" + container: String! + "The fields to identify a host by" + host: String! + "The fields that may contain the log event message. The first field found win." + message: [String!]! + "The field to identify a pod by" + pod: String! + "The field to use as a tiebreaker for log events that have identical timestamps" + tiebreaker: String! + "The field to use as a timestamp for metrics and logs" + timestamp: String! + } +`; diff --git a/x-pack/plugins/secops/server/init_server.ts b/x-pack/plugins/secops/server/init_server.ts new file mode 100644 index 0000000000000..98107857289d4 --- /dev/null +++ b/x-pack/plugins/secops/server/init_server.ts @@ -0,0 +1,19 @@ +/* + * 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 { IResolvers, makeExecutableSchema } from 'graphql-tools'; +import { schemas } from './graphql'; +import { createSourcesResolvers } from './graphql/sources'; +import { AppBackendLibs } from './lib/types'; + +export const initServer = (libs: AppBackendLibs) => { + const schema = makeExecutableSchema({ + resolvers: [createSourcesResolvers(libs) as IResolvers], + typeDefs: schemas, + }); + + libs.framework.registerGraphQLEndpoint('/api/secops/graphql', schema); +}; diff --git a/x-pack/plugins/secops/server/kibana.index.ts b/x-pack/plugins/secops/server/kibana.index.ts new file mode 100644 index 0000000000000..645640cad3378 --- /dev/null +++ b/x-pack/plugins/secops/server/kibana.index.ts @@ -0,0 +1,39 @@ +/* + * 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 { Server } from 'hapi'; +import JoiNamespace from 'joi'; +import { initServer } from './init_server'; +import { compose } from './lib/compose/kibana'; + +export interface KbnServer extends Server { + usage: any; +} + +export const initServerWithKibana = (kbnServer: KbnServer) => { + const libs = compose(kbnServer); + initServer(libs); +}; + +export const getConfigSchema = (Joi: typeof JoiNamespace) => { + const DefaultSourceConfigSchema = Joi.object({}); + + const AppRootConfigSchema = Joi.object({ + enabled: Joi.boolean().default(true), + query: Joi.object({ + partitionSize: Joi.number(), + partitionFactor: Joi.number(), + }).default(), + sources: Joi.object() + .keys({ + default: DefaultSourceConfigSchema, + }) + .pattern(/.*/, DefaultSourceConfigSchema) + .default(), + }).default(); + + return AppRootConfigSchema; +}; diff --git a/x-pack/plugins/secops/server/lib/compose/kibana.ts b/x-pack/plugins/secops/server/lib/compose/kibana.ts new file mode 100644 index 0000000000000..6d9be1afd4dc2 --- /dev/null +++ b/x-pack/plugins/secops/server/lib/compose/kibana.ts @@ -0,0 +1,32 @@ +/* + * 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 { Server } from 'hapi'; + +import { KibanaConfigurationAdapter } from '../configuration/kibana_configuration_adapter'; +import { KibanaBackendFrameworkAdapter } from '../framework/kibana_framework_adapter'; +import { Sources } from '../sources'; +import { ConfigurationSourcesAdapter } from '../sources/configuration_sources_adapter'; +import { AppBackendLibs, AppDomainLibs, Configuration } from '../types'; + +export function compose(server: Server): AppBackendLibs { + const configuration = new KibanaConfigurationAdapter(server); + const framework = new KibanaBackendFrameworkAdapter(server); + const sources = new Sources(new ConfigurationSourcesAdapter(configuration)); + + const domainLibs: AppDomainLibs = { + hello: '', + }; + + const libs: AppBackendLibs = { + configuration, + framework, + sources, + ...domainLibs, + }; + + return libs; +} diff --git a/x-pack/plugins/secops/server/lib/configuration/adapter_types.ts b/x-pack/plugins/secops/server/lib/configuration/adapter_types.ts new file mode 100644 index 0000000000000..69938e400aaef --- /dev/null +++ b/x-pack/plugins/secops/server/lib/configuration/adapter_types.ts @@ -0,0 +1,9 @@ +/* + * 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 interface ConfigurationAdapter { + get(): Promise; +} diff --git a/x-pack/plugins/secops/server/lib/configuration/index.ts b/x-pack/plugins/secops/server/lib/configuration/index.ts new file mode 100644 index 0000000000000..4e09b5d0e9e2d --- /dev/null +++ b/x-pack/plugins/secops/server/lib/configuration/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 * from './adapter_types'; diff --git a/x-pack/plugins/secops/server/lib/configuration/inmemory_configuration_adapter.ts b/x-pack/plugins/secops/server/lib/configuration/inmemory_configuration_adapter.ts new file mode 100644 index 0000000000000..d574b95755ebc --- /dev/null +++ b/x-pack/plugins/secops/server/lib/configuration/inmemory_configuration_adapter.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 { ConfigurationAdapter } from './adapter_types'; + +export class InmemoryConfigurationAdapter + implements ConfigurationAdapter { + constructor(private readonly configuration: Configuration) {} + + public async get() { + return this.configuration; + } +} diff --git a/x-pack/plugins/secops/server/lib/configuration/kibana_configuration_adapter.test.ts b/x-pack/plugins/secops/server/lib/configuration/kibana_configuration_adapter.test.ts new file mode 100644 index 0000000000000..07a3ce4bd9e7b --- /dev/null +++ b/x-pack/plugins/secops/server/lib/configuration/kibana_configuration_adapter.test.ts @@ -0,0 +1,40 @@ +/* + * 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 { KibanaConfigurationAdapter } from './kibana_configuration_adapter'; + +describe('the KibanaConfigurationAdapter', () => { + test('queries the xpack.secops configuration of the server', async () => { + const mockConfig = { + get: jest.fn(), + }; + + const configurationAdapter = new KibanaConfigurationAdapter({ + config: () => mockConfig, + }); + + await configurationAdapter.get(); + + expect(mockConfig.get).toBeCalledWith('xpack.secops'); + }); + + test('applies the query defaults', async () => { + const configurationAdapter = new KibanaConfigurationAdapter({ + config: () => ({ + get: () => ({}), + }), + }); + + const configuration = await configurationAdapter.get(); + + expect(configuration).toMatchObject({ + query: { + partitionSize: expect.any(Number), + partitionFactor: expect.any(Number), + }, + }); + }); +}); diff --git a/x-pack/plugins/secops/server/lib/configuration/kibana_configuration_adapter.ts b/x-pack/plugins/secops/server/lib/configuration/kibana_configuration_adapter.ts new file mode 100644 index 0000000000000..25cabfb4d0af3 --- /dev/null +++ b/x-pack/plugins/secops/server/lib/configuration/kibana_configuration_adapter.ts @@ -0,0 +1,75 @@ +/* + * 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 Joi from 'joi'; + +import { ConfigurationAdapter } from './adapter_types'; + +export class KibanaConfigurationAdapter + implements ConfigurationAdapter { + private readonly server: ServerWithConfig; + + constructor(server: any) { + if (!isServerWithConfig(server)) { + throw new Error('Failed to find configuration on server.'); + } + + this.server = server; + } + + public async get() { + const config = this.server.config(); + + if (!isKibanaConfiguration(config)) { + throw new Error('Failed to access configuration of server.'); + } + + const configuration = config.get('xpack.secops') || {}; + const configurationWithDefaults = { + enabled: true, + query: { + partitionSize: 75, + partitionFactor: 1.2, + ...(configuration.query || {}), + }, + sources: {}, + ...configuration, + } as Configuration; + + // we assume this to be the configuration because Kibana would have already validated it + return configurationWithDefaults; + } +} + +interface ServerWithConfig { + config(): any; +} + +function isServerWithConfig(maybeServer: any): maybeServer is ServerWithConfig { + return ( + Joi.validate( + maybeServer, + Joi.object({ + config: Joi.func().required(), + }).unknown() + ).error === null + ); +} + +interface KibanaConfiguration { + get(key: string): any; +} + +function isKibanaConfiguration(maybeConfiguration: any): maybeConfiguration is KibanaConfiguration { + return ( + Joi.validate( + maybeConfiguration, + Joi.object({ + get: Joi.func().required(), + }).unknown() + ).error === null + ); +} diff --git a/x-pack/plugins/secops/server/lib/framework/adapter_types.ts b/x-pack/plugins/secops/server/lib/framework/adapter_types.ts new file mode 100644 index 0000000000000..574d54abc16f7 --- /dev/null +++ b/x-pack/plugins/secops/server/lib/framework/adapter_types.ts @@ -0,0 +1,30 @@ +/* + * 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 { GraphQLSchema } from 'graphql'; + +export * from '../../../common/graphql/typed_resolvers'; + +export const internalFrameworkRequest = Symbol('internalFrameworkRequest'); + +export interface FrameworkAdapter { + version: string; + exposeStaticDir(urlPath: string, dir: string): void; + registerGraphQLEndpoint(routePath: string, schema: GraphQLSchema): void; +} + +export interface FrameworkRequest { + [internalFrameworkRequest]: InternalRequest; + payload: InternalRequest['payload']; + params: InternalRequest['params']; + query: InternalRequest['query']; +} + +export interface WrappableRequest { + payload: Payload; + params: Params; + query: Query; +} diff --git a/x-pack/plugins/secops/server/lib/framework/apollo_server_hapi.ts b/x-pack/plugins/secops/server/lib/framework/apollo_server_hapi.ts new file mode 100644 index 0000000000000..0af06c488e26e --- /dev/null +++ b/x-pack/plugins/secops/server/lib/framework/apollo_server_hapi.ts @@ -0,0 +1,117 @@ +/* + * 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 * as GraphiQL from 'apollo-server-module-graphiql'; +import Boom from 'boom'; +import { Plugin, Request, ResponseToolkit, RouteOptions, Server } from 'hapi'; + +import { GraphQLOptions, runHttpQuery } from 'apollo-server-core'; + +export type HapiOptionsFunction = (req: Request) => GraphQLOptions | Promise; + +export interface HapiGraphQLPluginOptions { + path: string; + vhost?: string; + route?: RouteOptions; + graphqlOptions: GraphQLOptions | HapiOptionsFunction; +} + +export const graphqlHapi: Plugin = { + name: 'graphql-secops', + register: (server: Server, options: HapiGraphQLPluginOptions) => { + if (!options || !options.graphqlOptions) { + throw new Error('Apollo Server requires options.'); + } + + server.route({ + options: options.route || {}, + handler: async (request: Request, h: ResponseToolkit) => { + try { + const query = + request.method === 'post' + ? (request.payload as Record) + : (request.query as Record); + + const gqlResponse = await runHttpQuery([request], { + method: request.method.toUpperCase(), + options: options.graphqlOptions, + query, + }); + + return h.response(gqlResponse).type('application/json'); + } catch (error) { + if ('HttpQueryError' !== error.name) { + const queryError = Boom.boomify(error); + + queryError.output.payload.message = error.message; + + return queryError; + } + + if (error.isGraphQLError === true) { + return h + .response(error.message) + .code(error.statusCode) + .type('application/json'); + } + + const genericError = new Boom(error.message, { statusCode: error.statusCode }); + + if (error.headers) { + Object.keys(error.headers).forEach(header => { + genericError.output.headers[header] = error.headers[header]; + }); + } + + // Boom hides the error when status code is 500 + + genericError.output.payload.message = error.message; + + throw genericError; + } + }, + method: ['GET', 'POST'], + path: options.path || '/graphql', + vhost: options.vhost || undefined, + }); + }, +}; + +export type HapiGraphiQLOptionsFunction = ( + req?: Request +) => GraphiQL.GraphiQLData | Promise; + +export interface HapiGraphiQLPluginOptions { + path: string; + + route?: any; + + graphiqlOptions: GraphiQL.GraphiQLData | HapiGraphiQLOptionsFunction; +} + +export const graphiqlHapi: Plugin = { + name: 'graphiql-secops', + register: (server: Server, options: HapiGraphiQLPluginOptions) => { + if (!options || !options.graphiqlOptions) { + throw new Error('Apollo Server GraphiQL requires options.'); + } + + server.route({ + options: options.route || {}, + handler: async (request: Request, h: ResponseToolkit) => { + const graphiqlString = await GraphiQL.resolveGraphiQLString( + request.query, + options.graphiqlOptions, + request + ); + + return h.response(graphiqlString).type('text/html'); + }, + method: 'GET', + path: options.path || '/graphiql', + }); + }, +}; diff --git a/x-pack/plugins/secops/server/lib/framework/index.ts b/x-pack/plugins/secops/server/lib/framework/index.ts new file mode 100644 index 0000000000000..4e09b5d0e9e2d --- /dev/null +++ b/x-pack/plugins/secops/server/lib/framework/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 * from './adapter_types'; diff --git a/x-pack/plugins/secops/server/lib/framework/kibana_framework_adapter.ts b/x-pack/plugins/secops/server/lib/framework/kibana_framework_adapter.ts new file mode 100644 index 0000000000000..3a35652198a1e --- /dev/null +++ b/x-pack/plugins/secops/server/lib/framework/kibana_framework_adapter.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 { GraphQLSchema } from 'graphql'; +import { Request, Server } from 'hapi'; + +import { + FrameworkAdapter, + FrameworkRequest, + internalFrameworkRequest, + WrappableRequest, +} from './adapter_types'; +import { + graphiqlHapi, + graphqlHapi, + HapiGraphiQLPluginOptions, + HapiGraphQLPluginOptions, +} from './apollo_server_hapi'; + +declare module 'hapi' { + interface PluginProperties { + elasticsearch: any; + kibana: any; + } +} + +export class KibanaBackendFrameworkAdapter implements FrameworkAdapter { + public version: string; + private server: Server; + + constructor(hapiServer: Server) { + this.server = hapiServer; + this.version = hapiServer.plugins.kibana.status.plugin.version; + } + + public exposeStaticDir(urlPath: string, dir: string): void { + this.server.route({ + handler: { + directory: { + path: dir, + }, + }, + method: 'GET', + path: urlPath, + }); + } + + public registerGraphQLEndpoint(routePath: string, schema: GraphQLSchema): void { + this.server.register({ + options: { + graphqlOptions: (req: Request) => ({ + context: { req: wrapRequest(req) }, + schema, + }), + path: routePath, + }, + plugin: graphqlHapi, + }); + + this.server.register({ + options: { + graphiqlOptions: { + endpointURL: routePath, + passHeader: `'kbn-version': '${this.version}'`, + }, + path: `${routePath}/graphiql`, + }, + plugin: graphiqlHapi, + }); + } +} + +export function wrapRequest( + req: InternalRequest +): FrameworkRequest { + const { params, payload, query } = req; + + return { + [internalFrameworkRequest]: req, + params, + payload, + query, + }; +} diff --git a/x-pack/plugins/secops/server/lib/sources/adapter_types.ts b/x-pack/plugins/secops/server/lib/sources/adapter_types.ts new file mode 100644 index 0000000000000..39672654e8562 --- /dev/null +++ b/x-pack/plugins/secops/server/lib/sources/adapter_types.ts @@ -0,0 +1,21 @@ +/* + * 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 { SourceConfiguration } from './index'; + +export type PartialSourceConfigurations = { + default?: PartialDefaultSourceConfiguration; +} & { + [sourceId: string]: PartialSourceConfiguration; +}; + +export type PartialDefaultSourceConfiguration = { + fields?: Partial; +} & Partial>>; + +export type PartialSourceConfiguration = { + fields?: Partial; +} & Pick>; diff --git a/x-pack/plugins/secops/server/lib/sources/configuration_sources_adapter.test.ts b/x-pack/plugins/secops/server/lib/sources/configuration_sources_adapter.test.ts new file mode 100644 index 0000000000000..76e12166cdd31 --- /dev/null +++ b/x-pack/plugins/secops/server/lib/sources/configuration_sources_adapter.test.ts @@ -0,0 +1,111 @@ +/* + * 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 { InmemoryConfigurationAdapter } from '../configuration/inmemory_configuration_adapter'; +import { PartialSourceConfiguration } from './adapter_types'; +import { ConfigurationSourcesAdapter } from './configuration_sources_adapter'; + +describe('the ConfigurationSourcesAdapter', () => { + test('adds the default source when no sources are configured', async () => { + const sourcesAdapter = new ConfigurationSourcesAdapter( + new InmemoryConfigurationAdapter({ sources: {} }) + ); + + expect(await sourcesAdapter.getAll()).toMatchObject({ + default: { + metricAlias: expect.any(String), + logAlias: expect.any(String), + fields: { + container: expect.any(String), + host: expect.any(String), + message: expect.arrayContaining([expect.any(String)]), + pod: expect.any(String), + tiebreaker: expect.any(String), + timestamp: expect.any(String), + }, + }, + }); + }); + + test('adds missing aliases to default source when they are missing from the configuration', async () => { + const sourcesAdapter = new ConfigurationSourcesAdapter( + new InmemoryConfigurationAdapter({ + sources: { + default: {} as PartialSourceConfiguration, + }, + }) + ); + + expect(await sourcesAdapter.getAll()).toMatchObject({ + default: { + metricAlias: expect.any(String), + logAlias: expect.any(String), + }, + }); + }); + + test('adds missing fields to default source when they are missing from the configuration', async () => { + const sourcesAdapter = new ConfigurationSourcesAdapter( + new InmemoryConfigurationAdapter({ + sources: { + default: { + metricAlias: 'METRIC_ALIAS', + logAlias: 'LOG_ALIAS', + fields: { + container: 'DIFFERENT_CONTAINER_FIELD', + }, + } as PartialSourceConfiguration, + }, + }) + ); + + expect(await sourcesAdapter.getAll()).toMatchObject({ + default: { + metricAlias: 'METRIC_ALIAS', + logAlias: 'LOG_ALIAS', + fields: { + container: 'DIFFERENT_CONTAINER_FIELD', + host: expect.any(String), + message: expect.arrayContaining([expect.any(String)]), + pod: expect.any(String), + tiebreaker: expect.any(String), + timestamp: expect.any(String), + }, + }, + }); + }); + + test('adds missing fields to non-default sources when they are missing from the configuration', async () => { + const sourcesAdapter = new ConfigurationSourcesAdapter( + new InmemoryConfigurationAdapter({ + sources: { + sourceOne: { + metricAlias: 'METRIC_ALIAS', + logAlias: 'LOG_ALIAS', + fields: { + container: 'DIFFERENT_CONTAINER_FIELD', + }, + }, + }, + }) + ); + + expect(await sourcesAdapter.getAll()).toMatchObject({ + sourceOne: { + metricAlias: 'METRIC_ALIAS', + logAlias: 'LOG_ALIAS', + fields: { + container: 'DIFFERENT_CONTAINER_FIELD', + host: expect.any(String), + message: expect.arrayContaining([expect.any(String)]), + pod: expect.any(String), + tiebreaker: expect.any(String), + timestamp: expect.any(String), + }, + }, + }); + }); +}); diff --git a/x-pack/plugins/secops/server/lib/sources/configuration_sources_adapter.ts b/x-pack/plugins/secops/server/lib/sources/configuration_sources_adapter.ts new file mode 100644 index 0000000000000..309ecffd4db94 --- /dev/null +++ b/x-pack/plugins/secops/server/lib/sources/configuration_sources_adapter.ts @@ -0,0 +1,63 @@ +/* + * 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 { ConfigurationAdapter } from '../configuration'; +import { PartialSourceConfigurations } from './adapter_types'; +import { SourceConfigurations, SourcesAdapter } from './index'; + +interface ConfigurationWithSources { + sources?: PartialSourceConfigurations; +} + +export class ConfigurationSourcesAdapter implements SourcesAdapter { + private readonly configuration: ConfigurationAdapter; + + constructor(configuration: ConfigurationAdapter) { + this.configuration = configuration; + } + + public async getAll() { + const sourceConfigurations = (await this.configuration.get()).sources || { + default: DEFAULT_SOURCE, + }; + const sourceConfigurationsWithDefault = { + ...sourceConfigurations, + default: { + ...DEFAULT_SOURCE, + ...(sourceConfigurations.default || {}), + }, + } as PartialSourceConfigurations; + + return Object.entries(sourceConfigurationsWithDefault).reduce( + (result, [sourceId, sourceConfiguration]) => + ({ + ...result, + [sourceId]: { + ...sourceConfiguration, + fields: { + ...DEFAULT_FIELDS, + ...(sourceConfiguration.fields || {}), + }, + }, + } as SourceConfigurations), + {} + ); + } +} + +const DEFAULT_FIELDS = { + container: 'docker.container.name', + host: 'beat.hostname', + message: ['message', '@message'], + pod: 'kubernetes.pod.name', + tiebreaker: '_doc', + timestamp: '@timestamp', +}; + +const DEFAULT_SOURCE = { + metricAlias: 'metricbeat-*', + logAlias: 'filebeat-*', + fields: DEFAULT_FIELDS, +}; diff --git a/x-pack/plugins/secops/server/lib/sources/index.ts b/x-pack/plugins/secops/server/lib/sources/index.ts new file mode 100644 index 0000000000000..d49451dde5de3 --- /dev/null +++ b/x-pack/plugins/secops/server/lib/sources/index.ts @@ -0,0 +1,45 @@ +/* + * 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 { ConfigurationSourcesAdapter } from './configuration_sources_adapter'; + +export class Sources { + constructor(private readonly adapter: SourcesAdapter) {} + + public async getConfiguration(sourceId: string) { + const sourceConfigurations = await this.getAllConfigurations(); + const requestedSourceConfiguration = sourceConfigurations[sourceId]; + + if (!requestedSourceConfiguration) { + throw new Error(`Failed to find source '${sourceId}'`); + } + + return requestedSourceConfiguration; + } + + public getAllConfigurations() { + return this.adapter.getAll(); + } +} + +export interface SourcesAdapter { + getAll(): Promise; +} + +export interface SourceConfigurations { + [sourceId: string]: SourceConfiguration; +} + +export interface SourceConfiguration { + fields: { + container: string; + host: string; + message: string[]; + pod: string; + tiebreaker: string; + timestamp: string; + }; +} diff --git a/x-pack/plugins/secops/server/lib/types.ts b/x-pack/plugins/secops/server/lib/types.ts new file mode 100644 index 0000000000000..8f79dde4be45f --- /dev/null +++ b/x-pack/plugins/secops/server/lib/types.ts @@ -0,0 +1,32 @@ +/* + * 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 { ConfigurationAdapter } from './configuration'; +import { FrameworkAdapter, FrameworkRequest } from './framework'; +import { SourceConfigurations, Sources } from './sources'; + +export interface AppDomainLibs { + hello: string; +} + +export interface AppBackendLibs extends AppDomainLibs { + configuration: ConfigurationAdapter; + framework: FrameworkAdapter; + sources: Sources; +} + +export interface Configuration { + enabled: boolean; + query: { + partitionSize: number; + partitionFactor: number; + }; + sources: SourceConfigurations; +} + +export interface Context { + req: FrameworkRequest; +} diff --git a/x-pack/plugins/secops/yarn.lock b/x-pack/plugins/secops/yarn.lock new file mode 100644 index 0000000000000..d0e11d6d6d3cd --- /dev/null +++ b/x-pack/plugins/secops/yarn.lock @@ -0,0 +1,37 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/boom@^7.2.0": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@types/boom/-/boom-7.2.1.tgz#a21e21ba08cc49d17b26baef98e1a77ee4d6cdb0" + integrity sha512-kOiap+kSa4DPoookJXQGQyKy1rjZ55tgfKAh9F0m1NUdukkcwVzpSnXPMH42a5L+U++ugdQlh/xFJu/WAdr1aw== + +"@types/color-convert@*": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@types/color-convert/-/color-convert-1.9.0.tgz#bfa8203e41e7c65471e9841d7e306a7cd8b5172d" + integrity sha512-OKGEfULrvSL2VRbkl/gnjjgbbF7ycIlpSsX7Nkab4MOWi5XxmgBYvuiQ7lcCFY5cPDz7MUNaKgxte2VRmtr4Fg== + dependencies: + "@types/color-name" "*" + +"@types/color-name@*": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.0.tgz#926f76f7e66f49cc59ad880bb15b030abbf0b66d" + integrity sha512-gZ/Rb+MFXF0pXSEQxdRoPMm5jeO3TycjOdvbpbcpHX/B+n9AqaHFe5q6Ga9CsZ7ir/UgIWPfrBzUzn3F19VH/w== + +"@types/color@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/color/-/color-3.0.0.tgz#40f8a6bf2fd86e969876b339a837d8ff1b0a6e30" + integrity sha512-5qqtNia+m2I0/85+pd2YzAXaTyKO8j+svirO5aN+XaQJ5+eZ8nx0jPtEWZLxCi50xwYsX10xUHetFzfb1WEs4Q== + dependencies: + "@types/color-convert" "*" + +"@types/lodash@^4.14.110": + version "4.14.117" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.117.tgz#695a7f514182771a1e0f4345d189052ee33c8778" + integrity sha512-xyf2m6tRbz8qQKcxYZa7PA4SllYcay+eh25DN3jmNYY6gSTL7Htc/bttVdkqj2wfJGbeWlQiX8pIyJpKU+tubw== + +lodash@^4.17.10: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== diff --git a/x-pack/yarn.lock b/x-pack/yarn.lock index 75f308e00caa0..151f5f9baf1a3 100644 --- a/x-pack/yarn.lock +++ b/x-pack/yarn.lock @@ -67,6 +67,24 @@ resolved "https://registry.yarnpkg.com/@elastic/numeral/-/numeral-2.3.2.tgz#06c9ef22f18dd8c2b39ffe353868d4d0c13ea4f9" integrity sha1-BsnvIvGN2MKzn/41OGjU0ME+pPk= +"@graphql-modules/epoxy@0.1.6": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@graphql-modules/epoxy/-/epoxy-0.1.6.tgz#f0555d72f5477f5a65bf880397137f422fb5bda5" + integrity sha512-DYq1RfTXEEaTYS2cKCTPNCdr6uCj3JgrERQjUMpn0bSBM28V2ncnx5ycDL+w2p/gnYiFD5LfHSJNnQ5u8/79Zg== + dependencies: + "@graphql-modules/logger" "0.1.6" + "@types/deepmerge" "2.1.0" + deepmerge "2.1.1" + graphql-tools "3.1.1" + +"@graphql-modules/logger@0.1.6": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@graphql-modules/logger/-/logger-0.1.6.tgz#89da70baf9e5802f5dc970a501f500bdbd8efedf" + integrity sha512-gh2etdA4kHHXKiHQMhqub9eVBhr8rfi7Pe6/TLx/9Dmm7Ikqy0FvyDvg1zSstP5dRgGj5xm7z1EP8wxSxWHg2w== + dependencies: + moment "2.22.2" + winston "3.0.0" + "@kbn/datemath@link:../packages/kbn-datemath": version "0.0.0" uid "" @@ -231,6 +249,11 @@ resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-1.0.8.tgz#6c083127b330b3c2fc65cd0f3a6e9cbd9607b28c" integrity sha512-/UCphyyw97YAq4zKsuXH33R3UNB4jDSza0fLvMubWr/ONh9IePi1NbgFP222blhiCe724ebJs8U87+aDuAq/jA== +"@types/deepmerge@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@types/deepmerge/-/deepmerge-2.1.0.tgz#22f175e5cb55874fe818caa6fd50a1d98fc3d748" + integrity sha512-/0Ct/q5g+SgaACZ+A0ylY3071nEBN7QDnTWiCtaB3fx24UpoAQXf25yNVloOYVUis7jytM1F1WC78+EOwXkQJQ== + "@types/delay@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/delay/-/delay-2.0.1.tgz#61bcf318a74b61e79d1658fbf054f984c90ef901" @@ -275,10 +298,10 @@ resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.13.1.tgz#7d39750355c9ecb921816d6f76c080405b5f6bea" integrity sha512-a6vRcP4M6+7Lqev1JeF3hGFmC3FNBIJ5cRnaSN/z1LtGVr/CaY6nqSlQbnFr2j8ucDlUAQU43LCnJrz6uLUyHg== -"@types/handlebars@4.0.38": - version "4.0.38" - resolved "https://registry.yarnpkg.com/@types/handlebars/-/handlebars-4.0.38.tgz#d0ebec1934c0bba97f99a0cb703fe2ef8c4a662f" - integrity sha512-oMzU0D7jDp+H2go/i0XqBHfr+HEhYD/e1TvkhHi3yrhQm/7JFR8FJMdvoH76X8G1FBpgc6Pwi+QslCJBeJ1N9g== +"@types/handlebars@4.0.39": + version "4.0.39" + resolved "https://registry.yarnpkg.com/@types/handlebars/-/handlebars-4.0.39.tgz#961fb54db68030890942e6aeffe9f93a957807bd" + integrity sha512-vjaS7Q0dVqFp85QhyPSZqDKnTTCemcSHNHFvDdalO1s0Ifz5KuE64jQD5xoUkfdWwF4WpqdJEl7LsWH8rzhKJA== "@types/hapi@^17.0.18": version "17.0.18" @@ -311,6 +334,11 @@ dependencies: "@types/node" "*" +"@types/is-glob@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/is-glob/-/is-glob-4.0.0.tgz#fb8a2bff539025d4dcd6d5efe7689e03341b876d" + integrity sha512-zC/2EmD8scdsGIeE+Xg7kP7oi9VP90zgMQtm9Cr25av4V+a+k8slQyiT60qSw8KORYrOKlPXfHwoa1bQbRzskQ== + "@types/is-stream@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@types/is-stream/-/is-stream-1.1.0.tgz#b84d7bb207a210f2af9bed431dc0fbe9c4143be1" @@ -396,10 +424,10 @@ resolved "https://registry.yarnpkg.com/@types/podium/-/podium-1.0.0.tgz#bfaa2151be2b1d6109cc69f7faa9dac2cba3bb20" integrity sha1-v6ohUb4rHWEJzGn3+qnawsujuyA= -"@types/prettier@1.13.1": - version "1.13.1" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.13.1.tgz#5dd359398de96863a0629156f382913a06ebe013" - integrity sha512-OlcCdqLtMvl+Hq4UkAxxppKX252NXsBm6RyJZVuBZtkduu3Dl8pdx78XS4K7oPGPOxpD6T+KzK0DV11G8ykTkw== +"@types/prettier@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.13.2.tgz#ffe96278e712a8d4e467e367a338b05e22872646" + integrity sha512-k6MCN8WuDiCj6O+UJsVMbrreZxkbrhQbO02oDj6yuRu8UAkp0MDdEcDKif8/gBKuJbT84kkO+VHQAqXkumEklg== "@types/prop-types@^15.5.3": version "15.5.3" @@ -455,6 +483,13 @@ dependencies: csstype "^2.2.0" +"@types/recompose@^0.26.0": + version "0.26.5" + resolved "https://registry.yarnpkg.com/@types/recompose/-/recompose-0.26.5.tgz#8496b63c535a60c3584b8b0aca54bfb86679ed70" + integrity sha512-Il5stz/Z3pVIMl48pyggl6nnhRLQ8N8YN8hi0Anm0M5UjVh2uMSY0ah2vzwZZKxnca4NzyJArloSjsJ9fL2vWw== + dependencies: + "@types/react" "*" + "@types/reduce-reducers@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@types/reduce-reducers/-/reduce-reducers-0.1.3.tgz#69f252207622ced7e063c7526ad46ec60b69f0c0" @@ -866,6 +901,14 @@ apollo-link@^1.0.0, apollo-link@^1.2.2: apollo-utilities "^1.0.0" zen-observable-ts "^0.8.9" +apollo-link@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.3.tgz#9bd8d5fe1d88d31dc91dae9ecc22474d451fb70d" + integrity sha512-iL9yS2OfxYhigme5bpTbmRyC+Htt6tyo2fRMHT3K1XRL/C5IQDDz37OjpPy4ndx7WInSvfSZaaOTKFja9VWqSw== + dependencies: + apollo-utilities "^1.0.0" + zen-observable-ts "^0.8.10" + apollo-server-core@^1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-1.3.6.tgz#08636243c2de56fa8c267d68dd602cb1fbd323e3" @@ -1186,18 +1229,13 @@ async@^2.1.4: dependencies: lodash "^4.14.0" -async@^2.5.0: +async@^2.5.0, async@^2.6.0: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== dependencies: lodash "^4.17.10" -async@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9" - integrity sha1-+PwEyjoTeErenhZBr5hXjPvWR6k= - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -2491,31 +2529,72 @@ color-convert@^1.9.0: dependencies: color-name "^1.1.1" -color-name@^1.1.1: +color-convert@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3, color-name@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +color-name@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.5.2: + version "1.5.3" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" + integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + color-support@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== +color@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a" + integrity sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + +colornames@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96" + integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y= + colors@0.5.x: version "0.5.1" resolved "https://registry.yarnpkg.com/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774" integrity sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q= -colors@1.0.x: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= +colors@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.2.tgz#2df8ff573dfbf255af562f8ce7181d6b971a359b" + integrity sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ== colors@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM= +colorspace@1.1.x: + version "1.1.1" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.1.tgz#9ac2491e1bc6f8fb690e2176814f8d091636d972" + integrity sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw== + dependencies: + color "3.0.x" + text-hex "1.0.x" + combined-stream@1.0.6, combined-stream@~1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" @@ -2545,10 +2624,10 @@ commander@2.15.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== -commander@2.16.0: - version "2.16.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" - integrity sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew== +commander@2.18.0: + version "2.18.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" + integrity sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ== commander@~2.17.1: version "2.17.1" @@ -2871,11 +2950,6 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" -cycle@1.0.x: - version "1.0.3" - resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" - integrity sha1-IegLK+hYD5i0aPN5QwZisEbDStI= - cyclist@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" @@ -3102,6 +3176,11 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +deepmerge@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.1.1.tgz#e862b4e45ea0555072bf51e7fd0d9845170ae768" + integrity sha512-urQxA1smbLZ2cBbXbaYObM1dJ82aJ2H57A1C/Kklfh/ZN1bgH4G/n5KWhdNfOK11W98gqZfyYj7W4frJJRwA2w== + default-require-extensions@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" @@ -3224,6 +3303,15 @@ dfa@^1.0.0: dependencies: babel-runtime "^6.11.6" +diagnostics@^1.0.1, diagnostics@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a" + integrity sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ== + dependencies: + colorspace "1.1.x" + enabled "1.0.x" + kuler "1.0.x" + diff@3.5.0, diff@^3.1.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -3392,6 +3480,13 @@ emojis-list@^2.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= +enabled@1.0.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93" + integrity sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M= + dependencies: + env-variable "0.0.x" + encoding@^0.1.11: version "0.1.12" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" @@ -3460,6 +3555,11 @@ entities@^1.1.1, entities@~1.1.1: resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA= +env-variable@0.0.x: + version "0.0.5" + resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88" + integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA== + enzyme-adapter-react-16@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.1.1.tgz#a8f4278b47e082fbca14f5bfb1ee50ee650717b4" @@ -3852,11 +3952,6 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -eyes@0.1.x: - version "0.1.8" - resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" - integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= - falafel@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/falafel/-/falafel-2.1.0.tgz#96bb17761daba94f46d001738b3cedf3a67fe06c" @@ -3896,7 +3991,12 @@ fast-levenshtein@~2.0.4: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fb-watchman@^2.0.0: +fast-safe-stringify@^2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz#04b26106cc56681f51a044cfc0d76cf0008ac2c2" + integrity sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg== + +fb-watchman@2.0.0, fb-watchman@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" integrity sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg= @@ -3943,6 +4043,11 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" +fecha@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd" + integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg== + fetch-mock@^5.13.1: version "5.13.1" resolved "https://registry.yarnpkg.com/fetch-mock/-/fetch-mock-5.13.1.tgz#955794a77f3d972f1644b9ace65a0fdfd60f1df7" @@ -4473,6 +4578,18 @@ glob@7.1.2, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glo once "^1.3.0" path-is-absolute "^1.0.0" +glob@7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^4.3.1: version "4.5.3" resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" @@ -4646,55 +4763,63 @@ graphql-anywhere@^4.1.16: dependencies: apollo-utilities "^1.0.18" -graphql-code-generator@^0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/graphql-code-generator/-/graphql-code-generator-0.10.1.tgz#b1c05b726ad4c9078a609233cb364eeeb512b5ab" - integrity sha1-scBbcmrUyQeKYJIzyzZO7rUStas= +graphql-code-generator@^0.12.6: + version "0.12.6" + resolved "https://registry.yarnpkg.com/graphql-code-generator/-/graphql-code-generator-0.12.6.tgz#72835046d6c833834d616135c59ad19b7af85d24" + integrity sha512-GSU06AJ4sPsqVKpKzK2KfQM+D2WtnGoazey5iLVUfef5LSYNJqFGsCHMN6bTcCoBLUTXs5gq79yaQvJp5P2gbg== dependencies: + "@graphql-modules/epoxy" "0.1.6" "@types/babylon" "6.16.3" - "@types/prettier" "1.13.1" + "@types/is-glob" "4.0.0" + "@types/prettier" "1.13.2" "@types/valid-url" "1.0.2" babel-types "7.0.0-beta.3" babylon "7.0.0-beta.47" - commander "2.16.0" - glob "7.1.2" - graphql-codegen-compiler "0.10.1" - graphql-codegen-core "0.10.1" + commander "2.18.0" + fb-watchman "2.0.0" + glob "7.1.3" + graphql-codegen-compiler "0.12.6" + graphql-codegen-core "0.12.6" + graphql-import "0.7.1" + is-glob "4.0.0" + is-valid-path "0.1.1" mkdirp "0.5.1" - prettier "1.13.7" - request "2.87.0" + pify "4.0.0" + prettier "1.14.3" + request "2.88.0" valid-url "1.0.9" -graphql-codegen-compiler@0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/graphql-codegen-compiler/-/graphql-codegen-compiler-0.10.1.tgz#de9a6dd037a665a1ad276b3366987e8a5f58bb9f" - integrity sha1-3ppt0DemZaGtJ2szZph+il9Yu58= +graphql-codegen-compiler@0.12.6: + version "0.12.6" + resolved "https://registry.yarnpkg.com/graphql-codegen-compiler/-/graphql-codegen-compiler-0.12.6.tgz#26b8e4c0fe4003c7feb9091d6b259c2505dd837d" + integrity sha512-f/GP19sMsXggdQHZLb7uZVaiuhDX/EqadeaZI9bRfPaALK02hLIOizTYQBKOVMExSmgj3Hiz6DGgu61gRO6z1w== dependencies: - "@types/handlebars" "4.0.38" + "@types/handlebars" "4.0.39" change-case "3.0.2" common-tags "1.8.0" - graphql-codegen-core "0.10.1" - handlebars "4.0.11" + graphql-codegen-core "0.12.6" + handlebars "4.0.12" moment "2.22.2" -graphql-codegen-core@0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/graphql-codegen-core/-/graphql-codegen-core-0.10.1.tgz#f7ab790b050f14b133c5a28f2260cdd8d1e7792d" - integrity sha1-96t5CwUPFLEzxaKPImDN2NHneS0= +graphql-codegen-core@0.12.6: + version "0.12.6" + resolved "https://registry.yarnpkg.com/graphql-codegen-core/-/graphql-codegen-core-0.12.6.tgz#ab3d4d9b0bd10268de749ae215eba84f7bb98fdb" + integrity sha512-yRdLsPEd3b4bJ9aYalGVwa7XKNNK3DP85Yq0nCPcqbfj+OnR7xiVNbfd/oshQ4Mb05QOzSw7sDKBVluA0WTXog== dependencies: graphql-tag "2.9.2" - graphql-tools "3.0.4" - winston "2.4.3" + graphql-tools "4.0.0" + ts-log "2.1.3" + winston "3.1.0" -graphql-codegen-introspection-template@^0.10.5: - version "0.10.5" - resolved "https://registry.yarnpkg.com/graphql-codegen-introspection-template/-/graphql-codegen-introspection-template-0.10.5.tgz#c8c0f647a9771c4e3c6ffbe26aa8da15af9af661" - integrity sha1-yMD2R6l3HE48b/viaqjaFa+a9mE= +graphql-codegen-introspection-template@^0.12.6: + version "0.12.6" + resolved "https://registry.yarnpkg.com/graphql-codegen-introspection-template/-/graphql-codegen-introspection-template-0.12.6.tgz#57e37384d1dd7fba14a0ac4fc8c989f56a358d8c" + integrity sha512-oHgsqz17oxBC84KT/srzBMCN4fByhe0yMMXaEiUuNQyrcj26eWP2qQBygheYAlcED3cYQ/eW8PL9dwphWxT9iQ== -graphql-codegen-typescript-template@^0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/graphql-codegen-typescript-template/-/graphql-codegen-typescript-template-0.10.1.tgz#bb631d2ebfcd8f15117ca642a9988bd767183e02" - integrity sha1-u2MdLr/NjxURfKZCqZiL12cYPgI= +graphql-codegen-typescript-template@^0.12.6: + version "0.12.6" + resolved "https://registry.yarnpkg.com/graphql-codegen-typescript-template/-/graphql-codegen-typescript-template-0.12.6.tgz#3120089a7aea93373261377b0e0f89792c8bb5ad" + integrity sha512-Qn0EvuFwOmUy4drNEugczNdSmpNtFjJ3oJAdvLW1nnM54GNMlm+9LJLmZfifjG1uB4nvKORV9+v3dY2fKrxaKQ== graphql-extensions@^0.0.x, graphql-extensions@~0.0.9: version "0.0.10" @@ -4709,12 +4834,42 @@ graphql-fields@^1.0.2: resolved "https://registry.yarnpkg.com/graphql-fields/-/graphql-fields-1.0.2.tgz#099ee1d4445b42d0f47e06d622acebb33abc6cce" integrity sha1-CZ7h1ERbQtD0fgbWIqzrszq8bM4= +graphql-import@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/graphql-import/-/graphql-import-0.7.1.tgz#4add8d91a5f752d764b0a4a7a461fcd93136f223" + integrity sha512-YpwpaPjRUVlw2SN3OPljpWbVRWAhMAyfSba5U47qGMOSsPLi2gYeJtngGpymjm9nk57RFWEpjqwh4+dpYuFAPw== + dependencies: + lodash "^4.17.4" + resolve-from "^4.0.0" + graphql-tag@2.9.2, graphql-tag@^2.9.2: version "2.9.2" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.9.2.tgz#2f60a5a981375f430bf1e6e95992427dc18af686" integrity sha512-qnNmof9pAqj/LUzs3lStP0Gw1qhdVCUS7Ab7+SUB6KD5aX1uqxWQRwMnOGTkhKuLvLNIs1TvNz+iS9kUGl1MhA== -graphql-tools@3.0.4, graphql-tools@^3.0.2: +graphql-tools@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-3.1.1.tgz#d593358f01e7c8b1671a17b70ddb034dea9dbc50" + integrity sha512-yHvPkweUB0+Q/GWH5wIG60bpt8CTwBklCSzQdEHmRUgAdEQKxw+9B7zB3dG7wB3Ym7M7lfrS4Ej+jtDZfA2UXg== + dependencies: + apollo-link "^1.2.2" + apollo-utilities "^1.0.1" + deprecated-decorator "^0.1.6" + iterall "^1.1.3" + uuid "^3.1.0" + +graphql-tools@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-4.0.0.tgz#6ea01937c6f947212f83567ba687e97c22fdd2a6" + integrity sha512-WokvjkanuZwY4BZBS3SlkDjrjCPu7WlCtLB2i9JiiXembVEkNos3Rl90zf7sJu72zSidGzTXU63iXRO2Fg3TtA== + dependencies: + apollo-link "^1.2.3" + apollo-utilities "^1.0.1" + deprecated-decorator "^0.1.6" + iterall "^1.1.3" + uuid "^3.1.0" + +graphql-tools@^3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-3.0.4.tgz#d08aa75db111d704cba05d92afd67ec5d1dc6b24" integrity sha512-doQeqej/1D7kowXjYaAKk9H04KZN6+Vm6/KqXk3iqq8kfeI5edHOCg+eDc4LZXb0EEue0vy76JW7TLOwf9ZMZQ== @@ -4838,18 +4993,7 @@ gulplog@^1.0.0: dependencies: glogg "^1.0.0" -handlebars@4.0.11, handlebars@^4.0.3: - version "4.0.11" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" - integrity sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw= - dependencies: - async "^1.4.0" - optimist "^0.6.1" - source-map "^0.4.4" - optionalDependencies: - uglify-js "^2.6" - -handlebars@^4.0.10: +handlebars@4.0.12, handlebars@^4.0.10: version "4.0.12" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" integrity sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA== @@ -4860,6 +5004,17 @@ handlebars@^4.0.10: optionalDependencies: uglify-js "^3.1.4" +handlebars@^4.0.3: + version "4.0.11" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" + integrity sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw= + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + hapi-auth-cookie@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/hapi-auth-cookie/-/hapi-auth-cookie-9.0.0.tgz#3b0af443334e2bd92490ddb17bed16e3e9edfd01" @@ -5444,6 +5599,11 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -5563,6 +5723,13 @@ is-generator-fn@^1.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-1.0.0.tgz#969d49e1bb3329f6bb7f09089be26578b2ddd46a" integrity sha1-lp1J4bszKfa7fwkIm+JleLLd1Go= +is-glob@4.0.0, is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= + dependencies: + is-extglob "^2.1.1" + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -5577,12 +5744,12 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" - integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= +is-invalid-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-invalid-path/-/is-invalid-path-0.1.0.tgz#307a855b3cf1a938b44ea70d2c61106053714f34" + integrity sha1-MHqFWzzxqTi0TqcNLGEQYFNxTzQ= dependencies: - is-extglob "^2.1.1" + is-glob "^2.0.0" is-lower-case@^1.1.0: version "1.1.3" @@ -5752,6 +5919,13 @@ is-valid-glob@^1.0.0: resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa" integrity sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao= +is-valid-path@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-valid-path/-/is-valid-path-0.1.1.tgz#110f9ff74c37f663e1ec7915eb451f2db93ac9df" + integrity sha1-EQ+f90w39mPh7HkV60UfLbk6yd8= + dependencies: + is-invalid-path "^0.1.0" + is-windows@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.1.tgz#310db70f742d259a16a369202b51af84233310d9" @@ -5799,7 +5973,7 @@ isomorphic-fetch@2.2.1, isomorphic-fetch@^2.1.1: node-fetch "^1.0.1" whatwg-fetch ">=0.10.0" -isstream@0.1.x, isstream@~0.1.2: +isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= @@ -6499,6 +6673,13 @@ kleur@^2.0.1: resolved "https://registry.yarnpkg.com/kleur/-/kleur-2.0.2.tgz#b704f4944d95e255d038f0cb05fb8a602c55a300" integrity sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ== +kuler@1.0.x: + version "1.0.1" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-1.0.1.tgz#ef7c784f36c9fb6e16dd3150d152677b2b0228a6" + integrity sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ== + dependencies: + colornames "^1.1.1" + lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" @@ -6964,6 +7145,17 @@ lodash@~1.0.1: resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551" integrity sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE= +logform@^1.9.0, logform@^1.9.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/logform/-/logform-1.10.0.tgz#c9d5598714c92b546e23f4e78147c40f1e02012e" + integrity sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg== + dependencies: + colors "^1.2.1" + fast-safe-stringify "^2.0.4" + fecha "^2.3.3" + ms "^2.1.1" + triple-beam "^1.2.0" + loglevel@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa" @@ -7899,6 +8091,11 @@ once@~1.3.0: dependencies: wrappy "1" +one-time@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e" + integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4= + onetime@^1.0.0: version "1.1.0" resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" @@ -8333,6 +8530,11 @@ pez@4.x.x: hoek "5.x.x" nigel "3.x.x" +pify@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.0.tgz#db04c982b632fd0df9090d14aaf1c8413cadb695" + integrity sha512-zrSP/KDf9DH3K3VePONoCstgPiYJy9z0SCatZuTpOc7YdnWIqwkWdXOuwlr4uDc7em8QZRsFWsT/685x5InjYg== + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -8490,10 +8692,10 @@ preserve@^0.2.0: resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= -prettier@1.13.7: - version "1.13.7" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281" - integrity sha512-KIU72UmYPGk4MujZGYMFwinB7lOf2LsDNGSOC8ufevsrPLISrZbNJlWstRi3m0AMuszbH+EFSQ/r6w56RSPK6w== +prettier@1.14.3: + version "1.14.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.14.3.tgz#90238dd4c0684b7edce5f83b0fb7328e48bd0895" + integrity sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg== pretty-format@^23.6.0: version "23.6.0" @@ -9214,7 +9416,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== @@ -9509,31 +9711,31 @@ request@2.81.0, "request@>=2.9.0 <2.82.0": tunnel-agent "^0.6.0" uuid "^3.0.0" -request@2.87.0: - version "2.87.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" - integrity sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw== +request@2.88.0, request@^2.88.0: + version "2.88.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== dependencies: aws-sign2 "~0.7.0" - aws4 "^1.6.0" + aws4 "^1.8.0" caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" + combined-stream "~1.0.6" + extend "~3.0.2" forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" + form-data "~2.3.2" + har-validator "~5.1.0" http-signature "~1.2.0" is-typedarray "~1.0.0" isstream "~0.1.2" json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" + mime-types "~2.1.19" + oauth-sign "~0.9.0" performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - tough-cookie "~2.3.3" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.4.3" tunnel-agent "^0.6.0" - uuid "^3.1.0" + uuid "^3.3.2" request@^2.83.0: version "2.83.0" @@ -9591,32 +9793,6 @@ request@^2.85.0: tunnel-agent "^0.6.0" uuid "^3.1.0" -request@^2.88.0: - version "2.88.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" - integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.0" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.4.3" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - request@~2.79.0: version "2.79.0" resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" @@ -9683,6 +9859,11 @@ resolve-from@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" integrity sha1-six699nWiBvItuZTM17rywoYh0g= +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-options@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131" @@ -10067,6 +10248,13 @@ simple-git@^1.91.0: dependencies: debug "^3.1.0" +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + sinon@^5.0.7: version "5.0.7" resolved "https://registry.yarnpkg.com/sinon/-/sinon-5.0.7.tgz#3bded6a73613ccc9e512e20246ced69a27c27dab" @@ -10781,6 +10969,11 @@ text-encoding@^0.6.4: resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19" integrity sha1-45mpgiV6J22uQou5KEXLcb3CbRk= +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + throat@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" @@ -11022,6 +11215,11 @@ trim-right@^1.0.1: resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= +triple-beam@^1.2.0, triple-beam@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" + integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== + "true-case-path@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.2.tgz#7ec91130924766c7f573be3020c34f8fdfd00d62" @@ -11029,6 +11227,11 @@ trim-right@^1.0.1: dependencies: glob "^6.0.4" +ts-log@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ts-log/-/ts-log-2.1.3.tgz#9e30aca1baffe7693a2e4142b8f07ecb01cb8340" + integrity sha512-VIk9+hzE80UjhJcSANst8LGRBpfNh32y9d3LVDMtEqcEb1x0hB71IO0aObNcLJ5VpK5tKeF9uI4pwEco03SkwA== + tslib@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" @@ -11604,17 +11807,43 @@ window-size@^0.2.0: resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" integrity sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU= -winston@2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.3.tgz#7a9fdab371b6d3d9b63a592947846d856948c517" - integrity sha512-GYKuysPz2pxYAVJD2NPsDLP5Z79SDEzPm9/j4tCjkF/n89iBNGBMJcR+dMUqxgPNgoSs6fVygPi+Vl2oxIpBuw== - dependencies: - async "~1.0.0" - colors "1.0.x" - cycle "1.0.x" - eyes "0.1.x" - isstream "0.1.x" +winston-transport@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.2.0.tgz#a20be89edf2ea2ca39ba25f3e50344d73e6520e5" + integrity sha512-0R1bvFqxSlK/ZKTH86nymOuKv/cT1PQBMuDdA7k7f0S9fM44dNH6bXnuxwXPrN8lefJgtZq08BKdyZ0DZIy/rg== + dependencies: + readable-stream "^2.3.6" + triple-beam "^1.2.0" + +winston@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.0.0.tgz#1f0b24a96586798bcf0cd149fb07ed47cb01a1b2" + integrity sha512-7QyfOo1PM5zGL6qma6NIeQQMh71FBg/8fhkSAePqtf5YEi6t+UrPDcUuHhuuUasgso49ccvMEsmqr0GBG2qaMQ== + dependencies: + async "^2.6.0" + diagnostics "^1.0.1" + is-stream "^1.1.0" + logform "^1.9.0" + one-time "0.0.4" + readable-stream "^2.3.6" stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.2.0" + +winston@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.1.0.tgz#80724376aef164e024f316100d5b178d78ac5331" + integrity sha512-FsQfEE+8YIEeuZEYhHDk5cILo1HOcWkGwvoidLrDgPog0r4bser1lEIOco2dN9zpDJ1M88hfDgZvxe5z4xNcwg== + dependencies: + async "^2.6.0" + diagnostics "^1.1.1" + is-stream "^1.1.0" + logform "^1.9.1" + one-time "0.0.4" + readable-stream "^2.3.6" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.2.0" wordwrap@0.0.2: version "0.0.2" @@ -11909,6 +12138,13 @@ yeast@0.1.2: resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= +zen-observable-ts@^0.8.10: + version "0.8.10" + resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.10.tgz#18e2ce1c89fe026e9621fd83cc05168228fce829" + integrity sha512-5vqMtRggU/2GhePC9OU4sYEWOdvmayp2k3gjPf4F0mXwB3CSbbNznfDUvDJx9O2ZTa1EIXdJhPchQveFKwNXPQ== + dependencies: + zen-observable "^0.8.0" + zen-observable-ts@^0.8.6, zen-observable-ts@^0.8.9: version "0.8.9" resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.9.tgz#d3c97af08c0afdca37ebcadf7cc3ee96bda9bab1"