Skip to content

[TASK-DRAGONFLYDB-MIGRATION] Migrasi In-Memory Database DragonflyDB, Penanganan Vulnerability Redis, dan Hardening Cache ​

Modul: Pengangkut | Tipe: Refactoring | Stage Saat Ini: STAGING | Tanggal Dokumen: 2026-09-03


1. Informasi Tugas & Referensi Bisnis ​

  • Task ID / Nomor Referensi: TASK-DRAGONFLYDB-MIGRATION

  • Sumber Instruksi: Nota Dinas Nomor ND-214/LNSW.34/2026 (Tindak Lanjut ND-18/LNSW.341/2026 perihal Penyampaian Hasil Validasi Kerentanan (Vulnerability) Redis dan Rekomendasi Tindak Lanjut)

  • Dokumen Referensi / Lampiran: Permintaan Informasi PIC Server Redis dalam Rangka Penanganan Celah Keamanan.pdf

  • Task / Dependensi Terkait (Cross-Service): Tidak ada

  • Modul Terkait: Pengangkut

  • Service / Repository: pengangkut-backend

  • PIC Pengembang: Muhamad Firly Ramadan

  • Latar Belakang & Ringkasan Kebutuhan: Menindaklanjuti Nota Dinas Nomor ND-214/LNSW.34/2026 juncto ND-18/LNSW.341/2026 mengenai temuan celah keamanan (vulnerability) pada perangkat lunak Redis (versi v6.0.16, v7.4.1, dan v8.2.2) di lingkungan Sistem INSW, Tim DevOps/Infrastruktur melakukan migrasi infrastruktur in-memory database ke cluster DragonflyDB yang baru. Sebagai tindak lanjut integrasi di sisi aplikasi, Tim Pengembang backend pengangkut melakukan migrasi konfigurasi dan integrasi konektivitas ke nodes DragonflyDB baru, meliputi: standarisasi parser cluster nodes dinamis, penegakan autentikasi wajib (REDIS_USERNAME & REDIS_PASSWORD), pengamanan isolasi namespace keyPrefix lintas environment, mitigasi ReDoS pada sanitasi trailing colon, penonaktifan perintah destruktif (FLUSHALL, FLUSHDB, KEYS), serta pembersihan dead-code koneksi DB prod dan 47 environment variables usang.

  • Ruang Lingkup & Rincian Sub-Pekerjaan (Technical Scope & Milestones):

    • [x] Integrasi dan refactor client database backend ke cluster nodes DragonflyDB baru (app/config/database/redis.js)
    • [x] Penguatan autentikasi dan isolasi namespace keyPrefix (REDIS_KEY_PREFIX:WHERE_AM_I:)
    • [x] Implementasi fail-fast assertion (requireEnv) dan mitigasi ReDoS pada stripTrailingColons
    • [x] Penguncian metode berbahaya FLUSHALL, FLUSHDB, dan KEYS di level application client
    • [x] Pembersihan dead-code koneksi database produksi legacy (app/db_conn_prod.js & app/connection_prod.js)
    • [x] Pembersihan 47 environment variable usang dari .env.example dan env-validator.js
    • [x] Pengujian empiris unit test Vitest untuk konfigurasi database & validator environment

2. Deployment Lifecycle ​

#EnvironmentTanggal & WaktuPICStatusCatatan
1Development2026-09-02 13:40Muhamad Firly RamadanDEPLOYEDBranch: development (Merged from feat/dragonflydb-migration)
2Staging (UAT)2026-09-09 11:34achmad fauziDEPLOYEDRelease Candidate v1.18.2 via MR !2080. Co-deployed: [TASK-DRAGONFLYDB-MIGRATION, TASK-SPLIT-BILLING-202608, FEAT-MANUAL-BILLING-REQUEST, MAINT-SUPERSET-SUMMARY-SHIP-SYNC-SECURITY, REFACTOR-DEPRECATE-POST-STATUS-SERVICE-MIGRATION, TASK-PINO-LOGGER-REFACTOR, ND-304-LNSW.34-2026, ND-256-LNSW.34-2026, ND-183-LNSW.34-2026]
3Production——PENDING—

Riwayat Update Log ​

TanggalEnvironmentPerubahanPIC
2026-09-09StagingPromosi ke STAGING via MR !2080 (Release Candidate v1.18.2)Hermansyah Efendi
2026-09-03DevelopmentInitial log created from backend context block & ND-214/LNSW.34/2026Muhamad Firly Ramadan

3. Analisis Teknis & Rincian Perubahan ​

  • Alur Logika & Bisnis: 0. Refactor Standalone Client (Patch v1.18.2 - MR !2080): Mengubah instansiasi dari Redis.Cluster ke standalone new Redis({ host, port }) untuk kompatibilitas deployment single-instance DragonflyDB di Staging, serta membatasi retryStrategy maksimal 3 kali (times > 3 ? null : delay) untuk mencegah infinite reconnect loop.

    1. Dynamic Cluster Resolver: Helper resolveHost() memecah string REDIS_NODES multi-node dan menyetel fallback default port 6379 secara aman.
    2. Fail-Fast Startup Assertion: Helper requireEnv() memvalidasi keberadaan REDIS_NODES, REDIS_KEY_PREFIX, dan WHERE_AM_I saat aplikasi boot.
    3. ReDoS Defense: Implementasi fungsi stripTrailingColons() menggantikan regex berulang guna mencegah potensi serangan Denial of Service pada regex parser.
    4. Shared Cache Security Guard: Memblokir eksekusi flushall(), flushdb(), dan keys() di level application instance untuk mencegah data wipe pada shared cluster.
    5. Pembersihan Envar & Dead Code: Menghapus 47 envar yang sudah tidak digunakan serta membuang modul app/db_conn_prod.js & app/connection_prod.js.
    6. Daftar File yang Berubah:
      • app/config/database/redis.js (Config / Cache / Security Defense)
      • app/utils/env-validator.js (Validation / Environment Schema Cleanup)
      • .env.example (Config / Environment Example Cleanup)
      • app/db_conn_prod.js [DELETED] (Database / Legacy Dead Code)
      • app/connection_prod.js [DELETED] (Database / Legacy Dead Code)
      • tests/config/redis.test.js (Unit Test Suite)
      • tests/utils/env-validator.test.js (Unit Test Suite)
  • Perubahan Database (DDL / DML):

    sql
    -- Tidak ada migration file terdeteksi — task ini merupakan integrasi caching layer baru, security hardening, dan pembersihan environment/dead code.
  • Kontrak API & Response Payload:(Tidak ada penambahan atau perubahan kontrak API.)

  • Panduan Envar Migration (DevOps Execution Checklist):

    1. Envar Baru DragonflyDB / Redis (Wajib Diisi): ​

    • REDIS_NODES (Wajib): Format daftar node host:port (contoh: 10.240.10.1:6379,10.240.10.2:6379 atau dragonfly-cluster.internal:6379).
    • REDIS_KEY_PREFIX (Wajib): Prefix namespace modul (contoh: pengangkut_backend).
    • WHERE_AM_I (Wajib): Nama environment (development / staging / prod).
    • REDIS_USERNAME (Wajib): Username autentikasi Redis/Dragonfly.
    • REDIS_PASSWORD (Wajib): Password autentikasi Redis/Dragonfly.

    2. Daftar Lengkap Envar yang Dihapus (Boleh Dibersihkan dari ConfigMap/Secret): ​

    • Redis Legacy: REDIS_CLUSTER_NODES, REDIS_CLUSTER_USERNAME, REDIS_CLUSTER_PASSWORD, REDIS_CLIENT_ID
    • Database Prod Legacy: DATABASE_PG_PASSWORD_PROD, DATABASE_PG_PORT_PROD, DATABASE_PG_PROD, DATABASE_PG_URL_PROD, DATABASE_PG_USERNAME_PROD
    • Kafka & Mail Service: KAFKA_BROKER, KAFKA_GROUPID, KAFKA_MECHANISM, KAFKA_PASSWORD, KAFKA_TOPIC, KAFKA_USER, MAIL_FROM, MAIL_PASS, MAIL_SERVICE, MAIL_USER
    • Integrasi & API Service Usang: API_BC_CEISA40_PPBT, APP_KEY, BASE_URL_BC, HEADERS_HOST, PROVISION_KEY, REPO_UPLOAD_PEMBATALAN_DEV, SERVICE_LNSW_DJP, SINKARKES_API_BILLING, SINKARKES_FEEDBACK_API, STATUS_APP, TOKEN_API_INAPORT, TOKEN_API_SINKARKES
    • Testing, Timeout & Auth Usang: PASSWORD_TOKEN, PASS_TESTER, PKKA_AUTH, TEST, USERNAME_TOKEN, USER_TESTER

4. Bukti Teknis (Technical Proof & Audit Trail) ​

Daftar Commit Terkait (Multi-Commit Trail) ​

Commit IDBranchAuthorTanggal & JamRingkasan Perubahan
59e86fdbfeat/dragonflydb-migrationMuhamad Firly Ramadan2026-08-28 16:07feat(cache): make redis connection optional and add safe env parsing
7d1036d2feat/dragonflydb-migrationMuhamad Firly Ramadan2026-08-28 16:15fix(redis): replace environment key prefix
450619cefeat/dragonflydb-migrationMuhamad Firly Ramadan2026-09-02 09:51fix(env-validator): remove NODE_ENV from env-validatorc
826747fcdevelopmentHermansyah Efendi2026-09-02 09:59Merge branch 'feat/dragonflydb-migration' into development
4e701176developmentMuhamad Firly Ramadan2026-09-02 10:54fix(redis): replace ReDoS-prone trailing-colon regex with endsWith loop
49591a01developmentHermansyah Efendi2026-09-02 11:32chore(env): remove unused variables from env example and validator
e0a4199bdevelopmentMuhamad Firly Ramadan2026-09-02 13:40chore: remove dead prod db connection files
9cc8c2b4developmentHermansyah Efendi2026-09-08 17:15refactor(redis): switch to standalone client and fix retry loop
3b6d915dstagingachmad fauzi2026-09-09 11:34Merge branch 'development' into 'staging' (Release Candidate v1.18.2, MR !2080)

Cuplikan Kode / Implementasi Inti ​

javascript
// app/config/database/redis.js
const resolveHost = (raw) => {
  if (!raw || typeof raw !== "string" || !raw.trim()) {
    return [];
  }
  return raw
    .split(',')
    .map((entry) => entry.trim())
    .filter(Boolean)
    .map((entry) => {
      const [host, port] = entry.split(':');
      return { host, port: port ? Number(port) : 6379 };
    });
};

const requireEnv = (name) => {
  const value = process.env[name];
  if (!value) {
    throw new Error(`[redis] Missing required env var: ${name}`);
  }
  return value;
};

const stripTrailingColons = (value) => {
  let result = value;
  while (result.endsWith(':')) {
    result = result.slice(0, -1);
  }
  return result;
};

const clusterNodes = resolveHost(requireEnv('REDIS_NODES'));
const keyPrefix = `${stripTrailingColons(requireEnv('REDIS_KEY_PREFIX'))}:${requireEnv('WHERE_AM_I')}:`;

const redis = new Redis.Cluster(clusterNodes, {
  redisOptions: {
    username: process.env.REDIS_USERNAME || undefined,
    password: process.env.REDIS_PASSWORD || undefined,
    enableReadyCheck: false,
    keyPrefix,
  },
  clusterRetryStrategy: (times) => {
    retryCount++;
    if (retryCount > MAX_RETRY) {
      logger.error(`Redis Cluster: Retry limit reached (${MAX_RETRY}x).`);
      return null;
    }
    const delay = Math.min(times * 100, 2000);
    logger.warn(`Redis Cluster: Retry #${retryCount}, retrying in ${delay}ms...`);
    return delay;
  },
});

5. Bukti Verifikasi Pengujian (QA / Unit Test / API Verification) ​

A. Verifikasi Unit Test (Development Stage) ​

  • Test Suite File: tests/config/redis.test.js, tests/utils/env-validator.test.js
  • Status Eksekusi CLI: PASSED
javascript
// tests/config/redis.test.js
describe('redis config', () => {
  it('initializes redis cluster instance', () => {
    expect(redis).toBeDefined();
    expect(redis.on).toHaveBeenCalledWith('connect', expect.any(Function));
    expect(redis.on).toHaveBeenCalledWith('error', expect.any(Function));
  });

  describe('security defenses', () => {
    it('throws forbidden error when flushall is called', () => {
      expect(() => redis.flushall()).toThrow('CRITICAL SECURITY: FLUSHALL is forbidden');
    });

    it('throws forbidden error when flushdb is called', () => {
      expect(() => redis.flushdb()).toThrow('CRITICAL SECURITY: FLUSHDB is forbidden');
    });

    it('throws forbidden error when keys is called', () => {
      expect(() => redis.keys()).toThrow('CRITICAL SECURITY: KEYS is forbidden');
    });
  });
});
text
 RUN  v4.1.10 D:/WORK/LNSW/pengangkut-backend
 ✓ tests/config/redis.test.js (6 tests) 11ms
 ✓ tests/utils/env-validator.test.js (2 tests) 6ms

 Test Files  2 passed (2)
      Tests  8 passed (8)
   Start at  09:51:04
   Duration  417ms (transform 109ms, setup 0ms, import 355ms, tests 17ms, environment 0ms)

B. Panduan Pengujian QA & Verifikasi Staging (QA Playbook) ​

Diisi saat development sebagai panduan eksekusi pengujian QA, kemudian dilengkapi bukti response JSON saat verifikasi di Staging.

  • Cakupan / Surface Pengujian: Worker / DB / Cron Only & API / Postman Only
  • Kebutuhan Akses / Role Akun: Akses container backend dengan koneksi DragonflyDB/Redis terpasang
  • Hasil Pengujian UAT: PENDING
  • Catatan QA: —
Skenario Pengujian QA (Test Scenarios) ​
  1. Skenario 1 — Inisialisasi Koneksi DragonflyDB / Redis (Happy Path):

    • Pre-kondisi: Envar REDIS_NODES, REDIS_KEY_PREFIX, WHERE_AM_I, REDIS_USERNAME, dan REDIS_PASSWORD terdefinisi dengan benar pada container runtime.
    • Trigger / Request: Jalankan backend service (npm start / container startup).
    • Ekspektasi Response: Backend berjalan normal tanpa crash, log mencatat: Connected to Redis Cluster.
    • Verifikasi Database / Log: Cek cluster DragonflyDB dengan CLI, key yang dibuat tersimpan dengan format prefix pengangkut_backend:{WHERE_AM_I}:*.
  2. Skenario 2 — Proteksi Missing Envar Fail-Fast (Negative Test):

    • Pre-kondisi: Envar REDIS_NODES atau REDIS_KEY_PREFIX tidak didefinisikan.
    • Trigger / Request: Jalankan backend service.
    • Ekspektasi Response: Backend gagal inisialisasi dengan pesan error eksplisit [redis] Missing required env var: REDIS_NODES.
    • Verifikasi Database / Log: Server berhenti seketika untuk mencegah status caching corrupt.
Bukti Response Verifikasi Staging (Diisi saat UAT) ​
json
{
  "status": "PENDING",
  "note": "Menunggu deployment ke environment Staging untuk eksekusi skenario uji QA."
}

Single Source of Truth (SSOT) Arsitektur & Perubahan Teknis Backend