Trigger is a Telegram channel reporting utility designed for multi-account management, persistent sessions, and automated reporting workflows. This document describes the architecture of the Ada/SPARK rewrite.
Trigger follows a layered architecture with clear separation of concerns:
┌─────────────────────────────────────────────────────────────┐ │ Trigger Application │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Main TUI │───▶│ Session │───▶│ Reporting │ │ │ │ (Ada) │ │ Manager │ │ (Zig/FFI) │ │ │ └─────────────┘ │ (Ada/SPARK)│ └─────────────┘ │ │ └─────────────┘ │ │ ▲ ▲ │ │ │ │ │ │ ┌────┴ └────┐ │ │ │ Configuration │ │ │ │ (Ada) │ │ │ └────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Utilities Layer │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │ Logging │ │ Terminal │ │ Crypto │ │ │ │ │ │ (Ada) │ │ (Ada) │ │ (Zig/FFI)│ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ FFI Layer │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │ Zig │ │ Idris2 │ │ C Headers│ │ │ │ │ │ (unified│ │ (API │ │ (FFI │ │ │ │ │ │ hexadeca│ │ layer) │ │ bridge) │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘
The main entry point provides:
-
Interactive TUI with colored menu
-
Application state management
-
Command dispatching
-
Exception handling
Implements the main loop and menu navigation using Ada.Text_IO and custom terminal utilities.
Manages Telegram accounts and their sessions:
-
account_types.adb/ads: Account data structures with SPARK annotations -
session_manager.adb/ads: Session lifecycle management
Provides:
-
Multi-account storage
-
Session creation and persistence
-
Account CRUD operations
-
Active account tracking
Handles application configuration:
-
API credentials (api_id, api_hash)
-
Session settings
-
Proxy configuration
-
Encryption settings
-
Logging preferences
Uses JSON for storage (simplified text format in current implementation).
Handles Telegram reporting operations:
-
Message reporting
-
Channel scanning
-
FloodWait handling
-
Statistics collection
Uses Zig FFI via unified-hexadeca-api for actual Telegram API calls.
Provides cross-cutting functionality:
-
logging.adb/ads: Structured logging with levels -
terminal.adb/ads: ANSI color support and utilities -
crypto.adb/ads: Session encryption/decryption (STUB)
Provides foreign function interfaces:
-
zig/telegram.zig: Telegram API bindings using unified-hexadeca-api -
idris2/TelegramAPI.idr: High-level, type-safe API abstractions
The Zig code provides the actual Telegram client functionality, while the Idris2 code provides a more functional, type-safe interface.
Used for:
-
Main application logic
-
Session management
-
Configuration
-
Utilities
Rationale:
-
Strong typing prevents many classes of bugs
-
SPARK provides formal verification capabilities
-
Mature concurrency model (tasking)
-
Suitable for safety-critical operations
Used for:
-
Telegram API bindings (FFI)
-
Low-level memory management
-
Error handling
Rationale:
-
Excellent C interop for FFI
-
Manual memory management
-
No hidden control flow
-
Compiles to native code
-
User selects "Add Account" from menu
-
Main application prompts for phone, API ID, API hash
-
Session Manager calls Zig FFI to create TelegramClient
-
Zig code uses unified-hexadeca-api to create session
-
Session data saved to file (optionally encrypted)
-
Account added to manager’s account list
-
User selects "Start Reporting" from menu
-
Main application prompts for channel, count, delay, option
-
Session Manager retrieves active accounts
-
For each account:
-
Session Manager loads session via Zig FFI
-
Reporter connects to Telegram via Zig FFI
-
Reporter retrieves last N messages via Zig FFI
-
Reporter reports each message via Zig FFI
-
FloodWait errors are caught and retried with delay
-
-
Statistics are collected and displayed
trigger/
├── LICENSE # MPL-2.0 license (root)
├── LICENSES/
│ ├── MPL-2.0.txt # MPL-2.0 license text
│ └── CC-BY-SA-4.0.txt # Documentation license
├── NOTICE # Original author attribution
├── README.adoc # Main documentation
├── CONTRIBUTING.adoc # Contribution guidelines
├── GOVERNANCE.adoc # Governance document
├── AFFIRMATION.adoc # Affirmation of compliance
├── trigger.gpr # GNAT project file
├── .gitignore
├── .gitattributes
└── .editorconfig
│
├── src/
│ └── trigger/
│ ├── trigger.adb/ads # Main application
│ ├── config/
│ │ └── config.adb/ads
│ ├── session/
│ │ ├── account_types.adb/ads
│ │ └── session_manager.adb/ads
│ ├── reporting/
│ │ └── reporter.adb/ads
│ └── utils/
│ ├── logging.adb/ads
│ ├── terminal.adb/ads
│ └── crypto.adb/ads
│
├── ffi/
│ ├── zig/
│ │ └── telegram.zig # Zig FFI bindings
│ └── idris2/
│ └── TelegramAPI.idr # Idris2 API layer
│
├── tests/
│ └── test_trigger.adb # Unit tests
│
└── docs/
└── ARCHITECTURE.adoc # This document
-
GNAT (Ada/SPARK compiler)
-
Zig compiler (for FFI bindings)
-
Idris2 compiler (for API layer, optional)
-
Zig runtime (for FFI)
-
Idris2 runtime (if used)
-
unified-hexadeca-api (Zig library)
-
Ada exceptions are caught at the top level
-
Zig errors are converted to Ada exceptions via FFI
-
FloodWait errors are handled with automatic retry
-
Network errors are logged and reported to user
-
Session data can be encrypted (AES-256-CFB)
-
API credentials are stored in config.json
-
Phone numbers are stored in accounts.json
-
All sensitive data can be optionally encrypted
Trigger is designed to run in containerized environments using Podman or Docker. The containerisation setup provides:
-
Base Image: Wolfi (Chainguard-owned, community-driven Linux distribution)
-
Package Manager: Guix (for functional package management)
-
Security: Full SELinux labeling, firewalld integration
-
Port Restrictions: All ports down except 80, 443, 8080, 8443
┌─────────────────────────────────────────────────────────────┐ │ Container Stack │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Application │ │ Runtime │ │ Build │ │ │ │ Layer │ │ Layer │ │ Layer │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ ▲ ▲ ▲ │ │ │ │ │ │ │ ┌──────┴──────┐ ┌──────┴──────┐ ┌──────┴──────┐ │ │ │ Trigger │ │ Wolfi + │ │ Wolfi + │ │ │ │ Binary │ │ Guix │ │ Guix + │ │ │ │ + Config │ │ Runtime │ │ Build │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Security Layer │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │ SELinux │ │ firewalld │ │ Non- │ │ │ │ │ │ (enforce) │ │ (drop) │ │ root user│ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘
The CONTAINERFILE uses a multi-stage build:
1. **builder**: Wolfi + Guix with full build toolchain - GCC, GNAT, musl-dev - Zig, Idris2 - libsodium, liboqs - Installs all build dependencies via Guix 2. **build**: Compiles the application - Builds Ada/SPARK code with GNAT - Builds Zig FFI libraries - Builds Idris2 API packages 3. **runtime**: Minimal runtime image - Only includes runtime dependencies - Wolfi + Guix runtime packages - firewalld configured with drop zone - SELinux policies for container runtime - Non-root user (trigger) for security - Only ports 80, 443, 8080, 8443, 22, 53 exposed 4. **dev**: Full development environment - Keeps all build tools - Includes debugging tools (gdb, valgrind) - Python with pons, panic-attack, testing tools
The firewalld configuration is in firewalld/ directory:
-
firewalld.conf: Main configuration with DefaultZone=drop -
zones/drop.xml: Drop zone with explicit port allowances -
zones/public.xml: Public zone with rate limiting -
services/trigger-https.xml: Custom service for HTTPS ports -
services/trigger-api.xml: Custom service for API port
Default Policy: All incoming traffic is DROPPED. Only explicitly allowed:
-
TCP: 22 (SSH), 53 (DNS), 80 (HTTP), 443 (HTTPS), 8080 (API), 8443 (Alt HTTPS)
-
UDP: 53 (DNS)
-
Services: ssh, https, dns
-
Rate limiting: 100/s for SSH, 1000/s for HTTPS
The SELinux configuration is in selinux/ directory:
-
selinux.config: Main SELinux configuration -
policies/trigger.te: Custom SELinux policy module -
contexts/file_contexts: File security contexts -
contexts/port_contexts: Port security contexts
Key Settings:
-
Mode: enforcing
-
Container SELinux: enforcing with container_runtime_t type
-
Custom types: trigger_t, trigger_exec_t, trigger_config_t, etc.
-
Deny rules: Prevent system file modification, writable memory execution
-
File contexts: Proper labeling for /app, /app/bin, /app/config, etc.
-
Port contexts: Proper labeling for ports 80, 443, 8080, 8443, 22, 53
# Build production image
podman build -f CONTAINERFILE -t hyperpolymath/trigger:latest .
# Run production container
podman run -it --rm --security-opt label=type:container_runtime_t \
-p 80:80 -p 443:443 -p 8080:8080 -p 8443:8443 \
--volume /path/to/config:/app/config:Z \
--volume /path/to/sessions:/app/sessions:Z \
hyperpolymath/trigger:latest
# Run development container
podman run -it --rm --security-opt label=type:container_runtime_t \
--volume $(pwd):/app:Z \
hyperpolymath/trigger:dev
The containerisation includes the following security measures:
-
Non-root user: Application runs as
triggeruser, not root -
Read-only filesystem: Where possible, filesystem is read-only
-
SELinux Enforcing: Mandatory access control with custom policies
-
firewalld Drop Zone: All incoming traffic dropped by default
-
Capability Dropping: All capabilities dropped, only needed ones added
-
Port Restrictions: Only ports 80, 443, 8080, 8443 exposed
-
Directory Permissions: Proper permissions on config, sessions, logs, cache
-
Health Checks: Container health monitoring
-
Full SPARK verification of critical components
-
Complete Zig FFI implementation with unified-hexadeca-api
-
Idris2 API layer with full functionality
-
Proper JSON parsing/serialization
-
Session encryption using SPARK-verified crypto
-
Proxy support implementation
-
Comprehensive test suite