skcomms 0.2.0__tar.gz → 0.2.1__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.
- {skcomms-0.2.0 → skcomms-0.2.1}/PKG-INFO +1 -1
- {skcomms-0.2.0 → skcomms-0.2.1}/pyproject.toml +1 -1
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/access/server.py +3 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/ack.py +85 -18
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/api.py +333 -57
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/capauth_validator.py +108 -27
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/cli.py +474 -0
- skcomms-0.2.1/src/skcomms/config.py +415 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/consent_group_gate.py +27 -14
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/consent_pipeline.py +52 -18
- skcomms-0.2.1/src/skcomms/core.py +1428 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/crypto.py +11 -1
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/discovery.py +24 -7
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/federation.py +85 -1
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/home.py +47 -6
- skcomms-0.2.1/src/skcomms/housekeeping.py +260 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/key_exchange.py +19 -8
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/mailbox.py +276 -41
- skcomms-0.2.1/src/skcomms/observability.py +398 -0
- skcomms-0.2.1/src/skcomms/outbox.py +1117 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/outbox_migrate.py +154 -0
- skcomms-0.2.1/src/skcomms/paths.py +405 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/queue.py +23 -6
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/registry.py +10 -4
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/router.py +475 -184
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/signaling.py +37 -7
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/signing.py +11 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/skfed_resolve.py +28 -86
- skcomms-0.2.1/src/skcomms/ssrf.py +398 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/store_forward.py +31 -11
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/tofu.py +59 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transport.py +32 -1
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/broker_server.py +9 -4
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/file.py +295 -15
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/http_s2s.py +189 -15
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/syncthing.py +104 -1
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/webrtc.py +61 -5
- skcomms-0.2.1/src/skcomms/trustbackup.py +549 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms.egg-info/PKG-INFO +1 -1
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms.egg-info/SOURCES.txt +31 -14
- skcomms-0.2.1/tests/test_ack_bind.py +380 -0
- skcomms-0.2.1/tests/test_api_cors.py +105 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_api_federation_inbox.py +31 -9
- skcomms-0.2.1/tests/test_api_health.py +97 -0
- skcomms-0.2.1/tests/test_api_send_signed_wire.py +247 -0
- skcomms-0.2.1/tests/test_broker_server.py +92 -0
- skcomms-0.2.1/tests/test_capauth_failclosed.py +249 -0
- skcomms-0.2.1/tests/test_consent_ban_gate_fail_closed.py +212 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_group_gate.py +111 -14
- skcomms-0.2.1/tests/test_core_inbound_beacon_skip.py +81 -0
- skcomms-0.2.1/tests/test_core_send_signed.py +251 -0
- skcomms-0.2.1/tests/test_deadletter_ops.py +481 -0
- skcomms-0.2.1/tests/test_delivery_semantics.py +268 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_home_scaffold.py +62 -0
- skcomms-0.2.1/tests/test_housekeeping.py +552 -0
- skcomms-0.2.1/tests/test_http_s2s_star_recipient.py +39 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_http_s2s_transport.py +149 -9
- skcomms-0.2.1/tests/test_identity_trust_backup.py +639 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_mailbox.py +24 -17
- skcomms-0.2.1/tests/test_mailbox_encrypt_at_rest.py +516 -0
- skcomms-0.2.1/tests/test_nonce_durable.py +258 -0
- skcomms-0.2.1/tests/test_observability.py +492 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_outbox_migrate.py +126 -11
- skcomms-0.2.1/tests/test_paths_scoping.py +536 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_pqroute_padding.py +2 -3
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_pqroute_transport.py +2 -3
- skcomms-0.2.1/tests/test_prune_inbox.py +96 -0
- skcomms-0.2.1/tests/test_queue_bounds.py +790 -0
- skcomms-0.2.1/tests/test_receiver_wire_ttl_expiry.py +50 -0
- skcomms-0.2.1/tests/test_router_failure_log_dedup.py +174 -0
- skcomms-0.2.1/tests/test_router_perm_backoff.py +131 -0
- skcomms-0.2.1/tests/test_router_perm_backoff_fixes.py +156 -0
- skcomms-0.2.1/tests/test_router_quarantine.py +122 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_router_rail_ordering.py +28 -23
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_router_route_anon.py +2 -1
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_router_route_signed.py +3 -2
- skcomms-0.2.1/tests/test_router_star_broadcast_routing.py +139 -0
- skcomms-0.2.1/tests/test_router_unsigned_excludes_https_s2s.py +155 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_skfed_ssrf.py +20 -9
- skcomms-0.2.1/tests/test_ssrf_guard.py +431 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_store_forward.py +92 -0
- skcomms-0.2.1/tests/test_webrtc_signaling_log_dedup.py +54 -0
- skcomms-0.2.0/src/skcomms/config.py +0 -230
- skcomms-0.2.0/src/skcomms/core.py +0 -947
- skcomms-0.2.0/src/skcomms/cot.py +0 -299
- skcomms-0.2.0/src/skcomms/cot_agent.py +0 -173
- skcomms-0.2.0/src/skcomms/cot_client.py +0 -142
- skcomms-0.2.0/src/skcomms/cot_pki.py +0 -622
- skcomms-0.2.0/src/skcomms/cot_server.py +0 -603
- skcomms-0.2.0/src/skcomms/cot_service.py +0 -191
- skcomms-0.2.0/src/skcomms/geo.py +0 -477
- skcomms-0.2.0/src/skcomms/outbox.py +0 -663
- skcomms-0.2.0/tests/test_ack_bind.py +0 -89
- skcomms-0.2.0/tests/test_broker_server.py +0 -36
- skcomms-0.2.0/tests/test_capauth_failclosed.py +0 -98
- skcomms-0.2.0/tests/test_cot_agent_nameagnostic.py +0 -18
- skcomms-0.2.0/tests/test_cot_beacon_outbox.py +0 -204
- skcomms-0.2.0/tests/test_cot_codec.py +0 -146
- skcomms-0.2.0/tests/test_cot_pki.py +0 -150
- skcomms-0.2.0/tests/test_cot_server.py +0 -216
- skcomms-0.2.0/tests/test_geo.py +0 -247
- skcomms-0.2.0/tests/test_mailbox_encrypt_at_rest.py +0 -173
- {skcomms-0.2.0 → skcomms-0.2.1}/LICENSE +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/README.md +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/setup.cfg +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/__init__.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/access/__init__.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/access/audit.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/access/config.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/access/exec.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/access/files.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/access/grants.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/access/knowledge.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/access/registry.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/access/routing.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/access/wiring.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/adapters/__init__.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/adapters/base.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/adapters/discord.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/adapters/factory.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/adapters/fake.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/adapters/matrix.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/adapters/models.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/adapters/registry.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/adapters/slack.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/adapters/telegram.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/anon_queue.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/anon_transport.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/capabilities.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/cluster.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/compression.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/consent.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/consent_banfeeds.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/consent_captcha.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/consent_greylist.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/consent_groups.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/consent_moderation.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/consent_policy.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/consent_requests.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/consent_runtime.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/consent_tiering.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/consent_tokens.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/crypto_suites.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/did_router.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/envelope.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/glossa/__init__.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/glossa/codebook.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/glossa/codec.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/glossa/emergent.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/glossa/gloss.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/glossa/handshake.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/glossa/macros.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/glossa/message.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/glossa/session.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/grants.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/heartbeat.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/household_router.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/identity.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/integration.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/marketplace.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/mcp_server.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/metrics.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/models.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/node_registry.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/nostr_discovery.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/padding.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/pairing.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/peers.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/pq_provider.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/pqdm.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/pqkem.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/pqkem_backend.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/pqroute.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/pqroute_transport.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/pqsig.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/profile_router.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/pubsub.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/pubsub_transport.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/ratelimit.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/realm.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/skfed_announce.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/skfed_directory.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/skfed_readdr.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/souls_router.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/__init__.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/audio_track.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/ble/__init__.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/ble/gatt.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/ble/identity.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/ble/node.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/ble/noise.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/ble/protocol.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/ble/radio.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/ble/relay.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/lora/__init__.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/lora/addressing.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/lora/framing.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/lora/interface.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/lora/meshtastic_iface.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/lora/store.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/lora/transport.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/nostr.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/p2p_connector.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/p2p_manager.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/p2p_session.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/signaling_base.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/signaling_broker.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/signaling_mailbox.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/tailscale.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/video_track.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/webrtc_media.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms/transports/websocket.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms.egg-info/dependency_links.txt +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms.egg-info/entry_points.txt +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms.egg-info/requires.txt +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/src/skcomms.egg-info/top_level.txt +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_access_exec.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_access_files.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_access_rbac.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_access_routing.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_access_server.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_access_wiring.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_adapter_factory.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_adapter_fake.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_anon_queue.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_anon_transport.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_api_access_token.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_api_consent.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_api_consent_token_gate.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_api_skfed_directory.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_backfill_file_locations.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_ble_fragment.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_ble_gatt.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_ble_identity.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_ble_mesh.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_ble_noise.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_ble_pairing_bundle.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_ble_protocol.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_ble_radio.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_ble_relay.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_capabilities.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_capauth_key_reconcile.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_channel_adapter.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_config.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_banfeeds.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_captcha.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_cli.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_cli_mgmt.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_greylist.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_groups.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_moderation.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_pipeline.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_policy.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_requests.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_runtime.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_tiering.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_consent_tokens.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_core_send_federated.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_crypto_failclosed.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_crypto_suites_q0.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_daemon_adapter_lifecycle.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_discord_adapter.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_encrypt_fail_closed.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_envelope_consent_token.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_envelope_v1.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_federation.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_federation_integration.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_codebook.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_codec_l0.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_codec_l1.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_codec_l2.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_emergent.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_emergent_negotiator.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_emergent_protocol.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_gloss.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_handshake.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_handshake_lexicon.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_macros.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_macros_render.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_message.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_session.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_session_macros.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_glossa_to_human.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_grants.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_hybrid_envelope_sig.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_identity_env_override.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_identity_key_binding.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_identity_realm.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_integration.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_knowledge.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_lora_addressing.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_lora_framing.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_lora_interface.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_lora_meshtastic_iface.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_lora_store.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_lora_transport.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_matrix_adapter.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_node_registry.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_nostr_discovery.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_p2p_connector.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_p2p_manager.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_p2p_media.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_p2p_session.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_padding.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_pairing.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_pairing_cli.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_peer_inbox_traversal.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_peers.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_pqc_cutover.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_pqc_shim.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_pqdm.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_pqkem.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_pqroute.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_pqsig.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_registry.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_registry_cli.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_sign_fail_closed.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_signaling_broker.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_signaling_mailbox.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_signaling_select.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_skfed_announce.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_skfed_cli.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_skfed_directory.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_skfed_operator_pin.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_skfed_readdr.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_skfed_resolve.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_slack_adapter.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_smoke.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_syncthing_recipient_guard.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_telegram_adapter.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_tofu.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_typed_message_content.py +0 -0
- {skcomms-0.2.0 → skcomms-0.2.1}/tests/test_webrtc_ice_logging.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "skcomms"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "Sovereign communications for AI agents — multi-channel transport + FQID realm addressing"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "GPL-3.0-or-later"}
|
|
@@ -118,6 +118,9 @@ class AccessServer:
|
|
|
118
118
|
self.registry = registry or DEFAULT_REGISTRY
|
|
119
119
|
self._peer_store = peer_store if peer_store is not None else PeerStore()
|
|
120
120
|
self.verifier = verifier or self._build_verifier()
|
|
121
|
+
# KNOWN GAP (follow-up coord f465b407): in-memory cache means a
|
|
122
|
+
# daemon restart reopens a replay window on the sk-access surface.
|
|
123
|
+
# Migrate to the durable per-node store (see api._get_nonce_cache).
|
|
121
124
|
self.nonce_cache = fed.NonceCache()
|
|
122
125
|
self.audit = audit or AccessAuditLog(node=self.config.node_name)
|
|
123
126
|
self._register_builtins()
|
|
@@ -20,7 +20,7 @@ import logging
|
|
|
20
20
|
from datetime import datetime, timezone
|
|
21
21
|
from enum import Enum
|
|
22
22
|
from pathlib import Path
|
|
23
|
-
from typing import Optional
|
|
23
|
+
from typing import Callable, Optional
|
|
24
24
|
|
|
25
25
|
from pydantic import BaseModel, Field
|
|
26
26
|
|
|
@@ -81,16 +81,27 @@ class AckTracker:
|
|
|
81
81
|
Args:
|
|
82
82
|
acks_dir: Directory for ACK tracking files.
|
|
83
83
|
default_timeout: Default seconds to wait for ACK.
|
|
84
|
+
sender_verifier: Optional callable authenticating an ACK envelope
|
|
85
|
+
against its claimed sender (CapAuth/PGP signature). Fails closed:
|
|
86
|
+
a verifier that returns falsy or raises rejects the ACK.
|
|
84
87
|
"""
|
|
85
88
|
|
|
86
89
|
def __init__(
|
|
87
90
|
self,
|
|
88
91
|
acks_dir: Optional[Path] = None,
|
|
89
92
|
default_timeout: int = DEFAULT_ACK_TIMEOUT,
|
|
93
|
+
sender_verifier: Optional[Callable[[MessageEnvelope], bool]] = None,
|
|
90
94
|
):
|
|
91
95
|
self._dir = acks_dir or Path(SKCOMMS_HOME).expanduser() / ACKS_DIR_NAME
|
|
92
96
|
self._dir.mkdir(parents=True, exist_ok=True)
|
|
93
97
|
self._default_timeout = default_timeout
|
|
98
|
+
# Optional cryptographic authenticator for inbound ACKs. Given the ACK
|
|
99
|
+
# envelope, returns True iff the ACK is authenticated as coming from its
|
|
100
|
+
# claimed sender (e.g. its CapAuth/PGP payload signature verifies). When
|
|
101
|
+
# wired in, string identity alone is not trusted. Reuses the existing
|
|
102
|
+
# signing stack (skcomms.crypto.EnvelopeCrypto.verify_signature), no new
|
|
103
|
+
# crypto scheme.
|
|
104
|
+
self._sender_verifier = sender_verifier
|
|
94
105
|
|
|
95
106
|
@property
|
|
96
107
|
def acks_dir(self) -> Path:
|
|
@@ -124,16 +135,51 @@ class AckTracker:
|
|
|
124
135
|
logger.debug("Tracking ACK for %s -> %s", envelope.envelope_id[:8], envelope.recipient)
|
|
125
136
|
return pending
|
|
126
137
|
|
|
138
|
+
@staticmethod
|
|
139
|
+
def _identity_matches(a: str, b: str) -> bool:
|
|
140
|
+
"""Compare two identities (agent name, FQID, or PGP fingerprint).
|
|
141
|
+
|
|
142
|
+
Whitespace- and case-insensitive: a PGP fingerprint may be stored
|
|
143
|
+
spaced or unspaced as it crosses different transports. Empty values
|
|
144
|
+
never match (fail closed).
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
a: First identity string.
|
|
148
|
+
b: Second identity string.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
True if both are non-empty and equal after normalization.
|
|
152
|
+
"""
|
|
153
|
+
if not a or not b:
|
|
154
|
+
return False
|
|
155
|
+
return a.replace(" ", "").casefold() == b.replace(" ", "").casefold()
|
|
156
|
+
|
|
127
157
|
def process_ack(self, ack_envelope: MessageEnvelope) -> Optional[PendingAck]:
|
|
128
158
|
"""Process a received ACK envelope and resolve the pending entry.
|
|
129
159
|
|
|
130
|
-
The ACK's content holds the original envelope_id.
|
|
160
|
+
The ACK's content holds the original envelope_id. Before an ACK is
|
|
161
|
+
allowed to confirm delivery it is bound to the sender identity and
|
|
162
|
+
checked for replay:
|
|
163
|
+
|
|
164
|
+
* Sender binding (anti-forgery): only the party the original message
|
|
165
|
+
was delivered to (``pending.recipient``) may acknowledge it. An ACK
|
|
166
|
+
whose ``sender`` is not that recipient is rejected, so a third party
|
|
167
|
+
cannot forge a delivery confirmation just by learning the
|
|
168
|
+
``envelope_id``.
|
|
169
|
+
* Cryptographic authentication (optional): when a ``sender_verifier``
|
|
170
|
+
is wired in, the ACK's CapAuth/PGP signature must authenticate its
|
|
171
|
+
claimed sender; string identity alone is not trusted. Fails closed.
|
|
172
|
+
* Replay / stale rejection: an ACK may confirm a pending entry exactly
|
|
173
|
+
once. A duplicate ACK for an already-confirmed message, or a stale
|
|
174
|
+
ACK replayed after the entry timed out, does not mutate state (no
|
|
175
|
+
re-confirmation, no resurrection).
|
|
131
176
|
|
|
132
177
|
Args:
|
|
133
178
|
ack_envelope: A received ACK-type envelope.
|
|
134
179
|
|
|
135
180
|
Returns:
|
|
136
|
-
The resolved PendingAck, or None if
|
|
181
|
+
The resolved PendingAck, or None if the ACK is unknown, forged,
|
|
182
|
+
unauthenticated, or a replay.
|
|
137
183
|
"""
|
|
138
184
|
if not ack_envelope.is_ack:
|
|
139
185
|
return None
|
|
@@ -142,7 +188,9 @@ class AckTracker:
|
|
|
142
188
|
path = self._dir / f"{original_id}{ACK_SUFFIX}"
|
|
143
189
|
|
|
144
190
|
if not path.exists():
|
|
145
|
-
|
|
191
|
+
# No pending entry: a forged ACK for a message we never sent, or a
|
|
192
|
+
# replay after the entry was purged. Either way, ignore.
|
|
193
|
+
logger.debug("ACK for unknown envelope %s: ignoring", original_id[:8])
|
|
146
194
|
return None
|
|
147
195
|
|
|
148
196
|
try:
|
|
@@ -151,27 +199,46 @@ class AckTracker:
|
|
|
151
199
|
logger.warning("Failed to read pending ACK %s: %s", original_id[:8], exc)
|
|
152
200
|
return None
|
|
153
201
|
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
#
|
|
157
|
-
|
|
202
|
+
# Sender-identity binding (anti-forgery): the ACK must come from the
|
|
203
|
+
# identity the original message was delivered to. Reject any ACK whose
|
|
204
|
+
# sender is not the intended recipient (forgery by a third party).
|
|
205
|
+
# Comparison is fingerprint-normalization aware and fails closed on
|
|
206
|
+
# empty identities.
|
|
207
|
+
if not self._identity_matches(ack_envelope.sender, pending.recipient):
|
|
158
208
|
logger.warning(
|
|
159
|
-
"
|
|
209
|
+
"Rejecting forged ACK for %s: sender %r is not tracked recipient %r",
|
|
160
210
|
original_id[:8],
|
|
161
|
-
|
|
211
|
+
ack_envelope.sender,
|
|
212
|
+
pending.recipient,
|
|
162
213
|
)
|
|
163
214
|
return None
|
|
164
215
|
|
|
165
|
-
#
|
|
166
|
-
#
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
216
|
+
# Optional cryptographic authentication of the ACK sender. Fail closed:
|
|
217
|
+
# a verifier error or a falsy result rejects the ACK.
|
|
218
|
+
if self._sender_verifier is not None:
|
|
219
|
+
try:
|
|
220
|
+
authenticated = bool(self._sender_verifier(ack_envelope))
|
|
221
|
+
except Exception as exc:
|
|
222
|
+
logger.warning(
|
|
223
|
+
"ACK sender verification errored for %s: %s", original_id[:8], exc
|
|
224
|
+
)
|
|
225
|
+
authenticated = False
|
|
226
|
+
if not authenticated:
|
|
227
|
+
logger.warning(
|
|
228
|
+
"Rejecting unauthenticated ACK for %s from %s (signature check failed)",
|
|
229
|
+
original_id[:8],
|
|
230
|
+
ack_envelope.sender,
|
|
231
|
+
)
|
|
232
|
+
return None
|
|
233
|
+
|
|
234
|
+
# Replay/dedupe protection: only a still-pending entry may be confirmed.
|
|
235
|
+
# A replayed ACK (or an ACK for an already-resolved or timed-out
|
|
236
|
+
# envelope) is rejected so it cannot re-confirm or mutate the entry.
|
|
237
|
+
if pending.status != AckStatus.PENDING:
|
|
170
238
|
logger.warning(
|
|
171
|
-
"ACK for %s
|
|
239
|
+
"Duplicate/replayed ACK for %s (status=%s): ignoring",
|
|
172
240
|
original_id[:8],
|
|
173
|
-
|
|
174
|
-
pending.recipient,
|
|
241
|
+
pending.status.value,
|
|
175
242
|
)
|
|
176
243
|
return None
|
|
177
244
|
|