DeveloperStorage Configuration Probes

Storage configuration probes

StudioBrain validates a storage configuration before it encrypts and persists the new settings. The shared OpenDAL probe is intentionally destructive only to a randomly named sentinel object: it writes known bytes, reads them back, verifies the content, and deletes the sentinel. Local-filesystem setup also performs the preflight described below.

The implementation lives in crates/sb-server/src/routes/settings.rs in build_probe_operator, probe_operator, and update_storage_config.

Validation sequence

PUT /api/settings/storage performs these steps in order:

  1. Validate the provider-specific configuration and construct an OpenDAL operator.
  2. Write a random probe object containing known bytes.
  3. Read the same object and compare the returned bytes.
  4. Delete the probe object.
  5. Only after the probe succeeds, encrypt credentials and persist the configuration.

Any probe failure returns HTTP 400 with the provider and the concrete error. A failed probe does not replace the previously stored configuration.

The content comparison matters: a successful write call alone does not prove the configured endpoint, bucket, credentials, and read path refer to the same usable store.

Provider behavior

ProviderConfiguration validation before the sentinel probe
Local filesystemThe path must exist, be a directory, and accept a temporary-file write and removal. The current preflight uses the fixed reserved name .sb-config-probe.tmp; do not store user content under that name. StudioBrain then creates an OpenDAL filesystem operator rooted at the configured path.
S3-compatibleRequires a bucket; applies the configured region, endpoint, access key, and secret key to the OpenDAL S3 operator. The generic sentinel write/read/delete sequence is the authoritative connectivity test.
Azure BlobBuilds an OpenDAL Azure Blob operator from the configured container and credentials, then runs the same sentinel sequence.
Google Drive / DropboxRejected by the core route because their OAuth-backed adapters belong to the cloud overlay.

The core route does not issue a separate S3 HEAD Object request. Provider-specific HTTP operations are OpenDAL implementation details; the application-level contract is the write/read/content-check/delete sequence above.

Cleanup and failure semantics

The sentinel key contains a random UUID, so concurrent probes do not share an object name.

  • If the read succeeds but returns different bytes, StudioBrain attempts a best-effort delete before returning the mismatch error.
  • If the final delete fails, the probe fails and the new configuration is not persisted.
  • If the read itself fails after a successful write, the route returns the error without the generated UUID. If provider-side inspection is required, look for stale .sb-probe-*.tmp objects and confirm their age before removal.

Do not weaken a delete failure into success. Leaving undeletable objects proves the credentials are not sufficient for normal StudioBrain storage lifecycle operations.

Capacity reporting is separate

Filesystem capacity is reported by GET /api/storage/info, which uses statvfs for local storage. Capacity or free-space reporting is not part of the configuration probe and does not establish read/write/delete correctness for a remote provider.

Operator verification

When troubleshooting a rejected configuration:

  1. Confirm the request reached PUT /api/settings/storage and record the returned provider/error fields.
  2. Verify the configured local directory, bucket, or container exists and that the supplied identity has create, read, and delete permissions.
  3. For S3-compatible services, verify the endpoint, region, and bucket are mutually consistent; do not infer success from an unrelated bucket-list operation.
  4. Check provider logs for the random sentinel key and remove an orphan only after confirming no probe is still active.
  5. Retry the settings update and verify that the response succeeds before assuming the encrypted configuration was persisted.

Tests for this route should cover a successful round trip plus write, read, content-mismatch, and delete failures. Provider builder tests should remain separate from the generic probe tests so the shared lifecycle contract cannot drift between backends.