Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Each GHL location can now have its own Cast API key and sender ID stored
in MongoDB. Falls back to global CAST_API_KEY / CAST_SENDER_ID env vars
when not set per-location.
Admin endpoints (all require Authorization: Bearer <INBOUND_API_KEY>):
GET /api/admin/locations — list all locations
GET /api/admin/locations/{locationId}/config — get location config
PUT /api/admin/locations/{locationId}/config — set sender_id + cast_api_key
Cast API key is masked in GET responses (first 12 chars + "...").
Replaces the /sender-id endpoint deployed in the previous commit.
Also adds FUTURE_DEV.md documenting the migration path to Infisical
for secret management, plus MongoDB security hardening checklist.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
76 lines
3.4 KiB
Markdown
76 lines
3.4 KiB
Markdown
# Future Development Notes
|
|
|
|
This document tracks planned improvements, technical debt with business impact, and migration paths
|
|
for features currently implemented with known limitations.
|
|
|
|
---
|
|
|
|
## Upgrade: Per-location Cast API keys from MongoDB → Infisical
|
|
|
|
### Current state (Option A)
|
|
|
|
Per-location Cast API keys (`cast_api_key`) and sender IDs (`sender_id`) are stored in MongoDB
|
|
alongside OAuth tokens in the `cast-ghl.oauth_tokens` collection.
|
|
|
|
**Limitation:** Secret material (Cast API keys) stored in the same database as operational data.
|
|
If MongoDB is compromised, all per-location Cast credentials are exposed. MongoDB auth and TLS
|
|
mitigate this but do not eliminate the risk.
|
|
|
|
### Target state (Option C)
|
|
|
|
Use **[Infisical](https://github.com/Infisical/infisical)** as the secrets backend for per-location
|
|
Cast API keys. Infisical is open-source, self-hostable, and provides secret versioning, audit logs,
|
|
access policies, and dynamic secrets.
|
|
|
|
### Migration plan
|
|
|
|
#### 1. Deploy Infisical (self-hosted or Infisical Cloud)
|
|
- Recommended: self-host on the same Vultr instance or a dedicated secrets VM
|
|
- Create a project: `cast-ghl-provider`
|
|
- Create an environment: `production`
|
|
- Create a machine identity (service account) for the bridge service
|
|
|
|
#### 2. Secret naming convention
|
|
Store each location's API key as a secret named:
|
|
```
|
|
CAST_API_KEY_<locationId>
|
|
```
|
|
Example: `CAST_API_KEY_q5LZDBHiJ9BsY9Vge5De`
|
|
|
|
#### 3. Code changes in the bridge
|
|
- Add `INFISICAL_CLIENT_ID` and `INFISICAL_CLIENT_SECRET` env vars to config
|
|
- Add Infisical Go SDK: `github.com/infisical/go-sdk`
|
|
- Create `internal/secrets/infisical.go` — wraps the SDK with a `GetLocationAPIKey(locationID) (string, error)` method and an in-process cache (TTL ~60s to avoid hammering the API)
|
|
- In `processOutbound`: call `secrets.GetLocationAPIKey(locationID)` instead of reading from the token record
|
|
- The `cast_api_key` field in `TokenRecord` can be kept as a fallback during migration, then removed
|
|
|
|
#### 4. Admin API changes
|
|
- `PUT /api/admin/locations/{locationId}/config` should write the API key to Infisical (not MongoDB)
|
|
- `GET` endpoints should read from Infisical and mask the returned value
|
|
|
|
#### 5. Migration of existing keys
|
|
1. For each location with a `cast_api_key` in MongoDB, write it to Infisical via the admin API
|
|
2. Verify the bridge reads the key correctly from Infisical
|
|
3. Clear `cast_api_key` from MongoDB records
|
|
4. Remove the MongoDB field once fully migrated
|
|
|
|
#### 6. MongoDB security hardening (do regardless of Infisical migration)
|
|
- Ensure `MONGO_URI` uses authentication: `mongodb://user:pass@host:27017/cast-ghl?authSource=admin`
|
|
- Enable TLS: append `?tls=true&tlsCAFile=/path/to/ca.pem` to the URI
|
|
- Restrict MongoDB network access to the bridge server IP only (Vultr firewall rules)
|
|
- Enable MongoDB audit logging for the `cast-ghl` database
|
|
|
|
---
|
|
|
|
## Other Future Items
|
|
|
|
### Inbound SMS (2-way) — Cast SIM gateway webhook
|
|
- Tracked in CASA-61
|
|
- Requires Cast SIM gateway to support outbound webhooks
|
|
- Bridge handler stub already exists (`PostInboundMessage` in `internal/ghl/api.go`)
|
|
- Need to agree on Cast webhook payload format and DID → locationId mapping
|
|
|
|
### Token refresh proactive scheduling
|
|
- Currently tokens are refreshed on-demand (when expired at webhook time)
|
|
- A background goroutine that refreshes tokens 1 hour before expiry would reduce latency on the first webhook after a 24-hour token lifetime
|