fix(signature): realigning SignatureManager with specs (#284)#290
Conversation
|
🤖 [AI-generated] Hey @guzmud! 👋 Thanks a lot for opening PR #290 — really appreciate the contribution to OpenAEV! 🙏 I just had a quick look and I think the description could be enhanced a little to help reviewers get through it faster. I haven't changed anything in your description — just a gentle, optional suggestion:
No rush at all — thanks again for contributing to the project! 🚀 |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #290 +/- ##
==========================================
+ Coverage 73.19% 73.58% +0.39%
==========================================
Files 53 54 +1
Lines 2350 2404 +54
==========================================
+ Hits 1720 1769 +49
- Misses 630 635 +5
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
… java InjectExecutionAction enum (#284)
…ureOutputStructure (#284)
…ements in the POST envelope (#284) Also, provide a convenience function to build SignatureCallbackPayload from a SignatureOutputStructure and a ExecutionDetails, and move the normalize_signature_payload function into the relevant class
…and new API contract
…e into ExecutionSignature (#284) rational: pre/post metadata is now more managed by ExecutionDetails bonus: adding post_execution_update functions to both ExecutionSignature and ExecutionDetails
2ea960e to
2433e5c
Compare
compile_pre_execution_signatures becomes build_execution_signatures compile_post_execution_signatures becomes post_execution_updates build_payload is more OOP
94ce2c9 to
8ab72ed
Compare
8ab72ed to
9a6b7c4
Compare
|
Tested against The injector logs are the following: with line 3 (after "post execution updates") showcasing the Network-wise, we can see both the pre-existing callback and the new one are sent and accepted by the platform (HTTP 200 for both):
The JSON payload sent to the platform to the callback URL in the format ends up being |
|
Regarding the developer experience, pre-realigning the quick start was the following from pyoaev import OpenAEV
from pyoaev.signatures import (
SignatureManager,
NetworkInjectorConfig,
build_network_configs,
)
client = OpenAEV(url="https://openaev.example.com", token="my-token")
sm = SignatureManager(client)
# 1. Build typed injector configs (one per distinct target asset)
configs = build_network_configs(["10.0.0.1", "2001:db8::1", "target.example.com"])
# or hand-build them: NetworkInjectorConfig(target_ipv4="10.0.0.1")
# or build a list: [NetworkInjectorConfig(target_ipv4="10.0.0.1"), NetworkInjectorConfig(target_ipv6="2001:db8::1"), NetworkInjectorConfig(target_domain="target.example.com")]
# 2. Compile pre-execution signatures (category is carried by the config type)
pre = sm.compile_pre_execution_signatures(config=configs)
# 3. Run your tool...
# 4. Compile post-execution signatures
post = sm.compile_post_execution_signatures(pre, tool_output)
# 5. Build the wire payload
payload = sm.build_payload(post, expectation_types=["DETECTION"])
# 6. Send to backend
sm.send_signatures(inject_id="abc-123", phase="execution_complete", signatures=payload)The quick start is now the following from pyoaev import OpenAEV
from pyoaev.signatures import (
ExecutionDetails,
SignatureManager,
NetworkInjectorConfig,
build_network_configs,
)
client = OpenAEV(url="https://openaev.example.com", token="my-token")
sm = SignatureManager(client)
# 1. Create execution details
execution_details = ExecutionDetails()
# 2. Build typed injector configs (one per distinct target asset)
configs = build_network_configs(["10.0.0.1", "2001:db8::1", "target.example.com"])
# or hand-build them: NetworkInjectorConfig(target_ipv4="10.0.0.1")
# or build a list: [NetworkInjectorConfig(target_ipv4="10.0.0.1"), NetworkInjectorConfig(target_ipv6="2001:db8::1"), NetworkInjectorConfig(target_domain="target.example.com")]
# 3. Build execution signatures
execution_signatures = sm.build_execution_signatures(config=configs)
# 4. Run your tool...
# 5. Update post-execution elements
sm.post_execution_updates(execution_details, execution_signatures, tool_output)
# 6. Build the wire payload
payload = sm.build_payload(
execution_signatures=execution_signatures,
targets_meta=targets_meta, # can be obtained through the new `Targets.extract_target_meta` from `injector_common`
expectation_types=["DETECTION"] # should be dynamically obtained from the message processed
)
# 7. Send to backend
sm.send_signatures(inject_id="abc-123", execution_details=execution_details, signatures=payload) |
9a6b7c4 to
5646ab2
Compare
5646ab2 to
005315c
Compare
… signature manager (#284)
There was a problem hiding this comment.
Pull request overview
This PR realigns the Python client’s signature pipeline (modeling + transport + tests) with the updated OpenAEV backend callback spec, including the new callback endpoint, the updated outer envelope, and a revised approach to splitting oversized payloads.
Changes:
- Updates the callback endpoint to
/injects/execution/callback/{injectId}and adjusts transport accordingly. - Introduces/updates signature-related models to match the new POST envelope (e.g.,
ExecutionDetails,SignatureTarget,SignatureOutputStructure,InjectExecutionActions). - Replaces chunk-metadata-based payload chunking with sequential “self-contained envelope” splitting and updates BDD tests/features.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
pyoaev/apis/signature.py |
Updates callback path, envelope construction, retry logging, and replaces chunk metadata with envelope splitting. |
pyoaev/signatures/models.py |
Adds/updates Pydantic models for the new callback envelope and structured signature output; removes external injector config model. |
pyoaev/signatures/signature_manager.py |
Aligns SignatureManager APIs with the new models/envelope and delegates transport with new parameters. |
pyoaev/signatures/types.py |
Adds InjectExecutionActions enum to match backend execution action values. |
pyoaev/signatures/signature_type.py |
Tightens typing of match_score to `int |
pyoaev/signatures/__init__.py |
Exposes new signature types/enums and removes external injector config from exports. |
test/signatures/test_signature_manager_transmission.py |
Updates transmission tests to validate the new endpoint, envelope format, and envelope splitting behavior. |
test/signatures/test_signature_manager_pre_execution.py |
Updates pre-execution tests for the new ExecutionSignature return types and removed external category. |
test/signatures/test_signature_manager_post_execution.py |
Updates post-execution tests to reflect the new split between execution details vs execution signatures updates. |
test/signatures/features/signature_manager_transmission.feature |
Updates BDD feature steps to pass execution details and assert new endpoint/payload structure. |
test/signatures/features/signature_manager_pre_execution.feature |
Updates BDD feature steps for renamed pre-execution API and removed external category scenario. |
test/signatures/features/signature_manager_post_execution.feature |
Updates post-execution feature to the new “update models in-place” workflow. |
test/signatures/constraints/signature_manager_transmission_constraints.feature |
Updates constraints to assert envelope splitting (no chunk metadata) and new endpoint. |
test/signatures/constraints/signature_manager_pre_execution_constraints.feature |
Updates constraints to use build_execution_signatures. |
test/signatures/constraints/signature_manager_post_execution_constraints.feature |
Updates constraints to the new post-execution update flow. |
Comments suppressed due to low confidence (1)
test/signatures/test_signature_manager_pre_execution.py:356
- This step still uses dict-style membership ("field not in result"), but result is now an ExecutionSignature model. That assertion will always pass and no longer verifies that the field is omitted from the serialized payload. Check the model_dump(exclude_none=True) instead.
@then(parsers.parse("the returned dict does not contain {field}"))
def returned_dict_does_not_contain_field(result, field):
assert field not in result
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
c573afc to
34731f1
Compare
34731f1 to
06dfb65
Compare

Proposed changes
/api/injects/execution/callback/{injectId}as the targeted endpointSignatureTargetmodelInjectExecutionActions(mirroring https://github.com/OpenAEV-Platform/openaev/blob/bba8f2f2180f1a789f7be84144bc2562b62b93e6/openaev-api/src/main/java/io/openaev/rest/inject/form/InjectExecutionAction.java#L3) for the POST outer envelopeexecution_actionSignatureOutputStructureto validate the json dumped string that will be in the updatedSignatureCallbackPayloadexecution_output_structuredto the POST outer envelope (typing:strbut actually a json dumps ofSignatureOutputStructure)ExecutionDetailsto wrap non-execution_output_structuredelements of the outer POST envelopeSignatureOutputStructureandExecutionDetailsto produce the new updatedSignatureCallbackPayload(convenience class function providedbuild_from_models)Testing Instructions
Related issues
Checklist
Further comments