Metadata-Version: 2.4
Name: sluice-cli
Version: 0.1.0
Summary: Kelola banyak tunnel, banyak port, banyak server dari satu config — dengan bukti bahwa tunnel-nya benar-benar bekerja.
Author: Samudra
License-Expression: MIT
Project-URL: Homepage, https://github.com/Rizkisam/sluice
Project-URL: BugTracker, https://github.com/Rizkisam/sluice/issues
Keywords: tunnel,ngrok,bore,cloudflared,zrok,nat,port-forwarding,devtools
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet
Classifier: Topic :: System :: Networking
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Dynamic: license-file

# Sluice

Satu tempat untuk **banyak tunnel, banyak port, banyak server** — pengganti ngrok yang
tidak membatasi jumlah tunnel.

ngrok gratis membatasi jumlah tunnel, dan alternatif open source masing-masing punya
sintaks sendiri. Sluice tidak menciptakan protokol baru: ia menyatukan cara
mengelolanya (satu config, perintah seragam) dan menambahkan hal yang paling sering
hilang, yaitu **bukti bahwa tunnel-nya benar-benar bekerja**.

## Kenapa ada health check

Ini bukan fitur hiasan. Di mesin pengembangan tempat project ini dibangun, `cloudflared`
**mencetak URL publik dan tetap berjalan**, sementara permintaan ke URL itu gagal
(`HTTP 000`). Prosesnya "hidup". Tunnelnya tidak.

Kalau `status` hanya melaporkan pid, kamu akan mengira semuanya beres. Karena itu
status dipisah dua:

```
nama       provider     port    pid    proses  binary  sehat  keterangan
api        bore         8123    78838  hidup   ada     ya     HTTP 200
```

`proses` = masih berjalan. `sehat` = benar-benar menjawab (butuh `--probe`).

## Pasang

Tidak ada dependensi Python selain 3.11+ itu sendiri (memakai `tomllib`). Yang perlu
langkah tambahan hanya **binary provider**-nya — lihat di bawah.

**Penting soal nama.** Nama paket di PyPI adalah **`sluice-cli`**, sedangkan perintah
yang dihasilkan bernama **`sluice`**. Keduanya sengaja berbeda: `sluice` di PyPI sudah
dipakai paket lain (alat pengelola snapshot ZFS, milik orang lain sejak lama), jadi
`pip install sluice` akan memasang **program yang salah** — dan galatnya tidak muncul,
karena paket itu memang ada.

```sh
pip install sluice-cli    # benar — perintah yang didapat: sluice
pip install sluice        # SALAH — itu paket orang lain
```

**Lalu ambil binary provider-nya.** `bore` adalah program Rust, bukan paket Python, jadi
pip tidak mungkin membawanya — tanpa langkah ini `up` akan menolak jalan:

```sh
sluice install bore
```

Selesai, tidak perlu mengubah config. Binary ditaruh di `~/.sluice/bin/` dan Sluice
memakainya otomatis (folder itu diperiksa lebih dulu daripada PATH). Kalau kamu sudah
punya `bore` sendiri — mis. `brew install bore-cli` — langkah ini boleh dilewati.

Yang diunduh adalah aset rilis resmi dari `github.com/ekzhang/bore` (lisensi MIT),
versi 0.6.0. **Rilis itu tidak menerbitkan checksum**, jadi isinya tidak bisa dicocokkan
dengan nilai dari pihak ketiga. Yang Sluice lakukan: HTTPS dengan verifikasi sertifikat
**aktif**, lalu mengekstrak **hanya** berkas bernama `bore` (bukan `extractall`), jadi
isinya tidak bisa menulis berkas lain ke disk. Kalau kamu butuh jaminan yang lebih kuat,
pasang lewat paket manager sistem — Sluice tetap memakainya.

> Diverifikasi di macOS. **Linux dan Windows: tabel targetnya ada, tetapi belum diuji** —
> nama asetnya berasal dari daftar aset rilis, bukan dari pengalaman menjalankannya.

**Sebagai package (disarankan kalau dipakai permanen):**

```sh
pip install -e .     # dari folder project
```

Setelah itu perintah `sluice` tersedia dari folder mana saja:

```sh
cd ~/di-mana-saja && sluice status --probe
```

Kalau punya `pipx`, itu lebih rapi lagi karena package-nya terisolasi dan tidak
mengotori Python sistem:

```sh
pipx install .                # dari folder project
pipx install sluice-cli       # atau dari PyPI
```

Untuk membuat distribusi (`.whl` / `.tar.gz`) yang bisa dibagikan:

```sh
pip install '.[dev]'
python3 -m build
```

**Langsung dari folder project (tanpa memasang apa pun):**

```sh
python3 -m sluice --help
```

### Di mana config dicari

Urutannya, dan yang pertama ditemukan yang dipakai:

1. `--config /path/ke/file.toml` — kalau kamu menyebutnya eksplisit
2. `./sluice.toml` — config per-project (menang atas yang pengguna)
3. `~/.sluice/sluice.toml` — config pengguna, berlaku dari folder mana saja

Ini penting setelah dipasang sebagai package: perintahnya bisa dijalankan dari folder
mana pun, jadi mencari config di folder kerja saja akan menyesatkan. Kalau tidak ada
satu pun yang ditemukan, pesan galatnya menyebut semua lokasi yang sudah dicari.

## Pakai

```sh
cp sluice.toml.example sluice.toml   # lalu sunting

python3 -m sluice plan                   # lihat perintahnya, TIDAK menjalankan apa pun
python3 -m sluice up                     # jalankan semua tunnel di config
python3 -m sluice up api db              # jalankan sebagian saja
python3 -m sluice status --probe         # proses hidup + benar-benar melayani
python3 -m sluice logs api               # log satu tunnel
python3 -m sluice down                   # hentikan semua
```

Menambah port/server = menambah satu blok `[tunnels.<nama>]`. Tidak ada batas jumlah.

Bisa juga lewat CLI supaya tidak salah tulis:

```sh
python3 -m sluice add db --provider bore --local 5432 \
    --set to=relay.contoh.com --set remote_port=9000 --set secret=RATA
```

## Provider

| provider | status | catatan |
|---|---|---|
| `cloudflared` | diverifikasi flag-nya | tanpa IP publik, tanpa buka port; butuh koneksi ke edge Cloudflare |
| `bore` | diverifikasi **end-to-end di mesin ini** | `bore server` bisa kamu host sendiri |
| `zrok` | flag diverifikasi | bisa pakai layanan zrok.io atau self-host |
| `command` | — | perintah sendiri untuk frp / rathole / tailscale |

Untuk provider yang belum punya builder, pakai `command` dan tulis perintahnya sendiri.
Itu disengaja: lebih baik kamu menulis flag yang kamu tahu benar daripada Sluice
menebak flag yang belum diverifikasi.

## Yang diverifikasi, dan yang tidak

Bagian ini penting supaya kamu tidak mengira lebih dari yang sebenarnya.

**Diverifikasi end-to-end (15 Sep 2026, mesin ini):** provider `bore`, memakai server
`bore` sendiri di loopback. `up` menjalankan tunnel, `status --probe` melaporkan
`HTTP 200`, alamat publik yang dilaporkan (`127.0.0.1:20050`) benar-benar mengembalikan
layanan lokal, `up` kedua kali melaporkan *skip* (tidak membuat proses ganda), dan
`down` menghentikan prosesnya.

**Diverifikasi hanya flag-nya:** `cloudflared` dan `zrok` perintahnya sesuai dokumentasi
resmi, tetapi belum pernah menyelesaikan tunnel dari jaringan ini.

**Tidak diverifikasi:** frp, rathole, dan tailscale — ketiganya **tidak** punya builder
di sini, justru karena flag-nya belum pernah dilihat langsung dari mesin ini.

**Catatan jaringan (temuan nyata):** dari koneksi ISP yang dipakai saat membangun ini,
Cloudflare Tunnel tidak bisa menyambung edge-nya (QUIC *datagram manager error*,
`HTTP 000`), padahal DNS-nya normal (`SRV argotunnel.com` resolve dari router maupun
1.1.1.1). Jadi kegagalannya di transport, bukan DNS. Kalau kamu menemui hal serupa,
`status --probe` yang akan menunjukkannya — dan `bore` dengan relay sendiri adalah
jalan yang terbukti bekerja.

## Aturan desain yang dipegang

1. **Opsi tak dikenal ditolak, bukan diabaikan.** Opsi yang diam-diam diabaikan membuat
   tunnel jalan dengan setelan berbeda dari yang kamu kira.
2. **Rahasia disamarkan** di `plan`, `status`, dan state file. Perintah tunnel sering
   membawa `--secret`/token, dan keluarannya mudah tersalin ke chat atau log.
3. **`plan` sebelum `up`.** Perintah dan argumennya bisa dilihat lebih dulu, termasuk
   memastikan tidak ada rahasia yang bocor.
4. **Config tidak ditulis ulang.** Hanya `add` yang menambah blok baru, dan hanya
   ditambahkan di akhir — komentar serta urutan yang kamu rapikan tidak pernah hilang.
5. **Nama yang salah tidak diabaikan.** `up apii` gagal dengan pesan jelas; kalau
   diabaikan, kamu akan mengira tunnel-nya jalan padahal tidak ada yang start.

## Tes

```sh
python3 -m unittest discover -s tests -t .
```

41 tes. Yang paling penting bukan "fungsi mengembalikan nilai", melainkan perilaku yang
kalau salah membuatmu salah paham tentang tunnel-mu: penyamaran rahasia, penolakan opsi
tak dikenal, pembedaan hidup vs sehat, dan regresi nyata yang ditemukan saat pengujian —
yaitu `--to` yang tidak boleh berisi port (bore menambahkan port kontrolnya sendiri,
sehingga `host:7835` menjadi `host:7835:7835`) dan alamat yang dilaporkan harus port
publik, bukan port kontrol.

## Keamanan

Jangan expose dashboard atau database tanpa autentikasi. Tunnel memindahkan masalah
keamanan, bukan menghilangkannya: begitu sesuatu punya URL publik, ia bisa dipindai
siapa pun. Untuk akses pribadi, mesh VPN (Tailscale/WireGuard) sering lebih tepat —
tidak ada yang di-expose ke publik, dan semua port langsung bisa diakses.
