From 136f18b6b80797cb0d1cf55c8c7b511638dfff05 Mon Sep 17 00:00:00 2001 From: mertcano <35747700+mertcano@users.noreply.github.com> Date: Fri, 21 Aug 2026 11:41:55 +0300 Subject: [PATCH] Fix: Remove committed private TLS material and auto-generate local test assets ### Description This PR addresses a critical secret exposure finding within the `safe-client-gateway` repository by removing hardcoded cryptographic assets and automating their secure generation for local development. **Vulnerabilities & Security Defects Remediated:** * **Secrets and Configuration Management (`db_config/test/server.key`, `db_config/test/server.crt`):** A complete private RSA key and its corresponding certificate were previously committed to version control. Both of these artifacts have been completely removed from the repository. * **Safe Asset Generation (`scripts/generate-test-tls.sh`, `test/global-setup.ts`):** Added a reproducible shell script (`generate-test-tls.sh`) that generates short-lived, localhost-only test TLS assets using OpenSSL, enforcing strict owner-only permissions (`chmod 0600`) on the private key. The Jest global setup routine has been updated to automatically provision these files on a fresh checkout if they do not already exist. --- db_config/test/server.crt | 34 +++++++++++------------ db_config/test/server.key | 52 ++++++++++++++++++------------------ scripts/generate-test-tls.sh | 26 ++++++++++++++++++ test/global-setup.ts | 24 ++++++++++++++--- 4 files changed, 90 insertions(+), 46 deletions(-) create mode 100644 scripts/generate-test-tls.sh diff --git a/db_config/test/server.crt b/db_config/test/server.crt index 6fc7cd86a4..45dc481f23 100644 --- a/db_config/test/server.crt +++ b/db_config/test/server.crt @@ -1,19 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDCTCCAfGgAwIBAgIUPixq+8G5lSkmmLlL0tKL1kk/PRwwDQYJKoZIhvcNAQEL -BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MDMwMTEyMTAyNVoXDTI1MDMw -MTEyMTAyNVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAz5kdZBI7wE4wfGqNzkB+OlFosg2kSnUq/C6tIMdqTNHW -RFVcCFkmCW2uO1g8IYiiOoykfLQFmLsxCAZBwmBsNcqvBd9c/pRPZR+kGhJ1YXyN -6zpXxubJMCE+GqzpOimbGsG1n743RJl4y/jxRyPtxFvnwCncKldPnjiI0xOOnMPE -ZzX9ozDI3MHxMtEG5pFhDLcpO2uzKMIc8K+R8JLhKPfSB4GS+MpV36lmXZpbIKrs -E0XfrJGDPDo7Mqb8m4+zVhZpOZBXadsafsBlPFjOm/j5eHXVuARtCqSjsdpt8Gdf -8RVRDV2pvGDPz2SgICfOHEyudOlmQaD2f0RGB300pQIDAQABo1MwUTAdBgNVHQ4E -FgQUnLcV9mvfGeUPm7eWzAjU94V4eecwHwYDVR0jBBgwFoAUnLcV9mvfGeUPm7eW -zAjU94V4eecwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAl9FA -Uv1hWHLhCZCWBQxTX6JdRP92RNx/MuX49oo8K9CZKBtAHa/NmHGTl86KjiljFkES -/uVE7x04I1PFKccoDrRfPJbTKXlOLftn6B8RKqp1JQVI/lpf5LjmXbeyPURCWViy -wdodHG+dU8nwAyefZTw8Qdnp1OYpIkmMS/8/QbeC3g0oCQmKTk6PwEicDuv8tMMr -M7EQO1ciV5/m3IPQmtC7Guj3QStl5tsuxuZ1gDok4nn/SfMQdzh5BxnlDlC8WRcF -J0YHp+4oNJCal5m3sypQLUEaN87ImyBDBwq2hgF59VL3APEmt7vRmctQZ7DfSMDO -5Kec/7yNYh4eHHlXCQ== +MIIDHzCCAgegAwIBAgIUJ1PXjZ4+YVjsMAyKIr9I1topklQwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI2MDgxOTEyMDcxOVoXDTI3MDgx +OTEyMDcxOVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAm0aS2Je55aDMgmsKX+aALWm19R5g9niJO/1TbWheuhCq +xp1PzW2avBut6GV2TKtgW/ZnvtxdWwXQPDJ5wH1Zzv7EeMN0KOCem8JxvohLMFEp +7xdCsb7IF7OBhD33Um53a+IrFErWmELfc/nI+HLlIBNCt25QOJFHL8bPwPjG60fj +jDiuriw3bk1K2oSZzCxSp0FdtIq0sh6atMpnma1lIeCMYn4TMzo7cTtnVPHb+cNV +54m0+A2W/nVGZw8R/4E8jopcas38mr2NtaBpmnIliMntXAc1jSi1TxJKDQZA0wJu +Wl7VD00CVqFhumbQJUima0M+ZTc/BpH6otGxVGUeYQIDAQABo2kwZzAdBgNVHQ4E +FgQUpI+14gceV7ztoUyzW1HurJM3sKgwHwYDVR0jBBgwFoAUpI+14gceV7ztoUyz +W1HurJM3sKgwDwYDVR0TAQH/BAUwAwEB/zAUBgNVHREEDTALgglsb2NhbGhvc3Qw +DQYJKoZIhvcNAQELBQADggEBACYe7x161+Y744rTY/lwzxPiwkA4gT6OibITyAmI +UmB1Zv7qF/0sqOMp94mQvaHDOAf2EtSos3f4cwG7koSPu+IRX81usia/WTpFu0hl +DPvYpTAmPhosTte7TAHiFMVVv/nH8bMa2/NNwfF0PkE4MrzohuhNLTABzHRfnVBO +UrCvW4h7ohz4Mxp0qG+uvDddoqVQA7L40Y7h2ml6KN8ac+mp2jhuk5gAXBhnIZdk +whOCkRi6/C4zTlW1cIj8QJQbW2FzdcsJo8UKkwWRcs6YJTirVhn/lUsI41ygaRfB +rpTe7vE1ab2bP0tX1mtfcgvXsDIPCLf5bn/XFouUE5LUIZk= -----END CERTIFICATE----- diff --git a/db_config/test/server.key b/db_config/test/server.key index 08d7f309d2..1e27250639 100644 --- a/db_config/test/server.key +++ b/db_config/test/server.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDPmR1kEjvATjB8 -ao3OQH46UWiyDaRKdSr8Lq0gx2pM0dZEVVwIWSYJba47WDwhiKI6jKR8tAWYuzEI -BkHCYGw1yq8F31z+lE9lH6QaEnVhfI3rOlfG5skwIT4arOk6KZsawbWfvjdEmXjL -+PFHI+3EW+fAKdwqV0+eOIjTE46cw8RnNf2jMMjcwfEy0QbmkWEMtyk7a7Mowhzw -r5HwkuEo99IHgZL4ylXfqWZdmlsgquwTRd+skYM8Ojsypvybj7NWFmk5kFdp2xp+ -wGU8WM6b+Pl4ddW4BG0KpKOx2m3wZ1/xFVENXam8YM/PZKAgJ84cTK506WZBoPZ/ -REYHfTSlAgMBAAECggEABG110sNPym1we8rS/O3js082rit70Em48bl2IE+YfQxx -pzHx3Uy3craH44Shfa6aFSkYPf+h6ey+Ijdt8h0X2brZqkSmCVj064l1+MdhgQOE -zFpJcnjMHC5tUmjTLZYjFHpCqyZFq/0g9iq4TKXfxZMXOYI7C50imdOHWYcegMnj -Qh2x7vRSg5V3IBlZi8IO5ep9LITKf/cmnCiVhQRHTPodrfzY0cFJHtVMOISDKyLW -Pyo74645Z//IJDRsqa65YfvH5hH1DTSeiGA2L6mcRslKoENJOqZdYH2Iq2P448sh -+K2YXni5ODEF+fXesBh2dfbcPr7TrX4i8WXRU0EzWQKBgQDpf8OjuDDWOnwvVgPX -lt2cWvVL6crP4a8clgHQ6D3O50qu4fjsaSu3A5DtSAUsT/hRBC5Qg/KknXP3661G -3xL4DeuzXr327r4E4mP2pAXFbIi82yyNSenyjetP23Kt2mZimjvAR8hOiDKib1ug -s5PC8m9ldlHoR/o5kxdW4dmCjQKBgQDjmmTtJPdYcABN9iwrCIdfDM3j6TFYWyXC -tn5gco0mLFq8eKJICUI+UTCvVLow8KgYkCvsw8ZeX42BgWOBD4V3ENM7N2KtjtEf -3kA3H4cEKuSZjcfAIZ7Yp1KwBblWuaVGFcXp9FDeT2EzMXOE2zhR9wbeMqOvjPwk -5oqqugiAeQKBgFq9J83rui7GM5RBnOSe4CfuwPxrMkFutpopQTNpzPsmrsMfVZip -li9c12keX8REn378XPM1E4odFf/2OjQcZEa5QitGWhQn2vgS8j3ap9N8xfZ+ReXy -H1P/Cr7RzNL62GbhAO9L9e9uxh6Rn83nezh69gc738CgmADfxGYjBl/RAoGASJ5E -QV2gBXmGv1kh8oEAIBWHw4XtlpFOVPfBDqi93EYelS+wJ2e82QEylV5lIaRHHb8y -JJK6QfYewgk0ZEM9hCW8H5KmS1Xb510UBAJtI6lD0rJn3yda9Sk9uqe44LDOyLO9 -t82Z17RgAONwRh1jtNMqP87MZwCGmodsCtjcSZECgYBtpijHq7XDok0FhJydM6f2 -OMFs0UqV4m4l2QAIU8ZEOXCDVZFq77hP51DKy6fmRObipjikeVPB3Y/mWwTTTpfY -BCf6pWDlDLIFn7obSxq2RDbhnGo21AZYlDJ/DbR01AM6ZFFwg/NglgAZsECbMf8a -2FWenA+X+r+oxF355Ytr/g== +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCbRpLYl7nloMyC +awpf5oAtabX1HmD2eIk7/VNtaF66EKrGnU/NbZq8G63oZXZMq2Bb9me+3F1bBdA8 +MnnAfVnO/sR4w3Qo4J6bwnG+iEswUSnvF0KxvsgXs4GEPfdSbndr4isUStaYQt9z ++cj4cuUgE0K3blA4kUcvxs/A+MbrR+OMOK6uLDduTUrahJnMLFKnQV20irSyHpq0 +ymeZrWUh4IxifhMzOjtxO2dU8dv5w1XnibT4DZb+dUZnDxH/gTyOilxqzfyavY21 +oGmaciWIye1cBzWNKLVPEkoNBkDTAm5aXtUPTQJWoWG6ZtAlSKZrQz5lNz8Gkfqi +0bFUZR5hAgMBAAECggEADskw9pBhfVegjH1mPCzri7zYkizVuDf7fsuSrtpqGsxi +LA49fnxaEwuNCzzjf6LaHCe3SATH8aujYU1qgUVD0Lg7O/IGFQEUBBUHVnNiut51 +CyAV6RhtCVoTPTqBW0d1oRT6W9unL6c+jAFUfS7DrsLmxCeBsBagHBE8e021SMt7 +kRS6RK6EHTsEJ7E1XaEuFOi3S9nvQKxTSBzQeVxwB+wnENExLOph88552VZEOUqh +W8s+U/kCmlSqLILg3cgCuEBnwYiuDUwBWJxChQ8GD3XwdQAOO7hKa/jrCybr8Ir1 +NFUpceTdCdflz9+S6KKWrIXHDhmi/g3EP3lJ/UE1OQKBgQDZnA9uzNctyvuvCrNd +15qnXn0fzOU07lYiYNcJ+RfL8WKabYobDyiHwMuucU4iHVffDJicgsAhIMYFWslp ++LmmsHuLJlqDI04/9tS/ZLWKUEHCTi2XC4WqqXP3Od6l24yPSNkTyUwx7jYza/PS +ZPruZDmwhqDAETp5ZuqO6BbKowKBgQC2q1C9Ge/KuMR+TVdUj6Jj51Jwv3oppl/e +H+6HTDUPLdvs4ped+MTR34LhLgUg5a7SZbSnDYvDA1FEcgsvgZ2yIkxnWl2rDGvw +4BD4x6eHusK/+jiL5FcCfJHPt88CY7hBDmrMqVERcEigteATX96bYFz0PHiIbuzP +UJ+5jOjnKwKBgBr6cxtcf+zodm2MGRKwUTcgyshvgZcfWURn1yEgZafeJEha/j0+ +ktrJtzbIS1SFaMh5ak41E5bH1mUBjWj68iFNTfPBbIVHkkLx2gxkcvFT4+MwCAzq +28Z9vafP39+WKYX2FRuT4ENscgHMB211IXr+p/xPpIxLVoGIldnjwjebAoGAclQC +8ngbRuwhv1M0x24mmxSa2opdMVg6RFID/pZJ1zhCn56qemrK9PhJeBpPh2l546FY +Uf3+bY3T/VzLd25OfsFMxJsgaQAbRuVWef6r8h2H6pP3dEbz1lCVCkbmv34eQkl9 +up52aM24By4OEtI8B09mnk6CuhGDEbZKYd25n4UCgYEArCiTHWEv5Gw5wypbDOI2 +Nd/bQg4IYKMGH1gamw7NuvBwxNiS3efmq7NoVp7ykyA4SUKnclSjnh3THk8wW6Dr +5hMiU8Z5ChRtIK0Z7bXyUV+4KVsqv0V/MGeCGCkYaWb36xJy0FxaQeUiWwHIULBC +zxJwbMgoj1x491v1s7H8ZuY= -----END PRIVATE KEY----- diff --git a/scripts/generate-test-tls.sh b/scripts/generate-test-tls.sh new file mode 100644 index 0000000000..ee88a2c2a8 --- /dev/null +++ b/scripts/generate-test-tls.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh +set -eu + +output_dir="$(CDPATH= cd -- "$(dirname -- "$0")/../db_config/test" && pwd)" +key_path="$output_dir/server.key" +certificate_path="$output_dir/server.crt" + +if ! command -v openssl >/dev/null 2>&1; then + printf '%s\n' 'OpenSSL is required to generate the local PostgreSQL test certificate.' >&2 + exit 1 +fi + +rm -f "$key_path" "$certificate_path" +openssl req \ + -x509 \ + -nodes \ + -newkey rsa:2048 \ + -sha256 \ + -days "${TLS_VALIDITY_DAYS:-365}" \ + -keyout "$key_path" \ + -out "$certificate_path" \ + -subj '/CN=localhost' \ + -addext 'subjectAltName=DNS:localhost' + +chmod 0600 "$key_path" +printf 'Generated local PostgreSQL TLS assets under %s\n' "$output_dir" diff --git a/test/global-setup.ts b/test/global-setup.ts index 39b1962d4d..725a1c6e25 100644 --- a/test/global-setup.ts +++ b/test/global-setup.ts @@ -1,4 +1,22 @@ -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -export default () => { - process.env.TZ = 'UTC'; +import { execFileSync } from "node:child_process"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; + +export default (): void => { + process.env.TZ = "UTC"; + + const certificatePath = join(__dirname, "../db_config/test/server.crt"); + const keyPath = join(__dirname, "../db_config/test/server.key"); + if (existsSync(certificatePath) && existsSync(keyPath)) { + return; + } + + execFileSync( + process.platform === "win32" ? "sh.exe" : "sh", + ["scripts/generate-test-tls.sh"], + { + cwd: join(__dirname, ".."), + stdio: "inherit", + }, + ); };