feat(line): full [line] section — credentials + connection config-first#1381
Conversation
First platform slice of the config-first parity umbrella (#1375): [line] now carries channel_secret, channel_access_token, and webhook_path alongside the trust fields, resolving each field config → LINE_* env → default (config always wins; empty-string ${} expansion falls through to env). Mirrors the TelegramConfig pattern. - core: LineConfig/ResolvedLine extended; resolve() per-field - gateway: GatewayLineConfig bridge + AppState::apply_line_config (crate-boundary pattern of apply_telegram_config); new line_webhook_path state field; standalone gateway honors LINE_WEBHOOK_PATH and mounts at the resolved path - unified: applies [line] before warn_unenforceable_l1, so a config-supplied channel_secret satisfies the #1373 L1 startup check (test pins this); line route mounts at the resolved path - docs: config.toml.example, config-reference.md, line.md — [line] primary, env fallback Backward compatible: env-only deployments resolve identically; the default mount path is unchanged. Closes #1376. Refs #1375, #1373.
This comment has been minimized.
This comment has been minimized.
The closing code fence had prose on the same line, so the block never closed and the following paragraph rendered inside it.
|
Note LGTM ✅ — Clean config-first parity slice; mirrors TelegramConfig pattern end-to-end with proper test coverage. What This PR DoesLINE channel credentials ( How It WorksMirrors the
Findings
What's Good (🟢)
Baseline Check
5️⃣ Three Reasons We Might Not Need This PR
|
…irst (#1382) * feat(wecom): full [wecom] section — credentials + connection config-first Second platform slice of the config-first parity umbrella (#1375): [wecom] graduates from the shared PlatformTrustConfig to a dedicated WecomConfig carrying corp_id, secret, token, encoding_aes_key, agent_id, webhook_path, streaming_enabled, debounce_secs alongside the trust fields. Each field resolves config → WECOM_* env → default. - core: WecomConfig/ResolvedWecom + resolve(); trust_config() view keeps the registry override path unchanged - gateway: GatewayWecomConfig bridge + AppState::apply_wecom_config; the apply rebuilds the adapter through the same from_reader validation as env-only construction (five mandatory credentials, numeric agent_id, 43-char AES key) — incomplete section resolves to no adapter, matching env-only semantics - unified: applies [wecom] before warn_unenforceable_l1 - docs: config.toml.example, config-reference.md ([wecom] gets its own full section; combined section shrinks to googlechat/teams), wecom.md Backward compatible: env-only deployments construct identically; existing trust-only [wecom] sections keep parsing (all fields optional). Closes #1378. Refs #1375. Stacked on #1381. * docs(config): drop graduated [wecom] from PlatformTrustConfig doc (review F1) --------- Co-authored-by: chaodu-agent <chaodu-agent@users.noreply.github.com>
…refs The design shipped across #1356/#1375 (#1297, #1365/#1366 trust slices; #1381-#1385 full config-first parity). Corrections vs implementation: googlechat field names (sa_key_json + audience), Teams sender-id is the Bot Framework activity.from.id (not AAD Object ID). The [gateway] section deprecation warning is deferred to Phase 1c (the WS two-process model still uses [gateway] legitimately) — tracked on #1356. Merging also fixes the dangling first-class-platform-config.md link in the already-merged identity-trust-none ADR.
* docs(adr): first-class per-platform config & trust-none default Propose promoting all gateway-connected platforms (Telegram, LINE, Feishu, WeCom, Google Chat, MS Teams) to top-level config sections, matching the existing [discord] and [slack] structure. Key decisions: - Per-platform [telegram], [line], [feishu], etc. sections - Trust-none default (empty allowed_users = deny all) - Single trust gate at AdapterRouter::handle_message() - Echo sender ID on deny - Deprecate [gateway] catch-all section Tracking: #1262 * docs(adr): add trust pyramid with platform auth comparison table Layer 1 (gateway): Platform authentication mechanisms per adapter - Telegram: secret token + IP range - LINE: HMAC-SHA256 - Feishu: SHA256 signature + encrypt key - WeCom: token signature + AES decrypt - Google Chat: JWT (RS256 via JWKS) - MS Teams: JWT (OpenID Connect) - Slack/Discord: WebSocket token auth Layer 2 (core): Channel/group trust (existing) Layer 3 (core): User trust (this ADR - flip to deny-all) * docs(adr): refine trust pyramid — L2 scope (open default) vs L3 identity (deny default) Clarify the three layers per review discussion: - L1 platform auth (security, edge) - L2 channel/group/DM scope control — NOT security, default OPEN; the platform already enforces channel membership, so L2 is operator scoping - L3 identity trust — THE security gate, default DENY-ALL, covers all paths - allow_dm is an L2 surface toggle; DMs have no platform membership gate so L3 is their sole protection - L2 must stay open by default for the echo-UID request-access flow to work * docs(adr): specify trait & type changes — extend carriers, no new trait - Extend TrustConfig with L2 scope fields (allow_all_channels, allow_dm) + surface_allowed(); defaults L2-open / L3-deny - Add 'Trait & Type Changes' section: pass SenderContext in MessageContext, add is_dm to ChannelRef, no new ChatAdapter method/trait (uniform logic) - Note the real refactor = remove scattered trust checks from discord.rs/slack.rs/gateway.rs so the router gate is un-bypassable - Fix architecture diagram gate labels (L2 optional/open, L3 deny default) * docs(adr): sharpen title to 'identity trust-none default' * docs(adr): scope down to per-platform config only Split the trust/security decision out into a separate ADR (docs/adr/identity-trust-none.md, PR #1264). This ADR now covers only the config schema change: first-class [platform] sections + [gateway] deprecation + migration. * docs(adr): mark first-class platform config as Accepted with shipped refs The design shipped across #1356/#1375 (#1297, #1365/#1366 trust slices; #1381-#1385 full config-first parity). Corrections vs implementation: googlechat field names (sa_key_json + audience), Teams sender-id is the Bot Framework activity.from.id (not AAD Object ID). The [gateway] section deprecation warning is deferred to Phase 1c (the WS two-process model still uses [gateway] legitimately) — tracked on #1356. Merging also fixes the dangling first-class-platform-config.md link in the already-merged identity-trust-none ADR. --------- Co-authored-by: 超渡法師 <chaodu-agent@openab.dev> Co-authored-by: chaodu-agent <chaodu-agent@users.noreply.github.com>
What problem does this solve?
First platform slice of the config-first parity umbrella #1375: LINE's channel credentials were env-only (
LINE_CHANNEL_SECRET/LINE_CHANNEL_ACCESS_TOKEN), violating the invariant that every platform setting resolves[section]config →PLATFORM_*env → default with config always winning.Proposed Solution
Mirrors the
TelegramConfigreference pattern end-to-end:config.rsLineConfiggainschannel_secret,channel_access_token,webhook_path;resolve()applies config →LINE_*env → default per field (empty-string${}expansion falls through to env)lib.rsGatewayLineConfigbridge +AppState::apply_line_config()(keeps the crate free of openab-core); newline_webhook_pathstate; standalone gateway honorsLINE_WEBHOOK_PATHand mounts at the resolved pathmain.rs[line]beforewarn_unenforceable_l1, so a config-suppliedchannel_secretsatisfies the #1373 L1 startup check; route mounts at the resolved pathconfig.toml.example,config-reference.mdfield table,line.md([line]primary, env fallback)Backward compatible: env-only deployments resolve identically; default mount path unchanged.
Tests
line_section_parses_from_toml— new fields parseline_resolve_all_scenarios— 3 new scenarios: config-wins-over-env for all three fields; empty-string expansion falls through to env; nothing set → defaultsapply_line_config_overrides_env_state_and_feeds_l1_warning— pins the feat(gateway): warn when webhook L1 auth is unenforceable (#1356 Phase 1) #1373 integration: env-derived flagged state clears once config supplies the secretValidation
At head (macOS arm64, main
9af9fcd):cargo clippy -p openab-core -p openab-gateway --all-features -- -D warnings— clean; gateway no-features also cleancargo check --features unifiedand default — passrustfmt --checkisolated per file: zero drift vs main (all three files 0→0)Closes #1376. Refs #1375 (umbrella), #1373 (L1 warning integration).