From 4358c12a25208642680ab799fde525de52f62702 Mon Sep 17 00:00:00 2001 From: tahmidefaz Date: Mon, 13 Jan 2020 16:42:43 -0500 Subject: [PATCH 01/13] initial call to rbac --- src/js/entry.js | 3 +++ src/js/rbac/userPermissions.js | 14 ++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/js/rbac/userPermissions.js diff --git a/src/js/entry.js b/src/js/entry.js index c1bfd9fd7..0819b385a 100644 --- a/src/js/entry.js +++ b/src/js/entry.js @@ -15,6 +15,7 @@ import RootApp from './App/RootApp'; import debugFunctions from './debugFunctions'; const sourceOfTruth = require('./nav/sourceOfTruth'); +const userPermissions = require('./rbac/userPermissions'); // used for translating event names exposed publicly to internal event names const PUBLIC_EVENTS = { @@ -42,6 +43,8 @@ export function chromeInit(libjwt) { actions.userLogIn(user); // Then, generate the global nav from the source of truth. // We use the JWT token as part of the cache key. + userPermissions(libjwt.jwt.getEncodedToken()) + .then((rbacResult) => console.log('rbac: ', rbacResult)); return sourceOfTruth(libjwt.jwt.getEncodedToken()) // Gets the navigation for the current bundle. .then(loadNav) diff --git a/src/js/rbac/userPermissions.js b/src/js/rbac/userPermissions.js new file mode 100644 index 000000000..6668f1181 --- /dev/null +++ b/src/js/rbac/userPermissions.js @@ -0,0 +1,14 @@ +const axios = require('axios'); +const { bootstrapCache } = require('../utils'); + +// Gets the source of truth from the CS Config repository, and caches it for 10 minutes. +module.exports = (cachePrefix) => { + const cache = bootstrapCache('/api/rbac/v1/access/?application=*', `${cachePrefix}-rbac`); + + const instance = axios.create({ adapter: cache.adapter }); + + instance.interceptors.response.use((response) => response.data || response); + + // TODO: Make this fetch paginated permissions list as well + return instance.get(window.location.origin + '/api/rbac/v1/access/?application=*'); +}; From 92f8eaaa72a716d3292dbacb4c520356433e05a1 Mon Sep 17 00:00:00 2001 From: tahmidefaz Date: Tue, 14 Jan 2020 15:52:52 -0500 Subject: [PATCH 02/13] get all paginated requests from rbac --- src/js/rbac/userPermissions.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/js/rbac/userPermissions.js b/src/js/rbac/userPermissions.js index 6668f1181..bfcecc61a 100644 --- a/src/js/rbac/userPermissions.js +++ b/src/js/rbac/userPermissions.js @@ -1,6 +1,21 @@ const axios = require('axios'); const { bootstrapCache } = require('../utils'); +const getAllPermissions = (url, permissions, resolve, reject) => { + axios.get(url) + .then(response => { + const allPermissions = permissions.concat(response.data.data) + if(response.data.links.next !== null) { + getAllPermissions(window.location.origin + response.data.links.next, allPermissions, resolve, reject) + } else { + resolve(allPermissions) + } + }) + .catch(error => { + console.log(error) + }) +} + // Gets the source of truth from the CS Config repository, and caches it for 10 minutes. module.exports = (cachePrefix) => { const cache = bootstrapCache('/api/rbac/v1/access/?application=*', `${cachePrefix}-rbac`); @@ -9,6 +24,7 @@ module.exports = (cachePrefix) => { instance.interceptors.response.use((response) => response.data || response); - // TODO: Make this fetch paginated permissions list as well - return instance.get(window.location.origin + '/api/rbac/v1/access/?application=*'); + return new Promise((resolve, reject) => { + getAllPermissions(window.location.origin + '/api/rbac/v1/access/?application=*', [], resolve, reject) + }) }; From 0055c5486c1e2db43087c34437c9c7d93ea60e8f Mon Sep 17 00:00:00 2001 From: tahmidefaz Date: Wed, 15 Jan 2020 14:57:42 -0500 Subject: [PATCH 03/13] using localstorage to store user permissions --- src/js/entry.js | 3 +-- src/js/rbac/userPermissions.js | 26 +++++++++++++++++--------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/js/entry.js b/src/js/entry.js index d43e2f260..602959c80 100644 --- a/src/js/entry.js +++ b/src/js/entry.js @@ -44,8 +44,7 @@ export function chromeInit(libjwt) { actions.userLogIn(user); // Then, generate the global nav from the source of truth. // We use the JWT token as part of the cache key. - userPermissions(libjwt.jwt.getEncodedToken()) - .then((rbacResult) => console.log('rbac: ', rbacResult)); + // console.log('rbac: ', userPermissions("cAcHe")); return sourceOfTruth(libjwt.jwt.getEncodedToken()) // Gets the navigation for the current bundle. .then(loadNav) diff --git a/src/js/rbac/userPermissions.js b/src/js/rbac/userPermissions.js index bfcecc61a..1518cf890 100644 --- a/src/js/rbac/userPermissions.js +++ b/src/js/rbac/userPermissions.js @@ -16,15 +16,23 @@ const getAllPermissions = (url, permissions, resolve, reject) => { }) } -// Gets the source of truth from the CS Config repository, and caches it for 10 minutes. module.exports = (cachePrefix) => { - const cache = bootstrapCache('/api/rbac/v1/access/?application=*', `${cachePrefix}-rbac`); - - const instance = axios.create({ adapter: cache.adapter }); - - instance.interceptors.response.use((response) => response.data || response); + if(window.localStorage){ + rbacStore = Object.keys(window.localStorage).filter(key => key.includes('-rbac-response')) + if(rbacStore.length < 1 || ( Date.now() > JSON.parse(window.localStorage.getItem(rbacStore[0]).expires ))) { + rbacResponse = new Promise((resolve, reject) => { + getAllPermissions(window.location.origin + '/api/rbac/v1/access/?application=*', [], resolve, reject) + }) + rbacResponse.then((response) => { + expTime = Date.now() + 10 * 60 * 1000 + window.localStorage.removeItem(rbacStore[0]) + window.localStorage.setItem(`${cachePrefix}-rbac-response`, + JSON.stringify({ expires: expTime, permissions: response })); + console.log(response); + return response + }); + } + return JSON.parse(window.localStorage.getItem(rbacStore[0].permissions)).permissions + } - return new Promise((resolve, reject) => { - getAllPermissions(window.location.origin + '/api/rbac/v1/access/?application=*', [], resolve, reject) - }) }; From 2e548bc8c7f1255e25c350367bd36d97acabb3fa Mon Sep 17 00:00:00 2001 From: tahmidefaz Date: Wed, 15 Jan 2020 17:00:02 -0500 Subject: [PATCH 04/13] using chrome function --- src/js/entry.js | 3 +++ src/js/rbac/userPermissions.js | 34 ++++++++++++++++++++-------------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/js/entry.js b/src/js/entry.js index 602959c80..d510df783 100644 --- a/src/js/entry.js +++ b/src/js/entry.js @@ -127,6 +127,9 @@ export function bootstrap(libjwt, initFunc) { isBeta: () => { return (window.location.pathname.split('/')[1] === 'beta' ? true : false); }, + getUserPermissions: () => { + return userPermissions() + }, init: initFunc }, loadInventory, diff --git a/src/js/rbac/userPermissions.js b/src/js/rbac/userPermissions.js index 1518cf890..7c052e407 100644 --- a/src/js/rbac/userPermissions.js +++ b/src/js/rbac/userPermissions.js @@ -1,5 +1,4 @@ const axios = require('axios'); -const { bootstrapCache } = require('../utils'); const getAllPermissions = (url, permissions, resolve, reject) => { axios.get(url) @@ -16,23 +15,30 @@ const getAllPermissions = (url, permissions, resolve, reject) => { }) } -module.exports = (cachePrefix) => { +const permissionsInfo = () => { + return new Promise((resolve, reject) => { + getAllPermissions(window.location.origin + '/api/rbac/v1/access/?application=*', [], resolve, reject) + }) +} + +module.exports = () => { if(window.localStorage){ - rbacStore = Object.keys(window.localStorage).filter(key => key.includes('-rbac-response')) - if(rbacStore.length < 1 || ( Date.now() > JSON.parse(window.localStorage.getItem(rbacStore[0]).expires ))) { - rbacResponse = new Promise((resolve, reject) => { - getAllPermissions(window.location.origin + '/api/rbac/v1/access/?application=*', [], resolve, reject) + if(!window.localStorage.getItem('rbac-response') || (Date.now() > JSON.parse(window.localStorage.getItem('rbac-response')).expires)) { + permissionsInfo().then((info) => { + // caching for 10 minutes + expTime = Date.now() + 10 * 60 * 1000; + data = { expires: expTime, permissions: info } + window.localStorage.setItem('rbac-response', JSON.stringify(data)); + return data + // FIX: doesn't work the first time }) - rbacResponse.then((response) => { - expTime = Date.now() + 10 * 60 * 1000 - window.localStorage.removeItem(rbacStore[0]) - window.localStorage.setItem(`${cachePrefix}-rbac-response`, - JSON.stringify({ expires: expTime, permissions: response })); - console.log(response); - return response + .catch(error => { + console.log(error) }); } - return JSON.parse(window.localStorage.getItem(rbacStore[0].permissions)).permissions + else{ + return JSON.parse(window.localStorage.getItem('rbac-response')) + } } }; From 4cff552797a65ab1c24ea11cd0fee486e69e64c1 Mon Sep 17 00:00:00 2001 From: tahmidefaz Date: Thu, 16 Jan 2020 11:15:29 -0500 Subject: [PATCH 05/13] making userPermissions() return Promise --- src/js/entry.js | 4 ++- src/js/rbac/userPermissions.js | 56 +++++++++++++++++----------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/js/entry.js b/src/js/entry.js index d510df783..c21cb3c7b 100644 --- a/src/js/entry.js +++ b/src/js/entry.js @@ -128,7 +128,9 @@ export function bootstrap(libjwt, initFunc) { return (window.location.pathname.split('/')[1] === 'beta' ? true : false); }, getUserPermissions: () => { - return userPermissions() + if (window.localStorage) { + return userPermissions(); + } }, init: initFunc }, diff --git a/src/js/rbac/userPermissions.js b/src/js/rbac/userPermissions.js index 7c052e407..0c624bbd9 100644 --- a/src/js/rbac/userPermissions.js +++ b/src/js/rbac/userPermissions.js @@ -3,42 +3,42 @@ const axios = require('axios'); const getAllPermissions = (url, permissions, resolve, reject) => { axios.get(url) .then(response => { - const allPermissions = permissions.concat(response.data.data) - if(response.data.links.next !== null) { - getAllPermissions(window.location.origin + response.data.links.next, allPermissions, resolve, reject) + const allPermissions = permissions.concat(response.data.data); + if (response.data.links.next !== null) { + getAllPermissions(window.location.origin + response.data.links.next, allPermissions, resolve, reject); } else { - resolve(allPermissions) + resolve(allPermissions); } }) .catch(error => { - console.log(error) - }) -} + window.console.log(error); + }); +}; const permissionsInfo = () => { return new Promise((resolve, reject) => { - getAllPermissions(window.location.origin + '/api/rbac/v1/access/?application=*', [], resolve, reject) - }) -} + getAllPermissions(window.location.origin + '/api/rbac/v1/access/?application=*', [], resolve, reject); + }); +}; module.exports = () => { - if(window.localStorage){ - if(!window.localStorage.getItem('rbac-response') || (Date.now() > JSON.parse(window.localStorage.getItem('rbac-response')).expires)) { - permissionsInfo().then((info) => { - // caching for 10 minutes - expTime = Date.now() + 10 * 60 * 1000; - data = { expires: expTime, permissions: info } - window.localStorage.setItem('rbac-response', JSON.stringify(data)); - return data - // FIX: doesn't work the first time - }) - .catch(error => { - console.log(error) - }); - } - else{ - return JSON.parse(window.localStorage.getItem('rbac-response')) - } + if (!window.localStorage.getItem('rbac-response') || (Date.now() > JSON.parse(window.localStorage.getItem('rbac-response')).expires)) { + return permissionsInfo().then((info) => { + // caching for 10 minutes + const expTime = Date.now() + 10 * 60 * 1000; + const data = { expires: expTime, permissions: info }; + window.localStorage.setItem('rbac-response', JSON.stringify(data)); + return data; + }) + .catch(error => { + window.console.log(error); + }); + } + else { + return new Promise((resolve, reject) => { + window.localStorage.getItem('rbac-response') ? + resolve(JSON.parse(window.localStorage.getItem('rbac-response'))) : + reject('Unable to fetch rbac-response from localStorage'); + }); } - }; From ed18b9b23ba1b02d342a72708f5fef195bfd6d05 Mon Sep 17 00:00:00 2001 From: tahmidefaz Date: Thu, 16 Jan 2020 11:32:48 -0500 Subject: [PATCH 06/13] using higher limit for fetching rbac permissions and updating tests --- config/setupTests.js | 5 +++++ src/js/rbac/userPermissions.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/config/setupTests.js b/config/setupTests.js index 17afc4781..7995a9d43 100644 --- a/config/setupTests.js +++ b/config/setupTests.js @@ -30,6 +30,11 @@ global.window.insights = { type: 'User' } })) + }, + getUserPermissions: () => { + return new Promise((permissionsObj) => permissionsObj({ + permissions: [], + })) } } }; diff --git a/src/js/rbac/userPermissions.js b/src/js/rbac/userPermissions.js index 0c624bbd9..260aab03d 100644 --- a/src/js/rbac/userPermissions.js +++ b/src/js/rbac/userPermissions.js @@ -17,7 +17,7 @@ const getAllPermissions = (url, permissions, resolve, reject) => { const permissionsInfo = () => { return new Promise((resolve, reject) => { - getAllPermissions(window.location.origin + '/api/rbac/v1/access/?application=*', [], resolve, reject); + getAllPermissions(window.location.origin + '/api/rbac/v1/access/?application=*&limit=25', [], resolve, reject); }); }; From a04b4f9aa0255f45d69ae57b259c771e0304bb74 Mon Sep 17 00:00:00 2001 From: tahmidefaz Date: Thu, 16 Jan 2020 12:57:03 -0500 Subject: [PATCH 07/13] code cleanup --- src/js/entry.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/js/entry.js b/src/js/entry.js index c21cb3c7b..0887fc143 100644 --- a/src/js/entry.js +++ b/src/js/entry.js @@ -44,7 +44,6 @@ export function chromeInit(libjwt) { actions.userLogIn(user); // Then, generate the global nav from the source of truth. // We use the JWT token as part of the cache key. - // console.log('rbac: ', userPermissions("cAcHe")); return sourceOfTruth(libjwt.jwt.getEncodedToken()) // Gets the navigation for the current bundle. .then(loadNav) From e1afc1e32b5cb78b6363d5f0521037d9679ba6b2 Mon Sep 17 00:00:00 2001 From: tahmidefaz Date: Thu, 16 Jan 2020 13:29:13 -0500 Subject: [PATCH 08/13] using custom logs --- src/js/rbac/userPermissions.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/js/rbac/userPermissions.js b/src/js/rbac/userPermissions.js index 260aab03d..8f9b6d241 100644 --- a/src/js/rbac/userPermissions.js +++ b/src/js/rbac/userPermissions.js @@ -1,4 +1,5 @@ const axios = require('axios'); +const log = require('../jwt/logger')('userPermissions.js'); const getAllPermissions = (url, permissions, resolve, reject) => { axios.get(url) @@ -11,7 +12,7 @@ const getAllPermissions = (url, permissions, resolve, reject) => { } }) .catch(error => { - window.console.log(error); + log(error); }); }; @@ -31,7 +32,7 @@ module.exports = () => { return data; }) .catch(error => { - window.console.log(error); + log(error); }); } else { From 0a35a06e3afe7df90db77862f5588f5370ae3adb Mon Sep 17 00:00:00 2001 From: tahmidefaz Date: Mon, 20 Jan 2020 16:49:22 -0500 Subject: [PATCH 09/13] using the rbac-client --- config/setupTests.js | 6 +---- package.json | 1 + src/js/entry.js | 6 ++--- src/js/rbac/fetchPermissions.js | 20 +++++++++++++++ src/js/rbac/rbac.js | 13 ++++++++++ src/js/rbac/userPermissions.js | 45 --------------------------------- 6 files changed, 37 insertions(+), 54 deletions(-) create mode 100644 src/js/rbac/fetchPermissions.js create mode 100644 src/js/rbac/rbac.js delete mode 100644 src/js/rbac/userPermissions.js diff --git a/config/setupTests.js b/config/setupTests.js index 7995a9d43..f592089a2 100644 --- a/config/setupTests.js +++ b/config/setupTests.js @@ -31,10 +31,6 @@ global.window.insights = { } })) }, - getUserPermissions: () => { - return new Promise((permissionsObj) => permissionsObj({ - permissions: [], - })) - } + getUserPermissions: () => Promise.resolve([]) } }; diff --git a/package.json b/package.json index e8155a8e4..0553875a2 100644 --- a/package.json +++ b/package.json @@ -121,6 +121,7 @@ "@redhat-cloud-services/frontend-components-remediations": "0.0.4", "@redhat-cloud-services/frontend-components-utilities": "0.0.15", "@redhat-cloud-services/keycloak-js": "0.0.3", + "@redhat-cloud-services/rbac-client": "^1.0.49", "@sentry/browser": "^5.4.3", "axios": "^0.19.0", "axios-cache-adapter": "^2.3.0", diff --git a/src/js/entry.js b/src/js/entry.js index 0887fc143..9b79c03a7 100644 --- a/src/js/entry.js +++ b/src/js/entry.js @@ -16,7 +16,7 @@ import debugFunctions from './debugFunctions'; import NoAccess from './App/NoAccess'; const sourceOfTruth = require('./nav/sourceOfTruth'); -const userPermissions = require('./rbac/userPermissions'); +import { fetchPermissions } from './rbac/fetchPermissions'; // used for translating event names exposed publicly to internal event names const PUBLIC_EVENTS = { @@ -127,9 +127,7 @@ export function bootstrap(libjwt, initFunc) { return (window.location.pathname.split('/')[1] === 'beta' ? true : false); }, getUserPermissions: () => { - if (window.localStorage) { - return userPermissions(); - } + return fetchPermissions(libjwt.jwt.getEncodedToken()); }, init: initFunc }, diff --git a/src/js/rbac/fetchPermissions.js b/src/js/rbac/fetchPermissions.js new file mode 100644 index 000000000..24d524352 --- /dev/null +++ b/src/js/rbac/fetchPermissions.js @@ -0,0 +1,20 @@ +import createRbacAPI from './rbac.js'; +const log = require('../jwt/logger')('fetchPermissions.js'); + +const perPage = 25; + +export const fetchPermissions = (userToken) => { + const rbacApi = createRbacAPI(userToken); + return rbacApi.getPrincipalAccess('*', undefined, perPage).then(({ data, meta }) => { + if (meta.count > perPage) { + return Promise.all( + [...new Array(Math.ceil(meta.count / perPage))] + .map((_empty, key) => rbacApi.getPrincipalAccess('*', undefined, perPage, (key + 1) * perPage) + .then(({ data }) => data)) + ).then(allAccess => allAccess.reduce((acc, curr) => ([...acc, ...curr]), data)) + .catch(error => log(error)); + } else { + return data; + }}) + .catch(error => log(error)); +}; diff --git a/src/js/rbac/rbac.js b/src/js/rbac/rbac.js new file mode 100644 index 000000000..f9062f73b --- /dev/null +++ b/src/js/rbac/rbac.js @@ -0,0 +1,13 @@ +const axios = require('axios'); +const { AccessApi } = require('@redhat-cloud-services/rbac-client'); +const { bootstrapCache } = require('../utils'); +const BASE_PATH = '/api/rbac/v1'; + +module.exports = (cachePrefix) => { + const cache = bootstrapCache(BASE_PATH, `${cachePrefix}-rbac`); + + const instance = axios.create({ adapter: cache.adapter }); + instance.interceptors.response.use((response) => response.data || response); + + return new AccessApi(undefined, BASE_PATH, instance); +}; diff --git a/src/js/rbac/userPermissions.js b/src/js/rbac/userPermissions.js deleted file mode 100644 index 8f9b6d241..000000000 --- a/src/js/rbac/userPermissions.js +++ /dev/null @@ -1,45 +0,0 @@ -const axios = require('axios'); -const log = require('../jwt/logger')('userPermissions.js'); - -const getAllPermissions = (url, permissions, resolve, reject) => { - axios.get(url) - .then(response => { - const allPermissions = permissions.concat(response.data.data); - if (response.data.links.next !== null) { - getAllPermissions(window.location.origin + response.data.links.next, allPermissions, resolve, reject); - } else { - resolve(allPermissions); - } - }) - .catch(error => { - log(error); - }); -}; - -const permissionsInfo = () => { - return new Promise((resolve, reject) => { - getAllPermissions(window.location.origin + '/api/rbac/v1/access/?application=*&limit=25', [], resolve, reject); - }); -}; - -module.exports = () => { - if (!window.localStorage.getItem('rbac-response') || (Date.now() > JSON.parse(window.localStorage.getItem('rbac-response')).expires)) { - return permissionsInfo().then((info) => { - // caching for 10 minutes - const expTime = Date.now() + 10 * 60 * 1000; - const data = { expires: expTime, permissions: info }; - window.localStorage.setItem('rbac-response', JSON.stringify(data)); - return data; - }) - .catch(error => { - log(error); - }); - } - else { - return new Promise((resolve, reject) => { - window.localStorage.getItem('rbac-response') ? - resolve(JSON.parse(window.localStorage.getItem('rbac-response'))) : - reject('Unable to fetch rbac-response from localStorage'); - }); - } -}; From 30f0c2022eaa2cedb502f0bc966d15ceacba1701 Mon Sep 17 00:00:00 2001 From: tahmidefaz Date: Mon, 20 Jan 2020 16:52:36 -0500 Subject: [PATCH 10/13] lint needs package-lock.json --- package-lock.json | 50 ++++++++++++++++++----------------------------- 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/package-lock.json b/package-lock.json index a809a6fbd..6b7c8dcde 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4383,6 +4383,14 @@ "js-sha256": "0.9.0" } }, + "@redhat-cloud-services/rbac-client": { + "version": "1.0.49", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/rbac-client/-/rbac-client-1.0.49.tgz", + "integrity": "sha512-9E1gcKaLLWFyfkszv6q28d5NArSlQFZcWZAQnceVm3ZZEBvimelnLlp6NTuSxkpFaidTp9YcBH/+4e3xxB+C0Q==", + "requires": { + "axios": "^0.19.0" + } + }, "@sentry/browser": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.4.3.tgz", @@ -10779,7 +10787,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -11268,7 +11275,6 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, - "optional": true, "requires": { "is-glob": "^2.0.0" } @@ -11716,7 +11722,7 @@ "dependencies": { "domelementtype": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "resolved": "http://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", "dev": true }, @@ -12194,8 +12200,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true, - "optional": true + "dev": true }, "is-finite": { "version": "1.0.2", @@ -12222,7 +12227,6 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, - "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -13575,8 +13579,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -13613,8 +13616,7 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", @@ -13623,8 +13625,7 @@ }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -13727,8 +13728,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -13738,7 +13738,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -13764,7 +13763,6 @@ "minipass": { "version": "2.3.5", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -13781,7 +13779,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -13854,8 +13851,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -13865,7 +13861,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -13941,8 +13936,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -13972,7 +13966,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -13990,7 +13983,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -14029,13 +14021,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.0.3", - "bundled": true, - "optional": true + "bundled": true } } }, @@ -16008,7 +15998,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -16018,8 +16007,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "dev": true, - "optional": true + "dev": true } } }, From 5fe8719fd8b1229ec40c8c5dd9ea17d071cbadcb Mon Sep 17 00:00:00 2001 From: tahmidefaz Date: Tue, 21 Jan 2020 16:40:23 -0500 Subject: [PATCH 11/13] attempt at async test --- package-lock.json | 159 ++++++++++++++++++++++----- package.json | 1 + src/__mocks__/rbacApi.js | 4 + src/js/rbac/fetchPermissions.test.js | 21 ++++ testdata/rbacAccess.json | 55 +++++++++ 5 files changed, 210 insertions(+), 30 deletions(-) create mode 100644 src/__mocks__/rbacApi.js create mode 100644 src/js/rbac/fetchPermissions.test.js create mode 100644 testdata/rbacAccess.json diff --git a/package-lock.json b/package-lock.json index 6b7c8dcde..a7c427e61 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3367,8 +3367,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -3389,14 +3388,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3411,20 +3408,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -3541,8 +3535,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -3554,7 +3547,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3569,7 +3561,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3577,14 +3568,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3603,7 +3592,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -3684,8 +3672,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -3697,7 +3684,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3783,8 +3769,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -3820,7 +3805,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3840,7 +3824,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3884,14 +3867,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -5340,6 +5321,14 @@ } } }, + "axios-mock-adapter": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.17.0.tgz", + "integrity": "sha512-q3efmwJUOO4g+wsLNSk9Ps1UlJoF3fQ3FSEe4uEEhkRtu7SoiAVPj8R3Hc/WP55MBTVFzaDP9QkdJhdVhP8A1Q==", + "requires": { + "deep-equal": "^1.0.1" + } + }, "babel-cli": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz", @@ -8491,6 +8480,26 @@ "integrity": "sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ=", "dev": true }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + }, + "dependencies": { + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, "deep-equal-ident": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal-ident/-/deep-equal-ident-1.1.1.tgz", @@ -12045,6 +12054,11 @@ "is-decimal": "^1.0.0" } }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -20270,6 +20284,91 @@ "integrity": "sha512-nUmxvfJyAODw+0B13hj8CFVAxhe7fDEAgJgaotBu3nnR+IgGgZq59YedJP5VYTlkEfqjuK6TuRpnymKdatLZfQ==", "dev": true }, + "regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "requires": { + "has": "^1.0.3" + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + } + } + }, "regexpp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", diff --git a/package.json b/package.json index 0553875a2..c6c964bdb 100644 --- a/package.json +++ b/package.json @@ -125,6 +125,7 @@ "@sentry/browser": "^5.4.3", "axios": "^0.19.0", "axios-cache-adapter": "^2.3.0", + "axios-mock-adapter": "^1.17.0", "babel-plugin-rewire": "^1.2.0", "babel-preset-es2015": "^6.24.1", "broadcast-channel": "^2.1.9", diff --git a/src/__mocks__/rbacApi.js b/src/__mocks__/rbacApi.js new file mode 100644 index 000000000..144fcd0f2 --- /dev/null +++ b/src/__mocks__/rbacApi.js @@ -0,0 +1,4 @@ +import accessRbac from '../js/rbac/rbac.js'; +import MockAdapter from 'axios-mock-adapter'; + +export const mock = new MockAdapter(accessRbac('uSeRtOkEn').axios); \ No newline at end of file diff --git a/src/js/rbac/fetchPermissions.test.js b/src/js/rbac/fetchPermissions.test.js new file mode 100644 index 000000000..b052546bb --- /dev/null +++ b/src/js/rbac/fetchPermissions.test.js @@ -0,0 +1,21 @@ +import { fetchPermissions } from './fetchPermissions'; +import { mock } from '../../__mocks__/rbacApi'; +import mockedRbac from '../../../testdata/rbacAccess.json'; + +// jest.mock('axios'); + +it('should send the data as array', async () => { + mock.onGet('/api/rbac/v1/access/?application=*&limit=25').reply(200, mockedRbac); + const data = await fetchPermissions('uSeRtOkEn'); + expect(mock.history.get.length).toBe(1); + data.then(permissions => expect(permissions).toEqual(mockedRbac.data)); +}); + +// it('should send the data as JSON', async () => { +// axios.get.mockResolvedValue(mockedRbac.data); + +// const data = await fetchPermissions('uSeRtOkEn').expect(200,done); +// // console.log(mockedRbac.data) + +// data.then(permissions => expect(permissions).toEqual(mockedRbac.data)); +// }, 10000); \ No newline at end of file diff --git a/testdata/rbacAccess.json b/testdata/rbacAccess.json new file mode 100644 index 000000000..930502ad0 --- /dev/null +++ b/testdata/rbacAccess.json @@ -0,0 +1,55 @@ +{ + "meta": { + "count": 10, + "limit": 25, + "offset": 0 + }, + "links": { + "first": "/api/rbac/v1/access/?application=%2A&limit=10&offset=0", + "next": null, + "previous": null, + "last": "/api/rbac/v1/access/?application=%2A&limit=10&offset=0" + }, + "data": [ + { + "permission": "ansible-hub:*:*", + "resourceDefinitions": [] + }, + { + "permission": "inventory:*:*", + "resourceDefinitions": [] + }, + { + "permission": "vulnerability:*:*", + "resourceDefinitions": [] + }, + { + "permission": "inventory:*:*", + "resourceDefinitions": [] + }, + { + "permission": "compliance:*:*", + "resourceDefinitions": [] + }, + { + "permission": "inventory:*:*", + "resourceDefinitions": [] + }, + { + "permission": "insights:*:*", + "resourceDefinitions": [] + }, + { + "permission": "inventory:*:*", + "resourceDefinitions": [] + }, + { + "permission": "remediations:*:*", + "resourceDefinitions": [] + }, + { + "permission": "inventory:*:*", + "resourceDefinitions": [] + } + ] +} \ No newline at end of file From aa346f688d332a964a755b357857aa9b378684e5 Mon Sep 17 00:00:00 2001 From: tahmidefaz Date: Wed, 22 Jan 2020 13:50:55 -0500 Subject: [PATCH 12/13] test --- src/__mocks__/rbacApi.js | 2 +- src/js/rbac/fetchPermissions.test.js | 14 +------------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/__mocks__/rbacApi.js b/src/__mocks__/rbacApi.js index 144fcd0f2..2e0d0f140 100644 --- a/src/__mocks__/rbacApi.js +++ b/src/__mocks__/rbacApi.js @@ -1,4 +1,4 @@ import accessRbac from '../js/rbac/rbac.js'; import MockAdapter from 'axios-mock-adapter'; -export const mock = new MockAdapter(accessRbac('uSeRtOkEn').axios); \ No newline at end of file +export const mock = new MockAdapter(accessRbac('uSeRtOkEn').axios); diff --git a/src/js/rbac/fetchPermissions.test.js b/src/js/rbac/fetchPermissions.test.js index b052546bb..7e4049beb 100644 --- a/src/js/rbac/fetchPermissions.test.js +++ b/src/js/rbac/fetchPermissions.test.js @@ -2,20 +2,8 @@ import { fetchPermissions } from './fetchPermissions'; import { mock } from '../../__mocks__/rbacApi'; import mockedRbac from '../../../testdata/rbacAccess.json'; -// jest.mock('axios'); - it('should send the data as array', async () => { mock.onGet('/api/rbac/v1/access/?application=*&limit=25').reply(200, mockedRbac); - const data = await fetchPermissions('uSeRtOkEn'); - expect(mock.history.get.length).toBe(1); + const data = fetchPermissions('uSeRtOkEn'); data.then(permissions => expect(permissions).toEqual(mockedRbac.data)); }); - -// it('should send the data as JSON', async () => { -// axios.get.mockResolvedValue(mockedRbac.data); - -// const data = await fetchPermissions('uSeRtOkEn').expect(200,done); -// // console.log(mockedRbac.data) - -// data.then(permissions => expect(permissions).toEqual(mockedRbac.data)); -// }, 10000); \ No newline at end of file From 3f83347f2a8e0206447c9e2788c93e1d4805ba6c Mon Sep 17 00:00:00 2001 From: tahmidefaz Date: Thu, 23 Jan 2020 13:14:34 -0500 Subject: [PATCH 13/13] adding test to verify the concatenation function --- src/js/rbac/fetchPermissions.test.js | 8 +++- testdata/rbacAccess.json | 68 +++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/js/rbac/fetchPermissions.test.js b/src/js/rbac/fetchPermissions.test.js index 7e4049beb..304fe6bcd 100644 --- a/src/js/rbac/fetchPermissions.test.js +++ b/src/js/rbac/fetchPermissions.test.js @@ -2,8 +2,14 @@ import { fetchPermissions } from './fetchPermissions'; import { mock } from '../../__mocks__/rbacApi'; import mockedRbac from '../../../testdata/rbacAccess.json'; -it('should send the data as array', async () => { +it('should send all the paginated data as array', async () => { mock.onGet('/api/rbac/v1/access/?application=*&limit=25').reply(200, mockedRbac); const data = fetchPermissions('uSeRtOkEn'); data.then(permissions => expect(permissions).toEqual(mockedRbac.data)); }); + +it('should send the data as array', async () => { + mock.onGet('/api/rbac/v1/access/?application=*&limit=50').reply(200, mockedRbac); + const data = fetchPermissions('uSeRtOkEn'); + data.then(permissions => expect(permissions).toEqual(mockedRbac.data)); +}); diff --git a/testdata/rbacAccess.json b/testdata/rbacAccess.json index 930502ad0..dba2da130 100644 --- a/testdata/rbacAccess.json +++ b/testdata/rbacAccess.json @@ -1,15 +1,9 @@ { "meta": { - "count": 10, + "count": 25, "limit": 25, "offset": 0 }, - "links": { - "first": "/api/rbac/v1/access/?application=%2A&limit=10&offset=0", - "next": null, - "previous": null, - "last": "/api/rbac/v1/access/?application=%2A&limit=10&offset=0" - }, "data": [ { "permission": "ansible-hub:*:*", @@ -47,6 +41,66 @@ "permission": "remediations:*:*", "resourceDefinitions": [] }, + { + "permission": "inventory:*:*", + "resourceDefinitions": [] + }, + { + "permission": "ansible-hub:*:*", + "resourceDefinitions": [] + }, + { + "permission": "inventory:*:*", + "resourceDefinitions": [] + }, + { + "permission": "vulnerability:*:*", + "resourceDefinitions": [] + }, + { + "permission": "inventory:*:*", + "resourceDefinitions": [] + }, + { + "permission": "compliance:*:*", + "resourceDefinitions": [] + }, + { + "permission": "inventory:*:*", + "resourceDefinitions": [] + }, + { + "permission": "insights:*:*", + "resourceDefinitions": [] + }, + { + "permission": "inventory:*:*", + "resourceDefinitions": [] + }, + { + "permission": "remediations:*:*", + "resourceDefinitions": [] + }, + { + "permission": "inventory:*:*", + "resourceDefinitions": [] + }, + { + "permission": "inventory:*:*", + "resourceDefinitions": [] + }, + { + "permission": "insights:*:*", + "resourceDefinitions": [] + }, + { + "permission": "inventory:*:*", + "resourceDefinitions": [] + }, + { + "permission": "remediations:*:*", + "resourceDefinitions": [] + }, { "permission": "inventory:*:*", "resourceDefinitions": []