mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Cases] RBAC (#95058)
* Adding feature flag for auth * Hiding SOs and adding consumer field * First pass at adding security changes * Consumer as the app's plugin ID * Create addConsumerToSO migration helper * Fix mapping's SO consumer * Add test for CasesActions * Declare hidden types on SO client * Restructure integration tests * Init spaces_only integration tests * Implementing the cases security string * Adding security plugin tests for cases * Rough concept for authorization class * Adding comments * Fix merge * Get requiredPrivileges for classes * Check privillages * Ensure that all classes are available * Success if hasAllRequested is true * Failure if hasAllRequested is false * Adding schema updates for feature plugin * Seperate basic from trial * Enable SIR on integration tests * Starting the plumbing for authorization in plugin * Unit tests working * Move find route logic to case client * Create integration test helper functions * Adding auth to create call * Create getClassFilter helper * Add class attribute to find request * Create getFindAuthorizationFilter * Ensure savedObject is authorized in find method * Include fields for authorization * Combine authorization filter with cases & subcases filter * Fix isAuthorized flag * Fix merge issue * Create/delete spaces & users before and after tests * Add more user and roles * [Cases] Convert filters from strings to KueryNode (#95288) * [Cases] RBAC: Rename class to scope (#95535) * [Cases][RBAC] Rename scope to owner (#96035) * [Cases] RBAC: Create & Find integration tests (#95511) * [Cases] Cases client enchantment (#95923) * [Cases] Authorization and Client Audit Logger (#95477) * Starting audit logger * Finishing auth audit logger * Fixing tests and types * Adding audit event creator * Renaming class to scope * Adding audit logger messages to create and find * Adding comments and fixing import issue * Fixing type errors * Fixing tests and adding username to message * Addressing PR feedback * Removing unneccessary log and generating id * Fixing module issue and remove expect.anything * [Cases] Migrate sub cases routes to a client (#96461) * Adding sub cases client * Move sub case routes to case client * Throw when attempting to access the sub cases client * Fixing throw and removing user ans soclients * [Cases] RBAC: Migrate routes' unit tests to integration tests (#96374) Co-authored-by: Jonathan Buttner <jonathan.buttner@elastic.co> * [Cases] Move remaining HTTP functionality to client (#96507) * Moving deletes and find for attachments * Moving rest of comment apis * Migrating configuration routes to client * Finished moving routes, starting utils refactor * Refactoring utilites and fixing integration tests * Addressing PR feedback * Fixing mocks and types * Fixing integration tests * Renaming status_stats * Fixing test type errors * Adding plugins to kibana.json * Adding cases to required plugin * [Cases] Refactoring authorization (#97483) * Refactoring authorization * Wrapping auth calls in helper for try catch * Reverting name change * Hardcoding the saved object types * Switching ensure to owner array * [Cases] Add authorization to configuration & cases routes (#97228) * [Cases] Attachments RBAC (#97756) * Starting rbac for comments * Adding authorization to rest of comment apis * Starting the comment rbac tests * Fixing some of the rbac tests * Adding some integration tests * Starting patch tests * Working tests for comments * Working tests * Fixing some tests * Fixing type issues from pulling in master * Fixing connector tests that only work in trial license * Attempting to fix cypress * Mock return of array for configure * Fixing cypress test * Cleaning up * Addressing PR comments * Reducing operations * [Cases] Add RBAC to remaining Cases APIs (#98762) * Starting rbac for comments * Adding authorization to rest of comment apis * Starting the comment rbac tests * Fixing some of the rbac tests * Adding some integration tests * Starting patch tests * Working tests for comments * Working tests * Fixing some tests * Fixing type issues from pulling in master * Fixing connector tests that only work in trial license * Attempting to fix cypress * Mock return of array for configure * Fixing cypress test * Cleaning up * Working case update tests * Addressing PR comments * Reducing operations * Working rbac push case tests * Starting stats apis * Working status tests * User action tests and fixing migration errors * Fixing type errors * including error in message * Addressing pr feedback * Fixing some type errors * [Cases] Add space only tests (#99409) * Starting spaces tests * Finishing space only tests * Refactoring createCaseWithConnector * Fixing spelling * Addressing PR feedback and creating alert tests * Fixing mocks * [Cases] Add security only tests (#99679) * Starting spaces tests * Finishing space only tests * Refactoring createCaseWithConnector * Fixing spelling * Addressing PR feedback and creating alert tests * Fixing mocks * Starting security only tests * Adding remainder security only tests * Using helper objects * Fixing type error for null space * Renaming utility variables * Refactoring users and roles for security only tests * Adding sub feature * [Cases] Cleaning up the services and TODOs (#99723) * Cleaning up the service intialization * Fixing type errors * Adding comments for the api * Working test for cases client * Fix type error * Adding generated docs * Adding more docs and cleaning up types * Cleaning up readme * More clean up and links * Changing some file names * Renaming docs * Integration tests for cases privs and fixes (#100038) * [Cases] RBAC on UI (#99478) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> * Fixing case ids by alert id route call * [Cases] Fixing UI feature permissions and adding UI tests (#100074) * Integration tests for cases privs and fixes * Fixing ui cases permissions and adding tests * Adding test for collection failure and fixing jest * Renaming variables * Fixing type error * Adding some comments * Validate cases features * Fix new schema * Adding owner param for the status stats * Fix get case status tests * Adjusting permissions text and fixing status * Address PR feedback * Adding top level feature back * Fixing feature privileges * Renaming * Removing uneeded else * Fixing tests and adding cases merge tests * [Cases][Security Solution] Basic license security solution API tests (#100925) * Cleaning up the fixture plugins * Adding basic feature test * renaming to unsecuredSavedObjectsClient (#101215) * [Cases] RBAC Refactoring audit logging (#100952) * Refactoring audit logging * Adding unit tests for authorization classes * Addressing feedback and adding util tests * return undefined on empty array * fixing eslint * [Cases] Cleaning up RBAC integration tests (#101324) * Adding tests for space permissions * Adding tests for testing a disable feature Co-authored-by: Christos Nasikas <christos.nasikas@elastic.co> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
999faecd2c
commit
b6c982c3b0
487 changed files with 33107 additions and 17281 deletions
|
@ -528,6 +528,10 @@ Array [
|
|||
"dashboards",
|
||||
"kibana",
|
||||
],
|
||||
"cases": Object {
|
||||
"all": Array [],
|
||||
"read": Array [],
|
||||
},
|
||||
"catalogue": Array [
|
||||
"dashboard",
|
||||
],
|
||||
|
@ -673,6 +677,10 @@ Array [
|
|||
"discover",
|
||||
"kibana",
|
||||
],
|
||||
"cases": Object {
|
||||
"all": Array [],
|
||||
"read": Array [],
|
||||
},
|
||||
"catalogue": Array [
|
||||
"discover",
|
||||
],
|
||||
|
@ -915,6 +923,10 @@ Array [
|
|||
"lens",
|
||||
"kibana",
|
||||
],
|
||||
"cases": Object {
|
||||
"all": Array [],
|
||||
"read": Array [],
|
||||
},
|
||||
"catalogue": Array [
|
||||
"visualize",
|
||||
],
|
||||
|
@ -1044,6 +1056,10 @@ Array [
|
|||
"dashboards",
|
||||
"kibana",
|
||||
],
|
||||
"cases": Object {
|
||||
"all": Array [],
|
||||
"read": Array [],
|
||||
},
|
||||
"catalogue": Array [
|
||||
"dashboard",
|
||||
],
|
||||
|
@ -1189,6 +1205,10 @@ Array [
|
|||
"discover",
|
||||
"kibana",
|
||||
],
|
||||
"cases": Object {
|
||||
"all": Array [],
|
||||
"read": Array [],
|
||||
},
|
||||
"catalogue": Array [
|
||||
"discover",
|
||||
],
|
||||
|
@ -1431,6 +1451,10 @@ Array [
|
|||
"lens",
|
||||
"kibana",
|
||||
],
|
||||
"cases": Object {
|
||||
"all": Array [],
|
||||
"read": Array [],
|
||||
},
|
||||
"catalogue": Array [
|
||||
"visualize",
|
||||
],
|
||||
|
|
|
@ -55,6 +55,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: [],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
read: {
|
||||
|
@ -76,6 +80,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -113,6 +120,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: [],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -137,6 +148,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -170,6 +184,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type-alerts'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
read: {
|
||||
|
@ -191,6 +209,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -229,6 +250,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type-alerts'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -261,6 +286,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-another-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
read: {
|
||||
|
@ -282,6 +311,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -311,6 +343,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
all: ['alerting-all-sub-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-sub-type'],
|
||||
read: ['cases-read-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
],
|
||||
|
@ -349,6 +385,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-another-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -373,6 +413,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -405,6 +448,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-another-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
read: {
|
||||
|
@ -426,6 +473,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -455,6 +505,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
all: ['alerting-all-sub-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-sub-type'],
|
||||
read: ['cases-read-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
],
|
||||
|
@ -493,6 +547,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-another-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -517,6 +575,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -549,6 +610,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-another-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
read: {
|
||||
|
@ -570,6 +635,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -600,6 +668,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
all: ['alerting-all-sub-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-sub-type'],
|
||||
read: ['cases-read-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
],
|
||||
|
@ -641,6 +713,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-another-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type', 'cases-all-sub-type'],
|
||||
read: ['cases-read-type', 'cases-read-sub-type'],
|
||||
},
|
||||
ui: ['ui-action', 'ui-sub-type'],
|
||||
},
|
||||
},
|
||||
|
@ -668,6 +744,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-sub-type'],
|
||||
read: ['cases-read-type', 'cases-read-sub-type'],
|
||||
},
|
||||
ui: ['ui-action', 'ui-sub-type'],
|
||||
},
|
||||
},
|
||||
|
@ -702,6 +782,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
read: {
|
||||
|
@ -723,6 +807,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -752,6 +839,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
all: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
],
|
||||
|
@ -792,6 +882,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -818,6 +912,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: [],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -850,6 +948,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-another-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
read: {
|
||||
|
@ -871,6 +973,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -901,6 +1006,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
all: ['alerting-all-sub-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-sub-type'],
|
||||
read: ['cases-read-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
],
|
||||
|
@ -942,6 +1051,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-another-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type', 'cases-all-sub-type'],
|
||||
read: ['cases-read-type', 'cases-read-sub-type'],
|
||||
},
|
||||
ui: ['ui-action', 'ui-sub-type'],
|
||||
},
|
||||
},
|
||||
|
@ -966,6 +1079,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -998,6 +1114,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-another-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
read: {
|
||||
|
@ -1019,6 +1139,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -1050,6 +1173,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
all: ['alerting-all-sub-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-sub-type'],
|
||||
read: ['cases-read-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
],
|
||||
|
@ -1088,6 +1215,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-another-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -1112,6 +1243,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -1168,6 +1302,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-sub-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-sub-type'],
|
||||
read: ['cases-read-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
],
|
||||
|
@ -1209,6 +1347,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: [],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-sub-type'],
|
||||
read: ['cases-read-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
},
|
||||
|
@ -1236,6 +1378,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: [],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-sub-type'],
|
||||
read: ['cases-read-sub-type'],
|
||||
},
|
||||
ui: ['ui-sub-type'],
|
||||
},
|
||||
},
|
||||
|
@ -1268,6 +1414,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-another-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
read: {
|
||||
|
@ -1289,6 +1439,9 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -1347,6 +1500,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-another-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: ['cases-all-type'],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
@ -1373,6 +1530,10 @@ describe('featurePrivilegeIterator', () => {
|
|||
read: ['alerting-read-type'],
|
||||
},
|
||||
},
|
||||
cases: {
|
||||
all: [],
|
||||
read: ['cases-read-type'],
|
||||
},
|
||||
ui: ['ui-action'],
|
||||
},
|
||||
},
|
||||
|
|
|
@ -131,6 +131,11 @@ function mergeWithSubFeatures(
|
|||
),
|
||||
},
|
||||
};
|
||||
|
||||
mergedConfig.cases = {
|
||||
all: mergeArrays(mergedConfig.cases?.all ?? [], subFeaturePrivilege.cases?.all ?? []),
|
||||
read: mergeArrays(mergedConfig.cases?.read ?? [], subFeaturePrivilege.cases?.read ?? []),
|
||||
};
|
||||
}
|
||||
return mergedConfig;
|
||||
}
|
||||
|
|
|
@ -1228,6 +1228,180 @@ describe('FeatureRegistry', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it(`prevents privileges from specifying cases entries that don't exist at the root level`, () => {
|
||||
const feature: KibanaFeatureConfig = {
|
||||
id: 'test-feature',
|
||||
name: 'Test Feature',
|
||||
app: [],
|
||||
category: { id: 'foo', label: 'foo' },
|
||||
cases: ['bar'],
|
||||
privileges: {
|
||||
all: {
|
||||
cases: {
|
||||
all: ['foo', 'bar'],
|
||||
read: ['baz'],
|
||||
},
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: [],
|
||||
},
|
||||
ui: [],
|
||||
app: [],
|
||||
},
|
||||
read: {
|
||||
cases: { read: ['foo', 'bar', 'baz'] },
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: [],
|
||||
},
|
||||
ui: [],
|
||||
app: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const featureRegistry = new FeatureRegistry();
|
||||
|
||||
expect(() =>
|
||||
featureRegistry.registerKibanaFeature(feature)
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Feature privilege test-feature.all has unknown cases entries: foo, baz"`
|
||||
);
|
||||
});
|
||||
|
||||
it(`prevents features from specifying cases entries that don't exist at the privilege level`, () => {
|
||||
const feature: KibanaFeatureConfig = {
|
||||
id: 'test-feature',
|
||||
name: 'Test Feature',
|
||||
app: [],
|
||||
category: { id: 'foo', label: 'foo' },
|
||||
cases: ['foo', 'bar', 'baz'],
|
||||
privileges: {
|
||||
all: {
|
||||
cases: { all: ['foo'] },
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: [],
|
||||
},
|
||||
ui: [],
|
||||
app: [],
|
||||
},
|
||||
read: {
|
||||
cases: { all: ['foo'] },
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: [],
|
||||
},
|
||||
ui: [],
|
||||
app: [],
|
||||
},
|
||||
},
|
||||
subFeatures: [
|
||||
{
|
||||
name: 'my sub feature',
|
||||
privilegeGroups: [
|
||||
{
|
||||
groupType: 'independent',
|
||||
privileges: [
|
||||
{
|
||||
id: 'cool-sub-feature-privilege',
|
||||
name: 'cool privilege',
|
||||
includeIn: 'none',
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: [],
|
||||
},
|
||||
ui: [],
|
||||
cases: { all: ['bar'] },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const featureRegistry = new FeatureRegistry();
|
||||
|
||||
expect(() =>
|
||||
featureRegistry.registerKibanaFeature(feature)
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Feature test-feature specifies cases entries which are not granted to any privileges: baz"`
|
||||
);
|
||||
});
|
||||
|
||||
it(`prevents reserved privileges from specifying cases entries that don't exist at the root level`, () => {
|
||||
const feature: KibanaFeatureConfig = {
|
||||
id: 'test-feature',
|
||||
name: 'Test Feature',
|
||||
app: [],
|
||||
category: { id: 'foo', label: 'foo' },
|
||||
cases: ['bar'],
|
||||
privileges: null,
|
||||
reserved: {
|
||||
description: 'something',
|
||||
privileges: [
|
||||
{
|
||||
id: 'reserved',
|
||||
privilege: {
|
||||
cases: { all: ['foo', 'bar', 'baz'] },
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: [],
|
||||
},
|
||||
ui: [],
|
||||
app: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const featureRegistry = new FeatureRegistry();
|
||||
|
||||
expect(() =>
|
||||
featureRegistry.registerKibanaFeature(feature)
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Feature privilege test-feature.reserved has unknown cases entries: foo, baz"`
|
||||
);
|
||||
});
|
||||
|
||||
it(`prevents features from specifying cases entries that don't exist at the reserved privilege level`, () => {
|
||||
const feature: KibanaFeatureConfig = {
|
||||
id: 'test-feature',
|
||||
name: 'Test Feature',
|
||||
app: [],
|
||||
category: { id: 'foo', label: 'foo' },
|
||||
cases: ['foo', 'bar', 'baz'],
|
||||
privileges: null,
|
||||
reserved: {
|
||||
description: 'something',
|
||||
privileges: [
|
||||
{
|
||||
id: 'reserved',
|
||||
privilege: {
|
||||
cases: { all: ['foo', 'bar'] },
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: [],
|
||||
},
|
||||
ui: [],
|
||||
app: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const featureRegistry = new FeatureRegistry();
|
||||
|
||||
expect(() =>
|
||||
featureRegistry.registerKibanaFeature(feature)
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Feature test-feature specifies cases entries which are not granted to any privileges: baz"`
|
||||
);
|
||||
});
|
||||
|
||||
it(`prevents privileges from specifying management sections that don't exist at the root level`, () => {
|
||||
const feature: KibanaFeatureConfig = {
|
||||
id: 'test-feature',
|
||||
|
|
|
@ -63,6 +63,7 @@ const managementSchema = schema.recordOf(
|
|||
);
|
||||
const catalogueSchema = listOfCapabilitiesSchema;
|
||||
const alertingSchema = schema.arrayOf(schema.string());
|
||||
const casesSchema = schema.arrayOf(schema.string());
|
||||
|
||||
const appCategorySchema = schema.object({
|
||||
id: schema.string(),
|
||||
|
@ -94,6 +95,12 @@ const kibanaPrivilegeSchema = schema.object({
|
|||
),
|
||||
})
|
||||
),
|
||||
cases: schema.maybe(
|
||||
schema.object({
|
||||
all: schema.maybe(casesSchema),
|
||||
read: schema.maybe(casesSchema),
|
||||
})
|
||||
),
|
||||
savedObject: schema.object({
|
||||
all: schema.arrayOf(schema.string()),
|
||||
read: schema.arrayOf(schema.string()),
|
||||
|
@ -130,6 +137,12 @@ const kibanaIndependentSubFeaturePrivilegeSchema = schema.object({
|
|||
),
|
||||
})
|
||||
),
|
||||
cases: schema.maybe(
|
||||
schema.object({
|
||||
all: schema.maybe(casesSchema),
|
||||
read: schema.maybe(casesSchema),
|
||||
})
|
||||
),
|
||||
api: schema.maybe(schema.arrayOf(schema.string())),
|
||||
app: schema.maybe(schema.arrayOf(schema.string())),
|
||||
savedObject: schema.object({
|
||||
|
@ -187,6 +200,7 @@ const kibanaFeatureSchema = schema.object({
|
|||
management: schema.maybe(managementSchema),
|
||||
catalogue: schema.maybe(catalogueSchema),
|
||||
alerting: schema.maybe(alertingSchema),
|
||||
cases: schema.maybe(casesSchema),
|
||||
privileges: schema.oneOf([
|
||||
schema.literal(null),
|
||||
schema.object({
|
||||
|
@ -252,7 +266,7 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) {
|
|||
kibanaFeatureSchema.validate(feature);
|
||||
|
||||
// the following validation can't be enforced by the Joi schema, since it'd require us looking "up" the object graph for the list of valid value, which they explicitly forbid.
|
||||
const { app = [], management = {}, catalogue = [], alerting = [] } = feature;
|
||||
const { app = [], management = {}, catalogue = [], alerting = [], cases = [] } = feature;
|
||||
|
||||
const unseenApps = new Set(app);
|
||||
|
||||
|
@ -267,6 +281,8 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) {
|
|||
|
||||
const unseenAlertTypes = new Set(alerting);
|
||||
|
||||
const unseenCasesTypes = new Set(cases);
|
||||
|
||||
function validateAppEntry(privilegeId: string, entry: readonly string[] = []) {
|
||||
entry.forEach((privilegeApp) => unseenApps.delete(privilegeApp));
|
||||
|
||||
|
@ -310,6 +326,23 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) {
|
|||
}
|
||||
}
|
||||
|
||||
function validateCasesEntry(privilegeId: string, entry: FeatureKibanaPrivileges['cases']) {
|
||||
const all = entry?.all ?? [];
|
||||
const read = entry?.read ?? [];
|
||||
|
||||
all.forEach((privilegeCasesTypes) => unseenCasesTypes.delete(privilegeCasesTypes));
|
||||
read.forEach((privilegeCasesTypes) => unseenCasesTypes.delete(privilegeCasesTypes));
|
||||
|
||||
const unknownCasesEntries = difference([...all, ...read], cases);
|
||||
if (unknownCasesEntries.length > 0) {
|
||||
throw new Error(
|
||||
`Feature privilege ${
|
||||
feature.id
|
||||
}.${privilegeId} has unknown cases entries: ${unknownCasesEntries.join(', ')}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function validateManagementEntry(
|
||||
privilegeId: string,
|
||||
managementEntry: Record<string, readonly string[]> = {}
|
||||
|
@ -371,6 +404,7 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) {
|
|||
|
||||
validateManagementEntry(privilegeId, privilegeDefinition.management);
|
||||
validateAlertingEntry(privilegeId, privilegeDefinition.alerting);
|
||||
validateCasesEntry(privilegeId, privilegeDefinition.cases);
|
||||
});
|
||||
|
||||
const subFeatureEntries = feature.subFeatures ?? [];
|
||||
|
@ -381,6 +415,7 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) {
|
|||
validateCatalogueEntry(subFeaturePrivilege.id, subFeaturePrivilege.catalogue);
|
||||
validateManagementEntry(subFeaturePrivilege.id, subFeaturePrivilege.management);
|
||||
validateAlertingEntry(subFeaturePrivilege.id, subFeaturePrivilege.alerting);
|
||||
validateCasesEntry(subFeaturePrivilege.id, subFeaturePrivilege.cases);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -431,6 +466,16 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) {
|
|||
).join(',')}`
|
||||
);
|
||||
}
|
||||
|
||||
if (unseenCasesTypes.size > 0) {
|
||||
throw new Error(
|
||||
`Feature ${
|
||||
feature.id
|
||||
} specifies cases entries which are not granted to any privileges: ${Array.from(
|
||||
unseenCasesTypes.values()
|
||||
).join(',')}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function validateElasticsearchFeature(feature: ElasticsearchFeatureConfig) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue