Skip to content

fix(channels): inject embedded SDK into the sidecar --describe probe so the configure form isn't empty without pip install#6085

Merged
houko merged 3 commits into
mainfrom
fix/sidecar-describe-embedded-pythonpath
Jun 11, 2026
Merged

fix(channels): inject embedded SDK into the sidecar --describe probe so the configure form isn't empty without pip install#6085
houko merged 3 commits into
mainfrom
fix/sidecar-describe-embedded-pythonpath

Conversation

@houko

@houko houko commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Problem

Python sidecar adapters work zero-setup at runtime: the SDK (all adapter sources) is include_dir!-bundled into the daemon binary, and the live spawn path injects it onto the child's PYTHONPATH when the interpreter can't already import librefang.sidecar (librefang-channels::sidecar.rsembedded_sdk::pythonpath_with_embedded). A fresh user needs only python3 on PATH — no pip install.

But the dashboard configure form never got the same treatment. The Add-a-channel form is schema-driven off python3 -m librefang.sidecar.adapters.<name> --describe, probed at boot by routes/sidecar_describe.rs::describe_sidecar — and that probe spawned the interpreter with a bare Command::new, no embedded-SDK injection.

Result on any host without pip install librefang-sdk:

  • --describe fails with ModuleNotFoundError: No module named 'librefang';
  • adapters without a hand-maintained static_fields fallback render an empty configure drawer — and that's telegram, ntfy, gotify, mastodon (channels.rs catalog: static_fields: None), i.e. the most common ones;
  • the adapter source was embedded in the binary the whole time; only the describe probe couldn't see it.

Only feishu had a static_fields fallback (which must be hand-synced with the Python SCHEMA and drifts).

Fix

describe_sidecar now injects the embedded SDK exactly like the runtime spawn path, threading the kernel's authoritative home_dir (KernelApi::home_dir(), never a recomputed LIBREFANG_HOME) through populate_sidecar_schema_cache:

  • librefang-channels: export embedded_sdk::pythonpath_with_embedded (pub mod + pub fn); only that one function becomes crate-public.
  • routes/sidecar_describe.rs: describe_sidecar(command, args, home_dir) injects PYTHONPATH before spawning --describe. No-op when a real SDK install already wins (developer editable installs stay authoritative) or for non-Python commands.
  • routes/channels.rs / server.rs: thread kernel.home_dir() to the boot probe.

Now the probe succeeds with just python3 on PATH and the dashboard gets each adapter's authoritative live schema with zero setup. static_fields drops back to a true last resort (no usable python3, or the embedded extract errored).

First-party adapter --describe is dependency-free — stdlib + the embedded librefang.sidecar only; telegram talks to the Bot API over urllib, no python-telegram-bot — so nothing third-party needs installing to populate the form.

Verification (Linux dev container: python3 3.13 present, librefang-sdk NOT installed)

  • cargo test -p librefang-api --test sidecar_describe_test — 5/5 pass. The telegram and feishu probes now succeed and assert their real schema fields (TELEGRAM_BOT_TOKEN, FEISHU_APP_ID, …) instead of skipping with "SDK not installed" — direct end-to-end proof the embedded probe works without pip. The two -c failure-mode tests still surface their errors (injection is a no-op for their assertions).
  • cargo check -p librefang-channels -p librefang-api --lib — clean.
  • cargo clippy -p librefang-channels -p librefang-api --lib -- -D warnings — clean.
  • cargo fmt --check — clean.

Scope

Independent of the goal-runner flake fix (#6083) and the Dependabot bump (#6080). The describe path is the only place that lacked the injection; the runtime spawn path already had it.

The dashboard's Add-a-channel form is schema-driven off
`python3 -m librefang.sidecar.adapters.<name> --describe`, probed once at boot
by `routes/sidecar_describe.rs::describe_sidecar` and cached.
That probe spawned the interpreter without the binary-embedded `librefang-sdk`
on PYTHONPATH — unlike the live channel-spawn path in `librefang-channels::sidecar`,
which has injected the embedded copy since the SDK was bundled.

So on a fresh host with only `python3` and no `pip install librefang-sdk`,
`--describe` failed with ModuleNotFoundError, and every adapter without a
hand-maintained `static_fields` fallback (telegram, ntfy, gotify, mastodon, …)
rendered a blank configure drawer — even though the adapter source ships
embedded in the daemon binary.

`describe_sidecar` now injects the embedded SDK exactly like the spawn path
(`pythonpath_with_embedded`, exported `pub`), threading the kernel's
authoritative `home_dir` through `populate_sidecar_schema_cache`.
The probe now succeeds with just `python3` on PATH and the dashboard gets each
adapter's authoritative live schema with zero setup; `static_fields` drops back
to a true last resort (no usable `python3`, or the embedded extract errored).

First-party adapter `--describe` is dependency-free (stdlib + the embedded
`librefang.sidecar`; telegram talks to the Bot API over urllib), so no
third-party install is needed to populate the form.

Verified in the Linux dev container (python3 present, librefang-sdk NOT
installed): `sidecar_describe_test` telegram/feishu probes now succeed and
assert their real schema fields instead of skipping; check + clippy clean.
@github-actions github-actions Bot added size/M 50-249 lines changed area/docs Documentation and guides area/channels Messaging channel adapters labels Jun 11, 2026
claude and others added 2 commits June 11, 2026 11:34
Four comment blocks added or modified by the sidecar-describe PR violated
the "never write multi-line comment blocks — one short line max" and
"never write multi-paragraph docstrings" rules in CLAUDE.md:

- sidecar_describe.rs: 10-line // block explaining PYTHONPATH injection → 1 line
- sidecar_describe.rs: 3rd doc-comment paragraph on describe_sidecar → merged
  as a single trailing sentence on paragraph 2 (no blank /// separator)
- sidecar_describe_test.rs: 5-line // comment in telegram test → removed
  (the test name and code already make the intent clear)
- server.rs: 7-line // block around populate_sidecar_schema_cache call
  (modified by the PR) → 1 line
The `static_fields` doc still said `--describe` fails / the form stays empty without `pip install librefang-sdk`.
That stopped being true once `describe_sidecar` started injecting the embedded SDK: a `python3`-only host now gets the adapter's live schema, and `static_fields` is consulted only when the probe fails outright (no usable `python3`, or the embedded extract errored).
@houko
houko enabled auto-merge (squash) June 11, 2026 11:48
@houko
houko merged commit 7abe735 into main Jun 11, 2026
31 checks passed
@houko
houko deleted the fix/sidecar-describe-embedded-pythonpath branch June 11, 2026 12:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/channels Messaging channel adapters area/docs Documentation and guides size/M 50-249 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants