capauth 0.3.12__tar.gz → 0.3.14__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 (414) hide show
  1. {capauth-0.3.12 → capauth-0.3.14}/.github/workflows/ci.yml +5 -0
  2. capauth-0.3.14/.github/workflows/image.yml +90 -0
  3. capauth-0.3.14/AGENTS.md +99 -0
  4. {capauth-0.3.12 → capauth-0.3.14}/CHANGELOG.md +42 -0
  5. {capauth-0.3.12 → capauth-0.3.14}/Dockerfile +4 -0
  6. {capauth-0.3.12 → capauth-0.3.14}/Dockerfile.authentik-capauth +22 -5
  7. {capauth-0.3.12/src/capauth.egg-info → capauth-0.3.14}/PKG-INFO +6 -4
  8. {capauth-0.3.12 → capauth-0.3.14}/README.md +2 -0
  9. {capauth-0.3.12 → capauth-0.3.14}/docs/AUTHENTIK_STRATEGY_DECISION.md +188 -43
  10. {capauth-0.3.12 → capauth-0.3.14}/docs/CAPAUTH_OIDC_IDP.md +8 -1
  11. capauth-0.3.14/docs/SIGN_CHALLENGE.md +80 -0
  12. {capauth-0.3.12 → capauth-0.3.14}/pyproject.toml +3 -3
  13. {capauth-0.3.12 → capauth-0.3.14}/scripts/capauth-backup.sh +10 -2
  14. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/cli.py +41 -0
  15. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integration.py +3 -3
  16. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/oidc/clients.py +9 -1
  17. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/oidc/provider.py +126 -27
  18. capauth-0.3.14/src/capauth/sign_challenge.py +192 -0
  19. {capauth-0.3.12 → capauth-0.3.14/src/capauth.egg-info}/PKG-INFO +6 -4
  20. {capauth-0.3.12 → capauth-0.3.14}/src/capauth.egg-info/SOURCES.txt +8 -2
  21. {capauth-0.3.12 → capauth-0.3.14}/src/capauth.egg-info/requires.txt +3 -3
  22. capauth-0.3.14/src/capauth.egg-info/scm_file_list.json +407 -0
  23. capauth-0.3.14/tests/test_backup_fallback.py +66 -0
  24. capauth-0.3.14/tests/test_dockerfile_version.py +17 -0
  25. {capauth-0.3.12 → capauth-0.3.14}/tests/test_integration.py +18 -4
  26. {capauth-0.3.12 → capauth-0.3.14}/tests/test_oidc_hardening.py +92 -0
  27. {capauth-0.3.12 → capauth-0.3.14}/tests/test_oidc_idp.py +30 -0
  28. capauth-0.3.14/tests/test_oidc_login_passphrase_dialog.py +38 -0
  29. capauth-0.3.14/tests/test_sign_challenge.py +229 -0
  30. {capauth-0.3.12 → capauth-0.3.14}/urllib.error +1 -1
  31. capauth-0.3.12/.cursorrules +0 -15
  32. capauth-0.3.12/AGENTS.md +0 -24
  33. capauth-0.3.12/CLAUDE.md +0 -144
  34. {capauth-0.3.12 → capauth-0.3.14}/.dockerignore +0 -0
  35. {capauth-0.3.12 → capauth-0.3.14}/.github/workflows/docs-check.yml +0 -0
  36. {capauth-0.3.12 → capauth-0.3.14}/.github/workflows/nextcloud-appstore.yml +0 -0
  37. {capauth-0.3.12 → capauth-0.3.14}/.github/workflows/publish.yml +0 -0
  38. {capauth-0.3.12 → capauth-0.3.14}/.github/workflows/pytest.yml +0 -0
  39. {capauth-0.3.12 → capauth-0.3.14}/.github/workflows/secret-scan.yml +0 -0
  40. {capauth-0.3.12 → capauth-0.3.14}/.gitignore +0 -0
  41. {capauth-0.3.12 → capauth-0.3.14}/.gitleaks-baseline.json +0 -0
  42. {capauth-0.3.12 → capauth-0.3.14}/.gitleaks.toml +0 -0
  43. {capauth-0.3.12 → capauth-0.3.14}/AI-ADVOCATE.md +0 -0
  44. {capauth-0.3.12 → capauth-0.3.14}/ARCHITECTURE.md +0 -0
  45. {capauth-0.3.12 → capauth-0.3.14}/CODE_OF_CONDUCT.md +0 -0
  46. {capauth-0.3.12 → capauth-0.3.14}/CONTRIBUTING.md +0 -0
  47. {capauth-0.3.12 → capauth-0.3.14}/LICENSE +0 -0
  48. {capauth-0.3.12 → capauth-0.3.14}/MANIFEST.in +0 -0
  49. {capauth-0.3.12 → capauth-0.3.14}/MISSION.md +0 -0
  50. {capauth-0.3.12 → capauth-0.3.14}/SECURITY.md +0 -0
  51. {capauth-0.3.12 → capauth-0.3.14}/SKILL.md +0 -0
  52. {capauth-0.3.12 → capauth-0.3.14}/SOP.md +0 -0
  53. {capauth-0.3.12 → capauth-0.3.14}/authentik-custom/capauth_migrate.py +0 -0
  54. {capauth-0.3.12 → capauth-0.3.14}/authentik-custom/imghdr.py +0 -0
  55. {capauth-0.3.12 → capauth-0.3.14}/authentik-custom/user_settings.py +0 -0
  56. {capauth-0.3.12 → capauth-0.3.14}/bin/cli.js +0 -0
  57. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/.gitignore +0 -0
  58. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/README.md +0 -0
  59. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/RELEASING.md +0 -0
  60. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/background.js +0 -0
  61. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/content_scripts/autofill.js +0 -0
  62. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/content_scripts/cross_origin_signing.js +0 -0
  63. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/content_scripts/detector.js +0 -0
  64. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/content_scripts/provider.js +0 -0
  65. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/content_scripts/provider_bridge.js +0 -0
  66. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/icons/icon.svg +0 -0
  67. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/icons/icon128.png +0 -0
  68. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/icons/icon16.png +0 -0
  69. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/icons/icon48.png +0 -0
  70. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/lib/bunker-e2e.js +0 -0
  71. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/lib/keyqr.js +0 -0
  72. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/lib/keyvault.js +0 -0
  73. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/lib/openpgp.js +0 -0
  74. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/lib/signer-backends.js +0 -0
  75. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/manifest.firefox.json +0 -0
  76. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/manifest.json +0 -0
  77. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/native-host/capauth_signer.py +0 -0
  78. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/native-host/com.capauth.signer.json +0 -0
  79. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/native-host/install.sh +0 -0
  80. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/options/options.html +0 -0
  81. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/options/options.js +0 -0
  82. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/package-lock.json +0 -0
  83. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/package.json +0 -0
  84. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/popup/popup.css +0 -0
  85. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/popup/popup.html +0 -0
  86. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/popup/popup.js +0 -0
  87. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/scripts/build.js +0 -0
  88. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/scripts/generate-icons.js +0 -0
  89. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/stages/AuthenticatorSelectionStage.js +0 -0
  90. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/stages/CapAuthStage.js +0 -0
  91. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/stages/QRDisplayStage.js +0 -0
  92. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/stages/SignatureVerificationStage.js +0 -0
  93. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/stages/StagePipeline.js +0 -0
  94. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/submission/STORE_LISTING.md +0 -0
  95. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/submission/privacy-policy.md +0 -0
  96. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/tests/fixtures/test_key.json +0 -0
  97. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/tests/unit/background.test.js +0 -0
  98. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/tests/unit/bunker_e2e.test.js +0 -0
  99. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/tests/unit/detector.test.js +0 -0
  100. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/tests/unit/keyqr.test.js +0 -0
  101. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/tests/unit/keyvault.test.js +0 -0
  102. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/tests/unit/openpgp.test.js +0 -0
  103. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/tests/unit/provider_api.test.js +0 -0
  104. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/tests/unit/provider_tierb.test.js +0 -0
  105. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/tests/unit/remote_bunker.test.js +0 -0
  106. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/tests/unit/signer_backends.test.js +0 -0
  107. {capauth-0.3.12 → capauth-0.3.14}/browser-extension/vitest.config.js +0 -0
  108. {capauth-0.3.12 → capauth-0.3.14}/deploy/capauth-service/.env.example +0 -0
  109. {capauth-0.3.12 → capauth-0.3.14}/deploy/capauth-service/deploy.sh +0 -0
  110. {capauth-0.3.12 → capauth-0.3.14}/deploy/capauth-service/docker-compose.yml +0 -0
  111. {capauth-0.3.12 → capauth-0.3.14}/deploy/capauth-service/systemd/capauth-backup.service +0 -0
  112. {capauth-0.3.12 → capauth-0.3.14}/deploy/capauth-service/systemd/capauth-backup.timer +0 -0
  113. {capauth-0.3.12 → capauth-0.3.14}/deploy/forgejo-capauth/.env.example +0 -0
  114. {capauth-0.3.12 → capauth-0.3.14}/deploy/forgejo-capauth/docker-compose.yml +0 -0
  115. {capauth-0.3.12 → capauth-0.3.14}/deploy/forgejo-capauth/preflight.sh +0 -0
  116. {capauth-0.3.12 → capauth-0.3.14}/docs/AIRGAPPED_SIGNING_WORKSTATION.md +0 -0
  117. {capauth-0.3.12 → capauth-0.3.14}/docs/ARCHITECTURE.md +0 -0
  118. {capauth-0.3.12 → capauth-0.3.14}/docs/AUTHENTIK_CUSTOM_STAGE.md +0 -0
  119. {capauth-0.3.12 → capauth-0.3.14}/docs/AUTHENTIK_DEPLOYMENT_SKSSO.md +0 -0
  120. {capauth-0.3.12 → capauth-0.3.14}/docs/AUTHENTIK_FORGEJO_DEPLOYMENT.md +0 -0
  121. {capauth-0.3.12 → capauth-0.3.14}/docs/CAPAUTH-WEBAUTHN-05-QUALIFICATION.md +0 -0
  122. {capauth-0.3.12 → capauth-0.3.14}/docs/CAPAUTH_BUNKER_REMOTE_SIGNER.md +0 -0
  123. {capauth-0.3.12 → capauth-0.3.14}/docs/CLAIMS.md +0 -0
  124. {capauth-0.3.12 → capauth-0.3.14}/docs/COLD_MACHINE_BOOTSTRAP_AND_DR.md +0 -0
  125. {capauth-0.3.12 → capauth-0.3.14}/docs/CRYPTO_SPEC.md +0 -0
  126. {capauth-0.3.12 → capauth-0.3.14}/docs/DELEGATED_CAPABILITIES.md +0 -0
  127. {capauth-0.3.12 → capauth-0.3.14}/docs/DOWNSTREAM_DURABLE_BACKENDS.md +0 -0
  128. {capauth-0.3.12 → capauth-0.3.14}/docs/ENTERPRISE_MANAGED_KEYS.md +0 -0
  129. {capauth-0.3.12 → capauth-0.3.14}/docs/HUMAN_IDENTITY_SETUP_AND_ROTATION.md +0 -0
  130. {capauth-0.3.12 → capauth-0.3.14}/docs/IDENTITY_ESTATE.md +0 -0
  131. {capauth-0.3.12 → capauth-0.3.14}/docs/INTEGRATION_BLUEPRINT.md +0 -0
  132. {capauth-0.3.12 → capauth-0.3.14}/docs/M0-capauth-api-v1.md +0 -0
  133. {capauth-0.3.12 → capauth-0.3.14}/docs/M0-capauth-importer-inventory.md +0 -0
  134. {capauth-0.3.12 → capauth-0.3.14}/docs/PASSPHRASE_ROTATION.md +0 -0
  135. {capauth-0.3.12 → capauth-0.3.14}/docs/PQC_CAPAUTH_REVISIT.md +0 -0
  136. {capauth-0.3.12 → capauth-0.3.14}/docs/PQC_ROOT_MIGRATION.md +0 -0
  137. {capauth-0.3.12 → capauth-0.3.14}/docs/PROTOCOL.md +0 -0
  138. {capauth-0.3.12 → capauth-0.3.14}/docs/ROOT_ROTATION_CEREMONY.md +0 -0
  139. {capauth-0.3.12 → capauth-0.3.14}/docs/SKDASHBOARD_CONTROL_PLANE_POLICY.md +0 -0
  140. {capauth-0.3.12 → capauth-0.3.14}/docs/TRUST_GRAPH_COORD_PROJECTION.md +0 -0
  141. {capauth-0.3.12 → capauth-0.3.14}/docs/ZERO_KNOWLEDGE_PROFILE.md +0 -0
  142. {capauth-0.3.12 → capauth-0.3.14}/docs/audits/BLAST-RADIUS-CAPAUTH-01.md +0 -0
  143. {capauth-0.3.12 → capauth-0.3.14}/docs/audits/BLAST-RADIUS-CAPAUTH-01.sha256 +0 -0
  144. {capauth-0.3.12 → capauth-0.3.14}/docs/authentik-capauth.md +0 -0
  145. {capauth-0.3.12 → capauth-0.3.14}/docs/deploy-plan/capauth-bulletproof-deploy.md +0 -0
  146. {capauth-0.3.12 → capauth-0.3.14}/docs/evidence/capauth/SKL-CAPAUTH-SIGNER-P3P-MUTATION-ENVELOPE-2026-08-25.json +0 -0
  147. {capauth-0.3.12 → capauth-0.3.14}/docs/evidence/capauth/SKL-CAPAUTH-SIGNER-P3P-ROSTER-2026-08-25.json +0 -0
  148. {capauth-0.3.12 → capauth-0.3.14}/index.d.ts +0 -0
  149. {capauth-0.3.12 → capauth-0.3.14}/index.js +0 -0
  150. {capauth-0.3.12 → capauth-0.3.14}/openclaw-plugin.archived-2026-04-23/package.json +0 -0
  151. {capauth-0.3.12 → capauth-0.3.14}/openclaw-plugin.archived-2026-04-23/src/index.ts +0 -0
  152. {capauth-0.3.12 → capauth-0.3.14}/openclaw-plugin.archived-2026-04-23/src/openclaw.plugin.json +0 -0
  153. {capauth-0.3.12 → capauth-0.3.14}/package.json +0 -0
  154. {capauth-0.3.12 → capauth-0.3.14}/phone-signer/app.js +0 -0
  155. {capauth-0.3.12 → capauth-0.3.14}/phone-signer/icons/icon-192.png +0 -0
  156. {capauth-0.3.12 → capauth-0.3.14}/phone-signer/icons/icon-512.png +0 -0
  157. {capauth-0.3.12 → capauth-0.3.14}/phone-signer/index.html +0 -0
  158. {capauth-0.3.12 → capauth-0.3.14}/phone-signer/lib/bunker-e2e.js +0 -0
  159. {capauth-0.3.12 → capauth-0.3.14}/phone-signer/lib/bunker-signer.js +0 -0
  160. {capauth-0.3.12 → capauth-0.3.14}/phone-signer/lib/canonical.js +0 -0
  161. {capauth-0.3.12 → capauth-0.3.14}/phone-signer/lib/keyqr.js +0 -0
  162. {capauth-0.3.12 → capauth-0.3.14}/phone-signer/lib/keyvault.js +0 -0
  163. {capauth-0.3.12 → capauth-0.3.14}/phone-signer/manifest.webmanifest +0 -0
  164. {capauth-0.3.12 → capauth-0.3.14}/phone-signer/sw.js +0 -0
  165. {capauth-0.3.12 → capauth-0.3.14}/phone-signer/vendor/openpgp.min.js +0 -0
  166. {capauth-0.3.12 → capauth-0.3.14}/phone-signer/vendor/qrcode-generator.js +0 -0
  167. {capauth-0.3.12 → capauth-0.3.14}/ruff-0.15.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
  168. {capauth-0.3.12 → capauth-0.3.14}/scripts/build_authentik_capauth_image.sh +0 -0
  169. {capauth-0.3.12 → capauth-0.3.14}/scripts/capauth-restore.sh +0 -0
  170. {capauth-0.3.12 → capauth-0.3.14}/scripts/gitleaks-scope.sh +0 -0
  171. {capauth-0.3.12 → capauth-0.3.14}/scripts/migrate_canonical_subjects.py +0 -0
  172. {capauth-0.3.12 → capauth-0.3.14}/scripts/pqc_ceremony_dryrun.py +0 -0
  173. {capauth-0.3.12 → capauth-0.3.14}/scripts/provision_agent_profiles.py +0 -0
  174. {capauth-0.3.12 → capauth-0.3.14}/setup.cfg +0 -0
  175. {capauth-0.3.12 → capauth-0.3.14}/skill.yaml +0 -0
  176. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/__init__.py +0 -0
  177. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/agent_identity.py +0 -0
  178. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/apps.py +0 -0
  179. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/authentik/__init__.py +0 -0
  180. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/authentik/api.py +0 -0
  181. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/authentik/blueprints/capauth-pgp-login.yaml +0 -0
  182. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/authentik/claims_mapper.py +0 -0
  183. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/authentik/nonce_store.py +0 -0
  184. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/authentik/stage.py +0 -0
  185. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/authentik/urls.py +0 -0
  186. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/authentik/verifier.py +0 -0
  187. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/authz.py +0 -0
  188. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/control_plane.py +0 -0
  189. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/control_plane_authorizer.py +0 -0
  190. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/control_plane_session.py +0 -0
  191. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/crypto/__init__.py +0 -0
  192. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/crypto/base.py +0 -0
  193. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/crypto/gnupg_backend.py +0 -0
  194. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/crypto/pgpy_backend.py +0 -0
  195. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/crypto/sequoia_backend.py +0 -0
  196. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/crypto/skpgp_backend.py +0 -0
  197. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/custody.py +0 -0
  198. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/delegated.py +0 -0
  199. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/did.py +0 -0
  200. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/discovery/__init__.py +0 -0
  201. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/discovery/base.py +0 -0
  202. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/discovery/file_discovery.py +0 -0
  203. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/discovery/mdns.py +0 -0
  204. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/discovery/syncthing.py +0 -0
  205. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/estate.py +0 -0
  206. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/exceptions.py +0 -0
  207. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/identity.py +0 -0
  208. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/identity_class.py +0 -0
  209. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/__init__.py +0 -0
  210. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/forgejo/__init__.py +0 -0
  211. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/forgejo/auth_flow.py +0 -0
  212. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/forgejo/cli.py +0 -0
  213. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/forgejo/config.py +0 -0
  214. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/forgejo/forgejo_api.py +0 -0
  215. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/forgejo/oidc_provider.py +0 -0
  216. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/forgejo/tests/__init__.py +0 -0
  217. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/forgejo/tests/test_auth_flow.py +0 -0
  218. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/forgejo/tests/test_cli.py +0 -0
  219. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/forgejo/tests/test_config.py +0 -0
  220. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/forgejo/tests/test_forgejo_api.py +0 -0
  221. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/forgejo/tests/test_oidc_provider.py +0 -0
  222. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/.gitignore +0 -0
  223. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/.nextcloudignore +0 -0
  224. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/CSR-PR.md +0 -0
  225. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/INFO-XML-CHANGES.md +0 -0
  226. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/PUBLISHING.md +0 -0
  227. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/README.md +0 -0
  228. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/appinfo/info.xml +0 -0
  229. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/appinfo/routes.php +0 -0
  230. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/build-release.sh +0 -0
  231. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/certificates/.gitignore +0 -0
  232. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/certificates/capauth.crt +0 -0
  233. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/certificates/capauth.csr +0 -0
  234. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/composer.json +0 -0
  235. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/css/login.css +0 -0
  236. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/js/login.js +0 -0
  237. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/krankerl.toml +0 -0
  238. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/AlternativeLogin/CapAuthLogin.php +0 -0
  239. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/AppInfo/Application.php +0 -0
  240. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/BackgroundJob/PruneExpiredNonces.php +0 -0
  241. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/Controller/LoginController.php +0 -0
  242. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/Controller/TokenController.php +0 -0
  243. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/Db/KeyRegistry.php +0 -0
  244. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/Exception/CapAuthUnauthorizedException.php +0 -0
  245. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/Middleware/PgpVerificationMiddleware.php +0 -0
  246. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/Migration/Version000300Date20260301000000.php +0 -0
  247. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/Provider/CapAuthProvider.php +0 -0
  248. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/Service/ChallengeService.php +0 -0
  249. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/Service/GroupSyncService.php +0 -0
  250. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/Service/UserProvisioningService.php +0 -0
  251. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/Service/VerifierService.php +0 -0
  252. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/lib/User/Backend.php +0 -0
  253. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/phpunit.xml +0 -0
  254. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/screenshots/README.md +0 -0
  255. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/screenshots/login.png +0 -0
  256. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/templates/login.php +0 -0
  257. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/tests/bootstrap.php +0 -0
  258. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/tests/integration/FullAuthFlowTest.php +0 -0
  259. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/tests/oidc/oidc_e2e_login_test.py +0 -0
  260. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/tests/unit/Controller/LoginControllerTest.php +0 -0
  261. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/tests/unit/Db/KeyRegistryTest.php +0 -0
  262. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/tests/unit/Provider/CapAuthProviderTest.php +0 -0
  263. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/tests/unit/Service/ChallengeServiceTest.php +0 -0
  264. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/tests/unit/Service/VerifierServiceTest.php +0 -0
  265. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/integrations/nextcloud/tests/unit/User/BackendTest.php +0 -0
  266. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/key_transparency.py +0 -0
  267. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/login.py +0 -0
  268. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/manifest.py +0 -0
  269. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/mesh.py +0 -0
  270. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/migrations/0001_initial.py +0 -0
  271. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/migrations/0002_widen_fingerprint_to_64.py +0 -0
  272. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/migrations/__init__.py +0 -0
  273. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/models.py +0 -0
  274. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/pairing/__init__.py +0 -0
  275. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/pairing/canonicalize.py +0 -0
  276. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/pairing/kernel.py +0 -0
  277. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/pairing/operator_session.py +0 -0
  278. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/pairing/proof.py +0 -0
  279. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/pairing/records.py +0 -0
  280. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/pairing/store.py +0 -0
  281. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/pairing/window.py +0 -0
  282. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/pma.py +0 -0
  283. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/pqc_confidentiality.py +0 -0
  284. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/pqc_identity.py +0 -0
  285. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/pqc_root_identity.py +0 -0
  286. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/pqc_tokens.py +0 -0
  287. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/profile.py +0 -0
  288. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/provisioning.py +0 -0
  289. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/registry.py +0 -0
  290. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/rotation.py +0 -0
  291. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/seal.py +0 -0
  292. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/__init__.py +0 -0
  293. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/app.py +0 -0
  294. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/bunker.py +0 -0
  295. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/bunker_e2e.py +0 -0
  296. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/keystore.py +0 -0
  297. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/oidc/__init__.py +0 -0
  298. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/oidc/clients.example.json +0 -0
  299. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/oidc/passkey.py +0 -0
  300. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/oidc/signing_key.py +0 -0
  301. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/oidc/static/bunker/lib/bunker-e2e.js +0 -0
  302. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/oidc/static/bunker/lib/keyvault.js +0 -0
  303. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/oidc/static/bunker/vendor/openpgp.min.js +0 -0
  304. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/oidc/store.py +0 -0
  305. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/push.py +0 -0
  306. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/service/server.py +0 -0
  307. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/subject.py +0 -0
  308. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/sync.py +0 -0
  309. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/testing.py +0 -0
  310. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/tokens.py +0 -0
  311. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/trust/__init__.py +0 -0
  312. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/trust/calibration.py +0 -0
  313. {capauth-0.3.12 → capauth-0.3.14}/src/capauth/trust/graph.py +0 -0
  314. {capauth-0.3.12 → capauth-0.3.14}/src/capauth.egg-info/dependency_links.txt +0 -0
  315. {capauth-0.3.12 → capauth-0.3.14}/src/capauth.egg-info/entry_points.txt +0 -0
  316. {capauth-0.3.12 → capauth-0.3.14}/src/capauth.egg-info/top_level.txt +0 -0
  317. {capauth-0.3.12 → capauth-0.3.14}/stages/ak-stage-capauth/.gitignore +0 -0
  318. {capauth-0.3.12 → capauth-0.3.14}/stages/ak-stage-capauth/package-lock.json +0 -0
  319. {capauth-0.3.12 → capauth-0.3.14}/stages/ak-stage-capauth/package.json +0 -0
  320. {capauth-0.3.12 → capauth-0.3.14}/stages/ak-stage-capauth/src/CapAuthStage.test.js +0 -0
  321. {capauth-0.3.12 → capauth-0.3.14}/stages/ak-stage-capauth/src/CapAuthStage.vue +0 -0
  322. {capauth-0.3.12 → capauth-0.3.14}/stages/ak-stage-capauth/src/index.js +0 -0
  323. {capauth-0.3.12 → capauth-0.3.14}/stages/ak-stage-capauth/vite.config.js +0 -0
  324. {capauth-0.3.12 → capauth-0.3.14}/tests/__init__.py +0 -0
  325. {capauth-0.3.12 → capauth-0.3.14}/tests/conftest.py +0 -0
  326. {capauth-0.3.12 → capauth-0.3.14}/tests/fixtures/bunker_e2e_v1_vector.json +0 -0
  327. {capauth-0.3.12 → capauth-0.3.14}/tests/fixtures/canonical_nonce_v2_vector.json +0 -0
  328. {capauth-0.3.12 → capauth-0.3.14}/tests/test_agent_identity.py +0 -0
  329. {capauth-0.3.12 → capauth-0.3.14}/tests/test_agentrun_capabilities.py +0 -0
  330. {capauth-0.3.12 → capauth-0.3.14}/tests/test_audience_mint_helper.py +0 -0
  331. {capauth-0.3.12 → capauth-0.3.14}/tests/test_audience_tokens.py +0 -0
  332. {capauth-0.3.12 → capauth-0.3.14}/tests/test_audience_ttl_seconds.py +0 -0
  333. {capauth-0.3.12 → capauth-0.3.14}/tests/test_authz.py +0 -0
  334. {capauth-0.3.12 → capauth-0.3.14}/tests/test_authz_legacy_grace.py +0 -0
  335. {capauth-0.3.12 → capauth-0.3.14}/tests/test_authz_signature_gate.py +0 -0
  336. {capauth-0.3.12 → capauth-0.3.14}/tests/test_backup_restore.py +0 -0
  337. {capauth-0.3.12 → capauth-0.3.14}/tests/test_bunker.py +0 -0
  338. {capauth-0.3.12 → capauth-0.3.14}/tests/test_bunker_e2e.py +0 -0
  339. {capauth-0.3.12 → capauth-0.3.14}/tests/test_canonicalize.py +0 -0
  340. {capauth-0.3.12 → capauth-0.3.14}/tests/test_capauth_service_deploy.py +0 -0
  341. {capauth-0.3.12 → capauth-0.3.14}/tests/test_change_capabilities.py +0 -0
  342. {capauth-0.3.12 → capauth-0.3.14}/tests/test_claims_mapper.py +0 -0
  343. {capauth-0.3.12 → capauth-0.3.14}/tests/test_control_plane.py +0 -0
  344. {capauth-0.3.12 → capauth-0.3.14}/tests/test_control_plane_authorizer.py +0 -0
  345. {capauth-0.3.12 → capauth-0.3.14}/tests/test_control_plane_capabilities.py +0 -0
  346. {capauth-0.3.12 → capauth-0.3.14}/tests/test_control_plane_session.py +0 -0
  347. {capauth-0.3.12 → capauth-0.3.14}/tests/test_crypto.py +0 -0
  348. {capauth-0.3.12 → capauth-0.3.14}/tests/test_custody.py +0 -0
  349. {capauth-0.3.12 → capauth-0.3.14}/tests/test_delegated_capabilities.py +0 -0
  350. {capauth-0.3.12 → capauth-0.3.14}/tests/test_device_key_proof.py +0 -0
  351. {capauth-0.3.12 → capauth-0.3.14}/tests/test_did_capability_relationships.py +0 -0
  352. {capauth-0.3.12 → capauth-0.3.14}/tests/test_enrollment_proof_helper.py +0 -0
  353. {capauth-0.3.12 → capauth-0.3.14}/tests/test_estate.py +0 -0
  354. {capauth-0.3.12 → capauth-0.3.14}/tests/test_fingerprint_v6.py +0 -0
  355. {capauth-0.3.12 → capauth-0.3.14}/tests/test_forgejo_preflight.py +0 -0
  356. {capauth-0.3.12 → capauth-0.3.14}/tests/test_home_resolution.py +0 -0
  357. {capauth-0.3.12 → capauth-0.3.14}/tests/test_identity.py +0 -0
  358. {capauth-0.3.12 → capauth-0.3.14}/tests/test_identity_class.py +0 -0
  359. {capauth-0.3.12 → capauth-0.3.14}/tests/test_identity_ttl.py +0 -0
  360. {capauth-0.3.12 → capauth-0.3.14}/tests/test_installed_bunker_assets.py +0 -0
  361. {capauth-0.3.12 → capauth-0.3.14}/tests/test_key_revocation_expiry.py +0 -0
  362. {capauth-0.3.12 → capauth-0.3.14}/tests/test_key_transparency.py +0 -0
  363. {capauth-0.3.12 → capauth-0.3.14}/tests/test_login.py +0 -0
  364. {capauth-0.3.12 → capauth-0.3.14}/tests/test_manifest.py +0 -0
  365. {capauth-0.3.12 → capauth-0.3.14}/tests/test_mesh.py +0 -0
  366. {capauth-0.3.12 → capauth-0.3.14}/tests/test_models_pqc_q0.py +0 -0
  367. {capauth-0.3.12 → capauth-0.3.14}/tests/test_nextcloud_app.py +0 -0
  368. {capauth-0.3.12 → capauth-0.3.14}/tests/test_no_subapp_dependency.py +0 -0
  369. {capauth-0.3.12 → capauth-0.3.14}/tests/test_nonce_store.py +0 -0
  370. {capauth-0.3.12 → capauth-0.3.14}/tests/test_oidc_durable_store.py +0 -0
  371. {capauth-0.3.12 → capauth-0.3.14}/tests/test_oidc_idp_e2e.py +0 -0
  372. {capauth-0.3.12 → capauth-0.3.14}/tests/test_oidc_refresh_family.py +0 -0
  373. {capauth-0.3.12 → capauth-0.3.14}/tests/test_operator_session.py +0 -0
  374. {capauth-0.3.12 → capauth-0.3.14}/tests/test_pairing.py +0 -0
  375. {capauth-0.3.12 → capauth-0.3.14}/tests/test_pairing_base_dir_env.py +0 -0
  376. {capauth-0.3.12 → capauth-0.3.14}/tests/test_passkey.py +0 -0
  377. {capauth-0.3.12 → capauth-0.3.14}/tests/test_passkey_enrollment_ux.py +0 -0
  378. {capauth-0.3.12 → capauth-0.3.14}/tests/test_pma.py +0 -0
  379. {capauth-0.3.12 → capauth-0.3.14}/tests/test_pqc_confidentiality.py +0 -0
  380. {capauth-0.3.12 → capauth-0.3.14}/tests/test_pqc_identity.py +0 -0
  381. {capauth-0.3.12 → capauth-0.3.14}/tests/test_pqc_root_integration.py +0 -0
  382. {capauth-0.3.12 → capauth-0.3.14}/tests/test_pqc_t3_gate.py +0 -0
  383. {capauth-0.3.12 → capauth-0.3.14}/tests/test_pqc_tokens.py +0 -0
  384. {capauth-0.3.12 → capauth-0.3.14}/tests/test_profile.py +0 -0
  385. {capauth-0.3.12 → capauth-0.3.14}/tests/test_provisioning.py +0 -0
  386. {capauth-0.3.12 → capauth-0.3.14}/tests/test_push.py +0 -0
  387. {capauth-0.3.12 → capauth-0.3.14}/tests/test_py313_compat.py +0 -0
  388. {capauth-0.3.12 → capauth-0.3.14}/tests/test_qr_login.py +0 -0
  389. {capauth-0.3.12 → capauth-0.3.14}/tests/test_real_pgp_e2e.py +0 -0
  390. {capauth-0.3.12 → capauth-0.3.14}/tests/test_register_cli.py +0 -0
  391. {capauth-0.3.12 → capauth-0.3.14}/tests/test_registry.py +0 -0
  392. {capauth-0.3.12 → capauth-0.3.14}/tests/test_rotation.py +0 -0
  393. {capauth-0.3.12 → capauth-0.3.14}/tests/test_seal.py +0 -0
  394. {capauth-0.3.12 → capauth-0.3.14}/tests/test_sequoia_backend.py +0 -0
  395. {capauth-0.3.12 → capauth-0.3.14}/tests/test_service.py +0 -0
  396. {capauth-0.3.12 → capauth-0.3.14}/tests/test_service_authz_decide.py +0 -0
  397. {capauth-0.3.12 → capauth-0.3.14}/tests/test_service_v6_fingerprint.py +0 -0
  398. {capauth-0.3.12 → capauth-0.3.14}/tests/test_skpgp_backend.py +0 -0
  399. {capauth-0.3.12 → capauth-0.3.14}/tests/test_subject.py +0 -0
  400. {capauth-0.3.12 → capauth-0.3.14}/tests/test_sync.py +0 -0
  401. {capauth-0.3.12 → capauth-0.3.14}/tests/test_syncthing_discovery.py +0 -0
  402. {capauth-0.3.12 → capauth-0.3.14}/tests/test_testing_helper.py +0 -0
  403. {capauth-0.3.12 → capauth-0.3.14}/tests/test_token_gc.py +0 -0
  404. {capauth-0.3.12 → capauth-0.3.14}/tests/test_token_store_flag.py +0 -0
  405. {capauth-0.3.12 → capauth-0.3.14}/tests/test_tokens.py +0 -0
  406. {capauth-0.3.12 → capauth-0.3.14}/tests/test_trust_calibration.py +0 -0
  407. {capauth-0.3.12 → capauth-0.3.14}/tests/test_trust_graph.py +0 -0
  408. {capauth-0.3.12 → capauth-0.3.14}/tests/test_trust_graph_coord_audit.py +0 -0
  409. {capauth-0.3.12 → capauth-0.3.14}/tests/test_verifier.py +0 -0
  410. {capauth-0.3.12 → capauth-0.3.14}/tests/test_version_honesty.py +0 -0
  411. {capauth-0.3.12 → capauth-0.3.14}/tests/test_zk_profile.py +0 -0
  412. {capauth-0.3.12 → capauth-0.3.14}/tools/build-sq.sh +0 -0
  413. {capauth-0.3.12 → capauth-0.3.14}/web/README.md +0 -0
  414. {capauth-0.3.12 → capauth-0.3.14}/web/stages/capauth/CapAuthStage.ts +0 -0
@@ -37,11 +37,16 @@ jobs:
37
37
  # `import skcapstone` succeeds without it while
38
38
  # `from skcapstone.coordination import Board` does not. --no-deps means we
39
39
  # have to name it ourselves.
40
+ # skcapstone requires Python 3.11+, capauth supports 3.10: on 3.10 the
41
+ # integration tests skip (pytest.importorskip); on 3.11+ the import is
42
+ # asserted here so those tests can never skip silently.
40
43
  - name: Install skcapstone (optional integration backbone) from source
44
+ if: matrix.python-version != '3.10'
41
45
  run: |
42
46
  pip install --no-deps --no-cache-dir \
43
47
  "skcapstone @ git+https://github.com/smilinTux/skcapstone" \
44
48
  "skcoord @ git+https://github.com/smilinTux/skcoord"
49
+ python -c "from skcapstone.scheduler_jobs import load_jobs_with_dropins"
45
50
  - name: Run tests with coverage
46
51
  run: python -m pytest tests/ -v --tb=short --cov=capauth --cov-report=xml --cov-report=term-missing
47
52
  - name: Upload coverage
@@ -0,0 +1,90 @@
1
+ name: Container image
2
+
3
+ # Publishes the CapAuth service image (the OIDC IdP and verify service) for a
4
+ # release tag as ghcr.io/smilintux/capauth:<version>, and records its digest.
5
+ # Consumers pin <version>@sha256:<digest> (SKStacks sksso.CAPAUTH_IMAGE refuses
6
+ # anything else). A published version is never overwritten.
7
+ on:
8
+ push:
9
+ tags: ["v*"]
10
+ workflow_dispatch:
11
+ inputs:
12
+ tag:
13
+ description: "Existing release tag to (re)build if its image is missing, e.g. v0.3.13"
14
+ required: true
15
+
16
+ permissions:
17
+ contents: read
18
+ packages: write
19
+
20
+ concurrency:
21
+ group: image-${{ inputs.tag || github.ref }}
22
+ cancel-in-progress: false
23
+
24
+ env:
25
+ IMAGE: ghcr.io/smilintux/capauth
26
+
27
+ jobs:
28
+ image:
29
+ runs-on: ubuntu-latest
30
+ steps:
31
+ - uses: actions/checkout@v4
32
+ with:
33
+ ref: ${{ inputs.tag || github.ref }}
34
+ fetch-depth: 0
35
+ fetch-tags: true
36
+ - name: Resolve the version and refuse a tag that is not on main
37
+ id: v
38
+ env:
39
+ TAG: ${{ inputs.tag || github.ref_name }}
40
+ run: |
41
+ set -euo pipefail
42
+ case "$TAG" in v[0-9]*.[0-9]*.[0-9]*) ;; *) echo "::error::not a release tag: $TAG"; exit 1 ;; esac
43
+ version="${TAG#v}"
44
+ if ! [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
45
+ echo "::error::not a release version: $version"; exit 1
46
+ fi
47
+ git fetch --no-tags origin main:refs/remotes/origin/main
48
+ sha="$(git rev-parse "refs/tags/$TAG^{commit}")"
49
+ git merge-base --is-ancestor "$sha" refs/remotes/origin/main || {
50
+ echo "::error::$TAG ($sha) is not on main"; exit 1; }
51
+ echo "version=$version" >> "$GITHUB_OUTPUT"
52
+ echo "sha=$sha" >> "$GITHUB_OUTPUT"
53
+ - name: Log in to ghcr.io
54
+ env:
55
+ TOKEN: ${{ secrets.GITHUB_TOKEN }}
56
+ run: echo "$TOKEN" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
57
+ - name: Refuse to overwrite a published version
58
+ run: |
59
+ if docker manifest inspect "$IMAGE:${{ steps.v.outputs.version }}" >/dev/null 2>&1; then
60
+ echo "::error::$IMAGE:${{ steps.v.outputs.version }} already exists; versions are immutable"
61
+ exit 1
62
+ fi
63
+ - name: Build
64
+ run: |
65
+ docker build \
66
+ --build-arg CAPAUTH_VERSION="${{ steps.v.outputs.version }}" \
67
+ --label org.opencontainers.image.source="https://github.com/${{ github.repository }}" \
68
+ --label org.opencontainers.image.revision="${{ steps.v.outputs.sha }}" \
69
+ --label org.opencontainers.image.version="${{ steps.v.outputs.version }}" \
70
+ -t "$IMAGE:${{ steps.v.outputs.version }}" .
71
+ - name: Smoke test (version, service answers)
72
+ run: |
73
+ set -euo pipefail
74
+ v="${{ steps.v.outputs.version }}"
75
+ docker run --rm "$IMAGE:$v" capauth --version | tee /dev/stderr | grep -F "$v"
76
+ docker run -d --name smoke -p 18420:8420 "$IMAGE:$v"
77
+ for i in $(seq 1 30); do
78
+ curl -fsS http://127.0.0.1:18420/capauth/v1/status >/dev/null && break
79
+ sleep 2
80
+ done
81
+ curl -fsS http://127.0.0.1:18420/capauth/v1/status >/dev/null
82
+ docker rm -f smoke
83
+ - name: Push and record the digest
84
+ run: |
85
+ set -euo pipefail
86
+ v="${{ steps.v.outputs.version }}"
87
+ docker push "$IMAGE:$v"
88
+ ref="$(docker inspect --format '{{index .RepoDigests 0}}' "$IMAGE:$v")"
89
+ echo "Pinned reference: \`$IMAGE:$v@${ref#*@}\`" >> "$GITHUB_STEP_SUMMARY"
90
+ echo "pinned: $IMAGE:$v@${ref#*@}"
@@ -0,0 +1,99 @@
1
+ # AGENTS.md (capauth)
2
+
3
+ CapAuth: PGP-based sovereign identity and authentication for the SK stack (Python library, `capauth`
4
+ CLI and FastAPI verification service). Overview: [README.md](./README.md). Operations:
5
+ [SOP.md](./SOP.md). Architecture: [ARCHITECTURE.md](./ARCHITECTURE.md). This file follows
6
+ [AGENT_INSTRUCTIONS_STANDARD](https://github.com/smilinTux/sk-standards/blob/main/standards/AGENT_INSTRUCTIONS_STANDARD.md).
7
+ There is no `CLAUDE.md` or `.cursorrules`: every agent reads this file.
8
+
9
+ ## Source of truth and invariants
10
+
11
+ - **CapAuth owns the one canonical agent identity resolver**, `resolve_agent_identity` in
12
+ `src/capauth/agent_identity.py` (re-exported from `capauth`). skchat, skcomms, skmemory and
13
+ skcapstone delegate to it; never reimplement identity logic elsewhere. It returns a dual URI:
14
+ `capauth_uri` (`capauth:<agent>@<domain>`, the wire identity, always derivable) and `fqid`
15
+ (`<agent>@<operator>.<realm>`, read from `~/.skcapstone/cluster.json`).
16
+ - **Operator vs agents:** the shared `~/.skcapstone/identity/identity.json` holds the operator
17
+ identity (`role: operator`); each agent's wire identity resolves per agent. No identity carries an
18
+ `@capauth.local` placeholder (`skcapstone doctor` `identity:*` checks).
19
+ - **DID documents, three tiers** (`src/capauth/did.py`): `did:key` (self-contained), mesh-private
20
+ `did:web`, and public `did:web` (minimal: key, name, org). `from_profile()` reads only
21
+ `public_key_armor`; a private key is never touched; no tailnet IPs and no `memory`, `journal` or
22
+ detailed `soul` fields appear in any document; the public tier respects
23
+ `publish_to_skworld: false` in `~/.capauth/config.yaml`.
24
+ - **Crypto goes through a backend**, never hand-rolled primitives: `src/capauth/crypto/`
25
+ (`pgpy_backend.py`, `gnupg_backend.py`, `sequoia_backend.py`). Only `sequoia_backend.py` (the `sq`
26
+ CLI) can sign post-quantum; GnuPG is signing-disqualified for PQC. Hybrid combiners are HKDF over
27
+ both shared secrets, never XOR and never pure PQ.
28
+ - **The live root identity is still classical.** PQC root migration is additive-first and
29
+ reversible, gated on a root-rotation ceremony (epic `PQC-MIGRATION`). Do not claim a PQC root.
30
+ Per-surface status: [docs/CRYPTO_SPEC.md](./docs/CRYPTO_SPEC.md).
31
+
32
+ ## Commands
33
+
34
+ CI: `.github/workflows/ci.yml` (test on 3.10 to 3.12, lint, build), `pytest.yml`, `secret-scan.yml`,
35
+ `docs-check.yml` (sk-standards gate, tiers 1 to 3).
36
+
37
+ ```bash
38
+ pip install -e ".[dev,service]"
39
+ python -m pytest tests/ -v --tb=short --cov=capauth # CI test
40
+ pip install "ruff==0.15.4"
41
+ ruff format --check src/ tests/ # CI lint, step 1
42
+ ruff check src/ # CI lint, step 2
43
+ python -m build && twine check dist/* # CI build
44
+ scripts/gitleaks-scope.sh full # CI secret scan
45
+ ```
46
+
47
+ On 3.11+ CI also installs `skcapstone` and `skcoord` from git with `--no-deps` so
48
+ `tests/test_integration.py` runs instead of skipping; skcapstone is an optional backbone, never a
49
+ dependency (skcapstone depends on capauth, not the other way round). Ruff config is in
50
+ `pyproject.toml` (line length 99, rules `E,F,I,N,W`, `E501` ignored).
51
+
52
+ ## Start here
53
+
54
+ 1. `src/capauth/cli.py`: every `capauth` command.
55
+ 2. `src/capauth/agent_identity.py`: the unified identity resolver.
56
+ 3. `src/capauth/identity.py` and `src/capauth/did.py`: challenge-response and DID generation.
57
+ 4. `src/capauth/crypto/`: the crypto backends.
58
+ 5. `src/capauth/service/`: the FastAPI service (`app.py`, `server.py`, `keystore.py`).
59
+
60
+ ## Rules
61
+
62
+ - **Writing style:** no em dashes (U+2014) and no en dashes (U+2013) anywhere: code, comments,
63
+ docs, commits, PR bodies. Use commas, parentheses, colons or a new sentence. Hyphens are fine.
64
+ - **Branch and commit:** never commit to `main`. Branch, commit as soon as a fast check passes and
65
+ before the full suite, then open a PR. Add an `## [Unreleased]` entry to
66
+ [CHANGELOG.md](./CHANGELOG.md) for any user-visible change.
67
+ - **Attribution:** a `Co-Authored-By` trailer names the agent that actually did the work, or is
68
+ left out. Never one you cannot evidence.
69
+ - **Code style:** Python 3.11+ for new code (the package still supports 3.10), type hints, pydantic
70
+ models, Google-style docstrings, at most 500 lines per file. Tests in `tests/` cover happy path,
71
+ edge case and failure.
72
+ - **Coordination:** run `skcapstone coord briefing` at the start of a session; claim work with
73
+ `skcapstone coord claim <id> --agent <you>`. SK packages install into `~/.skenv/`.
74
+ - **Generated files:** none checked in; build artefacts come from `python -m build`.
75
+
76
+ ## Privacy
77
+
78
+ This repo is public. Never put host names, LAN or tailnet IPs, estate names, personal names or data,
79
+ real key fingerprints, private keys or credentials in code, docs, tests, fixtures or commits.
80
+ Enforced by `secret-scan.yml` (`scripts/gitleaks-scope.sh`) and, for
81
+ DID output, by the invariants in `did.py`; the rest is on review.
82
+
83
+ ## Hazards
84
+
85
+ - **Environment-gated tests:** `pytest.yml` ignores `tests/test_integration.py` and deselects a few
86
+ Sequoia and QR-login tests that need tools CI lacks. A green `pytest.yml` is not the full suite;
87
+ `ci.yml` is.
88
+ - **No `capauth did` CLI group:** the identity card is a library and MCP surface (see SOP section 7).
89
+ - **Stray tracked files:** `ruff-0.15.4-*.whl` and `urllib.error` at the repo root are accidental
90
+ commits, not inputs; do not depend on them or add more like them.
91
+
92
+ ## See also
93
+
94
+ - [skcapstone](https://github.com/smilinTux/skcapstone): agent framework, coordination board,
95
+ `skcapstone doctor`.
96
+ - [skcomms](https://github.com/smilinTux/skcomms) and [skchat](https://github.com/smilinTux/skchat):
97
+ consumers of the identity resolver.
98
+ - [sk-standards](https://github.com/smilinTux/sk-standards): `CRYPTOGRAPHY_STANDARD`,
99
+ `SK_REPO_DOC_STANDARD`, `AGENT_INSTRUCTIONS_STANDARD`.
@@ -6,6 +6,47 @@ All notable changes to `capauth` are documented here. The format is based on
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ - Agent instructions live in one file, `AGENTS.md`, reshaped to the sk-standards
10
+ AGENT_INSTRUCTIONS_STANDARD. `CLAUDE.md` and `.cursorrules` are removed (Claude Code reads
11
+ `AGENTS.md` natively and skips it when a `CLAUDE.md` sits next to it).
12
+
13
+ - OIDC login asks for the vault passphrase in a masked in-page dialog instead of
14
+ a browser `prompt()`, which showed the passphrase as it was typed.
15
+
16
+ - Service discovery no longer invents a nonexistent CapAuth PID file. Without
17
+ an explicit daemon-owned PID path, health remains unknown.
18
+
19
+ - Release tags (`v*`) now also publish the service image
20
+ `ghcr.io/smilintux/capauth:<version>` (`.github/workflows/image.yml`): the
21
+ tag must be on main, a published version is never overwritten, the image is
22
+ smoke-tested (`capauth --version`, `/capauth/v1/status`) before the push,
23
+ and the job summary records the digest to pin (`<version>@sha256:...`).
24
+
25
+ - `capauth sign-challenge`: reads the CapAuth login challenge from the
26
+ clipboard (or `--stdin`), refuses anything that is not a complete
27
+ `CAPAUTH_NONCE_V1`/`V2` challenge, signs it with gpg (gpg-agent's pinentry
28
+ asks for the passphrase; the tool never handles it) and puts the armored
29
+ signature back on the clipboard (or `--stdout`), printing only
30
+ `signed, paste it now`. Key: `--key`, `$CAPAUTH_SIGN_KEY`, or the profile.
31
+ The OIDC login page gains a "Paste signature and continue" button, names
32
+ the command in its steps and remembers the fingerprint of the last manual
33
+ login, so a repeat login is copy, sign, paste. Docs: `docs/SIGN_CHALLENGE.md`.
34
+
35
+ - Service image builds from a plain checkout again: the Dockerfile takes
36
+ `--build-arg CAPAUTH_VERSION=<version>` (default `0.0.0+docker`) for
37
+ setuptools-scm, because `.dockerignore` keeps `.git` out of the context.
38
+
39
+ - OIDC IdP: a static client may set `require_nonce: false` so stock
40
+ Authentik's OAuth source, which never sends an OIDC `nonce`, can use the
41
+ authorization code flow. State, PKCE S256 and the confidential client secret
42
+ stay mandatory; the default is unchanged (nonce required), and a nonce that
43
+ is sent must still be well formed.
44
+
45
+ - CI: green on main again. `ruff format` (pinned 0.15.4) applied to
46
+ `tests/test_backup_fallback.py`; the Python 3.10 job no longer installs
47
+ skcapstone (it requires 3.11+), and the skcapstone integration tests skip
48
+ there while 3.11+ asserts the import so they cannot skip silently.
49
+
9
50
  - Raise operator proof absolute and idle ceilings to 24 hours while keeping
10
51
  access capabilities bounded to five minutes (card `4af0ae7f`).
11
52
 
@@ -542,6 +583,7 @@ All notable changes to `capauth` are documented here. The format is based on
542
583
 
543
584
  ### Security
544
585
 
586
+ - Raised `python-multipart` to `>=0.0.31`, `PyJWT` to `>=2.15.0` and `zeroconf` to `>=0.149.16` to clear the 2026-11-13 dependency sweep findings.
545
587
  - **Revoked / expired signing-key rejection**: the `pgpy` and `gnupg` verify
546
588
  paths now reject a signing key that carries a revocation signature or is expired
547
589
  **before** the signature check (`KeyRevokedError` / `KeyExpiredError`), closing
@@ -16,6 +16,10 @@ COPY src/ ./src/
16
16
  # resolves these relative to the package root → /app/phone-signer.
17
17
  COPY phone-signer/ ./phone-signer/
18
18
 
19
+ # The build context has no .git (.dockerignore), so setuptools-scm cannot
20
+ # derive a version: pass one with --build-arg CAPAUTH_VERSION=<version>.
21
+ ARG CAPAUTH_VERSION=0.0.0+docker
22
+ ENV SETUPTOOLS_SCM_PRETEND_VERSION=${CAPAUTH_VERSION}
19
23
  RUN pip install --no-cache-dir -e ".[service]"
20
24
  RUN pip install --no-cache-dir python-multipart>=0.0.6
21
25
 
@@ -4,16 +4,26 @@
4
4
  #
5
5
  # Build:
6
6
  # docker build -f Dockerfile.authentik-capauth \
7
- # -t ghcr.io/smilintux/authentik-capauth:2026.5.3 \
8
- # -t ghcr.io/smilintux/authentik-capauth:latest .
7
+ # -t skgit.skstack01.douno.it/skadmin/authentik-capauth:2025.12.6 \
8
+ # -t skgit.skstack01.douno.it/skadmin/authentik-capauth:latest .
9
9
  #
10
10
  # Push:
11
- # docker push ghcr.io/smilintux/authentik-capauth:2026.5.3
12
- # docker push ghcr.io/smilintux/authentik-capauth:latest
11
+ # docker push skgit.skstack01.douno.it/skadmin/authentik-capauth:2025.12.6
12
+ # docker push skgit.skstack01.douno.it/skadmin/authentik-capauth:latest
13
13
  #
14
14
  # AK_VERSION tracks the latest STABLE Authentik release (override with --build-arg).
15
+ #
16
+ # 2026-10-23 (Chef decision, tactical patch): pinned to 2025.12.6, the latest
17
+ # 2025.12.x patch, same major line as nor prod's running 2025.12.3. This is the
18
+ # SAME-LINE security patch (fixes GHSA-xp7f-xjjx-gwm8 Critical SourceStage bypass
19
+ # and GHSA-c3m2-jqmq-pvp3 SAML XML signature wrapping), not the full 2026.8.5
20
+ # migration. The 2025.12.x line does not receive the later privilege-escalation
21
+ # (GHSA-h6c5-mpvq-j4jc) or SAML-DoS (GHSA-cxwx-9x59-28qm) backports -- those land
22
+ # only with the full upgrade (see docs/AUTHENTIK_STRATEGY_DECISION.md, option b,
23
+ # decision 2026-10-23: retire this fork for CAPAUTH_ENABLED on stock Authentik as
24
+ # part of that upgrade).
15
25
  # ──────────────────────────────────────────────────────────────────────
16
- ARG AK_VERSION=2026.5.3
26
+ ARG AK_VERSION=2025.12.6
17
27
 
18
28
  # ── Stage 1: Rebuild Authentik frontend with ak-stage-capauth ────────
19
29
  FROM node:24-bookworm AS web-builder
@@ -60,6 +70,13 @@ USER root
60
70
  # instead of hardcoding it — otherwise capauth lands on the wrong path and Django can't import
61
71
  # it (ModuleNotFoundError: capauth, live-proven on .13 against 2026.5.3).
62
72
  COPY . /app/capauth
73
+ # capauth's pyproject.toml uses setuptools_scm (dynamic version from git tags),
74
+ # but .dockerignore excludes .git from the build context, so `pip install
75
+ # /app/capauth` cannot infer a version and fails with "setuptools-scm was
76
+ # unable to detect version" (hit rebuilding this image 2026-10-23, unrelated
77
+ # to the AK_VERSION bump -- would fail the same way at any Authentik version
78
+ # until this is set). Pin it explicitly to the latest released tag.
79
+ ENV SETUPTOOLS_SCM_PRETEND_VERSION_FOR_CAPAUTH=0.3.13
63
80
  RUN VENV_SP="$(ls -d /ak-root/.venv/lib/python3.*/site-packages | head -1)" && \
64
81
  echo "Installing capauth into $VENV_SP" && \
65
82
  pip install --no-cache-dir --no-deps --target "$VENV_SP" /app/capauth && \
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: capauth
3
- Version: 0.3.12
3
+ Version: 0.3.14
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
@@ -37,8 +37,8 @@ Requires-Dist: python-gnupg>=0.5; extra == "gnupg"
37
37
  Provides-Extra: service
38
38
  Requires-Dist: fastapi>=0.110; extra == "service"
39
39
  Requires-Dist: uvicorn[standard]>=0.27; extra == "service"
40
- Requires-Dist: python-multipart>=0.0.6; extra == "service"
41
- Requires-Dist: PyJWT>=2.8; extra == "service"
40
+ Requires-Dist: python-multipart>=0.0.31; extra == "service"
41
+ Requires-Dist: PyJWT>=2.15.0; extra == "service"
42
42
  Requires-Dist: python-gnupg>=0.5; extra == "service"
43
43
  Requires-Dist: httpx>=0.25; extra == "service"
44
44
  Requires-Dist: segno>=1.6; extra == "service"
@@ -53,7 +53,7 @@ Requires-Dist: fastapi>=0.110; extra == "dev"
53
53
  Requires-Dist: python-gnupg>=0.5; extra == "dev"
54
54
  Requires-Dist: black>=24.0; extra == "dev"
55
55
  Requires-Dist: ruff>=0.3; extra == "dev"
56
- Requires-Dist: zeroconf>=0.38; extra == "dev"
56
+ Requires-Dist: zeroconf>=0.149.16; extra == "dev"
57
57
  Requires-Dist: webauthn>=2.0; extra == "dev"
58
58
  Requires-Dist: soft-webauthn>=0.1; extra == "dev"
59
59
  Requires-Dist: pywebpush>=1.14; extra == "dev"
@@ -254,6 +254,7 @@ capauth pqc-report # live PQC posture per surface
254
254
 
255
255
  # Auth & integration
256
256
  capauth login <service_url> [--no-claims] # passwordless PGP login (caches OIDC token)
257
+ capauth sign-challenge # sign the copied browser login challenge, paste the result
257
258
  capauth setup forgejo --capauth-url <url> # generate Forgejo OIDC app.ini block
258
259
 
259
260
  # Mesh & membership
@@ -294,6 +295,7 @@ rides in the payload `event` field so routing stays severity-based.
294
295
  | **[Integration Blueprint](docs/INTEGRATION_BLUEPRINT.md)** | third-party integration guide |
295
296
  | **[Cold-Machine Bootstrap & DR](docs/COLD_MACHINE_BOOTSTRAP_AND_DR.md)** | standing capauth back up on a blank box + disaster recovery: the restore-not-regenerate rule, the ordered restore chain, and the operator checklist |
296
297
  | **[authentik-capauth](docs/authentik-capauth.md)** | the custom Authentik image with the CapAuth PGP stage baked in — build (`AK_VERSION`, version-agnostic venv install, frontend rebuild), SKStacks deploy + `lifecycle.migrate` override, and the four build/migrate gotchas |
298
+ | **[Sign a login: copy, sign, paste](docs/SIGN_CHALLENGE.md)** | `capauth sign-challenge`: the four-step browser login with your gpg key, one-time setup, desktop shortcut |
297
299
  | **[AI Advocate](AI-ADVOCATE.md)** | how AI advocates manage a sovereign profile on your behalf |
298
300
 
299
301
  ## Why it matters
@@ -191,6 +191,7 @@ capauth pqc-report # live PQC posture per surface
191
191
 
192
192
  # Auth & integration
193
193
  capauth login <service_url> [--no-claims] # passwordless PGP login (caches OIDC token)
194
+ capauth sign-challenge # sign the copied browser login challenge, paste the result
194
195
  capauth setup forgejo --capauth-url <url> # generate Forgejo OIDC app.ini block
195
196
 
196
197
  # Mesh & membership
@@ -231,6 +232,7 @@ rides in the payload `event` field so routing stays severity-based.
231
232
  | **[Integration Blueprint](docs/INTEGRATION_BLUEPRINT.md)** | third-party integration guide |
232
233
  | **[Cold-Machine Bootstrap & DR](docs/COLD_MACHINE_BOOTSTRAP_AND_DR.md)** | standing capauth back up on a blank box + disaster recovery: the restore-not-regenerate rule, the ordered restore chain, and the operator checklist |
233
234
  | **[authentik-capauth](docs/authentik-capauth.md)** | the custom Authentik image with the CapAuth PGP stage baked in — build (`AK_VERSION`, version-agnostic venv install, frontend rebuild), SKStacks deploy + `lifecycle.migrate` override, and the four build/migrate gotchas |
235
+ | **[Sign a login: copy, sign, paste](docs/SIGN_CHALLENGE.md)** | `capauth sign-challenge`: the four-step browser login with your gpg key, one-time setup, desktop shortcut |
234
236
  | **[AI Advocate](AI-ADVOCATE.md)** | how AI advocates manage a sovereign profile on your behalf |
235
237
 
236
238
  ## Why it matters