From 8dce2057ef1f369ed0c7613d861bb128c72c4f77 Mon Sep 17 00:00:00 2001 From: Angelina Uno-Antonison Date: Tue, 17 Dec 2024 13:24:41 -0600 Subject: [PATCH] Package vulnerability audit dec 2024 (#190) * Updated python docker images to gracefuly stop since they now start in the primary process in a container, through taking over execution of the entrypoint script via a command; * Increased python-multipart pacakge version to avoid vulnerability; * increased eslint's version to remove dependency which has vulnerability; this required upgrading the eslint configuration within rosalution to use the new flat file configuration. It is temporarily tuned to be close to the existing code base linting however, the team will review and revise linting guidelines when we gather soon. * @stylistic/eslint-plugin-js@2.12.1 requires 20.9 & higher; after investigating, in order to avoid the vulnerably also being inside the docker images, need to upgrade to both alpine3.21 & 23.4.; * Linting upgrade for eslint to 9.16 for system tests & some updates to corresponding tests. * Resolved unit test text formatting issue; updated system test package.json to indicate its of type module for JavaScript. * Updated system test with finicky rendering of context menus for test * Upping vite to 6.0.3 to resolve vulnerabilities and update its dependencies that have vulnerabilities * Updated to support attaching genbank .gb files * Forced package resolutions to avoid the vulnerabilities --- .github/workflows/nodejs.yml | 2 +- CHANGELOG.md | 7 + README.md | 2 +- backend/Dockerfile | 4 +- backend/etc/entrypoint-init.sh | 5 +- backend/requirements.txt | 2 +- docker-compose.local-production.yml | 2 +- docker-compose.staging.yml | 2 +- docker-compose.yml | 2 +- etc/fixtures/production.Dockerfile | 2 +- frontend/.eslintrc.cjs | 27 - frontend/Dockerfile | 6 +- frontend/README.md | 2 +- frontend/eslint-config-cgds.js | 113 ++ frontend/eslint.config.js | 71 + frontend/package.json | 26 +- .../AnalysisListing/AnalysisListingLegend.vue | 12 +- .../src/components/AnalysisView/GeneBox.vue | 26 +- .../SectionSupportingEvidence.vue | 12 +- .../components/AnalysisView/SectionText.vue | 3 +- .../components/AnnotationView/TextDataset.vue | 6 +- frontend/src/components/SectionImage.vue | 12 +- frontend/src/views/AnalysisView.vue | 8 +- .../AnalysisListing/AnalysisCard.spec.js | 3 +- .../components/Dialogs/InputDialog.spec.js | 2 +- frontend/test/stores/authStore.spec.js | 3 +- frontend/vite.config.js | 5 +- frontend/yarn.lock | 1329 ++++++++--------- setup.sh | 1 + system-tests/.eslintrc.js | 27 - system-tests/cypress.config.js | 4 +- .../e2e/case_supporting_evidence.cy.js | 2 +- system-tests/e2e/discussions_analysis.cy.js | 27 +- system-tests/e2e/edit_case_analysis.cy.js | 5 +- system-tests/e2e/rosalution_home.cy.js | 4 +- ...utilize_analysis_section_attachments.cy.js | 4 +- system-tests/eslint-config-cgds.js | 113 ++ system-tests/eslint.config.js | 28 + system-tests/package.json | 14 +- system-tests/yarn.lock | 351 +++-- 40 files changed, 1255 insertions(+), 1021 deletions(-) delete mode 100644 frontend/.eslintrc.cjs create mode 100644 frontend/eslint-config-cgds.js create mode 100644 frontend/eslint.config.js delete mode 100644 system-tests/.eslintrc.js create mode 100644 system-tests/eslint-config-cgds.js create mode 100644 system-tests/eslint.config.js diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 8be25361..d1e2b226 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - node-version: [20.8] + node-version: [23.4] steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 13299b78..5afd3362 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,10 +12,17 @@ using OpenCravat. VCF string provided by Ensembl's API is cached in the MongoDB Variant annotations were rendering vertically and it was taking too much space. - Analyses have a version manifest of annotation's dataset, source, and version - Increased VueJS version to 3.5.12 to use TemplateRef as a feature +- Added support for attaching genbank (.gb) files for supporting evidence attachments + +### Development + +- Minimum NodeJS version increased to v23.4 to support upgrading package dependencies to avoid reported vulnerabilities +- ESlint upgrade to 9 and migrating configuration to flat file config ### Bugs - Fixed developer API endpoint so that existing analyses can queue their annotations to be rendered again if desired. +- Backend starts takes over the shell process allowing it to receive SIGTERM for graceful shutdown ## 0.7.0 diff --git a/README.md b/README.md index 39f2f0bd..3a9c36e6 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ The following pre-requisites are required to be installed in the target *NIX env deploying and testing Rosalution. Install environment dependencies below using the respective installation instructions for your target environment. -- [Node.JS 20.8+](https://nodejs.org/en/) & [Classic Yarn](https://classic.yarnpkg.com/en/) +- [Node.JS 23.4+](https://nodejs.org/en/) & [Classic Yarn](https://classic.yarnpkg.com/en/) - Node.JS recommends managing Node.JS installations with [nvm](https://www.npmjs.com/package/npx) - [install](https://github.com/nvm-sh/nvm#install--update-script) - Yarn is not included with Node.JS with `nvm`. Run `npm install --global yarn` once Node.JS is installed. - [install](https://classic.yarnpkg.com/en/docs/install) - [Python 3.11+](https://www.python.org/) - [Install](https://www.python.org/downloads/) diff --git a/backend/Dockerfile b/backend/Dockerfile index 009d0215..5f810df1 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -4,7 +4,7 @@ WORKDIR /app COPY requirements.txt /app/requirements.txt RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt COPY ./src /app/src -ENTRYPOINT ["/bin/sh", "-c", "uvicorn src.main:app --host 0.0.0.0 --port 8000 --log-level info --reload"] +CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000", "--log-level", "info", "--reload"] # Production Build Stage FROM python:3.11-slim-bookworm AS production-stage @@ -15,4 +15,4 @@ RUN pip install --no-cache-dir -r /app/requirements.txt COPY ./src /app/src COPY etc/entrypoint-init.sh /app/entrypoint-init.sh RUN rm /app/src/routers/dev_router.py -ENTRYPOINT ["/bin/sh", "-c", "uvicorn src.main:app --host 0.0.0.0 --port 8000 --log-level info"] +CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000", "--log-level", "info"] diff --git a/backend/etc/entrypoint-init.sh b/backend/etc/entrypoint-init.sh index d27d0fa4..48b5580a 100755 --- a/backend/etc/entrypoint-init.sh +++ b/backend/etc/entrypoint-init.sh @@ -6,5 +6,6 @@ if [ "$ROSALUTION_ENV" = "production" ]; then DEBUG='-O' fi -ROSALUTION_KEY="$(< /dev/urandom tr -dc A-Za-z0-9 | head -c 65)" && export ROSALUTION_KEY && \ - python $DEBUG -m uvicorn src.main:app --host 0.0.0.0 --port 8000 --log-level info "$@" \ No newline at end of file +ROSALUTION_KEY="$(< /dev/urandom tr -dc A-Za-z0-9 | head -c 65)" && export ROSALUTION_KEY + +exec python $DEBUG -m uvicorn src.main:app --host 0.0.0.0 --port 8000 --log-level info "$@" \ No newline at end of file diff --git a/backend/requirements.txt b/backend/requirements.txt index faf82857..2c5be19a 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -5,7 +5,7 @@ itsdangerous==2.1.2 pymongo==4.6.3 jq==1.6.0 -python-multipart==0.0.7 +python-multipart==0.0.18 PyJWT[crypto]==2.8.0 bcrypt==4.2.0 diff --git a/docker-compose.local-production.yml b/docker-compose.local-production.yml index 6ad3130c..025b224b 100644 --- a/docker-compose.local-production.yml +++ b/docker-compose.local-production.yml @@ -52,7 +52,7 @@ services: environment: - ROSALUTION_ENV=production - MONGODB_HOST=rosalution-db - entrypoint: ['/bin/sh', '-c', './entrypoint-init.sh'] + command: ['./etc/entrypoint-init.sh'] labels: - "traefik.enable=true" - "traefik.docker.network=rosalution-network" diff --git a/docker-compose.staging.yml b/docker-compose.staging.yml index 2d9ccfff..47011302 100644 --- a/docker-compose.staging.yml +++ b/docker-compose.staging.yml @@ -24,7 +24,7 @@ services: - ROSALUTION_ENV=production - MONGODB_HOST=rosalution-db - CAS_LOGIN_ENABLE=True - entrypoint: ['/bin/sh', '-c', './entrypoint-init.sh'] + command: ['./etc/entrypoint-init.sh'] deploy: labels: - "traefik.enable=true" diff --git a/docker-compose.yml b/docker-compose.yml index d7d7daa5..6369cf40 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -57,7 +57,7 @@ services: - ./backend:/app environment: - MONGODB_HOST=rosalution-db - entrypoint: ['/bin/sh', '-c', './etc/entrypoint-init.sh --reload'] + command: ['./etc/entrypoint-init.sh', '--reload'] networks: - rosalution-network labels: diff --git a/etc/fixtures/production.Dockerfile b/etc/fixtures/production.Dockerfile index dbecb7c8..3deb27f4 100644 --- a/etc/fixtures/production.Dockerfile +++ b/etc/fixtures/production.Dockerfile @@ -1,3 +1,3 @@ -FROM mongo:5.0.9 as production-stage +FROM mongo:5.0.9 AS production-stage COPY --chmod=0777 ./initial-seed/initial-db-seed.sh /docker-entrypoint-initdb.d/initial-db-seed.sh COPY ./initial-seed/ /tmp/fixtures/initial-seed/ diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs deleted file mode 100644 index 00eac20a..00000000 --- a/frontend/.eslintrc.cjs +++ /dev/null @@ -1,27 +0,0 @@ -module.exports = { - root: true, - env: { - browser: true, - node: true, - es6: true, - }, - extends: [ - 'eslint:recommended', - 'plugin:vue/vue3-essential', - 'google', - ], - rules: { - 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', - 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', - 'max-len': [2, 120, 4], - 'no-invalid-this': 0, - }, - ignorePatterns: [ - 'node_modules/*', - 'dist/*', - ], - parserOptions: { - 'ecmaVersion': 2020, - 'sourceType': 'module', - }, -}; diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 6948a66a..d853edb1 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,5 +1,5 @@ # Local development stage -FROM node:20.8-alpine3.18 AS development-stage +FROM node:23.4-alpine3.21 AS development-stage WORKDIR /app COPY package.json /app/ COPY yarn.lock /app/ @@ -10,7 +10,7 @@ EXPOSE 3000 ENTRYPOINT ["yarn", "dev:host"] # Production Build stage -FROM node:20.8-alpine3.18 AS production-build +FROM node:23.4-alpine3.21 AS production-build WORKDIR /app COPY ./src /app/src/ COPY package.json /app/ @@ -23,7 +23,7 @@ ENV VITE_ROSALUTION_VERSION=$VERSION_BUILD_TAG RUN yarn install --frozen-lockfile && yarn build --base=/rosalution/ -FROM nginx:1.25.2-alpine3.18 AS production-stage +FROM nginx:1.26.2-alpine3.20 AS production-stage COPY etc/default.conf /etc/nginx/conf.d/ COPY --from=production-build /app/dist/ /usr/share/nginx/html/ diff --git a/frontend/README.md b/frontend/README.md index 6f10ce31..8915d3c0 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -8,7 +8,7 @@ for analysis. ### Dependencies -- [Node.JS 20.8+](https://nodejs.org/en/) +- [Node.JS 23.4.0+](https://nodejs.org/en/) - Recommended to manageNode.JS versions with [nvm](https://www.npmjs.com/package/npx) - [install](https://github.com/nvm-sh/nvm#install--update-script) - [Yarn - Classic](https://classic.yarnpkg.com/en/docs/getting-started) - [install](https://classic.yarnpkg.com/en/docs/install#windows-stable) diff --git a/frontend/eslint-config-cgds.js b/frontend/eslint-config-cgds.js new file mode 100644 index 00000000..41f195cd --- /dev/null +++ b/frontend/eslint-config-cgds.js @@ -0,0 +1,113 @@ +import stylistic from '@stylistic/eslint-plugin-js'; + +export default [{ + plugins: { + '@stylistic/js': stylistic, + }, + rules: { + // Possible Errors + 'no-cond-assign': 'off', + 'no-irregular-whitespace': 'error', + 'no-unexpected-multiline': 'error', + + // Best Practices + 'curly': ['error', 'multi-line'], + 'guard-for-in': 'error', + 'no-caller': 'error', + 'no-extend-native': 'error', + 'no-extra-bind': 'error', + 'no-invalid-this': 'off', + 'no-multi-str': 'error', + 'no-new-wrappers': 'error', + 'no-throw-literal': 'error', + 'no-with': 'error', + 'prefer-promise-reject-errors': 'error', + + // Variables + 'no-unused-vars': ['error', {args: 'none'}], + + // Stylistic + '@stylistic/js/array-bracket-newline': 'off', + '@stylistic/js/array-bracket-spacing': ['error', 'never'], + '@stylistic/js/array-element-newline': 'off', + '@stylistic/js/block-spacing': ['error', 'never'], + '@stylistic/js/brace-style': 'error', + 'camelcase': ['error', {properties: 'never'}], + '@stylistic/js/comma-dangle': ['error', 'always-multiline'], + '@stylistic/js/comma-spacing': 'error', + '@stylistic/js/comma-style': 'error', + '@stylistic/js/computed-property-spacing': 'error', + '@stylistic/js/eol-last': 'error', + '@stylistic/js/func-call-spacing': 'error', + '@stylistic/js/indent': [ + 'error', 2, { + 'CallExpression': { + 'arguments': 2, + }, + 'FunctionDeclaration': { + 'body': 1, + 'parameters': 2, + }, + 'FunctionExpression': { + 'body': 1, + 'parameters': 2, + }, + 'MemberExpression': 2, + 'ObjectExpression': 1, + 'SwitchCase': 1, + 'ignoredNodes': [ + 'ConditionalExpression', + ], + }, + ], + '@stylistic/js/key-spacing': 'error', + '@stylistic/js/keyword-spacing': 'error', + '@stylistic/js/linebreak-style': 'error', + '@stylistic/js/max-len': ['error', { + code: 120, + tabWidth: 2, + ignoreUrls: true, + ignorePattern: 'goog.(module|require)', + }], + 'new-cap': 'error', + 'no-array-constructor': 'error', + '@stylistic/js/no-mixed-spaces-and-tabs': 'error', + '@stylistic/js/no-multiple-empty-lines': ['error', {max: 2}], + 'no-new-object': 'error', + '@stylistic/js/no-tabs': 'error', + '@stylistic/js/no-trailing-spaces': 'error', + '@stylistic/js/object-curly-spacing': 'error', + 'one-var': ['error', { + var: 'never', + let: 'never', + const: 'never', + }], + '@stylistic/js/operator-linebreak': ['error', 'after'], + '@stylistic/js/padded-blocks': ['error', 'never'], + '@stylistic/js/quote-props': ['error', 'consistent'], + '@stylistic/js/quotes': ['error', 'single', {allowTemplateLiterals: true}], + '@stylistic/js/semi': 'error', + '@stylistic/js/semi-spacing': 'error', + '@stylistic/js/space-before-blocks': 'error', + '@stylistic/js/space-before-function-paren': ['error', { + asyncArrow: 'always', + anonymous: 'never', + named: 'never', + }], + '@stylistic/js/spaced-comment': ['error', 'always'], + '@stylistic/js/switch-colon-spacing': 'error', + + // ECMA 2022 rulesets + '@stylistic/js/arrow-parens': ['error', 'always'], + 'constructor-super': 'error', + '@stylistic/js/generator-star-spacing': ['error', 'after'], + 'no-new-symbol': 'error', + 'no-this-before-super': 'error', + 'no-var': 'error', + 'prefer-const': ['error', {destructuring: 'all'}], + 'prefer-rest-params': 'error', + 'prefer-spread': 'error', + 'rest-spread-spacing': 'error', + 'yield-star-spacing': ['error', 'after'], + }, +}]; diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js new file mode 100644 index 00000000..7d12339a --- /dev/null +++ b/frontend/eslint.config.js @@ -0,0 +1,71 @@ +import js from '@eslint/js'; +import pluginVue from 'eslint-plugin-vue'; +import globals from 'globals'; +import cgds from './eslint-config-cgds.js'; + + +export default [ + { + ignores: [ + 'node_modules/**', + 'dist/**', + 'test/__mocks__/**', + ], + }, + js.configs.recommended, + // { + ...cgds, + // Temporarily setting only essential rules; will make update after team discussion + // as to which level to increase vuejs linting rules too. + ...pluginVue.configs['flat/essential'], + // files: ['src/**/*.js', 'src/**/*.vue', 'test/**/*.spec.js'], + { + languageOptions: { + sourceType: 'module', + ecmaVersion: 2022, + globals: { + ...globals.browser, + ...globals.node, + process: 'readonly', + }, + }, + }, + { + rules: { + 'vue/prop-name-casing': 'off', + 'vue/require-default-prop': 'off', + 'vue/max-attributes-per-line': ['error', { + 'singleline': { + 'max': 6, + }, + 'multiline': { + 'max': 2, + }, + }], + // Disabling error temporarilly until team can reconvence and make a decision on us moving forward regarding + // this configuration. + 'vue/html-self-closing': ['off', { + 'html': { + 'void': 'never', + 'normal': 'always', + 'component': 'always', + }, + 'svg': 'always', + 'math': 'always', + }], + // We inconsistently 2 space tab in SFC template section at the template base. + // Will update in future update to set rule and make consistent in seperate PR + // after team discussion. + 'vue/html-indent': ['off'], + // 'vue/singleline-html-element-content-newline': ['error', { + // 'ignoreWhenNoAttributes': true, + // 'ignoreWhenEmpty': true, + // 'ignores': ['pre', 'textarea', ...INLINE_ELEMENTS], + // 'externalIgnores': [] + // }], + // 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', + // 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', + // }, + }, + }, +]; diff --git a/frontend/package.json b/frontend/package.json index 9be7f56a..2dbf02b6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,8 +7,8 @@ "build": "vite build", "dev": "vite", "dev:host": "vite --host 0.0.0.0 --port 80", - "lint": "eslint --ext .js,.vue ./", - "lint:auto": "eslint --ext .js,.vue ./ --fix", + "lint": "eslint ./", + "lint:auto": "eslint ./ --fix", "serve": "vite preview", "test:unit": "vitest run", "test:unit:watch": "vitest", @@ -25,16 +25,20 @@ "vue-router": "4.2.5" }, "devDependencies": { - "@vitejs/plugin-vue": "5.1.4", - "@vitest/coverage-v8": "2.1.1", - "@vitest/ui": "2.1.1", + "@stylistic/eslint-plugin-js": "2.12.1", + "@vitejs/plugin-vue": "5.2.1", + "@vitest/coverage-v8": "v3.0.0-beta.2", + "@vitest/ui": "v3.0.0-beta.2", "@vue/test-utils": "2.4.1", - "eslint": "8.50.0", - "eslint-config-google": "0.14.0", - "eslint-plugin-vue": "9.17.0", - "happy-dom": "14.12.3", + "eslint": "9.16.0", + "eslint-plugin-vue": "9.32.0", + "happy-dom": "15.10.2", "sinon": "19.0.2", - "vite": "5.4.8", - "vitest": "2.1.1" + "vite": "6.0.3", + "vitest": "v3.0.0-beta.2" + }, + "resolutions": { + "nanoid": "3.3.8", + "cross-spawn": "7.0.5" } } diff --git a/frontend/src/components/AnalysisListing/AnalysisListingLegend.vue b/frontend/src/components/AnalysisListing/AnalysisListingLegend.vue index fa796f77..4c9a620e 100644 --- a/frontend/src/components/AnalysisListing/AnalysisListingLegend.vue +++ b/frontend/src/components/AnalysisListing/AnalysisListingLegend.vue @@ -1,11 +1,13 @@