Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ apps/geolibre-desktop/dist
apps/geolibre-desktop/src-tauri
backend/geolibre_server/.venv
backend/**/__pycache__
workers
workers/*
!workers/collab-node
!workers/collab-node/**
Comment thread
giswqs marked this conversation as resolved.
# Re-narrowed after the negations above: .dockerignore is last-match-wins, so
# without these the re-include would pull a host-built node_modules/dist back
# into the build context that the earlier **/node_modules rule had excluded.
workers/collab-node/node_modules
workers/collab-node/dist
workers/collab-node/data
docs
sample-data
coverage
Expand Down
11 changes: 9 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ jobs:
with:
python-version: "3.12"
cache: pip
cache-dependency-path: backend/geolibre_server/pyproject.toml
cache-dependency-path: |
backend/geolibre_server/pyproject.toml
backend/geolibre_server_api/pyproject.toml

- name: Install Rust stable
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
Expand Down Expand Up @@ -176,7 +178,9 @@ jobs:
- name: Install backend test dependencies
# The full test suite needs the optional engines; without them the
# vector/raster/SQL/ML tests skip themselves and CI is green but hollow.
run: python -m pip install -e "backend/geolibre_server[test]"
run: |
python -m pip install -e "backend/geolibre_server[test]"
python -m pip install -e "backend/geolibre_server_api[test]"

# backend/geolibre_server/uv.lock is committed because the desktop
# installers bundle that project and `uv run --frozen` it from a read-only
Expand Down Expand Up @@ -217,3 +221,6 @@ jobs:
run: npm run ci
env:
VITE_GEE_OAUTH_CLIENT_ID: ${{ secrets.VITE_GEE_OAUTH_CLIENT_ID }}

- name: Test projects and identity server
run: python -m pytest backend/geolibre_server_api/tests
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,8 @@ python/examples/my-map.geolibre.json
# source of truth is Entitlements.mas.plist.template)
apps/geolibre-desktop/src-tauri/mas/Entitlements.mas.plist
apps/geolibre-desktop/src-tauri/mas/embedded.provisionprofile

# Local SQLite state for the reference projects/identity server. GEOLIBRE_DATABASE_URL
# defaults to sqlite:///./geolibre-server-api.db, so running it from the repo root
# (the obvious place) drops the file here.
/geolibre-server-api.db
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
COPY package.json package-lock.json ./
COPY apps/geolibre-desktop/package.json apps/geolibre-desktop/package.json
COPY packages/core/package.json packages/core/package.json
COPY packages/collab-core/package.json packages/collab-core/package.json
COPY packages/map/package.json packages/map/package.json
COPY packages/plugins/package.json packages/plugins/package.json
COPY packages/processing/package.json packages/processing/package.json
Expand All @@ -23,7 +24,7 @@

ARG GEOLIBRE_APP_BASE=/
ARG VITE_GEE_OAUTH_CLIENT_ID=
ARG VITE_MAPILLARY_ACCESS_TOKEN=

Check warning on line 27 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build and publish container image

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "VITE_MAPILLARY_ACCESS_TOKEN") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
# Set to 1 (or true) to disable the first-launch welcome wizard for the whole
# deployment; visitors land straight on the map.
ARG VITE_WELCOME_DISABLED=
Expand All @@ -41,7 +42,7 @@
ARG VITE_GEOLIBRE_COLLAB_URL=
ENV GEOLIBRE_APP_BASE=${GEOLIBRE_APP_BASE}
ENV VITE_GEE_OAUTH_CLIENT_ID=${VITE_GEE_OAUTH_CLIENT_ID}
ENV VITE_MAPILLARY_ACCESS_TOKEN=${VITE_MAPILLARY_ACCESS_TOKEN}

Check warning on line 45 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build and publish container image

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "VITE_MAPILLARY_ACCESS_TOKEN") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENV VITE_WELCOME_DISABLED=${VITE_WELCOME_DISABLED}
ENV VITE_GEOLIBRE_EMBED_ORIGINS=${VITE_GEOLIBRE_EMBED_ORIGINS}
ENV VITE_GEOLIBRE_SHARE_URL=${VITE_GEOLIBRE_SHARE_URL}
Expand Down
5 changes: 5 additions & 0 deletions backend/geolibre_server_api/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.venv/
.pytest_cache/
__pycache__/
tests/
*.db
2 changes: 2 additions & 0 deletions backend/geolibre_server_api/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
geolibre-server-api.db
data/
24 changes: 24 additions & 0 deletions backend/geolibre_server_api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM python:3.13-slim

WORKDIR /app
COPY pyproject.toml README.md ./
COPY geolibre_server_api ./geolibre_server_api
RUN pip install --no-cache-dir ".[postgres,s3]"

# Create the storage directory in the image, not just /data. A named volume
# mounted at /data/objects inherits the image's ownership only when that exact
# path already exists; otherwise Docker creates the mountpoint as root and the
# unprivileged user below cannot write projects into it.
# uid/gid pinned to 1000 rather than taking the next free id: README.md documents
# `chown -R 1000:1000` to repair a volume created by an earlier root-owned image,
# and that instruction is only correct while this user keeps that id.
RUN groupadd --gid 1000 geolibre \
&& useradd --uid 1000 --gid 1000 --create-home geolibre \
&& mkdir -p /data/objects \
&& chown -R geolibre:geolibre /data
USER geolibre

ENV GEOLIBRE_DATABASE_URL=sqlite:////data/geolibre-server-api.db \
GEOLIBRE_STORAGE_PATH=/data/objects
EXPOSE 8000
CMD ["geolibre-server-api"]
45 changes: 45 additions & 0 deletions backend/geolibre_server_api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# GeoLibre server API

Reference implementation of [`docs/server-api.md`](../../docs/server-api.md).
It is a separate multi-user service from the local desktop processing sidecar.

```bash
pip install -e ".[test]"
geolibre-server-api
```

Configuration:

- `GEOLIBRE_DATABASE_URL`: SQLAlchemy URL; defaults to
`sqlite:///./geolibre-server-api.db`. Use
`postgresql+psycopg://user:password@host/database` with the `postgres` extra.
- `GEOLIBRE_STORAGE_PATH`: local object directory, default `./data`.
- `GEOLIBRE_STORAGE=s3`, `GEOLIBRE_S3_BUCKET`, and optional
`GEOLIBRE_S3_ENDPOINT` / `GEOLIBRE_S3_REGION`: S3-compatible storage (install
the `s3` extra; standard AWS credential environment variables apply).
- `GEOLIBRE_PUBLIC_URL`: externally reachable API origin.
- `GEOLIBRE_VIEWER_URL`: GeoLibre viewer origin.
- `GEOLIBRE_CORS_ORIGINS`: comma-separated web origins, default `*`.
- `GEOLIBRE_MAX_PROJECT_BYTES`, `GEOLIBRE_MAX_THUMBNAIL_BYTES`: upload limits.
Comment thread
giswqs marked this conversation as resolved.
- `GEOLIBRE_HOST`, `GEOLIBRE_PORT`: bind address and port for the
`geolibre-server-api` entry point, default `0.0.0.0` and `8000`. Bind to
`127.0.0.1` when a reverse proxy fronts the service.

## Volume ownership

The container runs as the unprivileged `geolibre` user, and the image creates
`/data/objects` so a fresh named volume inherits that ownership. Docker applies
image ownership only to a volume it creates, so one that already holds data from
an image that ran as root stays root-owned and every upload fails with
`PermissionError`. Repair it once with

```bash
docker run --rm -v geolibre_geolibre-projects:/data/objects busybox \
chown -R 1000:1000 /data/objects
```

## Hardening

`429` and token expiry are part of the contract but are not implemented here;
see the "What the reference server leaves to the operator" section of
`docs/server-api.md` before exposing this publicly.
5 changes: 5 additions & 0 deletions backend/geolibre_server_api/geolibre_server_api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""GeoLibre projects and identity reference server."""

from .main import create_app

__all__ = ["create_app"]
Loading
Loading