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