Skip to content

feat(extensions): add private SilverBullet Markdown workspace - #5155

Closed
tang-vu wants to merge 2 commits into
Osmantic:public-betafrom
tang-vu:feat/beta-silverbullet-local-markdown-20260915
Closed

tang-vu wants to merge 2 commits into
Osmantic:public-betafrom
tang-vu:feat/beta-silverbullet-local-markdown-20260915

Conversation

@tang-vu

@tang-vu tang-vu commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Why this matters

ODS gains a private, programmable Markdown workspace whose pages and binary attachments remain ordinary local files. SilverBullet's empty-folder default now selects a multi-space setup wizard; this recipe explicitly selects single-space mode with required credentials so an optional extension install produces the intended private workspace immediately.

The invariant is that unauthenticated callers cannot list, read or mutate notes, valid browser sessions and bearer clients share the same persisted space, and rotating credentials revokes both old sessions and API access without losing data.

Production contract

Authenticated Extensions install copies the exact recipe and prepares data/silverbullet for UID 1000. The digest-pinned 2.10.0 image starts under its native tini, with a small guard validating both required credentials before exporting native SB_USER/SB_AUTH_TOKEN. The server receives an explicit --single /space. The manifest and Docker healthcheck use public /.ping availability; the image's default /.instance health probe is replaced for this deliberate single-space deployment.

The published port defaults to loopback and honors BIND_ADDRESS. The server has a read-only root, limited writable space/tmpfs, no capabilities or Docker socket, disabled native shell backend and disabled headless runtime. Browser-side scripting and authenticated upstream HTTP proxy functionality remain available: this is a trusted-user programmable workspace, not a hostile-content sandbox. The native HTTP file API and sign-in implementation remain responsible for sessions and persistence.

Stop the service and cold-copy the full data directory including hidden metadata plus credentials for backup. Restore with the matching pinned image and UID 1000. Rotate both .env credentials and recreate to revoke old access; browser cookies are scoped to host and port, so changing the origin requires signing in again. Removing the extension can retain data; deleting storage is separate. Do not assume database/metadata downgrade compatibility. README covers browser-local sync copies, HTTPS requirements, full-power bearer tokens and rollback.

Overlap check

All-state upstream searches for SilverBullet and Markdown workspace plus changed-production-file indexes for ods/extensions/library/services/silverbullet returned no existing implementation (2026-09-15). Existing Memos #4887, HedgeDoc #4990 and Trilium #5013 provide different upstream applications/storage and do not implement SilverBullet's single-space file/sync contract. Shared .env/schema/catalog edits are additive; independent branch based on public-beta 33155fb, with no dependency on other recipes.

Remaining limits

Browser visual/offline conflict behavior, external TLS, native macOS/Windows installation, multi-space accounts, runtime API, Git synchronization and version upgrades are not qualified. Plain loopback HTTP and the shared Docker network are trusted boundaries; Docker/.env administrators can read credentials. API tokens grant full workspace write access. Server data is not encrypted by this recipe, and uninstall cannot erase browser sync copies.

Exact upstream references: Dockerfile, HTTP API, native authentication hash.

Host publication

The published ports honor ODS BIND_ADDRESS: unset keeps 127.0.0.1; the
explicit LAN opt-in can select 0.0.0.0 or a specific host interface. This
controls Docker publication and preserves native authentication and application
policy. Disable/recreate after changes, and keep operator edits to the installed
definition backed up before updating or reinstalling the extension.

Remote browsers need an HTTPS origin for service-worker functionality.
Publishing an HTTP port on the LAN does not provide that secure browser context.

Compose regression tests cover unset, loopback, wildcard and a specific interface
while preserving target ports, credentials and storage. Actual lifecycle fixtures
remain bound to isolated loopback ports. Remote browser/TLS deployments are not
qualified by those local tests.

Regression tests and validation

Current candidate 7686720, Linux/amd64 Docker Desktop / WSL Ubuntu:

  • ODS_TEST_SILVERBULLET=1 python -m pytest tests/test_silverbullet.py -q --tb=short: 19 passed in 99.33s on this exact head. Native login cookie and file sync, Unicode pages and binary attachments, shell denial, recreation, rejection of old password/API token/session after rotation, and cold restoration with byte-exact files. All test-owned resources were cleaned up.
  • Four Compose boundary cases cover unset BIND_ADDRESS, explicit loopback, wildcard and a specific interface. Before the fix, both non-loopback cases failed; they now pass while target ports, native environment and storage remain unchanged. Actual HTTP/SMTP fixtures remain isolated on loopback; this does not qualify a remote browser/TLS deployment.
  • Changed-file secret/private-key/large-file hooks, git diff --check and bash tests/test-bind-address-sweep.sh: passed. The binding follow-up changes only publication, its regression tests and operator documentation.
  • Full combined API/UI and root contract receipts are tracked on integration/beta-quality40-20260915. The complete Makefile audit also exposed baseline no-sudo installer fixtures, Windows PowerShell environment handoff on this WSL host and root-permission macOS fixtures. Baseline BATS has five identical failures; all-file private-key scanning flags pre-existing test marker strings. These are recorded separately and a fully green local gate is not claimed.

The integration audit caught the original fixed binding before batch completion. This follow-up preserves the established ODS LAN opt-in contract, keeps loopback as the default and retains native host/origin/authentication policy. The original isolated checks did not detect that repository-level publication mismatch.

Merge independently into public-beta, preserving every additive environment/schema/catalog entry. Application-specific native limits and recovery are documented above and in the README; browser/TLS deployments, native platform hosts and upgrades remain unqualified unless a specific receipt says otherwise. This batch does not merge upstream.

Final combined receipt and review status

Ready for review at the 2026-09-15T08:28:06.7269998+00:00 snapshot; the candidate remains 768672004c3d0f40191a07129226a565839b127b. GitHub: 32 successful checks, 4 conditional skips, none failed or pending.

The versioned 40-PR compatibility receipt records every candidate SHA, merge order, shared-file resolutions, pairwise comparisons and remaining gates. All 40 candidates are ancestors of tested integration a72e15781e4f41c3bd81f3b7f27f5b0fc5503a63: 2,997 API tests passed (3 skipped), 1,134 UI tests passed, 247 changed root contract tests passed (28 opt-in skips), and all four smoke paths passed. The full Makefile audit passed 84/87 suites; the three failures reproduce on the unchanged base. Simulation correction: the wrapper exits 0 but its artifact records 3/4 golden paths passed; Linux NVIDIA stops at the root-user guard, reproduced on the unchanged base. This supersedes any earlier simulation-pass wording. BATS and all-file private-key baseline failures are also documented, so a fully green local gate is not claimed.

The receipt supersedes provisional batch-validation wording above, while preserving the candidate-specific tests and their stated limitations. Integration results do not substitute for unexecuted native platform, hardware, browser, upgrade or host-agent lifecycle probes. Ready status permits review; independent human review and every declared live/operational gate still apply. No upstream merge or deployment has been performed.

@tang-vu tang-vu closed this Oct 4, 2026
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