-
Notifications
You must be signed in to change notification settings - Fork 11
Vulnerability fix changes #370
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,50 @@ | ||
| FROM --platform=linux/amd64 node:24.3.0-alpine | ||
| RUN mkdir -p /opt/api-service | ||
| COPY ./api-service ./opt/api-service | ||
| # Build stage | ||
| FROM --platform=linux/amd64 public.ecr.aws/docker/library/node:24.13.1-slim AS builder | ||
| RUN npm install -g npm@11.10.1 \ | ||
| && npm pack tar@7.5.11 \ | ||
| && tar -xzf tar-7.5.11.tgz -C /usr/local/lib/node_modules/npm/node_modules/tar --strip-components=1 \ | ||
| && rm tar-7.5.11.tgz \ | ||
| && npm install -g minimatch@10.2.2 \ | ||
| && npm cache clean --force \ | ||
| && rm -rf /usr/local/lib/node_modules/npm/node_modules/minimatch \ | ||
| && cp -r /usr/local/lib/node_modules/minimatch /usr/local/lib/node_modules/npm/node_modules/ | ||
| RUN apt-get update \ | ||
| && apt-get install -y --no-install-recommends ca-certificates openssl \ | ||
| && apt-get upgrade -y \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
| WORKDIR /opt/api-service | ||
| RUN rm -rf postman-collection | ||
| RUN npm install | ||
| COPY . . | ||
| # Install all dependencies for building | ||
| COPY api-service/package.json api-service/package-lock.json ./ | ||
| RUN npm ci --ignore-scripts | ||
| # Copy source code and build | ||
| COPY api-service/tsconfig.json ./ | ||
| COPY api-service/src/ ./src/ | ||
| COPY api-service/@types/ ./@types/ | ||
| RUN npm run build | ||
| # Remove declaration files to avoid module resolution conflicts | ||
| RUN find dist -name "*.d.ts" -delete | ||
|
|
||
| # Production stage | ||
| FROM --platform=linux/amd64 public.ecr.aws/docker/library/node:24.13.1-slim AS production | ||
| RUN npm install -g npm@11.10.1 \ | ||
| && npm pack tar@7.5.11 \ | ||
| && tar -xzf tar-7.5.11.tgz -C /usr/local/lib/node_modules/npm/node_modules/tar --strip-components=1 \ | ||
| && rm tar-7.5.11.tgz \ | ||
| && npm install -g minimatch@10.2.2 \ | ||
| && npm cache clean --force \ | ||
| && rm -rf /usr/local/lib/node_modules/npm/node_modules/minimatch \ | ||
| && cp -r /usr/local/lib/node_modules/minimatch /usr/local/lib/node_modules/npm/node_modules/ | ||
| RUN apt-get update \ | ||
| && apt-get install -y --no-install-recommends ca-certificates openssl \ | ||
| && apt-get upgrade -y \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
| WORKDIR /opt/api-service | ||
| # Copy package.json and install only production dependencies | ||
| COPY api-service/package.json api-service/package-lock.json ./ | ||
| RUN npm ci --omit=dev --ignore-scripts | ||
| # Copy built application from build stage | ||
| COPY --from=builder /opt/api-service/dist ./ | ||
| # Verify the structure and ensure no declaration files | ||
| RUN ls -la && echo "=== Checking for .d.ts files ===" && find . -name "*.d.ts" | head -5 || echo "No .d.ts files found" | ||
| EXPOSE 3000 | ||
| CMD ["npm", "run", "start"] | ||
| CMD ["node", "app.js"] | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,45 @@ | ||||||||||||||||||||||
| import js from '@eslint/js'; | ||||||||||||||||||||||
| import typescript from '@typescript-eslint/eslint-plugin'; | ||||||||||||||||||||||
| import typescriptParser from '@typescript-eslint/parser'; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| export default [ | ||||||||||||||||||||||
|
Comment on lines
+1
to
+5
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Module type mismatch: ESM syntax with CommonJS package type. The Either rename the file to 🔧 Option 1: Rename to `eslint.config.mjs` (preferred for ESLint 9)Rename the file from 🔧 Option 2: Convert to CommonJS syntax-import js from '@eslint/js';
-import typescript from '@typescript-eslint/eslint-plugin';
-import typescriptParser from '@typescript-eslint/parser';
+const js = require('@eslint/js');
+const typescript = require('@typescript-eslint/eslint-plugin');
+const typescriptParser = require('@typescript-eslint/parser');
-export default [
+module.exports = [
{
files: ['**/*.ts', '**/*.tsx'],
// ... rest unchanged
}
];📝 Committable suggestion
Suggested change
🧰 Tools🪛 Biome (2.4.9)[error] 1-1: Illegal use of an import declaration outside of a module (parse) [error] 2-2: Illegal use of an import declaration outside of a module (parse) [error] 3-3: Illegal use of an import declaration outside of a module (parse) 🤖 Prompt for AI Agents |
||||||||||||||||||||||
| { | ||||||||||||||||||||||
| files: ['**/*.ts', '**/*.tsx'], | ||||||||||||||||||||||
| languageOptions: { | ||||||||||||||||||||||
| parser: typescriptParser, | ||||||||||||||||||||||
| parserOptions: { | ||||||||||||||||||||||
| ecmaVersion: 'latest', | ||||||||||||||||||||||
| sourceType: 'module' | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
| plugins: { | ||||||||||||||||||||||
| '@typescript-eslint': typescript | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
| rules: { | ||||||||||||||||||||||
| ...js.configs.recommended.rules, | ||||||||||||||||||||||
| ...typescript.configs.recommended.rules, | ||||||||||||||||||||||
| '@typescript-eslint/no-unused-vars': ['error', { 'argsIgnorePattern': '^_' }], | ||||||||||||||||||||||
| '@typescript-eslint/no-explicit-any': 'off', | ||||||||||||||||||||||
| '@typescript-eslint/quotes': [ | ||||||||||||||||||||||
| 'error', | ||||||||||||||||||||||
| 'double', | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| 'allowTemplateLiterals': true | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| ] | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| files: ['**/*.js'], | ||||||||||||||||||||||
| languageOptions: { | ||||||||||||||||||||||
| ecmaVersion: 'latest', | ||||||||||||||||||||||
| sourceType: 'module' | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
| rules: { | ||||||||||||||||||||||
| ...js.configs.recommended.rules | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| ignores: ['dist/', 'node_modules/', '**/*.d.ts'] | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| ]; | ||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,16 +1,27 @@ | ||
| import { Sequelize } from "sequelize"; | ||
| import { connectionConfig } from "../configs/ConnectionsConfig" | ||
|
|
||
| const { database, host, password, port, username } = connectionConfig.postgres | ||
| const { database, host, port } = connectionConfig.postgres; | ||
| const credentials = connectionConfig.postgres.credentials.split("::"); | ||
|
|
||
| export const sequelize = new Sequelize({ | ||
| database, password, username: username, dialect: "postgres", host, port: +port, pool: { | ||
| max: 2, | ||
| min: 1, | ||
| acquire: 30000, | ||
| idle: 10000 | ||
| } | ||
| }) | ||
| const decodedCredentials = Buffer.from(credentials[1], 'base64').toString('utf-8'); | ||
|
|
||
| export const sequelize = new Sequelize( | ||
| database, | ||
| credentials[0], | ||
| decodedCredentials, | ||
|
Comment on lines
+5
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "Producer:"
sed -n '4,10p' api-service/src/configs/ConnectionsConfig.ts
echo
echo "Consumer:"
sed -n '4,12p' api-service/src/connections/databaseConnection.ts
echo
python - <<'PY'
import base64
raw = "postgres"
print("raw password:", raw)
print("base64-decoded bytes:", base64.b64decode(raw))
PYRepository: Sanketika-Obsrv/obsrv-api-service Length of output: 813 🏁 Script executed: cat -n api-service/src/configs/ConnectionsConfig.tsRepository: Sanketika-Obsrv/obsrv-api-service Length of output: 1332 🏁 Script executed: cat -n api-service/src/connections/databaseConnection.tsRepository: Sanketika-Obsrv/obsrv-api-service Length of output: 1172 🏁 Script executed: rg "credentials" --type ts -B 2 -A 2 -iRepository: Sanketika-Obsrv/obsrv-api-service Length of output: 4936 Password must be base64-encoded when building credentials, or decoding must be removed from the consumer.
But Plain-text or default passwords will fail authentication. For example, Either base64-encode the password in 🤖 Prompt for AI Agents |
||
| { | ||
| host, | ||
| port: +port, | ||
| dialect: "postgres", | ||
| pool: { | ||
| max: 2, | ||
| min: 1, | ||
| acquire: 30000, | ||
| idle: 10000 | ||
| } | ||
| } | ||
| ) | ||
|
|
||
| export const health = async () => { | ||
| return sequelize.query("select 1") | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -10,8 +10,8 @@ const telemetryObject = { type: "metric", ver: "1.0.0" }; | |||||||||||
|
|
||||||||||||
| const createMetricHandler = async (req: Request, res: Response, next: NextFunction) => { | ||||||||||||
| try { | ||||||||||||
| const { component } = req.body; | ||||||||||||
| const metricsBody = await Metrics.create({ ...(req.body), component: component }); | ||||||||||||
| const component = _.get(req, 'body.component'); | ||||||||||||
| const metricsBody = await Metrics.create({ ...(_.get(req, 'body')), component: component }); | ||||||||||||
|
Comment on lines
+13
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing validation for undefined request body. If Consider adding a default or validation: Proposed fix const component = _.get(req, 'body.component');
- const metricsBody = await Metrics.create({ ...(_.get(req, 'body')), component: component });
+ const requestBody = _.get(req, 'body', {});
+ const metricsBody = await Metrics.create({ ...requestBody, component });📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||
| updateTelemetryAuditEvent({ request: req, object: { id: metricsBody?.dataValues?.id, ...telemetryObject } }); | ||||||||||||
| ResponseHandler.successResponse(req, res, { status: httpStatus.OK, data: { id: metricsBody.dataValues.id } }); | ||||||||||||
| } catch (error: any) { | ||||||||||||
|
|
@@ -36,8 +36,8 @@ const listMetricsHandler = async (req: Request, res: Response, next: NextFunctio | |||||||||||
|
|
||||||||||||
| const updateMetricHandler = async (req: Request, res: Response, next: NextFunction) => { | ||||||||||||
| try { | ||||||||||||
| const { id } = req.params; | ||||||||||||
| const toUpdatePayload = req.body; | ||||||||||||
| const id = _.get(req, 'params.id'); | ||||||||||||
| const toUpdatePayload = _.get(req, 'body'); | ||||||||||||
| const { component } = toUpdatePayload; | ||||||||||||
| const isEmpty = _.isEmpty(toUpdatePayload); | ||||||||||||
| if (isEmpty) throw new Error("Failed to update record"); | ||||||||||||
|
|
@@ -59,7 +59,7 @@ const updateMetricHandler = async (req: Request, res: Response, next: NextFuncti | |||||||||||
|
|
||||||||||||
| const deleteMetricHandler = async (req: Request, res: Response, next: NextFunction) => { | ||||||||||||
| try { | ||||||||||||
| const { id } = req.params; | ||||||||||||
| const id = _.get(req, 'params.id'); | ||||||||||||
| const record = await Metrics.findOne({ where: { id } }); | ||||||||||||
| if (!record) throw new Error(httpStatus[httpStatus.NOT_FOUND]); | ||||||||||||
| await record.destroy(); | ||||||||||||
|
|
@@ -72,7 +72,7 @@ const deleteMetricHandler = async (req: Request, res: Response, next: NextFuncti | |||||||||||
|
|
||||||||||||
| const deleteMultipleMetricHandler = async (req: Request, res: Response, next: NextFunction) => { | ||||||||||||
| try { | ||||||||||||
| const { filters } = req.body; | ||||||||||||
| const filters = _.get(req, 'body.filters'); | ||||||||||||
| if (!filters) throw new Error("Failed to update record"); | ||||||||||||
| await Metrics.destroy({ where: filters }); | ||||||||||||
| ResponseHandler.successResponse(req, res, { status: httpStatus.OK, data: {} }); | ||||||||||||
|
|
||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,7 @@ const telemetryObject = { type: "alert-silence", ver: "1.0.0" }; | |
|
|
||
| const createHandler = async (request: Request, response: Response, next: NextFunction) => { | ||
| try { | ||
| const payload = request.body; | ||
| const payload = _.get(request,'body'); | ||
| const { startDate, endDate, alertId } = payload; | ||
|
Comment on lines
+14
to
15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n "_\.get\(request,\s*['\"]body['\"]\)" api-service/src/controllers/Alerts/Silence.ts
echo
sed -n '12,18p;73,84p' api-service/src/controllers/Alerts/Silence.tsRepository: Sanketika-Obsrv/obsrv-api-service Length of output: 1370 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Get the full createHandler function (lines 12-30 should cover the try-catch)
echo "=== createHandler ==="
sed -n '12,35p' api-service/src/controllers/Alerts/Silence.ts
echo
echo "=== updateHandler ==="
# Get the full updateHandler function
sed -n '73,95p' api-service/src/controllers/Alerts/Silence.tsRepository: Sanketika-Obsrv/obsrv-api-service Length of output: 2776 🏁 Script executed: #!/bin/bash
set -euoelpipefail
# Get more lines to see the complete catch blocks
sed -n '12,45p' api-service/src/controllers/Alerts/Silence.tsRepository: Sanketika-Obsrv/obsrv-api-service Length of output: 751 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Get more lines to see the complete catch blocks
sed -n '12,45p' api-service/src/controllers/Alerts/Silence.tsRepository: Sanketika-Obsrv/obsrv-api-service Length of output: 1718 Return 400 for missing request bodies;
🛠️ Suggested fix- const payload = _.get(request,'body');
+ const payload = _.get(request, "body", {});
+ if (_.isEmpty(payload)) {
+ return next({ message: httpStatus[httpStatus.BAD_REQUEST], statusCode: httpStatus.BAD_REQUEST });
+ }
const { startDate, endDate, alertId } = payload;
@@
- const payload = _.get(request, 'body');
+ const payload = _.get(request, "body", {});
+ if (_.isEmpty(payload)) {
+ return next({ message: httpStatus[httpStatus.BAD_REQUEST], statusCode: httpStatus.BAD_REQUEST });
+ }Also applies to: line 76 in updateHandler. 🤖 Prompt for AI Agents |
||
| const existingSilence = await Silence.findOne({ where: { alert_id: alertId } }); | ||
| if (existingSilence) existingSilence.destroy(); | ||
|
|
@@ -59,7 +59,7 @@ const listHandler = async (request: Request, response: Response, next: NextFunct | |
|
|
||
| const fetchHandler = async (request: Request, response: Response, next: NextFunction) => { | ||
| try { | ||
| const id = request.params.id; | ||
| const id = _.get(request,'params.id'); | ||
| const silenceModel = await Silence.findOne({ where: { id } }); | ||
| const transformedSilence = await transformSilences(silenceModel); | ||
| if (!silenceModel) return next({ message: httpStatus[httpStatus.NOT_FOUND], statusCode: httpStatus.NOT_FOUND }); | ||
|
|
@@ -72,8 +72,8 @@ const fetchHandler = async (request: Request, response: Response, next: NextFunc | |
|
|
||
| const updateHandler = async (request: Request, response: Response, next: NextFunction) => { | ||
| try { | ||
| const id = request.params.id; | ||
| const payload = request.body; | ||
| const id = _.get(request,'params.id'); | ||
| const payload = _.get(request, 'body'); | ||
| const silenceModel = await Silence.findOne({ where: { id } }); | ||
| if (!silenceModel) return next({ message: httpStatus[httpStatus.NOT_FOUND], statusCode: httpStatus.NOT_FOUND }); | ||
| const silenceObject = silenceModel?.toJSON(); | ||
|
|
@@ -98,7 +98,7 @@ const updateHandler = async (request: Request, response: Response, next: NextFun | |
|
|
||
| const deleteHandler = async (request: Request, response: Response, next: NextFunction) => { | ||
| try { | ||
| const id = request.params.id; | ||
| const id = _.get(request,'params.id'); | ||
| const silenceModel = await Silence.findOne({ where: { id } }); | ||
| if (!silenceModel) return next({ message: httpStatus[httpStatus.NOT_FOUND], statusCode: httpStatus.NOT_FOUND }); | ||
| const silenceObject = silenceModel?.toJSON(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: Sanketika-Obsrv/obsrv-api-service
Length of output: 12569
🏁 Script executed:
Repository: Sanketika-Obsrv/obsrv-api-service
Length of output: 11458
Copy JSON schema files into
distduring the build stage.api-service/src/controllers/DataMetrics/DataMetricsController.tsand 39+ other files import JSON schemas (e.g.,DataMetricsValidationSchema.json,Constants.json,SchemaMapping.json). The build script at line 23 runsnpm run buildwhich compiles TypeScript withresolveJsonModule: true, but only copiespackage.jsontodist/. The build does not copy schema/config JSON files fromsrc/intodist/, so those files will be missing at runtime when the compiled application tries to load them.📦 Suggested fix
Also applies to: lines 46-48
🤖 Prompt for AI Agents