the clever type cost twelve errors; the untested rule was the load-bearing one
four fixes from a review, and the first one was leaking out of the plugin. TYPING. `respond` derived its context from `Parameters<typeof router.get>[1]`. hono's .get is overloaded, `Parameters<>` resolves the FIRST overload — `[path: string]` — so index 1 was `undefined`, ctx was `never`, and all nine handlers errored. twelve errors from one line, in a tree where `bunx tsgo` is shared with the platform and expected clean. imports hono's `Context` instead. tsgo now exits 0 tree-wide, which it has not done since this plugin landed. READONLYWRITES. `/_config/test` was declared as a read-only write so a member would not meet a 403 on the test button. they always would: authorize.ts asks isOwnerOnlyRoute before isRequestAllowedAtLevel, and ownerOnly is prefix matched, so `/_config` already covered it and the entry was inert. removed, and the reason it SHOULD be inert written down — that request carries the admin secret in its body, so a member who could call it would hold an oracle pointed at somebody else's password. STATUS WROTE ON EVERY POLL. recordProbe ran unconditionally on a GET whose own comment invites polling, so a read endpoint issued an UPDATE per poll per open panel. the probe is cached 30s and the row is written only when the verdict or the version changes — a flapping NPM still records every transition, which is the case the column exists for. the cache is dropped when the credential does. DEAD TERNARY. `likelyAuth ? 502 : 502`. and the tests. 22 over a stubbed fetch, 99% of npm-client.ts. the two that matter are the 404-means-credential rule and the mint-once-and-retry: both are silent when broken, and a refactor of either turns a working panel into one that says "not found" forever. every test uses its own credential because the token cache is module state — sharing one would let an earlier test's token satisfy the retry test, which would then pass for the wrong reason. still not installed, still no settings form, still no db:push. README says so. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
Nginx Proxy Manager inside Officer — which hosts are running, whether they are healthy, and which
|
||||
certificates are about to expire.
|
||||
|
||||
**Status: first round. Reads work against a live NPM 2.15.1; the settings form is not built yet** —
|
||||
see "What is not built" below.
|
||||
**Status: first round. Reads work against a live NPM 2.15.1; the settings form is not built and the
|
||||
plugin is not installed** — see "What is not built" below.
|
||||
|
||||
---
|
||||
|
||||
@@ -57,6 +57,12 @@ for, and the same shape Jellyfin uses for its admin token.
|
||||
**The secret is never returned across the API boundary**, at any level, to anybody, including the owner.
|
||||
A settings form asking "is one set" gets a boolean.
|
||||
|
||||
`POST /_config/test` is owner-only too, and that is on purpose rather than by accident of the prefix
|
||||
match. It is a genuine read-only write — it validates a credential and stores nothing — but the request
|
||||
carries the admin secret in its BODY, so a member who could call it would have an oracle pointed at
|
||||
somebody else's password. Testing a connection belongs to whoever owns it. (Declaring it in
|
||||
`readOnlyWrites` would also have done nothing: `authorize.ts` asks `isOwnerOnlyRoute` first.)
|
||||
|
||||
---
|
||||
|
||||
## The connection
|
||||
@@ -89,7 +95,10 @@ endpoint"* are the same response. Left alone that produces the worst kind of bug
|
||||
reads as missing when the credential is simply wrong.
|
||||
|
||||
So `npm-client.ts` treats a 404 on a path it knows exists as an authentication failure, carries that as
|
||||
`NpmError.likelyAuth`, and the panel turns it into a sentence pointing at settings. It also mints a fresh
|
||||
`NpmError.likelyAuth`, and the panel turns it into a sentence pointing at settings. Both halves of that
|
||||
— the rule and the single retry — are the plugin's most load-bearing behaviour and its only tested one:
|
||||
`api/npm-client.test.ts` covers them against a stubbed fetch, because a refactor of either fails silently
|
||||
and turns a working panel into one that says "not found" forever. It also mints a fresh
|
||||
token and retries once before concluding anything — otherwise a restarted NPM makes every panel look
|
||||
broken until a reload.
|
||||
|
||||
@@ -105,17 +114,21 @@ Verified against the live instance: a wrong credential comes back `likelyAuth =
|
||||
renders it yet, so the connection has to be inserted by hand for now.
|
||||
- **`db:push` has not been run**, so `proxy_manager_connection` does not exist in Postgres yet.
|
||||
- **Redirections, streams, 404 hosts and access lists** have routes and no panels.
|
||||
- **Nothing is polled.** Both panels load once and have a refresh button.
|
||||
- **No tests.** The client's behaviour was verified by hand against the live NPM; that should be a test
|
||||
with a stubbed fetch.
|
||||
- **Nothing is polled.** Both panels load once and have a refresh button. `GET /status` is built to be
|
||||
polled when something does: the probe is cached for 30 seconds and the row is written only when the
|
||||
verdict or the version changes, so a poll is not an UPDATE.
|
||||
- **It is not installed.** `plugin_installs` has no row for it and `proxy_manager_connection` does not
|
||||
exist in Postgres, so nothing here has been through the permission gate, `assertPermissionTotality` or
|
||||
a real request. The reads were verified by direct invocation against a live NPM 2.15.1.
|
||||
|
||||
---
|
||||
|
||||
## Files
|
||||
|
||||
```
|
||||
manifest.ts permission, ownerOnly, readOnlyWrites
|
||||
manifest.ts permission, ownerOnly
|
||||
api/npm-client.ts tokens, the 404 quirk, retry
|
||||
api/npm-client.test.ts 22 tests over a stubbed fetch
|
||||
api/connection.ts the one row; encryption; the secret never leaves
|
||||
api/router.ts mounted at /api/proxy-manager
|
||||
db/schema.ts proxy_manager_connection
|
||||
|
||||
Reference in New Issue
Block a user