agentnode-sdk 0.12.0__tar.gz → 0.13.0__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 (189) hide show
  1. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/CHANGELOG.md +76 -0
  2. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/PKG-INFO +2 -1
  3. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/__init__.py +1 -1
  4. agentnode_sdk-0.13.0/agentnode_sdk/cli/auth.py +243 -0
  5. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/main.py +8 -1
  6. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/config.py +23 -1
  7. agentnode_sdk-0.13.0/agentnode_sdk/credential_store.py +296 -0
  8. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/agent_runner.py +64 -1
  9. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/pyproject.toml +2 -1
  10. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/conftest.py +20 -0
  11. agentnode_sdk-0.13.0/tests/test_auth_cli_vault.py +221 -0
  12. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_cli.py +4 -1
  13. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_config.py +99 -0
  14. agentnode_sdk-0.13.0/tests/test_credential_vault.py +217 -0
  15. agentnode_sdk-0.13.0/tests/test_llm_vault_binding.py +143 -0
  16. agentnode_sdk-0.12.0/agentnode_sdk/cli/auth.py +0 -113
  17. agentnode_sdk-0.12.0/agentnode_sdk/credential_store.py +0 -143
  18. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/.env.example +0 -0
  19. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/.gitignore +0 -0
  20. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/README.md +0 -0
  21. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/REGISTRY_SIGNING_ACTIVATION.md +0 -0
  22. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/REGISTRY_SIGNING_SPEC.md +0 -0
  23. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/THREAT_MODEL.md +0 -0
  24. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/TRUST_STACK.md +0 -0
  25. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode.lock +0 -0
  26. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/_fileutil.py +0 -0
  27. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/async_client.py +0 -0
  28. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/capability_graph.py +0 -0
  29. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/capability_taxonomy.py +0 -0
  30. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/__init__.py +0 -0
  31. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/__main__.py +0 -0
  32. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/audit.py +0 -0
  33. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/cassette_audit.py +0 -0
  34. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/commands.py +0 -0
  35. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/complements.py +0 -0
  36. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/init.py +0 -0
  37. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/mcp_commands.py +0 -0
  38. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/mcp_status.py +0 -0
  39. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/mcp_submit.py +0 -0
  40. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/mcp_verify.py +0 -0
  41. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/output.py +0 -0
  42. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/publish.py +0 -0
  43. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/record_cases.py +0 -0
  44. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/sandbox_commands.py +0 -0
  45. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/serve.py +0 -0
  46. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/setup_wizard.py +0 -0
  47. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/smart_run.py +0 -0
  48. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/templates.py +0 -0
  49. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/validate.py +0 -0
  50. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/cli/verify_local.py +0 -0
  51. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/client.py +0 -0
  52. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/compatibility.py +0 -0
  53. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/credential_handle.py +0 -0
  54. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/credential_resolver.py +0 -0
  55. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/detect.py +0 -0
  56. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/exceptions.py +0 -0
  57. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/guard.py +0 -0
  58. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/input_guard.py +0 -0
  59. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/installer.py +0 -0
  60. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/key_status.py +0 -0
  61. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/lock_integrity.py +0 -0
  62. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/mcp_server.py +0 -0
  63. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/models.py +0 -0
  64. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/planner.py +0 -0
  65. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/policy.py +0 -0
  66. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/references.py +0 -0
  67. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/registry_trust.py +0 -0
  68. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/resolve.py +0 -0
  69. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/resource_provider.py +0 -0
  70. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/risk_profile.py +0 -0
  71. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/run_log.py +0 -0
  72. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runner.py +0 -0
  73. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtime.py +0 -0
  74. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/__init__.py +0 -0
  75. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/agent_llm_broker.py +0 -0
  76. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/agent_llm_policy.py +0 -0
  77. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/agent_sandbox.py +0 -0
  78. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/mcp_runner.py +0 -0
  79. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/python_runner.py +0 -0
  80. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/runtimes/remote_runner.py +0 -0
  81. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/__init__.py +0 -0
  82. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/agent_container_wrapper.py +0 -0
  83. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/agent_rpc.py +0 -0
  84. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/agent_session.py +0 -0
  85. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/backend.py +0 -0
  86. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/container_backend.py +0 -0
  87. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/policy.py +0 -0
  88. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/sandbox/types.py +0 -0
  89. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/signature.py +0 -0
  90. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/signing_key.py +0 -0
  91. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/agentnode_sdk/skill.py +0 -0
  92. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/sandbox-image/Dockerfile +0 -0
  93. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/sandbox-image/README.md +0 -0
  94. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/scripts/analyze_scores.py +0 -0
  95. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/scripts/batch_verify.py +0 -0
  96. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/scripts/ci_smoke_test.py +0 -0
  97. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/scripts/generate_compatibility_artifacts.py +0 -0
  98. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/scripts/verify_toolcalls.py +0 -0
  99. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/scripts/weekly_retest.sh +0 -0
  100. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/spikes/agent_sandbox_routing/README.md +0 -0
  101. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/spikes/agent_sandbox_routing/__init__.py +0 -0
  102. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/spikes/agent_sandbox_routing/container_agent_wrapper.py +0 -0
  103. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/spikes/agent_sandbox_routing/fake_llm.py +0 -0
  104. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/spikes/agent_sandbox_routing/host_driver.py +0 -0
  105. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/spikes/agent_sandbox_routing/trivial_agent.py +0 -0
  106. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/__init__.py +0 -0
  107. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_llm_broker.py +0 -0
  108. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_llm_policy.py +0 -0
  109. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_rpc.py +0 -0
  110. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_runner.py +0 -0
  111. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_sandbox_e2e.py +0 -0
  112. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_sandbox_routing.py +0 -0
  113. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_sandbox_spike.py +0 -0
  114. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_agent_session_container.py +0 -0
  115. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_async_client.py +0 -0
  116. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_audit_ux.py +0 -0
  117. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_auto_upgrade_policy.py +0 -0
  118. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_cli_lock.py +0 -0
  119. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_cli_run_resolution.py +0 -0
  120. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_client.py +0 -0
  121. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_client_json_guard.py +0 -0
  122. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_client_sprint_b.py +0 -0
  123. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_credential_handle.py +0 -0
  124. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_credential_integration.py +0 -0
  125. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_credential_resolver.py +0 -0
  126. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_credential_store.py +0 -0
  127. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_detect.py +0 -0
  128. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_detect_and_install.py +0 -0
  129. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_e2e_runtime.py +0 -0
  130. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_edge_cases.py +0 -0
  131. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard.py +0 -0
  132. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_check.py +0 -0
  133. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_config_cache.py +0 -0
  134. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_policy.py +0 -0
  135. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_preview.py +0 -0
  136. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_schema.py +0 -0
  137. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_set.py +0 -0
  138. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_status.py +0 -0
  139. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_tool_override.py +0 -0
  140. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_tool_override_audit.py +0 -0
  141. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_tool_override_cli.py +0 -0
  142. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_guard_ux.py +0 -0
  143. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_input_guard.py +0 -0
  144. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_input_guard_escalation.py +0 -0
  145. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_install_hardening.py +0 -0
  146. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_installer_sprint_b.py +0 -0
  147. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_intelligence.py +0 -0
  148. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_key_status.py +0 -0
  149. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_llm_binding.py +0 -0
  150. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_llm_call_runlog.py +0 -0
  151. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_lock_integrity.py +0 -0
  152. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_lock_runtime.py +0 -0
  153. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_mcp_audit.py +0 -0
  154. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_mcp_doctor.py +0 -0
  155. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_mcp_sandbox.py +0 -0
  156. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_mcp_server.py +0 -0
  157. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_observability.py +0 -0
  158. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_planner.py +0 -0
  159. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_policy.py +0 -0
  160. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_policy_integration.py +0 -0
  161. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_prompt_specs.py +0 -0
  162. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_provider_matrix.py +0 -0
  163. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_publish.py +0 -0
  164. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_references.py +0 -0
  165. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_registry_trust.py +0 -0
  166. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_remote_hardening.py +0 -0
  167. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_remote_runner.py +0 -0
  168. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_resource_provider.py +0 -0
  169. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_resource_specs.py +0 -0
  170. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_risk_profile.py +0 -0
  171. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_run_log.py +0 -0
  172. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_runner.py +0 -0
  173. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_runtime.py +0 -0
  174. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_runtime_audit.py +0 -0
  175. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_sandbox_backend.py +0 -0
  176. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_sandbox_doctor.py +0 -0
  177. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_sandbox_e2e.py +0 -0
  178. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_sandbox_gate.py +0 -0
  179. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_security_hardening.py +0 -0
  180. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_signature.py +0 -0
  181. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_signing_key.py +0 -0
  182. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_skill.py +0 -0
  183. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_smart.py +0 -0
  184. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_stability.py +0 -0
  185. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_toolpack_sandbox.py +0 -0
  186. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_v02.py +0 -0
  187. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_validate.py +0 -0
  188. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/test_validate_skill.py +0 -0
  189. {agentnode_sdk-0.12.0 → agentnode_sdk-0.13.0}/tests/validation_lockfile.json +0 -0
@@ -1,5 +1,81 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.13.0 — Credential vault for LLM providers
4
+
5
+ ### Added
6
+
7
+ - **OS-keychain credential storage:** `agentnode auth set openai|anthropic|openrouter`
8
+ now stores the key in the OS keychain (Windows Credential Manager, macOS
9
+ Keychain, Linux Secret Service). `credentials.json` keeps only non-secret
10
+ metadata for keychain-backed entries. If no keychain is available (e.g.
11
+ headless Linux/CI), storage falls back to the plaintext file (0600) — and
12
+ says so honestly.
13
+ - **The LLM runtime now reads stored credentials:** `_auto_detect_llm` falls
14
+ back to the credential store when no env var is set — `agentnode auth set
15
+ openai` is finally picked up by host agents AND the sandboxed-agent LLM
16
+ broker (the key still never enters the sandbox container).
17
+ - `agentnode auth test <provider>` — validates the effective key via a free
18
+ provider endpoint (no completion call, no cost). Exit codes: 0 valid,
19
+ 1 rejected, 2 not configured, 3 indeterminate (network errors are never
20
+ reported as "invalid").
21
+ - `agentnode auth set <provider> --from-env ENV_VAR` — import an existing
22
+ environment key into the store.
23
+ - `llm.default_provider` config key — which stored credential to try first
24
+ (`openai`, `anthropic`, `openrouter`). OpenRouter bindings pin the
25
+ namespaced default model (`openai/gpt-4o-mini`).
26
+
27
+ ### Changed
28
+
29
+ - `agentnode auth status` now leads with an LLM-provider section showing the
30
+ storage backend and the EFFECTIVE source per provider — including an
31
+ explicit "env var X — overrides stored credential" callout when an
32
+ environment variable shadows a stored key.
33
+ - `agentnode auth list` shows a storage column (OS keychain / plaintext file).
34
+ - Environment variables (and `~/.agentnode/.env`) always override stored
35
+ credentials — explicit/CI intent wins.
36
+
37
+ ### Hardened
38
+
39
+ - Keys are never printed (masked last-4 only), never logged (provider/backend
40
+ errors are reported by type, never message), never echoed from provider
41
+ responses, and never enter the sandbox container, audit records, manifests,
42
+ or lockfiles. `auth test` never accepts a key as a CLI argument.
43
+ - Keychain access is probed once per process with a timeout — a locked or
44
+ hanging Secret Service degrades cleanly to file storage instead of blocking.
45
+
46
+ ### Upgrade Notes
47
+
48
+ - New dependency: `keyring>=24` (pure Python, installed automatically).
49
+ - Honest scope of the OS keychain: it protects against other local users and
50
+ accidental file exposure; it does NOT protect against programs running as
51
+ the same user. The fallback is a plaintext file (0600) when no keychain is
52
+ available — neither mode is "encrypted at rest by AgentNode".
53
+ - Existing plaintext credentials keep working unchanged. Nothing migrates on
54
+ read; a credential moves into the keychain the next time you `auth set` it.
55
+ - No breaking changes.
56
+
57
+ ## 0.12.1 — agent_sandbox config fix
58
+
59
+ ### Fixed
60
+
61
+ - **`agent_sandbox` config section was stripped during `load_config()`.** The
62
+ config loader rebuilt the file from defaults and silently dropped a
63
+ hand-written `agent_sandbox` section, so the documented
64
+ `agent_sandbox.enabled: true` config path never took effect (only the
65
+ `AGENTNODE_AGENT_SANDBOX` env var worked), and the host LLM ceiling
66
+ (`agent_sandbox.llm.*`) never reached policy resolution. Both now survive
67
+ loading; the nested `llm` ceiling is passed through verbatim.
68
+ - **`agentnode config set agent_sandbox.enabled true|false` now works** (the
69
+ key was missing from the allowed-keys whitelist) and stores a **real
70
+ boolean** — previously a stored string `"false"` would have been truthy,
71
+ i.e. read as enabled.
72
+
73
+ ### Upgrade Notes
74
+
75
+ - No breaking changes. No behavior change unless you use the `agent_sandbox`
76
+ config path; the env var `AGENTNODE_AGENT_SANDBOX` behaves exactly as
77
+ before. The agent sandbox remains **default OFF**.
78
+
3
79
  ## 0.12.0 — Sandboxed community agents (flag-gated)
4
80
 
5
81
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentnode-sdk
3
- Version: 0.12.0
3
+ Version: 0.13.0
4
4
  Summary: Python SDK for AgentNode — the open upgrade and discovery infrastructure for AI agents.
5
5
  Project-URL: Homepage, https://agentnode.net
6
6
  Project-URL: Repository, https://github.com/agentnode-ai/agentnode
@@ -16,6 +16,7 @@ Classifier: Topic :: Software Development :: Libraries
16
16
  Requires-Python: >=3.10
17
17
  Requires-Dist: cryptography>=41.0
18
18
  Requires-Dist: httpx>=0.25
19
+ Requires-Dist: keyring>=24
19
20
  Requires-Dist: mcp>=1.0.0
20
21
  Requires-Dist: pyyaml>=6.0
21
22
  Provides-Extra: dev
@@ -38,7 +38,7 @@ from agentnode_sdk.runtime import AgentNodeRuntime
38
38
  Client = AgentNodeClient
39
39
  ToolError = AgentNodeToolError
40
40
 
41
- __version__ = "0.12.0"
41
+ __version__ = "0.13.0"
42
42
  __all__ = [
43
43
  "AgentNode",
44
44
  "AsyncAgentNode",
@@ -0,0 +1,243 @@
1
+ """agentnode auth — credential management CLI.
2
+
3
+ Secrets are entered via getpass (never argv, never echoed) and only ever
4
+ shown masked (last 4 chars). Storage labels are honest: "OS keychain" or
5
+ "plaintext file" — never "encrypted"."""
6
+ from __future__ import annotations
7
+
8
+ import getpass
9
+ import os
10
+ import sys
11
+
12
+ from agentnode_sdk.credential_store import (
13
+ LLM_PROVIDER_ENV,
14
+ has_credential,
15
+ list_credentials,
16
+ load_credentials,
17
+ remove_credential,
18
+ set_credential,
19
+ )
20
+ from agentnode_sdk.installer import read_lockfile
21
+ from agentnode_sdk.cli.output import bold, dim, section
22
+
23
+
24
+ def _masked(token: str) -> str:
25
+ """Only ever show the last 4 chars of a secret."""
26
+ return "..." + token[-4:] if len(token) >= 8 else "..."
27
+
28
+
29
+ def _storage_short(storage: str) -> str:
30
+ return "OS keychain" if storage == "keyring" else "plaintext file"
31
+
32
+
33
+ def _llm_effective_source(provider: str) -> tuple[str | None, str]:
34
+ """(effective key or None, human-readable source) for an LLM provider.
35
+
36
+ Mirrors the runtime's resolution: env (incl. ~/.agentnode/.env) overrides
37
+ the stored credential. Uses metadata only for the stored check here —
38
+ the real keychain read happens in ``auth test``."""
39
+ from agentnode_sdk.runtimes.agent_runner import _load_agentnode_env
40
+ _load_agentnode_env()
41
+
42
+ env_var = LLM_PROVIDER_ENV[provider]
43
+ env_key = os.environ.get(env_var) or None
44
+ meta = load_credentials().get("providers", {}).get(provider)
45
+ stored = isinstance(meta, dict)
46
+ storage = (meta or {}).get("storage", "file")
47
+
48
+ if env_key and stored:
49
+ return env_key, f"env var {env_var} — overrides stored credential"
50
+ if env_key:
51
+ return env_key, f"env var {env_var}"
52
+ if stored:
53
+ return None, _storage_short(storage)
54
+ return None, "not configured"
55
+
56
+
57
+ def _resolve_auth_type(provider: str) -> str:
58
+ """Read auth_type from lockfile connector entry. Falls back to 'api_key'.
59
+
60
+ If multiple installed connectors share a provider with different auth
61
+ types, this returns the first match — may need disambiguation later.
62
+ """
63
+ lock = read_lockfile()
64
+ for _slug, info in lock.get("packages", {}).items():
65
+ connector = info.get("connector")
66
+ if isinstance(connector, dict) and connector.get("provider", "").lower() == provider:
67
+ return connector.get("auth_type", "api_key")
68
+ return "api_key"
69
+
70
+
71
+ def cmd_auth_set(provider: str, from_env: str | None = None) -> int:
72
+ provider = provider.lower().strip()
73
+ if not provider:
74
+ print(" Error: provider name required.", file=sys.stderr)
75
+ return 1
76
+ if from_env:
77
+ # Import an existing env key (also honors ~/.agentnode/.env). A flag,
78
+ # not a prompt — keeps piped-stdin flows intact.
79
+ from agentnode_sdk.runtimes.agent_runner import _load_agentnode_env
80
+ _load_agentnode_env()
81
+ token = (os.environ.get(from_env) or "").strip()
82
+ if not token:
83
+ print(f" Error: environment variable {from_env} is not set.", file=sys.stderr)
84
+ return 1
85
+ else:
86
+ try:
87
+ token = getpass.getpass(f" Enter access token for {provider}: ")
88
+ except (KeyboardInterrupt, EOFError):
89
+ print("\n Cancelled.")
90
+ return 130
91
+ token = token.strip()
92
+ if not token:
93
+ print(" Error: no token provided.", file=sys.stderr)
94
+ return 1
95
+ auth_type = _resolve_auth_type(provider)
96
+ storage = set_credential(provider, token, auth_type=auth_type)
97
+ if storage == "keyring":
98
+ where = "OS keychain"
99
+ else:
100
+ where = "plaintext file (0600) — OS keychain unavailable on this system"
101
+ print(f"\n Credential stored for {provider} ({_masked(token)}) — storage: {where}.\n")
102
+ return 0
103
+
104
+
105
+ def cmd_auth_list() -> int:
106
+ creds = list_credentials()
107
+ if not creds:
108
+ print("\n No credentials configured.")
109
+ print(dim(" Run `agentnode auth set <provider>` to store a credential.\n"))
110
+ return 0
111
+ print()
112
+ print(section("Credentials"))
113
+ print(f" {'Provider':<14}{'Auth type':<13}{'Storage':<16}{'Stored'}")
114
+ print(f" {'--------':<14}{'--------':<13}{'-------':<16}{'------'}")
115
+ for provider, info in sorted(creds.items()):
116
+ stored = info.get("stored_at", "")[:10]
117
+ auth_type = info.get("auth_type", "unknown")
118
+ storage = _storage_short(info.get("storage", "file"))
119
+ print(f" {provider:<14}{auth_type:<13}{storage:<16}{stored}")
120
+ print(f"\n {len(creds)} credential(s) configured.\n")
121
+ return 0
122
+
123
+
124
+ def cmd_auth_remove(provider: str) -> int:
125
+ provider = provider.lower().strip()
126
+ if remove_credential(provider):
127
+ print(f"\n Removed credential for {provider}.\n")
128
+ return 0
129
+ print(f"\n No credential found for {provider}.\n")
130
+ return 1
131
+
132
+
133
+ def cmd_auth_status() -> int:
134
+ # --- LLM providers (host runtime / sandbox broker) -----------------------
135
+ print()
136
+ print(section("LLM Providers"))
137
+ print(f" {'Provider':<14}{'Status':<16}{'Effective source'}")
138
+ print(f" {'--------':<14}{'------':<16}{'----------------'}")
139
+ for provider in sorted(LLM_PROVIDER_ENV):
140
+ key, source = _llm_effective_source(provider)
141
+ configured = key is not None or source not in ("not configured",)
142
+ status = "configured" if configured else "missing"
143
+ print(f" {provider:<14}{status:<16}{source}")
144
+ print(dim(" Env vars always override stored credentials. "
145
+ "Test a key: agentnode auth test <provider>"))
146
+
147
+ # --- connector packages (unchanged) --------------------------------------
148
+ lock = read_lockfile()
149
+ pkgs = lock.get("packages", {})
150
+
151
+ # Collect provider → list of slugs
152
+ provider_packages: dict[str, list[str]] = {}
153
+ for slug, info in pkgs.items():
154
+ connector = info.get("connector")
155
+ if isinstance(connector, dict) and connector.get("provider"):
156
+ provider = connector["provider"].lower().strip()
157
+ provider_packages.setdefault(provider, []).append(slug)
158
+
159
+ if not provider_packages:
160
+ print("\n No installed packages require connector credentials.\n")
161
+ return 0
162
+
163
+ print()
164
+ print(section("Credential Status"))
165
+ print(f" {'Provider':<14}{'Status':<16}{'Used by'}")
166
+ print(f" {'--------':<14}{'------':<16}{'------'}")
167
+ missing: list[str] = []
168
+ for provider in sorted(provider_packages):
169
+ configured = has_credential(provider)
170
+ status = "configured" if configured else "missing"
171
+ slugs = ", ".join(sorted(provider_packages[provider]))
172
+ print(f" {provider:<14}{status:<16}{slugs}")
173
+ if not configured:
174
+ missing.append(provider)
175
+
176
+ if missing:
177
+ print()
178
+ print(dim(" Fix missing:"))
179
+ for p in missing:
180
+ print(dim(f" agentnode auth set {p}"))
181
+ print()
182
+ return 0
183
+
184
+
185
+ # Free, cost-less validation endpoints (no completion call, no charge).
186
+ # anthropic REQUIRES the anthropic-version header (a 400 without it would be
187
+ # misread as a bad key); openrouter's /models is UNAUTHENTICATED (validates
188
+ # nothing) — /auth/key is the correct probe.
189
+ _TEST_REQUESTS = {
190
+ "openai": lambda key: (
191
+ "https://api.openai.com/v1/models",
192
+ {"Authorization": f"Bearer {key}"},
193
+ ),
194
+ "anthropic": lambda key: (
195
+ "https://api.anthropic.com/v1/models",
196
+ {"x-api-key": key, "anthropic-version": "2023-06-01"},
197
+ ),
198
+ "openrouter": lambda key: (
199
+ "https://openrouter.ai/api/v1/auth/key",
200
+ {"Authorization": f"Bearer {key}"},
201
+ ),
202
+ }
203
+
204
+
205
+ def cmd_auth_test(provider: str) -> int:
206
+ """Validate the EFFECTIVE key for an LLM provider (env beats vault) via a
207
+ free endpoint. Exit codes: 0 valid / 1 rejected (401/403) / 2 not
208
+ configured or unsupported / 3 indeterminate (network/5xx — never reported
209
+ as invalid). Never prints the key (masked last-4 only) and never echoes
210
+ the provider's response body (it can contain key fragments)."""
211
+ provider = provider.lower().strip()
212
+ if provider not in _TEST_REQUESTS:
213
+ supported = ", ".join(sorted(_TEST_REQUESTS))
214
+ print(f" auth test supports: {supported}", file=sys.stderr)
215
+ return 2
216
+
217
+ key, source = _llm_effective_source(provider)
218
+ if key is None:
219
+ # No env override — resolve the stored credential (real keychain read).
220
+ from agentnode_sdk.credential_store import get_llm_api_key
221
+ key = get_llm_api_key(provider)
222
+ if not key:
223
+ print(f"\n {provider}: not configured. Run `agentnode auth set {provider}`.\n")
224
+ return 2
225
+
226
+ url, headers = _TEST_REQUESTS[provider](key)
227
+ import httpx
228
+ try:
229
+ resp = httpx.get(url, headers=headers, timeout=10.0)
230
+ except Exception:
231
+ print(f"\n {provider} ({_masked(key)}, {source}): could not reach the "
232
+ "provider — key validity unknown.\n")
233
+ return 3
234
+ if resp.status_code == 200:
235
+ print(f"\n {provider} ({_masked(key)}, {source}): key is valid.\n")
236
+ return 0
237
+ if resp.status_code in (401, 403):
238
+ print(f"\n {provider} ({_masked(key)}, {source}): key was rejected by "
239
+ f"the provider (HTTP {resp.status_code}).\n")
240
+ return 1
241
+ print(f"\n {provider} ({_masked(key)}, {source}): unexpected provider "
242
+ f"response (HTTP {resp.status_code}) — key validity unknown.\n")
243
+ return 3
@@ -63,10 +63,14 @@ def main(argv: list[str] | None = None) -> int:
63
63
  auth_sub = auth_parser.add_subparsers(dest="auth_action")
64
64
  auth_set_p = auth_sub.add_parser("set", help="Store a credential for a provider")
65
65
  auth_set_p.add_argument("provider")
66
+ auth_set_p.add_argument("--from-env", default=None, metavar="ENV_VAR",
67
+ help="Import the key from this environment variable instead of prompting")
66
68
  auth_sub.add_parser("list", help="Show configured credentials")
67
69
  auth_rm_p = auth_sub.add_parser("remove", help="Remove a stored credential")
68
70
  auth_rm_p.add_argument("provider")
69
71
  auth_sub.add_parser("status", help="Check credential status for installed packages")
72
+ auth_test_p = auth_sub.add_parser("test", help="Validate a stored LLM key via a free provider endpoint")
73
+ auth_test_p.add_argument("provider")
70
74
 
71
75
  # config
72
76
  config_parser = sub.add_parser("config", help="View or modify settings")
@@ -270,15 +274,18 @@ def main(argv: list[str] | None = None) -> int:
270
274
  if args.command == "auth":
271
275
  from agentnode_sdk.cli.auth import (
272
276
  cmd_auth_set, cmd_auth_list, cmd_auth_remove, cmd_auth_status,
277
+ cmd_auth_test,
273
278
  )
274
279
  if args.auth_action == "set":
275
- return cmd_auth_set(args.provider)
280
+ return cmd_auth_set(args.provider, from_env=args.from_env)
276
281
  if args.auth_action == "list":
277
282
  return cmd_auth_list()
278
283
  if args.auth_action == "remove":
279
284
  return cmd_auth_remove(args.provider)
280
285
  if args.auth_action == "status":
281
286
  return cmd_auth_status()
287
+ if args.auth_action == "test":
288
+ return cmd_auth_test(args.provider)
282
289
  return cmd_auth_list()
283
290
  if args.command == "config":
284
291
  if args.config_action == "list":
@@ -41,6 +41,12 @@ DEFAULTS: dict[str, Any] = {
41
41
  "compute": "allow",
42
42
  "unknown": "prompt",
43
43
  },
44
+ "agent_sandbox": {
45
+ "enabled": False,
46
+ },
47
+ "llm": {
48
+ "default_provider": "openai",
49
+ },
44
50
  }
45
51
 
46
52
  VALID_VALUES: dict[str, tuple[str, ...]] = {
@@ -61,6 +67,8 @@ VALID_VALUES: dict[str, tuple[str, ...]] = {
61
67
  "guard.read": ("allow", "prompt", "deny"),
62
68
  "guard.compute": ("allow", "prompt", "deny"),
63
69
  "guard.unknown": ("allow", "prompt", "deny"),
70
+ "agent_sandbox.enabled": ("true", "false"),
71
+ "llm.default_provider": ("openai", "anthropic", "openrouter"),
64
72
  }
65
73
 
66
74
 
@@ -82,6 +90,8 @@ CONFIG_DESCRIPTIONS: dict[str, str] = {
82
90
  "guard.read": "Guard policy for tools that read data",
83
91
  "guard.compute": "Guard policy for tools that perform computation",
84
92
  "guard.unknown": "Guard policy for tools with unknown action type",
93
+ "agent_sandbox.enabled": "Route community (verified/unverified) agents through the container sandbox",
94
+ "llm.default_provider": "Which stored LLM credential to try first (vault resolution order)",
85
95
  }
86
96
 
87
97
 
@@ -138,6 +148,18 @@ def _merge_defaults(data: dict) -> dict[str, Any]:
138
148
  for extra_key in ("rate_limits", "agent_overrides", "tool_overrides"):
139
149
  if extra_key in data["guard"]:
140
150
  cfg["guard"][extra_key] = data["guard"][extra_key]
151
+ if isinstance(data.get("agent_sandbox"), dict):
152
+ if "enabled" in data["agent_sandbox"]:
153
+ cfg["agent_sandbox"]["enabled"] = data["agent_sandbox"]["enabled"]
154
+ # The nested llm ceiling (max_calls/max_input_chars/max_output_chars/
155
+ # allowed_models/enabled) holds ints/lists — pass it through verbatim,
156
+ # like the guard extra keys above.
157
+ if isinstance(data["agent_sandbox"].get("llm"), dict):
158
+ cfg["agent_sandbox"]["llm"] = data["agent_sandbox"]["llm"]
159
+ if isinstance(data.get("llm"), dict):
160
+ for k in ("default_provider",):
161
+ if k in data["llm"]:
162
+ cfg["llm"][k] = data["llm"][k]
141
163
  return cfg
142
164
 
143
165
 
@@ -201,7 +223,7 @@ def set_value(cfg: dict[str, Any], key: str, value: str) -> dict[str, Any]:
201
223
  f"Allowed: {', '.join(allowed)}"
202
224
  )
203
225
 
204
- bool_keys = ("credentials.require_before_auto_install",)
226
+ bool_keys = ("credentials.require_before_auto_install", "agent_sandbox.enabled")
205
227
  actual_value: Any = value.lower() == "true" if key in bool_keys else value.lower()
206
228
 
207
229
  parts = key.split(".")