[TASK-TRUST-PROXY-IP-RESOLVER-AND-BILLING-FALLBACK] Resolusi Alamat IP Client di Balik Reverse Proxy Gateway & Normalisasi Fallback Nama Kementerian Billing
Modul: Pengangkut | Tipe: Bugfix | Stage Saat Ini:
STAGING| Tanggal Dokumen: 2026-10-12
STAGING STAGE (UAT VERIFICATION)
Dokumen ini sedang berada dalam tahap STAGING. Perubahan logika backend, penanganan konfigurasi reverse proxy, dan standardisasi fallback nama kementerian billing telah diterapkan di lingkungan Staging (UAT) untuk proses verifikasi QA.
1. Informasi Tugas & Referensi Bisnis
Task ID / Nomor Referensi:
TASK-TRUST-PROXY-IP-RESOLVER-AND-BILLING-FALLBACKSumber Instruksi: Internal Fix & Architecture Hardening / Code Maintenance
Dokumen Referensi / Lampiran: Tidak ada
Task / Dependensi Terkait (Cross-Service): Tidak ada
Modul Terkait:
PengangkutService / Repository:
pengangkut-backendPIC Pengembang: Hermansyah Efendi
Latar Belakang & Ringkasan Kebutuhan: Sistem backend pengangkut beroperasi di balik infrastruktur multi-layer reverse proxy gateway (Kubernetes Ingress, API Gateway, WAF/Load Balancer). Pencatatan alamat IP client sebelumnya belum dikonfigurasi secara dinamis pada Express trust proxy sehingga rentan mencatat IP internal gateway atau rentan terhadap spoofing header jika membaca
X-Real-IP/X-Forwarded-Formentah secara langsung. Dilakukan perbaikan dengan menyediakan parserTRUST_PROXY(mendukung jumlah hop, boolean, atau CIDR), pengamanan resolvergetClientIpberbasisreq.ipExpress, integrasi audit log, serta normalisasi fallback teks nama kementerian (Kemenhub & Kemenkes) pada query draft tagihan billing menjadi format title case.Ruang Lingkup & Rincian Sub-Pekerjaan (Technical Scope & Milestones):
- [x] Pembuatan helper
parseTrustProxydangetClientIppadaapp/utils/ip-resolver.js - [x] Pendaftaran variabel
TRUST_PROXYpada validasi schema env (app/utils/env-validator.js), bootstrap server (server.js), dan.env.example - [x] Integrasi extractor
getClientIppada HTTP request/response logger (app/middlewares/http_logger.js) dan audit log database (app/middlewares/log.js) - [x] Penambahan telemetri diagnostik
proxy_debugkondisional khusus environment non-production (devdanstaging) - [x] Normalisasi penulisan literal fallback kementerian kode 022 dan 024 pada
app/models/billing_models.js - [x] Pembuatan unit test komprehensif pada
tests/utils/ip-resolver.test.jsdan verifikasi regresitests/services/inquiry-billing.service.test.js
- [x] Pembuatan helper
2. Deployment Lifecycle
| # | Environment | Tanggal & Waktu | PIC | Status | Catatan |
|---|---|---|---|---|---|
| 1 | Development | 2026-10-12 18:34 | Hermansyah Efendi | DEPLOYED | Branch: development |
| 2 | Staging (UAT) | 2026-10-12 21:55 | achmad fauzi | DEPLOYED | Release Candidate v1.18.6 via MR !2085. Co-deployed: [TASK-TRUST-PROXY-IP-RESOLVER-AND-BILLING-FALLBACK, ND-274-LNSW.2-2026, ND-374-LNSW.2-2026, TASK-FIX-COMMENTED-BIND-PARAMS-V1.18.4, TASK-UNIFY-DB-POOL-AND-HEALTH-OBSERVABILITY, 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-10-12 | Staging | Promosi ke STAGING via MR !2085 (Release Candidate v1.18.6) | Hermansyah Efendi |
| 2026-10-12 | Development | Inisialisasi draft audit log dari context block backend (commit b73b91f9 s.d. 04b8d93c) | Hermansyah Efendi |
3. Analisis Teknis & Rincian Perubahan
Alur Logika & Bisnis:
- Dynamic Trust Proxy (
parseTrustProxy): Express memerlukan tipe dataNumberuntuk konfigurasi hop count (jika di-passingString, libraryproxy-addrmenganggapnya subnet yang tidak valid). Helper mengonversi string integer menjadiNumber, mempertahankan string format subnet/CIDR, dan menangani nilai boolean dengan fallback default1. - Anti-Spoofing IP Resolution (
getClientIp): Mengandalkanreq.ipyang dihitung oleh Express melalui algoritma traversal right-to-left terpercaya. Header buatan klien (sepertiX-Real-IPpalsu atau injeksi pada segmen kiriX-Forwarded-For) diabaikan secara aman, serta menghapus prefix IPv6-mapped IPv4::ffff:. - Audit Trail Alignment: Kolom
clientpada tabeltd_logdan log JSON Pino padahttpLoggerdiseragamkan menggunakangetClientIp(req). - Draft Billing Fallback Standardization: Mengubah literal string fallback kode KL
022dan024dari huruf kapital penuh (KEMENTERIAN PERHUBUNGAN,KEMENTERIAN KESEHATAN) menjadi title case (Kementerian Perhubungan,Kementerian Kesehatan).
- Dynamic Trust Proxy (
Perubahan Database (DDL / DML):
sql-- Tidak ada perubahan skema database (DDL/DML) untuk task ini. -- Penyesuaian murni pada layer konfigurasi Express trust proxy, middleware audit log, dan query runtime model billing.Kontrak API & Response Payload: Tidak ada penambahan endpoint baru. Format log HTTP (
httpLogger) dan field respons billing disesuaikan:GET/inquiry-billing- Deskripsi: Menampilkan rincian data tagihan pengangkut dengan fallback nama KL berformat title case.
- Autentikasi / Guard:
Bearer Token(doIntrospection,checkAccessAgentByServiceNumber) - Request Query:
serviceNumber - Response Payload (
200 OK- ArraydataDraftTagihan):json{ "status": 200, "message": "Data billing ditemukan", "data": { "dataDraftTagihan": [ { "id_tagihan_hdr": "HDR001", "id_tagihan_dtl": "DTL001", "trx_id_insw": "1010001", "uraian_kl": "Kementerian Perhubungan", "status_tagihan": "ACTIVE" } ] } }
4. Bukti Teknis (Technical Proof & Audit Trail)
- Repository:
pengangkut-backend - Branch Utama:
development - Merge Request / PR: MR !2085 (Release Candidate v1.18.6)
Daftar Commit Terkait (Multi-Commit Trail)
| Commit ID | Branch | Author | Tanggal & Jam | Ringkasan Perubahan |
|---|---|---|---|---|
04b8d93c8ea0a813f0262f7cd4ddcffa8afd9caf | development | Hermansyah Efendi | 2026-10-12 18:34 | fix(billing): normalize fallback ministry names in draft billing |
884a719908c5e31dba7f8994728e541a0787a0ce | development | Hermansyah Efendi | 2026-10-07 16:54 | feat(proxy): support dynamic hop count and cidr for express trust proxy |
813ab2c21777e8cf0a79479d1a6e1f8496949f53 | development | Hermansyah Efendi | 2026-10-07 15:47 | feat(logger): conditionally attach proxy debug telemetry in dev and staging |
45be17aec47ae000f51efc956376ddcadf7125a5 | development | Hermansyah Efendi | 2026-10-05 22:50 | refactor(logger): remove temporary proxy debug telemetry |
b73b91f9c4f1f375762a7dbc1e9af63bb8e7cfbf | development | Hermansyah Efendi | 2026-10-05 16:43 | fix(logger): resolve real client ip behind reverse proxy gateway |
Cuplikan Kode / Implementasi Inti
// app/utils/ip-resolver.js
export const parseTrustProxy = (value, defaultValue = 1) => {
if (value === undefined || value === null) return defaultValue;
if (typeof value === "number") return Number.isFinite(value) && value >= 0 ? Math.floor(value) : defaultValue;
if (typeof value === "boolean") return value;
if (typeof value === "string") {
const trimmed = value.trim();
if (!trimmed) return defaultValue;
if (trimmed.toLowerCase() === "true") return true;
if (trimmed.toLowerCase() === "false") return false;
if (/^\d+$/.test(trimmed)) return parseInt(trimmed, 10);
return trimmed;
}
return defaultValue;
};
export const getClientIp = (req) => {
if (!req) return "";
const ip = req.ip || req.socket?.remoteAddress || req.connection?.remoteAddress || "";
if (typeof ip === "string" && ip.startsWith("::ffff:")) {
return ip.slice(7);
}
return typeof ip === "string" ? ip.trim() : "";
};// app/models/billing_models.js
// Penyesuaian title case fallback nama KL pada query dataDraftTagihan:
COALESCE(
c.uraian_kl,
case
when b.kode_kl = '022' then 'Kementerian Perhubungan'
when b.kode_kl = '024' then 'Kementerian Kesehatan'
else b.kode_kl
end
) as uraian_kl,5. Bukti Verifikasi Pengujian (QA / Unit Test / API Verification)
A. Verifikasi Unit Test (Development Stage)
- Test Suite File:
tests/utils/ip-resolver.test.jstests/services/inquiry-billing.service.test.js
- Status Eksekusi CLI:
PASSED(21 tests passed)
Cuplikan Kode Unit Test
describe("parseTrustProxy helper", () => {
it("converts integer string to Number for Express hop count", () => {
expect(parseTrustProxy("5")).toBe(5);
expect(parseTrustProxy("1")).toBe(1);
expect(parseTrustProxy("0")).toBe(0);
});
it("returns trimmed CIDR and subnet lists as string", () => {
const cidr = "10.0.0.0/8, 192.168.0.0/16, loopback";
expect(parseTrustProxy(cidr)).toBe(cidr);
});
});
describe("getClientIp resolver", () => {
it("relies securely on req.ip computed by Express trust proxy", () => {
const req = {
ip: "203.0.113.195",
headers: {
"x-real-ip": "1.2.3.4",
"x-forwarded-for": "1.2.3.4, 203.0.113.195",
},
};
expect(getClientIp(req)).toBe("203.0.113.195");
});
});Output Raw CLI Runner
RUN v4.1.11 D:/WORK/LNSW/pengangkut-backend
✓ tests/utils/ip-resolver.test.js (13 tests) 8ms
✓ tests/services/inquiry-billing.service.test.js (8 tests) 15ms
Test Files 2 passed (2)
Tests 21 passed (21)
Start at 20:49:50
Duration 343ms (transform 109ms, setup 39ms, import 132ms, tests 23ms, environment 0ms)B. Panduan Pengujian QA & Verifikasi Staging (QA Playbook)
- Cakupan / Surface Pengujian:
API / Postman Only&Full E2E (UI + Backend) - Kebutuhan Akses / Role Akun: Token bearer valid untuk endpoint berproteksi atau akses endpoint public untuk validasi log HTTP.
- Hasil Pengujian UAT:
PENDING - Catatan QA: —
Skenario Pengujian QA
Skenario 1 — Resolusi IP Client dengan Multi-Hop Proxy (Happy Path):
- Pre-kondisi: Konfigurasi environment
TRUST_PROXY=2. - Trigger / Request: Kirim HTTP request dengan header
X-Forwarded-For: 203.0.113.50, 10.244.0.1(di mana10.244.0.1adalah proxy hop terakhir). - Ekspektasi Response: HTTP respon normal, pada log console / Loki tercatat field
ip: "203.0.113.50". - Verifikasi Database / Log: Kolom
clientpada tabel audittd_logmemuat nilai203.0.113.50.
- Pre-kondisi: Konfigurasi environment
Skenario 2 — Pencegahan Spoofing Header IP (Security / Edge Case):
- Pre-kondisi: Request dikirim dengan menyertakan header palsu
X-Real-IP: 8.8.8.8danX-Forwarded-For: 1.1.1.1, 203.0.113.195. - Trigger / Request: Akses endpoint API.
- Ekspektasi Response: Header
X-Real-IPpalsu diabaikan oleh resolver; sistem mencatat IP sesuai kalkulasi hop Express (203.0.113.195). - Verifikasi Database / Log: Log incoming request tidak terpengaruh injeksi header
8.8.8.8.
- Pre-kondisi: Request dikirim dengan menyertakan header palsu
Skenario 3 — Format Title Case Fallback Billing (Happy Path):
- Pre-kondisi: Terdapat tagihan aktif dengan kode KL 022 atau 024 yang memiliki
uraian_klNULL. - Trigger / Request:
GET /inquiry-billing?serviceNumber={serviceNumber}. - Ekspektasi Response: Field
uraian_klbernilai"Kementerian Perhubungan"atau"Kementerian Kesehatan". - Verifikasi Database / Log: Tampilan UI billing tidak lagi menampilkan huruf kapital penuh.
- Pre-kondisi: Terdapat tagihan aktif dengan kode KL 022 atau 024 yang memiliki