Commit graph

279 commits

Author SHA1 Message Date
Anish Sarkar
f40856b82d test(docker): the architecture check accepts install.ps1's wording 2026-10-28 21:30:57 +05:30
Anish Sarkar
e1ae146182 feat(docker): one-line installers that install and update the image 2026-10-28 20:57:18 +05:30
Anish Sarkar
229076cee6 fix(docker): the dev stack opens on any host name the access service allows
Vite serves only localhost and IPs, so Caddy hands it localhost; hot reload
goes through the same rewrite.
2026-10-28 19:19:13 +05:30
Anish Sarkar
259ffbfcf3 docs(docker): the Docker proposal becomes architecture/docker.md
The CPU image is built, so what is true now moves from the proposal into
docs/architecture/docker.md, written from the code: the container, the
entries, Caddy and HTTPS, the frontend without Electron, sign-ins, the
image, Compose, the dev stack, CI and releases, with what is not built as
Known gaps. The GPU images, not built, stay a proposal, as
proposals/docker-gpu.md. Every link and code comment that named the
proposal points at the new doc.
2026-10-28 18:28:54 +05:30
Anish Sarkar
c3d0cf73df feat(docker): the dev stack opens to the machine's networks, as the install does
It published on 127.0.0.1 only, so testing from a phone needed an override
to remember, and dev behaved unlike a real install. Both ports default to
0.0.0.0 now; SURFSENSE_BIND=127.0.0.1 keeps it to the machine. The commands
list says which port each answers on.
2026-10-28 18:17:13 +05:30
Anish Sarkar
4bd584f869 feat(docker): every instance has a password, set up on first visit, and opens to the server's networks
Sign-in is always on. Whoever opens a new instance first creates its
password, from any browser, with one field and an eye, as Immich and Open
WebUI have their first account. SURFSENSE_PASSWORD presets it, and the app
shows a password set there locked; without the variable it becomes the
app's to change. SURFSENSE_AUTH=none turns sign-in off for a server whose
own proxy or VPN decides who reaches it.

Compose now publishes on every network the server is on, so phones and
laptops reach a fresh install at once. docs/architecture/docker-access.md
holds every case, from a home server to a public domain.
2026-10-28 18:12:19 +05:30
Anish Sarkar
e5cbf7d81a feat(docker): a dev stack runs the image with the checkout mounted in
docker/surfsense/dev/compose.yml runs the image's new `app` stage, everything
but the SPA, with the source mounted over it, on 127.0.0.1:4930 beside a real
install on 4929. Vite runs as its own service and Caddy proxies the SPA's route
to it, so the frontend hot-reloads; under --watch a backend, sidecar, entry or
Caddy change restarts the app container in a few seconds instead of a rebuild.

The SPA's route moves into caddy/spa.caddy, the one file the dev stack replaces;
the shipped image is unchanged and passes image.test.ts.
2026-10-28 04:46:48 +05:30
Anish Sarkar
36ddda54e5 fix(docker): the image carries what Office support's LibreOffice links against
TDF's Linux build, unpacked into /data, could not start: a minimal Ubuntu
lacks NSS, D-Bus, cairo, GLib, CUPS, a few X11 libraries and any font.
The image installs them, about 21 MB, found by converting in throwaway
containers until it worked, and an image test checks they are present.
2026-10-28 03:14:33 +05:30
Anish Sarkar
a43fb2a383 feat(docker): HTTPS for a LAN name or a public domain
SURFSENSE_TLS=internal serves each allowed host under Caddy's own
certificate authority; SURFSENSE_DOMAIN gets a Let's Encrypt certificate.
The headless entry picks the Caddyfile and refuses, at start, a setting
it cannot serve. Both share one set of routes, and Compose publishes 443
on SURFSENSE_HTTPS_PORT. The API learns the public domain, for plugin
sign-ins there.
2026-10-28 01:43:04 +05:30
Anish Sarkar
d11955d1ee feat(docker): the image runs llama.cpp, sd.cpp and audio.cpp on the CPU
The desktop's staging scripts take --out, and llama.cpp's and sd.cpp's
--variant cpu, so the image stages each runtime from the same source:
llama.cpp from upstream's CPU build, sd.cpp compiled without Vulkan,
audio.cpp as the desktop's Linux build. The bundled Kokoro voice ships
too, so podcasts work from the first start.
2026-10-28 01:42:56 +05:30
Anish Sarkar
8361bc650e feat(docker): an access service behind Caddy signs browsers in
headless/access/ answers Caddy's forward_auth for every request, and the
app's /access/* routes. One password per instance, scrypt-hashed in
/data/access.json; sessions are HMAC-signed HttpOnly, SameSite=Strict
cookies, Secure over HTTPS, that a password change ends; five wrong tries
a minute per client answer 429; sign-in and sign-out refuse another site's
Origin. Without a password only the host is answered, by its Host and by
the client address Caddy sees. SURFSENSE_PASSWORD sets the password at
start and reaches no sidecar; SURFSENSE_ALLOWED_HOSTS limits the hosts;
SURFSENSE_BIND returns to compose. access.caddy replaces access-local.caddy.
The image tests start a second container with a password and check the
sign-in through Caddy, a forged X-Forwarded-Host included.
2026-10-27 23:01:30 +05:30
Anish Sarkar
a105de3247 fix(docker): publish on loopback only until the image takes a password
A Host header is the sender's to choose, so Caddy's local-only check stops
a browser on the LAN and DNS rebinding, not a client that sends
Host: localhost. With SURFSENSE_BIND widening the port, an instance with no
password was reachable that way. Compose now publishes on 127.0.0.1 only;
SURFSENSE_BIND returns with the password in step 10.
2026-10-27 21:52:18 +05:30
Anish Sarkar
c755e9a735 fix(docker): Claude Code installs where the backend looks for it
docker compose exec ran with HOME=/home/surfsense, so the dialog's install
command put Claude Code outside the volume, where the backend, on
HOME=/data/home, never found it and an image update lost it; and the image
had no curl, while the pipe still exited 0. The image now sets HOME on
/data for every process with its .local/bin on PATH, ships curl, and the
command runs under bash with pipefail.
2026-10-27 21:52:03 +05:30
Anish Sarkar
1fb84ef570 ci: keep caches for dev, build the image from GHCR, run unit tests in parallel
uv and pnpm caches are restored everywhere but saved only by dev pushes, so
pull request and tag caches, never reused, stop pushing dev's out of the
repository's 10 GB. pnpm comes from pnpm/setup, which can restore without
saving, as setup-node cannot. The image's build cache moves to GHCR, which
every branch, pull request and tag can read: dev pushes and release tags
write it, pull requests never do. Backend unit tests run one worker per
core with pytest-xdist and list the slowest; integration tests stay serial
until the ones that clash in parallel share an xdist_group. One test named
its parameters by a PDF's bytes, whose ID differs per worker; it names them
by file now.
2026-10-27 20:59:42 +05:30
Anish Sarkar
0b57a8653f ci(docker): test the Docker entry, the image and the backend inside it
headless/ becomes its own package, typechecked and tested in Docker Tests
rather than through Electron's run. image.test.ts replaces smoke.sh: off
unless SURFSENSE_TEST_IMAGE names an image, it checks health through
Caddy, the app and its script, the 403s, a clean stop, and that a new
container on the same /data keeps its secret. Docker Tests adds jobs for
headless, the frontend's docker-tagged tests and the backend's image tests
in the test stage, and checks the compose file; Release Docker runs the
same image tests before it pushes.
2026-10-27 19:23:07 +05:30
Anish Sarkar
9f90e07759 test(backend): an image marker for tests the Docker image changes
Tests whose outcome depends on what the image provides, its user, process
reaping, bundled models and system libraries, carry pytest.mark.image and
still run with the rest. The Dockerfile's backend-tests stage, never
shipped, runs them as uid 1000 under tini on the image's Ubuntu, Python and
models. Four figure-caption tests fail there and on a host given the same
Docling pack; no CI fetched the pack before, so they are strict xfails.
2026-10-27 19:22:40 +05:30
Anish Sarkar
6a4e9fda8b ci(docker): separate the image's tests from its release
As the desktop has desktop-tests.yml and release-local.yml, the image now
has docker-tests.yml, which builds and smokes it on pull requests and dev
pushes and never pushes, and release-docker.yml, which pushes X.Y.Z on a
tag and moves latest and X.Y when the release is published. Both run
docker/surfsense/smoke.sh, which also runs against a local image. dev
pushes no longer publish dev and git-<sha> images.
2026-10-27 18:14:33 +05:30
Anish Sarkar
10ad9b76b7 feat(docker): About shows the image's version
The image has no Electron bridge, so About showed neither the version nor
the release notes link. Its frontend is now built with
VITE_SURFSENSE_VERSION from surfsense_local/VERSION, the one version the
image shares with the desktop app, and a VERSION bump rebuilds the image.
2026-10-27 00:52:50 +05:30
Anish Sarkar
9b418c31b6 feat(feedback): name Docker under Which part?
The bug and feature forms list Docker beside the desktop app, and a report
started from the image, built with VITE_SURFSENSE_RUNTIME=docker, has it
picked already, so the reporter need not choose.
2026-10-27 00:05:13 +05:30
Anish Sarkar
7353fd934e feat(docker): the CPU image, compose and Caddy, with sign-ins on the host
Step 5 of the Docker proposal. docker/surfsense/ builds one image from the
repository root: the backend's venv, the SPA built for /api, opencode, the
bundled embedding, parser and voice-activity models, Node, Caddy and tini,
run as a non-root user over a /data volume. Compose publishes it on
127.0.0.1:4929, apart from the legacy stack's 3929 so both can run while
data moves over.

The headless entry starts Caddy when a Caddyfile is given; Caddy is the one
listener, refuses any host but localhost until a password exists, keeps the
workers' internal routes in, and forwards the sign-in callbacks. Plugin and
ChatGPT sign-ins send the browser back through the published port
(SURFSENSE_LOCAL_PUBLIC_PORT), ChatGPT's listener on a fixed port Caddy
forwards to. In the container the Claude dialog gives the docker compose
commands that install and sign in Claude Code there.
2026-10-27 00:03:22 +05:30
Anish Sarkar
c1a3ba88eb chore(legacy-split): delete the self-hosted stack from dev
The self-hosted stack lives on the legacy branch, released as
legacy-v0.0.41. Delete surfsense_backend/, surfsense_mcp/, docker/
except keygen/ (production's Keygen CE images), the root VERSION and
scripts/bump-version.{sh,ps1}. surfsense_web/ stays until the website
split.
2026-10-24 22:25:41 +05:30
DESKTOP-RTLN3BA\$punk
fb382d6e1b fix(sandbox): bump fast-uri, js-yaml and undici in remotion lockfile
Lockfile-only update of three transitive dependencies of the Remotion
render sandbox (docker/sandbox/remotion). All new versions sit inside the
ranges their parents already declare, so package.json is unchanged and no
overrides are needed.

fast-uri 3.1.5 -> 3.1.8 (via webpack > schema-utils > ajv)
- GHSA-hrr3-gc8f-f4qj, GHSA-qw65-cvwx-89v3, GHSA-5jgf-p345-68v8,
  GHSA-f65p-4m7j-42xc, GHSA-fph4-wmhf-6fwf, GHSA-jqff-g426-hqxp

js-yaml 4.3.1 -> 4.3.2 (via @svgr/core > cosmiconfig)
- GHSA-2883-xcg3-v3hh

undici 6.28.0 -> 6.28.1 (via markmap-lib > cheerio)
- GHSA-r53p-7pc4-xj5r, GHSA-rfgv-xxqx-mfg5, GHSA-3wwx-pv8p-q78v

undici is held at 6.28.1 rather than 6.29.0, which was published less
than seven days ago. Regenerated with npm 11 so the existing libc and
peer metadata in the lockfile is kept; lockfileVersion stays 3.

Nothing deferred.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:23:01 -07:00
Claude
cc8edf87b6
fix(license): refuse trial emails on the disposable-email-domains list
The trial check refused 20 hand-picked domains by exact match, so trial
spam walked around it with any other throwaway provider, any subdomain
of a listed one, or a punycode spelling.

Refuse the community disposable-email-domains list (~9.2k domains, CC0),
installed as its official PyPI package and pinned in uv.lock, plus the
three hand-picked domains it lacks. Match every parent domain short of
the TLD, as upstream requires, and look up the punycode form, since
EmailStr hands the route Unicode. Purchases and resends are unaffected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KrM98FAv8YT3boAVJpf6PW
2026-09-30 23:10:24 +00:00
DESKTOP-RTLN3BA\$punk
a7d797d2c1 chore: point code comments at the moved docs
Comments, docstrings and .env.example notes that cited moved or
deleted plan files now cite their new homes under docs/.

The three llama.cpp checksums in fetch-llamacpp.mjs and a URL-format
example in the backend config are marked `pragma: allowlist secret`.
Touching those files puts them in front of detect-secrets, and both
are false positives.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 21:27:27 -07:00
CREDO23
6295c53120 chore: merge main into dev before the release PR
Some checks are pending
Build and Push Docker Images / build (./surfsense_backend, cu128, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-24.04-arm, linux/arm64, arm64, -cuda, production, true, cuda) (push) Blocked by required conditions
Build and Push Docker Images / build (./surfsense_backend, cu128, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-latest, linux/amd64, amd64, -cuda, production, true, cuda) (push) Blocked by required conditions
Build and Push Docker Images / build (./surfsense_web, cpu, ./surfsense_web/Dockerfile, web, surfsense-web, ubuntu-24.04-arm, linux/arm64, arm64, , runner, false, cpu) (push) Blocked by required conditions
Build and Push Docker Images / build (./surfsense_web, cpu, ./surfsense_web/Dockerfile, web, surfsense-web, ubuntu-latest, linux/amd64, amd64, , runner, false, cpu) (push) Blocked by required conditions
Build and Push Docker Images / compute_version (push) Waiting to run
Build and Push Docker Images / build (./docker/sandbox, cpu, ./docker/sandbox/Dockerfile, sandbox, surfsense-sandbox, ubuntu-24.04-arm, linux/arm64, arm64, , false, cpu) (push) Blocked by required conditions
Build and Push Docker Images / build (./docker/sandbox, cpu, ./docker/sandbox/Dockerfile, sandbox, surfsense-sandbox, ubuntu-latest, linux/amd64, amd64, , false, cpu) (push) Blocked by required conditions
Build and Push Docker Images / build (./surfsense_backend, cpu, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-24.04-arm, linux/arm64, arm64, , production, false, cpu) (push) Blocked by required conditions
Build and Push Docker Images / build (./surfsense_backend, cpu, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-latest, linux/amd64, amd64, , production, false, cpu) (push) Blocked by required conditions
Build and Push Docker Images / build (./surfsense_backend, cu126, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-24.04-arm, linux/arm64, arm64, -cuda126, production, true, cuda126) (push) Blocked by required conditions
Build and Push Docker Images / build (./surfsense_backend, cu126, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-latest, linux/amd64, amd64, -cuda126, production, true, cuda126) (push) Blocked by required conditions
Build and Push Docker Images / create_manifest (backend, surfsense-backend, -cuda126, cuda126) (push) Blocked by required conditions
Build and Push Docker Images / verify_digests (push) Blocked by required conditions
Build and Push Docker Images / create_manifest (backend, surfsense-backend, , cpu) (push) Blocked by required conditions
Build and Push Docker Images / create_manifest (backend, surfsense-backend, -cuda, cuda) (push) Blocked by required conditions
Build and Push Docker Images / create_manifest (sandbox, surfsense-sandbox, , cpu) (push) Blocked by required conditions
Build and Push Docker Images / create_manifest (web, surfsense-web, , cpu) (push) Blocked by required conditions
Build and Push Docker Images / finalize_release (push) Blocked by required conditions
2026-09-18 09:12:52 +02:00
CREDO23
35c83caa82 chore: drop leftover skills, plans, and unused docker extras
Clear the SEO skill dump and shipped-phase plans so they can be rebuilt later. Leave Azure compose (SearxNG, sandbox, zero-cache) and license/export contracts untouched.
2026-09-18 08:51:33 +02:00
DESKTOP-RTLN3BA\$punk
49149ece1d feat(local): more pre release tweaks 2026-09-17 21:19:21 -07:00
CREDO23
c58b4296ac Merge branch 'pr-1777' into sunset-fixes
# Conflicts:
#	surfsense_local/frontend/src/components/ui/icons.tsx
#	surfsense_local/frontend/src/features/updates/update-settings.test.tsx
#	surfsense_local/frontend/src/features/updates/update-settings.tsx
#	surfsense_web/lib/auth-utils.ts
2026-09-17 07:06:57 +02:00
CREDO23
e2c277573f feat(license): send the app download link with the licence, and run trials for 30 days
A trial is handed to an email address, not to an installation, so the email now opens with an install link built from NEXT_FRONTEND_URL. Deployments without a portal keep the original steps rather than printing a dead link.

Trial length moves to 30 days so the week before the first plugin ships does not eat half of it. The number is read from LICENSE_TRIAL_DAYS everywhere, including the subject line and the pricing copy, which previously hardcoded 14.
2026-09-17 04:50:27 +02:00
Thierry CH.
01585d0de1 fix(keygen-ce): print the policy ids check.py just created
policies is {name: id}, so joining it yielded the names -- which the caller
already knew -- and dropped the ids, which are what KEYGEN_POLICY_* has to be
set to. Recovering them meant minting a second admin token and querying, and
the script's own warning is that re-running creates duplicate policies.
2026-09-15 23:40:40 +02:00
Thierry CH.
a5bf46a029 fix(keygen): probe health on 127.0.0.1, not localhost
localhost resolves to ::1 inside the container while Puma binds 0.0.0.0, so every healthcheck got connection refused regardless of Keygen's state.
2026-09-15 18:56:49 +02:00
Thierry CH.
0154b8b024 feat(keygen): pin Keygen CE web and worker images for Coolify
Coolify has no field for a container command, so the worker needs a Dockerfile to set CMD. The web file keeps both processes pinned to the same tag in one place.
2026-09-15 18:42:28 +02:00
Thierry CH.
f4a90b1f56 feat(keygen): pin Keygen CE web and worker images for Coolify
Coolify has no field for a container command, so the worker needs a Dockerfile to set CMD. The web file keeps both processes pinned to the same tag in one place.
2026-09-15 17:55:05 +02:00
DESKTOP-RTLN3BA\$punk
e65cb8a718 refactor(local): update licensing and Keygen integration details in documentation
- Revised the license file format to reflect the use of self-hosted Keygen CE.
- Clarified the configuration requirements for Keygen integration.
- Updated portal documentation to specify the handling of license routes and delivery processes.
- Added notes on the implications of self-hosting Keygen, including testing and contract management.
2026-09-14 18:07:53 -07:00
Anish Sarkar
1333c263b3 feat(sunset): refuse writes and redirect the app when SUNSET_MODE is on 2026-09-14 23:54:27 +05:30
Anish Sarkar
57a32f506b test(mail): cover the real SMTP path against Mailpit, fix trial's 500 on Keygen failure 2026-09-14 01:05:32 +05:30
Anish Sarkar
cf5d658468 refactor(mail): make the SMTP connection deployment-wide, drop the console transport 2026-09-14 00:51:51 +05:30
Anish Sarkar
e0eb3b0c2f chore(config): add Keygen, license mail and rate limit settings
LICENSE_MAIL_TRANSPORT selects how mail leaves the process (null, console, smtp), never which vendor delivers it: every provider exposes SMTP, so changing company means editing the connection strings and leaving this alone.
2026-09-14 00:07:57 +05:30
Anish Sarkar
3adf478720 Merge remote-tracking branch 'upstream/dev' into feat/workstream-b 2026-09-13 11:43:54 +05:30
thierry
b64f28635c revert: cloud pricing and no-login chat retirement 2026-09-12 21:03:52 +02:00
Anish Sarkar
b65004f99f feat(license): implement license purchase and issuance system 2026-09-12 11:54:00 +05:30
MODSetter
a507fe45f7 feat: changed pricing and retired no login chat 2026-09-06 22:09:08 +05:30
Anish Sarkar
117d4bdba4 refactor(infographics): clarify revision process and infographic style handling 2026-09-03 18:53:38 +05:30
Anish Sarkar
c40674d35b refactor(infographics): enhance prompt assembly and clarify content requirements 2026-09-03 18:23:44 +05:30
Anish Sarkar
19b4ea644c fix(infographics): update audience constraints terminology in SKILL.md 2026-09-03 17:15:03 +05:30
Anish Sarkar
d6f0fad263 fix(infographics): clarify audience specification in layout guidelines 2026-09-03 17:14:23 +05:30
Anish Sarkar
e28aa450e0 feat(infographics): add deliverables workflow 2026-09-03 16:49:26 +05:30
Anish Sarkar
35486d452b feat(agents): teach deliverables to create quizzes 2026-09-02 23:15:31 +05:30
Anish Sarkar
fbc1426052 refactor(flashcards): update card structure to use plain text and LaTeX, enforce minimum card count, and enhance validation logic 2026-09-02 04:06:49 +05:30
Anish Sarkar
27de5f9996 feat(agents): teach deliverables agent flashcards 2026-09-02 00:42:13 +05:30