Skip to content

feat(line): first-class [line] trust section (Phase 1)#1365

Merged
thepagent merged 1 commit into
mainfrom
feat/1355-line-config-section
Jul 11, 2026
Merged

feat(line): first-class [line] trust section (Phase 1)#1365
thepagent merged 1 commit into
mainfrom
feat/1355-line-config-section

Conversation

@chaodu-agent

Copy link
Copy Markdown
Collaborator

What problem does this solve?

LINE trust is currently controlled only by the uniform GATEWAY_ALLOW_ALL_USERS / GATEWAY_ALLOWED_USERS env vars, which apply to ALL gateway platforms at once — no per-platform granularity. Since the Phase 3 deny-all default flip, LINE deployments must set GATEWAY_ALLOW_ALL_USERS=true (opening every gateway platform) just to keep LINE working — the exact operator pain reported on the issue.

First slice of #1355 (umbrella #1356): a first-class [line] section, mirroring the [telegram] pattern from #1297. Group policy (open/members) and Reply-API deny-echo remain on the issue as follow-ups.

At a Glance

Before — one env pair opens every gateway platform

┌─ Trust sources ───────────────────┐  ┌─ PlatformTrustConfigs ────────────┐
│                                   │  │                                   │
│  ┌─────────────────────────────┐  │  │  ┌─────────────────────────────┐  │
│  │ GATEWAY_ALLOW_ALL_USERS     │──┼──┼─▶│ line      ← uniform seed    │  │
│  │ GATEWAY_ALLOWED_USERS       │  │  │  │ feishu    ← uniform seed    │  │
│  │ (uniform, all platforms)    │  │  │  │ wecom     ← uniform seed    │  │
│  └─────────────────────────────┘  │  │  │ googlechat← uniform seed    │  │
│                                   │  │  │ teams     ← uniform seed    │  │
│  ┌─────────────────────────────┐  │  │  └─────────────────────────────┘  │
│  │ [telegram] section (#1297)  │──┼──┼─▶ telegram (override)             │
│  └─────────────────────────────┘  │  │                                   │
└───────────────────────────────────┘  └───────────────────────────────────┘

After — LINE gets its own section, legacy env warns

┌─ Trust sources ───────────────────┐  ┌─ PlatformTrustConfigs ────────────┐
│                                   │  │                                   │
│  ┌─────────────────────────────┐  │  │  ┌─────────────────────────────┐  │
│  │ [line] section          NEW │──┼──┼─▶│ line      ← [line] override │  │
│  │ allow_all_users /           │  │  │  │             (L3 identity)   │  │
│  │ allowed_users               │  │  │  └─────────────────────────────┘  │
│  │ env fallback: LINE_*    NEW │  │  │  ┌─────────────────────────────┐  │
│  └─────────────────────────────┘  │  │  │ telegram  ← [telegram]      │  │
│  ┌─────────────────────────────┐  │  │  └─────────────────────────────┘  │
│  │ [telegram] section (#1297)  │  │  │  ┌─────────────────────────────┐  │
│  └─────────────────────────────┘  │  │  │ feishu │ wecom │ googlechat │  │
│  ┌─────────────────────────────┐  │  │  │ teams  ← uniform seed       │  │
│  │ GATEWAY_* env (legacy)      │  │  │  │ (until #1357–#1360)         │  │
│  │ ⚠ warns at startup when it  │  │  │  └─────────────────────────────┘  │
│  │ still drives LINE trust     │  │  └───────────────────────────────────┘
│  └─────────────────────────────┘  │
└───────────────────────────────────┘

Proposed Solution

  • crates/openab-core/src/config.rsLineConfig { allow_all_users: Option<bool>, allowed_users: Option<Vec<String>> } with per-field resolution [line]LINE_ALLOW_ALL_USERS / LINE_ALLOWED_USERS env → deny-all default (identity-trust-none ADR). Trust-only by design: channel credentials stay on the LINE_CHANNEL_SECRET / LINE_CHANNEL_ACCESS_TOKEN env vars the webhook adapter reads.
  • src/main.rs — the resolved [line] values override the uniform GATEWAY_* seed in the trust registry, exactly like the telegram override (also resolves env-only, matching the Telegram pattern). When no first-class LINE trust config exists, the unified LINE adapter is active, and the legacy GATEWAY_* env is set, a Phase 1 deprecation warning tells operators to migrate before Phase 2 turns it into an error.
  • Docsconfig.toml.example [line] block, docs/config-reference.md new ## [line] section, docs/line.md User Trust section + env var table rows with the deprecation callout.

Why this approach?

Backward-compatible by construction: existing LINE deployments driven by GATEWAY_* env keep working unchanged (warning only, per the umbrella's Phase 1 → 2 → 3 plan), and the [line] override is opt-in. Reuses the exact [telegram] resolution/override shape (#1297), so the remaining platforms (#1358#1360) become mechanical clones of this PR.

Validation

At 57cc547 (macOS arm64, rebased on 2f0342b):

  • cargo clippy --workspace --all-features -- -D warnings — clean
  • cargo clippy --workspace -- -D warnings (default features) — clean
  • cargo check -p openab-core --no-default-features — pass
  • cargo check --features unified (line feature on) — pass
  • cargo test -p openab-core --all-features — 656 passed, 1 failed: secrets::tests::resolve_exec_nonzero_exit, the known pre-existing macOS-only failure (also fails on unmodified main)
  • LINE-related tests — 16/16 including the two new ones
  • rustfmt --check — no new drift (config.rs 0→0, main.rs 4→4 vs main baseline)
  • docs/platforms/schema/line.toml reviewed: its trust-gate claims describe the shared ingress gate, which is unchanged by this PR — no schema update required (conformance CI not triggered).

Tests

  • line_section_parses_from_toml[line] parse + absent-section → None
  • line_resolve_all_scenarios — six env-resolution scenarios in one test fn (env vars are process-global; single-fn pattern mirrors telegram_resolve_all_scenarios for parallel-test safety): deny-all default, config-wins-over-env, comma-separated env fallback with trimming, empty-string flag treated as unset, "0"/"false" parsing, explicit empty list = deny-all

Refs #1355 (first slice — group policy + Reply-API deny-echo remain), umbrella #1356, ADR #1291.

Add a [line] config section for L3 identity trust, replacing the
uniform GATEWAY_ALLOW_ALL_USERS/GATEWAY_ALLOWED_USERS env vars for
LINE. First slice of #1355, mirroring the [telegram] pattern (#1297).

- config.rs: LineConfig { allow_all_users, allowed_users } with
  LINE_ALLOW_ALL_USERS / LINE_ALLOWED_USERS env fallbacks and deny-all
  default (identity-trust-none ADR). Trust-only by design — channel
  credentials stay on LINE_CHANNEL_SECRET / LINE_CHANNEL_ACCESS_TOKEN.
- main.rs: [line] (or LINE_* env) overrides the uniform GATEWAY_* seed
  in the trust registry, exactly like the telegram override. When LINE
  is active and still driven by the legacy GATEWAY_* env, log a Phase 1
  deprecation warning (becomes an error in Phase 2, #1356).
- docs: config.toml.example, config-reference.md ([line] section),
  line.md (User Trust section + env table).
- tests: TOML parse + all env resolution scenarios in one test fn
  (env-race safety, same pattern as telegram_resolve_all_scenarios).

Group policy (open/members) and Reply-API deny-echo are follow-ups on
the issue.

Refs #1355, umbrella #1356, ADR #1291.
@chaodu-agent chaodu-agent requested a review from thepagent as a code owner July 11, 2026 13:29
@chaodu-agent

Copy link
Copy Markdown
Collaborator Author

Note

LGTM ✅ — Clean first-class [line] trust section that mirrors the established [telegram] pattern exactly.

What This PR Does

LINE identity trust was tied to the uniform GATEWAY_ALLOW_ALL_USERS/GATEWAY_ALLOWED_USERS env vars, forcing operators to open all gateway platforms just to let LINE work. This PR adds a first-class [line] config section with dedicated LINE_* env fallbacks, matching the [telegram] pattern from #1297.

How It Works

  1. LineConfig + ResolvedLine in config.rs — trust-only struct (no channel credentials) with per-field resolution: [line].fieldLINE_* env → deny-all default.
  2. Trust registry override in main.rs — three-way match: config section present → resolve from config; env-only (LINE_ALLOW_ALL_USERS/LINE_ALLOWED_USERS set) → resolve from defaults+env; neither → legacy GATEWAY_* seed with Phase 1 deprecation warning.
  3. Docsconfig.toml.example, config-reference.md, docs/line.md all updated with the new section, env var table, and deprecation callout.

Findings

# Severity Finding Location
1 🟢 Exact structural mirror of the Telegram pattern — resolution logic, test shape, and registry override are 1:1 config.rs, main.rs
2 🟢 Comprehensive 6-scenario test with proper env cleanup and single-fn parallel-safety config.rs:1934
3 🟢 Deprecation warning only fires when LINE is active AND legacy env is the sole trust source — no false positives main.rs
4 🟢 Trust-only design keeps channel credentials on existing env vars — minimal blast radius
What's Good (🟢)
  • Pattern fidelity: The LineConfig::resolve() logic is a direct mirror of TelegramConfig::resolve() for the trust fields — same empty-string handling, same "0"/"false" parsing, same comma-split-trim for lists. This makes future platform clones (feat(wecom): migrate WeCom trust config to first-class [wecom] section (Phase 1) #1358feat(teams): migrate MS Teams trust config to first-class [teams] section (Phase 1) #1360) mechanical.
  • Backward compatibility: Existing LINE deployments with only GATEWAY_* set continue working unchanged — the deprecation is warning-only (Phase 1), matching the umbrella plan.
  • env_trust_present() static method: Clean separation for the binary to check whether LINE-specific env vars exist without constructing a full config.
  • Test design: The single-fn-six-scenarios pattern prevents env var races in parallel test execution, correctly mirrors telegram_resolve_all_scenarios.
  • Documentation completeness: All three doc surfaces updated (config.toml.example, config-reference.md, docs/line.md) with consistent wording and the deprecation callout.
Baseline Check
  • PR opened: 2026-07-11
  • Main already has: [telegram] first-class trust section (feat(telegram): add allow_all_users/allowed_users to [telegram] config #1297), uniform GATEWAY_* seed for all platforms, TelegramConfig with identical resolve pattern
  • Net-new value: [line] trust override with LINE_* env fallbacks, Phase 1 deprecation warning when LINE still rides on GATEWAY_*, docs for the new section

5️⃣ Three Reasons We Might Not Need This PR

  1. Could wait for batch implementationfeat(feishu): migrate Feishu trust config to first-class [feishu] section (Phase 1) #1357feat(teams): migrate MS Teams trust config to first-class [teams] section (Phase 1) #1360 will need identical sections for feishu/wecom/googlechat/teams; a single "all platforms at once" PR would reduce review cycles. Counter: the umbrella explicitly calls for incremental slices, and LINE is the reported pain point.

  2. LINE operator pain is low — operators could just set GATEWAY_ALLOW_ALL_USERS=true and accept the open-all tradeoff. Counter: this defeats the deny-all-by-default security posture from Phase 3; the whole point of per-platform granularity is to avoid that.

  3. Phase 1 warning adds log noise — existing deployments that work fine will now see a deprecation warning on every startup. Counter: the warning is narrowly scoped (only when LINE is active AND GATEWAY_* is the sole trust source) and the migration path is trivial.

@thepagent thepagent merged commit 6cf869d into main Jul 11, 2026
38 checks passed
chaodu-agent added a commit that referenced this pull request Jul 11, 2026
…(Phase 1)

Clone the [line] pattern to the three remaining gateway platforms via a
shared PlatformTrustConfig (allow_all_users/allowed_users with
{PREFIX}_ALLOW_ALL_USERS / {PREFIX}_ALLOWED_USERS env fallbacks and
deny-all default). Env prefixes follow the adapters' existing
conventions: WECOM, GOOGLE_CHAT, TEAMS.

main.rs gains a platform_trust_override helper that applies the
first-class section (or its env) over the uniform GATEWAY_* seed, and
logs the shared Phase 1 deprecation warning when an active platform is
still trust-driven by the legacy env (activity signals: WECOM_CORP_ID,
GOOGLE_CHAT_ENABLED, TEAMS_APP_ID — same as has_unified_platform_env).

Trust-only by design: platform credentials stay on the gateway env
vars. Platforms needing richer trust fields later (trusted_bot_ids for
wecom/teams per their issues) graduate to their own struct, as LINE
will for group policy.

Docs: config.toml.example, config-reference.md (combined section with
per-platform sender-ID formats), wecom.md, google-chat.md,
msteams-selfhosted.md.

Refs #1358 #1359 #1360, umbrella #1356, ADR #1291. Stacked on #1365.
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.

2 participants