Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Rename] kbn-config-schema to osd-config-schema #66

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# `@kbn/config-schema` — The Kibana config validation library
# `@osd/config-schema` — The OpenSearch Dashboards config validation library

`@kbn/config-schema` is a TypeScript library inspired by Joi and designed to allow run-time validation of the
Kibana configuration entries providing developers with a fully typed model of the validated data.
`@osd/config-schema` is a TypeScript library inspired by Joi and designed to allow run-time validation of the
OpenSearch Dashboards configuration entries providing developers with a fully typed model of the validated data.

## Table of Contents

- [Why `@kbn/config-schema`?](#why-kbnconfig-schema)
- [Why `@osd/config-schema`?](#why-osdconfig-schema)
- [Schema building blocks](#schema-building-blocks)
- [Basic types](#basic-types)
- [`schema.string()`](#schemastring)
Expand Down Expand Up @@ -35,14 +35,14 @@ Kibana configuration entries providing developers with a fully typed model of th
- [Custom validation](#custom-validation)
- [Default values](#default-values)

## Why `@kbn/config-schema`?
## Why `@osd/config-schema`?

Validation of externally supplied data is very important for Kibana. Especially if this data is used to configure how it operates.
Validation of externally supplied data is very important for OpenSearch Dashboards. Especially if this data is used to configure how it operates.

There are a number of reasons why we decided to roll our own solution for the configuration validation:

* **Limited API surface** - having a future rich library is awesome, but it's a really hard task to audit such library and make sure everything is sane and secure enough. As everyone knows complexity is the enemy of security and hence we'd like to have a full control over what exactly we expose and commit to maintain.
* **Custom error messages** - detailed validation error messages are a great help to developers, but at the same time they can contain information that's way too sensitive to expose to everyone. We'd like to control these messages and make them only as detailed as really needed. For example, we don't want validation error messages to contain the passwords for internal users to show-up in the logs. These logs are commonly ingested into Elasticsearch, and accessible to a large number of users which shouldn't have access to the internal user's password.
* **Custom error messages** - detailed validation error messages are a great help to developers, but at the same time they can contain information that's way too sensitive to expose to everyone. We'd like to control these messages and make them only as detailed as really needed. For example, we don't want validation error messages to contain the passwords for internal users to show-up in the logs. These logs are commonly ingested into OpenSearch Dashboards, and accessible to a large number of users which shouldn't have access to the internal user's password.
* **Type information** - having run-time guarantees is great, but additionally having compile-time guarantees is even better. We'd like to provide developers with a fully typed model of the validated data so that it's harder to misuse it _after_ validation.
* **Upgradability** - no matter how well a validation library is implemented, it will have bugs and may need to be improved at some point anyway. Some external libraries are very well supported, some aren't or won't be in the future. It's always a risk to depend on an external party with their own release cadence when you need to quickly fix a security vulnerability in a patch version. We'd like to have a better control over lifecycle of such an important piece of our codebase.

Expand Down Expand Up @@ -95,7 +95,7 @@ expect(() =>

__Notes:__
* `validate` method throws as soon as the first schema violation is encountered, no further validation is performed.
* when you retrieve configuration within a Kibana plugin `validate` function is called by the Core automatically providing appropriate namespace and context variables (environment name, package info etc.).
* when you retrieve configuration within a OpenSearch Dashboards plugin `validate` function is called by the Core automatically providing appropriate namespace and context variables (environment name, package info etc.).

### Basic types

Expand Down Expand Up @@ -478,8 +478,8 @@ valueSchema.validate({}, { envName: 'dev' });
```

__Notes:__
* The `@kbn/config-schema` neither validates nor coerces the "dereferenced" value and the developer is responsible for making sure that it has the appropriate type.
* The root context that Kibana provides during config validation includes lots of useful properties like `environment name` that can be used to provide a strict schema for production and more relaxed one for development.
* The `@osd/config-schema` neither validates nor coerces the "dereferenced" value and the developer is responsible for making sure that it has the appropriate type.
* The root context that OpenSearch Dashboards provides during config validation includes lots of useful properties like `environment name` that can be used to provide a strict schema for production and more relaxed one for development.

#### `schema.siblingRef()`

Expand All @@ -496,14 +496,14 @@ const valueSchema = schema.object({
```

__Notes:__
* The `@kbn/config-schema` neither validates nor coerces the "dereferenced" value and the developer is responsible for making sure that it has the appropriate type.
* The `@osd/config-schema` neither validates nor coerces the "dereferenced" value and the developer is responsible for making sure that it has the appropriate type.

## Custom validation

Using built-in schema primitives may not be enough in some scenarios or sometimes the attempt to model complex schemas with built-in primitives only may result in unreadable code.
For these cases `@kbn/config-schema` provides a way to specify a custom validation function for almost any schema building block through the `validate` option.
For these cases `@osd/config-schema` provides a way to specify a custom validation function for almost any schema building block through the `validate` option.

For example `@kbn/config-schema` doesn't have a dedicated primitive for the `RegExp` based validation currently, but you can easily do that with a custom `validate` function:
For example `@osd/config-schema` doesn't have a dedicated primitive for the `RegExp` based validation currently, but you can easily do that with a custom `validate` function:

```typescript
const valueSchema = schema.string({
Expand Down Expand Up @@ -552,4 +552,4 @@ const valueSchemaWithFunctionEvaluatedDefault = schema.string({ defaultValue: ()
```

__Notes:__
* `@kbn/config-schema` neither validates nor coerces default value and developer is responsible for making sure that it has the appropriate type.
* `@osd/config-schema` neither validates nor coerces default value and developer is responsible for making sure that it has the appropriate type.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "@kbn/config-schema",
"name": "@osd/config-schema",
"main": "./target/out/index.js",
"types": "./target/types/index.d.ts",
"version": "1.0.0",
"license": "Apache-2.0",
"private": true,
"scripts": {
"build": "tsc",
"kbn:bootstrap": "yarn build"
"osd:bootstrap": "yarn build"
},
"devDependencies": {
"typescript": "4.0.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export abstract class Type<V> {
public readonly type: V = null! as V;

// used for the `isConfigSchema` typeguard
public readonly __isKbnConfigSchemaType = true;
public readonly __isOsdConfigSchemaType = true;

/**
* Internal "schema" backed by Joi.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,18 @@ test('returns value for valid URI as per RFC3986', () => {
'http://tools.ietf.org/html/rfc3986'
);
expect(uriSchema.validate('udp://3domain.local')).toBe('udp://3domain.local');
expect(uriSchema.validate('urn:elastic:kibana')).toBe('urn:elastic:kibana');
expect(uriSchema.validate('urn:opensearch:opensearchDashboards')).toBe('urn:opensearch:opensearchDashboards');
expect(uriSchema.validate('ftp://ftp.ietf.org/rfc/rfc3986.txt')).toBe(
'ftp://ftp.ietf.org/rfc/rfc3986.txt'
);
expect(uriSchema.validate('mailto:Platform.Kibana@elastic.co')).toBe(
'mailto:Platform.Kibana@elastic.co'
expect(uriSchema.validate('mailto:Platform.opensearchDashboards@opensearch.co')).toBe(
'mailto:Platform.opensearchDashboards@opensearch.co'
);
expect(uriSchema.validate('tel:+500-111-222-333')).toBe('tel:+500-111-222-333');
expect(uriSchema.validate('file:///kibana.log')).toBe('file:///kibana.log');
expect(uriSchema.validate('http://elastic@localhost:9200')).toBe('http://elastic@localhost:9200');
expect(uriSchema.validate('http://elastic:changeme@localhost:9200')).toBe(
'http://elastic:changeme@localhost:9200'
expect(uriSchema.validate('file:///opensearch_dashboards.log')).toBe('file:///opensearch_dashboards.log');
expect(uriSchema.validate('http://opensearch@localhost:9200')).toBe('http://opensearch@localhost:9200');
expect(uriSchema.validate('http://opensearch:changeme@localhost:9200')).toBe(
'http://opensearch:changeme@localhost:9200'
);
expect(uriSchema.validate('ldap://[2001:db8::7]/c=GB?objectClass?one')).toBe(
'ldap://[2001:db8::7]/c=GB?objectClass?one'
Expand Down Expand Up @@ -79,17 +79,17 @@ describe('#scheme', () => {
test('returns value when URI has required scheme', () => {
const uriSchema = schema.uri({ scheme: ['http', 'https'] });

expect(uriSchema.validate('http://elastic.co')).toBe('http://elastic.co');
expect(uriSchema.validate('https://elastic.co')).toBe('https://elastic.co');
expect(uriSchema.validate('http://opensearch.co')).toBe('http://opensearch.co');
expect(uriSchema.validate('https://opensearch.co')).toBe('https://opensearch.co');
});

test('returns error when shorter string', () => {
const uriSchema = schema.uri({ scheme: ['http', 'https'] });

expect(() => uriSchema.validate('ftp://elastic.co')).toThrowErrorMatchingInlineSnapshot(
expect(() => uriSchema.validate('ftp://opensearch.co')).toThrowErrorMatchingInlineSnapshot(
`"expected URI with scheme [http|https]."`
);
expect(() => uriSchema.validate('file:///kibana.log')).toThrowErrorMatchingInlineSnapshot(
expect(() => uriSchema.validate('file:///opensearch_dashboards.log')).toThrowErrorMatchingInlineSnapshot(
`"expected URI with scheme [http|https]."`
);
});
Expand Down