agentauthlayer 0.1.2__tar.gz → 0.1.4__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.
- agentauthlayer-0.1.4/MANIFEST.in +2 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/PKG-INFO +71 -8
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/README.md +60 -7
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/cli.py +91 -4
- agentauthlayer-0.1.4/agent_auth/runtime.py +25 -0
- agentauthlayer-0.1.4/agent_auth/server_runtime.py +123 -0
- agentauthlayer-0.1.4/agent_auth/web_dist/assets/index-BBJ7rinV.css +1 -0
- agentauthlayer-0.1.4/agent_auth/web_dist/assets/index-DXUoW2DG.js +429 -0
- agentauthlayer-0.1.4/agent_auth/web_dist/favicon.ico +0 -0
- agentauthlayer-0.1.4/agent_auth/web_dist/grid.svg +8 -0
- agentauthlayer-0.1.4/agent_auth/web_dist/index.html +18 -0
- agentauthlayer-0.1.4/agent_auth/web_dist/placeholder.svg +40 -0
- agentauthlayer-0.1.4/agent_auth/web_dist/robots.txt +14 -0
- agentauthlayer-0.1.4/agent_auth_definitive_guide.pdf +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agentauthlayer.egg-info/PKG-INFO +71 -8
- agentauthlayer-0.1.4/agentauthlayer.egg-info/SOURCES.txt +113 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agentauthlayer.egg-info/entry_points.txt +1 -0
- agentauthlayer-0.1.4/agentauthlayer.egg-info/requires.txt +12 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agentauthlayer.egg-info/top_level.txt +1 -0
- agentauthlayer-0.1.4/auth_app/__init__.py +0 -0
- agentauthlayer-0.1.4/auth_app/api/__init__.py +0 -0
- agentauthlayer-0.1.4/auth_app/api/routes/__init__.py +0 -0
- agentauthlayer-0.1.4/auth_app/api/routes/agents.py +94 -0
- agentauthlayer-0.1.4/auth_app/api/routes/audit.py +19 -0
- agentauthlayer-0.1.4/auth_app/api/routes/auth.py +81 -0
- agentauthlayer-0.1.4/auth_app/api/routes/bootstrap.py +117 -0
- agentauthlayer-0.1.4/auth_app/api/routes/health.py +10 -0
- agentauthlayer-0.1.4/auth_app/api/routes/policy.py +218 -0
- agentauthlayer-0.1.4/auth_app/api/routes/projects.py +84 -0
- agentauthlayer-0.1.4/auth_app/api/routes/tokens.py +50 -0
- agentauthlayer-0.1.4/auth_app/api/routes/users.py +182 -0
- agentauthlayer-0.1.4/auth_app/core/__init__.py +0 -0
- agentauthlayer-0.1.4/auth_app/core/config.py +49 -0
- agentauthlayer-0.1.4/auth_app/core/db.py +28 -0
- agentauthlayer-0.1.4/auth_app/core/errors.py +21 -0
- agentauthlayer-0.1.4/auth_app/core/logging.py +11 -0
- agentauthlayer-0.1.4/auth_app/dependencies/__init__.py +0 -0
- agentauthlayer-0.1.4/auth_app/dependencies/auth.py +140 -0
- agentauthlayer-0.1.4/auth_app/dependencies/security.py +40 -0
- agentauthlayer-0.1.4/auth_app/dependencies/user.py +38 -0
- agentauthlayer-0.1.4/auth_app/domain/__init__.py +0 -0
- agentauthlayer-0.1.4/auth_app/domain/enums.py +12 -0
- agentauthlayer-0.1.4/auth_app/domain/models.py +75 -0
- agentauthlayer-0.1.4/auth_app/main.py +76 -0
- agentauthlayer-0.1.4/auth_app/middleware/__init__.py +0 -0
- agentauthlayer-0.1.4/auth_app/middleware/correlation.py +27 -0
- agentauthlayer-0.1.4/auth_app/repositories/__init__.py +0 -0
- agentauthlayer-0.1.4/auth_app/repositories/agent_repo.py +28 -0
- agentauthlayer-0.1.4/auth_app/repositories/audit_repo.py +16 -0
- agentauthlayer-0.1.4/auth_app/repositories/constraint_repo.py +15 -0
- agentauthlayer-0.1.4/auth_app/repositories/contracts.py +157 -0
- agentauthlayer-0.1.4/auth_app/repositories/delegation_repo.py +22 -0
- agentauthlayer-0.1.4/auth_app/repositories/project_repo.py +37 -0
- agentauthlayer-0.1.4/auth_app/repositories/role_repo.py +19 -0
- agentauthlayer-0.1.4/auth_app/repositories/sqlite_agent_repo.py +113 -0
- agentauthlayer-0.1.4/auth_app/repositories/sqlite_audit_repo.py +75 -0
- agentauthlayer-0.1.4/auth_app/repositories/sqlite_constraint_repo.py +46 -0
- agentauthlayer-0.1.4/auth_app/repositories/sqlite_delegation_repo.py +84 -0
- agentauthlayer-0.1.4/auth_app/repositories/sqlite_permission_repo.py +40 -0
- agentauthlayer-0.1.4/auth_app/repositories/sqlite_project_repo.py +104 -0
- agentauthlayer-0.1.4/auth_app/repositories/sqlite_role_repo.py +67 -0
- agentauthlayer-0.1.4/auth_app/repositories/sqlite_token_repo.py +92 -0
- agentauthlayer-0.1.4/auth_app/repositories/sqlite_user_repo.py +217 -0
- agentauthlayer-0.1.4/auth_app/repositories/token_repo.py +24 -0
- agentauthlayer-0.1.4/auth_app/repositories/user_repo.py +79 -0
- agentauthlayer-0.1.4/auth_app/schemas/__init__.py +0 -0
- agentauthlayer-0.1.4/auth_app/schemas/agent.py +26 -0
- agentauthlayer-0.1.4/auth_app/schemas/audit.py +12 -0
- agentauthlayer-0.1.4/auth_app/schemas/auth.py +18 -0
- agentauthlayer-0.1.4/auth_app/schemas/bootstrap.py +20 -0
- agentauthlayer-0.1.4/auth_app/schemas/device_agents.py +12 -0
- agentauthlayer-0.1.4/auth_app/schemas/policy.py +80 -0
- agentauthlayer-0.1.4/auth_app/schemas/project.py +29 -0
- agentauthlayer-0.1.4/auth_app/schemas/token.py +35 -0
- agentauthlayer-0.1.4/auth_app/schemas/user.py +100 -0
- agentauthlayer-0.1.4/auth_app/services/__init__.py +0 -0
- agentauthlayer-0.1.4/auth_app/services/agent_service.py +48 -0
- agentauthlayer-0.1.4/auth_app/services/audit_service.py +48 -0
- agentauthlayer-0.1.4/auth_app/services/device_agent_service.py +45 -0
- agentauthlayer-0.1.4/auth_app/services/policy_service.py +77 -0
- agentauthlayer-0.1.4/auth_app/services/project_service.py +38 -0
- agentauthlayer-0.1.4/auth_app/services/token_service.py +89 -0
- agentauthlayer-0.1.4/auth_app/services/user_service.py +47 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/pyproject.toml +17 -3
- agentauthlayer-0.1.2/agentauthlayer.egg-info/SOURCES.txt +0 -38
- agentauthlayer-0.1.2/agentauthlayer.egg-info/requires.txt +0 -2
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/__init__.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/__main__.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/agents.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/audit.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/auth.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/client.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/context.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/core.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/credentials.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/delegation.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/exceptions.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/models.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/policy.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/policy_service.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/principals.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/registry.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/session.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/storage.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/tokens.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agent_auth/users.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/agentauthlayer.egg-info/dependency_links.txt +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/setup.cfg +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/tests/test_agent_auth_library.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/tests/test_auth_flow.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/tests/test_core_first_boundary.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/tests/test_health.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/tests/test_iam_policy.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/tests/test_project_flow.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/tests/test_sqlite_repos.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/tests/test_storage.py +0 -0
- {agentauthlayer-0.1.2 → agentauthlayer-0.1.4}/tests/test_tool_registry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentauthlayer
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Library-first authentication and authorization SDK for AI agents
|
|
5
5
|
Author: Vaibhav Ahluwalia
|
|
6
6
|
License: MIT
|
|
@@ -17,19 +17,33 @@ Requires-Python: >=3.10
|
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
Requires-Dist: requests>=2.31.0
|
|
19
19
|
Requires-Dist: python-jose>=3.3.0
|
|
20
|
+
Requires-Dist: fastapi
|
|
21
|
+
Requires-Dist: uvicorn
|
|
22
|
+
Requires-Dist: pydantic
|
|
23
|
+
Requires-Dist: pydantic-settings
|
|
24
|
+
Requires-Dist: passlib[bcrypt]
|
|
25
|
+
Requires-Dist: bcrypt==4.0.1
|
|
26
|
+
Requires-Dist: python-multipart
|
|
27
|
+
Requires-Dist: httpx
|
|
28
|
+
Requires-Dist: sqlalchemy
|
|
29
|
+
Requires-Dist: email-validator
|
|
20
30
|
|
|
21
31
|
# agentauthlayer
|
|
22
32
|
|
|
23
|
-
|
|
33
|
+
Unified SDK and local control plane package for Agent Auth.
|
|
24
34
|
|
|
25
35
|
`agentauthlayer` helps you:
|
|
36
|
+
- start a local Agent Auth backend and UI with one command
|
|
26
37
|
- authenticate once and reuse local credentials
|
|
27
38
|
- register agents from code
|
|
28
39
|
- sync tool and capability definitions
|
|
29
40
|
- evaluate permissions against the control plane
|
|
30
41
|
- apply permission checks inside runtime functions
|
|
31
42
|
|
|
32
|
-
This package
|
|
43
|
+
This package now ships as a unified developer install containing:
|
|
44
|
+
- the reusable Python SDK layer
|
|
45
|
+
- the local control plane backend runtime
|
|
46
|
+
- the packaged admin UI assets
|
|
33
47
|
|
|
34
48
|
## Install
|
|
35
49
|
|
|
@@ -39,7 +53,38 @@ pip install agentauthlayer
|
|
|
39
53
|
|
|
40
54
|
## Quickstart
|
|
41
55
|
|
|
42
|
-
### 1.
|
|
56
|
+
### 1. Start the local control plane
|
|
57
|
+
|
|
58
|
+
For a local developer setup, start Agent Auth with one command:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
agentauth up
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This starts the packaged local control plane on `http://127.0.0.1:8002` by default.
|
|
65
|
+
|
|
66
|
+
If you want a different port:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
agentauth up --port 8014
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 2. First-time developer setup
|
|
73
|
+
|
|
74
|
+
For a fresh deployment:
|
|
75
|
+
|
|
76
|
+
1. Open the UI in your browser.
|
|
77
|
+
2. Create the first super admin password.
|
|
78
|
+
3. Create your first project.
|
|
79
|
+
4. Then log in from the CLI.
|
|
80
|
+
|
|
81
|
+
Open the UI with:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
agentauth ui --base-url http://127.0.0.1:8002
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Then log in once:
|
|
43
88
|
|
|
44
89
|
```bash
|
|
45
90
|
agentauth login --base-url http://127.0.0.1:8002
|
|
@@ -55,7 +100,9 @@ agentauth logout
|
|
|
55
100
|
agentauth ui
|
|
56
101
|
```
|
|
57
102
|
|
|
58
|
-
|
|
103
|
+
If the deployment has not been initialized yet, `agentauth login` will tell you to finish setup in the UI first.
|
|
104
|
+
|
|
105
|
+
### 3. Define tools and agents in code
|
|
59
106
|
|
|
60
107
|
```python
|
|
61
108
|
from agent_auth import register_tool, register_agent, require_permission
|
|
@@ -75,7 +122,7 @@ register_agent(
|
|
|
75
122
|
)
|
|
76
123
|
```
|
|
77
124
|
|
|
78
|
-
###
|
|
125
|
+
### 4. Sync everything with one command
|
|
79
126
|
|
|
80
127
|
```bash
|
|
81
128
|
agentauth sync --module your_module_name
|
|
@@ -111,6 +158,15 @@ export AGENT_AUTH_URL=http://127.0.0.1:8002
|
|
|
111
158
|
export AGENT_AUTH_TOKEN=YOUR_ADMIN_OR_SERVICE_TOKEN
|
|
112
159
|
```
|
|
113
160
|
|
|
161
|
+
`AGENT_AUTH_TOKEN` is typically a bearer token, often represented as a long JWT string.
|
|
162
|
+
|
|
163
|
+
Recommended usage:
|
|
164
|
+
- use `agentauth login` for local human developer workflows
|
|
165
|
+
- use `AGENT_AUTH_TOKEN` for CI, automation, or service-driven execution
|
|
166
|
+
|
|
167
|
+
If an env token expires, requests will fail until you replace it or log in again.
|
|
168
|
+
Avoid committing tokens into source control or long-lived shared `.env` files.
|
|
169
|
+
|
|
114
170
|
Resolution order used by `AuthAPIClient()`:
|
|
115
171
|
1. explicit constructor arguments
|
|
116
172
|
2. environment variables
|
|
@@ -160,12 +216,13 @@ agentauth delete-agent research-bot-01
|
|
|
160
216
|
|
|
161
217
|
This package provides:
|
|
162
218
|
- the Python SDK (`agent_auth`)
|
|
219
|
+
- local control plane startup via `agentauth up`
|
|
220
|
+
- packaged backend runtime (`auth_app`)
|
|
221
|
+
- packaged admin UI assets
|
|
163
222
|
- CLI helpers for login, sync, and agent cleanup
|
|
164
223
|
- registry-based tool and agent sync
|
|
165
224
|
- permission evaluation helpers
|
|
166
225
|
|
|
167
|
-
It does not package the full control plane server or admin dashboard.
|
|
168
|
-
|
|
169
226
|
## Suitable use cases
|
|
170
227
|
|
|
171
228
|
- Python agent runtimes
|
|
@@ -181,6 +238,12 @@ It does not package the full control plane server or admin dashboard.
|
|
|
181
238
|
|
|
182
239
|
## Notes
|
|
183
240
|
|
|
241
|
+
The package naming model is:
|
|
242
|
+
|
|
243
|
+
- install name: `agentauthlayer`
|
|
244
|
+
- CLI: `agentauth`
|
|
245
|
+
- Python import namespace: `agent_auth`
|
|
246
|
+
|
|
184
247
|
The import path remains:
|
|
185
248
|
|
|
186
249
|
```python
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
# agentauthlayer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Unified SDK and local control plane package for Agent Auth.
|
|
4
4
|
|
|
5
5
|
`agentauthlayer` helps you:
|
|
6
|
+
- start a local Agent Auth backend and UI with one command
|
|
6
7
|
- authenticate once and reuse local credentials
|
|
7
8
|
- register agents from code
|
|
8
9
|
- sync tool and capability definitions
|
|
9
10
|
- evaluate permissions against the control plane
|
|
10
11
|
- apply permission checks inside runtime functions
|
|
11
12
|
|
|
12
|
-
This package
|
|
13
|
+
This package now ships as a unified developer install containing:
|
|
14
|
+
- the reusable Python SDK layer
|
|
15
|
+
- the local control plane backend runtime
|
|
16
|
+
- the packaged admin UI assets
|
|
13
17
|
|
|
14
18
|
## Install
|
|
15
19
|
|
|
@@ -19,7 +23,38 @@ pip install agentauthlayer
|
|
|
19
23
|
|
|
20
24
|
## Quickstart
|
|
21
25
|
|
|
22
|
-
### 1.
|
|
26
|
+
### 1. Start the local control plane
|
|
27
|
+
|
|
28
|
+
For a local developer setup, start Agent Auth with one command:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
agentauth up
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This starts the packaged local control plane on `http://127.0.0.1:8002` by default.
|
|
35
|
+
|
|
36
|
+
If you want a different port:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
agentauth up --port 8014
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 2. First-time developer setup
|
|
43
|
+
|
|
44
|
+
For a fresh deployment:
|
|
45
|
+
|
|
46
|
+
1. Open the UI in your browser.
|
|
47
|
+
2. Create the first super admin password.
|
|
48
|
+
3. Create your first project.
|
|
49
|
+
4. Then log in from the CLI.
|
|
50
|
+
|
|
51
|
+
Open the UI with:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
agentauth ui --base-url http://127.0.0.1:8002
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Then log in once:
|
|
23
58
|
|
|
24
59
|
```bash
|
|
25
60
|
agentauth login --base-url http://127.0.0.1:8002
|
|
@@ -35,7 +70,9 @@ agentauth logout
|
|
|
35
70
|
agentauth ui
|
|
36
71
|
```
|
|
37
72
|
|
|
38
|
-
|
|
73
|
+
If the deployment has not been initialized yet, `agentauth login` will tell you to finish setup in the UI first.
|
|
74
|
+
|
|
75
|
+
### 3. Define tools and agents in code
|
|
39
76
|
|
|
40
77
|
```python
|
|
41
78
|
from agent_auth import register_tool, register_agent, require_permission
|
|
@@ -55,7 +92,7 @@ register_agent(
|
|
|
55
92
|
)
|
|
56
93
|
```
|
|
57
94
|
|
|
58
|
-
###
|
|
95
|
+
### 4. Sync everything with one command
|
|
59
96
|
|
|
60
97
|
```bash
|
|
61
98
|
agentauth sync --module your_module_name
|
|
@@ -91,6 +128,15 @@ export AGENT_AUTH_URL=http://127.0.0.1:8002
|
|
|
91
128
|
export AGENT_AUTH_TOKEN=YOUR_ADMIN_OR_SERVICE_TOKEN
|
|
92
129
|
```
|
|
93
130
|
|
|
131
|
+
`AGENT_AUTH_TOKEN` is typically a bearer token, often represented as a long JWT string.
|
|
132
|
+
|
|
133
|
+
Recommended usage:
|
|
134
|
+
- use `agentauth login` for local human developer workflows
|
|
135
|
+
- use `AGENT_AUTH_TOKEN` for CI, automation, or service-driven execution
|
|
136
|
+
|
|
137
|
+
If an env token expires, requests will fail until you replace it or log in again.
|
|
138
|
+
Avoid committing tokens into source control or long-lived shared `.env` files.
|
|
139
|
+
|
|
94
140
|
Resolution order used by `AuthAPIClient()`:
|
|
95
141
|
1. explicit constructor arguments
|
|
96
142
|
2. environment variables
|
|
@@ -140,12 +186,13 @@ agentauth delete-agent research-bot-01
|
|
|
140
186
|
|
|
141
187
|
This package provides:
|
|
142
188
|
- the Python SDK (`agent_auth`)
|
|
189
|
+
- local control plane startup via `agentauth up`
|
|
190
|
+
- packaged backend runtime (`auth_app`)
|
|
191
|
+
- packaged admin UI assets
|
|
143
192
|
- CLI helpers for login, sync, and agent cleanup
|
|
144
193
|
- registry-based tool and agent sync
|
|
145
194
|
- permission evaluation helpers
|
|
146
195
|
|
|
147
|
-
It does not package the full control plane server or admin dashboard.
|
|
148
|
-
|
|
149
196
|
## Suitable use cases
|
|
150
197
|
|
|
151
198
|
- Python agent runtimes
|
|
@@ -161,6 +208,12 @@ It does not package the full control plane server or admin dashboard.
|
|
|
161
208
|
|
|
162
209
|
## Notes
|
|
163
210
|
|
|
211
|
+
The package naming model is:
|
|
212
|
+
|
|
213
|
+
- install name: `agentauthlayer`
|
|
214
|
+
- CLI: `agentauth`
|
|
215
|
+
- Python import namespace: `agent_auth`
|
|
216
|
+
|
|
164
217
|
The import path remains:
|
|
165
218
|
|
|
166
219
|
```python
|
|
@@ -12,12 +12,51 @@ import requests
|
|
|
12
12
|
from agent_auth.client import AuthAPIClient
|
|
13
13
|
from agent_auth.credentials import clear_credentials, load_credentials, save_credentials
|
|
14
14
|
from agent_auth.registry import clear_registries, list_registered_agents, list_registered_tools
|
|
15
|
+
from agent_auth.server_runtime import DEFAULT_BASE_URL, start_local_server, wait_for_health
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _response_detail(response: requests.Response) -> str:
|
|
19
|
+
try:
|
|
20
|
+
payload = response.json()
|
|
21
|
+
if isinstance(payload, dict) and payload.get('detail'):
|
|
22
|
+
return str(payload['detail'])
|
|
23
|
+
except Exception:
|
|
24
|
+
pass
|
|
25
|
+
return response.text.strip() or f'Request failed with status {response.status_code}'
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _bootstrap_status(base_url: str) -> bool | None:
|
|
29
|
+
try:
|
|
30
|
+
response = requests.get(f"{base_url}/bootstrap/status", timeout=10)
|
|
31
|
+
except requests.RequestException:
|
|
32
|
+
return None
|
|
33
|
+
if not response.ok:
|
|
34
|
+
return None
|
|
35
|
+
try:
|
|
36
|
+
payload = response.json()
|
|
37
|
+
return bool(payload.get('is_setup'))
|
|
38
|
+
except Exception:
|
|
39
|
+
return None
|
|
15
40
|
|
|
16
41
|
|
|
17
42
|
def login_command(args) -> int:
|
|
43
|
+
base_url = (args.base_url or 'http://127.0.0.1:8002').rstrip('/')
|
|
44
|
+
setup_status = _bootstrap_status(base_url)
|
|
45
|
+
|
|
46
|
+
if setup_status is False:
|
|
47
|
+
print(
|
|
48
|
+
'\nThis Agent Auth deployment has not been initialized yet.\n'
|
|
49
|
+
'First-time developer setup:\n'
|
|
50
|
+
f' 1. Open the UI: {base_url}\n'
|
|
51
|
+
' 2. Create the first super admin password\n'
|
|
52
|
+
' 3. Create your first project\n'
|
|
53
|
+
' 4. Run agentauth login again\n',
|
|
54
|
+
file=sys.stderr,
|
|
55
|
+
)
|
|
56
|
+
return 1
|
|
57
|
+
|
|
18
58
|
email = args.email or input('Email: ').strip()
|
|
19
59
|
password = args.password or getpass.getpass('Password: ')
|
|
20
|
-
base_url = (args.base_url or 'http://127.0.0.1:8002').rstrip('/')
|
|
21
60
|
|
|
22
61
|
response = requests.post(
|
|
23
62
|
f"{base_url}/users/login",
|
|
@@ -25,7 +64,15 @@ def login_command(args) -> int:
|
|
|
25
64
|
timeout=30,
|
|
26
65
|
)
|
|
27
66
|
if not response.ok:
|
|
28
|
-
|
|
67
|
+
detail = _response_detail(response)
|
|
68
|
+
if response.status_code == 401 and setup_status is not True:
|
|
69
|
+
print(
|
|
70
|
+
f"{detail}\n\n"
|
|
71
|
+
'If this is your first time using this deployment, initialize it first in the UI, then try logging in again.',
|
|
72
|
+
file=sys.stderr,
|
|
73
|
+
)
|
|
74
|
+
else:
|
|
75
|
+
print(detail, file=sys.stderr)
|
|
29
76
|
return 1
|
|
30
77
|
|
|
31
78
|
payload = response.json()
|
|
@@ -97,18 +144,58 @@ def delete_agent_command(args) -> int:
|
|
|
97
144
|
|
|
98
145
|
def ui_command(args) -> int:
|
|
99
146
|
creds = load_credentials() or {}
|
|
100
|
-
base_url = (args.base_url or creds.get('base_url') or
|
|
147
|
+
base_url = (args.base_url or creds.get('base_url') or DEFAULT_BASE_URL).rstrip('/')
|
|
101
148
|
webbrowser.open(base_url)
|
|
102
149
|
print(f'Opened UI: {base_url}')
|
|
103
150
|
return 0
|
|
104
151
|
|
|
105
152
|
|
|
153
|
+
def up_command(args) -> int:
|
|
154
|
+
host = args.host
|
|
155
|
+
port = args.port
|
|
156
|
+
process, base_url = start_local_server(host=host, port=port)
|
|
157
|
+
|
|
158
|
+
if process is None:
|
|
159
|
+
print(f'Agent Auth server is already running at {base_url}')
|
|
160
|
+
else:
|
|
161
|
+
print(f'Starting Agent Auth local control plane at {base_url}...')
|
|
162
|
+
|
|
163
|
+
healthy = wait_for_health(base_url, timeout_seconds=args.wait)
|
|
164
|
+
if not healthy:
|
|
165
|
+
print(
|
|
166
|
+
f'Agent Auth did not become ready at {base_url} within {args.wait} seconds. '
|
|
167
|
+
'Check ~/.agentauth/server.log for details.',
|
|
168
|
+
file=sys.stderr,
|
|
169
|
+
)
|
|
170
|
+
return 1
|
|
171
|
+
|
|
172
|
+
print(f'Agent Auth is running at {base_url}')
|
|
173
|
+
print('Next steps:')
|
|
174
|
+
print(f' 1. Open the UI: {base_url}')
|
|
175
|
+
print(' 2. If first time, create the super admin and first project')
|
|
176
|
+
print(f' 3. Log in: agentauth login --base-url {base_url}')
|
|
177
|
+
print(' 4. Sync your module: agentauth sync --module your_module_name')
|
|
178
|
+
|
|
179
|
+
if args.open_browser:
|
|
180
|
+
webbrowser.open(base_url)
|
|
181
|
+
print('Opened browser.')
|
|
182
|
+
|
|
183
|
+
return 0
|
|
184
|
+
|
|
185
|
+
|
|
106
186
|
def main():
|
|
107
187
|
parser = argparse.ArgumentParser(prog='agentauth', description='Agent Auth SDK CLI')
|
|
108
188
|
subparsers = parser.add_subparsers(dest='command')
|
|
109
189
|
|
|
190
|
+
up_parser = subparsers.add_parser('up', help='Start the local Agent Auth control plane')
|
|
191
|
+
up_parser.add_argument('--host', default='127.0.0.1')
|
|
192
|
+
up_parser.add_argument('--port', type=int, default=8002)
|
|
193
|
+
up_parser.add_argument('--wait', type=int, default=20)
|
|
194
|
+
up_parser.add_argument('--open-browser', action='store_true')
|
|
195
|
+
up_parser.set_defaults(func=up_command)
|
|
196
|
+
|
|
110
197
|
login_parser = subparsers.add_parser('login', help='Log in and store local credentials')
|
|
111
|
-
login_parser.add_argument('--base-url', default=
|
|
198
|
+
login_parser.add_argument('--base-url', default=DEFAULT_BASE_URL)
|
|
112
199
|
login_parser.add_argument('--email')
|
|
113
200
|
login_parser.add_argument('--password')
|
|
114
201
|
login_parser.set_defaults(func=login_command)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def project_root() -> Path:
|
|
7
|
+
return Path(__file__).resolve().parent.parent
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def packaged_frontend_dist_dir() -> Path:
|
|
11
|
+
return Path(__file__).resolve().parent / "web_dist"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def frontend_dist_dir() -> Path:
|
|
15
|
+
packaged = packaged_frontend_dist_dir()
|
|
16
|
+
if packaged.is_dir() and (packaged / "index.html").is_file():
|
|
17
|
+
return packaged
|
|
18
|
+
return project_root() / "frontend" / "dist"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def project_pdf_path() -> Path:
|
|
22
|
+
packaged = project_root() / "agent_auth_definitive_guide.pdf"
|
|
23
|
+
if packaged.is_file():
|
|
24
|
+
return packaged
|
|
25
|
+
return Path(__file__).resolve().parent.parent / "agent_auth_definitive_guide.pdf"
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import secrets
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
import time
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
import requests
|
|
11
|
+
|
|
12
|
+
from agent_auth.runtime import project_root
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
DEFAULT_HOST = "127.0.0.1"
|
|
16
|
+
DEFAULT_PORT = 8002
|
|
17
|
+
DEFAULT_BASE_URL = f"http://{DEFAULT_HOST}:{DEFAULT_PORT}"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def local_data_dir() -> Path:
|
|
21
|
+
return Path.home() / ".agentauth"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _server_key(host: str, port: int) -> str:
|
|
25
|
+
safe_host = host.replace(":", "_").replace("/", "_")
|
|
26
|
+
return f"{safe_host}_{port}"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def local_db_path(host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> Path:
|
|
30
|
+
return local_data_dir() / f"auth_{_server_key(host, port)}.db"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def local_log_path(host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> Path:
|
|
34
|
+
return local_data_dir() / f"server_{_server_key(host, port)}.log"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def local_pid_path(host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> Path:
|
|
38
|
+
return local_data_dir() / f"server_{_server_key(host, port)}.pid"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def ensure_local_env(host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> dict[str, str]:
|
|
42
|
+
data_dir = local_data_dir()
|
|
43
|
+
data_dir.mkdir(parents=True, exist_ok=True)
|
|
44
|
+
|
|
45
|
+
env = os.environ.copy()
|
|
46
|
+
env.setdefault("STORAGE_BACKEND", "sqlite")
|
|
47
|
+
env.setdefault("DATABASE_URL", f"sqlite:///{local_db_path(host, port)}")
|
|
48
|
+
env.setdefault("JWT_SECRET_KEY", f"agentauth_local_{secrets.token_urlsafe(24)}")
|
|
49
|
+
env.setdefault("CORS_ORIGINS", "*")
|
|
50
|
+
return env
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def is_running(pid: int) -> bool:
|
|
54
|
+
try:
|
|
55
|
+
os.kill(pid, 0)
|
|
56
|
+
except OSError:
|
|
57
|
+
return False
|
|
58
|
+
return True
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def read_pid(host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> int | None:
|
|
62
|
+
pid_path = local_pid_path(host, port)
|
|
63
|
+
if not pid_path.exists():
|
|
64
|
+
return None
|
|
65
|
+
try:
|
|
66
|
+
return int(pid_path.read_text().strip())
|
|
67
|
+
except Exception:
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def write_pid(pid: int, host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> None:
|
|
72
|
+
local_pid_path(host, port).write_text(str(pid))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def server_url(host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> str:
|
|
76
|
+
return f"http://{host}:{port}"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def wait_for_health(base_url: str, timeout_seconds: int = 20) -> bool:
|
|
80
|
+
deadline = time.time() + timeout_seconds
|
|
81
|
+
while time.time() < deadline:
|
|
82
|
+
try:
|
|
83
|
+
response = requests.get(f"{base_url}/health", timeout=2)
|
|
84
|
+
if response.ok:
|
|
85
|
+
return True
|
|
86
|
+
except requests.RequestException:
|
|
87
|
+
pass
|
|
88
|
+
time.sleep(0.5)
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def start_local_server(host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> tuple[subprocess.Popen[bytes] | None, str]:
|
|
93
|
+
existing_pid = read_pid(host, port)
|
|
94
|
+
base_url = server_url(host, port)
|
|
95
|
+
if existing_pid and is_running(existing_pid) and wait_for_health(base_url, timeout_seconds=2):
|
|
96
|
+
return None, base_url
|
|
97
|
+
|
|
98
|
+
env = ensure_local_env(host, port)
|
|
99
|
+
log_path = local_log_path(host, port)
|
|
100
|
+
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
101
|
+
|
|
102
|
+
cmd = [
|
|
103
|
+
sys.executable,
|
|
104
|
+
"-m",
|
|
105
|
+
"uvicorn",
|
|
106
|
+
"auth_app.main:app",
|
|
107
|
+
"--host",
|
|
108
|
+
host,
|
|
109
|
+
"--port",
|
|
110
|
+
str(port),
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
with log_path.open("ab") as log_file:
|
|
114
|
+
process = subprocess.Popen(
|
|
115
|
+
cmd,
|
|
116
|
+
cwd=str(project_root()),
|
|
117
|
+
env=env,
|
|
118
|
+
stdout=log_file,
|
|
119
|
+
stderr=subprocess.STDOUT,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
write_pid(process.pid, host, port)
|
|
123
|
+
return process, base_url
|