Skip to content

docs(plugins): plugin documentation brought up to date (accounts boundary, auth_provider, multi-repo ids, real doc links) - #47

Merged
tajanthind merged 2 commits into
mainfrom
docs/plugin-auth-contract
Sep 10, 2026
Merged

tajanthind merged 2 commits into
mainfrom
docs/plugin-auth-contract

Conversation

@tajanthind

@tajanthind tajanthind commented Sep 10, 2026 •

Copy link
Copy Markdown
Owner

Rebased onto main after #46 merged (resolves the conflict in tests/architecture/test_accounts_first_run.py — both tests kept) and expanded into a proper documentation update.

1. Fixes the merge conflict

#46 and this branch both edited tests/architecture/test_accounts_first_run.py; the rebase keeps both the healthcheck test and the new plugin-context test, both registered in __main__.

2. Answers "do plugins have access to accounts? can a plugin log users in via API?"

  • No account access. There is no context.accounts facade. PluginContext exposes exactly library, settings, events, http, fs, ui, jobs, log — no user list, no password verification, no roles. Reaching around it would mean importing models/services.accounts, which the plugin boundary forbids.
  • Yes, a plugin can authenticate users via the auth_provider type: authenticate(request_headers) -> Optional[str]. Core calls enabled providers on every request with no session and no valid M2M key; returning a username authorizes the request. Clients can therefore "log in via API" by sending the plugin's own header credential (this is how fnack.reverse-proxy-auth works). Limits: the identity is opaque — no User row, no role, no account management, not shown in the UI chip; the provider check runs before the first-run /setup gate (deliberate for SSO).
  • plugins/base.py: AuthProviderPlugin docstring updated (it still said "do not implement until core auth is stable").
  • docs/plugins/AUTHORING.md: new §4 subsection "Can a plugin authenticate users? (auth_provider)" with a code example.
  • New test pins the boundary: PluginContext has exactly the eight facades (accounts/users/auth/login/password/roles/current_user must not exist) and authenticate takes headers only.

3. Repoints documentation at files that actually exist

The author guide and core comments referenced PLUGIN_ARCHITECTURE.md and INTEGRATION.md — neither exists in this repo. Fixed in docs/plugins/AUTHORING.md, plugins/registry.py, plugins/manager.py, plugins/api.py, app.py, services/queue_service.py, tests/run_smoke_test.py. Historical wayfinder/ tickets/research keep their original references — they are records of what was planned at the time.

4. Documents the shipped contract for plugin authors

  • §3 server_extension: routes are authenticated like every other route (accounts session, or the M2M X-API-Key for machine clients; Open_PATHs listed) — you cannot host your own unauthenticated login endpoint; use auth_provider.
  • §7 Versioning: states the current plugin API (1.0.1) and that ^1.0 covers minor bumps.
  • §8 Publishing: new "Your id is not globally unique (multi-repository rules)" — one marketplace entry per (repository, plugin), "Also in: …" duplicate warnings, installs record their source repository and are refused when ambiguous, switching source is explicit, plus the reverse-DNS recommendation.
  • §9 Trust model: fnack requires a login; plugins have no access to accounts.

Verification

  • Architecture suite 27/27 pass; smoke test passes; doc-gate, plugin-boundary and accounts test files pass; code-fence balance checked. CI: smoke-test + build-and-push both SUCCESS.

…s through auth_provider

Answers the recurring design question in code + docs:

- plugins/base.py: AuthProviderPlugin docstring no longer says "do not
  implement until core auth is stable" — core accounts ARE stable now. It
  documents the real contract: core calls authenticate(request_headers) only
  for requests without a session or M2M key, the returned username is an
  opaque identity that does NOT become a User row (no role, no account
  management).
- docs/plugins/AUTHORING.md: the auth_provider type row now describes the
  implemented interface, and a new subsection "Can a plugin authenticate
  users?" explains: there is no context.accounts facade (no user list, no
  password verification, no role management); a plugin CAN act as an
  authentication source so clients "log in via API" by sending the plugin's
  own header credential — every /api/* route is then allowed; provider
  identities get no User row/role/account UI; ordering (session -> M2M key ->
  providers) and the deliberate fact that the provider check precedes the
  first-run /setup gate; and that a plugin's server.extension routes are not
  open paths, so auth must go through authenticate().
- tests/architecture/test_accounts_first_run.py: new test asserts
  PluginContext exposes exactly the eight documented facades (no accounts,
  users, auth, login, password, roles, current_user) and that the
  auth_provider hook takes headers only.
…urrent contract

The author guide and core comments pointed at `PLUGIN_ARCHITECTURE.md` and
`INTEGRATION.md` — neither file exists in this repo (the design record lives
in docs/architecture.md and wayfinder/). Every non-historical reference is
repointed at a real document:

- AUTHORING.md header -> docs/architecture.md + wayfinder/plugin-architecture-map.md
- plugins/registry.py -> AUTHORING.md §8 (repository index shape)
- plugins/manager.py, app.py, services/queue_service.py, plugins/api.py,
  tests/run_smoke_test.py -> real descriptions instead of nonexistent sections

Documentation brought up to date with the shipped contract:

- §3 server_extension: routes are authenticated like every other route
  (accounts login; machine clients use the M2M API key; Open_PATHs listed);
  you cannot host your own unauthenticated login endpoint — use auth_provider.
- §7 Versioning: states the current plugin API (1.0.1) and that ^1.0 covers
  minor bumps.
- §8 Publishing: new "Your id is not globally unique" section — one
  marketplace entry per (repository, plugin), "Also in:" duplicate warnings,
  installs carry the source repository and are refused when ambiguous,
  switching source is explicit, reverse-DNS recommendation.
- §9 Trust model: fnack requires a login; plugins have no access to accounts.

(historical wayfinder tickets/research keep their original references — they
are records of what was planned at the time.)
@tajanthind
tajanthind force-pushed the docs/plugin-auth-contract branch from 8102790 to 88577a0 Compare September 10, 2026 01:55
@tajanthind tajanthind changed the title docs(plugins): plugins cannot access accounts — auth goes through auth_provider docs(plugins): plugin documentation brought up to date (accounts boundary, auth_provider, multi-repo ids, real doc links) Sep 10, 2026
@tajanthind
tajanthind merged commit 5a19847 into main Sep 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant