Skip to content

docs(adr): separate binaries by default, opt-in unified build#1116

Open
chaodu-agent wants to merge 3 commits into
mainfrom
docs/adr-unified-binary
Open

docs(adr): separate binaries by default, opt-in unified build#1116
chaodu-agent wants to merge 3 commits into
mainfrom
docs/adr-unified-binary

Conversation

@chaodu-agent

@chaodu-agent chaodu-agent commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

Proposes restructuring OpenAB as a Cargo workspace that keeps two separate binaries by default (core + gateway), while enabling a single unified binary via --features unified or a Dockerfile BUILD_MODE arg — zero code changes required.

Key Design

  • Default: cargo build → core binary (Discord + Slack). Gateway ships separately.
  • Unified opt-in: cargo build --features unified → all adapters in one binary.
  • Dockerfile: docker build --build-arg BUILD_MODE=unified flips to single binary.
  • Runtime activation: compiled-in adapters only start if their config section is present.
  • Feature flags: granular — pick just telegram,line if you don't need all adapters.

Published Artifacts

Image Contents
openab:latest Core only (Discord + Slack)
openab-gateway:latest Standalone gateway
openab:unified All adapters in single binary

Changes

  • docs/adr/unified-binary.md — new ADR document

Add ADR for restructuring OpenAB as a Cargo workspace that ships all
platform adapters in a single binary, activated at runtime via config.
This eliminates the two-process (core + gateway sidecar) deployment
model for most users while keeping the standalone gateway available
for advanced use cases.
@chaodu-agent chaodu-agent requested a review from thepagent as a code owner June 15, 2026 03:20
@chaodu-agent

chaodu-agent commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator Author

CHANGES REQUESTED ⚠️ — ADR is well-structured but lacks actionable mitigation details for security, CI pipeline, deployment edge cases, and Cargo manifest specifics.

What This PR Does

Proposes restructuring OpenAB into a Cargo workspace shipping all platform adapters (Telegram, LINE, Feishu, Google Chat, WeCom, Teams) in a single binary alongside Discord and Slack. Adapters activate at runtime via config — eliminating the two-process sidecar model for most users.

How It Works

  • Workspace with two library crates (openab-core + openab-gateway)
  • Feature flags allow minimal custom builds
  • Runtime activation: compiled-in adapters only start if config is present
  • Standalone gateway kept for backward compatibility, deprecated after 2 minor releases

Findings

# Severity Finding Location
1 🟡 Default features enable all adapters — expands attack surface without dep management strategy §2, §7
2 🟡 No supply chain gate (cargo-deny, cargo-audit, SBOM) mentioned in ADR §5, §7
3 🟡 CI/release pipeline for 3 artifacts + feature matrix not specified §5, §8
4 🟡 Code duplication risk between gateway/ (standalone) and crates/openab-gateway/ §2 layout
5 🟡 Network-isolated deployment story unclear after standalone gateway deprecation §6 Phase 3
6 🟡 Hardcoded axum port :9090 — no config for host runtime conflicts §3 diagram
7 🟡 Tracing correlation context propagation not addressed for in-process dispatch §4
8 🟡 Media proxy mode for non-colocated standalone deployments not covered §7
9 🟡 Feature flag dep:openab-gateway requires corresponding optional = true dependency declaration not shown §2 Feature Flags
10 🟡 Workspace root Cargo.toml structure missing ([workspace] + members + resolver = "2") §2 Workspace Layout
Finding Details

🟡 F1: Default features expand attack surface

default = ["discord","slack","telegram","line","feishu","googlechat","wecom","teams"] means openab:latest permanently carries transitive deps for all platforms (axum, crypto crates, XML parsers). ADR acknowledges "more deps in tree" but proposes no actionable control mechanism.

Suggestion: Add a section on dependency governance — e.g., cargo-deny policy for license + advisory checks gating CI, periodic cargo-audit in release workflow.

🟡 F2: No supply chain hardening requirements

Future platform crates will pull in aes/cbc (WeCom), quick-xml (WeCom/Feishu), jsonwebtoken (LINE/Google Chat). A single compromised transitive dep affects all published images. ADR should specify SBOM generation and vetting process for new platform deps.

🟡 F3: CI/release pipeline undefined

Three published images (latest, slim, gateway) + custom feature builds need: feature matrix CI testing, separate Dockerfiles or multi-stage builds, layer cache strategy, and clear "which image for new users" guidance. Without this, operational complexity may exceed the sidecar complexity being eliminated.

🟡 F4: Code duplication between standalone gateway and workspace crate

ADR shows gateway/ (standalone binary) coexisting with crates/openab-gateway/. During Phase 1-2, both exist. Need to clarify: does gateway/ simply re-export crates/openab-gateway as a standalone binary, or is it a separate copy? If the latter, divergence risk is high.

Suggestion: Explicitly state that gateway/ becomes a thin main.rs that depends on crates/openab-gateway as a library.

🟡 F5: Network-isolated deployment gap

Some deployments run gateway in a DMZ (webhook ingress) separate from core (internal network). Phase 3 deprecation of standalone gateway removes this option. ADR should document the recommended architecture for network-segmented environments post-deprecation.

🟡 F6: Hardcoded axum port

Diagram shows :9090 for webhook HTTP server. Should be configurable via [http] or [webhook] config section. Multiple services on one host or container orchestrators with port constraints need flexibility.

🟡 F7: Tracing context propagation

Moving from WS (separate processes with explicit trace propagation) to in-process Dispatcher.submit() changes observability. Need to ensure span context flows correctly through the direct call path — otherwise debugging multi-adapter issues becomes harder, not easier.

🟡 F8: Media handling for remote gateway

ADR lists "no shared volume" as an advantage of single-binary mode. But for users who keep standalone gateway (Phase 1-2, or network-isolated), media colocate mode still needs shared volume or a proxy mechanism. ADR should clarify what happens to media flow in hybrid deployments.

🟡 F9: Missing optional dependency declaration

The [features] section uses dep:openab-gateway syntax, which requires a corresponding entry in [dependencies]:

[dependencies]
openab-gateway = { path = "crates/openab-gateway", optional = true }

Without showing this, implementers may be confused about how dep: activation works.

🟡 F10: Incomplete workspace manifest example

ADR should show the workspace root Cargo.toml structure including [workspace] members declaration and explicit resolver = "2". This is modern Cargo workspace best practice and avoids ambiguity about whether the root is a virtual workspace or a root-package workspace.

Baseline Check
  • PR opened: 2026-06-15
  • Pure ADR document (docs/adr/unified-binary.md, 200 lines) + minor code delta in src/adapter.rs
  • Status: Proposed — no code restructuring yet
  • CI: ✅ passing
  • Net-new value: Documents architectural direction for eliminating two-process deployment model
What's Good (🟢)
  • Clean workspace layout with well-defined crate boundaries (openab-core vs openab-gateway)
  • Feature flag design follows Cargo best practices — dep:openab-gateway + sub-feature activation is correct (Rust 1.71+)
  • Phased migration with no breaking changes — respectful of existing users
  • Trade-offs section is honest about disadvantages
  • Backward compatibility explicitly preserved throughout all phases
  • "Rejected Alternatives" section provides good decision context
  • Message flow diagrams (Before/After) accurately match current implementation
  • Recommend adding [workspace.dependencies] for shared deps (tokio, serde, tracing, reqwest) to reduce version drift
Additional Note: Cross-ADR Security Model Change

The custom-gateway ADR §Credential Isolation specifies "platform credentials must reside in the gateway, not in OAB." The unified binary changes this model — OAB now directly holds platform tokens. This is acceptable (same process = no transport risk), but should be explicitly acknowledged in §7 Trade-offs with rationale for why the security boundary change is safe.


Summary: Strong ADR with clear problem statement and elegant solution. The 10 findings are all 🟡 — no blockers. Core architectural decision is sound. Recommend adding: (1) dependency governance section, (2) CI pipeline sketch, (3) network-isolated deployment guidance, (4) gateway code sharing strategy, and (5) complete Cargo manifest examples.

- Default: two separate binaries (core + gateway), unchanged from today
- Opt-in: --features unified compiles all adapters into single binary
- Zero code changes needed — just a build flag or image swap
- Published: openab:latest (core), openab:unified (all-in-one)
@chaodu-agent

Copy link
Copy Markdown
Collaborator Author

ADR Updated: Flipped default direction

Per maintainer's request, the ADR now proposes separate binaries by default with unified single-binary as opt-in.

Key changes:

  • Default build (cargo build) → core only (Discord + Slack). Gateway remains a separate binary.
  • Unified opt-incargo build --features unified compiles all adapters into one binary. Zero code changes needed.
  • Published images: openab:latest (core), openab-gateway:latest (standalone), openab:unified (all-in-one)
  • Migration path: no disruption — existing deployments unchanged. Unified mode is purely additive.
  • Rejected alternative: "unified by default" moved to rejected alternatives section.

This gives users the simplicity of the current two-binary model while making it trivial to opt into a single binary when desired — config only, no code changes.

@chaodu-agent chaodu-agent changed the title docs(adr): unified single-binary architecture docs(adr): separate binaries by default, opt-in unified build Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant