[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-MIGRATIONSumber 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:
PengangkutService / Repository:
pengangkut-backendPIC 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 namespacekeyPrefixlintas 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 padastripTrailingColons - [x] Penguncian metode berbahaya
FLUSHALL,FLUSHDB, danKEYSdi 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.exampledanenv-validator.js - [x] Pengujian empiris unit test Vitest untuk konfigurasi database & validator environment
- [x] Integrasi dan refactor client database backend ke cluster nodes DragonflyDB baru (
2. Deployment Lifecycle
| # | Environment | Tanggal & Waktu | PIC | Status | Catatan |
|---|---|---|---|---|---|
| 1 | Development | 2026-09-02 13:40 | Muhamad Firly Ramadan | DEPLOYED | Branch: development (Merged from feat/dragonflydb-migration) |
| 2 | Staging (UAT) | 2026-09-09 11:34 | achmad fauzi | DEPLOYED | Release 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] |
| 3 | Production | — | — | PENDING | — |
Riwayat Update Log
| Tanggal | Environment | Perubahan | PIC |
|---|---|---|---|
| 2026-09-09 | Staging | Promosi ke STAGING via MR !2080 (Release Candidate v1.18.2) | Hermansyah Efendi |
| 2026-09-03 | Development | Initial log created from backend context block & ND-214/LNSW.34/2026 | Muhamad Firly Ramadan |
3. Analisis Teknis & Rincian Perubahan
Alur Logika & Bisnis: 0. Refactor Standalone Client (Patch v1.18.2 - MR !2080): Mengubah instansiasi dari
Redis.Clusterke standalonenew Redis({ host, port })untuk kompatibilitas deployment single-instance DragonflyDB di Staging, serta membatasiretryStrategymaksimal 3 kali (times > 3 ? null : delay) untuk mencegah infinite reconnect loop.- Dynamic Cluster Resolver: Helper
resolveHost()memecah stringREDIS_NODESmulti-node dan menyetel fallback default port 6379 secara aman. - Fail-Fast Startup Assertion: Helper
requireEnv()memvalidasi keberadaanREDIS_NODES,REDIS_KEY_PREFIX, danWHERE_AM_Isaat aplikasi boot. - ReDoS Defense: Implementasi fungsi
stripTrailingColons()menggantikan regex berulang guna mencegah potensi serangan Denial of Service pada regex parser. - Shared Cache Security Guard: Memblokir eksekusi
flushall(),flushdb(), dankeys()di level application instance untuk mencegah data wipe pada shared cluster. - Pembersihan Envar & Dead Code: Menghapus 47 envar yang sudah tidak digunakan serta membuang modul
app/db_conn_prod.js&app/connection_prod.js. - 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)
- Dynamic Cluster Resolver: Helper
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 nodehost:port(contoh:10.240.10.1:6379,10.240.10.2:6379ataudragonfly-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)
- Repository:
pengangkut-backend - Branch Utama:
development - Merge Request / PR: MR !2080 (Release Candidate v1.18.2)
Daftar Commit Terkait (Multi-Commit Trail)
| Commit ID | Branch | Author | Tanggal & Jam | Ringkasan Perubahan |
|---|---|---|---|---|
59e86fdb | feat/dragonflydb-migration | Muhamad Firly Ramadan | 2026-08-28 16:07 | feat(cache): make redis connection optional and add safe env parsing |
7d1036d2 | feat/dragonflydb-migration | Muhamad Firly Ramadan | 2026-08-28 16:15 | fix(redis): replace environment key prefix |
450619ce | feat/dragonflydb-migration | Muhamad Firly Ramadan | 2026-09-02 09:51 | fix(env-validator): remove NODE_ENV from env-validatorc |
826747fc | development | Hermansyah Efendi | 2026-09-02 09:59 | Merge branch 'feat/dragonflydb-migration' into development |
4e701176 | development | Muhamad Firly Ramadan | 2026-09-02 10:54 | fix(redis): replace ReDoS-prone trailing-colon regex with endsWith loop |
49591a01 | development | Hermansyah Efendi | 2026-09-02 11:32 | chore(env): remove unused variables from env example and validator |
e0a4199b | development | Muhamad Firly Ramadan | 2026-09-02 13:40 | chore: remove dead prod db connection files |
9cc8c2b4 | development | Hermansyah Efendi | 2026-09-08 17:15 | refactor(redis): switch to standalone client and fix retry loop |
3b6d915d | staging | achmad fauzi | 2026-09-09 11:34 | Merge branch 'development' into 'staging' (Release Candidate v1.18.2, MR !2080) |
Cuplikan Kode / Implementasi Inti
// 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
// 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');
});
});
}); 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)
Skenario 1 — Inisialisasi Koneksi DragonflyDB / Redis (Happy Path):
- Pre-kondisi: Envar
REDIS_NODES,REDIS_KEY_PREFIX,WHERE_AM_I,REDIS_USERNAME, danREDIS_PASSWORDterdefinisi 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}:*.
- Pre-kondisi: Envar
Skenario 2 — Proteksi Missing Envar Fail-Fast (Negative Test):
- Pre-kondisi: Envar
REDIS_NODESatauREDIS_KEY_PREFIXtidak 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.
- Pre-kondisi: Envar
Bukti Response Verifikasi Staging (Diisi saat UAT)
{
"status": "PENDING",
"note": "Menunggu deployment ke environment Staging untuk eksekusi skenario uji QA."
}