feat: add YAML ability file upload endpoint#3342
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an API v2 endpoint to upload abilities as YAML files, persisting them under data/abilities/{tactic}/ and loading them into the in-memory ability store, along with a new test module covering basic upload scenarios.
Changes:
- Added
POST /api/v2/abilities/uploadhandler for multipart YAML uploads. - Implemented
AbilityApiManager.upload_ability_file()to validate, write, and load uploaded abilities. - Added new API tests validating successful upload and common failure cases.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| tests/api/v2/handlers/test_ability_upload.py | New tests for the abilities upload endpoint (success + error status cases). |
| app/api/v2/managers/ability_api_manager.py | Implements the core upload/validate/save/load logic for ability YAML uploads. |
| app/api/v2/handlers/ability_api.py | Registers the new route and adds the multipart upload handler. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| loaded = self.find_objects('abilities', dict(ability_id=str(ability_id))) | ||
| if loaded: | ||
| return list(loaded)[0] |
| # Write the file | ||
| with open(file_path, 'wb') as f: | ||
| f.write(yaml.dump([parsed], encoding='utf-8', sort_keys=False)) |
|
|
||
| # Load into memory | ||
| allowed = self._get_allowed_from_access(access) | ||
| await self._data_svc.load_ability_file(file_path, allowed) |
| file_field = await reader.next() | ||
| if not file_field or file_field.name != 'file': |
| raise JsonHttpBadRequest('Missing required field: "name".') | ||
| tactic = parsed.get('tactic') | ||
| if not tactic: | ||
| raise JsonHttpBadRequest('Missing required field: "tactic".') |
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
…date swaggerdocs and confirm security:
…m JSON create ability API endpoint
|
Overall comment - confirm the intent of this endpoint, and how usage would look (form YAML upload with filename, or include YAML in request [very similar to normal create just unwrapping YAML vs JSON]) |
… on caldera api to be more similar to adversary upload api
|
|
Working on compatibility with mitre/magma#97 for UI capability |
|
|
|



Summary
POST /api/v2/abilities/uploadendpoint that accepts multipart YAML ability filesdata/abilities/{tactic}/{id}.yml, and loads into memory viadata_svc.load_ability_file()Test plan
POST /api/v2/abilities/uploadwith a valid YAML ability file returns 200 and the ability JSON