3tears-interfaces 0.93.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.
- 3tears_interfaces-0.93.0/.gitignore +257 -0
- 3tears_interfaces-0.93.0/LICENSE +21 -0
- 3tears_interfaces-0.93.0/PKG-INFO +85 -0
- 3tears_interfaces-0.93.0/README.md +66 -0
- 3tears_interfaces-0.93.0/pyproject.toml +35 -0
- 3tears_interfaces-0.93.0/src/threetears/interfaces/__init__.py +26 -0
- 3tears_interfaces-0.93.0/src/threetears/interfaces/access.py +37 -0
- 3tears_interfaces-0.93.0/src/threetears/interfaces/media/__init__.py +69 -0
- 3tears_interfaces-0.93.0/src/threetears/interfaces/media/facets.py +131 -0
- 3tears_interfaces-0.93.0/src/threetears/interfaces/media/keys.py +146 -0
- 3tears_interfaces-0.93.0/src/threetears/interfaces/media/protocols.py +618 -0
- 3tears_interfaces-0.93.0/src/threetears/interfaces/py.typed +0 -0
- 3tears_interfaces-0.93.0/tests/access/test_surface.py +28 -0
- 3tears_interfaces-0.93.0/tests/media/test_facets.py +100 -0
- 3tears_interfaces-0.93.0/tests/media/test_keys.py +186 -0
- 3tears_interfaces-0.93.0/tests/media/test_object_handle.py +68 -0
- 3tears_interfaces-0.93.0/tests/media/test_surface.py +30 -0
- 3tears_interfaces-0.93.0/tests/test_dependency_free.py +35 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
# Anchored: these name top-level build output. Unanchored, `lib/` matches at ANY depth --
|
|
18
|
+
# it swallowed a vendored `.../pako/lib/` tree, and hatchling reads this file with its own
|
|
19
|
+
# matcher that does NOT honour `!` re-inclusion, so the miss reached built artifacts.
|
|
20
|
+
/lib/
|
|
21
|
+
/lib64/
|
|
22
|
+
parts/
|
|
23
|
+
sdist/
|
|
24
|
+
var/
|
|
25
|
+
wheels/
|
|
26
|
+
share/python-wheels/
|
|
27
|
+
*.egg-info/
|
|
28
|
+
.installed.cfg
|
|
29
|
+
*.egg
|
|
30
|
+
MANIFEST
|
|
31
|
+
|
|
32
|
+
# PyInstaller
|
|
33
|
+
# Usually these files are written by a python script from a template
|
|
34
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
35
|
+
*.manifest
|
|
36
|
+
*.spec
|
|
37
|
+
|
|
38
|
+
# Installer logs
|
|
39
|
+
pip-log.txt
|
|
40
|
+
pip-delete-this-directory.txt
|
|
41
|
+
|
|
42
|
+
# Unit test / coverage reports
|
|
43
|
+
htmlcov/
|
|
44
|
+
.tox/
|
|
45
|
+
.nox/
|
|
46
|
+
.coverage
|
|
47
|
+
.coverage.*
|
|
48
|
+
.cache
|
|
49
|
+
nosetests.xml
|
|
50
|
+
coverage.xml
|
|
51
|
+
*.cover
|
|
52
|
+
*.py.cover
|
|
53
|
+
.hypothesis/
|
|
54
|
+
.pytest_cache/
|
|
55
|
+
cover/
|
|
56
|
+
|
|
57
|
+
# Translations
|
|
58
|
+
*.mo
|
|
59
|
+
*.pot
|
|
60
|
+
|
|
61
|
+
# Django stuff:
|
|
62
|
+
*.log
|
|
63
|
+
local_settings.py
|
|
64
|
+
db.sqlite3
|
|
65
|
+
db.sqlite3-journal
|
|
66
|
+
|
|
67
|
+
# Flask stuff:
|
|
68
|
+
instance/
|
|
69
|
+
.webassets-cache
|
|
70
|
+
|
|
71
|
+
# Scrapy stuff:
|
|
72
|
+
.scrapy
|
|
73
|
+
|
|
74
|
+
# Sphinx documentation
|
|
75
|
+
docs/_build/
|
|
76
|
+
|
|
77
|
+
# PyBuilder
|
|
78
|
+
.pybuilder/
|
|
79
|
+
target/
|
|
80
|
+
|
|
81
|
+
# Jupyter Notebook
|
|
82
|
+
.ipynb_checkpoints
|
|
83
|
+
|
|
84
|
+
# IPython
|
|
85
|
+
profile_default/
|
|
86
|
+
ipython_config.py
|
|
87
|
+
|
|
88
|
+
# pyenv
|
|
89
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
90
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
91
|
+
# .python-version
|
|
92
|
+
|
|
93
|
+
# pipenv
|
|
94
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
95
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
96
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
97
|
+
# install all needed dependencies.
|
|
98
|
+
#Pipfile.lock
|
|
99
|
+
|
|
100
|
+
# UV
|
|
101
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
102
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
103
|
+
# commonly ignored for libraries.
|
|
104
|
+
#uv.lock
|
|
105
|
+
|
|
106
|
+
# poetry
|
|
107
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
108
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
109
|
+
# commonly ignored for libraries.
|
|
110
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
111
|
+
#poetry.lock
|
|
112
|
+
#poetry.toml
|
|
113
|
+
|
|
114
|
+
# pdm
|
|
115
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
116
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
117
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
118
|
+
#pdm.lock
|
|
119
|
+
#pdm.toml
|
|
120
|
+
.pdm-python
|
|
121
|
+
.pdm-build/
|
|
122
|
+
|
|
123
|
+
# pixi
|
|
124
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
125
|
+
#pixi.lock
|
|
126
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
127
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
128
|
+
.pixi
|
|
129
|
+
|
|
130
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
131
|
+
__pypackages__/
|
|
132
|
+
|
|
133
|
+
# Celery stuff
|
|
134
|
+
celerybeat-schedule
|
|
135
|
+
celerybeat.pid
|
|
136
|
+
|
|
137
|
+
# SageMath parsed files
|
|
138
|
+
*.sage.py
|
|
139
|
+
|
|
140
|
+
# Environments
|
|
141
|
+
.env
|
|
142
|
+
.envrc
|
|
143
|
+
.venv
|
|
144
|
+
env/
|
|
145
|
+
venv/
|
|
146
|
+
ENV/
|
|
147
|
+
env.bak/
|
|
148
|
+
venv.bak/
|
|
149
|
+
|
|
150
|
+
# Spyder project settings
|
|
151
|
+
.spyderproject
|
|
152
|
+
.spyproject
|
|
153
|
+
|
|
154
|
+
# Rope project settings
|
|
155
|
+
.ropeproject
|
|
156
|
+
|
|
157
|
+
# mkdocs documentation
|
|
158
|
+
/site
|
|
159
|
+
|
|
160
|
+
# mypy
|
|
161
|
+
.mypy_cache/
|
|
162
|
+
.dmypy.json
|
|
163
|
+
dmypy.json
|
|
164
|
+
|
|
165
|
+
# Pyre type checker
|
|
166
|
+
.pyre/
|
|
167
|
+
|
|
168
|
+
# pytype static type analyzer
|
|
169
|
+
.pytype/
|
|
170
|
+
|
|
171
|
+
# Cython debug symbols
|
|
172
|
+
cython_debug/
|
|
173
|
+
|
|
174
|
+
# PyCharm
|
|
175
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
176
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
177
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
178
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
179
|
+
#.idea/
|
|
180
|
+
|
|
181
|
+
# Abstra
|
|
182
|
+
# Abstra is an AI-powered process automation framework.
|
|
183
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
184
|
+
# Learn more at https://abstra.io/docs
|
|
185
|
+
.abstra/
|
|
186
|
+
|
|
187
|
+
# Visual Studio Code
|
|
188
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
189
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
190
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
191
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
192
|
+
# .vscode/
|
|
193
|
+
|
|
194
|
+
# Ruff stuff:
|
|
195
|
+
.ruff_cache/
|
|
196
|
+
|
|
197
|
+
# PyPI configuration file
|
|
198
|
+
.pypirc
|
|
199
|
+
|
|
200
|
+
# Cursor
|
|
201
|
+
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
|
202
|
+
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
|
203
|
+
# refer to https://docs.cursor.com/context/ignore-files
|
|
204
|
+
.cursorignore
|
|
205
|
+
.cursorindexingignore
|
|
206
|
+
|
|
207
|
+
# Marimo
|
|
208
|
+
marimo/_static/
|
|
209
|
+
marimo/_lsp/
|
|
210
|
+
__marimo__/
|
|
211
|
+
|
|
212
|
+
# Claude Code local state
|
|
213
|
+
# .claude/* rather than .claude/ so the one file below can be re-included:
|
|
214
|
+
# git never descends into an excluded DIRECTORY, so a negation inside one is
|
|
215
|
+
# silently dead. Excluding the contents instead leaves the directory readable.
|
|
216
|
+
.claude/*
|
|
217
|
+
# Prawduct install reference. Committed on purpose: it is what enables the
|
|
218
|
+
# plugin for anyone who clones this repo. Without it the governance hooks run
|
|
219
|
+
# only on a machine that already has prawduct installed, and a new developer
|
|
220
|
+
# gets none of them.
|
|
221
|
+
!.claude/settings.json
|
|
222
|
+
|
|
223
|
+
# prawduct session evidence (local governance artifacts, never shipped)
|
|
224
|
+
.prawduct/
|
|
225
|
+
|
|
226
|
+
# macOS folder metadata
|
|
227
|
+
.DS_Store
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# Prawduct session files
|
|
231
|
+
.claude/settings.local.json
|
|
232
|
+
.prawduct/.bug-inbox
|
|
233
|
+
.prawduct/.critic-active
|
|
234
|
+
.prawduct/.critic-findings.json
|
|
235
|
+
.prawduct/.critic-partials/
|
|
236
|
+
.prawduct/.critic-partials-archive/
|
|
237
|
+
.prawduct/.governance-ledger.jsonl
|
|
238
|
+
.prawduct/.handoff-notes.md
|
|
239
|
+
.prawduct/.test-evidence.json
|
|
240
|
+
.prawduct/.pr-reviews/
|
|
241
|
+
.prawduct/.session-base-tree
|
|
242
|
+
.prawduct/.session-git-baseline
|
|
243
|
+
.prawduct/.session-handoff.md
|
|
244
|
+
.prawduct/.session-reflected
|
|
245
|
+
.prawduct/.session-start
|
|
246
|
+
.prawduct/.subagent-briefing.md
|
|
247
|
+
.prawduct/.gates-waived
|
|
248
|
+
.prawduct/.advisories.json
|
|
249
|
+
.prawduct/.work-model-index.json
|
|
250
|
+
.prawduct/reflections.md
|
|
251
|
+
|
|
252
|
+
# Prawduct session files
|
|
253
|
+
.prawduct/.delegate-brief.md
|
|
254
|
+
.prawduct/.test-report.xml
|
|
255
|
+
.prawduct/.test-report.xml.scope.json
|
|
256
|
+
.prawduct/.critic-review-dispatch.json
|
|
257
|
+
.prawduct/.pr-review-dispatch.json
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mark Pace
|
|
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.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: 3tears-interfaces
|
|
3
|
+
Version: 0.93.0
|
|
4
|
+
Summary: Dependency-free Protocols and shared vocabulary for the 3tears family
|
|
5
|
+
Project-URL: Repository, https://github.com/pacepace/3tears
|
|
6
|
+
Author: pace
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Framework :: AsyncIO
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Classifier: Topic :: Security
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Python: >=3.14
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# 3tears-interfaces
|
|
21
|
+
|
|
22
|
+
The 3tears family's shared Protocols and vocabulary, in one package that
|
|
23
|
+
depends on nothing.
|
|
24
|
+
|
|
25
|
+
**The rule.** This package holds Protocols, the value types and enums that
|
|
26
|
+
cross them, and pure helpers over those types. No implementations, no
|
|
27
|
+
third-party imports, no dependencies. A provider can implement a Protocol, and
|
|
28
|
+
a consumer can accept one, without inheriting any feature package's dependency
|
|
29
|
+
closure. The workspace's `tests/enforcement/` fails any module-top import here
|
|
30
|
+
that is not the stdlib or `threetears.interfaces` itself.
|
|
31
|
+
|
|
32
|
+
One module per domain:
|
|
33
|
+
|
|
34
|
+
| Module | What it holds |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `threetears.interfaces.access` | The identity and authorization vocabulary `3tears-iam` and `3tears-agent-acl` both name |
|
|
37
|
+
| `threetears.interfaces.media` | Media capability Protocols, the value types that cross them, and the object-key builder |
|
|
38
|
+
|
|
39
|
+
## access
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from threetears.interfaces.access import ImpersonationCategory
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`ImpersonationCategory` is the fixed set of six sensitive actions: credential,
|
|
46
|
+
passkey and MFA management; account deletion; API-key mint or rotate for the
|
|
47
|
+
target; email change; RBAC grant changes; audit editing. agent-acl deny-lists
|
|
48
|
+
all six under impersonation, and iam's `stepup` requires a recent sign-in for
|
|
49
|
+
each. iam proves who a caller is and agent-acl decides what they may do;
|
|
50
|
+
neither depends on the other, so the values both must agree on live here.
|
|
51
|
+
|
|
52
|
+
## media
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from threetears.interfaces.media import GeneratedImage, ImageGenerationBackend
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The Protocols media providers (`3tears-models`, `3tears-object-store`)
|
|
59
|
+
implement and media consumers (`3tears-agent-tools`) accept: `VisionProvider`,
|
|
60
|
+
`ReferenceVisionProvider`, `TextProvider`, `TranscriptionProvider`,
|
|
61
|
+
`ImageGenerationBackend`, `MediaStorage` and `ObjectStore`. The value types
|
|
62
|
+
that cross them: `MediaInfo`, `GeneratedImage`, `ObjectHandle`,
|
|
63
|
+
`ObjectListing` and `MediaSizeLimitExceeded`. Plus the extraction-status and
|
|
64
|
+
generation-metadata constants, and the object-key builder `build_object_key`.
|
|
65
|
+
|
|
66
|
+
`MediaFacets` carries the additive carrier facets: rights status, pixel
|
|
67
|
+
dimensions, and whether a locator points at the file itself or at the page
|
|
68
|
+
containing it. The vocabulary grows by addition only, and a consumer that
|
|
69
|
+
does not recognise a facet ignores it rather than failing, so a new carrier
|
|
70
|
+
ships without a coordinated release.
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from threetears.interfaces.media import LOCATOR_KIND_DIRECT_FILE, MediaFacets
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Install
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install 3tears-interfaces
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Versioning policy
|
|
83
|
+
|
|
84
|
+
`3tears-interfaces` versions in lockstep with the rest of the 3tears
|
|
85
|
+
monorepo: every package shares one version, tracking the framework git tag.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# 3tears-interfaces
|
|
2
|
+
|
|
3
|
+
The 3tears family's shared Protocols and vocabulary, in one package that
|
|
4
|
+
depends on nothing.
|
|
5
|
+
|
|
6
|
+
**The rule.** This package holds Protocols, the value types and enums that
|
|
7
|
+
cross them, and pure helpers over those types. No implementations, no
|
|
8
|
+
third-party imports, no dependencies. A provider can implement a Protocol, and
|
|
9
|
+
a consumer can accept one, without inheriting any feature package's dependency
|
|
10
|
+
closure. The workspace's `tests/enforcement/` fails any module-top import here
|
|
11
|
+
that is not the stdlib or `threetears.interfaces` itself.
|
|
12
|
+
|
|
13
|
+
One module per domain:
|
|
14
|
+
|
|
15
|
+
| Module | What it holds |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `threetears.interfaces.access` | The identity and authorization vocabulary `3tears-iam` and `3tears-agent-acl` both name |
|
|
18
|
+
| `threetears.interfaces.media` | Media capability Protocols, the value types that cross them, and the object-key builder |
|
|
19
|
+
|
|
20
|
+
## access
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from threetears.interfaces.access import ImpersonationCategory
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`ImpersonationCategory` is the fixed set of six sensitive actions: credential,
|
|
27
|
+
passkey and MFA management; account deletion; API-key mint or rotate for the
|
|
28
|
+
target; email change; RBAC grant changes; audit editing. agent-acl deny-lists
|
|
29
|
+
all six under impersonation, and iam's `stepup` requires a recent sign-in for
|
|
30
|
+
each. iam proves who a caller is and agent-acl decides what they may do;
|
|
31
|
+
neither depends on the other, so the values both must agree on live here.
|
|
32
|
+
|
|
33
|
+
## media
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from threetears.interfaces.media import GeneratedImage, ImageGenerationBackend
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The Protocols media providers (`3tears-models`, `3tears-object-store`)
|
|
40
|
+
implement and media consumers (`3tears-agent-tools`) accept: `VisionProvider`,
|
|
41
|
+
`ReferenceVisionProvider`, `TextProvider`, `TranscriptionProvider`,
|
|
42
|
+
`ImageGenerationBackend`, `MediaStorage` and `ObjectStore`. The value types
|
|
43
|
+
that cross them: `MediaInfo`, `GeneratedImage`, `ObjectHandle`,
|
|
44
|
+
`ObjectListing` and `MediaSizeLimitExceeded`. Plus the extraction-status and
|
|
45
|
+
generation-metadata constants, and the object-key builder `build_object_key`.
|
|
46
|
+
|
|
47
|
+
`MediaFacets` carries the additive carrier facets: rights status, pixel
|
|
48
|
+
dimensions, and whether a locator points at the file itself or at the page
|
|
49
|
+
containing it. The vocabulary grows by addition only, and a consumer that
|
|
50
|
+
does not recognise a facet ignores it rather than failing, so a new carrier
|
|
51
|
+
ships without a coordinated release.
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from threetears.interfaces.media import LOCATOR_KIND_DIRECT_FILE, MediaFacets
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Install
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install 3tears-interfaces
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Versioning policy
|
|
64
|
+
|
|
65
|
+
`3tears-interfaces` versions in lockstep with the rest of the 3tears
|
|
66
|
+
monorepo: every package shares one version, tracking the framework git tag.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "3tears-interfaces"
|
|
7
|
+
version = "0.93.0"
|
|
8
|
+
description = "Dependency-free Protocols and shared vocabulary for the 3tears family"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.14"
|
|
11
|
+
authors = [{name = "pace"}]
|
|
12
|
+
license = "MIT"
|
|
13
|
+
license-files = ["LICENSE"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Framework :: AsyncIO",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.14",
|
|
20
|
+
"Topic :: Security",
|
|
21
|
+
"Topic :: Software Development :: Libraries",
|
|
22
|
+
"Typing :: Typed",
|
|
23
|
+
]
|
|
24
|
+
# The interfaces package: Protocols, the value types and enums that cross them, and pure
|
|
25
|
+
# helpers over those types. No implementations, no third-party imports, no dependencies --
|
|
26
|
+
# enforced by the dependency-free checks in tests/enforcement/. Providers and consumers on
|
|
27
|
+
# both sides of every Protocol here depend on this package; it depends on nothing, so
|
|
28
|
+
# speaking the vocabulary never costs either side the other's closure.
|
|
29
|
+
dependencies = []
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Repository = "https://github.com/pacepace/3tears"
|
|
33
|
+
|
|
34
|
+
[tool.hatch.build.targets.wheel]
|
|
35
|
+
packages = ["src/threetears"]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""The 3tears family's shared Protocols and vocabulary, in one package that depends on nothing.
|
|
2
|
+
|
|
3
|
+
One module per domain:
|
|
4
|
+
|
|
5
|
+
- :mod:`threetears.interfaces.access` -- the identity and authorization vocabulary
|
|
6
|
+
``3tears-iam`` (who a caller is) and ``3tears-agent-acl`` (what they may do) both name.
|
|
7
|
+
- :mod:`threetears.interfaces.media` -- the media capability Protocols shared by media
|
|
8
|
+
providers (``3tears-models``, ``3tears-object-store``) and consumers (``3tears-agent-tools``).
|
|
9
|
+
|
|
10
|
+
The rule: Protocols, the value types and enums that cross them, and pure helpers over those
|
|
11
|
+
types. No implementations, no third-party imports, no dependencies. A package that speaks
|
|
12
|
+
the vocabulary or implements a Protocol never inherits another feature package's closure by
|
|
13
|
+
doing so. The workspace's ``tests/enforcement/`` enforces it: every module-top import here
|
|
14
|
+
must be the stdlib or ``threetears.interfaces`` itself.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
# Version derived from package metadata so the metadata is the single source of truth: a
|
|
18
|
+
# release that bumps pyproject cannot drift the runtime ``__version__``. ``importlib.metadata``
|
|
19
|
+
# is stdlib, so the dependency-free floor is untouched.
|
|
20
|
+
from importlib.metadata import PackageNotFoundError as _PackageNotFoundError
|
|
21
|
+
from importlib.metadata import version as _version
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
__version__ = _version("3tears-interfaces")
|
|
25
|
+
except _PackageNotFoundError: # pragma: no cover - dev fallback
|
|
26
|
+
__version__ = "unknown"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""The sensitive-action categories authentication and authorization both name.
|
|
2
|
+
|
|
3
|
+
Two checks guard the same six actions. Authorization (``3tears-agent-acl``'s
|
|
4
|
+
``authorize_from_claims``) refuses them outright under impersonation. Authentication
|
|
5
|
+
(``3tears-iam``'s ``stepup``) lets them through only on a recent sign-in. Each check is
|
|
6
|
+
only as good as its agreement with the other about what the six are, so the set is
|
|
7
|
+
declared once, here, where neither side pays for the other's dependencies to import it.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from enum import StrEnum
|
|
13
|
+
|
|
14
|
+
__all__ = ["ImpersonationCategory"]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ImpersonationCategory(StrEnum):
|
|
18
|
+
"""The fixed, non-tenant-configurable sensitive-action category set.
|
|
19
|
+
|
|
20
|
+
security-model.md's Impersonation paragraph names these six categories verbatim:
|
|
21
|
+
"credential, passkey, and MFA management; account deletion; API-key mint/rotate for the
|
|
22
|
+
target; email change; RBAC grant changes; audit editing."
|
|
23
|
+
|
|
24
|
+
Two enforcement points read it. Under impersonation every member is deny-listed: there is
|
|
25
|
+
no partial or tenant-configurable subset. Outside impersonation every member requires
|
|
26
|
+
step-up re-authentication: the same taxonomy, enforced by freshness instead of subtraction.
|
|
27
|
+
|
|
28
|
+
The string values are a wire vocabulary as well as a type: a token, an audit record or a
|
|
29
|
+
peer repository may carry them, so a member is added, never renamed.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
CREDENTIAL_PASSKEY_MFA_MANAGEMENT = "credential_passkey_mfa_management"
|
|
33
|
+
ACCOUNT_DELETION = "account_deletion"
|
|
34
|
+
APIKEY_MINT_ROTATE_FOR_TARGET = "apikey_mint_rotate_for_target"
|
|
35
|
+
EMAIL_CHANGE = "email_change"
|
|
36
|
+
RBAC_GRANT_CHANGE = "rbac_grant_change"
|
|
37
|
+
AUDIT_EDITING = "audit_editing"
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Media capability interfaces.
|
|
2
|
+
|
|
3
|
+
Pure interface types -- ``typing.Protocol`` classes and stdlib dataclasses -- shared between
|
|
4
|
+
media providers (``3tears-models``, ``3tears-object-store``) and media consumers
|
|
5
|
+
(``3tears-agent-tools``). Implementing or accepting one never inherits a feature package's
|
|
6
|
+
dependency closure: ``3tears-interfaces`` depends on nothing (see :mod:`threetears.interfaces`).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from threetears.interfaces.media.facets import (
|
|
10
|
+
LOCATOR_KIND_CONTAINING_PAGE,
|
|
11
|
+
LOCATOR_KIND_DIRECT_FILE,
|
|
12
|
+
MediaFacets,
|
|
13
|
+
)
|
|
14
|
+
from threetears.interfaces.media.keys import build_object_key
|
|
15
|
+
from threetears.interfaces.media.protocols import (
|
|
16
|
+
EXTRACTION_STATUS_COMPLETE,
|
|
17
|
+
EXTRACTION_STATUS_FAILED,
|
|
18
|
+
EXTRACTION_STATUS_NONE,
|
|
19
|
+
EXTRACTION_STATUS_PENDING,
|
|
20
|
+
EXTRACTION_STATUS_REFUSED,
|
|
21
|
+
EXTRACTION_STATUS_UNCHANGED,
|
|
22
|
+
GENERATION_IGNORED,
|
|
23
|
+
GENERATION_SEED,
|
|
24
|
+
GENERATION_SIZE,
|
|
25
|
+
GENERATION_SOURCE_USED,
|
|
26
|
+
OBJECT_HANDLE_METADATA_KEY,
|
|
27
|
+
GeneratedImage,
|
|
28
|
+
ImageGenerationBackend,
|
|
29
|
+
MediaInfo,
|
|
30
|
+
MediaSizeLimitExceeded,
|
|
31
|
+
MediaStorage,
|
|
32
|
+
ObjectHandle,
|
|
33
|
+
ObjectListing,
|
|
34
|
+
ObjectStore,
|
|
35
|
+
TextProvider,
|
|
36
|
+
TranscriptionProvider,
|
|
37
|
+
ReferenceVisionProvider,
|
|
38
|
+
VisionProvider,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"EXTRACTION_STATUS_COMPLETE",
|
|
43
|
+
"EXTRACTION_STATUS_FAILED",
|
|
44
|
+
"EXTRACTION_STATUS_NONE",
|
|
45
|
+
"EXTRACTION_STATUS_PENDING",
|
|
46
|
+
"EXTRACTION_STATUS_REFUSED",
|
|
47
|
+
"EXTRACTION_STATUS_UNCHANGED",
|
|
48
|
+
"GENERATION_IGNORED",
|
|
49
|
+
"GENERATION_SEED",
|
|
50
|
+
"GENERATION_SIZE",
|
|
51
|
+
"GENERATION_SOURCE_USED",
|
|
52
|
+
"LOCATOR_KIND_CONTAINING_PAGE",
|
|
53
|
+
"LOCATOR_KIND_DIRECT_FILE",
|
|
54
|
+
"OBJECT_HANDLE_METADATA_KEY",
|
|
55
|
+
"GeneratedImage",
|
|
56
|
+
"ImageGenerationBackend",
|
|
57
|
+
"MediaFacets",
|
|
58
|
+
"MediaInfo",
|
|
59
|
+
"MediaSizeLimitExceeded",
|
|
60
|
+
"MediaStorage",
|
|
61
|
+
"ObjectHandle",
|
|
62
|
+
"ObjectListing",
|
|
63
|
+
"ObjectStore",
|
|
64
|
+
"TextProvider",
|
|
65
|
+
"TranscriptionProvider",
|
|
66
|
+
"ReferenceVisionProvider",
|
|
67
|
+
"VisionProvider",
|
|
68
|
+
"build_object_key",
|
|
69
|
+
]
|