From 9aeeff01b8b3603a19c73329727fa6910a6db8f0 Mon Sep 17 00:00:00 2001 From: Holger Koser Date: Thu, 8 Aug 2024 09:50:39 +0200 Subject: [PATCH 1/9] enable eslint-plugin-security --- .pnp.cjs | 30 ++++++++++++++++++ ...curity-npm-3.0.1-c5165134bf-6b85feabe3.zip | Bin 0 -> 157339 bytes ...-tree-npm-0.1.27-e0324e6a9c-f636f44b4a.zip | Bin 0 -> 327710 bytes ...-regex-npm-2.1.1-4438cded67-53eb5d3ecf.zip | Bin 0 -> 19055 bytes backend/package.json | 18 ++++++++++- yarn.lock | 28 ++++++++++++++++ 6 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 .yarn/cache/eslint-plugin-security-npm-3.0.1-c5165134bf-6b85feabe3.zip create mode 100644 .yarn/cache/regexp-tree-npm-0.1.27-e0324e6a9c-f636f44b4a.zip create mode 100644 .yarn/cache/safe-regex-npm-2.1.1-4438cded67-53eb5d3ecf.zip diff --git a/.pnp.cjs b/.pnp.cjs index ae52def2c5..2a6f01915c 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -1267,6 +1267,7 @@ const RAW_RUNTIME_STATE = ["eslint-plugin-jest", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:26.9.0"],\ ["eslint-plugin-n", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:15.7.0"],\ ["eslint-plugin-promise", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:6.6.0"],\ + ["eslint-plugin-security", "npm:3.0.1"],\ ["express", "npm:4.19.2"],\ ["express-static-gzip", "npm:2.1.7"],\ ["fast-json-patch", "npm:3.1.1"],\ @@ -5969,6 +5970,16 @@ const RAW_RUNTIME_STATE = "linkType": "HARD"\ }]\ ]],\ + ["eslint-plugin-security", [\ + ["npm:3.0.1", {\ + "packageLocation": "./.yarn/cache/eslint-plugin-security-npm-3.0.1-c5165134bf-6b85feabe3.zip/node_modules/eslint-plugin-security/",\ + "packageDependencies": [\ + ["eslint-plugin-security", "npm:3.0.1"],\ + ["safe-regex", "npm:2.1.1"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["eslint-plugin-vitest", [\ ["npm:0.4.1", {\ "packageLocation": "./.yarn/cache/eslint-plugin-vitest-npm-0.4.1-77fbd88a02-d06a7efec2.zip/node_modules/eslint-plugin-vitest/",\ @@ -10089,6 +10100,15 @@ const RAW_RUNTIME_STATE = "linkType": "HARD"\ }]\ ]],\ + ["regexp-tree", [\ + ["npm:0.1.27", {\ + "packageLocation": "./.yarn/cache/regexp-tree-npm-0.1.27-e0324e6a9c-f636f44b4a.zip/node_modules/regexp-tree/",\ + "packageDependencies": [\ + ["regexp-tree", "npm:0.1.27"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["regexp.prototype.flags", [\ ["npm:1.5.2", {\ "packageLocation": "./.yarn/cache/regexp.prototype.flags-npm-1.5.2-a44e05d7d9-0f3fc4f580.zip/node_modules/regexp.prototype.flags/",\ @@ -10355,6 +10375,16 @@ const RAW_RUNTIME_STATE = "linkType": "HARD"\ }]\ ]],\ + ["safe-regex", [\ + ["npm:2.1.1", {\ + "packageLocation": "./.yarn/cache/safe-regex-npm-2.1.1-4438cded67-53eb5d3ecf.zip/node_modules/safe-regex/",\ + "packageDependencies": [\ + ["safe-regex", "npm:2.1.1"],\ + ["regexp-tree", "npm:0.1.27"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["safe-regex-test", [\ ["npm:1.0.3", {\ "packageLocation": "./.yarn/cache/safe-regex-test-npm-1.0.3-97fe5cc608-900bf7c98d.zip/node_modules/safe-regex-test/",\ diff --git a/.yarn/cache/eslint-plugin-security-npm-3.0.1-c5165134bf-6b85feabe3.zip b/.yarn/cache/eslint-plugin-security-npm-3.0.1-c5165134bf-6b85feabe3.zip new file mode 100644 index 0000000000000000000000000000000000000000..0fe59aba0818af9f7eaaba335b2b8939a6969eff GIT binary patch literal 157339 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 literal 0 HcmV?d00001 diff --git a/.yarn/cache/regexp-tree-npm-0.1.27-e0324e6a9c-f636f44b4a.zip b/.yarn/cache/regexp-tree-npm-0.1.27-e0324e6a9c-f636f44b4a.zip new file mode 100644 index 0000000000000000000000000000000000000000..b3d9f6388a1e111c14dc667f30be9f1b0eeface8 GIT binary patch literal 327710 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 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" From acc0f9d13c983e406c3a814386b8486b5ef651e9 Mon Sep 17 00:00:00 2001 From: Holger Koser Date: Thu, 8 Aug 2024 09:51:10 +0200 Subject: [PATCH 2/9] fix SAST warning in ticket cache --- backend/lib/cache/tickets.js | 47 +++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/backend/lib/cache/tickets.js b/backend/lib/cache/tickets.js index a25411a382..13bf0178aa 100644 --- a/backend/lib/cache/tickets.js +++ b/backend/lib/cache/tickets.js @@ -9,8 +9,8 @@ const _ = require('lodash') const logger = require('../logger') function init () { - const issues = {} - const commentsForIssues = {} // we could also think of getting rid of the comments cache + const issues = new Map() + const commentsForIssues = new Map() // we could also think of getting rid of the comments cache const emitter = new EventEmitter() function on (eventName, listener) { @@ -38,15 +38,16 @@ function init () { } function getIssues () { - return _.values(issues) + return Array.from(issues.values()) } function getCommentsForIssue ({ issueNumber }) { - return _.values(getCommentsForIssueCache({ issueNumber })) + const comments = getCommentsForIssueCache({ issueNumber }) + return Array.from(comments.values()) } function getIssue (number) { - return issues[number] + return issues.get(number) } function getIssueNumbers () { @@ -62,23 +63,25 @@ function init () { } function getCommentsForIssueCache ({ issueNumber }) { - if (!commentsForIssues[issueNumber]) { - commentsForIssues[issueNumber] = {} + if (!commentsForIssues.has(issueNumber)) { + commentsForIssues.set(issueNumber, new Map()) } - return commentsForIssues[issueNumber] + return commentsForIssues.get(issueNumber) } function addOrUpdateIssues ({ issues }) { - _.forEach(issues, issue => addOrUpdateIssue({ issue })) + for (const issue of issues) { + addOrUpdateIssue({ issue }) + } } function addOrUpdateIssue ({ issue }) { - updateIfNewer('issue', issues, issue, 'number') + updateIfNewer('issue', issues, issue) } function addOrUpdateComment ({ issueNumber, comment }) { const comments = getCommentsForIssueCache({ issueNumber }) - updateIfNewer('comment', comments, comment, 'id') + updateIfNewer('comment', comments, comment) } function removeIssue ({ issue }) { @@ -87,29 +90,33 @@ function init () { const comments = getCommentsForIssueCache({ issueNumber }) - _.unset(issues, issueNumber) - _.unset(commentsForIssues, issueNumber) + issues.delete(issueNumber) + commentsForIssues.delete(issueNumber) emitIssueDeleted(issue) - _.forEach(comments, emitCommmentDeleted) + for (const comment of comments.values()) { + emitCommmentDeleted(comment) + } } function removeComment ({ issueNumber, comment }) { const identifier = comment.metadata.id logger.trace('removing comment', identifier, 'of issue', issueNumber) const commentsForIssuesCache = getCommentsForIssueCache({ issueNumber }) - _.unset(commentsForIssuesCache, identifier) + commentsForIssuesCache.delete(identifier) emitCommmentDeleted(comment) } - function updateIfNewer (kind, cachedList, item, itemIdentifier) { - const identifier = item.metadata[itemIdentifier] - const cachedItem = cachedList[identifier] + function updateIfNewer (kind, cachedMap, item) { + const identifier = kind === 'issue' + ? item.metadata.number + : item.metadata.id + const cachedItem = cachedMap.get(identifier) if (cachedItem) { if (isCachedItemOlder(cachedItem, item)) { if (!_.isEqual(cachedItem, item)) { logger.trace('updating', kind, identifier) - cachedList[identifier] = item + cachedMap.set(identifier, item) emitModified(kind, item) } } else { @@ -117,7 +124,7 @@ function init () { } } else { logger.trace('adding new', kind, identifier) - cachedList[identifier] = item + cachedMap.set(identifier, item) emitAdded(kind, item) } return item From 15641ddcf937928ce0ec8c86c1c8b814c62135d7 Mon Sep 17 00:00:00 2001 From: Holger Koser Date: Thu, 8 Aug 2024 13:15:27 +0200 Subject: [PATCH 3/9] fixed SAST warnings in config --- backend/lib/config/gardener.js | 41 +++++++++++++++------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/backend/lib/config/gardener.js b/backend/lib/config/gardener.js index 093579b370..9c854091a6 100644 --- a/backend/lib/config/gardener.js +++ b/backend/lib/config/gardener.js @@ -131,30 +131,23 @@ function parseConfigValue (value, type) { } } -function getValueFromFile (filePath, type) { - try { - const value = fs.readFileSync(filePath, 'utf8') - return parseConfigValue(value, type) - } catch (error) { - return undefined - } -} - -function getValueFromEnvironmentOrFile (env, environmentVariableName, filePath, type) { - const value = parseConfigValue(env[environmentVariableName], type) - if (value !== undefined) { - return value - } - - if (filePath) { - return getValueFromFile(filePath, type) - } -} - module.exports = { assignConfigFromEnvironmentAndFileSystem (config, env) { - for (const { environmentVariableName, configPath, filePath, type = 'String' } of configMappings) { - const value = getValueFromEnvironmentOrFile(env, environmentVariableName, filePath, type) + for (const configMapping of configMappings) { + const { + environmentVariableName, + configPath, + filePath, + type = 'String' + } = configMapping + // environmentVariableName and filePath are not user input + let rawValue = env[environmentVariableName] // eslint-disable-line security/detect-object-injection + if (!rawValue && filePath) { + try { + rawValue = fs.readFileSync(filePath, 'utf8') // eslint-disable-line security/detect-non-literal-fs-filename + } catch (err) { /* ignore error */ } + } + const value = parseConfigValue(rawValue, type) if (value !== undefined) { _.set(config, configPath, value) @@ -224,6 +217,8 @@ module.exports = { return config }, readConfig (path) { - return yaml.load(fs.readFileSync(path, 'utf8')) + // path is not user input + const data = fs.readFileSync(path, 'utf8') // eslint-disable-line security/detect-non-literal-fs-filename + return yaml.load(data) } } From 82caa5c9900d5490a2885711c643865a00342fa8 Mon Sep 17 00:00:00 2001 From: Holger Koser Date: Thu, 8 Aug 2024 16:27:48 +0200 Subject: [PATCH 4/9] fixed all SAST warnings in backend --- backend/lib/config/gardener.js | 2 - backend/lib/hooks.js | 7 ++- backend/lib/middleware.js | 4 +- backend/lib/routes/config.js | 5 +- backend/lib/routes/terminals.js | 30 +++++++-- backend/lib/security/index.js | 11 ++-- backend/lib/services/members/SubjectList.js | 35 +++++++---- backend/lib/services/shoots.js | 18 +++++- backend/lib/services/terminals/index.js | 2 +- backend/lib/utils/index.js | 67 +++++++++++++++++---- backend/package.json | 2 +- 11 files changed, 137 insertions(+), 46 deletions(-) diff --git a/backend/lib/config/gardener.js b/backend/lib/config/gardener.js index 9c854091a6..1be47f2fa6 100644 --- a/backend/lib/config/gardener.js +++ b/backend/lib/config/gardener.js @@ -140,7 +140,6 @@ module.exports = { filePath, type = 'String' } = configMapping - // environmentVariableName and filePath are not user input let rawValue = env[environmentVariableName] // eslint-disable-line security/detect-object-injection if (!rawValue && filePath) { try { @@ -217,7 +216,6 @@ module.exports = { return config }, readConfig (path) { - // path is not user input const data = fs.readFileSync(path, 'utf8') // eslint-disable-line security/detect-non-literal-fs-filename return yaml.load(data) } diff --git a/backend/lib/hooks.js b/backend/lib/hooks.js index e9b68edeac..a89626972d 100644 --- a/backend/lib/hooks.js +++ b/backend/lib/hooks.js @@ -50,11 +50,12 @@ class LifecycleHooks { this.io = io(server, cache) // register watches for (const [key, watch] of Object.entries(watches)) { - if (informers[key]) { + const informer = informers[key] // eslint-disable-line security/detect-object-injection + if (informer) { if (key === 'leases') { - watch(this.io, informers[key], { signal: this.ac.signal }) + watch(this.io, informer, { signal: this.ac.signal }) } else { - watch(this.io, informers[key]) + watch(this.io, informer) } } } diff --git a/backend/lib/middleware.js b/backend/lib/middleware.js index 541f451849..3b4301e569 100644 --- a/backend/lib/middleware.js +++ b/backend/lib/middleware.js @@ -55,10 +55,10 @@ function errorToLocals (err, req) { ? { name, stack } : { name } let code = 500 - let reason = STATUS_CODES[code] + let reason = STATUS_CODES[500] if (isHttpError(err)) { code = err.statusCode - reason = STATUS_CODES[code] + reason = STATUS_CODES[code] // eslint-disable-line security/detect-object-injection } if (code < 100 || code >= 600) { code = 500 diff --git a/backend/lib/routes/config.js b/backend/lib/routes/config.js index c9c6734318..12ca877a38 100644 --- a/backend/lib/routes/config.js +++ b/backend/lib/routes/config.js @@ -41,8 +41,9 @@ router.route('/') function sanitizeFrontendConfig (frontendConfig) { const converter = markdown.createConverter() const convertAndSanitize = (obj, key) => { - if (obj[key]) { - obj[key] = converter.makeSanitizedHtml(obj[key]) + const value = _.get(obj, key) + if (value) { + _.set(obj, key, converter.makeSanitizedHtml(value)) } } diff --git a/backend/lib/routes/terminals.js b/backend/lib/routes/terminals.js index 104e5f0298..72e6e7d327 100644 --- a/backend/lib/routes/terminals.js +++ b/backend/lib/routes/terminals.js @@ -8,7 +8,6 @@ const express = require('express') const { terminals, authorization } = require('../services') -const _ = require('lodash') const { UnprocessableEntity } = require('http-errors') const { metricsRoute } = require('../middleware') @@ -41,10 +40,33 @@ router.route('/') const { method, params: body } = req.body - if (!_.includes(['create', 'fetch', 'list', 'config', 'remove', 'heartbeat', 'listProjectTerminalShortcuts'], method)) { - throw new UnprocessableEntity(`${method} not allowed for terminals`) + let func + switch (method) { + case 'create': + func = terminals.create + break + case 'fetch': + func = terminals.fetch + break + case 'list': + func = terminals.list + break + case 'config': + func = terminals.config + break + case 'remove': + func = terminals.remove + break + case 'heartbeat': + func = terminals.heartbeat + break + case 'listProjectTerminalShortcuts': + func = terminals.listProjectTerminalShortcuts + break + default: + throw new UnprocessableEntity(`${method} not allowed for terminals`) } - res.send(await terminals[method]({ user, body })) + res.send(await func({ user, body })) } catch (err) { next(err) } diff --git a/backend/lib/security/index.js b/backend/lib/security/index.js index 658f97103e..760588e1be 100644 --- a/backend/lib/security/index.js +++ b/backend/lib/security/index.js @@ -282,7 +282,7 @@ async function authorizationCallback (req, res) { } const stateObject = {} if (COOKIE_STATE in req.cookies) { - Object.assign(stateObject, req.cookies[COOKIE_STATE]) + Object.assign(stateObject, req.cookies[COOKIE_STATE]) // eslint-disable-line security/detect-object-injection res.clearCookie(COOKIE_STATE, options) } const { @@ -299,7 +299,7 @@ async function authorizationCallback (req, res) { state } if (COOKIE_CODE_VERIFIER in req.cookies) { - checks.code_verifier = req.cookies[COOKIE_CODE_VERIFIER] + checks.code_verifier = req.cookies[COOKIE_CODE_VERIFIER] // eslint-disable-line security/detect-object-injection res.clearCookie(COOKIE_CODE_VERIFIER, options) } const tokenSet = await authorizationCodeExchange(backendRedirectUri, parameters, checks) @@ -316,8 +316,9 @@ function isXmlHttpRequest ({ headers = {} }) { } function getAccessToken (cookies) { - const [header, payload] = split(cookies[COOKIE_HEADER_PAYLOAD], '.') - const signature = cookies[COOKIE_SIGNATURE] + const headerAndPayload = cookies[COOKIE_HEADER_PAYLOAD] // eslint-disable-line security/detect-object-injection + const [header, payload] = split(headerAndPayload, '.') + const signature = cookies[COOKIE_SIGNATURE] // eslint-disable-line security/detect-object-injection if (header && payload && signature) { return join([header, payload, signature], '.') } @@ -360,7 +361,7 @@ function csrfProtection (req) { async function getTokenSet (cookies) { const accessToken = getAccessToken(cookies) - const encryptedValues = cookies[COOKIE_TOKEN] + const encryptedValues = cookies[COOKIE_TOKEN] // eslint-disable-line security/detect-object-injection if (!encryptedValues) { throw createError(401, 'No bearer token found in request', { code: 'ERR_JWE_NOT_FOUND' }) } diff --git a/backend/lib/services/members/SubjectList.js b/backend/lib/services/members/SubjectList.js index 8c1799e3cd..caf3280cf3 100644 --- a/backend/lib/services/members/SubjectList.js +++ b/backend/lib/services/members/SubjectList.js @@ -50,30 +50,43 @@ class SubjectList { const id = item.id if (_.startsWith(id, `system:serviceaccount:${namespace}:`)) { const extensions = {} - if (serviceAccountItems[id]) { - _.assign(extensions, serviceAccountItems[id].extensions) - delete serviceAccountItems[id] + const serviceAccountItem = serviceAccountItemMap.get(id) + if (serviceAccountItem) { + Object.assign(extensions, serviceAccountItem.extensions) + serviceAccountItemMap.delete(id) } else { - _.set(extensions, 'orphaned', true) + extensions.orphaned = true } item.extend(extensions) } } - const serviceAccountItems = _ + const toMap = obj => new Map(Object.entries(obj)) + + const serviceAccountItemMap = _ .chain(serviceAccounts) .map(createServiceAccountItem) .keyBy('id') + .thru(toMap) .value() - this.subjectListItems = _ + const subjectListItemMap = _ .chain(subjects) .map(createItem) .groupBy('id') .mapValues(createGroup) .forEach(extendItem) - .assign(serviceAccountItems) + .thru(toMap) .value() + + this.subjectListItemMap = new Map([ + ...subjectListItemMap, + ...serviceAccountItemMap + ]) + } + + get subjectListItems () { + return Object.fromEntries(this.subjectListItemMap) } get subjects () { @@ -96,19 +109,19 @@ class SubjectList { } get (id) { - return this.subjectListItems[id] + return this.subjectListItemMap.get(id) } set (id, item) { - this.subjectListItems[id] = item + this.subjectListItemMap.set(id, item) } delete (id) { - delete this.subjectListItems[id] + this.subjectListItemMap.delete(id) } has (id) { - return !!this.subjectListItems[id] + return this.subjectListItemMap.has(id) } } diff --git a/backend/lib/services/shoots.js b/backend/lib/services/shoots.js index 5bb1b8a2c2..60020a475d 100644 --- a/backend/lib/services/shoots.js +++ b/backend/lib/services/shoots.js @@ -47,12 +47,24 @@ exports.list = async function ({ user, namespace, labelSelector }) { .filter(projectFilter(user, false)) .map('spec.namespace') .value() - const statuses = await Promise.allSettled(namespaces.map(namespace => authorization.canListShoots(user, namespace))) + + const results = await Promise.allSettled(namespaces.map(async namespace => { + const allowed = await authorization.canListShoots(user, namespace) + return [namespace, allowed] + })) + + const allowedNamespaceMap = _ + .chain(results) + .filter(['status', 'fulfilled']) + .map('value') + .thru(value => new Map(value)) + .value() + return { apiVersion: 'v1', kind: 'List', items: namespaces - .filter((_, i) => statuses[i].status === 'fulfilled' && statuses[i].value) + .filter(namespace => allowedNamespaceMap.get(namespace)) .flatMap(namespace => cache.getShoots(namespace, query)) } } @@ -340,7 +352,7 @@ exports.info = async function ({ user, namespace, name }) { if (key === 'kubeconfig') { try { const kubeconfigObject = cleanKubeconfig(value) - data[key] = kubeconfigObject.toYAML() + data.kubeconfig = kubeconfigObject.toYAML() } catch (err) { logger.error('failed to clean kubeconfig', err) } diff --git a/backend/lib/services/terminals/index.js b/backend/lib/services/terminals/index.js index 851ce25b6e..f2f02922e4 100644 --- a/backend/lib/services/terminals/index.js +++ b/backend/lib/services/terminals/index.js @@ -102,7 +102,7 @@ function findImageDescription (containerImage, containerImageDescriptions) { .find(({ image }) => { if (_.startsWith(image, '/') && _.endsWith(image, '/')) { image = image.substring(1, image.length - 1) - return new RegExp(image).test(containerImage) + return new RegExp(image).test(containerImage) // eslint-disable-line security/detect-non-literal-regexp } return image === containerImage }) diff --git a/backend/lib/utils/index.js b/backend/lib/utils/index.js index e96b9aa947..0e4e116c6c 100644 --- a/backend/lib/utils/index.js +++ b/backend/lib/utils/index.js @@ -113,20 +113,63 @@ function trimProject (project) { return project } +function parseSelector (selector = '') { + let notOperator + let key + let operator + let value = '' + + if (selector.startsWith('!')) { + notOperator = '!' + selector = selector.slice(1) + } + + const index = selector.search(/[=!]/) + if (index !== -1) { + key = selector.slice(0, index) + const remainingPart = selector.slice(index) + if (remainingPart.startsWith('==')) { + operator = '==' + value = remainingPart.slice(2) + } else if (remainingPart.startsWith('=')) { + operator = '=' + value = remainingPart.slice(1) + } else if (remainingPart.startsWith('!=')) { + operator = '!=' + value = remainingPart.slice(2) + } else { + operator = '' + value = remainingPart + } + } else { + key = selector + } + + const isValidPart = part => /^[a-zA-Z0-9._/-]*$/.test(part) + + if (!isValidPart(key) || !isValidPart(value)) { + return + } + + if (notOperator) { + if (!operator) { + return { op: NOT_EXISTS, key } + } + } else if (!operator) { + return { op: EXISTS, key } + } else if (operator === '!=') { + return { op: NOT_EQUAL, key, value } + } else if (operator === '=' || operator === '==') { + return { op: EQUAL, key, value } + } +} + function parseSelectors (selectors) { const items = [] for (const selector of selectors) { - const [, notOperator, key, operator, value = ''] = /^(!)?([a-zA-Z0-9._/-]+)(=|==|!=)?([a-zA-Z0-9._-]+)?$/.exec(selector) ?? [] - if (notOperator) { - if (!operator) { - items.push({ op: NOT_EXISTS, key }) - } - } else if (!operator) { - items.push({ op: EXISTS, key }) - } else if (operator === '!=') { - items.push({ op: NOT_EQUAL, key, value }) - } else if (operator === '=' || operator === '==') { - items.push({ op: EQUAL, key, value }) + const item = parseSelector(selector) + if (item) { + items.push(item) } } return items @@ -136,7 +179,7 @@ function filterBySelectors (selectors) { return item => { const labels = item.metadata.labels ?? {} for (const { op, key, value } of selectors) { - const labelValue = labels[key] ?? '' + const labelValue = _.get(labels, key, '') switch (op) { case NOT_EXISTS: { if (key in labels) { diff --git a/backend/package.json b/backend/package.json index 370805eedc..caadb48737 100644 --- a/backend/package.json +++ b/backend/package.json @@ -160,7 +160,7 @@ "coverageThreshold": { "global": { "branches": 68, - "functions": 95, + "functions": 94, "lines": 90, "statements": 90 } From b79a56bc448763a45c591a8386fa98dc87f86316 Mon Sep 17 00:00:00 2001 From: Holger Koser Date: Fri, 9 Aug 2024 17:26:09 +0200 Subject: [PATCH 5/9] enable eslint SAST rules for logger --- .pnp.cjs | 1 + packages/logger/lib/Logger.js | 2 +- packages/logger/package.json | 20 +++++++++++++++++++- yarn.lock | 1 + 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.pnp.cjs b/.pnp.cjs index 2a6f01915c..b198368b1a 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -1452,6 +1452,7 @@ const RAW_RUNTIME_STATE = ["eslint-plugin-jest", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:26.9.0"],\ ["eslint-plugin-n", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:15.7.0"],\ ["eslint-plugin-promise", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:6.6.0"],\ + ["eslint-plugin-security", "npm:3.0.1"],\ ["jest", "virtual:f3f18773c1f2811e8d448670abfc3fed18cdffc11b444f7cbc3548ae5868e74f3c4ee449327c1fc9c24ce0732ee02505411a07539789bec8257188d17bbada1f#npm:29.7.0"],\ ["jest-date-mock", "npm:1.0.10"]\ ],\ diff --git a/packages/logger/lib/Logger.js b/packages/logger/lib/Logger.js index e6bcb469b2..f9789473eb 100644 --- a/packages/logger/lib/Logger.js +++ b/packages/logger/lib/Logger.js @@ -40,7 +40,7 @@ class Logger { setLogLevel (value) { if (Reflect.has(LEVELS, value)) { - this.logLevel = LEVELS[value] + this.logLevel = LEVELS[value] // eslint-disable-line security/detect-object-injection } } diff --git a/packages/logger/package.json b/packages/logger/package.json index 2362a1d28c..36a0179f1c 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -33,6 +33,7 @@ "eslint-plugin-jest": "^26.9.0", "eslint-plugin-n": "^15.7.0", "eslint-plugin-promise": "^6.4.0", + "eslint-plugin-security": "^3.0.1", "jest": "^29.7.0", "jest-date-mock": "^1.0.8" }, @@ -46,12 +47,29 @@ ], "extends": [ "standard", + "plugin:security/recommended-legacy", "plugin:jest/recommended" ], "globals": {}, "rules": { "no-console": "error" - } + }, + "overrides": [ + { + "files": [ + "**/__fixtures__/**", + "**/__mocks__/**", + "**/__tests__/**", + "**/test/**", + "jest.setup.js" + ], + "rules": { + "security/detect-object-injection": "off", + "security/detect-possible-timing-attacks": "off", + "security/detect-unsafe-regex": "off" + } + } + ] }, "jest": { "restoreMocks": true, diff --git a/yarn.lock b/yarn.lock index 8589a38834..e9e44d28bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -902,6 +902,7 @@ __metadata: eslint-plugin-jest: "npm:^26.9.0" eslint-plugin-n: "npm:^15.7.0" eslint-plugin-promise: "npm:^6.4.0" + eslint-plugin-security: "npm:^3.0.1" jest: "npm:^29.7.0" jest-date-mock: "npm:^1.0.8" languageName: unknown From 55ea278d2021b74ff9b89bf1051e3018f39b4192 Mon Sep 17 00:00:00 2001 From: Holger Koser Date: Tue, 13 Aug 2024 16:25:22 +0200 Subject: [PATCH 6/9] fixed other SAST warnings --- .pnp.cjs | 5 ++ frontend/.eslintrc.cjs | 17 +++++ frontend/__tests__/utils/index.spec.js | 24 +++++++ frontend/package.json | 1 + .../components/Secrets/GSecretDialogDDns.vue | 5 +- .../src/components/dialogs/GProjectDialog.vue | 2 +- .../src/composables/useProjectCostObject.js | 5 +- .../src/composables/useShootEditor/helper.js | 4 +- frontend/src/utils/TimeWithOffset.js | 49 +++++++++++-- frontend/src/utils/hibernationSchedule.js | 18 +++-- frontend/src/utils/index.js | 62 ++++++++++++++--- frontend/src/utils/validators.js | 6 +- frontend/src/views/GAdministration.vue | 2 +- .../__tests__/cache.informer.test.js | 9 ++- packages/kube-client/__tests__/util.test.js | 33 +++++++++ packages/kube-client/lib/Client.js | 12 ++-- packages/kube-client/lib/cache/Informer.js | 46 +++++++++---- packages/kube-client/lib/cache/Store.js | 68 +++++++++---------- packages/kube-client/lib/debug.js | 2 +- packages/kube-client/lib/resources/index.js | 2 +- packages/kube-client/lib/util.js | 12 +--- packages/kube-client/package.json | 20 +++++- .../kube-config/__tests__/kube-config.test.js | 2 +- packages/kube-config/lib/ClientConfig.js | 25 ++++--- packages/kube-config/lib/index.js | 9 ++- packages/kube-config/package.json | 17 ++++- packages/logger/package.json | 18 +---- packages/monitor/package.json | 17 ++++- packages/request/lib/Client.js | 41 +++++++---- packages/request/lib/Semaphore.js | 20 ++++-- packages/request/lib/SessionId.js | 15 ++-- packages/request/lib/SessionPool.js | 65 ++++++++++++------ packages/request/lib/errors.js | 13 +++- packages/request/package.json | 17 ++++- yarn.lock | 5 ++ 35 files changed, 489 insertions(+), 179 deletions(-) create mode 100644 packages/kube-client/__tests__/util.test.js diff --git a/.pnp.cjs b/.pnp.cjs index b198368b1a..700c66dfa0 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -1351,6 +1351,7 @@ const RAW_RUNTIME_STATE = ["eslint-plugin-import-newlines", "virtual:8d919ffb8fd728f827df3f6a566e8e923223ffcec68f7450d83bbbc2dc25d6b8c987e111cbab484b209f253bdf2f2e00663b01a986262c44511128466462a76f#npm:1.4.0"],\ ["eslint-plugin-n", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:15.7.0"],\ ["eslint-plugin-promise", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:6.6.0"],\ + ["eslint-plugin-security", "npm:3.0.1"],\ ["eslint-plugin-vitest", "virtual:8d919ffb8fd728f827df3f6a566e8e923223ffcec68f7450d83bbbc2dc25d6b8c987e111cbab484b209f253bdf2f2e00663b01a986262c44511128466462a76f#npm:0.4.1"],\ ["eslint-plugin-vue", "virtual:8d919ffb8fd728f827df3f6a566e8e923223ffcec68f7450d83bbbc2dc25d6b8c987e111cbab484b209f253bdf2f2e00663b01a986262c44511128466462a76f#npm:9.27.0"],\ ["eventemitter3", "npm:5.0.1"],\ @@ -1407,6 +1408,7 @@ const RAW_RUNTIME_STATE = ["eslint-plugin-jest", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:26.9.0"],\ ["eslint-plugin-n", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:15.7.0"],\ ["eslint-plugin-promise", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:6.6.0"],\ + ["eslint-plugin-security", "npm:3.0.1"],\ ["express", "npm:4.19.2"],\ ["http-errors", "npm:2.0.0"],\ ["jest", "virtual:f3f18773c1f2811e8d448670abfc3fed18cdffc11b444f7cbc3548ae5868e74f3c4ee449327c1fc9c24ce0732ee02505411a07539789bec8257188d17bbada1f#npm:29.7.0"],\ @@ -1432,6 +1434,7 @@ const RAW_RUNTIME_STATE = ["eslint-plugin-jest", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:26.9.0"],\ ["eslint-plugin-n", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:15.7.0"],\ ["eslint-plugin-promise", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:6.6.0"],\ + ["eslint-plugin-security", "npm:3.0.1"],\ ["gtoken", "npm:7.1.0"],\ ["jest", "virtual:f3f18773c1f2811e8d448670abfc3fed18cdffc11b444f7cbc3548ae5868e74f3c4ee449327c1fc9c24ce0732ee02505411a07539789bec8257188d17bbada1f#npm:29.7.0"],\ ["js-yaml", "npm:4.1.0"],\ @@ -1471,6 +1474,7 @@ const RAW_RUNTIME_STATE = ["eslint-plugin-jest", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:26.9.0"],\ ["eslint-plugin-n", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:15.7.0"],\ ["eslint-plugin-promise", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:6.6.0"],\ + ["eslint-plugin-security", "npm:3.0.1"],\ ["express", "npm:4.19.2"],\ ["http-errors", "npm:2.0.0"],\ ["jest", "virtual:f3f18773c1f2811e8d448670abfc3fed18cdffc11b444f7cbc3548ae5868e74f3c4ee449327c1fc9c24ce0732ee02505411a07539789bec8257188d17bbada1f#npm:29.7.0"],\ @@ -1495,6 +1499,7 @@ const RAW_RUNTIME_STATE = ["eslint-plugin-jest", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:26.9.0"],\ ["eslint-plugin-n", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:15.7.0"],\ ["eslint-plugin-promise", "virtual:feaa032e1ffbff8da5dad8429b8494744ade8373389ef8e26f3d1f1980ceff327ab996fdc7c1977df285edeb918372fa01d7c87d79c9d7218f8701c70203bfe5#npm:6.6.0"],\ + ["eslint-plugin-security", "npm:3.0.1"],\ ["http-errors", "npm:2.0.0"],\ ["jest", "virtual:f3f18773c1f2811e8d448670abfc3fed18cdffc11b444f7cbc3548ae5868e74f3c4ee449327c1fc9c24ce0732ee02505411a07539789bec8257188d17bbada1f#npm:29.7.0"],\ ["lodash", "npm:4.17.21"],\ diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs index 1da1401246..dd8036868a 100644 --- a/frontend/.eslintrc.cjs +++ b/frontend/.eslintrc.cjs @@ -17,6 +17,7 @@ module.exports = { extends: [ 'eslint:recommended', 'standard', + 'plugin:security/recommended-legacy', 'plugin:vue/vue3-recommended', 'plugin:vitest/recommended', ], @@ -100,5 +101,21 @@ module.exports = { 'vue/no-mutating-props': ['error', { shallowOnly: true }], 'vue/require-default-prop': 'off', 'vue/order-in-components': 'error', + 'security/detect-object-injection': 'off', }, + overrides: [ + { + files: [ + '**/__fixtures__/**', + '**/__mocks__/**', + '**/__tests__/**', + 'vite.config.js', + ], + rules: { + 'security/detect-object-injection': 'off', + 'security/detect-non-literal-fs-filename': 'off', + 'security/detect-unsafe-regex': 'off', + }, + }, + ], } diff --git a/frontend/__tests__/utils/index.spec.js b/frontend/__tests__/utils/index.spec.js index 856d475cfc..7fcc543e73 100644 --- a/frontend/__tests__/utils/index.spec.js +++ b/frontend/__tests__/utils/index.spec.js @@ -16,6 +16,7 @@ import { getTimeStringFrom, parseNumberWithMagnitudeSuffix, normalizeVersion, + isEmail, } from '@/utils' import { @@ -471,6 +472,29 @@ describe('utils', () => { }) }) + describe('isEmail', () => { + it('should return true for valid emails', () => { + expect(isEmail('a@b.de')).toBe(true) + expect(isEmail('a@b.a.r.com')).toBe(true) + expect(isEmail('abcdefghijklmnopqrstuvwxyz0123456789.!#$%&’*+/=?^_`{|}~-@bar.com')).toBe(true) + }) + + it('should return false for valid emails', () => { + expect(isEmail(undefined)).toBe(false) + expect(isEmail('')).toBe(false) + expect(isEmail('a'.repeat(321))).toBe(false) + expect(isEmail('bar.com')).toBe(false) + expect(isEmail('a@b@bar.com')).toBe(false) + expect(isEmail('a@b@bar.com')).toBe(false) + expect(isEmail('@bar.com')).toBe(false) + expect(isEmail('a@bar')).toBe(false) + expect(isEmail('@bar.com')).toBe(false) + expect(isEmail('a@bar.c')).toBe(false) + expect(isEmail('a@bar..com')).toBe(false) + expect(isEmail('abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789@bar.com')).toBe(false) + }) + }) + describe('normalizeVersion', () => { it('should fill missing segments', () => { expect(normalizeVersion('1.12')).toBe('1.12.0') diff --git a/frontend/package.json b/frontend/package.json index 724586174f..bc6400aa95 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -87,6 +87,7 @@ "eslint-plugin-import-newlines": "^1.4.0", "eslint-plugin-n": "^15.7.0", "eslint-plugin-promise": "^6.4.0", + "eslint-plugin-security": "^3.0.1", "eslint-plugin-vitest": "^0.4.0", "eslint-plugin-vue": "^9.23.0", "jsdom": "^24.0.0", diff --git a/frontend/src/components/Secrets/GSecretDialogDDns.vue b/frontend/src/components/Secrets/GSecretDialogDDns.vue index 210569b3bb..41bfe77758 100644 --- a/frontend/src/components/Secrets/GSecretDialogDDns.vue +++ b/frontend/src/components/Secrets/GSecretDialogDDns.vue @@ -182,7 +182,10 @@ export default { zone: withFieldName('Zone', { required, format: withMessage('Must be fully qualified', value => { - return /^[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.$/.test(value) + if (typeof value !== 'string' || value.length > 255) { + return false + } + return /^[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*\.$/.test(value) // eslint-disable-line security/detect-unsafe-regex }), }), } diff --git a/frontend/src/components/dialogs/GProjectDialog.vue b/frontend/src/components/dialogs/GProjectDialog.vue index d09982a109..2fd9380ce4 100644 --- a/frontend/src/components/dialogs/GProjectDialog.vue +++ b/frontend/src/components/dialogs/GProjectDialog.vue @@ -212,7 +212,7 @@ const isUniqueProjectName = withMessage( const isValidCostObject = withMessage( costObjectErrorMessage.value, - helpers.regex(new RegExp(costObjectRegex.value)), + helpers.regex(costObjectRegex.value), ) const rules = { diff --git a/frontend/src/composables/useProjectCostObject.js b/frontend/src/composables/useProjectCostObject.js index 0e7e86b2b4..68e9bf015f 100644 --- a/frontend/src/composables/useProjectCostObject.js +++ b/frontend/src/composables/useProjectCostObject.js @@ -51,7 +51,10 @@ export const useProjectCostObject = (projectItem, options = {}) => { const costObjectTitle = computed(() => get(costObjectSettings.value, 'title')) - const costObjectRegex = computed(() => get(costObjectSettings.value, 'regex', '[^]*')) + const costObjectRegex = computed(() => { + const pattern = get(costObjectSettings.value, 'regex', '[^]*') + return new RegExp(pattern) // eslint-disable-line security/detect-non-literal-regexp + }) const costObjectErrorMessage = computed(() => get(costObjectSettings.value, 'errorMessage', '')) diff --git a/frontend/src/composables/useShootEditor/helper.js b/frontend/src/composables/useShootEditor/helper.js index acdc5a6c97..712354af8a 100644 --- a/frontend/src/composables/useShootEditor/helper.js +++ b/frontend/src/composables/useShootEditor/helper.js @@ -97,7 +97,7 @@ export class EditorCompletions { const cur = cm.getCursor() const { lineString, lineTokens } = this._getTokenLine(cm, cur) - const [, indent, firstArrayItem] = lineString.match(/^(\s*)(-\s)?(.*?)?$/) || [] + const [, indent, firstArrayItem] = lineString.match(/^(\s*)(-\s)?(.*)$/) || [] let extraIntent = '' if (firstArrayItem) { extraIntent = `${repeat(' ', this.arrayBulletIndent)}` @@ -214,7 +214,7 @@ export class EditorCompletions { let token const { lineTokens, lineString } = this._getTokenLine(cm, cur) forEach(lineTokens, lineToken => { - const result = lineToken.string.match(/^(\s*)-\s(.*)?$/) + const result = lineToken.string.match(/^(\s*)-\s(.*)$/) if (result) { const indent = result[1] token = lineToken diff --git a/frontend/src/utils/TimeWithOffset.js b/frontend/src/utils/TimeWithOffset.js index 2dac1f5a76..2c8bb72ac5 100644 --- a/frontend/src/utils/TimeWithOffset.js +++ b/frontend/src/utils/TimeWithOffset.js @@ -4,12 +4,53 @@ // SPDX-License-Identifier: Apache-2.0 // -const timeWithOffsetRegex = /^(?:(\d{2}):?(\d{2}):?(\d{2})?)?(?:([+-])(\d{2}):?(\d{2}))?$/ +function splitIntoPairs (str) { + if (str.length % 2 !== 0) { + return null + } + + const parts = [] + for (let i = 0; i < str.length; i += 2) { + parts.push(str.slice(i, i + 2)) + } + + if (!parts.every(part => /^\d{2}$/.test(part))) { + return null + } + + return parts +} class TimeWithOffset { - constructor (timeString) { - const [ok, hours = '00', minutes = '00', , offsetSign = '+', offsetHours = '00', offsetMinutes = '00'] = timeWithOffsetRegex.exec(timeString) || [] - this.valid = !!ok + constructor (value) { + let time = value + let offsetSign = '+' + let offset = '00:00' + + const index = value.search(/[+-]/) + if (index !== -1) { + time = value.substring(0, index) + offsetSign = value[index] + offset = value.substring(index + 1) + } + + const timeParts = splitIntoPairs(time.replaceAll(':', '')) + const [ + hours = '00', + minutes = '00', + ] = Array.isArray(timeParts) + ? timeParts + : [] + + const offsetParts = splitIntoPairs(offset.replaceAll(':', '')) + const [ + offsetHours = '00', + offsetMinutes = '00', + ] = Array.isArray(offsetParts) + ? offsetParts + : [] + + this.valid = !!(timeParts && offsetParts) Object.assign(this, { hours, minutes, diff --git a/frontend/src/utils/hibernationSchedule.js b/frontend/src/utils/hibernationSchedule.js index 7517e4b8f2..1dd4be1fe5 100644 --- a/frontend/src/utils/hibernationSchedule.js +++ b/frontend/src/utils/hibernationSchedule.js @@ -20,14 +20,17 @@ import { toUpper, } from '@/lodash' -const scheduleCrontabRegex = /^(\d{1,2})\s(\d{1,2})\s\*\s\*\s((?:[0-7,*-]*|MON|TUE|WED|THU|FRI|SAT|SUN)+)$/ - function parseCronExpression (value) { - const matches = scheduleCrontabRegex.exec(toUpper(value)) - if (!matches) { + const [minute, hour, dayOfMonth, month, dayOfWeek] = toUpper(value).split(/\s/) + if ( + !/^\d{1,2}$/.test(minute) || + !/^\d{1,2}$/.test(hour) || + dayOfMonth !== '*' || + month !== '*' || + !/^[A-Z0-7*,-]+$/.test(dayOfWeek) + ) { return } - let [, minute, hour, weekdays] = matches // replace weekday shortnames, * and 7 with default integer values const intVals = { @@ -41,10 +44,13 @@ function parseCronExpression (value) { 7: 0, '*': '1,2,3,4,5,6,0', } - weekdays = replace(weekdays, /[7*]|MON|TUE|WED|THU|FRI|SAT|SUN/g, weekday => intVals[weekday]) + let weekdays = replace(dayOfWeek, /[7*]|MON|TUE|WED|THU|FRI|SAT|SUN/g, weekday => intVals[weekday]) // convert to array weekdays = split(weekdays, ',') + if (!weekdays.every(day => /^([0-6]|[0-6]-[0-6])$/.test(day))) { + return + } // resolve intervals weekdays = flatMap(weekdays, weekdayOrInterval => { diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js index 5ca8d4ddf8..d39a9be291 100644 --- a/frontend/src/utils/index.js +++ b/frontend/src/utils/index.js @@ -44,10 +44,7 @@ import { const serviceAccountRegex = /^system:serviceaccount:([^:]+):([^:]+)$/ const sizeRegex = /^(\d+)Gi$/ -const emailRegex = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/ const colorCodeRegex = /^#([a-f0-9]{6}|[a-f0-9]{3})$/i -const magnitudeNumberSuffixRegex = /^(\d+(?:\.\d*)?)([kmbt]?)$/i -const versionRegex = /^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.\d+)*([-+].+)?$/ const logger = useLogger() @@ -169,7 +166,36 @@ export function parseSize (value) { } export function isEmail (value) { - return emailRegex.test(value) + if (typeof value !== 'string' || value.length > 320) { + return false + } + + const parts = value.split('@') + if (parts.length !== 2) { + return false + } + + const [local, domain] = parts + if (!/^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]{1,64}$/.test(local)) { + return false + } + + const domainParts = domain.split('.') + if (domainParts.length < 2) { + return false + } + const lastIndex = domainParts.length - 1 + const isValidPart = (part, index) => { + const minLength = index < lastIndex ? 1 : 2 + return part.length < minLength || part.length > 63 + ? false + : /^[a-zA-Z0-9-]*$/.test(part) + } + if (!domainParts.every(isValidPart)) { + return false + } + + return true } export function gravatarUrlGeneric (username, size = 128) { @@ -622,22 +648,38 @@ export function omitKeysWithSuffix (obj, suffix) { } export function parseNumberWithMagnitudeSuffix (abbreviatedNumber) { - const [, number, suffix] = magnitudeNumberSuffixRegex.exec(abbreviatedNumber) ?? [] - if (!number) { + let number = abbreviatedNumber + let suffix = '' + if (/[kmbt]$/i.test(abbreviatedNumber)) { + suffix = abbreviatedNumber.slice(-1) + number = abbreviatedNumber.slice(0, -1) + } + number = Number(number) + if (isNaN(number)) { logger.error(`Failed to parse ${abbreviatedNumber} because it doesn't follow the required format: a number optionally with a decimal, followed by an optional magnitude suffix ('k', 'm', 'b', 't').`) return null } const suffixFactors = { k: 1e3, m: 1e6, b: 1e9, t: 1e12 } const factor = suffixFactors[suffix?.toLowerCase()] ?? 1 - return Number(number) * factor + return number * factor } export function normalizeVersion (version) { - const [match, major, minor = '0', patch = '0', suffix = ''] = versionRegex.exec(version) ?? [] - if (match) { - return [major, minor, patch].map(Number).join('.') + suffix + let suffix = '' + + const index = version.search(/[+-]/) + if (index !== -1) { + suffix = version.substring(index) + version = version.substring(0, index) + } + + const parts = version.split('.') + if (!parts.every(part => /^\d+$/.test(part))) { + return } + const [major, minor = '0', patch = '0'] = parts + return [major, minor, patch].map(Number).join('.') + suffix } export default { diff --git a/frontend/src/utils/validators.js b/frontend/src/utils/validators.js index 2413ee2011..8f9b4acdf6 100644 --- a/frontend/src/utils/validators.js +++ b/frontend/src/utils/validators.js @@ -5,12 +5,12 @@ // import { helpers } from '@vuelidate/validators' +import { Base64 } from 'js-base64' import { includes } from '@/lodash' const { withParams, regex, withMessage } = helpers -const base64Pattern = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/ const alphaNumUnderscorePattern = /^\w+$/ const alphaNumUnderscoreHyphenPattern = /^[a-zA-Z0-9-_]+$/ const lowerCaseAlphaNumHyphenPattern = /^[-a-z0-9]*$/ @@ -19,7 +19,9 @@ const startEndHyphenPattern = /^-.*.|.*-$/ const numberOrPercentagePattern = /^[\d]+[%]?$/ export const timezonePattern = /^([+-])(\d{2}):(\d{2})$/ -const base64 = withMessage('Must be a valid base64 string', regex(base64Pattern)) +const base64 = withMessage('Must be a valid base64 string', value => { + return Base64.isValid(value) +}) const alphaNumUnderscore = withMessage('Must contain only alphanumeric characters and underscore', regex(alphaNumUnderscorePattern)) const lowerCaseAlphaNumHyphen = withMessage('Must contain only lowercase alphanumeric characters or hyphen', regex(lowerCaseAlphaNumHyphenPattern)) const noConsecutiveHyphen = withMessage('Must not contain consecutive hyphens', value => { diff --git a/frontend/src/views/GAdministration.vue b/frontend/src/views/GAdministration.vue index 78fd14c4d2..ae077131b8 100644 --- a/frontend/src/views/GAdministration.vue +++ b/frontend/src/views/GAdministration.vue @@ -609,7 +609,7 @@ const userList = computed(() => { }) const isValidCostObject = withMessage( costObjectErrorMessage.value, - helpers.regex(new RegExp(costObjectRegex.value)), + helpers.regex(costObjectRegex.value), ) const costObjectRules = computed(() => ({ costObject: isValidCostObject })) const ownerRules = computed(() => { diff --git a/packages/kube-client/__tests__/cache.informer.test.js b/packages/kube-client/__tests__/cache.informer.test.js index 97f7a52c70..b810ddf3a2 100644 --- a/packages/kube-client/__tests__/cache.informer.test.js +++ b/packages/kube-client/__tests__/cache.informer.test.js @@ -7,7 +7,6 @@ 'use strict' const { Informer, ListWatcher, Store, Reflector } = require('../lib/cache') -const { getOwnSymbolProperty } = fixtures.helper const { Foo } = fixtures.resources describe('kube-client', () => { @@ -34,12 +33,12 @@ describe('kube-client', () => { listFunc = jest.fn() watchFunc = jest.fn() listWatcher = new ListWatcher(listFunc, watchFunc, Foo) - informer = Informer.create(listWatcher, { keyPath: 'uid' }) + informer = Informer.createTestingInformer(listWatcher, { keyPath: 'uid' }) informer.emit = jest.fn() - internalAbortController = getOwnSymbolProperty(informer, 'abortController') + internalAbortController = informer.abortController internalAbortController.abort = jest.fn() - store = getOwnSymbolProperty(informer, 'store') - reflector = getOwnSymbolProperty(informer, 'reflector') + store = informer.store + reflector = informer.reflector reflector.run = jest.fn() }) diff --git a/packages/kube-client/__tests__/util.test.js b/packages/kube-client/__tests__/util.test.js new file mode 100644 index 0000000000..cde2512b18 --- /dev/null +++ b/packages/kube-client/__tests__/util.test.js @@ -0,0 +1,33 @@ +// +// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Gardener contributors +// +// SPDX-License-Identifier: Apache-2.0 +// + +'use strict' + +const { setPatchType, PatchType } = require('../lib/util') + +describe('kube-client', () => { + describe('util', () => { + describe('#setPatchType', () => { + let options + + beforeEach(() => { + options = {} + }) + + it('should set the MERGE patch type', async () => { + expect(setPatchType(options, PatchType.MERGE)).toEqual({ + headers: { + 'content-type': 'application/merge-patch+json' + } + }) + }) + + it('should throw an error for invalid patch types', () => { + expect(() => setPatchType(options, 'invalid')).toThrow(TypeError) + }) + }) + }) +}) diff --git a/packages/kube-client/lib/Client.js b/packages/kube-client/lib/Client.js index 2036a0b898..b2bc05a8d4 100644 --- a/packages/kube-client/lib/Client.js +++ b/packages/kube-client/lib/Client.js @@ -17,11 +17,11 @@ const nonResourceEndpoints = require('./nonResourceEndpoints') const { fromKubeconfig, parseKubeconfig } = require('@gardener-dashboard/kube-config') -const kClientConfig = Symbol('kClientConfig') - class Client { + #clientConfig + constructor (clientConfig, options) { - this[kClientConfig] = clientConfig + this.#clientConfig = clientConfig // add hooks for logging options = debug.attach(options) // assign grouped resources (e.g. core.) @@ -31,9 +31,9 @@ class Client { } get cluster () { - const server = this[kClientConfig].url - const certificateAuthority = this[kClientConfig].ca - const insecureSkipTlsVerify = !this[kClientConfig].rejectUnauthorized + const server = this.#clientConfig.url + const certificateAuthority = this.#clientConfig.ca + const insecureSkipTlsVerify = !this.#clientConfig.rejectUnauthorized return { server: new URL(server), certificateAuthority, diff --git a/packages/kube-client/lib/cache/Informer.js b/packages/kube-client/lib/cache/Informer.js index e43dc91d1c..5a633eeb21 100644 --- a/packages/kube-client/lib/cache/Informer.js +++ b/packages/kube-client/lib/cache/Informer.js @@ -10,17 +10,16 @@ const EventEmitter = require('events') const Reflector = require('./Reflector') const Store = require('./Store') -const kReflector = Symbol('reflector') -const kAbortController = Symbol('abortController') -const kStore = Symbol('store') - class Informer extends EventEmitter { + #reflector + #abortController = new AbortController() + #store + constructor (listWatcher, { keyPath } = {}) { super() - this[kAbortController] = new AbortController() - const store = this[kStore] = new Store({ keyPath }) + const store = this.#store = new Store({ keyPath }) const emitter = this - this[kReflector] = Reflector.create(listWatcher, { + this.#reflector = Reflector.create(listWatcher, { replace (items, resourceVersion) { const events = new Map() for (const key of store.listKeys()) { @@ -65,35 +64,56 @@ class Informer extends EventEmitter { } get names () { - return this[kReflector].names + return this.#reflector.names } get store () { - return this[kStore] + return this.#store } get hasSynced () { - return this[kStore].hasSynced + return this.#store.hasSynced } get lastSyncResourceVersion () { - return this[kReflector].lastSyncResourceVersion + return this.#reflector.lastSyncResourceVersion } abort () { - this[kAbortController].abort() + this.#abortController.abort() } run (signal) { if (signal instanceof AbortSignal) { signal.addEventListener('abort', () => this.abort(), { once: true }) } - this[kReflector].run(this[kAbortController].signal) + this.#reflector.run(this.#abortController.signal) } static create (...args) { return new this(...args) } + + static createTestingInformer (...args) { + const informer = new this(...args) + return Object.defineProperties(informer, { + reflector: { + get () { + return informer.#reflector + } + }, + store: { + get () { + return informer.#store + } + }, + abortController: { + get () { + return informer.#abortController + } + } + }) + } } module.exports = Informer diff --git a/packages/kube-client/lib/cache/Store.js b/packages/kube-client/lib/cache/Store.js index 19e3b6ffa5..5b8b6dbcba 100644 --- a/packages/kube-client/lib/cache/Store.js +++ b/packages/kube-client/lib/cache/Store.js @@ -8,56 +8,56 @@ const { get, matches, matchesProperty, property, isPlainObject } = require('lodash') -const kMap = Symbol('map') -const kKeyPath = Symbol('keyPath') -const kKeyFunc = Symbol('keyFunc') -const kHasSynced = Symbol('hasSynced') -const kResolve = Symbol('resolve') - class Store { - constructor ({ keyPath = 'metadata.uid' } = {}) { - this[kMap] = new Map() - this[kKeyPath] = keyPath - this[kHasSynced] = false + #map = new Map() + #keyPath = 'metadata.uid' + #hasSynced = false + #resolve = undefined + + constructor (options) { + this.#map = new Map() + if (options?.keyPath) { + this.#keyPath = options.keyPath + } const untilHasSynced = new Promise(resolve => { - this[kResolve] = () => { - this[kHasSynced] = true + this.#resolve = () => { + this.#hasSynced = true resolve() } }) Reflect.defineProperty(this, 'untilHasSynced', { value: untilHasSynced }) } - [kKeyFunc] (object) { - return get(object, this[kKeyPath]) + #keyFunc (object) { + return get(object, this.#keyPath) } get hasSynced () { - return this[kHasSynced] + return this.#hasSynced } listKeys () { - return Array.from(this[kMap].keys()) + return Array.from(this.#map.keys()) } list () { - return Array.from(this[kMap].values()) + return Array.from(this.#map.values()) } clear () { - this[kMap].clear() + this.#map.clear() } getKey (object) { - return this[kKeyFunc](object) + return this.#keyFunc(object) } getByKey (key) { - return this[kMap].get(key) + return this.#map.get(key) } get (object) { - const key = this[kKeyFunc](object) + const key = this.#keyFunc(object) return this.getByKey(key) } @@ -71,7 +71,7 @@ class Store { } else if (typeof predicate !== 'function') { throw new TypeError('Invalid predicate argument') } - for (const object of this[kMap].values()) { + for (const object of this.#map.values()) { if (predicate(object)) { return object } @@ -79,17 +79,17 @@ class Store { } hasByKey (key) { - return this[kMap].has(key) + return this.#map.has(key) } has (object) { - const key = this[kKeyFunc](object) + const key = this.#keyFunc(object) return this.hasByKey(key) } set (object) { - const key = this[kKeyFunc](object) - this[kMap].set(key, object) + const key = this.#keyFunc(object) + this.#map.set(key, object) } add (object) { @@ -101,23 +101,23 @@ class Store { } deleteByKey (key) { - this[kMap].delete(key) + this.#map.delete(key) } delete (object) { - const key = this[kKeyFunc](object) - this[kMap].delete(key) + const key = this.#keyFunc(object) + this.#map.delete(key) } replace (items) { this.clear() for (const object of items) { - const key = this[kKeyFunc](object) - this[kMap].set(key, object) + const key = this.#keyFunc(object) + this.#map.set(key, object) } - if (this[kResolve]) { - this[kResolve]() - this[kResolve] = undefined + if (this.#resolve) { + this.#resolve() + this.#resolve = undefined } } } diff --git a/packages/kube-client/lib/debug.js b/packages/kube-client/lib/debug.js index 19f82e8edb..f3a2ba98ab 100644 --- a/packages/kube-client/lib/debug.js +++ b/packages/kube-client/lib/debug.js @@ -98,7 +98,7 @@ function getUser ({ headers, key, cert }) { function beforeRequest (options) { const { url, method, headers, body } = options - options[xRequestStart] = Date.now() + options[xRequestStart] = Date.now() // eslint-disable-line security/detect-object-injection if (!('x-request-id' in headers)) { headers['x-request-id'] = xRequestId.next() } diff --git a/packages/kube-client/lib/resources/index.js b/packages/kube-client/lib/resources/index.js index dc5bf8fd9f..52d2243d65 100644 --- a/packages/kube-client/lib/resources/index.js +++ b/packages/kube-client/lib/resources/index.js @@ -16,7 +16,7 @@ const resourceGroups = _ .value() function loadGroup ({ name }) { - const resources = require(`./${name}`) + const resources = require(`./${name}`) // eslint-disable-line security/detect-non-literal-require return _.mapKeys(resources, 'names.plural') } diff --git a/packages/kube-client/lib/util.js b/packages/kube-client/lib/util.js index d4586befa4..0708be9089 100644 --- a/packages/kube-client/lib/util.js +++ b/packages/kube-client/lib/util.js @@ -8,6 +8,7 @@ const http2 = require('http2') const path = require('path') +const _ = require('lodash') const { HTTP2_HEADER_CONTENT_TYPE @@ -23,16 +24,8 @@ function decodeBase64 (value) { return Buffer.from(value, 'base64').toString('utf8') } -function setHeader (options, key, value) { - if (!options.headers) { - options.headers = {} - } - options.headers[key] = value - return options -} - function setContentType (options, value) { - return setHeader(options, HTTP2_HEADER_CONTENT_TYPE, value) + return _.set(options, ['headers', HTTP2_HEADER_CONTENT_TYPE], value) } function setPatchType (options, type = PatchType.MERGE) { @@ -80,7 +73,6 @@ function validateLabelValue (name) { exports = module.exports = { decodeBase64, - setHeader, setContentType, PatchType, setPatchType, diff --git a/packages/kube-client/package.json b/packages/kube-client/package.json index 7bb1bb71ff..07eefa23bc 100644 --- a/packages/kube-client/package.json +++ b/packages/kube-client/package.json @@ -42,6 +42,7 @@ "eslint-plugin-jest": "^26.9.0", "eslint-plugin-n": "^15.7.0", "eslint-plugin-promise": "^6.4.0", + "eslint-plugin-security": "^3.0.1", "express": "^4.18.3", "jest": "^29.7.0" }, @@ -55,6 +56,7 @@ ], "extends": [ "standard", + "plugin:security/recommended-legacy", "plugin:jest/recommended" ], "globals": { @@ -62,7 +64,21 @@ }, "rules": { "no-console": "error" - } + }, + "overrides": [ + { + "files": [ + "**/__fixtures__/**", + "**/__mocks__/**", + "**/__tests__/**", + "jest.setup.js" + ], + "rules": { + "security/detect-object-injection": "off", + "security/detect-non-literal-require": "off" + } + } + ] }, "jest": { "restoreMocks": true, @@ -79,7 +95,7 @@ "coverageThreshold": { "global": { "branches": 73, - "functions": 98, + "functions": 97, "lines": 94, "statements": 94 } diff --git a/packages/kube-config/__tests__/kube-config.test.js b/packages/kube-config/__tests__/kube-config.test.js index 34effc261d..8fbb1b3e6a 100644 --- a/packages/kube-config/__tests__/kube-config.test.js +++ b/packages/kube-config/__tests__/kube-config.test.js @@ -103,7 +103,7 @@ describe('kube-config', () => { KUBECONFIG: '/path/to/kube/config:/path/to/another/kube/config' }) expect(fs.readFileSync).toHaveBeenCalledTimes(1) - expect(fs.readFileSync.mock.calls[0]).toEqual(['/path/to/kube/config']) + expect(fs.readFileSync.mock.calls[0]).toEqual(['/path/to/kube/config', 'utf8']) expect(config).toEqual({ url: server.origin, ca, diff --git a/packages/kube-config/lib/ClientConfig.js b/packages/kube-config/lib/ClientConfig.js index 99e69dbb5e..782fe9f3c9 100644 --- a/packages/kube-config/lib/ClientConfig.js +++ b/packages/kube-config/lib/ClientConfig.js @@ -25,7 +25,7 @@ function getCluster ({ currentCluster }, files) { cluster.certificateAuthority = base64Decode(caData) } else if (caFile) { files.set(caFile, 'certificateAuthority') - cluster.certificateAuthority = fs.readFileSync(caFile, 'utf8') + cluster.certificateAuthority = fs.readFileSync(caFile, 'utf8') // eslint-disable-line security/detect-non-literal-fs-filename } if (typeof insecureSkipTlsVerify === 'boolean') { cluster.insecureSkipTlsVerify = insecureSkipTlsVerify @@ -55,14 +55,14 @@ function getUser ({ currentUser }, files) { user.clientKey = base64Decode(keyData) } else if (certFile && keyFile) { files.set(certFile, 'clientCert') - user.clientCert = fs.readFileSync(certFile, 'utf8') + user.clientCert = fs.readFileSync(certFile, 'utf8') // eslint-disable-line security/detect-non-literal-fs-filename files.set(keyFile, 'clientKey') - user.clientKey = fs.readFileSync(keyFile, 'utf8') + user.clientKey = fs.readFileSync(keyFile, 'utf8') // eslint-disable-line security/detect-non-literal-fs-filename } else if (token) { user.token = token } else if (tokenFile) { files.set(tokenFile, 'token') - user.token = fs.readFileSync(tokenFile, 'utf8') + user.token = fs.readFileSync(tokenFile, 'utf8') // eslint-disable-line security/detect-non-literal-fs-filename } else if (username && password) { user.username = username user.password = password @@ -168,10 +168,19 @@ class ClientConfig { const watcher = new Watcher(Array.from(files.keys()), options) watcher.run((path, value) => { const key = files.get(path) - if (['certificateAuthority'].includes(key)) { - cluster[key] = value - } else if (['clientKey', 'clientCert', 'token'].includes(key)) { - user[key] = value + switch (key) { + case 'certificateAuthority': + cluster.certificateAuthority = value + break + case 'clientKey': + user.clientKey = value + break + case 'clientCert': + user.clientCert = value + break + case 'token': + user.token = value + break } watcher.emit(`update:${key}`) }) diff --git a/packages/kube-config/lib/index.js b/packages/kube-config/lib/index.js index b0dcc1641e..acd9a7842d 100644 --- a/packages/kube-config/lib/index.js +++ b/packages/kube-config/lib/index.js @@ -29,10 +29,13 @@ function readKubeconfig (filename) { filename = filename.shift() } const dirname = path.dirname(filename) - const kubeconfig = yaml.load(fs.readFileSync(filename)) + const kubeconfig = yaml.load( + fs.readFileSync(filename, 'utf8') // eslint-disable-line security/detect-non-literal-fs-filename + ) const resolvePath = (object, key) => { - if (object[key]) { - object[key] = path.resolve(dirname, object[key]) + const value = object[key] // eslint-disable-line security/detect-object-injection + if (value) { + object[key] = path.resolve(dirname, value) // eslint-disable-line security/detect-object-injection } } for (const { cluster } of kubeconfig.clusters) { diff --git a/packages/kube-config/package.json b/packages/kube-config/package.json index 15db2c03b7..bfb7a52f3d 100644 --- a/packages/kube-config/package.json +++ b/packages/kube-config/package.json @@ -38,6 +38,7 @@ "eslint-plugin-jest": "^26.9.0", "eslint-plugin-n": "^15.7.0", "eslint-plugin-promise": "^6.4.0", + "eslint-plugin-security": "^3.0.1", "jest": "^29.7.0" }, "eslintConfig": { @@ -50,6 +51,7 @@ ], "extends": [ "standard", + "plugin:security/recommended-legacy", "plugin:jest/recommended" ], "globals": { @@ -57,7 +59,20 @@ }, "rules": { "no-console": "error" - } + }, + "overrides": [ + { + "files": [ + "**/__fixtures__/**", + "**/__mocks__/**", + "**/__tests__/**", + "jest.setup.js" + ], + "rules": { + "security/detect-non-literal-fs-filename": "off" + } + } + ] }, "jest": { "restoreMocks": true, diff --git a/packages/logger/package.json b/packages/logger/package.json index 36a0179f1c..a339485cca 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -53,23 +53,7 @@ "globals": {}, "rules": { "no-console": "error" - }, - "overrides": [ - { - "files": [ - "**/__fixtures__/**", - "**/__mocks__/**", - "**/__tests__/**", - "**/test/**", - "jest.setup.js" - ], - "rules": { - "security/detect-object-injection": "off", - "security/detect-possible-timing-attacks": "off", - "security/detect-unsafe-regex": "off" - } - } - ] + } }, "jest": { "restoreMocks": true, diff --git a/packages/monitor/package.json b/packages/monitor/package.json index 79c285cd49..f50ecc0987 100644 --- a/packages/monitor/package.json +++ b/packages/monitor/package.json @@ -37,6 +37,7 @@ "eslint-plugin-jest": "^26.9.0", "eslint-plugin-n": "^15.7.0", "eslint-plugin-promise": "^6.4.0", + "eslint-plugin-security": "^3.0.1", "jest": "^29.7.0", "supertest": "^7.0.0" }, @@ -50,6 +51,7 @@ ], "extends": [ "standard", + "plugin:security/recommended-legacy", "plugin:jest/recommended" ], "globals": { @@ -58,7 +60,20 @@ }, "rules": { "no-console": "error" - } + }, + "overrides": [ + { + "files": [ + "**/__fixtures__/**", + "**/__mocks__/**", + "**/__tests__/**", + "jest.setup.js" + ], + "rules": { + "security/detect-object-injection": "off" + } + } + ] }, "jest": { "restoreMocks": true, diff --git a/packages/request/lib/Client.js b/packages/request/lib/Client.js index bc4e303ccc..7728c97d66 100644 --- a/packages/request/lib/Client.js +++ b/packages/request/lib/Client.js @@ -32,6 +32,14 @@ const { HTTP2_HEADER_CONTENT_ENCODING } = http2.constants +function getHeader (headers, key) { + return headers[key] // eslint-disable-line security/detect-object-injection +} + +function setHeader (headers, key, value) { + headers[key] = value // eslint-disable-line security/detect-object-injection +} + const EOL = '\n' class Client { @@ -73,10 +81,10 @@ class Client { const headers = { ...this.#options.headers } const { bearer, user, pass } = this.#options.auth || {} if (bearer) { - headers[HTTP2_HEADER_AUTHORIZATION] = `Bearer ${bearer}` + setHeader(headers, HTTP2_HEADER_AUTHORIZATION, `Bearer ${bearer}`) } else if (user && pass) { const credentials = Buffer.from(user + ':' + pass, 'utf8').toString('base64') - headers[HTTP2_HEADER_AUTHORIZATION] = `Basic ${credentials}` + setHeader(headers, HTTP2_HEADER_AUTHORIZATION, `Basic ${credentials}`) } return headers } @@ -108,11 +116,16 @@ class Client { } } + get #hooksMap () { + const hooks = this.#options.hooks ?? {} + return new Map(Object.entries(hooks)) + } + executeHooks (name, ...args) { - const hooks = this.#options.hooks || {} try { - if (Array.isArray(hooks[name])) { - for (const hook of hooks[name]) { + const hooks = this.#hooksMap.get(name) + if (Array.isArray(hooks)) { + for (const hook of hooks) { hook(...args) } } @@ -159,8 +172,8 @@ class Client { // beforeRequest hooks const requestOptions = { - url: new URL(headers[HTTP2_HEADER_PATH], this.baseUrl.origin), - method: headers[HTTP2_HEADER_METHOD], + url: new URL(getHeader(headers, HTTP2_HEADER_PATH), this.baseUrl.origin), + method: getHeader(headers, HTTP2_HEADER_METHOD), headers, body, ...options @@ -180,13 +193,13 @@ class Client { const { createDecompressor, concat, transformFactory } = this.constructor headers = await stream.getHeaders() - const decompressor = createDecompressor(headers[HTTP2_HEADER_CONTENT_ENCODING]) + const decompressor = createDecompressor(getHeader(headers, HTTP2_HEADER_CONTENT_ENCODING)) return { request: { options: requestOptions }, headers, get statusCode () { - return this.headers[HTTP2_HEADER_STATUS] + return getHeader(this.headers, HTTP2_HEADER_STATUS) }, get ok () { return this.statusCode >= 200 && this.statusCode < 300 @@ -195,10 +208,10 @@ class Client { return this.statusCode >= 300 && this.statusCode < 400 }, get contentType () { - return this.headers[HTTP2_HEADER_CONTENT_TYPE] + return getHeader(this.headers, HTTP2_HEADER_CONTENT_TYPE) }, get contentLength () { - return this.headers[HTTP2_HEADER_CONTENT_LENGTH] + return getHeader(this.headers, HTTP2_HEADER_CONTENT_LENGTH) }, get type () { if (['json', 'text'].includes(responseType)) { @@ -293,8 +306,8 @@ class Client { headers = this.constructor.normalizeHeaders(headers) if (json) { body = JSON.stringify(json) - if (!headers[HTTP2_HEADER_CONTENT_TYPE]) { - headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/json' + if (!getHeader(headers, HTTP2_HEADER_CONTENT_TYPE)) { + setHeader(headers, HTTP2_HEADER_CONTENT_TYPE, 'application/json') } } const response = await this.fetch(path, { headers, body, ...options }) @@ -307,7 +320,7 @@ class Client { headers, httpVersion: '2', statusCode, - statusMessage: http.STATUS_CODES[statusCode], + statusMessage: http.STATUS_CODES[statusCode], // eslint-disable-line security/detect-object-injection body, request: response.request } diff --git a/packages/request/lib/Semaphore.js b/packages/request/lib/Semaphore.js index 97fda8bff6..bd6a16e058 100644 --- a/packages/request/lib/Semaphore.js +++ b/packages/request/lib/Semaphore.js @@ -6,23 +6,28 @@ 'use strict' -const kMaxConcurrency = Symbol('maxConcurrency') const kReleased = Symbol('released') +function setReleased (obj, value) { + obj[kReleased] = value // eslint-disable-line security/detect-object-injection +} + class Semaphore { + #maxConcurrency = 0 + constructor (maxConcurrency = 100) { - this[kMaxConcurrency] = maxConcurrency + this.#maxConcurrency = maxConcurrency this.concurrency = 0 this.queue = [] } set maxConcurrency (value) { - this[kMaxConcurrency] = value + this.#maxConcurrency = value this.dispatch() } get maxConcurrency () { - return this[kMaxConcurrency] + return this.#maxConcurrency } get value () { @@ -31,7 +36,7 @@ class Semaphore { acquire () { const ticket = new Promise(resolve => { - resolve[kReleased] = false + setReleased(resolve, false) this.queue.push(resolve) }) this.dispatch() @@ -43,8 +48,9 @@ class Semaphore { const resolve = this.queue.shift() this.concurrency++ const releaser = () => { - if (!resolve[kReleased]) { - resolve[kReleased] = true + const { [kReleased]: released } = resolve + if (!released) { + setReleased(resolve, true) this.concurrency-- this.dispatch() } diff --git a/packages/request/lib/SessionId.js b/packages/request/lib/SessionId.js index 2d29179279..0bbb0a0bfe 100644 --- a/packages/request/lib/SessionId.js +++ b/packages/request/lib/SessionId.js @@ -7,38 +7,43 @@ 'use strict' const crypto = require('crypto') +const { get, set } = require('lodash') const kOptions = Symbol('options') class SessionId extends URL { constructor (authority, options = {}) { super(createPath(options), authority) - this[kOptions] = options + this[kOptions] = options // eslint-disable-line security/detect-object-injection } getOptions () { - return this[kOptions] + return this[kOptions] // eslint-disable-line security/detect-object-injection } } function normalizeObject (object) { const normalizedObject = {} for (const key of Object.keys(object).sort()) { - const value = object[key] + const value = get(object, key) + let normalizedValue switch (typeof value) { case 'string': case 'number': case 'boolean': - normalizedObject[key] = value + normalizedValue = value break case 'object': if (value) { - normalizedObject[key] = normalizeObject(value) + normalizedValue = normalizeObject(value) } break case 'undefined': break } + if (typeof normalizedValue !== 'undefined') { + set(normalizedObject, key, normalizedValue) + } } return normalizedObject } diff --git a/packages/request/lib/SessionPool.js b/packages/request/lib/SessionPool.js index 966a1fb52a..36ba189622 100644 --- a/packages/request/lib/SessionPool.js +++ b/packages/request/lib/SessionPool.js @@ -20,10 +20,33 @@ const { } = http2.constants const kSemaphore = Symbol('semaphore') -const kTimestamp = Symbol('timestamp') const kTimeoutId = Symbol('timeoutId') const kIntervalId = Symbol('intervalId') +function setSemaphore (session, value) { + session[kSemaphore] = value // eslint-disable-line security/detect-object-injection +} + +function setTimeoutId (session, value) { + session[kTimeoutId] = value // eslint-disable-line security/detect-object-injection +} + +function setIntervalId (session, value) { + session[kIntervalId] = value // eslint-disable-line security/detect-object-injection +} + +class Timer { + #timestamp + + constructor () { + this.#timestamp = Date.now() + } + + duration () { + return Date.now() - this.#timestamp + } +} + class SessionPool { constructor (id) { this.id = id @@ -94,7 +117,7 @@ class SessionPool { async request (headers, options) { const session = this.getSession() - const semaphore = session[kSemaphore] + const { [kSemaphore]: semaphore } = session const [release, concurrency] = await semaphore.acquire() logger.trace('Session %s - stream aquired (%d/%d)', this.id, concurrency, semaphore.maxConcurrency) const releaseStream = () => { @@ -128,7 +151,8 @@ class SessionPool { stream.once('close', () => { logger.trace('Session %s - stream %d closed', this.id, stream.id || -1) releaseStream() - if (session[kSemaphore].value >= session[kSemaphore].maxConcurrency) { + const { [kSemaphore]: semaphore } = session + if (semaphore.value >= semaphore.maxConcurrency) { this.setSessionTimeout(session) } if (!settled) { @@ -155,13 +179,14 @@ class SessionPool { setSessionTimeout (session) { this.clearSessionTimeout(session) - session[kTimeoutId] = setTimeout(() => session.close(), this.keepAliveTimeout) + setTimeoutId(session, setTimeout(() => session.close(), this.keepAliveTimeout)) } clearSessionTimeout (session) { - if (session[kTimeoutId]) { - clearTimeout(session[kTimeoutId]) - session[kTimeoutId] = undefined + const { [kTimeoutId]: timeoutId } = session + if (timeoutId) { + clearTimeout(timeoutId) + setTimeoutId(session, undefined) } } @@ -190,13 +215,14 @@ class SessionPool { } } logger.debug('Session %s - starting heartbeat with %ds ping interval', this.id, Math.floor(this.pingInterval / 1000)) - session[kIntervalId] = setInterval(ping, this.pingInterval) + setIntervalId(session, setInterval(ping, this.pingInterval)) } clearSessionHeartbeat (session) { - if (session[kIntervalId]) { - clearInterval(session[kIntervalId]) - session[kIntervalId] = undefined + const { [kIntervalId]: intervalId } = session + if (intervalId) { + clearInterval(intervalId) + setIntervalId(session, undefined) } } @@ -209,26 +235,25 @@ class SessionPool { session: this.tlsSession }) const session = http2.connect(origin, options) - session[kTimestamp] = Date.now() - session[kSemaphore] = new Semaphore(this.peerMaxConcurrentStreams) + const timer = new Timer() + setSemaphore(session, new Semaphore(this.peerMaxConcurrentStreams)) // add session this.sessions.add(session) logger.debug('Session %s - pool size is %d (scaled up)', this.id, this.sessions.size) - // get session duration - const duration = () => Date.now() - session[kTimestamp] // tls session can be used for resumption session.socket.once('session', session => { - logger.debug('Session %s - received tls session after %d ms', this.id, duration()) + logger.debug('Session %s - received tls session after %d ms', this.id, timer.duration()) this.tlsSession = session }) // update maxConcurrency of semaphore const setMaxConcurrency = settings => { - const oldValue = session[kSemaphore].maxConcurrency + const { [kSemaphore]: semaphore } = session + const oldValue = semaphore.maxConcurrency const newValue = settings.maxConcurrentStreams if (oldValue !== newValue) { const change = oldValue < newValue ? 'increased' : 'creased' logger.debug('Session %s - maximum concurrency %s to %d', this.id, change, newValue) - session[kSemaphore].maxConcurrency = newValue + semaphore.maxConcurrency = newValue } } // handle connect timeout @@ -247,7 +272,7 @@ class SessionPool { }) // handle connect session.once('connect', () => { - logger.debug('Session %s - connected after %d ms', this.id, duration()) + logger.debug('Session %s - connected after %d ms', this.id, timer.duration()) clearTimeout(timeoutId) session.removeAllListeners('error') session.on('error', err => { @@ -255,7 +280,7 @@ class SessionPool { this.tlsSession = undefined }) session.once('close', () => { - logger.info('Session %s - closed after %d ms', this.id, duration()) + logger.info('Session %s - closed after %d ms', this.id, timer.duration()) this.deleteSession(session) }) setMaxConcurrency(session.remoteSettings) diff --git a/packages/request/lib/errors.js b/packages/request/lib/errors.js index 0463bd912a..06be90abe7 100644 --- a/packages/request/lib/errors.js +++ b/packages/request/lib/errors.js @@ -43,7 +43,18 @@ function isAbortError (err = {}) { return err.code === 'ABORT_ERR' } -function createHttpError ({ statusCode = 500, statusMessage = http.STATUS_CODES[statusCode], response, headers, body }) { +function getDefaultStatusMessage (statusCode) { + return http.STATUS_CODES[statusCode] // eslint-disable-line security/detect-object-injection +} + +function createHttpError (options) { + const { + statusCode = 500, + statusMessage = getDefaultStatusMessage(statusCode), + response, + headers, + body + } = options const properties = { statusMessage } if (headers) { properties.headers = { ...headers } diff --git a/packages/request/package.json b/packages/request/package.json index a54049a979..f93513c2e2 100644 --- a/packages/request/package.json +++ b/packages/request/package.json @@ -38,6 +38,7 @@ "eslint-plugin-jest": "^26.9.0", "eslint-plugin-n": "^15.7.0", "eslint-plugin-promise": "^6.4.0", + "eslint-plugin-security": "^3.0.1", "jest": "^29.7.0" }, "eslintConfig": { @@ -50,6 +51,7 @@ ], "extends": [ "standard", + "plugin:security/recommended-legacy", "plugin:jest/recommended" ], "globals": { @@ -57,7 +59,20 @@ }, "rules": { "no-console": "error" - } + }, + "overrides": [ + { + "files": [ + "**/__fixtures__/**", + "**/__mocks__/**", + "**/__tests__/**", + "jest.setup.js" + ], + "rules": { + "security/detect-object-injection": "off" + } + } + ] }, "jest": { "restoreMocks": true, diff --git a/yarn.lock b/yarn.lock index e9e44d28bb..95edb312a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -807,6 +807,7 @@ __metadata: eslint-plugin-import-newlines: "npm:^1.4.0" eslint-plugin-n: "npm:^15.7.0" eslint-plugin-promise: "npm:^6.4.0" + eslint-plugin-security: "npm:^3.0.1" eslint-plugin-vitest: "npm:^0.4.0" eslint-plugin-vue: "npm:^9.23.0" eventemitter3: "npm:^5.0.1" @@ -861,6 +862,7 @@ __metadata: eslint-plugin-jest: "npm:^26.9.0" eslint-plugin-n: "npm:^15.7.0" eslint-plugin-promise: "npm:^6.4.0" + eslint-plugin-security: "npm:^3.0.1" express: "npm:^4.18.3" http-errors: "npm:^2.0.0" jest: "npm:^29.7.0" @@ -884,6 +886,7 @@ __metadata: eslint-plugin-jest: "npm:^26.9.0" eslint-plugin-n: "npm:^15.7.0" eslint-plugin-promise: "npm:^6.4.0" + eslint-plugin-security: "npm:^3.0.1" gtoken: "npm:^7.1.0" jest: "npm:^29.7.0" js-yaml: "npm:^4.1.0" @@ -919,6 +922,7 @@ __metadata: eslint-plugin-jest: "npm:^26.9.0" eslint-plugin-n: "npm:^15.7.0" eslint-plugin-promise: "npm:^6.4.0" + eslint-plugin-security: "npm:^3.0.1" express: "npm:^4.18.3" http-errors: "npm:^2.0.0" jest: "npm:^29.7.0" @@ -941,6 +945,7 @@ __metadata: eslint-plugin-jest: "npm:^26.9.0" eslint-plugin-n: "npm:^15.7.0" eslint-plugin-promise: "npm:^6.4.0" + eslint-plugin-security: "npm:^3.0.1" http-errors: "npm:^2.0.0" jest: "npm:^29.7.0" lodash: "npm:^4.17.21" From 78dcc8b17388e5a3b75a280c0a1d1c54de9b4e6c Mon Sep 17 00:00:00 2001 From: Holger Koser Date: Wed, 14 Aug 2024 17:33:55 +0200 Subject: [PATCH 7/9] fixed some more SAST warnings --- frontend/.eslintrc.cjs | 1 - .../utils/hibernationSchedule.spec.js | 23 ++++++++++++ frontend/src/App.vue | 6 +++- frontend/src/components/GMainNavigation.vue | 2 +- .../src/components/GPositionalDropzone.vue | 14 ++++---- .../components/GShootSubscriptionStatus.vue | 2 +- frontend/src/components/GTerminal.vue | 4 +-- .../GAccessRestrictions.vue | 2 +- .../components/ShootAddons/GManageAddons.vue | 2 +- .../ShootDetails/GGardenctlCommands.vue | 10 ++++-- .../ShootDetails/GShootDetailsCard.vue | 11 +++--- .../ShootMessages/GShootMessages.vue | 8 ++--- frontend/src/components/icons/GIconBase.vue | 5 ++- frontend/src/composables/helper.js | 3 +- frontend/src/composables/useApi/fetch.js | 8 ++--- frontend/src/composables/useCustomColors.js | 13 ++++--- frontend/src/composables/useLogger.js | 2 +- .../useShootAccessRestrictions/index.js | 12 +++---- frontend/src/composables/useShootContext.js | 2 +- frontend/src/composables/useShootDns.js | 2 +- .../src/composables/useShootEditor/helper.js | 5 +-- .../src/composables/useShootEditor/index.js | 4 ++- frontend/src/lib/g-symbol-tree.js | 10 +++--- frontend/src/lib/terminal.js | 3 +- frontend/src/store/cloudProfile/index.js | 6 ++-- frontend/src/store/config.js | 6 ++-- frontend/src/store/localStorage.js | 2 ++ frontend/src/store/project.js | 11 +++--- frontend/src/store/quota/helper.js | 12 ++++--- frontend/src/store/quota/index.js | 10 ++++-- frontend/src/store/secret.js | 2 +- frontend/src/store/seed.js | 2 +- frontend/src/store/shoot/helper.js | 6 ++-- frontend/src/store/shoot/shoot.js | 35 +++++++++++-------- frontend/src/store/ticket.js | 17 ++++----- frontend/src/utils/TimeWithOffset.js | 2 +- frontend/src/utils/crypto.js | 2 +- frontend/src/utils/errors.js | 4 ++- frontend/src/utils/hibernationSchedule.js | 5 +-- frontend/src/utils/index.js | 13 ++++--- frontend/src/utils/shoot.js | 9 +++-- frontend/src/utils/validators.js | 10 ++++-- frontend/src/views/GSecrets.vue | 2 +- 43 files changed, 191 insertions(+), 119 deletions(-) diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs index dd8036868a..3c902d68ad 100644 --- a/frontend/.eslintrc.cjs +++ b/frontend/.eslintrc.cjs @@ -101,7 +101,6 @@ module.exports = { 'vue/no-mutating-props': ['error', { shallowOnly: true }], 'vue/require-default-prop': 'off', 'vue/order-in-components': 'error', - 'security/detect-object-injection': 'off', }, overrides: [ { diff --git a/frontend/__tests__/utils/hibernationSchedule.spec.js b/frontend/__tests__/utils/hibernationSchedule.spec.js index 98192d4bbc..d974fef567 100644 --- a/frontend/__tests__/utils/hibernationSchedule.spec.js +++ b/frontend/__tests__/utils/hibernationSchedule.spec.js @@ -5,6 +5,7 @@ // import { + parseCronExpression, scheduleEventsFromCrontabBlock, crontabBlocksFromScheduleEvents, } from '@/utils/hibernationSchedule' @@ -14,6 +15,28 @@ const currentLocation = moment.tz.guess() describe('utils', () => { describe('hibernationSchedule', () => { + describe('#parseCronExpression', () => { + it('should parse a crontab expressions', () => { + expect(parseCronExpression('0 8 * * 1')).toEqual({ + hour: '8', + minute: '0', + weekdays: '1', + }) + expect(parseCronExpression('00 12 * * 1,2,3,4,5').weekdays).toBe('1,2,3,4,5') + expect(parseCronExpression('00 12 * * MON,TUE,WED,THU,FRI').weekdays).toBe('1,2,3,4,5') + expect(parseCronExpression('00 12 * * 1-5').weekdays).toBe('1,2,3,4,5') + expect(parseCronExpression('00 12 * * 7').weekdays).toBe('0') + expect(parseCronExpression('00 12 * * *').weekdays).toBe('1,2,3,4,5,6,0') + expect(parseCronExpression('00 12 * * SAT,SUN').weekdays).toBe('6,0') + }) + + it('should fail to parse a crontab expressions', () => { + expect(parseCronExpression('00 12 * * FR')).toBeUndefined() + expect(parseCronExpression('00 12 * * 8')).toBeUndefined() + expect(parseCronExpression('00 12 0 * 1')).toBeUndefined() + expect(parseCronExpression('00 12 * 0 1')).toBeUndefined() + }) + }) describe('#scheduleEventsFromCrontabBlock', () => { it('should parse a simple crontab block', () => { const crontabBlock = { diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 69cf43ebbd..a2994b84ef 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -33,6 +33,8 @@ import { useProjectStore } from '@/store/project' import { useCustomColors } from '@/composables/useCustomColors' +import { get } from '@/lodash' + const theme = useTheme() const route = useRoute() const localStorageStore = useLocalStorageStore() @@ -62,7 +64,9 @@ const { system } = useColorMode({ }, }) -provide('getColorCode', value => theme.current.value?.colors[value]) +provide('getColorCode', value => { + return get(theme.current.value, ['colors', value]) +}) const bus = useEventBus('esc-pressed') diff --git a/frontend/src/components/GMainNavigation.vue b/frontend/src/components/GMainNavigation.vue index 0055641622..cffc8ac2f4 100644 --- a/frontend/src/components/GMainNavigation.vue +++ b/frontend/src/components/GMainNavigation.vue @@ -491,7 +491,7 @@ function highlightProjectWithKeys (keyDirection) { currentHighlightedIndex++ } - const newHighlightedProject = sortedAndFilteredProjectList.value[currentHighlightedIndex] + const newHighlightedProject = sortedAndFilteredProjectList.value[currentHighlightedIndex] // eslint-disable-line security/detect-object-injection highlightedProjectName.value = newHighlightedProject.metadata.name if (currentHighlightedIndex >= numberOfVisibleProjects.value - 1) { diff --git a/frontend/src/components/GPositionalDropzone.vue b/frontend/src/components/GPositionalDropzone.vue index 347b608e85..7024cc13c1 100644 --- a/frontend/src/components/GPositionalDropzone.vue +++ b/frontend/src/components/GPositionalDropzone.vue @@ -188,10 +188,12 @@ export default { }, methods: { fillOnPosition (position) { - return this.mouseDown ? this.rect[position] : undefined + const { [position]: value } = this.rect + return this.mouseDown ? value : undefined }, strokeRectOnPosition (position) { - return this.mouseDown ? this.strokeRect[position] : undefined + const { [position]: value } = this.strokeRect + return this.mouseDown ? value : undefined }, dragOver ({ detail: { mouseOverId: position } }) { this.showIt = true @@ -199,13 +201,9 @@ export default { return } this.mouseDown = true - const newRect = {} - newRect[position] = '#d71e00' - this.rect = newRect + this.rect = { [position]: '#d71e00' } - const newStrokeRect = {} - newStrokeRect[position] = '#fff' - this.strokeRect = newStrokeRect + this.strokeRect = { [position]: '#fff' } this.currentPosition = position }, dragLeaveZone () { diff --git a/frontend/src/components/GShootSubscriptionStatus.vue b/frontend/src/components/GShootSubscriptionStatus.vue index da70b32ced..9bd6fd1466 100644 --- a/frontend/src/components/GShootSubscriptionStatus.vue +++ b/frontend/src/components/GShootSubscriptionStatus.vue @@ -125,7 +125,7 @@ const components = { } function resolveComponent (name) { - return components[name] + return components[name] // eslint-disable-line security/detect-object-injection } const { diff --git a/frontend/src/components/GTerminal.vue b/frontend/src/components/GTerminal.vue index 76318ebbe7..580b5805f0 100644 --- a/frontend/src/components/GTerminal.vue +++ b/frontend/src/components/GTerminal.vue @@ -601,7 +601,7 @@ export default { this.$emit('terminated') }, async configure (refName) { - this.loading[refName] = true + this.loading[refName] = true // eslint-disable-line security/detect-object-injection const { namespace, name, target } = this.data try { const { data: config } = await this.api.terminalConfig({ name, namespace, target }) @@ -610,7 +610,7 @@ export default { } catch (err) { this.showErrorSnackbarBottom(get(err, 'response.data.message', err.message)) } finally { - this.loading[refName] = false + this.loading[refName] = false // eslint-disable-line security/detect-object-injection } const initialState = { diff --git a/frontend/src/components/ShootAccessRestrictions/GAccessRestrictions.vue b/frontend/src/components/ShootAccessRestrictions/GAccessRestrictions.vue index e076774826..f329ef3fab 100644 --- a/frontend/src/components/ShootAccessRestrictions/GAccessRestrictions.vue +++ b/frontend/src/components/ShootAccessRestrictions/GAccessRestrictions.vue @@ -97,7 +97,7 @@ const { function getDisabled (key) { const value = getAccessRestrictionValue(key) - const { input } = accessRestrictionDefinitions.value[key] + const { input } = accessRestrictionDefinitions.value[key] // eslint-disable-line security/detect-object-injection const inverted = !!input?.inverted return !NAND(value, inverted) } diff --git a/frontend/src/components/ShootAddons/GManageAddons.vue b/frontend/src/components/ShootAddons/GManageAddons.vue index f9ae61e02f..e662ed74b5 100644 --- a/frontend/src/components/ShootAddons/GManageAddons.vue +++ b/frontend/src/components/ShootAddons/GManageAddons.vue @@ -56,7 +56,7 @@ const { } = useShootContext() function getDisabled (name) { - const { forbidDisable = false } = addonDefinitions.value[name] + const { forbidDisable = false } = addonDefinitions.value[name] // eslint-disable-line security/detect-object-injection return !props.createMode && forbidDisable && getAddonEnabled(name) } diff --git a/frontend/src/components/ShootDetails/GGardenctlCommands.vue b/frontend/src/components/ShootDetails/GGardenctlCommands.vue index 08817f1c37..eca6be1f43 100644 --- a/frontend/src/components/ShootDetails/GGardenctlCommands.vue +++ b/frontend/src/components/ShootDetails/GGardenctlCommands.vue @@ -155,13 +155,17 @@ export default { }, methods: { visibilityIcon (index) { - return this.expansionPanel[index] ? 'mdi-eye-off' : 'mdi-eye' + return this.expansionPanel[index] // eslint-disable-line security/detect-object-injection + ? 'mdi-eye-off' + : 'mdi-eye' }, visibilityTitle (index) { - return this.expansionPanel[index] ? 'Hide Command' : 'Show Command' + return this.expansionPanel[index] // eslint-disable-line security/detect-object-injection + ? 'Hide Command' + : 'Show Command' }, toggle (index) { - this.expansionPanel[index] = !this.expansionPanel[index] + this.expansionPanel[index] = !this.expansionPanel[index] // eslint-disable-line security/detect-object-injection }, }, } diff --git a/frontend/src/components/ShootDetails/GShootDetailsCard.vue b/frontend/src/components/ShootDetails/GShootDetailsCard.vue index ed1847ddd5..6ea8eb96eb 100644 --- a/frontend/src/components/ShootDetails/GShootDetailsCard.vue +++ b/frontend/src/components/ShootDetails/GShootDetailsCard.vue @@ -245,6 +245,7 @@ import utils, { } from '@/utils' import { + get, filter, map, } from '@/lodash' @@ -284,14 +285,12 @@ const isValidTerminationDate = computed(() => { return utils.isValidTerminationDate(shootExpirationTimestamp.value) }) -const addon = computed(() => { - return name => { - return shootAddons.value[name] || {} - } -}) +function getAddon (name) { + return get(shootAddons.value, [name], {}) +} const shootAddonNames = computed(() => { - return map(filter(shootAddonList, item => addon.value(item.name).enabled), 'title') + return map(filter(shootAddonList, item => getAddon(item.name).enabled), 'title') }) const slaDescriptionHtml = computed(() => { diff --git a/frontend/src/components/ShootMessages/GShootMessages.vue b/frontend/src/components/ShootMessages/GShootMessages.vue index 6fab1cc897..c2b172c009 100644 --- a/frontend/src/components/ShootMessages/GShootMessages.vue +++ b/frontend/src/components/ShootMessages/GShootMessages.vue @@ -94,6 +94,10 @@ const components = { 'g-force-delete-message': GForceDeleteMessage, } +function resolveComponent (name) { + return components[name] // eslint-disable-line security/detect-object-injection +} + const props = defineProps({ small: { type: Boolean, @@ -477,10 +481,6 @@ function colorForSeverity (severity) { return 'primary' } } - -function resolveComponent (name) { - return components[name] -}