feat: support API specs and Postman collections as targets#866
feat: support API specs and Postman collections as targets#8665h4d0wr007 wants to merge 12 commits into
Conversation
Greptile SummaryAdds API-contract targets throughout the CLI and scan-input pipeline.
Confidence Score: 1/5This PR is not safe to merge until live Postman targets can start, API inventories preserve common schema semantics, and specifications cannot expand authorized testing scope. The documented live Postman path raises a key error, common OpenAPI and Swagger constructs produce incorrect endpoint inventories, and spec-controlled server URLs are promoted directly into the platform-verified authorization set. strix/interface/main.py, strix/interface/utils.py, strix/core/api_spec.py, strix/core/inputs.py
|
| Filename | Overview |
|---|---|
| strix/core/api_spec.py | Implements the new parser and Postman integration, but mishandles explicit no-auth overrides and drops body fields from referenced schemas. |
| strix/interface/main.py | Adds fail-fast API-spec validation, but a mismatched Postman identifier key prevents every live Postman target from starting. |
| strix/interface/utils.py | Adds content-based local-spec detection and Postman URI parsing; its normalized collection_uid key is not consumed consistently by the CLI. |
| strix/core/inputs.py | Threads API inventories into root tasks but authorizes every spec-declared host without requiring an independently selected target. |
| strix/config/settings.py | Adds the aliased Postman API-key integration setting consistently with the existing configuration model. |
| tests/test_api_spec.py | Covers primary parser paths but omits referenced request schemas and operation-level empty security overrides. |
| tests/test_api_spec_targets.py | Covers target and scope wiring but does not exercise the full CLI parsing path or constrain spec-declared hosts to explicit targets. |
Prompt To Fix All With AI
Fix the following 4 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 4
strix/interface/main.py:659
**Postman identifier key mismatch**
When a fresh scan uses `postman://<collection-uid>`, target inference stores the identifier as `collection_uid`, but this validation branch reads `collection_uuid`, causing a `KeyError` before the collection is fetched.
### Issue 2 of 4
strix/core/api_spec.py:237
**Empty security override is lost**
When an operation declares `security: []` under a nonempty global security policy, the falsy result falls back to `global_security`, incorrectly labeling an explicitly unauthenticated endpoint as authenticated and giving the agent the wrong testing context. The Swagger branch at line 287 has the same behavior.
### Issue 3 of 4
strix/core/api_spec.py:198-202
**Referenced body fields are dropped**
When an OpenAPI request body uses a local `$ref` or schema composition such as `allOf`, this code only checks direct `schema.properties` and emits an empty field list, removing declared body fields from the agent's endpoint inventory and operation-specific testing context.
### Issue 4 of 4
strix/core/inputs.py:138-140
**Spec URLs bypass target authorization**
When a supplied specification declares an unrelated server URL, this code promotes that URL directly into the platform-verified authorized target list without matching it against an explicit user-selected host, causing the autonomous scanner to treat the unrelated host as approved for active pentesting.
Reviews (1): Last reviewed commit: "feat: support API specs and Postman coll..." | Re-trigger Greptile
| if target_dict.get("source") == "postman_api": | ||
| postman_key = load_settings().integrations.postman_api_key or "" | ||
| inventory = parse_postman_api( | ||
| target_dict["collection_uuid"], |
There was a problem hiding this comment.
Postman identifier key mismatch
When a fresh scan uses postman://<collection-uid>, target inference stores the identifier as collection_uid, but this validation branch reads collection_uuid, causing a KeyError before the collection is fetched.
Knowledge Base Used: CLI and Runner: from strix invocation to a running scan
Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/interface/main.py
Line: 659
Comment:
**Postman identifier key mismatch**
When a fresh scan uses `postman://<collection-uid>`, target inference stores the identifier as `collection_uid`, but this validation branch reads `collection_uuid`, causing a `KeyError` before the collection is fetched.
**Knowledge Base Used:** [CLI and Runner: from `strix` invocation to a running scan](https://app.greptile.com/strix-org-3/-/custom-context/knowledge-base/usestrix/strix/-/docs/cli-and-runner.md)
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Fixed: postman://… now fails cleanly via parser.error (e.g. 401 Check POSTMAN_API_KEY) instead of crashing, and ?env= is now honoured cleanly(issue bc of an accidental previous commit).
| for p in (*shared_params, *(op.get("parameters", []) or [])) | ||
| if isinstance(p, dict) | ||
| ] | ||
| op_security = _security_names(op.get("security")) or global_security |
There was a problem hiding this comment.
Empty security override is lost
When an operation declares security: [] under a nonempty global security policy, the falsy result falls back to global_security, incorrectly labeling an explicitly unauthenticated endpoint as authenticated and giving the agent the wrong testing context. The Swagger branch at line 287 has the same behavior.
Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/core/api_spec.py
Line: 237
Comment:
**Empty security override is lost**
When an operation declares `security: []` under a nonempty global security policy, the falsy result falls back to `global_security`, incorrectly labeling an explicitly unauthenticated endpoint as authenticated and giving the agent the wrong testing context. The Swagger branch at line 287 has the same behavior.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
In OpenAPI/Swagger, security: [] on an operation is an explicit opt-out that overrides a non-empty global policy; a missing security key is what inherits the global.
Verified: /public (security: []) → []; /private (no key) -> inherits global.
| for media in content.values(): | ||
| schema = media.get("schema") if isinstance(media, dict) else None | ||
| props = schema.get("properties") if isinstance(schema, dict) else None | ||
| if isinstance(props, dict): | ||
| return list(props.keys()) |
There was a problem hiding this comment.
Referenced body fields are dropped
When an OpenAPI request body uses a local $ref or schema composition such as allOf, this code only checks direct schema.properties and emits an empty field list, removing declared body fields from the agent's endpoint inventory and operation-specific testing context.
Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/core/api_spec.py
Line: 198-202
Comment:
**Referenced body fields are dropped**
When an OpenAPI request body uses a local `$ref` or schema composition such as `allOf`, this code only checks direct `schema.properties` and emits an empty field list, removing declared body fields from the agent's endpoint inventory and operation-specific testing context.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Fixed: referenced/composed request bodies drop the fields.
| authorized.extend( | ||
| {"type": "web_application", "value": base_url, "workspace_path": ""} | ||
| for base_url in inventory.base_urls |
There was a problem hiding this comment.
Spec URLs bypass target authorization
When a supplied specification declares an unrelated server URL, this code promotes that URL directly into the platform-verified authorized target list without matching it against an explicit user-selected host, causing the autonomous scanner to treat the unrelated host as approved for active pentesting.
Knowledge Base Used: CLI and Runner: from strix invocation to a running scan
Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/core/inputs.py
Line: 138-140
Comment:
**Spec URLs bypass target authorization**
When a supplied specification declares an unrelated server URL, this code promotes that URL directly into the platform-verified authorized target list without matching it against an explicit user-selected host, causing the autonomous scanner to treat the unrelated host as approved for active pentesting.
**Knowledge Base Used:** [CLI and Runner: from `strix` invocation to a running scan](https://app.greptile.com/strix-org-3/-/custom-context/knowledge-base/usestrix/strix/-/docs/cli-and-runner.md)
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Expected. A spec/collection under pentest is expected to have user verified URLs. But to add an extra control, here's the new design: the environment-driven workflow is intentional, so a spec/collection self-authorizes the hosts it declares when no explicit host is given (strix -t postman://?env= still works with no -t). When the user also passes explicit -t targets, those act as an allow-list that narrows the declared URLs, so a stray example/prod server can't expand scope past what the user selected. See _explicit_target_hosts.
Verified: env-only -> declared base URLs authorized; spec + explicit host -> only the matching host kept, unrelated declared hosts dropped. Tests updated in tests/test_api_spec_targets.py (self-authorize, narrowing, and match cases).
|
@5h4d0wr007 i think the idea is great -- wanna review the greptile findings? |
5h4d0wr007
left a comment
There was a problem hiding this comment.
@bearsyankees - these are all reviewed and updated. Please feel free to verify and re-run Greptile. Cheers!
Closes (#844)
Summary
Adds an
api_spectarget type so Strix can be pointed directly at an API contract instead of only crawling a live URL. The declared endpoints are parsed into the agent's task and the spec's base URLs are authorized as in-scope hosts, so the agent tests the full declared surface - including endpoints that aren't reachable by crawling (with correct parameter, body, and auth context).Three input forms, all via
--target:.json/.yaml).json)postman://<collection-uuid>, optionally?env=<environment-uuid>to resolve{{variables}}from a Postman environmentMotivation
For an API, the only prior option was passing a base URL as a
web_applicationtarget and relying on discovery (crawling, fuzzing, JS parsing). That misses endpoints with no UI link (internal, mobile-backing, partner APIs), doesn't know declared parameter types or request bodies, and provides no systematic per-endpoint coverage. Most teams already have an OpenAPI document or a Postman collection describing exactly this surface, so feeding it in directly makes API pentests far more complete and deterministic.What's included
api_spectarget type: detected ininfer_target_type(spec files by content,postman://by scheme). Parsed into a normalized endpoint inventory (method, path, parameters, body fields, auth, base URLs).strix/core/api_spec.py) for OpenAPI 3.x, Swagger 2.0, and Postman v2.1, with defensive parsing and size/recursion guards.fetch_postman_collection(GET /collections/{uid}) and optionalfetch_postman_environment(GET /environments/{uid}) via the official API usingPOSTMAN_API_KEY.{{vars}}from the collection variable block, merged with (and overridden by) the environment, resolve in the URL/path, headers, request body, and query keys. Colon-style path variables (/pets/:id) are normalized to{id}and registered as path parameters.strix/core/inputs.py): the inventory renders into the root task; the spec's base URLs are authorized as in-scope web targets.api_spec_testingskill: guiding spec-driven methodology (BOLA/BFLA, mass assignment, per-type injection, coverage tracking).--targetCLI help + examples,docs/usage/cli.mdx, andPOSTMAN_API_KEYindocs/advanced/configuration.mdx.tests/test_api_spec.py(parser, fetch, environment, variable/path/auth/body extraction) andtests/test_api_spec_targets.py(target detection + input/scope wiring).Usage
Pairing the spec with the deployed base URL gives the agent both the endpoint inventory and a reachable host to attack (if Postman environment file UUID is not provided).
Design notes
api_spectarget is validated (file parsed / collection fetched) during CLI arg parsing, so a bad key, missing collection, or empty spec errors immediately with an actionable message.Known limitations / possible future work
localhostaren't rewritten to the sandbox host gateway the way an explicit--targetURL is; pass the reachable host explicitly for local targets.Testing
uv run pytest tests/test_api_spec.py tests/test_api_spec_targets.py -vpostman://…?env=…collection.