Skip to main content

Keamanan inventory_service

Dokumen ini merangkum keunggulan keamanan yang telah diimplementasikan pada inventory_service (port 8084). Semua item di bawah telah diimplementasikan dan diverifikasi per audit keamanan 2026-05-29–2026-06-05.


Keamanan & Hardening

Semua item di bawah telah diimplementasikan dan diverifikasi per audit keamanan 2026-05-29–2026-06-05.

Auth & Authorization

  • Internal-only endpoint dengan constant-time API key compare: Seluruh endpoint inventory_service dilindungi header X-Internal-API-Key yang diverifikasi menggunakan constant-time comparison — mencegah timing attack yang dapat digunakan untuk menebak nilai key secara inkremental.

Input Validation

  • Validasi format UUID pada semua mutation handler: Helper isValidUUID dan validateUUIDs ditambahkan di handlers.go menggunakan stdlib regexp. Setiap UUID dalam request body divalidasi sebelum menyentuh store layer — nilai non-UUID (termasuk string dengan karakter SQL khusus) ditolak dengan HTTP 400 sebelum sampai ke pqUUIDArray. Ini mencegah kemungkinan SQL injection via string interpolation pada array literal PostgreSQL.

  • Validasi allowlist untuk kondisi return unit: Nilai condition pada endpoint return divalidasi di handler layer — hanya "stock" dan "returned" yang diterima, request dengan nilai lain dikembalikan langsung sebagai 400 Bad Request. Validasi dilakukan di layer HTTP sebelum memanggil store, bukan diserahkan ke logika default di store layer.

Batch & Resource Limits

  • Batch limit pada semua mutation bulk: Endpoint assign-shipment membatasi maksimum 100 unit per request, sementara deliver dan return membatasi 200 unit per request. Guard ini mencegah request tunggal menghabiskan koneksi DB atau menyebabkan latensi berlebih pada service.

  • Limit pada endpoint read berbasis batch: Endpoint available membatasi default 50 dan maksimum 200 unit per request. Endpoint count-by-products dan merchant-device-counts membatasi 200 product/merchant ID per request.

Database & Query Safety

  • Bulk UPDATE via parameterized ANY($1::uuid[]): Semua operasi mutasi massal (AssignToShipment, MarkDelivered, ReturnUnits) menggunakan single bulk UPDATE ... WHERE id = ANY($1::uuid[]) — menggantikan pendekatan N+1 loop. Query sepenuhnya parameterized; tidak ada string interpolation yang masuk ke SQL.

  • DB constraint sebagai lapisan pertahanan kedua: Schema database menegakkan constraint merchant_consistency_chk yang memastikan merchant_id selalu NULL saat unit berstatus stock/returned, dan tidak NULL pada status lainnya. Ini mencegah data inconsistency bahkan jika ada bug di application layer.

  • Soft delete — data tidak dihapus permanen: Operasi delete menggunakan deleted_at timestamp, bukan DELETE SQL. Data audit trail tetap tersedia untuk investigasi.

Response Integrity

  • Count response berbasis actual rows affected: Handler deliver dan return mengembalikan jumlah unit yang benar-benar terupdate di DB (RowsAffected()), bukan sekadar panjang input array. Caller mendapat gambaran akurat tentang apa yang benar-benar terjadi di DB.

  • skipped_ids transparan di response AssignToShipment: Response menyertakan assigned_ids, assigned_count, skipped_ids, dan skipped_count — caller dapat mengetahui unit mana yang gagal di-assign (misalnya karena sudah dalam status lain) tanpa ambiguitas.

Observability & Operational Safety

  • Graceful shutdown dengan timeout 30 detik: Service menunggu in-flight request selesai sebelum berhenti — mencegah state inconsistency saat deploy ulang.

  • /ready endpoint dengan DB ping aktif: Readiness probe melakukan koneksi aktual ke DB, bukan sekadar return 200 — load balancer dan orchestrator mendapat sinyal akurat tentang kesiapan service.

  • Request logging lengkap di setiap endpoint: loggingMiddleware mencatat method, path, HTTP status code, dan durasi pada setiap request — memudahkan investigasi insiden dan deteksi anomali.

  • DB connection pool terkonfigurasi: Pool dikonfigurasi dengan MaxOpen=25, MaxIdle=5, ConnMaxLifetime=5m — mencegah connection exhaustion dan memastikan koneksi tidak dibiarkan idle terlalu lama.

Domain Isolation

  • Database terpisah untuk inventory lifecycle: inventory_service menggunakan database db_kesles_merchant_inventory yang terisolasi dari database lain. Semua data lifecycle unit (tabel inventory.product_inventory_items) hanya dapat diakses melalui service ini — tidak ada akses langsung dari service lain ke tabel inventory lifecycle.