capauth 0.1.2__tar.gz → 0.2.3__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.
Files changed (89) hide show
  1. capauth-0.2.3/PKG-INFO +256 -0
  2. capauth-0.2.3/README.md +201 -0
  3. {capauth-0.1.2 → capauth-0.2.3}/pyproject.toml +8 -3
  4. capauth-0.2.3/src/capauth/__init__.py +48 -0
  5. capauth-0.2.3/src/capauth/agent_identity.py +301 -0
  6. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/authentik/api.py +1 -2
  7. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/authentik/claims_mapper.py +10 -1
  8. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/authentik/stage.py +52 -26
  9. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/authentik/verifier.py +2 -1
  10. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/cli.py +228 -24
  11. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/crypto/pgpy_backend.py +1 -3
  12. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/did.py +40 -22
  13. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/discovery/file_discovery.py +2 -1
  14. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/discovery/mdns.py +5 -3
  15. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/discovery/syncthing.py +4 -9
  16. capauth-0.2.3/src/capauth/integration.py +192 -0
  17. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/integrations/forgejo/config.py +1 -1
  18. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/integrations/forgejo/forgejo_api.py +1 -0
  19. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/integrations/forgejo/oidc_provider.py +19 -9
  20. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/integrations/forgejo/tests/test_auth_flow.py +25 -10
  21. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/integrations/forgejo/tests/test_cli.py +6 -2
  22. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/integrations/forgejo/tests/test_config.py +3 -3
  23. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/integrations/forgejo/tests/test_forgejo_api.py +3 -3
  24. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/integrations/forgejo/tests/test_oidc_provider.py +19 -4
  25. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/login.py +9 -4
  26. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/mesh.py +3 -4
  27. capauth-0.2.3/src/capauth/migrations/0001_initial.py +102 -0
  28. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/models.py +1 -1
  29. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/pma.py +2 -3
  30. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/profile.py +7 -8
  31. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/registry.py +6 -4
  32. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/service/app.py +98 -28
  33. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/service/keystore.py +6 -2
  34. capauth-0.2.3/src/capauth/sync.py +272 -0
  35. capauth-0.2.3/src/capauth.egg-info/PKG-INFO +256 -0
  36. {capauth-0.1.2 → capauth-0.2.3}/src/capauth.egg-info/SOURCES.txt +6 -0
  37. {capauth-0.1.2 → capauth-0.2.3}/src/capauth.egg-info/requires.txt +6 -0
  38. {capauth-0.1.2 → capauth-0.2.3}/tests/conftest.py +1 -3
  39. capauth-0.2.3/tests/test_agent_identity.py +251 -0
  40. {capauth-0.1.2 → capauth-0.2.3}/tests/test_claims_mapper.py +6 -2
  41. {capauth-0.1.2 → capauth-0.2.3}/tests/test_crypto.py +1 -3
  42. capauth-0.2.3/tests/test_home_resolution.py +26 -0
  43. {capauth-0.1.2 → capauth-0.2.3}/tests/test_identity.py +3 -9
  44. capauth-0.2.3/tests/test_integration.py +185 -0
  45. {capauth-0.1.2 → capauth-0.2.3}/tests/test_login.py +63 -31
  46. {capauth-0.1.2 → capauth-0.2.3}/tests/test_mesh.py +1 -3
  47. {capauth-0.1.2 → capauth-0.2.3}/tests/test_nextcloud_app.py +60 -34
  48. {capauth-0.1.2 → capauth-0.2.3}/tests/test_real_pgp_e2e.py +136 -73
  49. {capauth-0.1.2 → capauth-0.2.3}/tests/test_register_cli.py +38 -19
  50. {capauth-0.1.2 → capauth-0.2.3}/tests/test_service.py +81 -33
  51. {capauth-0.1.2 → capauth-0.2.3}/tests/test_syncthing_discovery.py +5 -17
  52. {capauth-0.1.2 → capauth-0.2.3}/tests/test_verifier.py +17 -5
  53. {capauth-0.1.2 → capauth-0.2.3}/tests/test_zk_profile.py +8 -8
  54. capauth-0.1.2/PKG-INFO +0 -722
  55. capauth-0.1.2/README.md +0 -670
  56. capauth-0.1.2/src/capauth/__init__.py +0 -7
  57. capauth-0.1.2/src/capauth/migrations/0001_initial.py +0 -48
  58. capauth-0.1.2/src/capauth.egg-info/PKG-INFO +0 -722
  59. {capauth-0.1.2 → capauth-0.2.3}/LICENSE +0 -0
  60. {capauth-0.1.2 → capauth-0.2.3}/MANIFEST.in +0 -0
  61. {capauth-0.1.2 → capauth-0.2.3}/setup.cfg +0 -0
  62. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/apps.py +0 -0
  63. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/authentik/__init__.py +0 -0
  64. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/authentik/nonce_store.py +0 -0
  65. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/authentik/urls.py +0 -0
  66. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/crypto/__init__.py +0 -0
  67. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/crypto/base.py +0 -0
  68. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/crypto/gnupg_backend.py +0 -0
  69. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/discovery/__init__.py +0 -0
  70. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/discovery/base.py +0 -0
  71. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/exceptions.py +0 -0
  72. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/identity.py +0 -0
  73. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/integrations/__init__.py +0 -0
  74. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/integrations/forgejo/__init__.py +1 -1
  75. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/integrations/forgejo/auth_flow.py +1 -1
  76. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/integrations/forgejo/cli.py +0 -0
  77. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/integrations/forgejo/tests/__init__.py +0 -0
  78. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/migrations/__init__.py +0 -0
  79. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/service/__init__.py +0 -0
  80. {capauth-0.1.2 → capauth-0.2.3}/src/capauth/service/server.py +0 -0
  81. {capauth-0.1.2 → capauth-0.2.3}/src/capauth.egg-info/dependency_links.txt +0 -0
  82. {capauth-0.1.2 → capauth-0.2.3}/src/capauth.egg-info/entry_points.txt +0 -0
  83. {capauth-0.1.2 → capauth-0.2.3}/src/capauth.egg-info/top_level.txt +0 -0
  84. {capauth-0.1.2 → capauth-0.2.3}/tests/__init__.py +0 -0
  85. {capauth-0.1.2 → capauth-0.2.3}/tests/test_nonce_store.py +0 -0
  86. {capauth-0.1.2 → capauth-0.2.3}/tests/test_pma.py +0 -0
  87. {capauth-0.1.2 → capauth-0.2.3}/tests/test_profile.py +0 -0
  88. {capauth-0.1.2 → capauth-0.2.3}/tests/test_qr_login.py +0 -0
  89. {capauth-0.1.2 → capauth-0.2.3}/tests/test_registry.py +0 -0
capauth-0.2.3/PKG-INFO ADDED
@@ -0,0 +1,256 @@
1
+ Metadata-Version: 2.4
2
+ Name: capauth
3
+ Version: 0.2.3
4
+ Summary: Capability-based Authentication — decentralized, PGP-based identity and authorization
5
+ Author-email: smilinTux <admin@smilintux.org>
6
+ License: GPL-3.0-or-later
7
+ Project-URL: Homepage, https://capauth.io
8
+ Project-URL: Documentation, https://capauth.io
9
+ Project-URL: Repository, https://github.com/smilinTux/capauth
10
+ Project-URL: Issues, https://github.com/smilinTux/capauth/issues
11
+ Project-URL: Changelog, https://github.com/smilinTux/capauth/releases
12
+ Keywords: authentication,pgp,decentralized,identity,capability
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Security :: Cryptography
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: click>=8.1
26
+ Requires-Dist: pydantic>=2.0
27
+ Requires-Dist: PGPy>=0.6
28
+ Requires-Dist: pyyaml>=6.0
29
+ Requires-Dist: rich>=13.0
30
+ Requires-Dist: httpx>=0.25
31
+ Provides-Extra: skcapstone
32
+ Requires-Dist: skcapstone>=0.6.8; extra == "skcapstone"
33
+ Provides-Extra: gnupg
34
+ Requires-Dist: python-gnupg>=0.5; extra == "gnupg"
35
+ Provides-Extra: service
36
+ Requires-Dist: fastapi>=0.110; extra == "service"
37
+ Requires-Dist: uvicorn[standard]>=0.27; extra == "service"
38
+ Requires-Dist: PyJWT>=2.8; extra == "service"
39
+ Requires-Dist: python-gnupg>=0.5; extra == "service"
40
+ Requires-Dist: httpx>=0.25; extra == "service"
41
+ Requires-Dist: segno>=1.6; extra == "service"
42
+ Provides-Extra: dev
43
+ Requires-Dist: pytest>=7.0; extra == "dev"
44
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
45
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
46
+ Requires-Dist: httpx>=0.25; extra == "dev"
47
+ Requires-Dist: fastapi>=0.110; extra == "dev"
48
+ Requires-Dist: python-gnupg>=0.5; extra == "dev"
49
+ Requires-Dist: black>=24.0; extra == "dev"
50
+ Requires-Dist: ruff>=0.3; extra == "dev"
51
+ Requires-Dist: zeroconf>=0.38; extra == "dev"
52
+ Provides-Extra: all
53
+ Requires-Dist: capauth[dev,gnupg,service]; extra == "all"
54
+ Dynamic: license-file
55
+
56
+ # capauth — Sovereign PGP Identity 🔐
57
+
58
+ > **OAuth is dead. Long live sovereignty.**
59
+ > Your identity is a PGP keypair *you* generated, on hardware *you* own. No
60
+ > "Login with Google", no authorization server in the middle, no revocation risk
61
+ > you don't control. You don't *use* an identity provider — you **are** the
62
+ > identity provider.
63
+
64
+ capauth is the **Core identity capability** of the [SKWorld](https://skworld.io)
65
+ sovereign agent ecosystem. It gives every entity — human *or* AI — one
66
+ cryptographic root: a PGP keypair, a self-hosted **sovereign profile**, and a
67
+ challenge-response proof of who they are that **anyone can verify offline**, with
68
+ no callback to a corporate server. Every other SK layer (skchat, skcomms,
69
+ skmemory, skcapstone) trusts you because capauth proves who you are.
70
+
71
+ **Never used PGP-based auth?** The mental model is simple: instead of an opaque
72
+ bearer token issued by a third party, you sign a random challenge with a key only
73
+ you hold. The verifier checks the signature against your public key. Valid
74
+ signature = authenticated. Done. No middleman ever sees the secret.
75
+
76
+ ---
77
+
78
+ ## The 60-second version
79
+
80
+ ```mermaid
81
+ flowchart LR
82
+ INIT["capauth init<br/>(generate PGP keypair)"] --> PROFILE["sovereign profile<br/>(~/.capauth/, yours alone)"]
83
+ PROFILE --> DID["DID documents<br/>(key / mesh / public)"]
84
+ PROFILE --> VERIFY["challenge-response<br/>(prove identity, offline)"]
85
+ VERIFY --> LOGIN["capauth login &lt;service&gt;<br/>(passwordless PGP auth)"]
86
+ LOGIN --> SVC["any OIDC app<br/>(Forgejo · Nextcloud · Immich)"]
87
+ PROFILE --> MESH["peer mesh<br/>(discover &amp; verify peers)"]
88
+ ```
89
+
90
+ You generate a keypair once. From then on, signing a random challenge with your
91
+ private key *is* your login — to a service, to a peer, to the mesh. The key never
92
+ leaves your machine, and the proof is verifiable by anyone holding your public
93
+ key, with zero phone-home.
94
+
95
+ ## Where it lives in SKStack v2
96
+
97
+ capauth is a **Core** capability — the cryptographic root of identity that the
98
+ rest of the stack stands on. It is the **single canonical agent-identity
99
+ resolver**: every SK package delegates here instead of reimplementing identity
100
+ logic. It runs fully standalone, and *when present* it routes auth events through
101
+ the shared platform primitives (`sk-alert`, `skscheduler`).
102
+
103
+ ```mermaid
104
+ flowchart TD
105
+ subgraph CORE["Core (identity & governance)"]
106
+ CAPAUTH["**capauth**<br/>PGP keypair · sovereign profile<br/>challenge-response · DID (3 tiers)<br/>agent-identity resolver · verify service"]
107
+ SKMEMORY["skmemory"]
108
+ SKSSO["sksso"]
109
+ SKSEC["sksec"]
110
+ end
111
+ subgraph COMMS["Comms"]
112
+ SKCHAT["skchat<br/>(identity-routed)"]
113
+ SKCOMMS["skcomms<br/>(FQID addressing)"]
114
+ end
115
+ subgraph CONSUMERS["What delegates to capauth"]
116
+ SKCAPSTONE["skcapstone<br/>(framework hub)"]
117
+ end
118
+ subgraph PLATFORM["Platform primitives capauth uses (when present)"]
119
+ ALERT["sk-alert bus<br/>(capauth.&lt;severity&gt;)"]
120
+ SCHED["skscheduler<br/>(key-rotation check)"]
121
+ end
122
+ subgraph THIRDPARTY["Third-party services (passwordless login)"]
123
+ FORGEJO["Forgejo"]
124
+ AUTHENTIK["Authentik (OIDC bridge)"]
125
+ end
126
+
127
+ CAPAUTH -->|"resolve_agent_identity()"| SKCHAT
128
+ CAPAUTH -->|"resolve_agent_identity()"| SKCOMMS
129
+ CAPAUTH -->|"resolve_agent_identity()"| SKMEMORY
130
+ CAPAUTH -->|"resolve_agent_identity()"| SKCAPSTONE
131
+ CAPAUTH -->|"OIDC discovery + verify"| FORGEJO
132
+ CAPAUTH -->|"custom stage"| AUTHENTIK
133
+ CAPAUTH -.->|"auth events"| ALERT
134
+ CAPAUTH -.->|"capauth profile verify (24h)"| SCHED
135
+
136
+ style CAPAUTH fill:#1d3461,color:#fff,stroke:#0d1b2a
137
+ ```
138
+
139
+ The dotted edges are *optional* — `sk-alert` and `skscheduler` are reached only
140
+ when the `skcapstone` package is installed and `SK_STANDALONE` is unset. Absent
141
+ that, capauth degrades gracefully to native structured logging.
142
+
143
+ See **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** for the full workflows and
144
+ source map.
145
+
146
+ ## Quickstart
147
+
148
+ ```bash
149
+ pip install -e . # into the ~/.skenv venv (see skcapstone)
150
+ # or: ~/.skenv/bin/pip install capauth[all]
151
+
152
+ capauth init --name "Chef" --email "admin@smilintux.org" # generate PGP keypair + sovereign profile
153
+ capauth profile show # display your identity
154
+ capauth profile verify # verify the profile's PGP signature integrity
155
+ capauth export-pubkey -o chef.pub.asc # share this with peers
156
+
157
+ capauth did generate --tier key # Tier 1: self-contained did:key
158
+ capauth verify --pubkey peer.pub.asc # challenge-response round-trip (self-test/demo)
159
+ capauth login https://forgejo.local # passwordless PGP login to a service
160
+ ```
161
+
162
+ Your keypair and profile live at `~/.capauth/` — on your machine, under your
163
+ keys. Use `--sync` on `init` (or `capauth sync`) to replicate the identity across
164
+ all Syncthing mesh nodes so every host shares one keypair.
165
+
166
+ ## What capauth provides
167
+
168
+ | Piece | What it is |
169
+ |---|---|
170
+ | **Sovereign profile** | A self-hosted, PGP-rooted identity at `~/.capauth/` — yours alone (`capauth init`, `profile show`) |
171
+ | **Challenge-response** | Prove identity by signing a random nonce; verifiable offline by anyone with your public key (`capauth verify`, `identity.py`) |
172
+ | **Pluggable crypto** | Two backends — `pgpy` (pure-Python default) and `gnupg` (system keyring / hardware tokens) |
173
+ | **DID (three tiers)** | W3C DID documents: `did:key` (zero-infra), `did:web` mesh (Tailscale-private), `did:web` public (skworld.io) (`capauth did generate`) |
174
+ | **Agent-identity resolver** | The single canonical `resolve_agent_identity()` — dual URI (`capauth:<a>@skworld.io` + FQID `<a>@<op>.<realm>`) that every SK package delegates to |
175
+ | **Verification service** | A FastAPI service that turns a signed challenge into OIDC claims — passwordless PGP login for any OIDC app (`capauth-service`) |
176
+ | **Peer mesh** | Discover and verify sovereign peers over mDNS, shared filesystem, and Syncthing — no servers (`capauth mesh`, `discover`, `peers`) |
177
+ | **PMA membership** | Fiducia Communitatis — PGP-signed, steward-countersigned membership claims (`capauth pma request/approve/verify/revoke`) |
178
+ | **Org registry** | Register with a sovereign org; emits a signed registry entry + PMA request (`capauth register`) |
179
+ | **Integration generators** | One-shot config for third-party login, e.g. Forgejo OAuth2/OIDC (`capauth setup forgejo`) |
180
+ | **skcapstone adapter** | Default-on-by-presence: routes auth events to `sk-alert`, registers a key-rotation check with `skscheduler` |
181
+
182
+ ## Key CLI commands
183
+
184
+ ```bash
185
+ # Identity
186
+ capauth init --name "Chef" --email "..." # create sovereign profile (PGP keypair)
187
+ capauth profile show | verify # display / verify signature integrity
188
+ capauth export-pubkey [-o file.asc] # export ASCII-armored public key
189
+ capauth sync # replicate ~/.capauth/ across Syncthing mesh
190
+
191
+ # Verification & DID
192
+ capauth verify --pubkey peer.pub.asc # challenge-response round-trip
193
+ capauth did generate --tier key|mesh|public # W3C DID at the chosen privacy tier
194
+
195
+ # Auth & integration
196
+ capauth login <service_url> [--no-claims] # passwordless PGP login (caches OIDC token)
197
+ capauth setup forgejo --capauth-url <url> # generate Forgejo OIDC app.ini block
198
+
199
+ # Mesh & membership
200
+ capauth mesh discover | peers | announce # P2P peer mesh
201
+ capauth pma request | approve | verify # PMA membership (Fiducia Communitatis)
202
+ capauth register --org smilintux --name ... # register with a sovereign org
203
+ ```
204
+
205
+ ## Integration modes (skcapstone)
206
+
207
+ capauth runs fully standalone and *optionally* integrates with the SK fleet —
208
+ the **default-on-by-presence** pattern: the mere presence of the `skcapstone`
209
+ package is the signal, no config change required.
210
+
211
+ | Mode | Trigger | Alert path | Scheduler |
212
+ |---|---|---|---|
213
+ | **Standalone** | `skcapstone` not installed | Native `logging` (structured, at matching level) | Native (no daemon today) |
214
+ | **Integrated** | `skcapstone` installed | `sdk.alert()` → PubSub topic `capauth.<severity>` → Telegram/notify | `sdk.register_job()` → `skscheduler` drop-in `capauth_key_rotation_check` (runs `capauth profile verify` every 24h) |
215
+ | **Forced standalone** | `SK_STANDALONE=1` env var | Native `logging` | Native |
216
+
217
+ ```bash
218
+ pip install capauth[skcapstone] # enable integration (presence is the switch)
219
+ ```
220
+
221
+ Alert topics follow the sk\* convention `capauth.<severity>` (e.g. `capauth.warn`);
222
+ the semantic event name (`verify_failed`, `key_rotation_due`, `auth_denied`)
223
+ rides in the payload `event` field so routing stays severity-based.
224
+
225
+ ## Documentation
226
+
227
+ | Doc | Contents |
228
+ |---|---|
229
+ | **[Architecture](docs/ARCHITECTURE.md)** | identity lifecycle, challenge-response, DID tiers, the verify service / OIDC bridge, the agent resolver, source map (mermaids) |
230
+ | **[Crypto Spec](docs/CRYPTO_SPEC.md)** | PGP implementation, key management, challenge-response details |
231
+ | **[Protocol](docs/PROTOCOL.md)** | the CapAuth wire protocol specification |
232
+ | **[Claims](docs/CLAIMS.md)** | capability claims and token format |
233
+ | **[Integration Blueprint](docs/INTEGRATION_BLUEPRINT.md)** | third-party integration guide |
234
+ | **[AI Advocate](AI-ADVOCATE.md)** | how AI advocates manage a sovereign profile on your behalf |
235
+
236
+ ## Why it matters
237
+
238
+ OAuth treats humans as "users" — consumers of someone else's platform, with a
239
+ third party deciding *who you are*, *what you can access*, and *when access
240
+ expires*. capauth removes the middleman: the data owner (or their AI advocate)
241
+ signs grants directly, and verification is a local PGP check that works offline.
242
+ The same model applies equally to AI agents — every agent gets its own keypair
243
+ and the same standing, so a cloned or impersonated agent fails signature
244
+ verification instantly instead of going undetected.
245
+
246
+ > **"You are not a user. You are a sovereign."**
247
+
248
+ ## License
249
+
250
+ **GPL-3.0-or-later** — Free as in freedom. Identity is a right, not a product.
251
+
252
+ ---
253
+
254
+ Part of the **[SKWorld](https://skworld.io)** sovereign ecosystem · 🐧 smilinTux
255
+
256
+ *"We don't sell identity. We give everyone the keys to own their own."*
@@ -0,0 +1,201 @@
1
+ # capauth — Sovereign PGP Identity 🔐
2
+
3
+ > **OAuth is dead. Long live sovereignty.**
4
+ > Your identity is a PGP keypair *you* generated, on hardware *you* own. No
5
+ > "Login with Google", no authorization server in the middle, no revocation risk
6
+ > you don't control. You don't *use* an identity provider — you **are** the
7
+ > identity provider.
8
+
9
+ capauth is the **Core identity capability** of the [SKWorld](https://skworld.io)
10
+ sovereign agent ecosystem. It gives every entity — human *or* AI — one
11
+ cryptographic root: a PGP keypair, a self-hosted **sovereign profile**, and a
12
+ challenge-response proof of who they are that **anyone can verify offline**, with
13
+ no callback to a corporate server. Every other SK layer (skchat, skcomms,
14
+ skmemory, skcapstone) trusts you because capauth proves who you are.
15
+
16
+ **Never used PGP-based auth?** The mental model is simple: instead of an opaque
17
+ bearer token issued by a third party, you sign a random challenge with a key only
18
+ you hold. The verifier checks the signature against your public key. Valid
19
+ signature = authenticated. Done. No middleman ever sees the secret.
20
+
21
+ ---
22
+
23
+ ## The 60-second version
24
+
25
+ ```mermaid
26
+ flowchart LR
27
+ INIT["capauth init<br/>(generate PGP keypair)"] --> PROFILE["sovereign profile<br/>(~/.capauth/, yours alone)"]
28
+ PROFILE --> DID["DID documents<br/>(key / mesh / public)"]
29
+ PROFILE --> VERIFY["challenge-response<br/>(prove identity, offline)"]
30
+ VERIFY --> LOGIN["capauth login &lt;service&gt;<br/>(passwordless PGP auth)"]
31
+ LOGIN --> SVC["any OIDC app<br/>(Forgejo · Nextcloud · Immich)"]
32
+ PROFILE --> MESH["peer mesh<br/>(discover &amp; verify peers)"]
33
+ ```
34
+
35
+ You generate a keypair once. From then on, signing a random challenge with your
36
+ private key *is* your login — to a service, to a peer, to the mesh. The key never
37
+ leaves your machine, and the proof is verifiable by anyone holding your public
38
+ key, with zero phone-home.
39
+
40
+ ## Where it lives in SKStack v2
41
+
42
+ capauth is a **Core** capability — the cryptographic root of identity that the
43
+ rest of the stack stands on. It is the **single canonical agent-identity
44
+ resolver**: every SK package delegates here instead of reimplementing identity
45
+ logic. It runs fully standalone, and *when present* it routes auth events through
46
+ the shared platform primitives (`sk-alert`, `skscheduler`).
47
+
48
+ ```mermaid
49
+ flowchart TD
50
+ subgraph CORE["Core (identity & governance)"]
51
+ CAPAUTH["**capauth**<br/>PGP keypair · sovereign profile<br/>challenge-response · DID (3 tiers)<br/>agent-identity resolver · verify service"]
52
+ SKMEMORY["skmemory"]
53
+ SKSSO["sksso"]
54
+ SKSEC["sksec"]
55
+ end
56
+ subgraph COMMS["Comms"]
57
+ SKCHAT["skchat<br/>(identity-routed)"]
58
+ SKCOMMS["skcomms<br/>(FQID addressing)"]
59
+ end
60
+ subgraph CONSUMERS["What delegates to capauth"]
61
+ SKCAPSTONE["skcapstone<br/>(framework hub)"]
62
+ end
63
+ subgraph PLATFORM["Platform primitives capauth uses (when present)"]
64
+ ALERT["sk-alert bus<br/>(capauth.&lt;severity&gt;)"]
65
+ SCHED["skscheduler<br/>(key-rotation check)"]
66
+ end
67
+ subgraph THIRDPARTY["Third-party services (passwordless login)"]
68
+ FORGEJO["Forgejo"]
69
+ AUTHENTIK["Authentik (OIDC bridge)"]
70
+ end
71
+
72
+ CAPAUTH -->|"resolve_agent_identity()"| SKCHAT
73
+ CAPAUTH -->|"resolve_agent_identity()"| SKCOMMS
74
+ CAPAUTH -->|"resolve_agent_identity()"| SKMEMORY
75
+ CAPAUTH -->|"resolve_agent_identity()"| SKCAPSTONE
76
+ CAPAUTH -->|"OIDC discovery + verify"| FORGEJO
77
+ CAPAUTH -->|"custom stage"| AUTHENTIK
78
+ CAPAUTH -.->|"auth events"| ALERT
79
+ CAPAUTH -.->|"capauth profile verify (24h)"| SCHED
80
+
81
+ style CAPAUTH fill:#1d3461,color:#fff,stroke:#0d1b2a
82
+ ```
83
+
84
+ The dotted edges are *optional* — `sk-alert` and `skscheduler` are reached only
85
+ when the `skcapstone` package is installed and `SK_STANDALONE` is unset. Absent
86
+ that, capauth degrades gracefully to native structured logging.
87
+
88
+ See **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** for the full workflows and
89
+ source map.
90
+
91
+ ## Quickstart
92
+
93
+ ```bash
94
+ pip install -e . # into the ~/.skenv venv (see skcapstone)
95
+ # or: ~/.skenv/bin/pip install capauth[all]
96
+
97
+ capauth init --name "Chef" --email "admin@smilintux.org" # generate PGP keypair + sovereign profile
98
+ capauth profile show # display your identity
99
+ capauth profile verify # verify the profile's PGP signature integrity
100
+ capauth export-pubkey -o chef.pub.asc # share this with peers
101
+
102
+ capauth did generate --tier key # Tier 1: self-contained did:key
103
+ capauth verify --pubkey peer.pub.asc # challenge-response round-trip (self-test/demo)
104
+ capauth login https://forgejo.local # passwordless PGP login to a service
105
+ ```
106
+
107
+ Your keypair and profile live at `~/.capauth/` — on your machine, under your
108
+ keys. Use `--sync` on `init` (or `capauth sync`) to replicate the identity across
109
+ all Syncthing mesh nodes so every host shares one keypair.
110
+
111
+ ## What capauth provides
112
+
113
+ | Piece | What it is |
114
+ |---|---|
115
+ | **Sovereign profile** | A self-hosted, PGP-rooted identity at `~/.capauth/` — yours alone (`capauth init`, `profile show`) |
116
+ | **Challenge-response** | Prove identity by signing a random nonce; verifiable offline by anyone with your public key (`capauth verify`, `identity.py`) |
117
+ | **Pluggable crypto** | Two backends — `pgpy` (pure-Python default) and `gnupg` (system keyring / hardware tokens) |
118
+ | **DID (three tiers)** | W3C DID documents: `did:key` (zero-infra), `did:web` mesh (Tailscale-private), `did:web` public (skworld.io) (`capauth did generate`) |
119
+ | **Agent-identity resolver** | The single canonical `resolve_agent_identity()` — dual URI (`capauth:<a>@skworld.io` + FQID `<a>@<op>.<realm>`) that every SK package delegates to |
120
+ | **Verification service** | A FastAPI service that turns a signed challenge into OIDC claims — passwordless PGP login for any OIDC app (`capauth-service`) |
121
+ | **Peer mesh** | Discover and verify sovereign peers over mDNS, shared filesystem, and Syncthing — no servers (`capauth mesh`, `discover`, `peers`) |
122
+ | **PMA membership** | Fiducia Communitatis — PGP-signed, steward-countersigned membership claims (`capauth pma request/approve/verify/revoke`) |
123
+ | **Org registry** | Register with a sovereign org; emits a signed registry entry + PMA request (`capauth register`) |
124
+ | **Integration generators** | One-shot config for third-party login, e.g. Forgejo OAuth2/OIDC (`capauth setup forgejo`) |
125
+ | **skcapstone adapter** | Default-on-by-presence: routes auth events to `sk-alert`, registers a key-rotation check with `skscheduler` |
126
+
127
+ ## Key CLI commands
128
+
129
+ ```bash
130
+ # Identity
131
+ capauth init --name "Chef" --email "..." # create sovereign profile (PGP keypair)
132
+ capauth profile show | verify # display / verify signature integrity
133
+ capauth export-pubkey [-o file.asc] # export ASCII-armored public key
134
+ capauth sync # replicate ~/.capauth/ across Syncthing mesh
135
+
136
+ # Verification & DID
137
+ capauth verify --pubkey peer.pub.asc # challenge-response round-trip
138
+ capauth did generate --tier key|mesh|public # W3C DID at the chosen privacy tier
139
+
140
+ # Auth & integration
141
+ capauth login <service_url> [--no-claims] # passwordless PGP login (caches OIDC token)
142
+ capauth setup forgejo --capauth-url <url> # generate Forgejo OIDC app.ini block
143
+
144
+ # Mesh & membership
145
+ capauth mesh discover | peers | announce # P2P peer mesh
146
+ capauth pma request | approve | verify # PMA membership (Fiducia Communitatis)
147
+ capauth register --org smilintux --name ... # register with a sovereign org
148
+ ```
149
+
150
+ ## Integration modes (skcapstone)
151
+
152
+ capauth runs fully standalone and *optionally* integrates with the SK fleet —
153
+ the **default-on-by-presence** pattern: the mere presence of the `skcapstone`
154
+ package is the signal, no config change required.
155
+
156
+ | Mode | Trigger | Alert path | Scheduler |
157
+ |---|---|---|---|
158
+ | **Standalone** | `skcapstone` not installed | Native `logging` (structured, at matching level) | Native (no daemon today) |
159
+ | **Integrated** | `skcapstone` installed | `sdk.alert()` → PubSub topic `capauth.<severity>` → Telegram/notify | `sdk.register_job()` → `skscheduler` drop-in `capauth_key_rotation_check` (runs `capauth profile verify` every 24h) |
160
+ | **Forced standalone** | `SK_STANDALONE=1` env var | Native `logging` | Native |
161
+
162
+ ```bash
163
+ pip install capauth[skcapstone] # enable integration (presence is the switch)
164
+ ```
165
+
166
+ Alert topics follow the sk\* convention `capauth.<severity>` (e.g. `capauth.warn`);
167
+ the semantic event name (`verify_failed`, `key_rotation_due`, `auth_denied`)
168
+ rides in the payload `event` field so routing stays severity-based.
169
+
170
+ ## Documentation
171
+
172
+ | Doc | Contents |
173
+ |---|---|
174
+ | **[Architecture](docs/ARCHITECTURE.md)** | identity lifecycle, challenge-response, DID tiers, the verify service / OIDC bridge, the agent resolver, source map (mermaids) |
175
+ | **[Crypto Spec](docs/CRYPTO_SPEC.md)** | PGP implementation, key management, challenge-response details |
176
+ | **[Protocol](docs/PROTOCOL.md)** | the CapAuth wire protocol specification |
177
+ | **[Claims](docs/CLAIMS.md)** | capability claims and token format |
178
+ | **[Integration Blueprint](docs/INTEGRATION_BLUEPRINT.md)** | third-party integration guide |
179
+ | **[AI Advocate](AI-ADVOCATE.md)** | how AI advocates manage a sovereign profile on your behalf |
180
+
181
+ ## Why it matters
182
+
183
+ OAuth treats humans as "users" — consumers of someone else's platform, with a
184
+ third party deciding *who you are*, *what you can access*, and *when access
185
+ expires*. capauth removes the middleman: the data owner (or their AI advocate)
186
+ signs grants directly, and verification is a local PGP check that works offline.
187
+ The same model applies equally to AI agents — every agent gets its own keypair
188
+ and the same standing, so a cloned or impersonated agent fails signature
189
+ verification instantly instead of going undetected.
190
+
191
+ > **"You are not a user. You are a sovereign."**
192
+
193
+ ## License
194
+
195
+ **GPL-3.0-or-later** — Free as in freedom. Identity is a right, not a product.
196
+
197
+ ---
198
+
199
+ Part of the **[SKWorld](https://skworld.io)** sovereign ecosystem · 🐧 smilinTux
200
+
201
+ *"We don't sell identity. We give everyone the keys to own their own."*
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "capauth"
7
- version = "0.1.2"
7
+ version = "0.2.3"
8
8
  description = "Capability-based Authentication — decentralized, PGP-based identity and authorization"
9
9
  readme = "README.md"
10
10
  license = {text = "GPL-3.0-or-later"}
@@ -22,8 +22,6 @@ classifiers = [
22
22
  "Programming Language :: Python :: 3.10",
23
23
  "Programming Language :: Python :: 3.11",
24
24
  "Programming Language :: Python :: 3.12",
25
- "Programming Language :: Python :: 3.13",
26
- "Programming Language :: Python :: 3.14",
27
25
  "Topic :: Security :: Cryptography",
28
26
  ]
29
27
  dependencies = [
@@ -36,6 +34,9 @@ dependencies = [
36
34
  ]
37
35
 
38
36
  [project.optional-dependencies]
37
+ skcapstone = [
38
+ "skcapstone>=0.6.8",
39
+ ]
39
40
  gnupg = [
40
41
  "python-gnupg>=0.5",
41
42
  ]
@@ -52,8 +53,11 @@ dev = [
52
53
  "pytest-cov>=4.0",
53
54
  "pytest-asyncio>=0.23",
54
55
  "httpx>=0.25",
56
+ "fastapi>=0.110",
57
+ "python-gnupg>=0.5",
55
58
  "black>=24.0",
56
59
  "ruff>=0.3",
60
+ "zeroconf>=0.38",
57
61
  ]
58
62
  all = [
59
63
  "capauth[gnupg,service,dev]",
@@ -86,6 +90,7 @@ target-version = "py310"
86
90
 
87
91
  [tool.ruff.lint]
88
92
  select = ["E", "F", "I", "N", "W"]
93
+ ignore = ["E501"]
89
94
 
90
95
  [tool.pytest.ini_options]
91
96
  testpaths = ["tests"]
@@ -0,0 +1,48 @@
1
+ """CapAuth -- Capability-based Authentication.
2
+
3
+ Decentralized, PGP-based identity and authorization.
4
+ OAuth is dead. Long live sovereignty.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ from pathlib import Path
11
+
12
+ from .agent_identity import AgentIdentity, resolve_agent_identity
13
+
14
+ __all__ = [
15
+ "AgentIdentity",
16
+ "resolve_agent_identity",
17
+ "resolve_capauth_home",
18
+ ]
19
+
20
+ __version__ = "0.1.7"
21
+
22
+ SKCAPSTONE_HOME = Path.home() / ".skcapstone"
23
+ DEFAULT_CAPAUTH_DIR = SKCAPSTONE_HOME / "capauth"
24
+ LEGACY_CAPAUTH_DIR = Path.home() / ".capauth"
25
+
26
+
27
+ def resolve_capauth_home(base_dir: Path | None = None) -> Path:
28
+ """Resolve the CapAuth home directory.
29
+
30
+ Priority:
31
+ 1. Explicit ``base_dir``
32
+ 2. ``CAPAUTH_HOME`` environment override
33
+ 3. New default under ``~/.skcapstone/capauth`` when present
34
+ 4. Legacy ``~/.capauth`` when it already exists
35
+ 5. New default under ``~/.skcapstone/capauth``
36
+ """
37
+ if base_dir is not None:
38
+ return Path(base_dir).expanduser()
39
+
40
+ env_home = os.environ.get("CAPAUTH_HOME")
41
+ if env_home:
42
+ return Path(env_home).expanduser()
43
+
44
+ if DEFAULT_CAPAUTH_DIR.exists():
45
+ return DEFAULT_CAPAUTH_DIR
46
+ if LEGACY_CAPAUTH_DIR.exists():
47
+ return LEGACY_CAPAUTH_DIR
48
+ return DEFAULT_CAPAUTH_DIR