Repository navigation
Releases: davidrukahu/openussd
Release list
v0.1.0 - gateway core, Go SDK, and Fediverse adapter
A USSD dialogue reaches a tenant application and a screen comes back, with no telco account required.
git clone https://github.com/davidrukahu/openussd.git && cd openussd
export FEDIVERSE_WEBHOOK_SECRET=$(openssl rand -hex 32)
docker compose up --buildThen, in another terminal:
go run ./cmd/ussdsim -shortcode '*384*1234#'That reads a live Mastodon public timeline over a simulated handset, paginated into real USSD screens. cmd/ussdsim is a terminal handset: no telco account, no sandbox registration, no inbound tunnel.
Interfaces will break before 1.0.
First code. A USSD dialogue reaches a tenant application and a screen comes
back, with no telco account required.
Added
- Gateway (
gateway/). Canonical session events per
RFC-0001, a telco adapter
interface with a registry, session storage behind an interface with
in-memory and Redis implementations, and tenant routing on
(shortcode, sub-prefix)with HMAC-signed outbound webhooks. - Africa's Talking adapter, with fixture-driven contract tests. First
rather than Safaricom Daraja, which is the M-Pesa API portal and exposes
no USSD sandbox. See docs/telco-access.md. adapter.TrustedProxy, a source-address allowlist for networks that
authenticate nothing. This resolves RFC-0001's open question as a wrapper
rather than a flag, so the weakness is visible in the deployment wiring.- Go SDK (
sdk/go). Typed screens and state machine, render helpers
that enforce the screen budget, an i18n bundle, and a handler that
verifies the gateway's signature before decoding. - Fediverse reference adapter, read-only Mastodon public timeline
paginated into USSD screens, with alt text for attachments. cmd/ussdsim, a terminal handset, so the whole thing runs with no
telco account, no sandbox registration and no inbound tunnel.- docs/webhook-protocol.md, the full wire
contract, so a tenant can be written in any language. - Docker Compose, Makefile, and CI running gofmt, vet, race tests and
golangci-lint.
Notes
- The screen budget is 182 GSM 03.38 septets, or 70 UCS-2 units once a
screen contains any non-GSM character. Everything measures cost in the
encoding the text forces, rather than counting runes against 182. - Session state is opaque JSON, resolving
#10. - The Africa's Talking fixtures are hand-written from the published request
shape. They prove the adapter is self-consistent, not that it matches the
network. Capturing them against the live sandbox is what
#7 should become.
Known limitations
- No replay nonce. The signature's 5-minute window bounds replay but does
not prevent it; tenants should deduplicate on(session_id, turn). - The simulator adapter ships enabled in the example config and
authenticates nothing. It is the demo. Do not expose it. - The Redis session store has no tests.
- No release pipeline. Build from source or use Docker Compose.
No prebuilt binaries. Build from source with Go 1.24 or newer, or use the Docker Compose path above. A release pipeline is tracked in TODOS.md.
Writing a tenant application? The wire protocol is documented in full, so it does not have to be Go. The Go SDK is one implementation of it.
Integrated against an African MNO? #11 wants to hear what surprised you, and captured callback bodies from any network are the most useful thing anyone could contribute.