zerobyte
zerobyte copied to clipboard
feat: Add secret reference support (Environmental variables, Docker secrets)
Summary
Adds secret references so users can avoid storing credentials directly in Zerobyte.
Sensitive fields can now be provided as env://... or file://... references which are not encrypted, but visible in UI as they are not the actual secrets.
Supported secret formats
env://VAR_NAME— readsprocess.env.VAR_NAMEinside the Zerobyte containerfile://secret_name— reads/run/secrets/secret_name(Docker secrets)encv1:...— encrypted value stored in the database (existing native encryption)
What changed
- Centralized secret handling (server)
cryptoUtils.sealSecret()encrypts plaintext before storing, but storesenv:/// references as-iscryptoUtils.resolveSecret()resolvesenv:///file://and decryptsencv1:...when needed
- Wired through the app
- Repositories, volumes (SMB/WebDAV), notifications store via
sealSecret()and resolve viaresolveSecret() - Restic env building resolves credentials at runtime
- Backend compatibility checks compare resolved values (not raw encrypted strings)
- Repositories, volumes (SMB/WebDAV), notifications store via
- UI: consistent secret input UX
- While editing: masked input with an eye toggle
- After save (stored value is
env://,file://, orencv1:and field is not dirty): shown as plaintext with no eye icon - Scoped CSS fix to prevent “double eye” in Edge/Windows by hiding native reveal/clear controls only within
SecretInput
- Docs & examples
- Added README section explaining
env://andfile:// - Added docker-compose commented examples for env var + Docker secrets wiring
- Added README section explaining
Security notes
- File secret references are restricted to a single path segment and resolved under
/run/secretsusing POSIX semantics (prevents traversal).
Breaking changes
None.
How to test
- Set a sensitive field to
env://SOME_SECRETand confirm it resolves at runtime. - Mount a Docker secret at
/run/secrets/<name>and set the field tofile://<name>. - Enter a plaintext secret and confirm it is stored as
encv1:...and still works end-to-end.