feat(tools): add Creduent zero-trust agent verification tool (Closes #6773) - #6780
feat(tools): add Creduent zero-trust agent verification tool (Closes #6773)#6780cyberfascinate wants to merge 6 commits into
Conversation
📝 WalkthroughWalkthroughAdds ChangesCreduent verification integration
Sequence Diagram(s)sequenceDiagram
participant Caller
participant CreduentVerificationTool
participant CreduentVerify
Caller->>CreduentVerificationTool: provide agent_uri
CreduentVerificationTool->>CreduentVerify: verify agent_uri
CreduentVerify-->>CreduentVerificationTool: verification result or error
CreduentVerificationTool-->>Caller: success details or failure response
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Warning |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
lib/crewai-tools/tests/tools/test_creduent_verification_tool.py (2)
37-50: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winStrengthen the failure-message assertion to catch message corruption.
This test only checks
"Invalid signature" in str(exc_info.value). Because of the double-wrapping bug flagged increduent_verification_tool.py(Lines 58-75), the actual raised message becomes"Verification failure for {agent_uri}: Verification FAILED for {agent_uri}: Invalid signature"instead of the intended single-wrapped message, yet this test still passes. Assert the exact expected message (once the tool fix is applied) to catch this class of regression.✅ Proposed stronger assertion
- assert "Invalid signature" in str(exc_info.value) + assert str(exc_info.value) == ( + "Verification FAILED for agent://untrusted.dev/hacker: Invalid signature" + )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/crewai-tools/tests/tools/test_creduent_verification_tool.py` around lines 37 - 50, Update test_failed_verification_strict to assert the complete exact ValueError message, including the agent URI and the intended single “Verification FAILED” wrapper around “Invalid signature,” rather than checking substring inclusion. Keep the strict-mode setup and exception capture unchanged so the test detects double-wrapped or otherwise corrupted messages.
1-51: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a test for the missing-package fallback path.
No test covers the
ImportErrorbranch in_run(Lines 49-55 ofcreduent_verification_tool.py) wherecreduentis not installed and the tool returns an install-hint message. Add a test that simulates the missing import (e.g., patchingbuiltins.__import__or usingsys.modulesmanipulation) to confirm the fallback message is returned instead of raising.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/crewai-tools/tests/tools/test_creduent_verification_tool.py` around lines 1 - 51, Add a test covering the ImportError fallback in CreduentVerificationTool._run by simulating an unavailable creduent package, then invoke the tool and assert it returns the expected installation-hint message without raising. Preserve the existing verification tests and use import mocking or sys.modules manipulation to trigger the missing-package branch.Source: Path instructions
lib/crewai-tools/src/crewai_tools/tools/creduent_verification_tool/creduent_verification_tool.py (1)
9-19: 🚀 Performance & Scalability | 🔵 TrivialConsider validating the
agent://<namespace>/<name>format at the schema level.
agent_uriaccepts any string with no pattern constraint, even though the tool's contract is specificallyagent://<namespace>/<name>per the description and README. Adding apatternto theFieldwould reject malformed URIs before the lazy import and network-free crypto check, giving faster and clearer feedback to the calling agent.♻️ Optional pattern validation
agent_uri: str = Field( ..., description="Target agent URI to verify, formatted as agent://<namespace>/<name>", + pattern=r"^agent://[^/]+/[^/]+$", )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/crewai-tools/src/crewai_tools/tools/creduent_verification_tool/creduent_verification_tool.py` around lines 9 - 19, Add schema-level pattern validation to the agent_uri field in CreduentVerificationSchema so only values matching the documented agent://<namespace>/<name> format are accepted. Keep the existing field description and ensure malformed URIs are rejected before tool execution.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@lib/crewai-tools/src/crewai_tools/tools/creduent_verification_tool/creduent_verification_tool.py`:
- Around line 58-75: Separate the verify(agent_uri) call from the invalid-result
handling in the surrounding method so exceptions raised by verify are handled by
the generic error path, while the deliberate strict-mode ValueError for
result.valid == False bypasses it. Preserve the existing warning and exact
“Verification FAILED…” message for invalid results, and keep unexpected
exception logging and chaining unchanged.
- Around line 22-55: Wire the optional creduent dependency through
CreduentVerificationTool by declaring its package dependency, adding a
corresponding pyproject extra, and referencing that extra in the tool
documentation. Update test_creduent_verification_tool.py to provide a test-only
importable boundary or patch a local abstraction instead of requiring the
upstream creduent package to exist.
---
Nitpick comments:
In
`@lib/crewai-tools/src/crewai_tools/tools/creduent_verification_tool/creduent_verification_tool.py`:
- Around line 9-19: Add schema-level pattern validation to the agent_uri field
in CreduentVerificationSchema so only values matching the documented
agent://<namespace>/<name> format are accepted. Keep the existing field
description and ensure malformed URIs are rejected before tool execution.
In `@lib/crewai-tools/tests/tools/test_creduent_verification_tool.py`:
- Around line 37-50: Update test_failed_verification_strict to assert the
complete exact ValueError message, including the agent URI and the intended
single “Verification FAILED” wrapper around “Invalid signature,” rather than
checking substring inclusion. Keep the strict-mode setup and exception capture
unchanged so the test detects double-wrapped or otherwise corrupted messages.
- Around line 1-51: Add a test covering the ImportError fallback in
CreduentVerificationTool._run by simulating an unavailable creduent package,
then invoke the tool and assert it returns the expected installation-hint
message without raising. Preserve the existing verification tests and use import
mocking or sys.modules manipulation to trigger the missing-package branch.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: b36547a4-835b-419b-a4d7-ed1c9b6e0598
📒 Files selected for processing (5)
lib/crewai-tools/src/crewai_tools/tools/__init__.pylib/crewai-tools/src/crewai_tools/tools/creduent_verification_tool/README.mdlib/crewai-tools/src/crewai_tools/tools/creduent_verification_tool/__init__.pylib/crewai-tools/src/crewai_tools/tools/creduent_verification_tool/creduent_verification_tool.pylib/crewai-tools/tests/tools/test_creduent_verification_tool.py
| class CreduentVerificationTool(BaseTool): | ||
| """Tool for verifying agent identity using the Creduent protocol. | ||
|
|
||
| Performs local cryptographic signature verification (Ed25519) and canonical JCS RFC 8785 | ||
| attestation checks on target agent URIs. | ||
| """ | ||
|
|
||
| name: str = "Creduent Agent Identity Verification" | ||
| description: str = ( | ||
| "Verifies the cryptographic identity, signature, and attestations of a target AI agent " | ||
| "using the Creduent open protocol before delegating tasks." | ||
| ) | ||
| args_schema: type[BaseModel] = CreduentVerificationSchema | ||
| strict: bool = True | ||
|
|
||
| def _run(self, agent_uri: str) -> str: | ||
| """Execute verification of the target agent URI. | ||
|
|
||
| Args: | ||
| agent_uri: Target agent URI formatted as agent://<namespace>/<name>. | ||
|
|
||
| Returns: | ||
| String containing verification status message or error details. | ||
|
|
||
| Raises: | ||
| ValueError: If strict mode is enabled and verification fails. | ||
| """ | ||
| try: | ||
| from creduent.verify import verify | ||
| except ImportError: | ||
| return ( | ||
| "Error: creduent package is not installed. " | ||
| "Install it using: pip install creduent" | ||
| ) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check pyproject.toml for a creduent extra and confirm no other tool exposes package_dependencies for reference.
set -euo pipefail
fd -a pyproject.toml lib/crewai-tools | xargs -I{} sh -c 'echo "== {} =="; rg -n -A3 "creduent" {}'
rg -n "package_dependencies" lib/crewai-tools/src/crewai_tools/tools --iglob '*.py' -A2 | head -50Repository: crewAIInc/crewAI
Length of output: 215
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== pyproject creduent/package dependencies =="
rg -n -C 6 'creduent|optional-dependencies|dependencies|package_dependencies' lib/crewai-tools/pyproject.toml || true
echo
echo "== creduent references in pyproject and tool code ==" | sed -n '1p'
rg -n 'creduent|package_dependencies' lib/crewai-tools \
-g 'pyproject.toml' \
-g '*.py' | sed -n '1,200p'
echo
echo "== BUILDING_TOOLS dependency documentation =="
fd -a "BUILDING_TOOLS.md" . | while read -r f; do
echo "--- $f ---"
rg -n -C 5 'package_dependencies|optional-dependencies|additional dependencies|dependencies' "$f" || true
done
echo
echo "== target files =="
fd -a 'creduent_verification_tool.py|test_creduent_verification_tool.py' . | while read -r f; do
echo "--- $f ---"
wc -l "$f"
doneRepository: crewAIInc/crewAI
Length of output: 10931
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== pyproject creduent/package dependencies =="
rg -n -C 6 'creduent|optional-dependencies|dependencies|package_dependencies' lib/crewai-tools/pyproject.toml || true
echo
echo "== creduent references in pyproject and tool code ==" | sed -n '1p'
rg -n 'creduent|package_dependencies' lib/crewai-tools \
-g 'pyproject.toml' \
-g '*.py' | sed -n '1,200p'
echo
echo "== BUILDING_TOOLS dependency documentation =="
fd -a "BUILDING_TOOLS.md" . | while read -r f; do
echo "--- $f ---"
rg -n -C 5 'package_dependencies|optional-dependencies|dependencies|additional dependencies' "$f" || true
done
echo
echo "== target files =="
fd -a 'creduent_verification_tool.py|test_creduent_verification_tool.py' . | while read -r f; do
echo "--- $f ---"
wc -l "$f"
doneRepository: crewAIInc/crewAI
Length of output: 10931
Wire creduent as an optional dependency.
CreduentVerificationTool imports creduent.verify.verify, but it does not set package_dependencies: list[str] = ["creduent"], and lib/crewai-tools/pyproject.toml only declares extras for scrapfly-sdk and sqlalchemy. Add a creduent extra and reference it in the tool docs so installers can opt in.
test_creduent_verification_tool.py patches creduent.verify.verify, so the test/dev environment must make creduent importable even if the installed package lacks the actual package. Add a test-only dependency/fixture boundary or avoid patching the missing upstream library directly.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@lib/crewai-tools/src/crewai_tools/tools/creduent_verification_tool/creduent_verification_tool.py`
around lines 22 - 55, Wire the optional creduent dependency through
CreduentVerificationTool by declaring its package dependency, adding a
corresponding pyproject extra, and referencing that extra in the tool
documentation. Update test_creduent_verification_tool.py to provide a test-only
importable boundary or patch a local abstraction instead of requiring the
upstream creduent package to exist.
| try: | ||
| result = verify(agent_uri) | ||
| if result.valid: | ||
| return ( | ||
| f"Verification SUCCESS for {agent_uri}. " | ||
| "Agent identity and cryptographic attestations are trusted." | ||
| ) | ||
| error_msg = f"Verification FAILED for {agent_uri}: {result.error}" | ||
| logger.warning(error_msg) | ||
| if self.strict: | ||
| raise ValueError(error_msg) | ||
| return error_msg | ||
| except Exception as err: | ||
| error_msg = f"Verification failure for {agent_uri}: {str(err)}" | ||
| logger.error(error_msg) | ||
| if self.strict: | ||
| raise ValueError(error_msg) from err | ||
| return error_msg |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Fix double-wrapped error message on strict-mode failed verification.
The raise ValueError(error_msg) at Line 68 sits inside the same try block that Line 70's except Exception as err guards. When result.valid is False and self.strict is True, this raised ValueError is immediately re-caught by the outer except. The code then builds a second error_msg wrapping the first one, logs it again at error level (in addition to the warning already logged at Line 66), and raises a new ValueError chained from err.
The final message becomes "Verification failure for {agent_uri}: Verification FAILED for {agent_uri}: {result.error}" instead of the intended "Verification FAILED for {agent_uri}: {result.error}". This mislabels a normal failed-verification result as an unexpected exception, duplicates logging, and corrupts the message any caller inspects. The existing test only asserts "Invalid signature" in str(exc_info.value), which still passes despite the corrupted message, so this bug is not caught.
Separate the "call verify()" exception handling from the "handle an invalid result" logic so a deliberate raise ValueError for a failed result is not re-caught by the generic exception handler.
🐛 Proposed fix to separate exception handling from failed-result handling
- logger.info(f"Verifying target agent identity: {agent_uri}")
- try:
- result = verify(agent_uri)
- if result.valid:
- return (
- f"Verification SUCCESS for {agent_uri}. "
- "Agent identity and cryptographic attestations are trusted."
- )
- error_msg = f"Verification FAILED for {agent_uri}: {result.error}"
- logger.warning(error_msg)
- if self.strict:
- raise ValueError(error_msg)
- return error_msg
- except Exception as err:
- error_msg = f"Verification failure for {agent_uri}: {str(err)}"
- logger.error(error_msg)
- if self.strict:
- raise ValueError(error_msg) from err
- return error_msg
+ logger.info(f"Verifying target agent identity: {agent_uri}")
+ try:
+ result = verify(agent_uri)
+ except Exception as err:
+ error_msg = f"Verification failure for {agent_uri}: {str(err)}"
+ logger.error(error_msg)
+ if self.strict:
+ raise ValueError(error_msg) from err
+ return error_msg
+
+ if result.valid:
+ return (
+ f"Verification SUCCESS for {agent_uri}. "
+ "Agent identity and cryptographic attestations are trusted."
+ )
+ error_msg = f"Verification FAILED for {agent_uri}: {result.error}"
+ logger.warning(error_msg)
+ if self.strict:
+ raise ValueError(error_msg)
+ return error_msg🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@lib/crewai-tools/src/crewai_tools/tools/creduent_verification_tool/creduent_verification_tool.py`
around lines 58 - 75, Separate the verify(agent_uri) call from the
invalid-result handling in the surrounding method so exceptions raised by verify
are handled by the generic error path, while the deliberate strict-mode
ValueError for result.valid == False bypasses it. Preserve the existing warning
and exact “Verification FAILED…” message for invalid results, and keep
unexpected exception logging and chaining unchanged.
|
Great work on this @cyberfascinate — zero-trust agent identity verification is a real gap in multi-agent orchestration, and integrating it natively into crewai-tools is the right move. A few observations from our work on CCS (Common Component Standard for Agent Runtime Verification) that might be worth considering: Identity is necessary but not sufficientCreduent covers the Identity dimension well — Ed25519 signatures + JCS canonical attestation in <5ms is solid. But identity alone does not guarantee safe delegation. A verified agent can still:
This is exactly why we designed CCS as a 6-dimensional runtime verification framework: Structure, Schema, Latency, Cost, Identity, Integrity. Identity is one of six pillars, not the whole story. Practical suggestionThe Creduent tool here could serve as the Identity layer within a broader verification pipeline. For example, before delegating a task:
Our reference implementation On standardizationWe've submitted an IETF Internet-Draft for CCS to keep it vendor-neutral and open. Creduent's agent URI scheme ( Happy to collaborate on a conformance test suite or a joint reference implementation if the crewAI maintainers are interested. Either way, glad to see identity verification getting attention in the ecosystem. |
Summary
Adds
CreduentVerificationTooltocrewai-toolsto enable local zero-trust verification of external agent identities and attestations before task delegation.Proposed Changes
CreduentVerificationToolunderlib/crewai-tools/src/crewai_tools/tools/creduent_verification_tool/crewai_tools.toolsexportslib/crewai-tools/tests/tools/test_creduent_verification_tool.pyProtocol Verification
Performs local Ed25519 signature verification and canonical JCS RFC 8785 attestation validation on agent URIs (
agent://<namespace>/<name>) in under 5ms.Closes #6773