Status: Accepted Date: 2026-03-30 Supersedes: N/A Superseded by: N/A

Context

F006 adds TLS support to ztick’s TCP server (FR-001). This requires a server-side TLS implementation capable of accepting connections, performing handshakes, and wrapping streams.

Zig’s stdlib std.crypto.tls provides client-side TLS only — the std/crypto/tls/ directory contains only Client.zig as of Zig 0.15.2. There is no server-side handshake capability in the stdlib.

ADR 0002 chose Zig specifically for its zero-dependency philosophy, with build.zig.zon dependencies = .{}. Adding TLS support forces the first decision to reach outside the Zig stdlib, creating tension with this foundational constraint.

Candidates

OptionProsCons
System OpenSSL via @cImportZig’s C interop is zero-overhead and first-class; OpenSSL is universally available and battle-tested; build.zig.zon dependencies stays = .{}Adds platform dependency on libssl-dev; TLS behavior tied to system OpenSSL version
iguanaTLS (Zig package)Pure Zig; no system library dependencyZig 0.15.2 compatibility unverified; appears unmaintained; adds entry to build.zig.zon dependencies, breaking zero-Zig-package invariant
Defer TLS (abstraction only)No new dependencies; lowest riskDoes not deliver functional TLS (FR-001, US1); defers the core feature deliverable

Decision

Use system OpenSSL (libssl + libcrypto) accessed via Zig’s @cImport C interop.

  • A new infrastructure module src/infrastructure/tls_context.zig isolates all OpenSSL FFI at a clean boundary
  • build.zig conditionally links libssl and libcrypto only when the TLS module is compiled; plaintext-only builds remain fully zero-dependency
  • build.zig.zon dependencies stays = .{} — system libraries linked via linkSystemLibrary are not Zig packages

Consequences

What becomes easier:

  • Delivering functional TLS (FR-001 compliance) without adding Zig package dependencies
  • Auditing the TLS implementation path (one file: tls_context.zig)
  • Reverting: remove tls_context.zig and the conditional linkSystemLibrary calls

What becomes harder:

  • Builds now require libssl-dev on development machines and CI (apt-get install libssl-dev on Debian/Ubuntu)
  • Platform portability: system OpenSSL may not be present on minimal musl-based containers
  • TLS behavior tied to the system’s OpenSSL version

Trade-offs Accepted

  • System library dependency: Plaintext-only builds remain zero-dependency. Conditional linking in build.zig ensures developers who don’t need TLS are unaffected.
  • OpenSSL version variance: OpenSSL’s C API is stable across major versions. The implementation uses only core primitives (SSL_CTX_new, SSL_accept, SSL_read, SSL_write).
  • Platform availability: OpenSSL is installed on every mainstream Linux distribution and macOS. CI adds libssl-dev as a build prerequisite.

Constitution Compliance

PrincipleStatusJustification
Zero external Zig dependenciesCompliantbuild.zig.zon dependencies = .{} unchanged; system libs are not Zig packages
Minimal AbstractionCompliantTlsContext and Connection each have a single, justified purpose; no speculative interfaces
Hexagonal ArchitectureCompliantAll OpenSSL FFI isolated in infrastructure/tls_context.zig; domain and application layers untouched
Build SimplicityCompliantConditional linkSystemLibrary in build.zig; no new build scripts or tooling

References

  • Spec: .specify/implementation/F006/spec-content.md
  • Plan: .specify/implementation/F006/plan.md
  • Implementation: src/infrastructure/tls_context.zig, src/infrastructure/tcp_server.zig
  • ADR 0002: docs/ADR/0002-zig-language-choice.md (zero-dependency decision this ADR extends)