From 07e65356338edf1d29a6b4d6d7baf3e0aa36665d Mon Sep 17 00:00:00 2001 From: imfozilbek Date: Thu, 27 Nov 2025 19:27:07 +0500 Subject: [PATCH] refactor: add context keywords and improve hardcoded value suggestions --- .../guardian/src/domain/constants/Messages.ts | 9 + .../src/domain/constants/Suggestions.ts | 148 +++++++++++++ .../domain/value-objects/HardcodedValue.ts | 196 ++++++++++-------- 3 files changed, 270 insertions(+), 83 deletions(-) diff --git a/packages/guardian/src/domain/constants/Messages.ts b/packages/guardian/src/domain/constants/Messages.ts index 5c62372..aa3ca91 100644 --- a/packages/guardian/src/domain/constants/Messages.ts +++ b/packages/guardian/src/domain/constants/Messages.ts @@ -80,3 +80,12 @@ export const ANEMIC_MODEL_MESSAGES = { ENCAPSULATE_BUSINESS_RULES: "3. Encapsulate business rules inside entity methods", USE_DOMAIN_EVENTS: "4. Use domain events to communicate state changes", } + +/** + * Example values used in violation messages + */ +export const VIOLATION_EXAMPLE_VALUES = { + UNKNOWN: "unknown", + USER_REPOSITORY: "UserRepository", + FIND_ONE: "findOne", +} diff --git a/packages/guardian/src/domain/constants/Suggestions.ts b/packages/guardian/src/domain/constants/Suggestions.ts index d9d3bcc..99afec4 100644 --- a/packages/guardian/src/domain/constants/Suggestions.ts +++ b/packages/guardian/src/domain/constants/Suggestions.ts @@ -24,6 +24,106 @@ export const SUGGESTION_KEYWORDS = { CONSOLE_ERROR: "console.error", } as const +/** + * Context keywords for email detection + */ +export const EMAIL_CONTEXT_KEYWORDS = { + ADMIN: "admin", + SUPPORT: "support", + NOREPLY: "noreply", + NO_REPLY: "no-reply", +} as const + +/** + * Context keywords for API key detection + */ +export const API_KEY_CONTEXT_KEYWORDS = { + SECRET: "secret", + PUBLIC: "public", +} as const + +/** + * Context keywords for URL detection + */ +export const URL_CONTEXT_KEYWORDS = { + API: "api", + DATABASE: "database", + DB: "db", + MONGO: "mongo", + POSTGRES: "postgres", + PG: "pg", +} as const + +/** + * Context keywords for IP address detection + */ +export const IP_CONTEXT_KEYWORDS = { + SERVER: "server", + REDIS: "redis", +} as const + +/** + * Context keywords for file path detection + */ +export const FILE_PATH_CONTEXT_KEYWORDS = { + LOG: "log", + DATA: "data", + TEMP: "temp", +} as const + +/** + * Context keywords for date detection + */ +export const DATE_CONTEXT_KEYWORDS = { + DEADLINE: "deadline", + START: "start", + END: "end", + EXPIR: "expir", +} as const + +/** + * Context keywords for UUID detection + */ +export const UUID_CONTEXT_KEYWORDS = { + ID: "id", + IDENTIFIER: "identifier", + REQUEST: "request", + SESSION: "session", +} as const + +/** + * Context keywords for version detection + */ +export const VERSION_CONTEXT_KEYWORDS = { + APP: "app", +} as const + +/** + * Context keywords for color detection + */ +export const COLOR_CONTEXT_KEYWORDS = { + PRIMARY: "primary", + SECONDARY: "secondary", + BACKGROUND: "background", +} as const + +/** + * Context keywords for base64 detection + */ +export const BASE64_CONTEXT_KEYWORDS = { + TOKEN: "token", + KEY: "key", +} as const + +/** + * Context keywords for config detection + */ +export const CONFIG_CONTEXT_KEYWORDS = { + ENDPOINT: "endpoint", + ROUTE: "route", + CONNECTION: "connection", +} as const + /** * Constant name templates */ @@ -41,6 +141,50 @@ export const CONSTANT_NAMES = { MAGIC_STRING: "MAGIC_STRING", MAGIC_NUMBER: "MAGIC_NUMBER", UNKNOWN_CONSTANT: "UNKNOWN_CONSTANT", + ADMIN_EMAIL: "ADMIN_EMAIL", + SUPPORT_EMAIL: "SUPPORT_EMAIL", + NOREPLY_EMAIL: "NOREPLY_EMAIL", + DEFAULT_EMAIL: "DEFAULT_EMAIL", + API_SECRET_KEY: "API_SECRET_KEY", + API_PUBLIC_KEY: "API_PUBLIC_KEY", + API_KEY: "API_KEY", + DATABASE_URL: "DATABASE_URL", + MONGODB_CONNECTION_STRING: "MONGODB_CONNECTION_STRING", + POSTGRES_URL: "POSTGRES_URL", + BASE_URL: "BASE_URL", + SERVER_IP: "SERVER_IP", + DATABASE_HOST: "DATABASE_HOST", + REDIS_HOST: "REDIS_HOST", + HOST_IP: "HOST_IP", + LOG_FILE_PATH: "LOG_FILE_PATH", + CONFIG_FILE_PATH: "CONFIG_FILE_PATH", + DATA_DIR_PATH: "DATA_DIR_PATH", + TEMP_DIR_PATH: "TEMP_DIR_PATH", + FILE_PATH: "FILE_PATH", + DEADLINE: "DEADLINE", + START_DATE: "START_DATE", + END_DATE: "END_DATE", + EXPIRATION_DATE: "EXPIRATION_DATE", + DEFAULT_DATE: "DEFAULT_DATE", + DEFAULT_ID: "DEFAULT_ID", + REQUEST_ID: "REQUEST_ID", + SESSION_ID: "SESSION_ID", + UUID_CONSTANT: "UUID_CONSTANT", + API_VERSION: "API_VERSION", + APP_VERSION: "APP_VERSION", + VERSION: "VERSION", + PRIMARY_COLOR: "PRIMARY_COLOR", + SECONDARY_COLOR: "SECONDARY_COLOR", + BACKGROUND_COLOR: "BACKGROUND_COLOR", + COLOR_CONSTANT: "COLOR_CONSTANT", + MAC_ADDRESS: "MAC_ADDRESS", + ENCODED_TOKEN: "ENCODED_TOKEN", + ENCODED_KEY: "ENCODED_KEY", + BASE64_VALUE: "BASE64_VALUE", + API_ENDPOINT: "API_ENDPOINT", + ROUTE_PATH: "ROUTE_PATH", + CONNECTION_STRING: "CONNECTION_STRING", + CONFIG_VALUE: "CONFIG_VALUE", } as const /** @@ -50,4 +194,8 @@ export const LOCATIONS = { SHARED_CONSTANTS: "shared/constants", DOMAIN_CONSTANTS: "domain/constants", INFRASTRUCTURE_CONFIG: "infrastructure/config", + CONFIG_ENVIRONMENT: "src/config/environment.ts", + CONFIG_CONTACTS: "src/config/contacts.ts", + CONFIG_PATHS: "src/config/paths.ts", + CONFIG_DATES: "src/config/dates.ts", } as const diff --git a/packages/guardian/src/domain/value-objects/HardcodedValue.ts b/packages/guardian/src/domain/value-objects/HardcodedValue.ts index 6f42eab..5081dc7 100644 --- a/packages/guardian/src/domain/value-objects/HardcodedValue.ts +++ b/packages/guardian/src/domain/value-objects/HardcodedValue.ts @@ -1,6 +1,21 @@ import { ValueObject } from "./ValueObject" import { DETECTION_PATTERNS, HARDCODE_TYPES } from "../../shared/constants/rules" -import { CONSTANT_NAMES, LOCATIONS, SUGGESTION_KEYWORDS } from "../constants/Suggestions" +import { + API_KEY_CONTEXT_KEYWORDS, + BASE64_CONTEXT_KEYWORDS, + COLOR_CONTEXT_KEYWORDS, + CONFIG_CONTEXT_KEYWORDS, + CONSTANT_NAMES, + DATE_CONTEXT_KEYWORDS, + EMAIL_CONTEXT_KEYWORDS, + FILE_PATH_CONTEXT_KEYWORDS, + IP_CONTEXT_KEYWORDS, + LOCATIONS, + SUGGESTION_KEYWORDS, + URL_CONTEXT_KEYWORDS, + UUID_CONTEXT_KEYWORDS, + VERSION_CONTEXT_KEYWORDS, +} from "../constants/Suggestions" export type HardcodeType = (typeof HARDCODE_TYPES)[keyof typeof HARDCODE_TYPES] @@ -162,150 +177,165 @@ export class HardcodedValue extends ValueObject { const valueType = this.props.valueType if (valueType === "email") { - if (context.includes("admin")) { - return "ADMIN_EMAIL" + if (context.includes(EMAIL_CONTEXT_KEYWORDS.ADMIN)) { + return CONSTANT_NAMES.ADMIN_EMAIL } - if (context.includes("support")) { - return "SUPPORT_EMAIL" + if (context.includes(EMAIL_CONTEXT_KEYWORDS.SUPPORT)) { + return CONSTANT_NAMES.SUPPORT_EMAIL } - if (context.includes("noreply") || context.includes("no-reply")) { - return "NOREPLY_EMAIL" + if ( + context.includes(EMAIL_CONTEXT_KEYWORDS.NOREPLY) || + context.includes(EMAIL_CONTEXT_KEYWORDS.NO_REPLY) + ) { + return CONSTANT_NAMES.NOREPLY_EMAIL } - return "DEFAULT_EMAIL" + return CONSTANT_NAMES.DEFAULT_EMAIL } if (valueType === "api_key") { - if (context.includes("secret")) { - return "API_SECRET_KEY" + if (context.includes(API_KEY_CONTEXT_KEYWORDS.SECRET)) { + return CONSTANT_NAMES.API_SECRET_KEY } - if (context.includes("public")) { - return "API_PUBLIC_KEY" + if (context.includes(API_KEY_CONTEXT_KEYWORDS.PUBLIC)) { + return CONSTANT_NAMES.API_PUBLIC_KEY } - return "API_KEY" + return CONSTANT_NAMES.API_KEY } if (valueType === "url") { - if (context.includes("api")) { - return "API_BASE_URL" + if (context.includes(URL_CONTEXT_KEYWORDS.API)) { + return CONSTANT_NAMES.API_BASE_URL } - if (context.includes("database") || context.includes("db")) { - return "DATABASE_URL" + if ( + context.includes(URL_CONTEXT_KEYWORDS.DATABASE) || + context.includes(URL_CONTEXT_KEYWORDS.DB) + ) { + return CONSTANT_NAMES.DATABASE_URL } - if (context.includes("mongo")) { - return "MONGODB_CONNECTION_STRING" + if (context.includes(URL_CONTEXT_KEYWORDS.MONGO)) { + return CONSTANT_NAMES.MONGODB_CONNECTION_STRING } - if (context.includes("postgres") || context.includes("pg")) { - return "POSTGRES_URL" + if ( + context.includes(URL_CONTEXT_KEYWORDS.POSTGRES) || + context.includes(URL_CONTEXT_KEYWORDS.PG) + ) { + return CONSTANT_NAMES.POSTGRES_URL } - return "BASE_URL" + return CONSTANT_NAMES.BASE_URL } if (valueType === "ip_address") { - if (context.includes("server")) { - return "SERVER_IP" + if (context.includes(IP_CONTEXT_KEYWORDS.SERVER)) { + return CONSTANT_NAMES.SERVER_IP } - if (context.includes("database") || context.includes("db")) { - return "DATABASE_HOST" + if ( + context.includes(URL_CONTEXT_KEYWORDS.DATABASE) || + context.includes(URL_CONTEXT_KEYWORDS.DB) + ) { + return CONSTANT_NAMES.DATABASE_HOST } - if (context.includes("redis")) { - return "REDIS_HOST" + if (context.includes(IP_CONTEXT_KEYWORDS.REDIS)) { + return CONSTANT_NAMES.REDIS_HOST } - return "HOST_IP" + return CONSTANT_NAMES.HOST_IP } if (valueType === "file_path") { - if (context.includes("log")) { - return "LOG_FILE_PATH" + if (context.includes(FILE_PATH_CONTEXT_KEYWORDS.LOG)) { + return CONSTANT_NAMES.LOG_FILE_PATH } - if (context.includes("config")) { - return "CONFIG_FILE_PATH" + if (context.includes(SUGGESTION_KEYWORDS.CONFIG)) { + return CONSTANT_NAMES.CONFIG_FILE_PATH } - if (context.includes("data")) { - return "DATA_DIR_PATH" + if (context.includes(FILE_PATH_CONTEXT_KEYWORDS.DATA)) { + return CONSTANT_NAMES.DATA_DIR_PATH } - if (context.includes("temp")) { - return "TEMP_DIR_PATH" + if (context.includes(FILE_PATH_CONTEXT_KEYWORDS.TEMP)) { + return CONSTANT_NAMES.TEMP_DIR_PATH } - return "FILE_PATH" + return CONSTANT_NAMES.FILE_PATH } if (valueType === "date") { - if (context.includes("deadline")) { - return "DEADLINE" + if (context.includes(DATE_CONTEXT_KEYWORDS.DEADLINE)) { + return CONSTANT_NAMES.DEADLINE } - if (context.includes("start")) { - return "START_DATE" + if (context.includes(DATE_CONTEXT_KEYWORDS.START)) { + return CONSTANT_NAMES.START_DATE } - if (context.includes("end")) { - return "END_DATE" + if (context.includes(DATE_CONTEXT_KEYWORDS.END)) { + return CONSTANT_NAMES.END_DATE } - if (context.includes("expir")) { - return "EXPIRATION_DATE" + if (context.includes(DATE_CONTEXT_KEYWORDS.EXPIR)) { + return CONSTANT_NAMES.EXPIRATION_DATE } - return "DEFAULT_DATE" + return CONSTANT_NAMES.DEFAULT_DATE } if (valueType === "uuid") { - if (context.includes("id") || context.includes("identifier")) { - return "DEFAULT_ID" + if ( + context.includes(UUID_CONTEXT_KEYWORDS.ID) || + context.includes(UUID_CONTEXT_KEYWORDS.IDENTIFIER) + ) { + return CONSTANT_NAMES.DEFAULT_ID } - if (context.includes("request")) { - return "REQUEST_ID" + if (context.includes(UUID_CONTEXT_KEYWORDS.REQUEST)) { + return CONSTANT_NAMES.REQUEST_ID } - if (context.includes("session")) { - return "SESSION_ID" + if (context.includes(UUID_CONTEXT_KEYWORDS.SESSION)) { + return CONSTANT_NAMES.SESSION_ID } - return "UUID_CONSTANT" + return CONSTANT_NAMES.UUID_CONSTANT } if (valueType === "version") { - if (context.includes("api")) { - return "API_VERSION" + if (context.includes(URL_CONTEXT_KEYWORDS.API)) { + return CONSTANT_NAMES.API_VERSION } - if (context.includes("app")) { - return "APP_VERSION" + if (context.includes(VERSION_CONTEXT_KEYWORDS.APP)) { + return CONSTANT_NAMES.APP_VERSION } - return "VERSION" + return CONSTANT_NAMES.VERSION } if (valueType === "color") { - if (context.includes("primary")) { - return "PRIMARY_COLOR" + if (context.includes(COLOR_CONTEXT_KEYWORDS.PRIMARY)) { + return CONSTANT_NAMES.PRIMARY_COLOR } - if (context.includes("secondary")) { - return "SECONDARY_COLOR" + if (context.includes(COLOR_CONTEXT_KEYWORDS.SECONDARY)) { + return CONSTANT_NAMES.SECONDARY_COLOR } - if (context.includes("background")) { - return "BACKGROUND_COLOR" + if (context.includes(COLOR_CONTEXT_KEYWORDS.BACKGROUND)) { + return CONSTANT_NAMES.BACKGROUND_COLOR } - return "COLOR_CONSTANT" + return CONSTANT_NAMES.COLOR_CONSTANT } if (valueType === "mac_address") { - return "MAC_ADDRESS" + return CONSTANT_NAMES.MAC_ADDRESS } if (valueType === "base64") { - if (context.includes("token")) { - return "ENCODED_TOKEN" + if (context.includes(BASE64_CONTEXT_KEYWORDS.TOKEN)) { + return CONSTANT_NAMES.ENCODED_TOKEN } - if (context.includes("key")) { - return "ENCODED_KEY" + if (context.includes(BASE64_CONTEXT_KEYWORDS.KEY)) { + return CONSTANT_NAMES.ENCODED_KEY } - return "BASE64_VALUE" + return CONSTANT_NAMES.BASE64_VALUE } if (valueType === "config") { - if (context.includes("endpoint")) { - return "API_ENDPOINT" + if (context.includes(CONFIG_CONTEXT_KEYWORDS.ENDPOINT)) { + return CONSTANT_NAMES.API_ENDPOINT } - if (context.includes("route")) { - return "ROUTE_PATH" + if (context.includes(CONFIG_CONTEXT_KEYWORDS.ROUTE)) { + return CONSTANT_NAMES.ROUTE_PATH } - if (context.includes("connection")) { - return "CONNECTION_STRING" + if (context.includes(CONFIG_CONTEXT_KEYWORDS.CONNECTION)) { + return CONSTANT_NAMES.CONNECTION_STRING } - return "CONFIG_VALUE" + return CONSTANT_NAMES.CONFIG_VALUE } if (value.includes(SUGGESTION_KEYWORDS.HTTP)) { @@ -339,19 +369,19 @@ export class HardcodedValue extends ValueObject { const valueType = this.props.valueType if (valueType === "api_key" || valueType === "url" || valueType === "ip_address") { - return "src/config/environment.ts" + return LOCATIONS.CONFIG_ENVIRONMENT } if (valueType === "email") { - return "src/config/contacts.ts" + return LOCATIONS.CONFIG_CONTACTS } if (valueType === "file_path") { - return "src/config/paths.ts" + return LOCATIONS.CONFIG_PATHS } if (valueType === "date") { - return "src/config/dates.ts" + return LOCATIONS.CONFIG_DATES } if (