authgebra 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.
- authgebra-0.1.0/LICENSE +42 -0
- authgebra-0.1.0/PKG-INFO +181 -0
- authgebra-0.1.0/README.md +123 -0
- authgebra-0.1.0/pyproject.toml +34 -0
- authgebra-0.1.0/setup.cfg +4 -0
- authgebra-0.1.0/src/authgebra/__init__.py +92 -0
- authgebra-0.1.0/src/authgebra/_core.py +477 -0
- authgebra-0.1.0/src/authgebra/_generated/__init__.py +2 -0
- authgebra-0.1.0/src/authgebra/_generated/aio.py +1535 -0
- authgebra-0.1.0/src/authgebra/_generated/codes.py +29 -0
- authgebra-0.1.0/src/authgebra/_generated/models.py +4041 -0
- authgebra-0.1.0/src/authgebra/_generated/operations.py +108 -0
- authgebra-0.1.0/src/authgebra/_generated/sync.py +1535 -0
- authgebra-0.1.0/src/authgebra/_model.py +252 -0
- authgebra-0.1.0/src/authgebra/_parse.py +158 -0
- authgebra-0.1.0/src/authgebra/_version.py +3 -0
- authgebra-0.1.0/src/authgebra/aclient.py +256 -0
- authgebra-0.1.0/src/authgebra/client.py +272 -0
- authgebra-0.1.0/src/authgebra/config.py +79 -0
- authgebra-0.1.0/src/authgebra/errors.py +177 -0
- authgebra-0.1.0/src/authgebra/models.py +263 -0
- authgebra-0.1.0/src/authgebra/py.typed +0 -0
- authgebra-0.1.0/src/authgebra.egg-info/PKG-INFO +181 -0
- authgebra-0.1.0/src/authgebra.egg-info/SOURCES.txt +32 -0
- authgebra-0.1.0/src/authgebra.egg-info/dependency_links.txt +1 -0
- authgebra-0.1.0/src/authgebra.egg-info/requires.txt +5 -0
- authgebra-0.1.0/src/authgebra.egg-info/top_level.txt +1 -0
- authgebra-0.1.0/tests/test_behavior.py +443 -0
- authgebra-0.1.0/tests/test_examples.py +35 -0
- authgebra-0.1.0/tests/test_fixtures.py +180 -0
- authgebra-0.1.0/tests/test_integration.py +247 -0
- authgebra-0.1.0/tests/test_operations.py +59 -0
- authgebra-0.1.0/tests/test_tls.py +42 -0
- authgebra-0.1.0/tests/test_typed_models.py +310 -0
authgebra-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Authgebra 专有软件许可
|
|
2
|
+
|
|
3
|
+
版权所有 (C) 2026 Authgebra 权利人。保留所有权利。
|
|
4
|
+
Copyright (C) 2026 The Authgebra Rights Holder. All rights reserved.
|
|
5
|
+
|
|
6
|
+
本仓库及其全部内容(包括但不限于源代码、二进制、文档、设计、数据集、
|
|
7
|
+
基准报告、测试与部署脚本,以下合称"本软件")是**专有且保密的**(proprietary
|
|
8
|
+
and confidential),受著作权法及国际著作权条约保护。
|
|
9
|
+
|
|
10
|
+
一、无许可授予
|
|
11
|
+
|
|
12
|
+
未经权利人事先书面授权,任何人不得:
|
|
13
|
+
|
|
14
|
+
1. 复制、分发、出租、出借、出售、转授权或以其他方式向第三方提供本软件
|
|
15
|
+
或其任何部分;
|
|
16
|
+
2. 修改、改编、翻译、演绎本软件,或基于本软件创作衍生作品;
|
|
17
|
+
3. 反向工程、反编译或反汇编本软件,法律明确不可排除者除外;
|
|
18
|
+
4. 移除、遮蔽或篡改本软件中的任何著作权、商标或其他权利声明;
|
|
19
|
+
5. 将本软件或其任何部分用于训练、微调、蒸馏或评估任何机器学习模型;
|
|
20
|
+
6. 将本软件作为服务对外提供(包括但不限于 SaaS、托管、API 转售)。
|
|
21
|
+
|
|
22
|
+
二、无担保
|
|
23
|
+
|
|
24
|
+
本软件按"现状"提供,不附带任何明示或默示的担保,包括但不限于对适销性、
|
|
25
|
+
特定用途适用性及不侵权的担保。在任何情况下,权利人不对任何索赔、损害
|
|
26
|
+
或其他责任承担责任,无论是在合同诉讼、侵权行为还是其他方面。
|
|
27
|
+
|
|
28
|
+
三、第三方组件
|
|
29
|
+
|
|
30
|
+
本软件包含或链接第三方开源组件,各自适用其自身许可证;这些组件清单与
|
|
31
|
+
适用条款见 `Cargo.lock`、`fronted/admin/pnpm-lock.yaml` 及
|
|
32
|
+
`docs/05-代码治理/02-依赖决策记录.md`。本节不改变上述组件原有的许可条件,
|
|
33
|
+
也不授予对本软件第一方代码的任何权利。
|
|
34
|
+
|
|
35
|
+
四、商业授权
|
|
36
|
+
|
|
37
|
+
如需获取商业授权、评估许可、OEM 或定制交付,请联系权利人。
|
|
38
|
+
|
|
39
|
+
五、终止
|
|
40
|
+
|
|
41
|
+
任何违反本许可的行为将自动终止本许可下的全部权利,且不影响权利人
|
|
42
|
+
追究其他救济的权利。
|
authgebra-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: authgebra
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python client for the Authgebra /api/v1 HTTP API (thin wrapper; performs no authorization computation).
|
|
5
|
+
License: Authgebra 专有软件许可
|
|
6
|
+
|
|
7
|
+
版权所有 (C) 2026 Authgebra 权利人。保留所有权利。
|
|
8
|
+
Copyright (C) 2026 The Authgebra Rights Holder. All rights reserved.
|
|
9
|
+
|
|
10
|
+
本仓库及其全部内容(包括但不限于源代码、二进制、文档、设计、数据集、
|
|
11
|
+
基准报告、测试与部署脚本,以下合称"本软件")是**专有且保密的**(proprietary
|
|
12
|
+
and confidential),受著作权法及国际著作权条约保护。
|
|
13
|
+
|
|
14
|
+
一、无许可授予
|
|
15
|
+
|
|
16
|
+
未经权利人事先书面授权,任何人不得:
|
|
17
|
+
|
|
18
|
+
1. 复制、分发、出租、出借、出售、转授权或以其他方式向第三方提供本软件
|
|
19
|
+
或其任何部分;
|
|
20
|
+
2. 修改、改编、翻译、演绎本软件,或基于本软件创作衍生作品;
|
|
21
|
+
3. 反向工程、反编译或反汇编本软件,法律明确不可排除者除外;
|
|
22
|
+
4. 移除、遮蔽或篡改本软件中的任何著作权、商标或其他权利声明;
|
|
23
|
+
5. 将本软件或其任何部分用于训练、微调、蒸馏或评估任何机器学习模型;
|
|
24
|
+
6. 将本软件作为服务对外提供(包括但不限于 SaaS、托管、API 转售)。
|
|
25
|
+
|
|
26
|
+
二、无担保
|
|
27
|
+
|
|
28
|
+
本软件按"现状"提供,不附带任何明示或默示的担保,包括但不限于对适销性、
|
|
29
|
+
特定用途适用性及不侵权的担保。在任何情况下,权利人不对任何索赔、损害
|
|
30
|
+
或其他责任承担责任,无论是在合同诉讼、侵权行为还是其他方面。
|
|
31
|
+
|
|
32
|
+
三、第三方组件
|
|
33
|
+
|
|
34
|
+
本软件包含或链接第三方开源组件,各自适用其自身许可证;这些组件清单与
|
|
35
|
+
适用条款见 `Cargo.lock`、`fronted/admin/pnpm-lock.yaml` 及
|
|
36
|
+
`docs/05-代码治理/02-依赖决策记录.md`。本节不改变上述组件原有的许可条件,
|
|
37
|
+
也不授予对本软件第一方代码的任何权利。
|
|
38
|
+
|
|
39
|
+
四、商业授权
|
|
40
|
+
|
|
41
|
+
如需获取商业授权、评估许可、OEM 或定制交付,请联系权利人。
|
|
42
|
+
|
|
43
|
+
五、终止
|
|
44
|
+
|
|
45
|
+
任何违反本许可的行为将自动终止本许可下的全部权利,且不影响权利人
|
|
46
|
+
追究其他救济的权利。
|
|
47
|
+
|
|
48
|
+
Project-URL: Repository, https://github.com/iwen-conf/authgebra-sdks
|
|
49
|
+
Project-URL: Releases, https://github.com/iwen-conf/authgebra-sdks/releases
|
|
50
|
+
Requires-Python: >=3.10
|
|
51
|
+
Description-Content-Type: text/markdown
|
|
52
|
+
License-File: LICENSE
|
|
53
|
+
Requires-Dist: httpx<1,>=0.27
|
|
54
|
+
Provides-Extra: dev
|
|
55
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
56
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
57
|
+
Dynamic: license-file
|
|
58
|
+
|
|
59
|
+
# authgebra (Python)
|
|
60
|
+
|
|
61
|
+
Official Python client for the Authgebra `/api/v1` HTTP API. It is a **thin wrapper**: it calls
|
|
62
|
+
the server and interprets the response. It does not evaluate RBAC/ABAC/ReBAC.
|
|
63
|
+
|
|
64
|
+
| | |
|
|
65
|
+
|---|---|
|
|
66
|
+
| Distribution / import | `authgebra` |
|
|
67
|
+
| Python | `>= 3.10` (tested on 3.10.22 and 3.14.7) |
|
|
68
|
+
| Runtime dependency | `httpx` |
|
|
69
|
+
| Server API | `/api/v1` |
|
|
70
|
+
| Contract digest | OpenAPI export `sdks/contracts/openapi.json`, sha256 `907bd9616dba9993c479cf551bc1e69ac046776b72dd58f5af1138be10c34c25` |
|
|
71
|
+
| Verification | **INTEGRATION_TESTED** — [evidence and limits](../DISTRIBUTION.md); native and real integration tests passed |
|
|
72
|
+
| Package status | 0.1.0 wheel and sdist on GitHub Releases; PyPI publication is tracked separately |
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
python -m pip install ./authgebra-0.1.0-py3-none-any.whl
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Quick start
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from authgebra import Client, Config, CheckRequest, ResourceRef
|
|
82
|
+
|
|
83
|
+
config = Config(base_url="https://authgebra.example", token_provider=lambda: access_token)
|
|
84
|
+
with Client(config) as client:
|
|
85
|
+
result = client.authorization.check(
|
|
86
|
+
CheckRequest(subject_id, "document:read", resource=ResourceRef("document", "doc-123"))
|
|
87
|
+
)
|
|
88
|
+
result.allowed # False is a normal result, not an exception
|
|
89
|
+
result.meta # Meta(authz_revision, snapshot_generation) or None
|
|
90
|
+
result.info.request_id, result.info.trace_id
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Async: `AsyncClient` has the same surface (`async with`, `await`, `async for`).
|
|
94
|
+
|
|
95
|
+
`client.admin.<group>.<operation_id>(...)` covers every operation in the OpenAPI export, grouped by
|
|
96
|
+
tag (`admin.users.list_users`, `admin.policies.publish_policy`, `admin.relation_tuples.create_relation_tuple`).
|
|
97
|
+
Admin calls return a named response with typed `data` and the existing `meta`, `page`, `info`,
|
|
98
|
+
`etag`, `replayed`, and `authz_revision_header` members. `from authgebra import api_models` exposes
|
|
99
|
+
generated request, response, nested object, enum, and union models. Both clients share these models.
|
|
100
|
+
Legacy request mappings and response mapping access remain supported. A query filter that collides with an SDK keyword gets a `query_` prefix
|
|
101
|
+
(`query_request_id` for the audit filter).
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from authgebra import api_models
|
|
105
|
+
|
|
106
|
+
request = api_models.CreateRoleRequest(code="reader", name="Reader")
|
|
107
|
+
created = client.admin.roles.create_role(body=request)
|
|
108
|
+
created.data.id
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Optional generated fields default to `UNSET` (absent); assigning `None` sends explicit JSON null,
|
|
112
|
+
only where the schema allows it. Zero, `False`, and empty collections remain values. Models validate
|
|
113
|
+
the reviewed machine constraints before sending; legacy mappings retain server-side validation.
|
|
114
|
+
Response decoding requires mandatory fields, preserves integer precision and accepts new object fields.
|
|
115
|
+
Source comments and `_generated/provenance.json` identify each schema and field's JSON Pointer.
|
|
116
|
+
Only genuinely open JSON schemas use the recursive `JSONValue` type.
|
|
117
|
+
|
|
118
|
+
## Authentication and transport
|
|
119
|
+
|
|
120
|
+
`token_provider` is called before every attempt (so refreshed tokens are used); async clients may pass an
|
|
121
|
+
`async def`. Tokens never appear in logs, `repr`, or exceptions. TLS verification is always on
|
|
122
|
+
(`verify=` takes `True`, a CA bundle path, or an `ssl.SSLContext`; `False` is rejected). Timeouts are
|
|
123
|
+
finite by default (connect 5 s, total 30 s per attempt); responses are capped at 8 MiB.
|
|
124
|
+
Inject `http_client=` or `transport=` to customise proxies, mTLS, etc. (the SDK does not read proxy
|
|
125
|
+
environment variables itself; an injected `httpx` client is never closed by the SDK).
|
|
126
|
+
|
|
127
|
+
## Errors
|
|
128
|
+
|
|
129
|
+
| Class | Meaning |
|
|
130
|
+
|---|---|
|
|
131
|
+
| `ApiError` | The server sent `{"error": {...}}`. Fields: `status`, `code` (raw string), `known_code`, `request_id`, `trace_id`, `violations`, `retryable` (True/False/None), `retry_after_seconds`, `commit_state`, `request_id_mismatch`. |
|
|
132
|
+
| `CursorStaleError`, `NotReadyError`, `RateLimitedError`, `ReloadPendingError` | `ApiError` subclasses for the codes callers most often branch on. |
|
|
133
|
+
| `TransportError` | No usable response: `error` is `timeout`, `connect_error`, `tls_error`, `connection_reset`, `transport`. |
|
|
134
|
+
| `ProtocolError` | A response that violates the contract: `non_json_response`, `malformed_error_body`, `malformed_success_body`, `response_too_large`, `unknown_decision`. |
|
|
135
|
+
| `PaginationError` | The page iterator refused to go on. |
|
|
136
|
+
|
|
137
|
+
Rules: branch on `code`/class, never on `message`. An unknown `code` is kept verbatim with
|
|
138
|
+
`known_code=False`. **`NOT_READY` is never turned into a deny**; an unrecognised `decision` is a
|
|
139
|
+
`ProtocolError`, not an allow.
|
|
140
|
+
|
|
141
|
+
## Writes: idempotency and "committed but not published"
|
|
142
|
+
|
|
143
|
+
* Writes are **never resent automatically**. To allow bounded resends set
|
|
144
|
+
`RetryPolicy(retry_writes=True)` **and** pass the same `idempotency_key=` (`new_idempotency_key()`) with the same body.
|
|
145
|
+
* `AUTHZ_RELOAD_PENDING` / `IDENTITY_RELOAD_PENDING` raise `ReloadPendingError` with
|
|
146
|
+
`commit_state=CommitState.COMMITTED_UNPUBLISHED`: the mutation **executed**; it is never resent,
|
|
147
|
+
and you must not report it as "in effect" before publication is confirmed (for example by reading the
|
|
148
|
+
entity or `authorization.revision()`).
|
|
149
|
+
* A write that times out or loses its connection raises `TransportError` with `commit_state=UNKNOWN`
|
|
150
|
+
(never assume "not committed"). Resend only with the same idempotency key and body.
|
|
151
|
+
* Reads (GET, plus the pure decision POSTs) retry at most `max_retries` (default 2) on `RATE_LIMITED`,
|
|
152
|
+
`NOT_READY`, timeouts and connection failures; `Retry-After` is honoured but capped by `max_delay`.
|
|
153
|
+
|
|
154
|
+
## Tracing
|
|
155
|
+
|
|
156
|
+
Every request carries a valid `X-Request-ID` (`py-<hex>` unless you pass `request_id=`) and a W3C
|
|
157
|
+
`traceparent` (yours via `traceparent=` or `Config.trace_provider`, else a new trace; each retry is a new span of the same
|
|
158
|
+
trace). Results and errors expose `request_id` (response header preferred, body as fallback) and `trace_id`
|
|
159
|
+
(`error.trace_id`, else `X-Trace-ID`/`traceparent` response headers; invalid values are ignored).
|
|
160
|
+
|
|
161
|
+
## Pagination
|
|
162
|
+
|
|
163
|
+
`list_resources(request)` returns one page; `iter_list_resources(request, max_pages=100)` yields pages lazily.
|
|
164
|
+
`CURSOR_STALE` is raised as `CursorStaleError` (the SDK never restarts silently), a snapshot-generation change
|
|
165
|
+
between pages raises `PaginationError`, and the iterator is bounded by `max_pages`.
|
|
166
|
+
|
|
167
|
+
## Versions and numbers
|
|
168
|
+
|
|
169
|
+
`authz_revision` / `snapshot_generation` are Python `int`s parsed from the raw JSON text (no float round trip).
|
|
170
|
+
Admin reads have no `meta`; the SDK reports `None`, never `0`.
|
|
171
|
+
|
|
172
|
+
## Development
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
python -m venv .venv && .venv/bin/pip install -e '.[dev]'
|
|
176
|
+
.venv/bin/python tools/generate.py --check # generated admin surface matches ../contracts/openapi.json
|
|
177
|
+
.venv/bin/python -m pytest # runs all shared fixtures (sync + async) and behavior tests
|
|
178
|
+
.venv/bin/mypy --strict src tests tools examples
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Licensing: proprietary, same terms as the Authgebra repository (`LICENSE`).
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# authgebra (Python)
|
|
2
|
+
|
|
3
|
+
Official Python client for the Authgebra `/api/v1` HTTP API. It is a **thin wrapper**: it calls
|
|
4
|
+
the server and interprets the response. It does not evaluate RBAC/ABAC/ReBAC.
|
|
5
|
+
|
|
6
|
+
| | |
|
|
7
|
+
|---|---|
|
|
8
|
+
| Distribution / import | `authgebra` |
|
|
9
|
+
| Python | `>= 3.10` (tested on 3.10.22 and 3.14.7) |
|
|
10
|
+
| Runtime dependency | `httpx` |
|
|
11
|
+
| Server API | `/api/v1` |
|
|
12
|
+
| Contract digest | OpenAPI export `sdks/contracts/openapi.json`, sha256 `907bd9616dba9993c479cf551bc1e69ac046776b72dd58f5af1138be10c34c25` |
|
|
13
|
+
| Verification | **INTEGRATION_TESTED** — [evidence and limits](../DISTRIBUTION.md); native and real integration tests passed |
|
|
14
|
+
| Package status | 0.1.0 wheel and sdist on GitHub Releases; PyPI publication is tracked separately |
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
python -m pip install ./authgebra-0.1.0-py3-none-any.whl
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick start
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from authgebra import Client, Config, CheckRequest, ResourceRef
|
|
24
|
+
|
|
25
|
+
config = Config(base_url="https://authgebra.example", token_provider=lambda: access_token)
|
|
26
|
+
with Client(config) as client:
|
|
27
|
+
result = client.authorization.check(
|
|
28
|
+
CheckRequest(subject_id, "document:read", resource=ResourceRef("document", "doc-123"))
|
|
29
|
+
)
|
|
30
|
+
result.allowed # False is a normal result, not an exception
|
|
31
|
+
result.meta # Meta(authz_revision, snapshot_generation) or None
|
|
32
|
+
result.info.request_id, result.info.trace_id
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Async: `AsyncClient` has the same surface (`async with`, `await`, `async for`).
|
|
36
|
+
|
|
37
|
+
`client.admin.<group>.<operation_id>(...)` covers every operation in the OpenAPI export, grouped by
|
|
38
|
+
tag (`admin.users.list_users`, `admin.policies.publish_policy`, `admin.relation_tuples.create_relation_tuple`).
|
|
39
|
+
Admin calls return a named response with typed `data` and the existing `meta`, `page`, `info`,
|
|
40
|
+
`etag`, `replayed`, and `authz_revision_header` members. `from authgebra import api_models` exposes
|
|
41
|
+
generated request, response, nested object, enum, and union models. Both clients share these models.
|
|
42
|
+
Legacy request mappings and response mapping access remain supported. A query filter that collides with an SDK keyword gets a `query_` prefix
|
|
43
|
+
(`query_request_id` for the audit filter).
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from authgebra import api_models
|
|
47
|
+
|
|
48
|
+
request = api_models.CreateRoleRequest(code="reader", name="Reader")
|
|
49
|
+
created = client.admin.roles.create_role(body=request)
|
|
50
|
+
created.data.id
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Optional generated fields default to `UNSET` (absent); assigning `None` sends explicit JSON null,
|
|
54
|
+
only where the schema allows it. Zero, `False`, and empty collections remain values. Models validate
|
|
55
|
+
the reviewed machine constraints before sending; legacy mappings retain server-side validation.
|
|
56
|
+
Response decoding requires mandatory fields, preserves integer precision and accepts new object fields.
|
|
57
|
+
Source comments and `_generated/provenance.json` identify each schema and field's JSON Pointer.
|
|
58
|
+
Only genuinely open JSON schemas use the recursive `JSONValue` type.
|
|
59
|
+
|
|
60
|
+
## Authentication and transport
|
|
61
|
+
|
|
62
|
+
`token_provider` is called before every attempt (so refreshed tokens are used); async clients may pass an
|
|
63
|
+
`async def`. Tokens never appear in logs, `repr`, or exceptions. TLS verification is always on
|
|
64
|
+
(`verify=` takes `True`, a CA bundle path, or an `ssl.SSLContext`; `False` is rejected). Timeouts are
|
|
65
|
+
finite by default (connect 5 s, total 30 s per attempt); responses are capped at 8 MiB.
|
|
66
|
+
Inject `http_client=` or `transport=` to customise proxies, mTLS, etc. (the SDK does not read proxy
|
|
67
|
+
environment variables itself; an injected `httpx` client is never closed by the SDK).
|
|
68
|
+
|
|
69
|
+
## Errors
|
|
70
|
+
|
|
71
|
+
| Class | Meaning |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `ApiError` | The server sent `{"error": {...}}`. Fields: `status`, `code` (raw string), `known_code`, `request_id`, `trace_id`, `violations`, `retryable` (True/False/None), `retry_after_seconds`, `commit_state`, `request_id_mismatch`. |
|
|
74
|
+
| `CursorStaleError`, `NotReadyError`, `RateLimitedError`, `ReloadPendingError` | `ApiError` subclasses for the codes callers most often branch on. |
|
|
75
|
+
| `TransportError` | No usable response: `error` is `timeout`, `connect_error`, `tls_error`, `connection_reset`, `transport`. |
|
|
76
|
+
| `ProtocolError` | A response that violates the contract: `non_json_response`, `malformed_error_body`, `malformed_success_body`, `response_too_large`, `unknown_decision`. |
|
|
77
|
+
| `PaginationError` | The page iterator refused to go on. |
|
|
78
|
+
|
|
79
|
+
Rules: branch on `code`/class, never on `message`. An unknown `code` is kept verbatim with
|
|
80
|
+
`known_code=False`. **`NOT_READY` is never turned into a deny**; an unrecognised `decision` is a
|
|
81
|
+
`ProtocolError`, not an allow.
|
|
82
|
+
|
|
83
|
+
## Writes: idempotency and "committed but not published"
|
|
84
|
+
|
|
85
|
+
* Writes are **never resent automatically**. To allow bounded resends set
|
|
86
|
+
`RetryPolicy(retry_writes=True)` **and** pass the same `idempotency_key=` (`new_idempotency_key()`) with the same body.
|
|
87
|
+
* `AUTHZ_RELOAD_PENDING` / `IDENTITY_RELOAD_PENDING` raise `ReloadPendingError` with
|
|
88
|
+
`commit_state=CommitState.COMMITTED_UNPUBLISHED`: the mutation **executed**; it is never resent,
|
|
89
|
+
and you must not report it as "in effect" before publication is confirmed (for example by reading the
|
|
90
|
+
entity or `authorization.revision()`).
|
|
91
|
+
* A write that times out or loses its connection raises `TransportError` with `commit_state=UNKNOWN`
|
|
92
|
+
(never assume "not committed"). Resend only with the same idempotency key and body.
|
|
93
|
+
* Reads (GET, plus the pure decision POSTs) retry at most `max_retries` (default 2) on `RATE_LIMITED`,
|
|
94
|
+
`NOT_READY`, timeouts and connection failures; `Retry-After` is honoured but capped by `max_delay`.
|
|
95
|
+
|
|
96
|
+
## Tracing
|
|
97
|
+
|
|
98
|
+
Every request carries a valid `X-Request-ID` (`py-<hex>` unless you pass `request_id=`) and a W3C
|
|
99
|
+
`traceparent` (yours via `traceparent=` or `Config.trace_provider`, else a new trace; each retry is a new span of the same
|
|
100
|
+
trace). Results and errors expose `request_id` (response header preferred, body as fallback) and `trace_id`
|
|
101
|
+
(`error.trace_id`, else `X-Trace-ID`/`traceparent` response headers; invalid values are ignored).
|
|
102
|
+
|
|
103
|
+
## Pagination
|
|
104
|
+
|
|
105
|
+
`list_resources(request)` returns one page; `iter_list_resources(request, max_pages=100)` yields pages lazily.
|
|
106
|
+
`CURSOR_STALE` is raised as `CursorStaleError` (the SDK never restarts silently), a snapshot-generation change
|
|
107
|
+
between pages raises `PaginationError`, and the iterator is bounded by `max_pages`.
|
|
108
|
+
|
|
109
|
+
## Versions and numbers
|
|
110
|
+
|
|
111
|
+
`authz_revision` / `snapshot_generation` are Python `int`s parsed from the raw JSON text (no float round trip).
|
|
112
|
+
Admin reads have no `meta`; the SDK reports `None`, never `0`.
|
|
113
|
+
|
|
114
|
+
## Development
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
python -m venv .venv && .venv/bin/pip install -e '.[dev]'
|
|
118
|
+
.venv/bin/python tools/generate.py --check # generated admin surface matches ../contracts/openapi.json
|
|
119
|
+
.venv/bin/python -m pytest # runs all shared fixtures (sync + async) and behavior tests
|
|
120
|
+
.venv/bin/mypy --strict src tests tools examples
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Licensing: proprietary, same terms as the Authgebra repository (`LICENSE`).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "authgebra"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Official Python client for the Authgebra /api/v1 HTTP API (thin wrapper; performs no authorization computation)."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { file = "LICENSE" }
|
|
12
|
+
dependencies = ["httpx>=0.27,<1"]
|
|
13
|
+
|
|
14
|
+
[project.urls]
|
|
15
|
+
Repository = "https://github.com/iwen-conf/authgebra-sdks"
|
|
16
|
+
Releases = "https://github.com/iwen-conf/authgebra-sdks/releases"
|
|
17
|
+
|
|
18
|
+
[project.optional-dependencies]
|
|
19
|
+
dev = ["pytest>=8", "mypy>=1.10"]
|
|
20
|
+
|
|
21
|
+
[tool.setuptools.packages.find]
|
|
22
|
+
where = ["src"]
|
|
23
|
+
|
|
24
|
+
[tool.setuptools.package-data]
|
|
25
|
+
authgebra = ["py.typed"]
|
|
26
|
+
|
|
27
|
+
[tool.mypy]
|
|
28
|
+
strict = true
|
|
29
|
+
python_version = "3.10"
|
|
30
|
+
files = ["src", "tests", "examples", "tools"]
|
|
31
|
+
|
|
32
|
+
[tool.pytest.ini_options]
|
|
33
|
+
testpaths = ["tests"]
|
|
34
|
+
pythonpath = ["src"]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Official Python client for the Authgebra ``/api/v1`` HTTP API.
|
|
2
|
+
|
|
3
|
+
A thin wrapper: it calls the server and interprets responses; it never evaluates
|
|
4
|
+
RBAC/ABAC/ReBAC itself. See ``README.md`` for semantics (results vs errors, retries, tracing).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from ._core import new_idempotency_key, new_traceparent, parse_traceparent
|
|
8
|
+
from ._generated.operations import OPERATIONS, SPEC_SHA256
|
|
9
|
+
from ._generated import models as api_models
|
|
10
|
+
from ._model import JSONValue, UNSET, Unset
|
|
11
|
+
from ._version import __version__
|
|
12
|
+
from .aclient import AsyncAuthorizationClient, AsyncClient
|
|
13
|
+
from .client import AuthorizationClient, Client
|
|
14
|
+
from .config import Config
|
|
15
|
+
from .errors import (
|
|
16
|
+
ApiError,
|
|
17
|
+
AuthgebraError,
|
|
18
|
+
CommitState,
|
|
19
|
+
CursorStaleError,
|
|
20
|
+
NotReadyError,
|
|
21
|
+
PaginationError,
|
|
22
|
+
ProtocolError,
|
|
23
|
+
RateLimitedError,
|
|
24
|
+
ReloadPendingError,
|
|
25
|
+
TransportError,
|
|
26
|
+
Violation,
|
|
27
|
+
)
|
|
28
|
+
from .models import (
|
|
29
|
+
ApiResult,
|
|
30
|
+
BatchCheckRequest,
|
|
31
|
+
BatchCheckResult,
|
|
32
|
+
BatchDecision,
|
|
33
|
+
CheckRequest,
|
|
34
|
+
CheckResult,
|
|
35
|
+
Decision,
|
|
36
|
+
ExplainRequest,
|
|
37
|
+
ExplainResult,
|
|
38
|
+
ListResourcesRequest,
|
|
39
|
+
Meta,
|
|
40
|
+
PageInfo,
|
|
41
|
+
ResourcePage,
|
|
42
|
+
ResourceRef,
|
|
43
|
+
ResponseInfo,
|
|
44
|
+
RetryPolicy,
|
|
45
|
+
RevisionResult,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
__all__ = [
|
|
49
|
+
"api_models",
|
|
50
|
+
"JSONValue",
|
|
51
|
+
"UNSET",
|
|
52
|
+
"Unset",
|
|
53
|
+
"OPERATIONS",
|
|
54
|
+
"SPEC_SHA256",
|
|
55
|
+
"ApiError",
|
|
56
|
+
"ApiResult",
|
|
57
|
+
"AsyncAuthorizationClient",
|
|
58
|
+
"AsyncClient",
|
|
59
|
+
"AuthgebraError",
|
|
60
|
+
"AuthorizationClient",
|
|
61
|
+
"BatchCheckRequest",
|
|
62
|
+
"BatchCheckResult",
|
|
63
|
+
"BatchDecision",
|
|
64
|
+
"CheckRequest",
|
|
65
|
+
"CheckResult",
|
|
66
|
+
"Client",
|
|
67
|
+
"CommitState",
|
|
68
|
+
"Config",
|
|
69
|
+
"CursorStaleError",
|
|
70
|
+
"Decision",
|
|
71
|
+
"ExplainRequest",
|
|
72
|
+
"ExplainResult",
|
|
73
|
+
"ListResourcesRequest",
|
|
74
|
+
"Meta",
|
|
75
|
+
"NotReadyError",
|
|
76
|
+
"PageInfo",
|
|
77
|
+
"PaginationError",
|
|
78
|
+
"ProtocolError",
|
|
79
|
+
"RateLimitedError",
|
|
80
|
+
"ReloadPendingError",
|
|
81
|
+
"ResourcePage",
|
|
82
|
+
"ResourceRef",
|
|
83
|
+
"ResponseInfo",
|
|
84
|
+
"RetryPolicy",
|
|
85
|
+
"RevisionResult",
|
|
86
|
+
"TransportError",
|
|
87
|
+
"Violation",
|
|
88
|
+
"__version__",
|
|
89
|
+
"new_idempotency_key",
|
|
90
|
+
"new_traceparent",
|
|
91
|
+
"parse_traceparent",
|
|
92
|
+
]
|