capauth 0.3.1__tar.gz → 0.3.2__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 (369) hide show
  1. {capauth-0.3.1 → capauth-0.3.2}/CHANGELOG.md +107 -0
  2. {capauth-0.3.1 → capauth-0.3.2}/PKG-INFO +1 -1
  3. {capauth-0.3.1 → capauth-0.3.2}/SOP.md +23 -1
  4. capauth-0.3.2/docs/TRUST_GRAPH_COORD_PROJECTION.md +201 -0
  5. capauth-0.3.2/ruff-0.15.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
  6. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/__init__.py +4 -1
  7. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/pairing/__init__.py +15 -0
  8. capauth-0.3.2/src/capauth/pairing/proof.py +455 -0
  9. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/pairing/store.py +57 -2
  10. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/testing.py +50 -11
  11. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/trust/__init__.py +2 -0
  12. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/trust/graph.py +258 -23
  13. {capauth-0.3.1 → capauth-0.3.2}/src/capauth.egg-info/PKG-INFO +1 -1
  14. {capauth-0.3.1 → capauth-0.3.2}/src/capauth.egg-info/SOURCES.txt +6 -0
  15. capauth-0.3.2/tests/test_enrollment_proof_helper.py +432 -0
  16. capauth-0.3.2/tests/test_pairing_base_dir_env.py +122 -0
  17. capauth-0.3.2/tests/test_trust_graph_coord_audit.py +292 -0
  18. {capauth-0.3.1 → capauth-0.3.2}/.cursorrules +0 -0
  19. {capauth-0.3.1 → capauth-0.3.2}/.dockerignore +0 -0
  20. {capauth-0.3.1 → capauth-0.3.2}/.github/workflows/ci.yml +0 -0
  21. {capauth-0.3.1 → capauth-0.3.2}/.github/workflows/docs-check.yml +0 -0
  22. {capauth-0.3.1 → capauth-0.3.2}/.github/workflows/nextcloud-appstore.yml +0 -0
  23. {capauth-0.3.1 → capauth-0.3.2}/.github/workflows/publish.yml +0 -0
  24. {capauth-0.3.1 → capauth-0.3.2}/.github/workflows/pytest.yml +0 -0
  25. {capauth-0.3.1 → capauth-0.3.2}/.github/workflows/secret-scan.yml +0 -0
  26. {capauth-0.3.1 → capauth-0.3.2}/.gitignore +0 -0
  27. {capauth-0.3.1 → capauth-0.3.2}/.gitleaks-baseline.json +0 -0
  28. {capauth-0.3.1 → capauth-0.3.2}/AGENTS.md +0 -0
  29. {capauth-0.3.1 → capauth-0.3.2}/AI-ADVOCATE.md +0 -0
  30. {capauth-0.3.1 → capauth-0.3.2}/ARCHITECTURE.md +0 -0
  31. {capauth-0.3.1 → capauth-0.3.2}/CLAUDE.md +0 -0
  32. {capauth-0.3.1 → capauth-0.3.2}/CODE_OF_CONDUCT.md +0 -0
  33. {capauth-0.3.1 → capauth-0.3.2}/CONTRIBUTING.md +0 -0
  34. {capauth-0.3.1 → capauth-0.3.2}/Dockerfile +0 -0
  35. {capauth-0.3.1 → capauth-0.3.2}/Dockerfile.authentik-capauth +0 -0
  36. {capauth-0.3.1 → capauth-0.3.2}/LICENSE +0 -0
  37. {capauth-0.3.1 → capauth-0.3.2}/MANIFEST.in +0 -0
  38. {capauth-0.3.1 → capauth-0.3.2}/MISSION.md +0 -0
  39. {capauth-0.3.1 → capauth-0.3.2}/README.md +0 -0
  40. {capauth-0.3.1 → capauth-0.3.2}/SECURITY.md +0 -0
  41. {capauth-0.3.1 → capauth-0.3.2}/SKILL.md +0 -0
  42. {capauth-0.3.1 → capauth-0.3.2}/authentik-custom/capauth_migrate.py +0 -0
  43. {capauth-0.3.1 → capauth-0.3.2}/authentik-custom/imghdr.py +0 -0
  44. {capauth-0.3.1 → capauth-0.3.2}/authentik-custom/user_settings.py +0 -0
  45. {capauth-0.3.1 → capauth-0.3.2}/bin/cli.js +0 -0
  46. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/.gitignore +0 -0
  47. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/README.md +0 -0
  48. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/RELEASING.md +0 -0
  49. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/background.js +0 -0
  50. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/content_scripts/autofill.js +0 -0
  51. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/content_scripts/cross_origin_signing.js +0 -0
  52. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/content_scripts/detector.js +0 -0
  53. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/content_scripts/provider.js +0 -0
  54. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/content_scripts/provider_bridge.js +0 -0
  55. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/icons/icon.svg +0 -0
  56. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/icons/icon128.png +0 -0
  57. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/icons/icon16.png +0 -0
  58. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/icons/icon48.png +0 -0
  59. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/lib/bunker-e2e.js +0 -0
  60. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/lib/keyqr.js +0 -0
  61. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/lib/keyvault.js +0 -0
  62. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/lib/openpgp.js +0 -0
  63. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/lib/signer-backends.js +0 -0
  64. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/manifest.firefox.json +0 -0
  65. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/manifest.json +0 -0
  66. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/native-host/capauth_signer.py +0 -0
  67. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/native-host/com.capauth.signer.json +0 -0
  68. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/native-host/install.sh +0 -0
  69. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/options/options.html +0 -0
  70. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/options/options.js +0 -0
  71. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/package-lock.json +0 -0
  72. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/package.json +0 -0
  73. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/popup/popup.css +0 -0
  74. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/popup/popup.html +0 -0
  75. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/popup/popup.js +0 -0
  76. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/scripts/build.js +0 -0
  77. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/scripts/generate-icons.js +0 -0
  78. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/stages/AuthenticatorSelectionStage.js +0 -0
  79. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/stages/CapAuthStage.js +0 -0
  80. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/stages/QRDisplayStage.js +0 -0
  81. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/stages/SignatureVerificationStage.js +0 -0
  82. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/stages/StagePipeline.js +0 -0
  83. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/submission/STORE_LISTING.md +0 -0
  84. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/submission/privacy-policy.md +0 -0
  85. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/tests/fixtures/test_key.json +0 -0
  86. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/tests/unit/background.test.js +0 -0
  87. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/tests/unit/bunker_e2e.test.js +0 -0
  88. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/tests/unit/detector.test.js +0 -0
  89. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/tests/unit/keyqr.test.js +0 -0
  90. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/tests/unit/keyvault.test.js +0 -0
  91. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/tests/unit/openpgp.test.js +0 -0
  92. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/tests/unit/provider_api.test.js +0 -0
  93. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/tests/unit/provider_tierb.test.js +0 -0
  94. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/tests/unit/remote_bunker.test.js +0 -0
  95. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/tests/unit/signer_backends.test.js +0 -0
  96. {capauth-0.3.1 → capauth-0.3.2}/browser-extension/vitest.config.js +0 -0
  97. {capauth-0.3.1 → capauth-0.3.2}/deploy/capauth-service/.env.example +0 -0
  98. {capauth-0.3.1 → capauth-0.3.2}/deploy/capauth-service/deploy.sh +0 -0
  99. {capauth-0.3.1 → capauth-0.3.2}/deploy/capauth-service/docker-compose.yml +0 -0
  100. {capauth-0.3.1 → capauth-0.3.2}/deploy/capauth-service/systemd/capauth-backup.service +0 -0
  101. {capauth-0.3.1 → capauth-0.3.2}/deploy/capauth-service/systemd/capauth-backup.timer +0 -0
  102. {capauth-0.3.1 → capauth-0.3.2}/deploy/forgejo-capauth/.env.example +0 -0
  103. {capauth-0.3.1 → capauth-0.3.2}/deploy/forgejo-capauth/docker-compose.yml +0 -0
  104. {capauth-0.3.1 → capauth-0.3.2}/deploy/forgejo-capauth/preflight.sh +0 -0
  105. {capauth-0.3.1 → capauth-0.3.2}/docs/AIRGAPPED_SIGNING_WORKSTATION.md +0 -0
  106. {capauth-0.3.1 → capauth-0.3.2}/docs/ARCHITECTURE.md +0 -0
  107. {capauth-0.3.1 → capauth-0.3.2}/docs/AUTHENTIK_CUSTOM_STAGE.md +0 -0
  108. {capauth-0.3.1 → capauth-0.3.2}/docs/AUTHENTIK_DEPLOYMENT_SKSSO.md +0 -0
  109. {capauth-0.3.1 → capauth-0.3.2}/docs/AUTHENTIK_FORGEJO_DEPLOYMENT.md +0 -0
  110. {capauth-0.3.1 → capauth-0.3.2}/docs/AUTHENTIK_STRATEGY_DECISION.md +0 -0
  111. {capauth-0.3.1 → capauth-0.3.2}/docs/CAPAUTH_BUNKER_REMOTE_SIGNER.md +0 -0
  112. {capauth-0.3.1 → capauth-0.3.2}/docs/CAPAUTH_OIDC_IDP.md +0 -0
  113. {capauth-0.3.1 → capauth-0.3.2}/docs/CLAIMS.md +0 -0
  114. {capauth-0.3.1 → capauth-0.3.2}/docs/COLD_MACHINE_BOOTSTRAP_AND_DR.md +0 -0
  115. {capauth-0.3.1 → capauth-0.3.2}/docs/CRYPTO_SPEC.md +0 -0
  116. {capauth-0.3.1 → capauth-0.3.2}/docs/ENTERPRISE_MANAGED_KEYS.md +0 -0
  117. {capauth-0.3.1 → capauth-0.3.2}/docs/INTEGRATION_BLUEPRINT.md +0 -0
  118. {capauth-0.3.1 → capauth-0.3.2}/docs/M0-capauth-api-v1.md +0 -0
  119. {capauth-0.3.1 → capauth-0.3.2}/docs/M0-capauth-importer-inventory.md +0 -0
  120. {capauth-0.3.1 → capauth-0.3.2}/docs/PQC_CAPAUTH_REVISIT.md +0 -0
  121. {capauth-0.3.1 → capauth-0.3.2}/docs/PQC_ROOT_MIGRATION.md +0 -0
  122. {capauth-0.3.1 → capauth-0.3.2}/docs/PROTOCOL.md +0 -0
  123. {capauth-0.3.1 → capauth-0.3.2}/docs/ROOT_ROTATION_CEREMONY.md +0 -0
  124. {capauth-0.3.1 → capauth-0.3.2}/docs/ZERO_KNOWLEDGE_PROFILE.md +0 -0
  125. {capauth-0.3.1 → capauth-0.3.2}/docs/authentik-capauth.md +0 -0
  126. {capauth-0.3.1 → capauth-0.3.2}/docs/deploy-plan/capauth-bulletproof-deploy.md +0 -0
  127. {capauth-0.3.1 → capauth-0.3.2}/index.d.ts +0 -0
  128. {capauth-0.3.1 → capauth-0.3.2}/index.js +0 -0
  129. {capauth-0.3.1 → capauth-0.3.2}/openclaw-plugin.archived-2026-04-23/package.json +0 -0
  130. {capauth-0.3.1 → capauth-0.3.2}/openclaw-plugin.archived-2026-04-23/src/index.ts +0 -0
  131. {capauth-0.3.1 → capauth-0.3.2}/openclaw-plugin.archived-2026-04-23/src/openclaw.plugin.json +0 -0
  132. {capauth-0.3.1 → capauth-0.3.2}/package.json +0 -0
  133. {capauth-0.3.1 → capauth-0.3.2}/phone-signer/app.js +0 -0
  134. {capauth-0.3.1 → capauth-0.3.2}/phone-signer/icons/icon-192.png +0 -0
  135. {capauth-0.3.1 → capauth-0.3.2}/phone-signer/icons/icon-512.png +0 -0
  136. {capauth-0.3.1 → capauth-0.3.2}/phone-signer/index.html +0 -0
  137. {capauth-0.3.1 → capauth-0.3.2}/phone-signer/lib/bunker-e2e.js +0 -0
  138. {capauth-0.3.1 → capauth-0.3.2}/phone-signer/lib/bunker-signer.js +0 -0
  139. {capauth-0.3.1 → capauth-0.3.2}/phone-signer/lib/canonical.js +0 -0
  140. {capauth-0.3.1 → capauth-0.3.2}/phone-signer/lib/keyqr.js +0 -0
  141. {capauth-0.3.1 → capauth-0.3.2}/phone-signer/lib/keyvault.js +0 -0
  142. {capauth-0.3.1 → capauth-0.3.2}/phone-signer/manifest.webmanifest +0 -0
  143. {capauth-0.3.1 → capauth-0.3.2}/phone-signer/sw.js +0 -0
  144. {capauth-0.3.1 → capauth-0.3.2}/phone-signer/vendor/openpgp.min.js +0 -0
  145. {capauth-0.3.1 → capauth-0.3.2}/phone-signer/vendor/qrcode-generator.js +0 -0
  146. {capauth-0.3.1 → capauth-0.3.2}/pyproject.toml +0 -0
  147. {capauth-0.3.1 → capauth-0.3.2}/scripts/build_authentik_capauth_image.sh +0 -0
  148. {capauth-0.3.1 → capauth-0.3.2}/scripts/capauth-backup.sh +0 -0
  149. {capauth-0.3.1 → capauth-0.3.2}/scripts/capauth-restore.sh +0 -0
  150. {capauth-0.3.1 → capauth-0.3.2}/scripts/migrate_canonical_subjects.py +0 -0
  151. {capauth-0.3.1 → capauth-0.3.2}/scripts/pqc_ceremony_dryrun.py +0 -0
  152. {capauth-0.3.1 → capauth-0.3.2}/scripts/provision_agent_profiles.py +0 -0
  153. {capauth-0.3.1 → capauth-0.3.2}/setup.cfg +0 -0
  154. {capauth-0.3.1 → capauth-0.3.2}/skill.yaml +0 -0
  155. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/agent_identity.py +0 -0
  156. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/apps.py +0 -0
  157. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/authentik/__init__.py +0 -0
  158. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/authentik/api.py +0 -0
  159. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/authentik/blueprints/capauth-pgp-login.yaml +0 -0
  160. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/authentik/claims_mapper.py +0 -0
  161. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/authentik/nonce_store.py +0 -0
  162. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/authentik/stage.py +0 -0
  163. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/authentik/urls.py +0 -0
  164. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/authentik/verifier.py +0 -0
  165. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/authz.py +0 -0
  166. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/cli.py +0 -0
  167. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/crypto/__init__.py +0 -0
  168. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/crypto/base.py +0 -0
  169. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/crypto/gnupg_backend.py +0 -0
  170. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/crypto/pgpy_backend.py +0 -0
  171. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/crypto/sequoia_backend.py +0 -0
  172. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/crypto/skpgp_backend.py +0 -0
  173. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/custody.py +0 -0
  174. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/did.py +0 -0
  175. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/discovery/__init__.py +0 -0
  176. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/discovery/base.py +0 -0
  177. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/discovery/file_discovery.py +0 -0
  178. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/discovery/mdns.py +0 -0
  179. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/discovery/syncthing.py +0 -0
  180. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/exceptions.py +0 -0
  181. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/identity.py +0 -0
  182. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/identity_class.py +0 -0
  183. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integration.py +0 -0
  184. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/__init__.py +0 -0
  185. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/forgejo/__init__.py +0 -0
  186. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/forgejo/auth_flow.py +0 -0
  187. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/forgejo/cli.py +0 -0
  188. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/forgejo/config.py +0 -0
  189. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/forgejo/forgejo_api.py +0 -0
  190. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/forgejo/oidc_provider.py +0 -0
  191. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/forgejo/tests/__init__.py +0 -0
  192. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/forgejo/tests/test_auth_flow.py +0 -0
  193. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/forgejo/tests/test_cli.py +0 -0
  194. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/forgejo/tests/test_config.py +0 -0
  195. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/forgejo/tests/test_forgejo_api.py +0 -0
  196. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/forgejo/tests/test_oidc_provider.py +0 -0
  197. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/.gitignore +0 -0
  198. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/.nextcloudignore +0 -0
  199. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/CSR-PR.md +0 -0
  200. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/INFO-XML-CHANGES.md +0 -0
  201. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/PUBLISHING.md +0 -0
  202. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/README.md +0 -0
  203. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/appinfo/info.xml +0 -0
  204. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/appinfo/routes.php +0 -0
  205. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/build-release.sh +0 -0
  206. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/certificates/.gitignore +0 -0
  207. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/certificates/capauth.crt +0 -0
  208. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/certificates/capauth.csr +0 -0
  209. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/composer.json +0 -0
  210. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/css/login.css +0 -0
  211. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/js/login.js +0 -0
  212. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/krankerl.toml +0 -0
  213. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/AlternativeLogin/CapAuthLogin.php +0 -0
  214. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/AppInfo/Application.php +0 -0
  215. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/BackgroundJob/PruneExpiredNonces.php +0 -0
  216. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/Controller/LoginController.php +0 -0
  217. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/Controller/TokenController.php +0 -0
  218. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/Db/KeyRegistry.php +0 -0
  219. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/Exception/CapAuthUnauthorizedException.php +0 -0
  220. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/Middleware/PgpVerificationMiddleware.php +0 -0
  221. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/Migration/Version000300Date20260301000000.php +0 -0
  222. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/Provider/CapAuthProvider.php +0 -0
  223. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/Service/ChallengeService.php +0 -0
  224. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/Service/GroupSyncService.php +0 -0
  225. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/Service/UserProvisioningService.php +0 -0
  226. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/Service/VerifierService.php +0 -0
  227. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/lib/User/Backend.php +0 -0
  228. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/phpunit.xml +0 -0
  229. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/screenshots/README.md +0 -0
  230. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/screenshots/login.png +0 -0
  231. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/templates/login.php +0 -0
  232. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/tests/bootstrap.php +0 -0
  233. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/tests/integration/FullAuthFlowTest.php +0 -0
  234. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/tests/oidc/oidc_e2e_login_test.py +0 -0
  235. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/tests/unit/Controller/LoginControllerTest.php +0 -0
  236. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/tests/unit/Db/KeyRegistryTest.php +0 -0
  237. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/tests/unit/Provider/CapAuthProviderTest.php +0 -0
  238. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/tests/unit/Service/ChallengeServiceTest.php +0 -0
  239. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/tests/unit/Service/VerifierServiceTest.php +0 -0
  240. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/integrations/nextcloud/tests/unit/User/BackendTest.php +0 -0
  241. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/key_transparency.py +0 -0
  242. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/login.py +0 -0
  243. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/manifest.py +0 -0
  244. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/mesh.py +0 -0
  245. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/migrations/0001_initial.py +0 -0
  246. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/migrations/0002_widen_fingerprint_to_64.py +0 -0
  247. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/migrations/__init__.py +0 -0
  248. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/models.py +0 -0
  249. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/pairing/canonicalize.py +0 -0
  250. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/pairing/kernel.py +0 -0
  251. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/pairing/operator_session.py +0 -0
  252. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/pairing/records.py +0 -0
  253. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/pairing/window.py +0 -0
  254. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/pma.py +0 -0
  255. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/pqc_confidentiality.py +0 -0
  256. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/pqc_identity.py +0 -0
  257. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/pqc_root_identity.py +0 -0
  258. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/pqc_tokens.py +0 -0
  259. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/profile.py +0 -0
  260. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/provisioning.py +0 -0
  261. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/registry.py +0 -0
  262. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/seal.py +0 -0
  263. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/__init__.py +0 -0
  264. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/app.py +0 -0
  265. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/bunker.py +0 -0
  266. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/bunker_e2e.py +0 -0
  267. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/keystore.py +0 -0
  268. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/oidc/__init__.py +0 -0
  269. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/oidc/clients.example.json +0 -0
  270. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/oidc/clients.py +0 -0
  271. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/oidc/passkey.py +0 -0
  272. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/oidc/provider.py +0 -0
  273. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/oidc/signing_key.py +0 -0
  274. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/oidc/store.py +0 -0
  275. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/push.py +0 -0
  276. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/service/server.py +0 -0
  277. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/subject.py +0 -0
  278. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/sync.py +0 -0
  279. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/tokens.py +0 -0
  280. {capauth-0.3.1 → capauth-0.3.2}/src/capauth/trust/calibration.py +0 -0
  281. {capauth-0.3.1 → capauth-0.3.2}/src/capauth.egg-info/dependency_links.txt +0 -0
  282. {capauth-0.3.1 → capauth-0.3.2}/src/capauth.egg-info/entry_points.txt +0 -0
  283. {capauth-0.3.1 → capauth-0.3.2}/src/capauth.egg-info/requires.txt +0 -0
  284. {capauth-0.3.1 → capauth-0.3.2}/src/capauth.egg-info/top_level.txt +0 -0
  285. {capauth-0.3.1 → capauth-0.3.2}/stages/ak-stage-capauth/.gitignore +0 -0
  286. {capauth-0.3.1 → capauth-0.3.2}/stages/ak-stage-capauth/package-lock.json +0 -0
  287. {capauth-0.3.1 → capauth-0.3.2}/stages/ak-stage-capauth/package.json +0 -0
  288. {capauth-0.3.1 → capauth-0.3.2}/stages/ak-stage-capauth/src/CapAuthStage.test.js +0 -0
  289. {capauth-0.3.1 → capauth-0.3.2}/stages/ak-stage-capauth/src/CapAuthStage.vue +0 -0
  290. {capauth-0.3.1 → capauth-0.3.2}/stages/ak-stage-capauth/src/index.js +0 -0
  291. {capauth-0.3.1 → capauth-0.3.2}/stages/ak-stage-capauth/vite.config.js +0 -0
  292. {capauth-0.3.1 → capauth-0.3.2}/tests/__init__.py +0 -0
  293. {capauth-0.3.1 → capauth-0.3.2}/tests/conftest.py +0 -0
  294. {capauth-0.3.1 → capauth-0.3.2}/tests/fixtures/bunker_e2e_v1_vector.json +0 -0
  295. {capauth-0.3.1 → capauth-0.3.2}/tests/fixtures/canonical_nonce_v2_vector.json +0 -0
  296. {capauth-0.3.1 → capauth-0.3.2}/tests/test_agent_identity.py +0 -0
  297. {capauth-0.3.1 → capauth-0.3.2}/tests/test_agentrun_capabilities.py +0 -0
  298. {capauth-0.3.1 → capauth-0.3.2}/tests/test_audience_mint_helper.py +0 -0
  299. {capauth-0.3.1 → capauth-0.3.2}/tests/test_audience_tokens.py +0 -0
  300. {capauth-0.3.1 → capauth-0.3.2}/tests/test_authz.py +0 -0
  301. {capauth-0.3.1 → capauth-0.3.2}/tests/test_authz_legacy_grace.py +0 -0
  302. {capauth-0.3.1 → capauth-0.3.2}/tests/test_authz_signature_gate.py +0 -0
  303. {capauth-0.3.1 → capauth-0.3.2}/tests/test_backup_restore.py +0 -0
  304. {capauth-0.3.1 → capauth-0.3.2}/tests/test_bunker.py +0 -0
  305. {capauth-0.3.1 → capauth-0.3.2}/tests/test_bunker_e2e.py +0 -0
  306. {capauth-0.3.1 → capauth-0.3.2}/tests/test_canonicalize.py +0 -0
  307. {capauth-0.3.1 → capauth-0.3.2}/tests/test_capauth_service_deploy.py +0 -0
  308. {capauth-0.3.1 → capauth-0.3.2}/tests/test_change_capabilities.py +0 -0
  309. {capauth-0.3.1 → capauth-0.3.2}/tests/test_claims_mapper.py +0 -0
  310. {capauth-0.3.1 → capauth-0.3.2}/tests/test_crypto.py +0 -0
  311. {capauth-0.3.1 → capauth-0.3.2}/tests/test_custody.py +0 -0
  312. {capauth-0.3.1 → capauth-0.3.2}/tests/test_device_key_proof.py +0 -0
  313. {capauth-0.3.1 → capauth-0.3.2}/tests/test_did_capability_relationships.py +0 -0
  314. {capauth-0.3.1 → capauth-0.3.2}/tests/test_fingerprint_v6.py +0 -0
  315. {capauth-0.3.1 → capauth-0.3.2}/tests/test_forgejo_preflight.py +0 -0
  316. {capauth-0.3.1 → capauth-0.3.2}/tests/test_home_resolution.py +0 -0
  317. {capauth-0.3.1 → capauth-0.3.2}/tests/test_identity.py +0 -0
  318. {capauth-0.3.1 → capauth-0.3.2}/tests/test_identity_class.py +0 -0
  319. {capauth-0.3.1 → capauth-0.3.2}/tests/test_identity_ttl.py +0 -0
  320. {capauth-0.3.1 → capauth-0.3.2}/tests/test_integration.py +0 -0
  321. {capauth-0.3.1 → capauth-0.3.2}/tests/test_key_revocation_expiry.py +0 -0
  322. {capauth-0.3.1 → capauth-0.3.2}/tests/test_key_transparency.py +0 -0
  323. {capauth-0.3.1 → capauth-0.3.2}/tests/test_login.py +0 -0
  324. {capauth-0.3.1 → capauth-0.3.2}/tests/test_manifest.py +0 -0
  325. {capauth-0.3.1 → capauth-0.3.2}/tests/test_mesh.py +0 -0
  326. {capauth-0.3.1 → capauth-0.3.2}/tests/test_models_pqc_q0.py +0 -0
  327. {capauth-0.3.1 → capauth-0.3.2}/tests/test_nextcloud_app.py +0 -0
  328. {capauth-0.3.1 → capauth-0.3.2}/tests/test_no_subapp_dependency.py +0 -0
  329. {capauth-0.3.1 → capauth-0.3.2}/tests/test_nonce_store.py +0 -0
  330. {capauth-0.3.1 → capauth-0.3.2}/tests/test_oidc_idp.py +0 -0
  331. {capauth-0.3.1 → capauth-0.3.2}/tests/test_oidc_idp_e2e.py +0 -0
  332. {capauth-0.3.1 → capauth-0.3.2}/tests/test_operator_session.py +0 -0
  333. {capauth-0.3.1 → capauth-0.3.2}/tests/test_pairing.py +0 -0
  334. {capauth-0.3.1 → capauth-0.3.2}/tests/test_passkey.py +0 -0
  335. {capauth-0.3.1 → capauth-0.3.2}/tests/test_pma.py +0 -0
  336. {capauth-0.3.1 → capauth-0.3.2}/tests/test_pqc_confidentiality.py +0 -0
  337. {capauth-0.3.1 → capauth-0.3.2}/tests/test_pqc_identity.py +0 -0
  338. {capauth-0.3.1 → capauth-0.3.2}/tests/test_pqc_root_integration.py +0 -0
  339. {capauth-0.3.1 → capauth-0.3.2}/tests/test_pqc_t3_gate.py +0 -0
  340. {capauth-0.3.1 → capauth-0.3.2}/tests/test_pqc_tokens.py +0 -0
  341. {capauth-0.3.1 → capauth-0.3.2}/tests/test_profile.py +0 -0
  342. {capauth-0.3.1 → capauth-0.3.2}/tests/test_provisioning.py +0 -0
  343. {capauth-0.3.1 → capauth-0.3.2}/tests/test_push.py +0 -0
  344. {capauth-0.3.1 → capauth-0.3.2}/tests/test_py313_compat.py +0 -0
  345. {capauth-0.3.1 → capauth-0.3.2}/tests/test_qr_login.py +0 -0
  346. {capauth-0.3.1 → capauth-0.3.2}/tests/test_real_pgp_e2e.py +0 -0
  347. {capauth-0.3.1 → capauth-0.3.2}/tests/test_register_cli.py +0 -0
  348. {capauth-0.3.1 → capauth-0.3.2}/tests/test_registry.py +0 -0
  349. {capauth-0.3.1 → capauth-0.3.2}/tests/test_seal.py +0 -0
  350. {capauth-0.3.1 → capauth-0.3.2}/tests/test_sequoia_backend.py +0 -0
  351. {capauth-0.3.1 → capauth-0.3.2}/tests/test_service.py +0 -0
  352. {capauth-0.3.1 → capauth-0.3.2}/tests/test_service_authz_decide.py +0 -0
  353. {capauth-0.3.1 → capauth-0.3.2}/tests/test_service_v6_fingerprint.py +0 -0
  354. {capauth-0.3.1 → capauth-0.3.2}/tests/test_skpgp_backend.py +0 -0
  355. {capauth-0.3.1 → capauth-0.3.2}/tests/test_subject.py +0 -0
  356. {capauth-0.3.1 → capauth-0.3.2}/tests/test_syncthing_discovery.py +0 -0
  357. {capauth-0.3.1 → capauth-0.3.2}/tests/test_testing_helper.py +0 -0
  358. {capauth-0.3.1 → capauth-0.3.2}/tests/test_token_gc.py +0 -0
  359. {capauth-0.3.1 → capauth-0.3.2}/tests/test_token_store_flag.py +0 -0
  360. {capauth-0.3.1 → capauth-0.3.2}/tests/test_tokens.py +0 -0
  361. {capauth-0.3.1 → capauth-0.3.2}/tests/test_trust_calibration.py +0 -0
  362. {capauth-0.3.1 → capauth-0.3.2}/tests/test_trust_graph.py +0 -0
  363. {capauth-0.3.1 → capauth-0.3.2}/tests/test_verifier.py +0 -0
  364. {capauth-0.3.1 → capauth-0.3.2}/tests/test_version_honesty.py +0 -0
  365. {capauth-0.3.1 → capauth-0.3.2}/tests/test_zk_profile.py +0 -0
  366. {capauth-0.3.1 → capauth-0.3.2}/tools/build-sq.sh +0 -0
  367. {capauth-0.3.1 → capauth-0.3.2}/urllib.error +0 -0
  368. {capauth-0.3.1 → capauth-0.3.2}/web/README.md +0 -0
  369. {capauth-0.3.1 → capauth-0.3.2}/web/stages/capauth/CapAuthStage.ts +0 -0
@@ -8,6 +8,68 @@ All notable changes to `capauth` are documented here. The format is based on
8
8
 
9
9
  ### Added
10
10
 
11
+ - **`capauth.pairing.proof`: a supported way to BUILD the enrollment proof card
12
+ N10 made mandatory.** `83c1fa2` made `proof` required for `verified` and
13
+ `operator_pubkey` + `attestation` required for `attested`, but shipped the
14
+ requirement with no supported constructor. A downstream had to reconstruct the
15
+ challenge from capauth's source (derive the fingerprint with
16
+ `fingerprint_for`, canonicalize the subject with `canonical_subject`, assemble
17
+ `verified_challenge` over exactly those two) and get all three right, or emit a
18
+ signature that fails identically to a forged one. skchat did it by hand, with a
19
+ comment saying "capauth has no public helper for this today; if it grows one,
20
+ delete this and call it."
21
+ - `build_verified_proof(pubkey, *, private_key, passphrase="", subject=None)` —
22
+ signs the `verified` challenge with the device's OWN key.
23
+ - `build_attested_proof(pubkey, *, operator_pubkey, operator_private_key,
24
+ passphrase="", subject=None)` — an operator vouching for a device it does not
25
+ hold the private key of.
26
+ - `enrollment_challenge(pubkey, *, subject=None, mode="verified")` — the
27
+ challenge bytes derived from the PUBLIC key alone. No secret is involved and
28
+ none is disclosed, so a server can hand these to a client whose WebCrypto
29
+ device key is non-extractable and let it sign them.
30
+ - `EnrollmentProof` — frozen, and implements the mapping protocol, so it
31
+ splats into `enroll_device` with no massaging:
32
+ `enroll_device(pub, scopes, mode="verified", subject=subj, **proof)`. It
33
+ yields only the evidence kwargs the claimed mode requires, never both sets.
34
+ - `ProofSigningError(PairingError)` — signing failure RAISES, in the same
35
+ spirit as `TokenSigningError`. An unsigned or empty proof is never returned.
36
+ - **It is a constructor, not a bypass.** The verifier is untouched, and is in
37
+ fact called on this module's own output before that output is returned (the
38
+ round trip is a structural property, not a hope). Every function signs with a
39
+ private key the CALLER supplies: presenting a proof for a key you do not
40
+ control is impossible by construction, because the signature IS the proof.
41
+ The signing branch is chosen from the device public key alone, using the same
42
+ `"BEGIN PGP" in key` discriminator `_proof_verifies` uses, so a caller can
43
+ never pick a weaker verifier for itself. Both PGP-armored keys and skchat's
44
+ base64 DER SPKI ECDSA P-256 device keys are supported.
45
+ - Negative controls in `tests/test_enrollment_proof_helper.py` pin that a proof
46
+ over the wrong subject, over the wrong fingerprint, signed by a different
47
+ key, replayed across the verified/attested domain separation, or simply
48
+ absent is STILL refused by the real `enroll_device`. They were verified to
49
+ catch a real regression by deliberately loosening the check and observing
50
+ them go red.
51
+
52
+ - **`$SKCAPSTONE_HOME` now overrides `capauth.pairing.store.default_base_dir()`.**
53
+ The root was hardcoded to `~/.skcapstone` with no override, so a node that
54
+ legitimately holds a per-agent key but whose flat
55
+ `~/.skcapstone/identity/identity.json` declares a different key had no
56
+ supported way to point capauth at a home it can actually sign from. Precedence
57
+ matches the `capauth.manifest.shell_home` idiom already in this repo: explicit
58
+ `base_dir=` (unchanged, still wins), then `$SKCAPSTONE_HOME` when set and
59
+ non-empty, then `~/.skcapstone`. An empty or whitespace-only value falls back
60
+ to the default rather than resolving against the cwd. Exported as
61
+ `capauth.pairing.SKCAPSTONE_HOME_ENV`.
62
+ - With the variable unset, behaviour is unchanged in every respect.
63
+ - ⚠ **Setting it moves the PAIRING STORE, not just the identity.** The same
64
+ function locates the peer registry and its device sidecars, pending
65
+ enrollments, identity-class assignments, and the capability-token store
66
+ `decide()` reads. A node pointed at a new home starts with an EMPTY device
67
+ store and will deny every subject enrolled in the old one for "no enrolled
68
+ device" until it is re-enrolled there. Nothing migrates, merges, or falls
69
+ back to the previous location: whether two homes should be reconciled is a
70
+ separate decision, and a silent merge is how one node's device population
71
+ quietly becomes another's.
72
+
11
73
  - **`capauth.testing`: the gpg signing test seam, promoted from `tests/conftest.py`
12
74
  into shipped, importable code.** Since `0d412ab`, `issue_token` and
13
75
  `mint_audience_token` RAISE rather than storing an unsigned token, and
@@ -50,6 +112,51 @@ All notable changes to `capauth` are documented here. The format is based on
50
112
 
51
113
  ### Fixed
52
114
 
115
+ - **An unreadable coordination projection rendered identically to an agent with
116
+ no collaborators** (coord card `49e9b427`).
117
+ `capauth.trust.graph._add_coord_agents` reads
118
+ `~/.skcapstone/coordination/agents/*.json`, a rebuildable PROJECTION of the
119
+ coordination board, and turns `len(completed_tasks)` into a trust edge weight
120
+ via `0.3 + 0.05n`. It continued past `json.JSONDecodeError` and `OSError` per
121
+ file, and skdashboard collapses any exception out of `build_trust_graph` into
122
+ an empty graph, so a projection that could not be read at all produced zero
123
+ coord edges, no warning, and the same picture in every output format as a
124
+ healthy agent that simply has no collaborators. Per-file tolerance is kept (one
125
+ corrupt file must not blank the trust web), but the failures are now counted
126
+ and reported:
127
+ - `capauth.trust.SourceHealth`, a new exported record on `TrustGraph`, with
128
+ statuses `ok` / `absent` / `degraded` / `unreadable`, file counts, the source
129
+ path, and a bounded sample of the read errors. `TrustGraph.warnings()` is
130
+ empty only when every instrumented source was read in full, so an absent edge
131
+ can once again be read as an absent relationship.
132
+ - `format_json` gains `sources`, `warnings` and `complete` (this is the dict
133
+ skdashboard's trust panel already parses), `format_table` gains a Sources
134
+ section plus an explicit incomplete-graph warning, and `format_dot` draws a
135
+ red node for a degraded source so a rendered image shows the gap instead of
136
+ just being smaller.
137
+ - A JSON payload that parses but is not an object (an error page, an array, a
138
+ bare `null`) now counts as a failed file. Previously it raised an uncaught
139
+ `AttributeError` out of `build_trust_graph`, which the caller turned into an
140
+ empty graph.
141
+ - The directory listing uses `iterdir` rather than `glob`, because `glob`
142
+ swallows a `PermissionError` on the directory and returns nothing, reporting
143
+ an unreadable store as an empty one.
144
+ - Coord edges now carry `source`, `corroborated: False` and `tasks_claimed`
145
+ metadata, and the read carries a `# PROJECTION-OK:` marker whose
146
+ justification is conditional on a verified property: `TrustEdge.strength` is
147
+ consumed only by renderers (DOT `penwidth`, the ASCII bar, skdashboard's
148
+ stroke width), never by an authorization path.
149
+
150
+ Trust SEMANTICS are unchanged on purpose. The audit (188 of 1,683 claimed
151
+ completions backed by no store, identity fields describing the rebuilder,
152
+ Syncthing conflict resolution losing completions in one direction, and no
153
+ representation of the board's `review` column) and the recommendation to stop
154
+ deriving a weight from a completion count are in
155
+ `docs/TRUST_GRAPH_COORD_PROJECTION.md`, for the repo owner to decide. The
156
+ `0.3 + 0.05n` curve is now named (`COORD_BASE_STRENGTH`,
157
+ `COORD_STRENGTH_PER_TASK`, `COORD_SATURATION_TASKS = 14`) and locked by a test
158
+ so any future change to it is deliberate.
159
+
53
160
  - **`verified` enrollment was unprovable for WebCrypto device keys**
54
161
  (`inc-c72a9120`). N10's proof check was correct but PGP-only: it verified
55
162
  `proof` solely through `capauth.crypto`'s armored-signature backend, while
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: capauth
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: Capability-based Authentication — decentralized, PGP-based identity and authorization
5
5
  Author-email: smilinTux <admin@smilintux.org>
6
6
  License: GPL-3.0-or-later
@@ -383,6 +383,18 @@ verify `POST /capauth/v1/verify` (`:266`), authz decision
383
383
  (`:653`). **No `/health` route exists**; `/capauth/v1/status` is the liveness probe
384
384
  (that is what the compose healthcheck curls).
385
385
 
386
+ **Trust graph.** `capauth.trust.graph.build_trust_graph` is a VISUALISATION, not
387
+ a decision input: `TrustEdge.strength` is read only by the renderers (DOT
388
+ `penwidth`, the ASCII bar, skdashboard's stroke width), and no authorization path
389
+ (`authz.py`, `tokens.py`, `service/`) imports the trust graph at all. One of its
390
+ inputs, the coordination `agents/*.json` projection, is known to be corrupt in
391
+ four measured ways and is read anyway under a `# PROJECTION-OK:` marker whose
392
+ justification depends on that separation holding. Every graph now reports per
393
+ source read health (`ok` / `absent` / `degraded` / `unreadable`) so an unreadable
394
+ input is distinguishable from a genuinely empty one. Audit, the marker's
395
+ conditions, and the proposed weighting change:
396
+ [docs/TRUST_GRAPH_COORD_PROJECTION.md](docs/TRUST_GRAPH_COORD_PROJECTION.md).
397
+
386
398
  Full protocol + claim/token format: [docs/PROTOCOL.md](docs/PROTOCOL.md),
387
399
  [docs/CLAIMS.md](docs/CLAIMS.md). Crypto detail: [docs/CRYPTO_SPEC.md](docs/CRYPTO_SPEC.md).
388
400
 
@@ -443,8 +455,18 @@ Full protocol + claim/token format: [docs/PROTOCOL.md](docs/PROTOCOL.md),
443
455
  **SK = staycuriousANDkeepsmilin 🐧** — *capauth: you are not a user, you are a sovereign.*
444
456
 
445
457
  <!-- docs-evidence
446
- verified: 2026-08-15
458
+ verified: 2026-08-16
447
459
  checks:
460
+ - name: the trust graph is still display-only, which is what section 7 and the PROJECTION-OK marker rest on
461
+ run: ! grep -rqE 'trust\.graph|build_trust_graph|TrustEdge' src/capauth/authz.py src/capauth/tokens.py src/capauth/service/
462
+ - name: the coord projection read still carries its PROJECTION-OK justification
463
+ run: grep -qF '# PROJECTION-OK:' src/capauth/trust/graph.py
464
+ - name: coord edges still declare their count uncorroborated
465
+ run: grep -qF '"corroborated": False' src/capauth/trust/graph.py
466
+ - name: the coord weight constants and their saturation point are still recorded, not inline magic
467
+ run: grep -qxF 'COORD_SATURATION_TASKS = 14' src/capauth/trust/graph.py && grep -qxF 'COORD_BASE_STRENGTH = 0.3' src/capauth/trust/graph.py
468
+ - name: a degraded source is still reported rather than swallowed into an empty graph
469
+ run: grep -qF 'def warnings(' src/capauth/trust/graph.py && grep -qF '"unreadable"' src/capauth/trust/graph.py
448
470
  - name: both console-script entry points are exactly as section 7 documents
449
471
  run: grep -qxF 'capauth = "capauth.cli:main"' pyproject.toml && grep -qxF 'capauth-service = "capauth.service.server:main"' pyproject.toml
450
472
  - name: capauth-service still defaults to 127.0.0.1 and port 8420 (section 5 Scenario A)
@@ -0,0 +1,201 @@
1
+ # The coordination projection as a trust input
2
+
3
+ **Status:** audit landed, failure visibility fixed, weighting change PROPOSED and
4
+ NOT applied.
5
+ **Audited:** 2026-08-16, against the live fleet coordination store.
6
+ **Owner decision required:** yes. See "Recommendation to the repo owner" below.
7
+ **Refs:** coord card `49e9b427`, upstream `ebc927c3` (A5.1), `7dd497bc`.
8
+
9
+ ## 1. What this document is for
10
+
11
+ `capauth.trust.graph` builds the trust web that `skcapstone trust graph`, the
12
+ skcapstone shell, the `trust_graph` MCP tool and skdashboard's trust panel all
13
+ render. One of its five input sources is the coordination board, and it reads
14
+ that board through a REBUILDABLE PROJECTION rather than through the board's
15
+ store of record.
16
+
17
+ That read was never audited, because the read lives in capauth and the store
18
+ lives in skcapstone. This document records the audit, states plainly what was
19
+ fixed, and puts the part that changes trust semantics in front of the repo
20
+ owner instead of quietly changing it.
21
+
22
+ ## 2. The read, as it stands
23
+
24
+ `src/capauth/trust/graph.py::_add_coord_agents` opens every
25
+ `~/.skcapstone/coordination/agents/*.json`, takes `data["agent"]` as the
26
+ collaborator name, and computes:
27
+
28
+ ```
29
+ completed = len(data.get("completed_tasks", []))
30
+ strength = min(1.0, 0.3 + completed * 0.05)
31
+ ```
32
+
33
+ So a claimed completion count is a direct multiplier on a trust edge weight.
34
+ Fourteen claimed completions saturate the edge at 1.0, and every collaborator
35
+ at or above fourteen is thereafter indistinguishable from every other.
36
+
37
+ ## 3. The audit: four independent ways the count is wrong
38
+
39
+ All four were measured on the live store on 2026-08-16, not estimated.
40
+
41
+ 1. **1,683 completions are claimed across the agent projections, and 188 of
42
+ them are backed by no store at all.** Not the coordination event log, not
43
+ the archive manifest. Each uncorroborated claim inflates a trust edge by
44
+ 0.05.
45
+ 2. **The identity fields describe the rebuilder, not the agent.** 106 of about
46
+ 120 agent files share a two-second-wide `last_seen`, and 100 carry the
47
+ rebuilder's hostname, because `export_to_legacy -> save_agent` restamps
48
+ `last_seen` and `AgentFile.host` defaults to `socket.gethostname()`. Any
49
+ freshness or provenance signal on these nodes is an artifact of whoever last
50
+ ran a rebuild.
51
+ 3. **Conflict resolution loses completions in one consistent direction.** All 6
52
+ Syncthing conflict copies claimed completions that the surviving live file
53
+ had lost (autopilot 4 versus 0; opus-swarm 5, 11, 22, 5, 11 versus 0), and
54
+ never the reverse. The live counts are therefore systematically low, and
55
+ nothing about the surviving file reveals that.
56
+ 4. **The projection cannot represent the board's `review` column at all.** 32
57
+ cards currently disagree between store and projection for structural
58
+ reasons that no rebuild can fix. A projection that cannot express a state of
59
+ the thing it projects is not a faithful view of it.
60
+
61
+ None of this is evidence of an attack. It is evidence that a trust weight is
62
+ computed from a number that is wrong in at least four unrelated ways, and that
63
+ nobody noticed because the reader and the writer live in different repos.
64
+
65
+ ## 4. The aggravating factor, and the thing that was actually fixed
66
+
67
+ The whole consumer chain was built to hide this. `_add_coord_agents` continued
68
+ past `json.JSONDecodeError` and `OSError` per file, and
69
+ `skdashboard/src/skdashboard/dashboard.py` collapses every exception out of
70
+ `build_trust_graph` into an empty graph so the panel never 500s. The net
71
+ effect: a totally unreadable projection rendered as a graph with zero coord
72
+ edges, which is exactly what a healthy agent with no collaborators renders as.
73
+ Healthy and broken were the same picture, in all three output formats.
74
+
75
+ That is fixed. `TrustGraph` now carries a `SourceHealth` record per
76
+ instrumented source with four states:
77
+
78
+ | status | meaning |
79
+ | ------------ | -------------------------------------------------------------- |
80
+ | `ok` | read succeeded. Zero edges means zero relationships. |
81
+ | `absent` | the source does not exist on this home. |
82
+ | `degraded` | some records read, some failed. The graph UNDERCOUNTS. |
83
+ | `unreadable` | nothing could be read. Absence of edges means nothing at all. |
84
+
85
+ `TrustGraph.warnings()` is empty only when every instrumented source was read
86
+ in full. The three renderers surface it: `format_json` gains `sources`,
87
+ `warnings` and `complete` (this is the dict skdashboard renders), `format_table`
88
+ gains a Sources section and an explicit incomplete-graph warning, and
89
+ `format_dot` draws a red node for a degraded source so the gap is visible in a
90
+ rendered image rather than expressed as a smaller graph.
91
+
92
+ Two smaller correctness fixes came with it, both cases where "unreadable" was
93
+ being silently converted into "empty":
94
+
95
+ - A JSON payload that parses but is not an object (an error page, an array, a
96
+ bare `null`) is now counted as a failed file. Previously `[1,2,3]` raised an
97
+ uncaught `AttributeError` out of `build_trust_graph`, which skdashboard then
98
+ turned into an empty graph.
99
+ - The directory listing uses `iterdir` rather than `glob`, because `glob`
100
+ swallows a `PermissionError` on the directory and returns nothing, reporting
101
+ an unreadable store as an empty one.
102
+
103
+ Per-file tolerance is deliberately KEPT. One corrupt agent file should not
104
+ blank the whole trust web. The change is that tolerated failures are now
105
+ counted and reported instead of being invisible.
106
+
107
+ ## 5. Why the projection is still read at all (the PROJECTION-OK marker)
108
+
109
+ The marker above `_add_coord_agents` justifies the read for a trust weight
110
+ specifically, and it rests on exactly one property, which was verified rather
111
+ than assumed:
112
+
113
+ > `TrustEdge.strength` is a DISPLAY quantity and nothing else.
114
+
115
+ Its only consumers fleet-wide are renderers: DOT `penwidth` in `format_dot`,
116
+ the ASCII bar in `format_table`, and skdashboard's `static/trust.html` stroke
117
+ width and label. No authorization, capability issuance, token gate or policy
118
+ decision in capauth or in any consumer reads it. Nothing under
119
+ `src/capauth/authz.py`, `src/capauth/tokens.py` or `src/capauth/service/`
120
+ imports the trust graph at all. An inflated coord edge draws a thicker line. It
121
+ does not grant anything.
122
+
123
+ That justification is CONDITIONAL, and the condition is the entire basis of the
124
+ marker. The moment any code path makes an access decision from a coord edge
125
+ weight, this read stops being acceptable and must move to the corroborated
126
+ source. Every coord edge therefore ships with `corroborated: False` in its
127
+ metadata so a future consumer cannot claim it was not told.
128
+
129
+ ## 6. Recommendation to the repo owner
130
+
131
+ Two of the card's four questions change what trust MEANS, so they are proposed
132
+ here rather than applied. Both are yours.
133
+
134
+ ### (a) Should trust weight derive from a completion count at all?
135
+
136
+ **Recommendation: no.** Reasoning, in order of weight:
137
+
138
+ 1. **A count measures volume, not trustworthiness.** Fourteen trivial
139
+ completions produce the same maximal 1.0 edge as years of high-stakes work.
140
+ The formula rewards task churn, and the fleet's own agents are the ones
141
+ generating the churn.
142
+ 2. **The channel is monotonic and one-directional.** Nothing decays and nothing
143
+ subtracts. An agent that failed two hundred cards and completed fourteen is
144
+ rendered as maximally trusted. A trust signal with no way to go down is not
145
+ measuring trust.
146
+ 3. **It is precisely the quantity the store cannot corroborate.** 188 of 1,683
147
+ claims are backed by nothing (section 3.1). If a count is kept, it must read
148
+ the union of the coordination event log and the archive manifest, never
149
+ `agents/*.json`; per card `7dd497bc` an events-only read under-reports by 93
150
+ percent, so the union is not optional.
151
+ 4. **The projection is structurally incomplete** (section 3.4) and its identity
152
+ fields are rebuild artifacts (section 3.2). It cannot be made faithful by
153
+ rebuilding it more often.
154
+
155
+ **Preferred replacement: make the coord edge a PRESENCE edge with a fixed
156
+ strength (0.3), and keep the count as a label and metadata only.** What the
157
+ projection can genuinely support is "these two agents appear on the same
158
+ coordination board". That is a real fact about collaboration, it survives all
159
+ four corruption modes above, and it is all the projection is entitled to
160
+ assert. The human reader still sees "collaborator (7 tasks)" in the label; the
161
+ number simply stops moving a weight. This is also the smallest possible change:
162
+ one constant, no new data source, and the saturation cliff disappears because
163
+ the ramp disappears.
164
+
165
+ **Second option, if a ramp is wanted:** source it from the corroborated union
166
+ (event log plus archive manifest), make it logarithmic rather than linear so
167
+ volume has diminishing returns, and add recency decay. Note that recency decay
168
+ needs a corroborated timestamp, because `last_seen` on these files is the
169
+ rebuilder's clock (section 3.2). This is real work and it still measures
170
+ volume, so I would only do it if the trust graph is going to become an input to
171
+ something that decides.
172
+
173
+ **Third option:** keep the status quo plus the marker, which is what this
174
+ change ships as an interim. Acceptable only while section 5 stays true.
175
+
176
+ ### (d) Record or replace `0.3 + 0.05n`
177
+
178
+ Recorded, not silently kept. The constants are now named in `graph.py` as
179
+ `COORD_BASE_STRENGTH`, `COORD_STRENGTH_PER_TASK` and `COORD_SATURATION_TASKS`
180
+ (14), the saturation point is stated in the code rather than left to be
181
+ discovered, and `tests/test_trust_graph_coord_audit.py` locks the exact curve at
182
+ n = 0, 3, 14 and 200 so that any future change to it is a deliberate, reviewed
183
+ edit rather than a drift.
184
+
185
+ That test is a lock, not an endorsement. If (a) is accepted, the lock changes in
186
+ the same commit as the formula and the reasoning goes here.
187
+
188
+ ## 7. Follow-ups this change does NOT do
189
+
190
+ - **skdashboard still collapses every exception into an empty graph** with a
191
+ `note` field. It now has `sources` and `complete` available in the payload it
192
+ already parses, and its trust panel should surface both, but that is another
193
+ repo and another card.
194
+ - **The other file-scanning readers in `graph.py`** (`_add_token_edges`,
195
+ `_add_feb_edges`, `_add_sync_edges`) still swallow per-file failures without
196
+ counting them. `SourceHealth` is deliberately general so they can be
197
+ instrumented the same way. Coord was done first because it is the one whose
198
+ source is known to be corrupt.
199
+ - **Nothing in this change touches the coordination store or its rebuilder.**
200
+ The four corruption modes in section 3 are still live. This change makes
201
+ capauth stop presenting them as fact; it does not fix them.
@@ -91,6 +91,7 @@ from .trust import (
91
91
  CALIBRATION_FILENAME,
92
92
  DEFAULT_THRESHOLDS,
93
93
  FORMATTERS,
94
+ SourceHealth,
94
95
  TrustEdge,
95
96
  TrustGraph,
96
97
  TrustNode,
@@ -191,6 +192,7 @@ __all__ = [
191
192
  "has_scope",
192
193
  # trust (kernel track M1: moved verbatim from skcapstone)
193
194
  "FORMATTERS",
195
+ "SourceHealth",
194
196
  "CALIBRATION_FILENAME",
195
197
  "DEFAULT_THRESHOLDS",
196
198
  "TrustEdge",
@@ -217,7 +219,8 @@ __all__ = [
217
219
  # distribution metadata instead, so this attribute can only ever agree with what
218
220
  # pip actually resolved.
219
221
  try: # pragma: no cover - trivial, and the fallback is exercised below
220
- from importlib.metadata import PackageNotFoundError, version as _dist_version
222
+ from importlib.metadata import PackageNotFoundError
223
+ from importlib.metadata import version as _dist_version
221
224
 
222
225
  __version__ = _dist_version("capauth")
223
226
  except PackageNotFoundError: # running from a source tree with no install
@@ -66,6 +66,13 @@ from .operator_session import (
66
66
  verify_device_signature,
67
67
  verify_operator_session,
68
68
  )
69
+ from .proof import (
70
+ EnrollmentProof,
71
+ ProofSigningError,
72
+ build_attested_proof,
73
+ build_verified_proof,
74
+ enrollment_challenge,
75
+ )
69
76
  from .records import (
70
77
  MODE_SEVERITY,
71
78
  DeviceRecord,
@@ -77,6 +84,7 @@ from .records import (
77
84
  from .store import (
78
85
  SIDECAR_KEY,
79
86
  SIDECAR_VERSION,
87
+ SKCAPSTONE_HOME_ENV,
80
88
  PairingStore,
81
89
  default_base_dir,
82
90
  fingerprint_for,
@@ -93,6 +101,12 @@ __all__ = [
93
101
  "PairingError",
94
102
  "verified_challenge",
95
103
  "attested_challenge",
104
+ # supported proof construction (the constructor for the N10 requirement)
105
+ "build_verified_proof",
106
+ "build_attested_proof",
107
+ "enrollment_challenge",
108
+ "EnrollmentProof",
109
+ "ProofSigningError",
96
110
  # records + modes
97
111
  "EnrollmentMode",
98
112
  "Enrollment",
@@ -106,6 +120,7 @@ __all__ = [
106
120
  "PairingStore",
107
121
  "SIDECAR_KEY",
108
122
  "SIDECAR_VERSION",
123
+ "SKCAPSTONE_HOME_ENV",
109
124
  "default_base_dir",
110
125
  "fingerprint_for",
111
126
  # canonical-subject rewrite (card N5)