-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Telemetry] Settings Collector: redact sensitive reported values #88675
Changes from 7 commits
bc32777
e81d8bf
a4bb8a0
1bf819a
5b6d98b
192963f
a9a1068
e8fb492
7b61956
ec3bc7d
21b3059
18e9e89
210d7b0
840d689
4dde310
0dd8b14
141b634
c9d1314
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<!-- Do not edit this file. It is automatically generated by API Documenter. --> | ||
|
||
[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [UiSettingsParams](./kibana-plugin-core-public.uisettingsparams.md) > [sensitive](./kibana-plugin-core-public.uisettingsparams.sensitive.md) | ||
|
||
## UiSettingsParams.sensitive property | ||
|
||
a flag indicating that value might contain user sensitive data. used by telemetry to mask the value of the setting when sent. | ||
|
||
<b>Signature:</b> | ||
|
||
```typescript | ||
sensitive?: boolean; | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<!-- Do not edit this file. It is automatically generated by API Documenter. --> | ||
|
||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IUiSettingsClient](./kibana-plugin-core-server.iuisettingsclient.md) > [isSensitive](./kibana-plugin-core-server.iuisettingsclient.issensitive.md) | ||
|
||
## IUiSettingsClient.isSensitive property | ||
|
||
Shows whether the uiSetting is a sensitive value. Used by telemetry to not send sensitive values. | ||
|
||
<b>Signature:</b> | ||
|
||
```typescript | ||
isSensitive: (key: string) => boolean; | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<!-- Do not edit this file. It is automatically generated by API Documenter. --> | ||
|
||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [UiSettingsParams](./kibana-plugin-core-server.uisettingsparams.md) > [sensitive](./kibana-plugin-core-server.uisettingsparams.sensitive.md) | ||
|
||
## UiSettingsParams.sensitive property | ||
|
||
a flag indicating that value might contain user sensitive data. used by telemetry to mask the value of the setting when sent. | ||
|
||
<b>Signature:</b> | ||
|
||
```typescript | ||
sensitive?: boolean; | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
* and the Server Side Public License, v 1; you may not use this file except in | ||
* compliance with, at your election, the Elastic License or the Server Side | ||
* Public License, v 1. | ||
*/ | ||
|
||
export interface UsageStats { | ||
withBooleanValue: boolean; | ||
withStringValue: string; | ||
withNumberValue: number; | ||
withStringArrayValue: string[]; | ||
withObjectValue: { withBooleanValue: boolean }; | ||
withObjectArrayValue: Array<{ withNumberValue: number }>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* and the Server Side Public License, v 1; you may not use this file except in | ||
* compliance with, at your election, the Elastic License or the Server Side | ||
* Public License, v 1. | ||
*/ | ||
|
||
import * as ts from 'typescript'; | ||
import * as path from 'path'; | ||
import { loadProgram } from './utils'; | ||
import { getInterfacesDescriptors } from './interface_to_object'; | ||
|
||
describe('getInterfacesDescriptors', () => { | ||
it('creates object descriptors from interfaces', async () => { | ||
const fixturePath = path.resolve(__dirname, '__fixture__', 'usage_stats_type.ts'); | ||
const { program } = loadProgram('./', [fixturePath]); | ||
const sourceFile = program.getSourceFile(fixturePath); | ||
if (!sourceFile) { | ||
throw Error('sourceFile is undefined!'); | ||
} | ||
|
||
const results = getInterfacesDescriptors(sourceFile, program, 'UsageStats'); | ||
expect(results).toEqual([ | ||
{ | ||
withBooleanValue: { | ||
kind: ts.SyntaxKind.BooleanKeyword, | ||
type: 'BooleanKeyword', | ||
}, | ||
withStringValue: { | ||
kind: ts.SyntaxKind.StringKeyword, | ||
type: 'StringKeyword', | ||
}, | ||
withNumberValue: { | ||
kind: ts.SyntaxKind.NumberKeyword, | ||
type: 'NumberKeyword', | ||
}, | ||
withStringArrayValue: { | ||
items: { | ||
kind: ts.SyntaxKind.StringKeyword, | ||
type: 'StringKeyword', | ||
}, | ||
}, | ||
withObjectValue: { | ||
withBooleanValue: { | ||
kind: ts.SyntaxKind.BooleanKeyword, | ||
type: 'BooleanKeyword', | ||
}, | ||
}, | ||
withObjectArrayValue: { | ||
items: { | ||
withNumberValue: { | ||
kind: ts.SyntaxKind.NumberKeyword, | ||
type: 'NumberKeyword', | ||
}, | ||
}, | ||
}, | ||
}, | ||
]); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* and the Server Side Public License, v 1; you may not use this file except in | ||
* compliance with, at your election, the Elastic License or the Server Side | ||
* Public License, v 1. | ||
*/ | ||
|
||
import * as ts from 'typescript'; | ||
import { getDescriptor, Descriptor, DescriptorValue } from './serializer'; | ||
|
||
export type InterfaceObjectType = Record<string, Descriptor | DescriptorValue>; | ||
|
||
export function getInterfacesDescriptors( | ||
sourceFile: ts.SourceFile, | ||
program: ts.Program, | ||
interfaceName: string | ||
): InterfaceObjectType[] { | ||
const interfacesObjects: InterfaceObjectType[] = []; | ||
const typeChecker = program.getTypeChecker(); | ||
|
||
ts.forEachChild(sourceFile, (node) => { | ||
if (ts.isInterfaceDeclaration(node)) { | ||
if (ts.getNameOfDeclaration(node)?.getText() === interfaceName) { | ||
const symbols = typeChecker.getSymbolsInScope(node, ts.SymbolFlags.Interface); | ||
|
||
const symbolDeclaration = symbols | ||
.find((symbol) => symbol.name === interfaceName) | ||
?.getDeclarations() | ||
?.find(ts.isInterfaceDeclaration) | ||
?.getChildren() | ||
.filter((child) => child.kind === 334) | ||
.pop(); | ||
|
||
const interfaceObject = symbolDeclaration?.getChildren().reduce((acc, child) => { | ||
if (ts.isPropertySignature(child)) { | ||
const childNameText = child.name.getText(); | ||
const key = childNameText.replace(/["']/g, ''); | ||
return { ...acc, [key]: getDescriptor(child, program) }; | ||
} | ||
|
||
throw new Error(`Unrecognized property in interface of kind: ${child.kind}.`); | ||
}, {} as InterfaceObjectType); | ||
|
||
if (interfaceObject) { | ||
interfacesObjects.push(interfaceObject); | ||
} | ||
} | ||
} | ||
}); | ||
|
||
return interfacesObjects; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,17 +6,28 @@ | |
* Public License, v 1. | ||
*/ | ||
|
||
import { schema } from '@kbn/config-schema'; | ||
import { IRouter } from '../../http'; | ||
import { SavedObjectsErrorHelpers } from '../../saved_objects'; | ||
|
||
export function registerGetRoute(router: IRouter) { | ||
router.get( | ||
{ path: '/api/kibana/settings', validate: false }, | ||
{ | ||
path: '/api/kibana/settings', | ||
validate: { | ||
query: schema.object({ | ||
_allRegistered: schema.maybe(schema.boolean()), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are exposing this only for test purposes. What do you think about following a similar approach to the Application Usage's functional tests?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree exposing an API just for testing might not be ideal. I'm curious if anyone else from the team ( @elastic/kibana-core ) has different ideas. Using the browser might be ok, even an api in the test plugin that exposes those settings might be even better too. Since |
||
}), | ||
}, | ||
}, | ||
async (context, request, response) => { | ||
try { | ||
const { _allRegistered } = request.query; | ||
const uiSettingsClient = context.core.uiSettings.client; | ||
|
||
return response.ok({ | ||
body: { | ||
registered: _allRegistered ? uiSettingsClient.getRegistered() : undefined, | ||
settings: await uiSettingsClient.getUserProvided(), | ||
}, | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UltraNIT: better safe than sorry I guess, but I still wonder if this assertion is really useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not needed but to stay consistent with other symbols we check for.