> ## Documentation Index
> Fetch the complete documentation index at: https://docs.westyx.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Python SDK - File-type secret security

> On-disk permissions, per-client isolation, and lifecycle for secrets materialised to files.

A secret stored in Nexus with `type: "file"` is materialised to a real file on disk so you can hand its path to something that only accepts a path - a TLS certificate for nginx, a service-account JSON for a cloud client library, a private key for an SSH tool.

```python theme={null}
cert_path = nexus.get_secret_file_path("TLS_CERT")
if cert_path is None:
    raise RuntimeError("TLS_CERT is not a file-type secret")
```

This is the one place the SDK puts credential material somewhere another process can reach, so the guarantees are worth stating precisely.

## Permissions

*Changed in v0.11.0.*

Files are created with mode `0600` - readable and writable by the owning user only.

The mode is applied **at creation**, not by a `chmod` afterwards. A chmod-after leaves a window in which the file already exists with the process umask applied, and anything watching the directory can read it during that window.

<Warning>
  Before v0.11.0 the file was written with `Path.write_text`, which takes no mode argument at all, so it inherited the process umask - typically `0644` in a shared `/tmp`, where **every local user on the machine could read the secret**. If you ran an affected version on a multi-tenant or shared host, treat any file-type secret it materialised as exposed and rotate it.
</Warning>

The SDK also opens the file with `O_NOFOLLOW`, so it refuses to write through a symlink planted at the target path.

### Windows

There is no `0600` equivalent. The file inherits the temp directory ACL, which on a default single-user install is not world-readable but is not equivalent to `0600` either. This matches the other Nexus SDKs.

## Isolation between clients

*Changed in v0.11.0.*

Each client instance materialises secrets to its own paths. Two clients in the same process holding the same secret get two files.

Previously the path came from the secret's key and value alone, so both clients resolved to a single file - and whichever was closed first deleted it out from under the other. The survivor's `get_secret_file_path` then returned a path to a file that no longer existed, usually surfacing much later as a confusing `FileNotFoundError` from whatever consumed it.

## Lifecycle

* Written on the first sync that contains the secret, and rewritten when the value changes.
* The old file is removed when the value changes.
* Removed when the secret leaves the sync payload, or its type stops being `file`.
* All remaining files are removed on `close()`.

Because cleanup happens in `close()`, use the client as a context manager (or call `close()` in a `finally`) so a clean shutdown leaves nothing on disk:

```python theme={null}
with NexusClient.create(config) as nexus:
    ...
# every materialised file-type secret is gone here
```

A hard kill (`SIGKILL`, a container OOM) skips cleanup and leaves the files. They are mode `0600` and in the temp directory, so the OS clears them on the usual schedule - but if your threat model cares, mount a `tmpfs` for `TMPDIR`.

## Choosing the directory

The SDK writes to `tempfile.gettempdir()`, which honours `TMPDIR` on POSIX. Point it at a `tmpfs` or a dedicated per-service directory to keep secrets off a persistent disk:

```sh theme={null}
TMPDIR=/dev/shm/myservice python -m myservice
```

## Next

* [API reference](/sdks/python/api-reference)
* [Configuration](/sdks/python/configuration)
* [Error handling](/sdks/python/error-handling)
