envref 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ dist/
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ # Real values never belong here; .env files in this repo are examples.
8
+ .env
9
+ .env.*
10
+ !.env.example
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — 2026-11-07
4
+
5
+ First release. Extracted from a private automation repository where the
6
+ 1Password path had run daily for a year.
7
+
8
+ - `.env` files whose values may be `{{ scheme://… }}` references.
9
+ - Resolvers: `op://` (1Password, via the `op` CLI with a cached session and
10
+ Touch ID sign-in, or via a service account), `keychain://` (macOS Keychain),
11
+ `file://`, `env://`.
12
+ - Third-party resolvers through the `envref.resolvers` entry-point group.
13
+ - CLI: `envref run`, `export`, `check`, `doctor`, `op save-password`.
envref-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sebastian Haglund
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
envref-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,188 @@
1
+ Metadata-Version: 2.5
2
+ Name: envref
3
+ Version: 0.1.0
4
+ Summary: A .env where any value can be a reference into a secret store, resolved at load time. op://, keychain://, file://, env://, and your own.
5
+ Project-URL: Homepage, https://github.com/sebaheg/envref
6
+ Project-URL: Repository, https://github.com/sebaheg/envref
7
+ Project-URL: Issues, https://github.com/sebaheg/envref/issues
8
+ Project-URL: Changelog, https://github.com/sebaheg/envref/blob/main/CHANGELOG.md
9
+ Author: Sebastian Haglund
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: 1password,dotenv,environment,keychain,secrets,twelve-factor
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: MacOS
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Security
24
+ Classifier: Topic :: Software Development :: Libraries
25
+ Classifier: Topic :: Utilities
26
+ Requires-Python: >=3.11
27
+ Provides-Extra: op
28
+ Requires-Dist: onepassword-sdk>=0.3; (python_version < '3.14') and extra == 'op'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # envref
32
+
33
+ A `.env` where any value can be a reference into a secret store, resolved
34
+ when the file is loaded.
35
+
36
+ ```dotenv
37
+ # .env
38
+ ATTIO_KEY={{ op://work/Attio/api_key }} # 1Password
39
+ DB_PASSWORD={{ keychain://myapp/postgres }} # macOS Keychain
40
+ TLS_KEY={{ file://~/.ssh/server.pem }} # a file's contents
41
+ GITHUB_TOKEN={{ env://GH_TOKEN }} # another variable
42
+ REGION=eu-north-1 # a plain literal
43
+ ```
44
+
45
+ ```bash
46
+ envref run -- python app.py # app.py sees ATTIO_KEY=<the real key>
47
+ ```
48
+
49
+ ```python
50
+ import envref
51
+ envref.load(".env") # same thing, into os.environ
52
+ ```
53
+
54
+ The file holds no secrets, so it can be committed. The scheme of each
55
+ reference picks the backend. Four ship built in, and your own takes one class
56
+ and one entry point.
57
+
58
+ ## Why
59
+
60
+ `op run`, `berglas exec`, `chamber exec` and friends each do this for one
61
+ store. Teams rarely have one store. A laptop has 1Password and Keychain, a
62
+ container has a service account, a CI job has its own vault, and the same
63
+ `.env` should work in all three with the same names. `envref` keeps the file
64
+ format (plain dotenv, plus `{{ scheme://… }}`), and makes the backend a plugin.
65
+
66
+ ## Install
67
+
68
+ ```bash
69
+ uv tool install envref # CLI
70
+ pip install envref # library, zero dependencies
71
+ pip install 'envref[op]' # + 1Password service-account support (SDK)
72
+ ```
73
+
74
+ The `op://` CLI path needs only the [`op`](https://developer.1password.com/docs/cli/)
75
+ binary on PATH, no extra.
76
+
77
+ ## Resolvers
78
+
79
+ | Scheme | Resolves to | Needs |
80
+ | --- | --- | --- |
81
+ | `op://vault/item/field` | a 1Password field | `op` CLI, or `OP_SERVICE_ACCOUNT_TOKEN` + `envref[op]` |
82
+ | `keychain://service/account` | a macOS Keychain generic password | macOS |
83
+ | `file://path` | the file's contents, one trailing newline dropped | — |
84
+ | `env://NAME` | another environment variable | — |
85
+
86
+ A value written as `{{ scheme://… }}` is always a reference, and an unknown
87
+ scheme is an error. A bare `scheme://…` without braces is resolved only when a
88
+ resolver for that scheme is installed, so `URL=https://example.com` stays a
89
+ literal and `KEY=op://vault/item/field` still works for files written for
90
+ `op read`.
91
+
92
+ ### 1Password in detail
93
+
94
+ Two modes, chosen by the environment:
95
+
96
+ - **Service account** when `OP_SERVICE_ACCOUNT_TOKEN` is set. The SDK resolves
97
+ every reference in one round trip. No binary, no biometrics. For containers.
98
+ - **CLI** otherwise. Every reference goes through one `op inject`. If `op` has
99
+ no session, `envref` signs in: the account password comes from Keychain
100
+ behind Touch ID if you stored it with `envref op save-password`, or from the
101
+ terminal if not. The session token is cached in `~/.cache/envref/` so a
102
+ burst of commands costs one sign-in; concurrent processes share it through
103
+ a lock. See [SECURITY.md](SECURITY.md) for what that cache means.
104
+
105
+ Session caching presumes "biometric unlock for the CLI" is off in the
106
+ 1Password app. With it on, `op` prompts per invocation and `envref` holds no
107
+ token.
108
+
109
+ Knobs: `OP_ACCOUNT` (shorthand, when several accounts are signed in),
110
+ `ENVREF_OP_SESSION_TTL` (seconds, default 1500, `0` disables the cache),
111
+ `ENVREF_OP_KEYCHAIN_SERVICE` / `ENVREF_OP_KEYCHAIN_ACCOUNT` (where the
112
+ password is stored, default `envref-op` / the account's email).
113
+
114
+ ## CLI
115
+
116
+ ```bash
117
+ envref run [-f FILE]... [--override] -- cmd args # exec cmd with the resolved environment
118
+ envref export [-f FILE]... [--format shell|dotenv|json]
119
+ envref check [-f FILE]... # resolve and report per key; never prints a value
120
+ envref doctor # installed resolvers and whether each can run here
121
+ envref op save-password [--account SHORTHAND] # store the 1Password password in Keychain for Touch ID sign-in
122
+ ```
123
+
124
+ `-f` repeats. The first file to set a name wins, so `-f .env.refs -f .env`
125
+ lets a local `.env` fill in what the shared references file lacks without
126
+ overriding it. Default is `.env`.
127
+
128
+ ## Library
129
+
130
+ ```python
131
+ import envref
132
+
133
+ values = envref.load(".env.refs", ".env") # dict, also exported into os.environ
134
+ values = envref.load(".env", export=False) # dict only
135
+ envref.load(".env", override=True) # let the file win over existing variables
136
+
137
+ entries = envref.parse(text) # list[Entry], refs identified
138
+ envref.resolve(entries, registry={"op": ...}) # bring your own resolvers
139
+ ```
140
+
141
+ Errors are typed: `UnknownScheme`, `ResolverUnavailable` (the backend cannot
142
+ run here: no `op`, not macOS, no token) and `ResolveError` (which references
143
+ failed and why, in `.failures`). All derive from `EnvrefError`.
144
+
145
+ ## Writing a resolver
146
+
147
+ ```python
148
+ # myenvref/aws.py
149
+ class SecretsManagerResolver:
150
+ scheme = "awssm"
151
+
152
+ def resolve(self, refs: list[str]) -> dict[str, str]:
153
+ # refs are every awssm:// reference in the file, deduplicated: batch them.
154
+ ...
155
+ return {ref: value for ref, value in ...}
156
+
157
+ def doctor(self) -> str: # optional, shown by `envref doctor`
158
+ return "ok"
159
+ ```
160
+
161
+ ```toml
162
+ # pyproject.toml
163
+ [project.entry-points."envref.resolvers"]
164
+ awssm = "myenvref.aws:SecretsManagerResolver"
165
+ ```
166
+
167
+ Installed next to `envref`, `{{ awssm://… }}` now resolves. An entry point
168
+ with a built-in's name replaces it.
169
+
170
+ ## Prior art
171
+
172
+ [`teller`](https://github.com/tellerops/teller) and
173
+ [`novops`](https://github.com/PierreBeucher/novops) are multi-provider too,
174
+ with the mapping in a YAML config rather than inline in the `.env`.
175
+ [`berglas`](https://github.com/GoogleCloudPlatform/berglas) has inline
176
+ `sm://` references, for Google Cloud only. [`dotenvx`](https://dotenvx.com)
177
+ encrypts the values rather than referencing them. `op inject` is what the
178
+ `{{ }}` syntax comes from, and any `.env.op` written for it is a valid
179
+ `envref` file.
180
+
181
+ ## Status
182
+
183
+ Extracted in November 2026 from a private automation repository where the
184
+ 1Password path had run daily for a year, on a laptop and in scheduled
185
+ containers. The other resolvers are new. macOS and Linux; Keychain and Touch
186
+ ID are macOS only.
187
+
188
+ MIT.
envref-0.1.0/README.md ADDED
@@ -0,0 +1,158 @@
1
+ # envref
2
+
3
+ A `.env` where any value can be a reference into a secret store, resolved
4
+ when the file is loaded.
5
+
6
+ ```dotenv
7
+ # .env
8
+ ATTIO_KEY={{ op://work/Attio/api_key }} # 1Password
9
+ DB_PASSWORD={{ keychain://myapp/postgres }} # macOS Keychain
10
+ TLS_KEY={{ file://~/.ssh/server.pem }} # a file's contents
11
+ GITHUB_TOKEN={{ env://GH_TOKEN }} # another variable
12
+ REGION=eu-north-1 # a plain literal
13
+ ```
14
+
15
+ ```bash
16
+ envref run -- python app.py # app.py sees ATTIO_KEY=<the real key>
17
+ ```
18
+
19
+ ```python
20
+ import envref
21
+ envref.load(".env") # same thing, into os.environ
22
+ ```
23
+
24
+ The file holds no secrets, so it can be committed. The scheme of each
25
+ reference picks the backend. Four ship built in, and your own takes one class
26
+ and one entry point.
27
+
28
+ ## Why
29
+
30
+ `op run`, `berglas exec`, `chamber exec` and friends each do this for one
31
+ store. Teams rarely have one store. A laptop has 1Password and Keychain, a
32
+ container has a service account, a CI job has its own vault, and the same
33
+ `.env` should work in all three with the same names. `envref` keeps the file
34
+ format (plain dotenv, plus `{{ scheme://… }}`), and makes the backend a plugin.
35
+
36
+ ## Install
37
+
38
+ ```bash
39
+ uv tool install envref # CLI
40
+ pip install envref # library, zero dependencies
41
+ pip install 'envref[op]' # + 1Password service-account support (SDK)
42
+ ```
43
+
44
+ The `op://` CLI path needs only the [`op`](https://developer.1password.com/docs/cli/)
45
+ binary on PATH, no extra.
46
+
47
+ ## Resolvers
48
+
49
+ | Scheme | Resolves to | Needs |
50
+ | --- | --- | --- |
51
+ | `op://vault/item/field` | a 1Password field | `op` CLI, or `OP_SERVICE_ACCOUNT_TOKEN` + `envref[op]` |
52
+ | `keychain://service/account` | a macOS Keychain generic password | macOS |
53
+ | `file://path` | the file's contents, one trailing newline dropped | — |
54
+ | `env://NAME` | another environment variable | — |
55
+
56
+ A value written as `{{ scheme://… }}` is always a reference, and an unknown
57
+ scheme is an error. A bare `scheme://…` without braces is resolved only when a
58
+ resolver for that scheme is installed, so `URL=https://example.com` stays a
59
+ literal and `KEY=op://vault/item/field` still works for files written for
60
+ `op read`.
61
+
62
+ ### 1Password in detail
63
+
64
+ Two modes, chosen by the environment:
65
+
66
+ - **Service account** when `OP_SERVICE_ACCOUNT_TOKEN` is set. The SDK resolves
67
+ every reference in one round trip. No binary, no biometrics. For containers.
68
+ - **CLI** otherwise. Every reference goes through one `op inject`. If `op` has
69
+ no session, `envref` signs in: the account password comes from Keychain
70
+ behind Touch ID if you stored it with `envref op save-password`, or from the
71
+ terminal if not. The session token is cached in `~/.cache/envref/` so a
72
+ burst of commands costs one sign-in; concurrent processes share it through
73
+ a lock. See [SECURITY.md](SECURITY.md) for what that cache means.
74
+
75
+ Session caching presumes "biometric unlock for the CLI" is off in the
76
+ 1Password app. With it on, `op` prompts per invocation and `envref` holds no
77
+ token.
78
+
79
+ Knobs: `OP_ACCOUNT` (shorthand, when several accounts are signed in),
80
+ `ENVREF_OP_SESSION_TTL` (seconds, default 1500, `0` disables the cache),
81
+ `ENVREF_OP_KEYCHAIN_SERVICE` / `ENVREF_OP_KEYCHAIN_ACCOUNT` (where the
82
+ password is stored, default `envref-op` / the account's email).
83
+
84
+ ## CLI
85
+
86
+ ```bash
87
+ envref run [-f FILE]... [--override] -- cmd args # exec cmd with the resolved environment
88
+ envref export [-f FILE]... [--format shell|dotenv|json]
89
+ envref check [-f FILE]... # resolve and report per key; never prints a value
90
+ envref doctor # installed resolvers and whether each can run here
91
+ envref op save-password [--account SHORTHAND] # store the 1Password password in Keychain for Touch ID sign-in
92
+ ```
93
+
94
+ `-f` repeats. The first file to set a name wins, so `-f .env.refs -f .env`
95
+ lets a local `.env` fill in what the shared references file lacks without
96
+ overriding it. Default is `.env`.
97
+
98
+ ## Library
99
+
100
+ ```python
101
+ import envref
102
+
103
+ values = envref.load(".env.refs", ".env") # dict, also exported into os.environ
104
+ values = envref.load(".env", export=False) # dict only
105
+ envref.load(".env", override=True) # let the file win over existing variables
106
+
107
+ entries = envref.parse(text) # list[Entry], refs identified
108
+ envref.resolve(entries, registry={"op": ...}) # bring your own resolvers
109
+ ```
110
+
111
+ Errors are typed: `UnknownScheme`, `ResolverUnavailable` (the backend cannot
112
+ run here: no `op`, not macOS, no token) and `ResolveError` (which references
113
+ failed and why, in `.failures`). All derive from `EnvrefError`.
114
+
115
+ ## Writing a resolver
116
+
117
+ ```python
118
+ # myenvref/aws.py
119
+ class SecretsManagerResolver:
120
+ scheme = "awssm"
121
+
122
+ def resolve(self, refs: list[str]) -> dict[str, str]:
123
+ # refs are every awssm:// reference in the file, deduplicated: batch them.
124
+ ...
125
+ return {ref: value for ref, value in ...}
126
+
127
+ def doctor(self) -> str: # optional, shown by `envref doctor`
128
+ return "ok"
129
+ ```
130
+
131
+ ```toml
132
+ # pyproject.toml
133
+ [project.entry-points."envref.resolvers"]
134
+ awssm = "myenvref.aws:SecretsManagerResolver"
135
+ ```
136
+
137
+ Installed next to `envref`, `{{ awssm://… }}` now resolves. An entry point
138
+ with a built-in's name replaces it.
139
+
140
+ ## Prior art
141
+
142
+ [`teller`](https://github.com/tellerops/teller) and
143
+ [`novops`](https://github.com/PierreBeucher/novops) are multi-provider too,
144
+ with the mapping in a YAML config rather than inline in the `.env`.
145
+ [`berglas`](https://github.com/GoogleCloudPlatform/berglas) has inline
146
+ `sm://` references, for Google Cloud only. [`dotenvx`](https://dotenvx.com)
147
+ encrypts the values rather than referencing them. `op inject` is what the
148
+ `{{ }}` syntax comes from, and any `.env.op` written for it is a valid
149
+ `envref` file.
150
+
151
+ ## Status
152
+
153
+ Extracted in November 2026 from a private automation repository where the
154
+ 1Password path had run daily for a year, on a laptop and in scheduled
155
+ containers. The other resolvers are new. macOS and Linux; Keychain and Touch
156
+ ID are macOS only.
157
+
158
+ MIT.
@@ -0,0 +1,52 @@
1
+ # Security
2
+
3
+ ## Threat model
4
+
5
+ `envref` moves secrets from a store into a process's environment. It never
6
+ stores a secret itself, with one deliberate exception described below. What
7
+ you should know before trusting it:
8
+
9
+ **The file is not secret.** An `.env` of references holds the names of your
10
+ vaults and items, which is an inventory of what you use. Treat it like source
11
+ code: fine in a private repository, think twice in a public one.
12
+
13
+ **Resolved values live in the environment of the process you start.** Any
14
+ child process inherits them, and on most systems any process running as the
15
+ same user can read another process's environment. This is true of every
16
+ secrets-to-env tool; `envref` adds nothing and removes nothing here.
17
+
18
+ **The 1Password CLI resolver caches a session token.** With "biometric unlock
19
+ for the CLI" turned off in 1Password, `op signin` returns a session token that
20
+ is good for about 30 minutes of inactivity. `envref` writes it to
21
+ `$XDG_CACHE_HOME/envref/op-session.json` (default `~/.cache/envref/`), mode
22
+ 0600, and re-uses it so a burst of commands costs one sign-in rather than one
23
+ per command. The trade: during that window, any process running as your user
24
+ can read the token and, with it, every item the account can see, with no
25
+ Touch ID. If that is unacceptable for your machine, set
26
+ `ENVREF_OP_SESSION_TTL=0` to disable the cache, or turn biometric CLI unlock
27
+ on in 1Password, in which case `op` prompts per invocation and `envref` never
28
+ holds a token.
29
+
30
+ **The 1Password account password may live in macOS Keychain.** `envref op
31
+ save-password` stores it as a generic password item, so that an expired
32
+ session can be renewed without typing. Reading it goes through a small Swift
33
+ helper that requires Touch ID (`LAContext`, biometrics only) before calling
34
+ `security find-generic-password`. Without Touch ID hardware, or without
35
+ `swiftc`, the read falls back to `security` alone, which shows the system's
36
+ own authorisation dialog. The helper is compiled from source on first use
37
+ into the cache directory; it is not shipped as a binary.
38
+
39
+ **The service-account path holds a bearer token in the environment.** That is
40
+ how 1Password service accounts work. Scope the account to one vault that holds
41
+ only what the job needs, so a leaked token reads five items rather than every
42
+ credential you own. `envref` fails loudly when a reference points outside the
43
+ granted vault rather than falling back to another method.
44
+
45
+ **Resolvers are code.** A third-party resolver installed through the
46
+ `envref.resolvers` entry point runs with your privileges and sees every
47
+ reference of its scheme. Install resolvers the way you install any dependency.
48
+
49
+ ## Reporting
50
+
51
+ Open a private security advisory on GitHub, or email the address on the
52
+ author's GitHub profile. Please do not open a public issue for a vulnerability.
@@ -0,0 +1,66 @@
1
+ [project]
2
+ name = "envref"
3
+ version = "0.1.0"
4
+ description = "A .env where any value can be a reference into a secret store, resolved at load time. op://, keychain://, file://, env://, and your own."
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ license = { text = "MIT" }
8
+ authors = [{ name = "Sebastian Haglund" }]
9
+ keywords = ["dotenv", "secrets", "1password", "keychain", "environment", "twelve-factor"]
10
+ classifiers = [
11
+ "Development Status :: 4 - Beta",
12
+ "Environment :: Console",
13
+ "Intended Audience :: Developers",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Operating System :: MacOS",
16
+ "Operating System :: POSIX :: Linux",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Topic :: Security",
22
+ "Topic :: Software Development :: Libraries",
23
+ "Topic :: Utilities",
24
+ ]
25
+ dependencies = []
26
+
27
+ [project.optional-dependencies]
28
+ # 1Password service accounts (unattended, no `op` binary). The CLI path needs
29
+ # nothing but the `op` binary on PATH.
30
+ op = ["onepassword-sdk>=0.3; python_version < '3.14'"]
31
+
32
+ [project.urls]
33
+ Homepage = "https://github.com/sebaheg/envref"
34
+ Repository = "https://github.com/sebaheg/envref"
35
+ Issues = "https://github.com/sebaheg/envref/issues"
36
+ Changelog = "https://github.com/sebaheg/envref/blob/main/CHANGELOG.md"
37
+
38
+ [project.scripts]
39
+ envref = "envref.cli:main"
40
+
41
+ # Third-party resolvers register here: `name` is the URL scheme, the value a
42
+ # `module:Class` whose instances have `.resolve(refs) -> dict[str, str]`.
43
+ [project.entry-points."envref.resolvers"]
44
+ env = "envref.resolvers.env:EnvResolver"
45
+ file = "envref.resolvers.file:FileResolver"
46
+ keychain = "envref.resolvers.keychain:KeychainResolver"
47
+ op = "envref.resolvers.op:OnePasswordResolver"
48
+
49
+ [dependency-groups]
50
+ dev = ["pytest>=8"]
51
+
52
+ [build-system]
53
+ requires = ["hatchling"]
54
+ build-backend = "hatchling.build"
55
+
56
+ [tool.hatch.build.targets.wheel]
57
+ packages = ["src/envref"]
58
+
59
+ [tool.hatch.build.targets.sdist]
60
+ include = ["src/envref", "tests", "README.md", "LICENSE", "CHANGELOG.md", "SECURITY.md"]
61
+
62
+ [tool.pytest.ini_options]
63
+ testpaths = ["tests"]
64
+
65
+ [tool.ruff]
66
+ line-length = 100
@@ -0,0 +1,40 @@
1
+ """envref — a .env where any value can be a reference into a secret store.
2
+
3
+ ATTIO_KEY={{ op://vault/Attio/api_key }}
4
+ DB_PASSWORD={{ keychain://myapp/db }}
5
+ TLS_KEY={{ file://~/.ssh/server.pem }}
6
+ REGION=eu-north-1
7
+
8
+ >>> import envref
9
+ >>> envref.load(".env") # resolves every reference, exports the rest
10
+
11
+ The scheme of a reference picks the resolver. Four ship built in (`op`,
12
+ `keychain`, `file`, `env`); others register through the `envref.resolvers`
13
+ entry-point group.
14
+ """
15
+
16
+ from envref.core import (
17
+ EnvrefError,
18
+ Resolver,
19
+ ResolveError,
20
+ ResolverUnavailable,
21
+ UnknownScheme,
22
+ load,
23
+ resolve,
24
+ )
25
+ from envref.parse import Entry, parse
26
+
27
+ __version__ = "0.1.0"
28
+
29
+ __all__ = [
30
+ "Entry",
31
+ "EnvrefError",
32
+ "ResolveError",
33
+ "Resolver",
34
+ "ResolverUnavailable",
35
+ "UnknownScheme",
36
+ "__version__",
37
+ "load",
38
+ "parse",
39
+ "resolve",
40
+ ]