Skip to main content

Gonic

@magistr/gonicv2026.08.19.1· 23d agoMODELS
01README

Gonic Subsonic-compatible music server API for swamp — browse, search, stream, and scrobble against the Subsonic REST API, manage podcasts, and drive library scans.

Model:

  • @magistr/gonic — connectivity ping plus podcast management (list, refresh, delete channel/episode, trigger download), library scan status and rescan, and playlist listing over the Subsonic REST API. Also offers direct SQLite maintenance helpers over SSH (read-only query, write exec, and ensure-podcast-dirs) for the underlying gonic.db.

The Subsonic password is marked sensitive so it is never persisted in cleartext; database access uses non-interactive SSH (BatchMode) so it never blocks on a prompt.

02Models1
@magistr/gonicv2026.08.19.1extensions/models/gonic.ts

Global Arguments

ArgumentTypeDescription
hoststringGonic host (IP or hostname)
portnumberGonic HTTP port
usernamestringSubsonic API username
passwordstringSubsonic API password
sshUserstringSSH user for DB access
dbPathstringPath to gonic.db on the host
fn ping()
Test connectivity to the Gonic server

Resources

podcasts(infinite)— Podcast channels with episodes
scanStatus(infinite)— Library scan status
playlists(infinite)— Playlist summaries
serverStatus(infinite)— Server status info
dbResult(infinite)— Database query result
03Previous Versions4
2026.08.02.1

2026.08.02.1

Real-fixes the six remaining open findings tracked by the local gonic-latent-bugs issue-lifecycle model (LB3, LB4, LB5, LB7, LB8, LB9) — every one of these was previously characterized/PINNED as buggy behavior; this release closes each of them and flips its pin to "fixed". LB1/LB2/LB6 (fixed in 2026.08.01.1) are untouched and stay green.

  • LB3 — db-query now REALLY enforces read-only, FIXED. sshExecSql gained a readOnly parameter; db-query passes readOnly: true, so the command line is sqlite3 -json -readonly '<dbPath>' (precedent: music-library's sqlite3 -json -readonly). A mutating statement is rejected by sqlite3's own read-only connection (non-zero exit, "attempt to write a readonly database") — stronger than SQL-string sniffing. db-exec and ensure-podcast-dirs are unaffected (readOnly defaults to false).
  • LB4 — db-exec's change-count is now connection-scoped, FIXED. The write and SELECT changes() now run as ONE combined statement (<sql>;\nSELECT changes();) on a SINGLE sshExecSql session, instead of two separate sqlite3 connections. The reported count is parsed from that session's own trailing output line, so it is structurally derived from the write's real effect. On a failing write, sqlite3's non-zero exit (LB8) makes sshExecSql throw before any count is reported — no bogus count on failure.
  • LB5 — network-error credential redaction, FIXED. gonicApi now wraps await fetch(url) in a try/catch (precedent: telegram-send's redactToken/redactedCause). A rejection is rethrown via redactSecret, which redacts the raw password AND its hex encoding (plus a generic enc:<hex> backstop) from the WHOLE error — message, cause, and cause's .stack — not just .message. The !resp.ok and failed-envelope throws stay OUTSIDE the try/catch, so the "full body verbatim" pins are unchanged.
  • LB7 — dbResult name clobber, FIXED. A module-level monotonic counter (dbResultTag()) is appended to the full ms+Z timestamp for all three name builders (dirs-, query-, exec-), so two calls within the identical wall-clock instant (even under a frozen Date in tests) get DISTINCT resource names instead of clobbering.
  • LB8 — sshExecSql no longer swallows warning-only stderr failures, FIXED. When !output.success, it now always throws — using the warning-filtered realErrors when non-empty, else falling back to raw stderr/stdout/"unknown error" — so a success: false result whose stderr contains ONLY an SSH "Warning: Permanently added..." line is surfaced instead of silently treated as success. The real-error case (realErrors non-empty) is byte-identical to before.
  • LB9 — README doc drift, FIXED. The instance example's typeVersion now reads 2026.08.02.1 instead of the stale 2026.05.25.1.
  • Model version and manifest.yaml bumped to 2026.08.02.1 (kept in sync); added an identity no-op upgrades[] entry (toVersion: "2026.08.02.1") — none of LB3-LB9 change globalArguments or any resource schema.
  • Test flips (characterization → fix-verification), all in extensions/models/:
    • gonic_adversarial_test.ts: (b) the HONEST-GAP fetch-rejection pin now asserts REDACTION (no sentinel password/hex in message, cause, or stack; <redacted> marker present); (e) the db-query "no read-only guard" pin now asserts -readonly on the command line AND a real, non-vacuous sqlite3 rejection of a DELETE; (f) the db-exec change-count pin now asserts a SINGLE combined invocation whose reported count derives from its own connection; (d2) the LB6 dbPath-escaping pin's expected command line absorbs the new -readonly token (and its slice prefix), with the POSIX-grammar assertion kept intact; (h) the dbResult name-clobber pin now asserts DISTINCT names under a frozen Date, matching the new ms+Z+counter-suffixed regex. (g) hostile-Subsonic-response pins are unrelated and stay unchanged.
    • gonic_coverage_test.ts: the db-query/db-exec command-line guard now expects -readonly on db-query and a single db-exec invocation (dropped the third command-line assertion); the warning-only-stderr guard flips from "SWALLOWS" to "SURFACES" (now asserts a throw); the real-error guard is unchanged; the NaN/007 parseInt fallback guards are rerouted to the single combined invocation (same assertions, one stub call instead of two).
    • gonic_methods_test.ts: db-query's happy-path command-line assertion gains -readonly; db-exec's happy path and error path are rewritten from "two

Notes trimmed at a line boundary to fit the registry's 4900-byte per-version cap. Full section: https://github.com/umag/swamp-workspace/blob/d850d8e8372d4c0008c9245959a090b37095de7a/gonic/CHANGELOG.md

2026.08.01.1

2026.08.01.1

Fixes the two HIGH-severity findings tracked by the local gonic-latent-bugs issue-lifecycle model (never filed against the Lab — see that model for full detail and the deferred MED/LOW findings, which are unchanged and stay pinned).

  • HIGH — command injection, FIXED. ensure-podcast-dirs now quotes the DB-sourced root_dir/host-mount path with a shellEsc helper (copied verbatim from firecracker/extensions/models/firecracker.ts: wrap in single quotes, escape each embedded ' as '\'') before interpolating it into mkdir -p <hostDir>. Applied to sshExecSql's dbPath interpolation in the same change (smaller blast radius — operator-controlled config, not live DB content — but trivially shared hardening). mkdir runs on the REMOTE gonic host over SSH, so Deno.mkdir is not a substitute for this fix.
  • HIGH — URL-query credential leak, FIXED. buildAuthParams no longer sends p=enc:<hex(password)> (a trivially-reversible encoding) as a URL query parameter. It now generates a random per-request salt (crypto.getRandomValues), computes a Subsonic TOKEN t = md5hex(password + salt) via jsr:@std/crypto (MD5 is absent from Deno's native WebCrypto subtle.digest), and emits u, t, s, v, c, fp is dropped entirely. gonic's server fully supports this scheme (ctrlsubsonic/ctrl.go's checkCredsToken); see the corrected auth-reality note in Unreleased above. buildAuthParams is now async; gonicApi awaits it.
  • Added jsr:@std/crypto@1 to deno.json imports; regenerated deno.lock under deno 2.8.3.
  • Model version and manifest.yaml bumped to 2026.08.01.1 (kept in sync).
  • Test flips (characterization → fix-verification), all in extensions/models/: the enc-hex recovery pin and the mkdir-injection pin in gonic_adversarial_test.ts now assert the FIX (no p param / password not recoverable; the injected ' is neutralized rather than breaking out); the u/p assertion in gonic_methods_test.ts now asserts t/s (the u/v/c/f assertions are unchanged); the three enc-hex relation/recovery/collapse properties in gonic_property_test.ts collapse into one token-auth invariant (p absent, s hex-shaped, t recomputed as md5hex(password + the emitted per-request salt) — necessarily derived from the captured salt, since the salt is random). Every other pinned characterization test (db-query not-read-only, db-exec change-count, fetch-rejection honest gap, domain-error non-leak, dbResult name clobber, sshExecSql warning-swallow, fixtures-secret-scan, and every quote-free happy-path mkdir/sqlite3 command-line assertion) is unchanged and stays green — shellEsc on a quote-free input is byte-identical to the old bare single-quoting.
  • Out of scope, deferred as before: db-query's missing read-only guard, db-exec's structurally-disconnected change-count, the fetch-rejection honest gap, the dbResult name clobber, sshExecSql's warning-swallow, and the stale README typeVersion. Token auth over http:// still permits passive replay of a captured t+s pair for that one salt — it does not expose the password; forcing https:// is out of scope.
2026.07.16.2

Release 2026.07.16.2 — align model versions with manifests

Maintenance release across the @magistr extensions. For most packages this carries no functional change: the only edit is the model's version: field, brought back in line with its manifest version so the published model type version and the package version no longer drift.

Functional changes in this release are limited to:

  • anime-cron: normalizeTitle now strips a ": subtitle" suffix and a trailing parenthesized year before comparison, fixing dedup false-misses where the torrent title carries a subtitle or year that the AniList romaji does not.

  • arckit: first publish. Standalone ArcKit port — a 12-phase architecture governance state machine with 65 bundled templates, driven by a bundled skill.

Also tracks three extensions (kaiten, observability-agent, music-library) that previously existed only as untracked working-tree directories, recovered from stashes.

2026.05.25.1

Merge pull request #5 from umag/extensions/jscad-stl-pair

extensions: add 15 more @magistr extensions + auto-discover CI

04Stats
A
100 / 100
Downloads
6
Archive size
90.9 KB
  • Has README or module doc2/2earned
  • README has a code example1/1earned
  • README is substantive1/1earned
  • Most symbols documented1/1earned
  • No slow types (deprecated)1/1earned
  • Dependencies pass trust audit2/2earned
  • Has description1/1earned
  • Platform support declared (or universal)2/2earned
  • License declared1/1earned
  • Verified public repository2/2earned
05Platforms
06Labels