capauth 0.3.2__tar.gz → 0.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (370) hide show
  1. {capauth-0.3.2 → capauth-0.3.4}/CHANGELOG.md +17 -0
  2. {capauth-0.3.2 → capauth-0.3.4}/PKG-INFO +3 -1
  3. {capauth-0.3.2 → capauth-0.3.4}/README.md +2 -0
  4. {capauth-0.3.2 → capauth-0.3.4}/SOP.md +25 -1
  5. capauth-0.3.4/docs/HUMAN_IDENTITY_SETUP_AND_ROTATION.md +149 -0
  6. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/agent_identity.py +4 -4
  7. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/pairing/proof.py +36 -6
  8. {capauth-0.3.2 → capauth-0.3.4}/src/capauth.egg-info/PKG-INFO +3 -1
  9. {capauth-0.3.2 → capauth-0.3.4}/src/capauth.egg-info/SOURCES.txt +1 -0
  10. {capauth-0.3.2 → capauth-0.3.4}/tests/test_enrollment_proof_helper.py +86 -4
  11. {capauth-0.3.2 → capauth-0.3.4}/.cursorrules +0 -0
  12. {capauth-0.3.2 → capauth-0.3.4}/.dockerignore +0 -0
  13. {capauth-0.3.2 → capauth-0.3.4}/.github/workflows/ci.yml +0 -0
  14. {capauth-0.3.2 → capauth-0.3.4}/.github/workflows/docs-check.yml +0 -0
  15. {capauth-0.3.2 → capauth-0.3.4}/.github/workflows/nextcloud-appstore.yml +0 -0
  16. {capauth-0.3.2 → capauth-0.3.4}/.github/workflows/publish.yml +0 -0
  17. {capauth-0.3.2 → capauth-0.3.4}/.github/workflows/pytest.yml +0 -0
  18. {capauth-0.3.2 → capauth-0.3.4}/.github/workflows/secret-scan.yml +0 -0
  19. {capauth-0.3.2 → capauth-0.3.4}/.gitignore +0 -0
  20. {capauth-0.3.2 → capauth-0.3.4}/.gitleaks-baseline.json +0 -0
  21. {capauth-0.3.2 → capauth-0.3.4}/AGENTS.md +0 -0
  22. {capauth-0.3.2 → capauth-0.3.4}/AI-ADVOCATE.md +0 -0
  23. {capauth-0.3.2 → capauth-0.3.4}/ARCHITECTURE.md +0 -0
  24. {capauth-0.3.2 → capauth-0.3.4}/CLAUDE.md +0 -0
  25. {capauth-0.3.2 → capauth-0.3.4}/CODE_OF_CONDUCT.md +0 -0
  26. {capauth-0.3.2 → capauth-0.3.4}/CONTRIBUTING.md +0 -0
  27. {capauth-0.3.2 → capauth-0.3.4}/Dockerfile +0 -0
  28. {capauth-0.3.2 → capauth-0.3.4}/Dockerfile.authentik-capauth +0 -0
  29. {capauth-0.3.2 → capauth-0.3.4}/LICENSE +0 -0
  30. {capauth-0.3.2 → capauth-0.3.4}/MANIFEST.in +0 -0
  31. {capauth-0.3.2 → capauth-0.3.4}/MISSION.md +0 -0
  32. {capauth-0.3.2 → capauth-0.3.4}/SECURITY.md +0 -0
  33. {capauth-0.3.2 → capauth-0.3.4}/SKILL.md +0 -0
  34. {capauth-0.3.2 → capauth-0.3.4}/authentik-custom/capauth_migrate.py +0 -0
  35. {capauth-0.3.2 → capauth-0.3.4}/authentik-custom/imghdr.py +0 -0
  36. {capauth-0.3.2 → capauth-0.3.4}/authentik-custom/user_settings.py +0 -0
  37. {capauth-0.3.2 → capauth-0.3.4}/bin/cli.js +0 -0
  38. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/.gitignore +0 -0
  39. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/README.md +0 -0
  40. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/RELEASING.md +0 -0
  41. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/background.js +0 -0
  42. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/content_scripts/autofill.js +0 -0
  43. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/content_scripts/cross_origin_signing.js +0 -0
  44. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/content_scripts/detector.js +0 -0
  45. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/content_scripts/provider.js +0 -0
  46. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/content_scripts/provider_bridge.js +0 -0
  47. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/icons/icon.svg +0 -0
  48. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/icons/icon128.png +0 -0
  49. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/icons/icon16.png +0 -0
  50. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/icons/icon48.png +0 -0
  51. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/lib/bunker-e2e.js +0 -0
  52. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/lib/keyqr.js +0 -0
  53. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/lib/keyvault.js +0 -0
  54. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/lib/openpgp.js +0 -0
  55. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/lib/signer-backends.js +0 -0
  56. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/manifest.firefox.json +0 -0
  57. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/manifest.json +0 -0
  58. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/native-host/capauth_signer.py +0 -0
  59. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/native-host/com.capauth.signer.json +0 -0
  60. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/native-host/install.sh +0 -0
  61. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/options/options.html +0 -0
  62. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/options/options.js +0 -0
  63. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/package-lock.json +0 -0
  64. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/package.json +0 -0
  65. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/popup/popup.css +0 -0
  66. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/popup/popup.html +0 -0
  67. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/popup/popup.js +0 -0
  68. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/scripts/build.js +0 -0
  69. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/scripts/generate-icons.js +0 -0
  70. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/stages/AuthenticatorSelectionStage.js +0 -0
  71. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/stages/CapAuthStage.js +0 -0
  72. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/stages/QRDisplayStage.js +0 -0
  73. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/stages/SignatureVerificationStage.js +0 -0
  74. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/stages/StagePipeline.js +0 -0
  75. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/submission/STORE_LISTING.md +0 -0
  76. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/submission/privacy-policy.md +0 -0
  77. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/tests/fixtures/test_key.json +0 -0
  78. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/tests/unit/background.test.js +0 -0
  79. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/tests/unit/bunker_e2e.test.js +0 -0
  80. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/tests/unit/detector.test.js +0 -0
  81. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/tests/unit/keyqr.test.js +0 -0
  82. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/tests/unit/keyvault.test.js +0 -0
  83. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/tests/unit/openpgp.test.js +0 -0
  84. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/tests/unit/provider_api.test.js +0 -0
  85. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/tests/unit/provider_tierb.test.js +0 -0
  86. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/tests/unit/remote_bunker.test.js +0 -0
  87. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/tests/unit/signer_backends.test.js +0 -0
  88. {capauth-0.3.2 → capauth-0.3.4}/browser-extension/vitest.config.js +0 -0
  89. {capauth-0.3.2 → capauth-0.3.4}/deploy/capauth-service/.env.example +0 -0
  90. {capauth-0.3.2 → capauth-0.3.4}/deploy/capauth-service/deploy.sh +0 -0
  91. {capauth-0.3.2 → capauth-0.3.4}/deploy/capauth-service/docker-compose.yml +0 -0
  92. {capauth-0.3.2 → capauth-0.3.4}/deploy/capauth-service/systemd/capauth-backup.service +0 -0
  93. {capauth-0.3.2 → capauth-0.3.4}/deploy/capauth-service/systemd/capauth-backup.timer +0 -0
  94. {capauth-0.3.2 → capauth-0.3.4}/deploy/forgejo-capauth/.env.example +0 -0
  95. {capauth-0.3.2 → capauth-0.3.4}/deploy/forgejo-capauth/docker-compose.yml +0 -0
  96. {capauth-0.3.2 → capauth-0.3.4}/deploy/forgejo-capauth/preflight.sh +0 -0
  97. {capauth-0.3.2 → capauth-0.3.4}/docs/AIRGAPPED_SIGNING_WORKSTATION.md +0 -0
  98. {capauth-0.3.2 → capauth-0.3.4}/docs/ARCHITECTURE.md +0 -0
  99. {capauth-0.3.2 → capauth-0.3.4}/docs/AUTHENTIK_CUSTOM_STAGE.md +0 -0
  100. {capauth-0.3.2 → capauth-0.3.4}/docs/AUTHENTIK_DEPLOYMENT_SKSSO.md +0 -0
  101. {capauth-0.3.2 → capauth-0.3.4}/docs/AUTHENTIK_FORGEJO_DEPLOYMENT.md +0 -0
  102. {capauth-0.3.2 → capauth-0.3.4}/docs/AUTHENTIK_STRATEGY_DECISION.md +0 -0
  103. {capauth-0.3.2 → capauth-0.3.4}/docs/CAPAUTH_BUNKER_REMOTE_SIGNER.md +0 -0
  104. {capauth-0.3.2 → capauth-0.3.4}/docs/CAPAUTH_OIDC_IDP.md +0 -0
  105. {capauth-0.3.2 → capauth-0.3.4}/docs/CLAIMS.md +0 -0
  106. {capauth-0.3.2 → capauth-0.3.4}/docs/COLD_MACHINE_BOOTSTRAP_AND_DR.md +0 -0
  107. {capauth-0.3.2 → capauth-0.3.4}/docs/CRYPTO_SPEC.md +0 -0
  108. {capauth-0.3.2 → capauth-0.3.4}/docs/ENTERPRISE_MANAGED_KEYS.md +0 -0
  109. {capauth-0.3.2 → capauth-0.3.4}/docs/INTEGRATION_BLUEPRINT.md +0 -0
  110. {capauth-0.3.2 → capauth-0.3.4}/docs/M0-capauth-api-v1.md +0 -0
  111. {capauth-0.3.2 → capauth-0.3.4}/docs/M0-capauth-importer-inventory.md +0 -0
  112. {capauth-0.3.2 → capauth-0.3.4}/docs/PQC_CAPAUTH_REVISIT.md +0 -0
  113. {capauth-0.3.2 → capauth-0.3.4}/docs/PQC_ROOT_MIGRATION.md +0 -0
  114. {capauth-0.3.2 → capauth-0.3.4}/docs/PROTOCOL.md +0 -0
  115. {capauth-0.3.2 → capauth-0.3.4}/docs/ROOT_ROTATION_CEREMONY.md +0 -0
  116. {capauth-0.3.2 → capauth-0.3.4}/docs/TRUST_GRAPH_COORD_PROJECTION.md +0 -0
  117. {capauth-0.3.2 → capauth-0.3.4}/docs/ZERO_KNOWLEDGE_PROFILE.md +0 -0
  118. {capauth-0.3.2 → capauth-0.3.4}/docs/authentik-capauth.md +0 -0
  119. {capauth-0.3.2 → capauth-0.3.4}/docs/deploy-plan/capauth-bulletproof-deploy.md +0 -0
  120. {capauth-0.3.2 → capauth-0.3.4}/index.d.ts +0 -0
  121. {capauth-0.3.2 → capauth-0.3.4}/index.js +0 -0
  122. {capauth-0.3.2 → capauth-0.3.4}/openclaw-plugin.archived-2026-04-23/package.json +0 -0
  123. {capauth-0.3.2 → capauth-0.3.4}/openclaw-plugin.archived-2026-04-23/src/index.ts +0 -0
  124. {capauth-0.3.2 → capauth-0.3.4}/openclaw-plugin.archived-2026-04-23/src/openclaw.plugin.json +0 -0
  125. {capauth-0.3.2 → capauth-0.3.4}/package.json +0 -0
  126. {capauth-0.3.2 → capauth-0.3.4}/phone-signer/app.js +0 -0
  127. {capauth-0.3.2 → capauth-0.3.4}/phone-signer/icons/icon-192.png +0 -0
  128. {capauth-0.3.2 → capauth-0.3.4}/phone-signer/icons/icon-512.png +0 -0
  129. {capauth-0.3.2 → capauth-0.3.4}/phone-signer/index.html +0 -0
  130. {capauth-0.3.2 → capauth-0.3.4}/phone-signer/lib/bunker-e2e.js +0 -0
  131. {capauth-0.3.2 → capauth-0.3.4}/phone-signer/lib/bunker-signer.js +0 -0
  132. {capauth-0.3.2 → capauth-0.3.4}/phone-signer/lib/canonical.js +0 -0
  133. {capauth-0.3.2 → capauth-0.3.4}/phone-signer/lib/keyqr.js +0 -0
  134. {capauth-0.3.2 → capauth-0.3.4}/phone-signer/lib/keyvault.js +0 -0
  135. {capauth-0.3.2 → capauth-0.3.4}/phone-signer/manifest.webmanifest +0 -0
  136. {capauth-0.3.2 → capauth-0.3.4}/phone-signer/sw.js +0 -0
  137. {capauth-0.3.2 → capauth-0.3.4}/phone-signer/vendor/openpgp.min.js +0 -0
  138. {capauth-0.3.2 → capauth-0.3.4}/phone-signer/vendor/qrcode-generator.js +0 -0
  139. {capauth-0.3.2 → capauth-0.3.4}/pyproject.toml +0 -0
  140. {capauth-0.3.2 → capauth-0.3.4}/ruff-0.15.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
  141. {capauth-0.3.2 → capauth-0.3.4}/scripts/build_authentik_capauth_image.sh +0 -0
  142. {capauth-0.3.2 → capauth-0.3.4}/scripts/capauth-backup.sh +0 -0
  143. {capauth-0.3.2 → capauth-0.3.4}/scripts/capauth-restore.sh +0 -0
  144. {capauth-0.3.2 → capauth-0.3.4}/scripts/migrate_canonical_subjects.py +0 -0
  145. {capauth-0.3.2 → capauth-0.3.4}/scripts/pqc_ceremony_dryrun.py +0 -0
  146. {capauth-0.3.2 → capauth-0.3.4}/scripts/provision_agent_profiles.py +0 -0
  147. {capauth-0.3.2 → capauth-0.3.4}/setup.cfg +0 -0
  148. {capauth-0.3.2 → capauth-0.3.4}/skill.yaml +0 -0
  149. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/__init__.py +0 -0
  150. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/apps.py +0 -0
  151. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/authentik/__init__.py +0 -0
  152. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/authentik/api.py +0 -0
  153. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/authentik/blueprints/capauth-pgp-login.yaml +0 -0
  154. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/authentik/claims_mapper.py +0 -0
  155. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/authentik/nonce_store.py +0 -0
  156. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/authentik/stage.py +0 -0
  157. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/authentik/urls.py +0 -0
  158. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/authentik/verifier.py +0 -0
  159. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/authz.py +0 -0
  160. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/cli.py +0 -0
  161. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/crypto/__init__.py +0 -0
  162. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/crypto/base.py +0 -0
  163. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/crypto/gnupg_backend.py +0 -0
  164. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/crypto/pgpy_backend.py +0 -0
  165. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/crypto/sequoia_backend.py +0 -0
  166. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/crypto/skpgp_backend.py +0 -0
  167. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/custody.py +0 -0
  168. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/did.py +0 -0
  169. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/discovery/__init__.py +0 -0
  170. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/discovery/base.py +0 -0
  171. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/discovery/file_discovery.py +0 -0
  172. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/discovery/mdns.py +0 -0
  173. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/discovery/syncthing.py +0 -0
  174. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/exceptions.py +0 -0
  175. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/identity.py +0 -0
  176. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/identity_class.py +0 -0
  177. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integration.py +0 -0
  178. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/__init__.py +0 -0
  179. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/forgejo/__init__.py +0 -0
  180. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/forgejo/auth_flow.py +0 -0
  181. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/forgejo/cli.py +0 -0
  182. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/forgejo/config.py +0 -0
  183. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/forgejo/forgejo_api.py +0 -0
  184. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/forgejo/oidc_provider.py +0 -0
  185. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/forgejo/tests/__init__.py +0 -0
  186. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/forgejo/tests/test_auth_flow.py +0 -0
  187. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/forgejo/tests/test_cli.py +0 -0
  188. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/forgejo/tests/test_config.py +0 -0
  189. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/forgejo/tests/test_forgejo_api.py +0 -0
  190. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/forgejo/tests/test_oidc_provider.py +0 -0
  191. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/.gitignore +0 -0
  192. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/.nextcloudignore +0 -0
  193. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/CSR-PR.md +0 -0
  194. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/INFO-XML-CHANGES.md +0 -0
  195. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/PUBLISHING.md +0 -0
  196. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/README.md +0 -0
  197. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/appinfo/info.xml +0 -0
  198. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/appinfo/routes.php +0 -0
  199. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/build-release.sh +0 -0
  200. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/certificates/.gitignore +0 -0
  201. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/certificates/capauth.crt +0 -0
  202. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/certificates/capauth.csr +0 -0
  203. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/composer.json +0 -0
  204. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/css/login.css +0 -0
  205. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/js/login.js +0 -0
  206. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/krankerl.toml +0 -0
  207. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/AlternativeLogin/CapAuthLogin.php +0 -0
  208. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/AppInfo/Application.php +0 -0
  209. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/BackgroundJob/PruneExpiredNonces.php +0 -0
  210. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/Controller/LoginController.php +0 -0
  211. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/Controller/TokenController.php +0 -0
  212. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/Db/KeyRegistry.php +0 -0
  213. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/Exception/CapAuthUnauthorizedException.php +0 -0
  214. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/Middleware/PgpVerificationMiddleware.php +0 -0
  215. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/Migration/Version000300Date20260301000000.php +0 -0
  216. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/Provider/CapAuthProvider.php +0 -0
  217. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/Service/ChallengeService.php +0 -0
  218. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/Service/GroupSyncService.php +0 -0
  219. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/Service/UserProvisioningService.php +0 -0
  220. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/Service/VerifierService.php +0 -0
  221. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/lib/User/Backend.php +0 -0
  222. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/phpunit.xml +0 -0
  223. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/screenshots/README.md +0 -0
  224. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/screenshots/login.png +0 -0
  225. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/templates/login.php +0 -0
  226. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/tests/bootstrap.php +0 -0
  227. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/tests/integration/FullAuthFlowTest.php +0 -0
  228. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/tests/oidc/oidc_e2e_login_test.py +0 -0
  229. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/tests/unit/Controller/LoginControllerTest.php +0 -0
  230. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/tests/unit/Db/KeyRegistryTest.php +0 -0
  231. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/tests/unit/Provider/CapAuthProviderTest.php +0 -0
  232. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/tests/unit/Service/ChallengeServiceTest.php +0 -0
  233. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/tests/unit/Service/VerifierServiceTest.php +0 -0
  234. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/integrations/nextcloud/tests/unit/User/BackendTest.php +0 -0
  235. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/key_transparency.py +0 -0
  236. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/login.py +0 -0
  237. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/manifest.py +0 -0
  238. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/mesh.py +0 -0
  239. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/migrations/0001_initial.py +0 -0
  240. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/migrations/0002_widen_fingerprint_to_64.py +0 -0
  241. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/migrations/__init__.py +0 -0
  242. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/models.py +0 -0
  243. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/pairing/__init__.py +0 -0
  244. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/pairing/canonicalize.py +0 -0
  245. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/pairing/kernel.py +0 -0
  246. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/pairing/operator_session.py +0 -0
  247. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/pairing/records.py +0 -0
  248. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/pairing/store.py +0 -0
  249. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/pairing/window.py +0 -0
  250. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/pma.py +0 -0
  251. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/pqc_confidentiality.py +0 -0
  252. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/pqc_identity.py +0 -0
  253. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/pqc_root_identity.py +0 -0
  254. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/pqc_tokens.py +0 -0
  255. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/profile.py +0 -0
  256. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/provisioning.py +0 -0
  257. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/registry.py +0 -0
  258. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/seal.py +0 -0
  259. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/__init__.py +0 -0
  260. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/app.py +0 -0
  261. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/bunker.py +0 -0
  262. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/bunker_e2e.py +0 -0
  263. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/keystore.py +0 -0
  264. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/oidc/__init__.py +0 -0
  265. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/oidc/clients.example.json +0 -0
  266. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/oidc/clients.py +0 -0
  267. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/oidc/passkey.py +0 -0
  268. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/oidc/provider.py +0 -0
  269. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/oidc/signing_key.py +0 -0
  270. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/oidc/store.py +0 -0
  271. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/push.py +0 -0
  272. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/service/server.py +0 -0
  273. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/subject.py +0 -0
  274. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/sync.py +0 -0
  275. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/testing.py +0 -0
  276. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/tokens.py +0 -0
  277. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/trust/__init__.py +0 -0
  278. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/trust/calibration.py +0 -0
  279. {capauth-0.3.2 → capauth-0.3.4}/src/capauth/trust/graph.py +0 -0
  280. {capauth-0.3.2 → capauth-0.3.4}/src/capauth.egg-info/dependency_links.txt +0 -0
  281. {capauth-0.3.2 → capauth-0.3.4}/src/capauth.egg-info/entry_points.txt +0 -0
  282. {capauth-0.3.2 → capauth-0.3.4}/src/capauth.egg-info/requires.txt +0 -0
  283. {capauth-0.3.2 → capauth-0.3.4}/src/capauth.egg-info/top_level.txt +0 -0
  284. {capauth-0.3.2 → capauth-0.3.4}/stages/ak-stage-capauth/.gitignore +0 -0
  285. {capauth-0.3.2 → capauth-0.3.4}/stages/ak-stage-capauth/package-lock.json +0 -0
  286. {capauth-0.3.2 → capauth-0.3.4}/stages/ak-stage-capauth/package.json +0 -0
  287. {capauth-0.3.2 → capauth-0.3.4}/stages/ak-stage-capauth/src/CapAuthStage.test.js +0 -0
  288. {capauth-0.3.2 → capauth-0.3.4}/stages/ak-stage-capauth/src/CapAuthStage.vue +0 -0
  289. {capauth-0.3.2 → capauth-0.3.4}/stages/ak-stage-capauth/src/index.js +0 -0
  290. {capauth-0.3.2 → capauth-0.3.4}/stages/ak-stage-capauth/vite.config.js +0 -0
  291. {capauth-0.3.2 → capauth-0.3.4}/tests/__init__.py +0 -0
  292. {capauth-0.3.2 → capauth-0.3.4}/tests/conftest.py +0 -0
  293. {capauth-0.3.2 → capauth-0.3.4}/tests/fixtures/bunker_e2e_v1_vector.json +0 -0
  294. {capauth-0.3.2 → capauth-0.3.4}/tests/fixtures/canonical_nonce_v2_vector.json +0 -0
  295. {capauth-0.3.2 → capauth-0.3.4}/tests/test_agent_identity.py +0 -0
  296. {capauth-0.3.2 → capauth-0.3.4}/tests/test_agentrun_capabilities.py +0 -0
  297. {capauth-0.3.2 → capauth-0.3.4}/tests/test_audience_mint_helper.py +0 -0
  298. {capauth-0.3.2 → capauth-0.3.4}/tests/test_audience_tokens.py +0 -0
  299. {capauth-0.3.2 → capauth-0.3.4}/tests/test_authz.py +0 -0
  300. {capauth-0.3.2 → capauth-0.3.4}/tests/test_authz_legacy_grace.py +0 -0
  301. {capauth-0.3.2 → capauth-0.3.4}/tests/test_authz_signature_gate.py +0 -0
  302. {capauth-0.3.2 → capauth-0.3.4}/tests/test_backup_restore.py +0 -0
  303. {capauth-0.3.2 → capauth-0.3.4}/tests/test_bunker.py +0 -0
  304. {capauth-0.3.2 → capauth-0.3.4}/tests/test_bunker_e2e.py +0 -0
  305. {capauth-0.3.2 → capauth-0.3.4}/tests/test_canonicalize.py +0 -0
  306. {capauth-0.3.2 → capauth-0.3.4}/tests/test_capauth_service_deploy.py +0 -0
  307. {capauth-0.3.2 → capauth-0.3.4}/tests/test_change_capabilities.py +0 -0
  308. {capauth-0.3.2 → capauth-0.3.4}/tests/test_claims_mapper.py +0 -0
  309. {capauth-0.3.2 → capauth-0.3.4}/tests/test_crypto.py +0 -0
  310. {capauth-0.3.2 → capauth-0.3.4}/tests/test_custody.py +0 -0
  311. {capauth-0.3.2 → capauth-0.3.4}/tests/test_device_key_proof.py +0 -0
  312. {capauth-0.3.2 → capauth-0.3.4}/tests/test_did_capability_relationships.py +0 -0
  313. {capauth-0.3.2 → capauth-0.3.4}/tests/test_fingerprint_v6.py +0 -0
  314. {capauth-0.3.2 → capauth-0.3.4}/tests/test_forgejo_preflight.py +0 -0
  315. {capauth-0.3.2 → capauth-0.3.4}/tests/test_home_resolution.py +0 -0
  316. {capauth-0.3.2 → capauth-0.3.4}/tests/test_identity.py +0 -0
  317. {capauth-0.3.2 → capauth-0.3.4}/tests/test_identity_class.py +0 -0
  318. {capauth-0.3.2 → capauth-0.3.4}/tests/test_identity_ttl.py +0 -0
  319. {capauth-0.3.2 → capauth-0.3.4}/tests/test_integration.py +0 -0
  320. {capauth-0.3.2 → capauth-0.3.4}/tests/test_key_revocation_expiry.py +0 -0
  321. {capauth-0.3.2 → capauth-0.3.4}/tests/test_key_transparency.py +0 -0
  322. {capauth-0.3.2 → capauth-0.3.4}/tests/test_login.py +0 -0
  323. {capauth-0.3.2 → capauth-0.3.4}/tests/test_manifest.py +0 -0
  324. {capauth-0.3.2 → capauth-0.3.4}/tests/test_mesh.py +0 -0
  325. {capauth-0.3.2 → capauth-0.3.4}/tests/test_models_pqc_q0.py +0 -0
  326. {capauth-0.3.2 → capauth-0.3.4}/tests/test_nextcloud_app.py +0 -0
  327. {capauth-0.3.2 → capauth-0.3.4}/tests/test_no_subapp_dependency.py +0 -0
  328. {capauth-0.3.2 → capauth-0.3.4}/tests/test_nonce_store.py +0 -0
  329. {capauth-0.3.2 → capauth-0.3.4}/tests/test_oidc_idp.py +0 -0
  330. {capauth-0.3.2 → capauth-0.3.4}/tests/test_oidc_idp_e2e.py +0 -0
  331. {capauth-0.3.2 → capauth-0.3.4}/tests/test_operator_session.py +0 -0
  332. {capauth-0.3.2 → capauth-0.3.4}/tests/test_pairing.py +0 -0
  333. {capauth-0.3.2 → capauth-0.3.4}/tests/test_pairing_base_dir_env.py +0 -0
  334. {capauth-0.3.2 → capauth-0.3.4}/tests/test_passkey.py +0 -0
  335. {capauth-0.3.2 → capauth-0.3.4}/tests/test_pma.py +0 -0
  336. {capauth-0.3.2 → capauth-0.3.4}/tests/test_pqc_confidentiality.py +0 -0
  337. {capauth-0.3.2 → capauth-0.3.4}/tests/test_pqc_identity.py +0 -0
  338. {capauth-0.3.2 → capauth-0.3.4}/tests/test_pqc_root_integration.py +0 -0
  339. {capauth-0.3.2 → capauth-0.3.4}/tests/test_pqc_t3_gate.py +0 -0
  340. {capauth-0.3.2 → capauth-0.3.4}/tests/test_pqc_tokens.py +0 -0
  341. {capauth-0.3.2 → capauth-0.3.4}/tests/test_profile.py +0 -0
  342. {capauth-0.3.2 → capauth-0.3.4}/tests/test_provisioning.py +0 -0
  343. {capauth-0.3.2 → capauth-0.3.4}/tests/test_push.py +0 -0
  344. {capauth-0.3.2 → capauth-0.3.4}/tests/test_py313_compat.py +0 -0
  345. {capauth-0.3.2 → capauth-0.3.4}/tests/test_qr_login.py +0 -0
  346. {capauth-0.3.2 → capauth-0.3.4}/tests/test_real_pgp_e2e.py +0 -0
  347. {capauth-0.3.2 → capauth-0.3.4}/tests/test_register_cli.py +0 -0
  348. {capauth-0.3.2 → capauth-0.3.4}/tests/test_registry.py +0 -0
  349. {capauth-0.3.2 → capauth-0.3.4}/tests/test_seal.py +0 -0
  350. {capauth-0.3.2 → capauth-0.3.4}/tests/test_sequoia_backend.py +0 -0
  351. {capauth-0.3.2 → capauth-0.3.4}/tests/test_service.py +0 -0
  352. {capauth-0.3.2 → capauth-0.3.4}/tests/test_service_authz_decide.py +0 -0
  353. {capauth-0.3.2 → capauth-0.3.4}/tests/test_service_v6_fingerprint.py +0 -0
  354. {capauth-0.3.2 → capauth-0.3.4}/tests/test_skpgp_backend.py +0 -0
  355. {capauth-0.3.2 → capauth-0.3.4}/tests/test_subject.py +0 -0
  356. {capauth-0.3.2 → capauth-0.3.4}/tests/test_syncthing_discovery.py +0 -0
  357. {capauth-0.3.2 → capauth-0.3.4}/tests/test_testing_helper.py +0 -0
  358. {capauth-0.3.2 → capauth-0.3.4}/tests/test_token_gc.py +0 -0
  359. {capauth-0.3.2 → capauth-0.3.4}/tests/test_token_store_flag.py +0 -0
  360. {capauth-0.3.2 → capauth-0.3.4}/tests/test_tokens.py +0 -0
  361. {capauth-0.3.2 → capauth-0.3.4}/tests/test_trust_calibration.py +0 -0
  362. {capauth-0.3.2 → capauth-0.3.4}/tests/test_trust_graph.py +0 -0
  363. {capauth-0.3.2 → capauth-0.3.4}/tests/test_trust_graph_coord_audit.py +0 -0
  364. {capauth-0.3.2 → capauth-0.3.4}/tests/test_verifier.py +0 -0
  365. {capauth-0.3.2 → capauth-0.3.4}/tests/test_version_honesty.py +0 -0
  366. {capauth-0.3.2 → capauth-0.3.4}/tests/test_zk_profile.py +0 -0
  367. {capauth-0.3.2 → capauth-0.3.4}/tools/build-sq.sh +0 -0
  368. {capauth-0.3.2 → capauth-0.3.4}/urllib.error +0 -0
  369. {capauth-0.3.2 → capauth-0.3.4}/web/README.md +0 -0
  370. {capauth-0.3.2 → capauth-0.3.4}/web/stages/capauth/CapAuthStage.ts +0 -0
@@ -6,6 +6,23 @@ All notable changes to `capauth` are documented here. The format is based on
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ### Documentation
10
+
11
+ - Added the SK-standards-aligned human identity setup and rotation runbook,
12
+ covering human-only key handling, revocation certificates, protected backup
13
+ transfer, additive trust migration, signed CAB approval, verification,
14
+ rollback, evidence, and recurring custody management.
15
+
16
+ ### Fixed
17
+
18
+ - **Identity docstrings taught the wrong fqid shape.** `agent_identity.py`
19
+ showed `lumina@chef.skworld` in its prose, its worked example and its
20
+ doctest: the missing-TLD form that the N5 store migration exists to correct.
21
+ Verified against the live resolver, which returns `lumina@chef.skworld.io`.
22
+ A wrong example in the module that defines identity is what the next reader
23
+ or agent copies. `subject.py` deliberately keeps its legacy examples, since
24
+ they document the shapes the alias table normalizes.
25
+
9
26
  ### Added
10
27
 
11
28
  - **`capauth.pairing.proof`: a supported way to BUILD the enrollment proof card
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: capauth
3
- Version: 0.3.2
3
+ Version: 0.3.4
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
@@ -317,6 +317,8 @@ capauth is the identity root of SKWorld — most of the stack links back here.
317
317
  — produces the runtime crypto self-report that makes capauth's claims evidence-backed.
318
318
  - 📐 **Standards:** [sk-standards](https://github.com/smilinTux/sk-standards) — the
319
319
  crypto, data-flow, version, and doc/SOP standards (incl. `CRYPTOGRAPHY_STANDARD`).
320
+ - 🔐 **Human key operations:**
321
+ [setup, recovery, rotation, approval, and rollback](docs/HUMAN_IDENTITY_SETUP_AND_ROTATION.md).
320
322
 
321
323
  ## License
322
324
 
@@ -255,6 +255,8 @@ capauth is the identity root of SKWorld — most of the stack links back here.
255
255
  — produces the runtime crypto self-report that makes capauth's claims evidence-backed.
256
256
  - 📐 **Standards:** [sk-standards](https://github.com/smilinTux/sk-standards) — the
257
257
  crypto, data-flow, version, and doc/SOP standards (incl. `CRYPTOGRAPHY_STANDARD`).
258
+ - 🔐 **Human key operations:**
259
+ [setup, recovery, rotation, approval, and rollback](docs/HUMAN_IDENTITY_SETUP_AND_ROTATION.md).
258
260
 
259
261
  ## License
260
262
 
@@ -346,6 +346,25 @@ capauth manifest sign | verify | list # signed module manifests
346
346
  capauth token mint-audience ... # mint an audience-scoped token
347
347
  ```
348
348
 
349
+ ### Authorization token incident check
350
+
351
+ `capauth.authz.decide()` is fail-closed on token authenticity: a granting token
352
+ must have a non-empty signature, `signature_verifies()` must succeed, it must be
353
+ active, and its token ID must not appear in
354
+ `$SKCAPSTONE_HOME/security/revoked-tokens.json`. Never infer trust from the
355
+ persisted `verified` field alone. `issue_token()` must also abort before storage
356
+ when signing fails; an unsigned compatibility token may only pass through the
357
+ explicit, bounded legacy-grace configuration documented in `authz.py`.
358
+
359
+ For an incident sweep, inventory the token payloads in
360
+ `$SKCAPSTONE_HOME/security/tokens/`, confirm every live grant has a detached
361
+ signature, search the revocation list for the reported token ID, and exercise
362
+ both controls: an unsigned/tampered token is denied while a valid signed token
363
+ is allowed. Revoke a discovered token through `capauth.tokens.revoke_token()`;
364
+ do not delete the evidence file by hand. Preserve the test evidence from
365
+ `tests/test_authz_signature_gate.py` and `tests/test_authz_legacy_grace.py` on
366
+ the coordination card.
367
+
349
368
  > **There is NO `capauth did` command group.** Earlier revisions of this SOP and of
350
369
  > the README documented `capauth did generate` and `capauth did identity-card`; both
351
370
  > are fabrications, and running them exits non-zero with "No such command". The DID
@@ -402,6 +421,12 @@ Full protocol + claim/token format: [docs/PROTOCOL.md](docs/PROTOCOL.md),
402
421
 
403
422
  ## 8. Troubleshooting
404
423
 
424
+ Human identity setup, custody recovery, rotation, signed approval, and rollback
425
+ are governed by
426
+ [docs/HUMAN_IDENTITY_SETUP_AND_ROTATION.md](docs/HUMAN_IDENTITY_SETUP_AND_ROTATION.md).
427
+ The human performs all passphrase/private-key operations; automation may only
428
+ prepare paths and verify public evidence.
429
+
405
430
  | Symptom | Likely cause | Fix |
406
431
  |---|---|---|
407
432
  | `capauth verify` fails on a valid peer | wrong public key / stale profile | re-`export-pubkey`; confirm fingerprint matches the DID/identity card |
@@ -486,4 +511,3 @@ checks:
486
511
  - name: ci.yml lint gate is ruff (section 4 says black is NOT a gate)
487
512
  run: grep -qF 'ruff format --check src/ tests/' .github/workflows/ci.yml
488
513
  -->
489
-
@@ -0,0 +1,149 @@
1
+ # Human identity setup, recovery, and key rotation
2
+
3
+ Status: operational runbook. Owner: the human identity holder. Applies to
4
+ classical CapAuth human identities used for signed approvals and operator
5
+ governance. This runbook follows the SK standards for provenance, reversible
6
+ mutation, backup/retention, testing evidence, and ITIL change control.
7
+
8
+ ## 1. Purpose and invariants
9
+
10
+ - A human private key is generated and unlocked only by that human.
11
+ - Agents may prepare paths and verify public evidence, but never type, copy,
12
+ print, or forge the human passphrase or private key.
13
+ - Rotation is additive first: retain the old public key and profile as audit
14
+ history, enroll the new fingerprint, verify it, then retire old trust.
15
+ - Private keys and revocation certificates are `0600`; containing directories
16
+ are `0700`. Public keys may be `0644`.
17
+ - Never paste key material or passphrases into chat, tickets, shell history,
18
+ source control, logs, or command output.
19
+ - A backup is not accepted until its fingerprint and restore path are tested.
20
+
21
+ ## 2. State and ownership
22
+
23
+ ```mermaid
24
+ flowchart LR
25
+ H[Human at terminal] -->|generates and unlocks| S[staging identity]
26
+ S -->|public fingerprint verification| V[verification gate]
27
+ S -->|0600 copy by human| B[two offline custody copies]
28
+ V -->|approved change| L[live CapAuth identity]
29
+ L --> R[registries and trust consumers]
30
+ L --> A[signed authorization envelope]
31
+ O[old public identity] --> X[retired audit history]
32
+ ```
33
+
34
+ Canonical live home on the operator workstation is
35
+ `~/.skcapstone/capauth`. Temporary ceremony homes and home-directory backups
36
+ are transitional custody only and must be moved to two independent offline
37
+ media after acceptance.
38
+
39
+ ## 3. Initial setup
40
+
41
+ The human runs key generation personally:
42
+
43
+ ```bash
44
+ install -d -m 700 "$HOME/.chef-cauth-setup"
45
+ capauth --home "$HOME/.chef-cauth-setup" init \
46
+ --name Chef --email chef@skworld.io --type human \
47
+ --algorithm ed25519 --no-sync
48
+ ```
49
+
50
+ Use a unique passphrase and retain it outside the workstation. Verify without
51
+ printing key contents:
52
+
53
+ ```bash
54
+ capauth --home "$HOME/.chef-cauth-setup" profile verify
55
+ capauth --home "$HOME/.chef-cauth-setup" doctor custody --json
56
+ ```
57
+
58
+ `doctor` will remain red until a matching revocation certificate and backup
59
+ exist. A red custody gate is not waived.
60
+
61
+ ## 4. Revocation certificate and custody copies
62
+
63
+ The human imports the staged key into an isolated temporary GnuPG home and
64
+ runs `gpg --gen-revoke <fingerprint>`. Creating the certificate does not revoke
65
+ the key. Store the resulting `root-revocation.asc` beside each protected
66
+ private-key custody copy. Confirm:
67
+
68
+ ```bash
69
+ stat -c '%a %U %G %n' \
70
+ "$HOME/.chef-cauth-setup/identity/private.asc" \
71
+ "$HOME/.chef-cauth-setup/identity/root-revocation.asc"
72
+ ```
73
+
74
+ Expected mode is `600`. Maintain two independent offline copies. An on-host
75
+ backup is only a transfer/staging copy, not the required 3-2-1 end state.
76
+
77
+ ## 5. Rotation workflow
78
+
79
+ 1. Open an ITIL change with old fingerprint, reason, affected trust surfaces,
80
+ maintenance window, verification plan, and rollback target.
81
+ 2. Snapshot the old public key, signed profile, custody declaration, and
82
+ revocation certificate into an owner-only `retired-keys/` directory.
83
+ 3. Generate the replacement in an isolated `0700` ceremony home.
84
+ 4. Verify public/private/backup fingerprints are identical and the profile
85
+ signature is valid.
86
+ 5. Generate and duplicate the replacement revocation certificate.
87
+ 6. Install the replacement keypair and profile with the modes in section 1.
88
+ 7. Update explicit fingerprint bindings in registries. Do not use global text
89
+ replacement; validate every target record before mutation.
90
+ 8. Run a fresh public-state backup and its restore verification.
91
+ 9. Run `capauth doctor custody`; all mandatory checks must be `OK`.
92
+ 10. Produce a signed, short-lived authorization and verify it through the real
93
+ consuming workflow.
94
+ 11. Keep both public fingerprints during the declared grace period. Revoke the
95
+ old key only for compromise; an unavailable secret is retired, not falsely
96
+ claimed revoked.
97
+
98
+ ## 6. Signed approval ceremony
99
+
100
+ For an ATLAS/CMDB change, the authorization binds decision, target, change,
101
+ scope, expiry, nonce, signer fingerprint, and role:
102
+
103
+ ```bash
104
+ skcapstone itil cab authorize CHANGE_ID \
105
+ --decision approved --target TARGET --scope SCOPE \
106
+ --output "$HOME/.skcapstone/authorizations/CHANGE_ID.json"
107
+ skcapstone itil cab vote CHANGE_ID \
108
+ --decision approved \
109
+ --authorization "$HOME/.skcapstone/authorizations/CHANGE_ID.json" \
110
+ --target TARGET --scope SCOPE
111
+ ```
112
+
113
+ Read the folded change back. The named human, authenticated role,
114
+ fingerprint, authorization ID, target, and scope must all match. Authorization
115
+ does not bypass freeze, maintenance-window, evidence, or rollback gates.
116
+
117
+ ## 7. Verification and rollback
118
+
119
+ Acceptance evidence:
120
+
121
+ ```bash
122
+ capauth --home "$HOME/.skcapstone/capauth" profile verify
123
+ capauth --home "$HOME/.skcapstone/capauth" doctor custody --json
124
+ capauth manifest verify-all
125
+ ```
126
+
127
+ If any check fails, stop consumers, restore the prior public/profile state from
128
+ the named rollback directory, restore the previous registry fingerprint, and
129
+ rerun the same checks. Never delete the failed replacement; quarantine it with
130
+ its evidence and record the reversing event on the ITIL change.
131
+
132
+ ## 8. Ongoing management
133
+
134
+ - Daily: custody doctor and backup freshness through the wrapped scheduler.
135
+ - Monthly: verify permissions, registry fingerprint parity, and restore the
136
+ newest public-state backup into a temporary directory.
137
+ - Quarterly: verify both offline custody media and revocation-certificate
138
+ readability; do not import the private key during routine inspection.
139
+ - Before each approval: verify profile signature and exact action/change/scope.
140
+ - On suspected compromise: freeze ATLAS, publish the held revocation
141
+ certificate, invalidate affected grants, rotate, and open an incident/problem.
142
+
143
+ ## 9. Evidence, records, and prohibited shortcuts
144
+
145
+ Record fingerprints, timestamps, modes, doctor results, backup artifact ID,
146
+ change ID, and verification outcome. Never record passphrases or private-key
147
+ content. Prohibited shortcuts include agent-generated human keys, reusing an
148
+ agent key as a person, unsigned votes, copying secrets through chat, accepting
149
+ a mismatched backup, or deleting old identity history to make checks green.
@@ -19,7 +19,7 @@ A resolved identity carries **two complementary URIs**:
19
19
 
20
20
  ``fqid``
21
21
  ``<agent>@<operator>.<realm>`` — the skcomms three-tier FQID
22
- (agent @ operator . realm, e.g. ``lumina@chef.skworld``). Derived from
22
+ (agent @ operator . realm, e.g. ``lumina@chef.skworld.io``). Derived from
23
23
  ``~/.skcapstone/cluster.json`` for operator/realm; ``None`` when
24
24
  cluster.json is absent or malformed.
25
25
 
@@ -38,7 +38,7 @@ Public API
38
38
  # AgentIdentity(
39
39
  # agent = "lumina",
40
40
  # capauth_uri = "capauth:lumina@skworld.io",
41
- # fqid = "lumina@chef.skworld",
41
+ # fqid = "lumina@chef.skworld.io",
42
42
  # fingerprint = "02BC0EB3CAD31DB691A753C70C5629AB893F9746",
43
43
  # )
44
44
 
@@ -84,7 +84,7 @@ class AgentIdentity:
84
84
  agent: Short agent name (e.g. ``"lumina"``).
85
85
  capauth_uri: Wire identity — ``capauth:<agent>@skworld.io``.
86
86
  fqid: Three-tier label — ``<agent>@<operator>.<realm>``
87
- (e.g. ``"lumina@chef.skworld"``). ``None`` when
87
+ (e.g. ``"lumina@chef.skworld.io"``). ``None`` when
88
88
  cluster.json is not available.
89
89
  fingerprint: 40 (v4) or 64 (v6) hex PGP fingerprint from the agent's
90
90
  CapAuth profile. ``None`` when no real profile exists.
@@ -274,7 +274,7 @@ def resolve_agent_identity(
274
274
  >>> ident.capauth_uri
275
275
  'capauth:lumina@skworld.io'
276
276
  >>> ident.fqid # only if cluster.json present
277
- 'lumina@chef.skworld'
277
+ 'lumina@chef.skworld.io'
278
278
  """
279
279
  if agent is None:
280
280
  agent = _resolve_active_agent_name()
@@ -173,6 +173,36 @@ def _is_pgp(key: Optional[str]) -> bool:
173
173
  return "BEGIN PGP" in (key or "")
174
174
 
175
175
 
176
+ def _require_subject(subject: Optional[str]) -> str:
177
+ """Reject an absent or blank subject, loudly, at the call.
178
+
179
+ ``subject`` is a REQUIRED keyword on every public builder here, but a caller
180
+ can still hand us ``None`` at runtime (an Optional threaded down from its own
181
+ config, a dict lookup that missed). Falling back to a derived default there
182
+ is the one thing this module must never do.
183
+
184
+ Why: the challenge binds the subject, so a proof built for subject A does not
185
+ verify for subject B. If the builder quietly substituted its own default
186
+ while ``enroll_device`` was called with the caller's real subject, the device
187
+ would sign honestly, capauth would reject the proof, and the enrollment would
188
+ land on the TOFU floor behind a success response with nothing raised. That is
189
+ exactly the silent downgrade card N10 exists to remove.
190
+
191
+ This bit for real: capauth's derived default is the full 40-char
192
+ ``fingerprint_for`` value, while skchat's own derivation is a 16-char device
193
+ id. Two individually reasonable defaults, different signed bytes, and the
194
+ mismatch is invisible until the security boundary rejects it. Caught in
195
+ review by clawd-43 on 2026-08-17 before it shipped to a caller.
196
+ """
197
+ if subject is None or not str(subject).strip():
198
+ raise ProofSigningError(
199
+ "subject is required: the enrollment challenge binds it, so it must be "
200
+ "the SAME subject you pass to enroll_device(). Deriving one here would "
201
+ "silently change the signed bytes and downgrade the enrollment to tofu."
202
+ )
203
+ return str(subject)
204
+
205
+
176
206
  def _resolve_subject(pubkey: str, subject: Optional[str]) -> tuple[str, str]:
177
207
  """Derive ``(fingerprint, canonical_subject)`` exactly as ``enroll_device`` will.
178
208
 
@@ -208,7 +238,7 @@ def _coerce_mode(mode: EnrollmentMode | str) -> EnrollmentMode:
208
238
  def enrollment_challenge(
209
239
  pubkey: str,
210
240
  *,
211
- subject: Optional[str] = None,
241
+ subject: str,
212
242
  mode: EnrollmentMode | str = EnrollmentMode.VERIFIED,
213
243
  ) -> bytes:
214
244
  """The exact bytes an enrollment's proof must sign, from the PUBLIC key alone.
@@ -245,7 +275,7 @@ def enrollment_challenge(
245
275
  PairingError: If ``mode`` is not a known enrollment mode.
246
276
  """
247
277
  resolved = _coerce_mode(mode)
248
- fingerprint, canonical = _resolve_subject(pubkey, subject)
278
+ fingerprint, canonical = _resolve_subject(pubkey, _require_subject(subject))
249
279
  if resolved is EnrollmentMode.ATTESTED:
250
280
  return attested_challenge(fingerprint, canonical)
251
281
  if resolved is EnrollmentMode.VERIFIED:
@@ -340,8 +370,8 @@ def build_verified_proof(
340
370
  pubkey: str,
341
371
  *,
342
372
  private_key: Any,
373
+ subject: str,
343
374
  passphrase: str = "",
344
- subject: Optional[str] = None,
345
375
  ) -> EnrollmentProof:
346
376
  """Sign the ``verified`` enrollment challenge with the device's OWN key.
347
377
 
@@ -379,7 +409,7 @@ def build_verified_proof(
379
409
  capauth.exceptions.SubjectNamingError: If ``subject`` does not conform
380
410
  to the canonical fqid grammar even after alias translation.
381
411
  """
382
- fingerprint, canonical = _resolve_subject(pubkey, subject)
412
+ fingerprint, canonical = _resolve_subject(pubkey, _require_subject(subject))
383
413
  challenge = verified_challenge(fingerprint, canonical)
384
414
  signature = _sign(challenge, private_key, passphrase, pgp=_is_pgp(pubkey))
385
415
  _self_check(pubkey, signature, challenge, what="verified proof")
@@ -398,8 +428,8 @@ def build_attested_proof(
398
428
  *,
399
429
  operator_pubkey: str,
400
430
  operator_private_key: Any,
431
+ subject: str,
401
432
  passphrase: str = "",
402
- subject: Optional[str] = None,
403
433
  ) -> EnrollmentProof:
404
434
  """Sign the ``attested`` challenge with a VOUCHING OPERATOR's key.
405
435
 
@@ -440,7 +470,7 @@ def build_attested_proof(
440
470
  capauth.exceptions.SubjectNamingError: If ``subject`` does not conform
441
471
  to the canonical fqid grammar even after alias translation.
442
472
  """
443
- fingerprint, canonical = _resolve_subject(pubkey, subject)
473
+ fingerprint, canonical = _resolve_subject(pubkey, _require_subject(subject))
444
474
  challenge = attested_challenge(fingerprint, canonical)
445
475
  signature = _sign(challenge, operator_private_key, passphrase, pgp=_is_pgp(operator_pubkey))
446
476
  _self_check(operator_pubkey, signature, challenge, what="attestation")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: capauth
3
- Version: 0.3.2
3
+ Version: 0.3.4
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
@@ -317,6 +317,8 @@ capauth is the identity root of SKWorld — most of the stack links back here.
317
317
  — produces the runtime crypto self-report that makes capauth's claims evidence-backed.
318
318
  - 📐 **Standards:** [sk-standards](https://github.com/smilinTux/sk-standards) — the
319
319
  crypto, data-flow, version, and doc/SOP standards (incl. `CRYPTOGRAPHY_STANDARD`).
320
+ - 🔐 **Human key operations:**
321
+ [setup, recovery, rotation, approval, and rollback](docs/HUMAN_IDENTITY_SETUP_AND_ROTATION.md).
320
322
 
321
323
  ## License
322
324
 
@@ -107,6 +107,7 @@ docs/CLAIMS.md
107
107
  docs/COLD_MACHINE_BOOTSTRAP_AND_DR.md
108
108
  docs/CRYPTO_SPEC.md
109
109
  docs/ENTERPRISE_MANAGED_KEYS.md
110
+ docs/HUMAN_IDENTITY_SETUP_AND_ROTATION.md
110
111
  docs/INTEGRATION_BLUEPRINT.md
111
112
  docs/M0-capauth-api-v1.md
112
113
  docs/M0-capauth-importer-inventory.md
@@ -155,10 +155,22 @@ def test_attested_proof_round_trips_through_enroll_device(tmp_path):
155
155
 
156
156
 
157
157
  def test_helper_defaults_subject_to_the_device_fingerprint_like_enroll_device(tmp_path):
158
- """Omitting ``subject`` on both sides still agrees: both derive device:<fp>."""
158
+ """An EXPLICIT subject on both sides agrees end to end.
159
+
160
+ This test used to omit ``subject`` and rely on the builder and
161
+ ``enroll_device`` deriving the same default. That default was removed: two
162
+ individually reasonable defaults (capauth's 40-char fingerprint, skchat's
163
+ 16-char device id) produce different signed bytes, and the mismatch is
164
+ invisible until the security boundary rejects it. The subject is now
165
+ required, so the agreement is asserted rather than assumed.
166
+ """
159
167
  bundle = _pgp_keypair()
168
+ subject = fingerprint_for(bundle.public_armor)
160
169
  proof = build_verified_proof(
161
- bundle.public_armor, private_key=bundle.private_armor, passphrase=TEST_PASSPHRASE
170
+ bundle.public_armor,
171
+ private_key=bundle.private_armor,
172
+ subject=subject,
173
+ passphrase=TEST_PASSPHRASE,
162
174
  )
163
175
 
164
176
  enrollment = enroll_device(
@@ -412,11 +424,19 @@ def test_building_with_a_WRONG_PASSPHRASE_raises():
412
424
  def test_building_with_a_NON_KEY_raises_rather_than_returning_an_empty_proof():
413
425
  bundle = _pgp_keypair()
414
426
  with pytest.raises(ProofSigningError):
415
- build_verified_proof(bundle.public_armor, private_key="not a key at all")
427
+ build_verified_proof(
428
+ bundle.public_armor,
429
+ private_key="not a key at all",
430
+ subject=fingerprint_for(bundle.public_armor),
431
+ )
416
432
 
417
433
  pubkey_b64, _ = _device_keypair()
418
434
  with pytest.raises(ProofSigningError):
419
- build_verified_proof(pubkey_b64, private_key=b"-----BEGIN PRIVATE KEY-----\nnope\n")
435
+ build_verified_proof(
436
+ pubkey_b64,
437
+ private_key=b"-----BEGIN PRIVATE KEY-----\nnope\n",
438
+ subject=fingerprint_for(pubkey_b64),
439
+ )
420
440
 
421
441
 
422
442
  def test_a_built_proof_is_never_empty():
@@ -430,3 +450,65 @@ def test_a_built_proof_is_never_empty():
430
450
  assert proof.proof
431
451
  assert dict(proof) == {"proof": proof.proof}
432
452
  assert "operator_pubkey" not in dict(proof)
453
+
454
+
455
+ # --- subject is REQUIRED (regression: two reasonable defaults, different bytes) ---
456
+
457
+
458
+ def test_subject_is_required_on_every_public_builder():
459
+ """A derived default here silently changes the SIGNED BYTES.
460
+
461
+ capauth's own default was the full 40-char `fingerprint_for` value. skchat,
462
+ the helper's first caller, derives a 16-char device id. Both defensible in
463
+ isolation. But a proof built with capauth's default, then handed to
464
+ `enroll_device` with skchat's real subject, does not verify: the device signs
465
+ honestly, capauth rejects, and the enrollment lands on the TOFU floor behind
466
+ a success response with nothing raised. That is the exact silent downgrade
467
+ card N10 exists to remove, reintroduced by the convenience meant to close it.
468
+
469
+ Caught in review by clawd-43 on 2026-08-17, before any caller shipped it.
470
+ """
471
+ bundle = _pgp_keypair()
472
+
473
+ for call in (
474
+ lambda: enrollment_challenge(bundle.public_armor),
475
+ lambda: build_verified_proof(
476
+ bundle.public_armor,
477
+ private_key=bundle.private_armor,
478
+ passphrase=TEST_PASSPHRASE,
479
+ ),
480
+ ):
481
+ with pytest.raises(TypeError, match="subject"):
482
+ call()
483
+
484
+
485
+ @pytest.mark.parametrize("blank", [None, "", " "])
486
+ def test_an_explicitly_blank_subject_raises_rather_than_deriving_one(blank):
487
+ """The signature makes it required; this makes a runtime None fail too.
488
+
489
+ A caller can still thread an Optional down from its own config and hand us
490
+ None. Falling back to a derived default there is the failure this module
491
+ must never have.
492
+ """
493
+ bundle = _pgp_keypair()
494
+
495
+ with pytest.raises(ProofSigningError, match="subject is required"):
496
+ enrollment_challenge(bundle.public_armor, subject=blank)
497
+
498
+ with pytest.raises(ProofSigningError, match="subject is required"):
499
+ build_verified_proof(
500
+ bundle.public_armor,
501
+ private_key=bundle.private_armor,
502
+ subject=blank,
503
+ passphrase=TEST_PASSPHRASE,
504
+ )
505
+
506
+
507
+ def test_two_different_subjects_produce_different_challenges():
508
+ """The property the whole guard exists to protect, asserted directly."""
509
+ bundle = _pgp_keypair()
510
+ full = fingerprint_for(bundle.public_armor)
511
+
512
+ assert enrollment_challenge(bundle.public_armor, subject=full) != enrollment_challenge(
513
+ bundle.public_armor, subject=full[:16]
514
+ ), "challenge must bind the subject, or a subject mismatch would go unnoticed"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes