auths-python 0.1.0__cp38-abi3-win_amd64.whl
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.
- auths/__init__.py +147 -0
- auths/__init__.pyi +486 -0
- auths/_client.py +713 -0
- auths/_errors.py +80 -0
- auths/_native.pyd +0 -0
- auths/agent.py +55 -0
- auths/artifact.py +60 -0
- auths/attestation_query.py +141 -0
- auths/audit.py +226 -0
- auths/commit.py +28 -0
- auths/devices.py +162 -0
- auths/doctor.py +109 -0
- auths/git.py +473 -0
- auths/identity.py +221 -0
- auths/jwt.py +253 -0
- auths/org.py +310 -0
- auths/pairing.py +216 -0
- auths/policy.py +382 -0
- auths/py.typed +0 -0
- auths/rotation.py +30 -0
- auths/sign.py +5 -0
- auths/trust.py +169 -0
- auths/verify.py +111 -0
- auths/witness.py +91 -0
- auths_python-0.1.0.dist-info/METADATA +152 -0
- auths_python-0.1.0.dist-info/RECORD +28 -0
- auths_python-0.1.0.dist-info/WHEEL +4 -0
- auths_python-0.1.0.dist-info/sboms/auths-python.cyclonedx.json +14418 -0
auths/trust.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import enum
|
|
4
|
+
import json
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from auths._native import (
|
|
9
|
+
get_pinned_identity as _get_pinned_identity,
|
|
10
|
+
list_pinned_identities as _list_pinned_identities,
|
|
11
|
+
pin_identity as _pin_identity,
|
|
12
|
+
remove_pinned_identity as _remove_pinned_identity,
|
|
13
|
+
)
|
|
14
|
+
from auths._client import _map_error
|
|
15
|
+
from auths._errors import AuthsError
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TrustLevel(enum.Enum):
|
|
19
|
+
"""Trust level for a pinned identity.
|
|
20
|
+
|
|
21
|
+
Values match the Rust ``TrustLevel`` enum in ``auths-core/src/trust/pinned.rs``.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
TOFU = "tofu"
|
|
25
|
+
"""Accepted on first use (interactive prompt)."""
|
|
26
|
+
MANUAL = "manual"
|
|
27
|
+
"""Manually pinned via CLI or ``--issuer-pk``."""
|
|
28
|
+
ORG_POLICY = "org_policy"
|
|
29
|
+
"""Loaded from roots.json org policy file."""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class TrustEntry:
|
|
34
|
+
"""A pinned trusted identity."""
|
|
35
|
+
|
|
36
|
+
did: str
|
|
37
|
+
label: Optional[str]
|
|
38
|
+
trust_level: str
|
|
39
|
+
first_seen: str
|
|
40
|
+
kel_sequence: Optional[int]
|
|
41
|
+
pinned_at: str
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def trust_level_enum(self) -> TrustLevel:
|
|
45
|
+
"""Parse the trust_level string into a typed :class:`TrustLevel` enum."""
|
|
46
|
+
return TrustLevel(self.trust_level)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class TrustService:
|
|
50
|
+
"""Resource service for trust anchor management."""
|
|
51
|
+
|
|
52
|
+
def __init__(self, client):
|
|
53
|
+
self._client = client
|
|
54
|
+
|
|
55
|
+
def pin(
|
|
56
|
+
self,
|
|
57
|
+
did: str,
|
|
58
|
+
label: str | None = None,
|
|
59
|
+
trust_level: str = "manual",
|
|
60
|
+
repo_path: str | None = None,
|
|
61
|
+
) -> TrustEntry:
|
|
62
|
+
"""Pin an identity as trusted.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
did: The DID to trust (`did:keri:...` or `did:key:...`).
|
|
66
|
+
label: Optional human-readable label.
|
|
67
|
+
trust_level: One of "tofu", "manual", "org_policy".
|
|
68
|
+
|
|
69
|
+
Usage:
|
|
70
|
+
entry = client.trust.pin(identity.did, label="peer")
|
|
71
|
+
"""
|
|
72
|
+
rp = repo_path or self._client.repo_path
|
|
73
|
+
try:
|
|
74
|
+
did_out, lbl, tl, first_seen, kel_seq, pinned_at = _pin_identity(
|
|
75
|
+
did, rp, label, trust_level,
|
|
76
|
+
)
|
|
77
|
+
return TrustEntry(
|
|
78
|
+
did=did_out,
|
|
79
|
+
label=lbl,
|
|
80
|
+
trust_level=tl,
|
|
81
|
+
first_seen=first_seen,
|
|
82
|
+
kel_sequence=kel_seq,
|
|
83
|
+
pinned_at=pinned_at,
|
|
84
|
+
)
|
|
85
|
+
except (ValueError, RuntimeError) as exc:
|
|
86
|
+
raise _map_error(exc, default_cls=AuthsError) from exc
|
|
87
|
+
|
|
88
|
+
def remove(
|
|
89
|
+
self,
|
|
90
|
+
did: str,
|
|
91
|
+
repo_path: str | None = None,
|
|
92
|
+
) -> None:
|
|
93
|
+
"""Remove a pinned identity from the trust store.
|
|
94
|
+
|
|
95
|
+
Usage:
|
|
96
|
+
client.trust.remove(identity.did)
|
|
97
|
+
"""
|
|
98
|
+
rp = repo_path or self._client.repo_path
|
|
99
|
+
try:
|
|
100
|
+
_remove_pinned_identity(did, rp)
|
|
101
|
+
except (ValueError, RuntimeError) as exc:
|
|
102
|
+
raise _map_error(exc, default_cls=AuthsError) from exc
|
|
103
|
+
|
|
104
|
+
def list(
|
|
105
|
+
self,
|
|
106
|
+
repo_path: str | None = None,
|
|
107
|
+
) -> list[TrustEntry]:
|
|
108
|
+
"""List all pinned trusted identities.
|
|
109
|
+
|
|
110
|
+
Usage:
|
|
111
|
+
entries = client.trust.list()
|
|
112
|
+
"""
|
|
113
|
+
rp = repo_path or self._client.repo_path
|
|
114
|
+
try:
|
|
115
|
+
raw = _list_pinned_identities(rp)
|
|
116
|
+
data = json.loads(raw)
|
|
117
|
+
return [
|
|
118
|
+
TrustEntry(
|
|
119
|
+
did=e["did"],
|
|
120
|
+
label=e.get("label"),
|
|
121
|
+
trust_level=e["trust_level"],
|
|
122
|
+
first_seen=e["first_seen"],
|
|
123
|
+
kel_sequence=e.get("kel_sequence"),
|
|
124
|
+
pinned_at=e["pinned_at"],
|
|
125
|
+
)
|
|
126
|
+
for e in data
|
|
127
|
+
]
|
|
128
|
+
except (ValueError, RuntimeError) as exc:
|
|
129
|
+
raise _map_error(exc, default_cls=AuthsError) from exc
|
|
130
|
+
|
|
131
|
+
def get(
|
|
132
|
+
self,
|
|
133
|
+
did: str,
|
|
134
|
+
repo_path: str | None = None,
|
|
135
|
+
) -> TrustEntry | None:
|
|
136
|
+
"""Look up a specific pinned identity. Returns None if not pinned.
|
|
137
|
+
|
|
138
|
+
Usage:
|
|
139
|
+
entry = client.trust.get(identity.did)
|
|
140
|
+
"""
|
|
141
|
+
rp = repo_path or self._client.repo_path
|
|
142
|
+
try:
|
|
143
|
+
result = _get_pinned_identity(did, rp)
|
|
144
|
+
if result is None:
|
|
145
|
+
return None
|
|
146
|
+
did_out, lbl, tl, first_seen, kel_seq, pinned_at = result
|
|
147
|
+
return TrustEntry(
|
|
148
|
+
did=did_out,
|
|
149
|
+
label=lbl,
|
|
150
|
+
trust_level=tl,
|
|
151
|
+
first_seen=first_seen,
|
|
152
|
+
kel_sequence=kel_seq,
|
|
153
|
+
pinned_at=pinned_at,
|
|
154
|
+
)
|
|
155
|
+
except (ValueError, RuntimeError) as exc:
|
|
156
|
+
raise _map_error(exc, default_cls=AuthsError) from exc
|
|
157
|
+
|
|
158
|
+
def is_trusted(
|
|
159
|
+
self,
|
|
160
|
+
did: str,
|
|
161
|
+
repo_path: str | None = None,
|
|
162
|
+
) -> bool:
|
|
163
|
+
"""Check whether a DID is in the trust store.
|
|
164
|
+
|
|
165
|
+
Usage:
|
|
166
|
+
if client.trust.is_trusted(identity.did):
|
|
167
|
+
print("Trusted!")
|
|
168
|
+
"""
|
|
169
|
+
return self.get(did, repo_path=repo_path) is not None
|
auths/verify.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""Witness-based attestation chain verification."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
from auths._native import (
|
|
9
|
+
verify_at_time,
|
|
10
|
+
verify_at_time_with_capability,
|
|
11
|
+
verify_attestation,
|
|
12
|
+
verify_attestation_with_capability,
|
|
13
|
+
verify_chain,
|
|
14
|
+
verify_chain_with_capability,
|
|
15
|
+
verify_chain_with_witnesses as _verify_chain_with_witnesses,
|
|
16
|
+
verify_device_authorization,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class WitnessKey:
|
|
22
|
+
"""A witness node's identity and public key."""
|
|
23
|
+
|
|
24
|
+
did: str
|
|
25
|
+
"""The witness node's DID."""
|
|
26
|
+
public_key_hex: str
|
|
27
|
+
"""Hex-encoded Ed25519 public key of the witness."""
|
|
28
|
+
|
|
29
|
+
def __repr__(self) -> str:
|
|
30
|
+
return f"WitnessKey(did='{self.did[:20]}...')"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class WitnessConfig:
|
|
35
|
+
"""Configuration for witness quorum verification.
|
|
36
|
+
|
|
37
|
+
Examples:
|
|
38
|
+
```python
|
|
39
|
+
config = WitnessConfig(
|
|
40
|
+
receipts=[receipt1_json, receipt2_json],
|
|
41
|
+
keys=[WitnessKey("did:key:z...", "ab12...")],
|
|
42
|
+
threshold=2,
|
|
43
|
+
)
|
|
44
|
+
```
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
receipts: list[str]
|
|
48
|
+
"""JSON-serialized witness receipt strings."""
|
|
49
|
+
keys: list[WitnessKey]
|
|
50
|
+
"""Witness public keys to verify receipts against."""
|
|
51
|
+
threshold: int
|
|
52
|
+
"""Minimum number of valid witness receipts required."""
|
|
53
|
+
|
|
54
|
+
def __post_init__(self):
|
|
55
|
+
if self.threshold < 1:
|
|
56
|
+
raise ValueError(f"threshold must be >= 1, got {self.threshold}")
|
|
57
|
+
if self.threshold > len(self.keys):
|
|
58
|
+
raise ValueError(
|
|
59
|
+
f"threshold ({self.threshold}) cannot exceed number of "
|
|
60
|
+
f"witness keys ({len(self.keys)})"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def verify_chain_with_witnesses(
|
|
65
|
+
attestations_json: list[str],
|
|
66
|
+
root_pk_hex: str,
|
|
67
|
+
witnesses: WitnessConfig,
|
|
68
|
+
):
|
|
69
|
+
"""Verify an attestation chain with witness receipt quorum enforcement.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
attestations_json: List of attestation JSON strings, ordered root-to-leaf.
|
|
73
|
+
root_pk_hex: Root identity's Ed25519 public key (hex-encoded).
|
|
74
|
+
witnesses: Witness configuration with receipts, keys, and threshold.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
VerificationReport with per-link results and witness quorum status.
|
|
78
|
+
|
|
79
|
+
Raises:
|
|
80
|
+
VerificationError: If the chain or witness quorum fails verification.
|
|
81
|
+
|
|
82
|
+
Examples:
|
|
83
|
+
```python
|
|
84
|
+
report = verify_chain_with_witnesses(chain, root_key, config)
|
|
85
|
+
```
|
|
86
|
+
"""
|
|
87
|
+
keys_json = [
|
|
88
|
+
json.dumps({"did": k.did, "public_key_hex": k.public_key_hex})
|
|
89
|
+
for k in witnesses.keys
|
|
90
|
+
]
|
|
91
|
+
return _verify_chain_with_witnesses(
|
|
92
|
+
attestations_json,
|
|
93
|
+
root_pk_hex,
|
|
94
|
+
witnesses.receipts,
|
|
95
|
+
keys_json,
|
|
96
|
+
witnesses.threshold,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
__all__ = [
|
|
101
|
+
"WitnessConfig",
|
|
102
|
+
"WitnessKey",
|
|
103
|
+
"verify_at_time",
|
|
104
|
+
"verify_at_time_with_capability",
|
|
105
|
+
"verify_attestation",
|
|
106
|
+
"verify_attestation_with_capability",
|
|
107
|
+
"verify_chain",
|
|
108
|
+
"verify_chain_with_capability",
|
|
109
|
+
"verify_chain_with_witnesses",
|
|
110
|
+
"verify_device_authorization",
|
|
111
|
+
]
|
auths/witness.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from auths._native import (
|
|
8
|
+
add_witness as _add_witness,
|
|
9
|
+
list_witnesses as _list_witnesses,
|
|
10
|
+
remove_witness as _remove_witness,
|
|
11
|
+
)
|
|
12
|
+
from auths._client import _map_error
|
|
13
|
+
from auths._errors import AuthsError
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class Witness:
|
|
18
|
+
"""A configured witness endpoint."""
|
|
19
|
+
|
|
20
|
+
url: str
|
|
21
|
+
did: Optional[str]
|
|
22
|
+
label: Optional[str]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class WitnessService:
|
|
26
|
+
"""Resource service for witness configuration."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, client):
|
|
29
|
+
self._client = client
|
|
30
|
+
|
|
31
|
+
def add(
|
|
32
|
+
self,
|
|
33
|
+
url: str,
|
|
34
|
+
label: str | None = None,
|
|
35
|
+
repo_path: str | None = None,
|
|
36
|
+
) -> Witness:
|
|
37
|
+
"""Add a witness URL to the identity configuration.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
url: Witness server URL (e.g. "http://127.0.0.1:3333").
|
|
41
|
+
label: Optional human-readable label.
|
|
42
|
+
|
|
43
|
+
Usage:
|
|
44
|
+
w = client.witnesses.add("https://witness.example.com")
|
|
45
|
+
"""
|
|
46
|
+
rp = repo_path or self._client.repo_path
|
|
47
|
+
try:
|
|
48
|
+
url_out, did, lbl = _add_witness(url, rp, label)
|
|
49
|
+
return Witness(url=url_out, did=did, label=lbl)
|
|
50
|
+
except (ValueError, RuntimeError) as exc:
|
|
51
|
+
raise _map_error(exc, default_cls=AuthsError) from exc
|
|
52
|
+
|
|
53
|
+
def remove(
|
|
54
|
+
self,
|
|
55
|
+
url: str,
|
|
56
|
+
repo_path: str | None = None,
|
|
57
|
+
) -> None:
|
|
58
|
+
"""Remove a witness URL from configuration.
|
|
59
|
+
|
|
60
|
+
Usage:
|
|
61
|
+
client.witnesses.remove("https://witness.example.com")
|
|
62
|
+
"""
|
|
63
|
+
rp = repo_path or self._client.repo_path
|
|
64
|
+
try:
|
|
65
|
+
_remove_witness(url, rp)
|
|
66
|
+
except (ValueError, RuntimeError) as exc:
|
|
67
|
+
raise _map_error(exc, default_cls=AuthsError) from exc
|
|
68
|
+
|
|
69
|
+
def list(
|
|
70
|
+
self,
|
|
71
|
+
repo_path: str | None = None,
|
|
72
|
+
) -> list[Witness]:
|
|
73
|
+
"""List all configured witnesses.
|
|
74
|
+
|
|
75
|
+
Usage:
|
|
76
|
+
witnesses = client.witnesses.list()
|
|
77
|
+
"""
|
|
78
|
+
rp = repo_path or self._client.repo_path
|
|
79
|
+
try:
|
|
80
|
+
raw = _list_witnesses(rp)
|
|
81
|
+
data = json.loads(raw)
|
|
82
|
+
return [
|
|
83
|
+
Witness(
|
|
84
|
+
url=w["url"],
|
|
85
|
+
did=w.get("did"),
|
|
86
|
+
label=w.get("label"),
|
|
87
|
+
)
|
|
88
|
+
for w in data
|
|
89
|
+
]
|
|
90
|
+
except (ValueError, RuntimeError) as exc:
|
|
91
|
+
raise _map_error(exc, default_cls=AuthsError) from exc
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: auths-python
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Classifier: Development Status :: 4 - Beta
|
|
5
|
+
Classifier: Programming Language :: Python :: 3
|
|
6
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
7
|
+
Classifier: Programming Language :: Rust
|
|
8
|
+
Classifier: Operating System :: MacOS
|
|
9
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
10
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Typing :: Typed
|
|
13
|
+
Classifier: Topic :: Security :: Cryptography
|
|
14
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
15
|
+
Requires-Dist: pyjwt>=2.0 ; extra == 'jwt'
|
|
16
|
+
Requires-Dist: cryptography>=3.0 ; extra == 'jwt'
|
|
17
|
+
Provides-Extra: jwt
|
|
18
|
+
Summary: Auths Python SDK - decentralized identity for developers and AI agents
|
|
19
|
+
Keywords: identity,cryptography,did,signing,verification,git,keri
|
|
20
|
+
License: Apache-2.0
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
23
|
+
Project-URL: Bug Tracker, https://github.com/auths-dev/auths/issues
|
|
24
|
+
Project-URL: Documentation, https://docs.auths.dev
|
|
25
|
+
Project-URL: Homepage, https://auths.dev
|
|
26
|
+
Project-URL: Repository, https://github.com/auths-dev/auths
|
|
27
|
+
|
|
28
|
+
# Auths Python SDK
|
|
29
|
+
|
|
30
|
+
Decentralized identity for developers and AI agents. Sign, verify, and manage cryptographic identities with Git-native storage.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install auths-python
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick start
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from auths import Auths
|
|
42
|
+
|
|
43
|
+
auths = Auths()
|
|
44
|
+
|
|
45
|
+
# Verify an attestation
|
|
46
|
+
result = auths.verify(attestation_json=data, issuer_key=public_key_hex)
|
|
47
|
+
print(result.valid) # True
|
|
48
|
+
|
|
49
|
+
# Sign bytes
|
|
50
|
+
signature = auths.sign(b"hello world", private_key=secret_key_hex)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Identity management
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from auths import Auths
|
|
57
|
+
|
|
58
|
+
auths = Auths(repo_path="~/.auths")
|
|
59
|
+
|
|
60
|
+
# Create a cryptographic identity
|
|
61
|
+
identity = auths.identities.create(label="laptop")
|
|
62
|
+
print(identity.did) # did:keri:EBfd...
|
|
63
|
+
|
|
64
|
+
# Provision an agent (for CI, MCP servers, etc.)
|
|
65
|
+
agent = auths.identities.provision_agent(
|
|
66
|
+
identity.did,
|
|
67
|
+
name="deploy-bot",
|
|
68
|
+
capabilities=["sign"],
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Sign using the keychain-stored identity key
|
|
72
|
+
sig = auths.sign_as(b"hello world", identity=identity.did)
|
|
73
|
+
|
|
74
|
+
# Link and manage devices
|
|
75
|
+
device = auths.devices.link(identity_did=identity.did, capabilities=["sign"])
|
|
76
|
+
auths.devices.revoke(device.did, identity_did=identity.did, note="replaced")
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Git commit verification
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from auths.git import verify_commit_range
|
|
83
|
+
|
|
84
|
+
result = verify_commit_range("HEAD~5..HEAD")
|
|
85
|
+
for commit in result.commits:
|
|
86
|
+
print(f"{commit.commit_sha}: {'valid' if commit.is_valid else commit.error}")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Capability-aware verification
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# Verify an attestation grants a specific capability
|
|
93
|
+
result = auths.verify(attestation_json=data, issuer_key=key, required_capability="sign_commit")
|
|
94
|
+
|
|
95
|
+
# Verify an entire chain grants a capability
|
|
96
|
+
report = auths.verify_chain(chain, root_key, required_capability="deploy")
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Agent auth for MCP / AI frameworks
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from auths.agent import AgentAuth
|
|
103
|
+
|
|
104
|
+
auth = AgentAuth(
|
|
105
|
+
bridge_url="https://bridge.example.com",
|
|
106
|
+
attestation_chain_path=".auths/agent-chain.json",
|
|
107
|
+
)
|
|
108
|
+
token = auth.get_token(capabilities=["read", "write"])
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Error handling
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from auths import Auths, VerificationError, NetworkError
|
|
115
|
+
|
|
116
|
+
auths = Auths()
|
|
117
|
+
try:
|
|
118
|
+
result = auths.verify(attestation_json=data, issuer_key=key)
|
|
119
|
+
except VerificationError as e:
|
|
120
|
+
print(e.code) # "expired_attestation"
|
|
121
|
+
print(e.message) # "Attestation expired at 2024-01-15T..."
|
|
122
|
+
except NetworkError as e:
|
|
123
|
+
if e.should_retry:
|
|
124
|
+
pass # safe to retry
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
All errors inherit from `AuthsError` and carry `.code`, `.message`, and `.context`.
|
|
128
|
+
|
|
129
|
+
## Configuration
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
# Auto-discover (uses ~/.auths)
|
|
133
|
+
auths = Auths()
|
|
134
|
+
|
|
135
|
+
# Explicit repo path
|
|
136
|
+
auths = Auths(repo_path="/path/to/identity-repo")
|
|
137
|
+
|
|
138
|
+
# With passphrase (or set AUTHS_PASSPHRASE env var)
|
|
139
|
+
auths = Auths(passphrase="my-secret")
|
|
140
|
+
|
|
141
|
+
# Headless / CI mode
|
|
142
|
+
# Set AUTHS_KEYCHAIN_BACKEND=file for environments without a system keychain
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## API reference
|
|
146
|
+
|
|
147
|
+
Type stubs are bundled (`py.typed` + `__init__.pyi`). Your editor will show full signatures, docstrings, and return types for all methods.
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
Apache-2.0
|
|
152
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
auths/__init__.py,sha256=xvo9RtGBE676iNFg5I11KdlnXJWhapVEEsVRW3xVgz8,3956
|
|
2
|
+
auths/__init__.pyi,sha256=qXSbL9GNgJcb-f1yqU-CkhiKKdIcRiIQUROQefDpdRs,18303
|
|
3
|
+
auths/_client.py,sha256=vL2f2E-UF6gvIKfhsmzdrk0y6clXSg5bV7SAh0eQh4c,26469
|
|
4
|
+
auths/_errors.py,sha256=deTIgyCcUB_McrhVHk-vHHzXMPMe0ft748tpqgQwgpQ,2223
|
|
5
|
+
auths/_native.pyd,sha256=OcyhwpsLTdKNt9AVJK85sEqWO6AIl8v_4bZ36qAhyqw,13433856
|
|
6
|
+
auths/agent.py,sha256=OWIzWdbSs7CA2hdY21BM8qZFXL-8s7ygMUdVUw8PpLw,1713
|
|
7
|
+
auths/artifact.py,sha256=IbtHM6pJhxTdPkYx6k3veTVS49wQ4VI1yGtWt1cl4FE,2070
|
|
8
|
+
auths/attestation_query.py,sha256=KFuGXUxcpEuXawhFVzxAiqosGRaio-GtVhcuJtx10KQ,4573
|
|
9
|
+
auths/audit.py,sha256=5vQvrJU2vomIPRJeSzuHwN2lGoV696bsMWq5G-e-6Pk,7297
|
|
10
|
+
auths/commit.py,sha256=a2ue91XW2mnE5xkYVB-RSNDSHgSJf8Kzo2x8-IZvvms,870
|
|
11
|
+
auths/devices.py,sha256=QYjOP_fYZd2gYfe1EjPq-r-wWBT_G_zZU9xQ912RNEk,5085
|
|
12
|
+
auths/doctor.py,sha256=NCbY88pJLmdSqDNISL_NBIVSGFPvG7SVj4cS9k0eWZY,3061
|
|
13
|
+
auths/git.py,sha256=NXQL6DLaT0NxkvIbHXMDX2maZW1r2bFXEtCEqmUcmfc,15925
|
|
14
|
+
auths/identity.py,sha256=QGf-GAODUItdUJo0dI4Lp8PXzdL3vTIvuxu-WG50gWY,7767
|
|
15
|
+
auths/jwt.py,sha256=Q0_U578ncvOakYkiuZEnxW3FzPZ99IZHQB7010ubA5Y,8878
|
|
16
|
+
auths/org.py,sha256=Ok_uWFZQp8EDwnffh8GS2Tg98YHWw0qCM_jbgufKp-o,10330
|
|
17
|
+
auths/pairing.py,sha256=QXsFWvq-ZE1V65TbFZTbSbaP67yZ8f2Zc6eDfyW_Sko,6858
|
|
18
|
+
auths/policy.py,sha256=23kXn3tmq6x2jweK5XMhAAVSZrIuICq5KVKoglhL3dw,12616
|
|
19
|
+
auths/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
auths/rotation.py,sha256=fX64VxZKW7YMge8LU3OJ1LmDs5iH4acCAU1FYBH_XQk,900
|
|
21
|
+
auths/sign.py,sha256=sGIiKw8MYfnP3oWbepVAUQmhExWkC0D4ZvVg7XAFQrs,200
|
|
22
|
+
auths/trust.py,sha256=YbvxBkPxbu7kycJyQI_d5foyINPnP8H-AklkqqLbVuw,5108
|
|
23
|
+
auths/verify.py,sha256=ymSJNcsgyknAVCA5mP05aT-jaZD1d7oAEoNHbqac31s,3110
|
|
24
|
+
auths/witness.py,sha256=WvVnpZZFZCb8RygGs2ZBE6Y0pUfktwq6NN56rvT0DhI,2562
|
|
25
|
+
auths_python-0.1.0.dist-info/METADATA,sha256=ZUhJJoUboVMu3nhHyOOV5iq1yXvZ9ItbyX9cbzwHfSg,4304
|
|
26
|
+
auths_python-0.1.0.dist-info/WHEEL,sha256=pR3QVM8fbZ6NHAmOlF_iyjo3X1LezoW7fOuSwC4jKRw,95
|
|
27
|
+
auths_python-0.1.0.dist-info/sboms/auths-python.cyclonedx.json,sha256=4o2K2EYZQEFxp5PXZZN0NOJXYclZ1uhxI5z2lvs2-0E,479513
|
|
28
|
+
auths_python-0.1.0.dist-info/RECORD,,
|