# Connector Dev Stack This directory keeps local Docker Compose assets for GovOPlaN file connector development. The stack is intentionally separate from production deployment and binds services to localhost high ports. ## Start ```bash cd /mnt/DATA/git/govoplan-files/dev/connectors cp .env.example .env mkdir -p data/smb data/webdav docker compose up -d nextcloud nextcloud-db webdav smb minio docker compose up -d seafile-db seafile-memcached seafile ``` If the SMB service was already running before a compose change, recreate it so the image and share configuration are applied: ```bash docker compose rm -sf smb docker compose up -d --build smb ``` Endpoints: - Nextcloud: `http://127.0.0.1:9081`, WebDAV root `http://127.0.0.1:9081/remote.php/dav/files/admin/` - Seafile: `http://127.0.0.1:9082`, WebDAV root `http://127.0.0.1:9082/seafdav/` - WebDAV: `http://127.0.0.1:9083` - SMB: `smb://127.0.0.1:1445/files` - MinIO/S3 API: `http://127.0.0.1:9000`, console `http://127.0.0.1:9001` The local fixture data under `data/` is ignored by git. ## GovOPlaN Profile Config Connector profiles are read from `GOVOPLAN_FILES_CONNECTOR_PROFILES_JSON` or `GOVOPLAN_FILES_CONNECTOR_PROFILES_FILE`. This deployment-owned configuration may reference environment variables only when their exact names are listed in `GOVOPLAN_CONNECTOR_SECRET_ENV_ALLOWLIST`; profile API responses expose only the credential source and configured state. Example local profile file: ```json { "profiles": [ { "id": "dev-seafile", "label": "Dev Seafile", "provider": "seafile", "endpoint_url": "http://127.0.0.1:9082", "scope_type": "system", "credential_mode": "basic", "username": "admin@example.local", "password_env": "SEAFILE_ADMIN_PASSWORD", "capabilities": ["browse", "import"], "metadata": { "webdav_endpoint_url": "http://127.0.0.1:9082/seafdav/" }, "policy": { "allow": { "providers": ["seafile"] } } }, { "id": "dev-nextcloud", "label": "Dev Nextcloud", "provider": "nextcloud", "endpoint_url": "http://127.0.0.1:9081/remote.php/dav/files/admin/", "scope_type": "system", "credential_mode": "basic", "username": "admin", "password_env": "NEXTCLOUD_ADMIN_PASSWORD", "capabilities": ["browse", "import"], "policy": { "allow": { "providers": ["nextcloud", "webdav"] } } }, { "id": "dev-webdav", "label": "Dev WebDAV", "provider": "webdav", "endpoint_url": "http://127.0.0.1:9083", "scope_type": "system", "credential_mode": "basic", "username": "govoplan", "password_env": "WEBDAV_PASSWORD", "capabilities": ["browse", "import"], "policy": { "allow": { "providers": ["webdav"] } } }, { "id": "dev-smb", "label": "Dev SMB", "provider": "smb", "endpoint_url": "smb://127.0.0.1:1445/files", "scope_type": "system", "credential_mode": "basic", "username": "govoplan", "password_env": "SMB_PASSWORD", "capabilities": ["browse", "import"], "policy": { "allow": { "providers": ["smb"] } } }, { "id": "dev-s3", "label": "Dev MinIO", "provider": "s3", "endpoint_url": "http://127.0.0.1:9000", "base_path": "", "scope_type": "system", "credential_mode": "basic", "username": "govoplan", "password_env": "MINIO_ROOT_PASSWORD", "capabilities": ["browse", "import"], "metadata": { "bucket": "govoplan", "region": "us-east-1", "path_style": true, "verify_tls": false }, "policy": { "allow": { "providers": ["s3"] } } } ] } ``` Start GovOPlaN with: ```bash export GOVOPLAN_FILES_CONNECTOR_PROFILES_FILE=/mnt/DATA/git/govoplan-files/dev/connectors/profiles.local.json export GOVOPLAN_CONNECTOR_SECRET_ENV_ALLOWLIST=SEAFILE_ADMIN_PASSWORD,NEXTCLOUD_ADMIN_PASSWORD,WEBDAV_PASSWORD,SMB_PASSWORD,MINIO_ROOT_PASSWORD export GOVOPLAN_CONNECTOR_ALLOW_PRIVATE_NETWORKS=true ``` ## Smoke Test Run the connector helper smoke checks from an environment where `govoplan-files` and `httpx` are importable: ```bash cd /mnt/DATA/git/govoplan-files/dev/connectors /mnt/DATA/git/govoplan-core/.venv/bin/python smoke.py ``` The script reads `.env` from this directory when present and seeds tiny WebDAV, Nextcloud, SMB, and MinIO fixtures. WebDAV and Nextcloud use the pinned HTTP transport. SMB uses the Files-owned `smbprotocol` connection cache so initial connections, reconnects, aliases, and DFS referral targets are pinned. S3 uses pinned botocore pools for retries, redirects, discovery, and aliases. Every socket destination is revalidated when it opens, including when private-network access is enabled for these local fixtures. SMB and S3 are optional by default: a missing provider dependency or unavailable target is reported as `SKIP`. Use `--require-smb` and `--require-s3` to turn such provider failures into a non-zero smoke result during deployment validation. The bundled Samba service is a deterministic single-share target, not a DFS topology. Referral and reconnect behavior is covered by the transport contract tests; deployments using DFS must additionally run the required SMB smoke check against their actual referral topology and record the resolved peers. SMB smoke checks need the optional Python dependency in the environment running the script: ```bash /mnt/DATA/git/govoplan-core/.venv/bin/python -m pip install -e /mnt/DATA/git/govoplan-files[smb] ``` S3 smoke checks need the optional boto3 dependency in the environment running the script: ```bash /mnt/DATA/git/govoplan-core/.venv/bin/python -m pip install -e /mnt/DATA/git/govoplan-files[s3] ``` The SMB service is built from `dev/connectors/smb/` so the development share is deterministic: one `files` share backed by `data/smb`, with the credentials from `.env`. The SMB image runs as the non-root `govoplan` user with UID/GID `1000` and listens on unprivileged container port `1445`. The default host endpoint remains `smb://127.0.0.1:1445/files`. `SMB_USER` must stay `govoplan` unless the image is rebuilt with a matching user; `SMB_PORT` must be `1024` or higher. `SMB_PASSWORD` is applied when the image is built, so rebuild the `smb` service after changing it in `.env`.