feat(gophish): add Gophish phishing campaign injector (#311) - #321
feat(gophish): add Gophish phishing campaign injector (#311)#321SamuelHassine wants to merge 7 commits into
Conversation
Launches phishing campaigns through a Gophish server and reports open/click/submit stats as human-response expectations. Wires the injector into the CircleCI build, publish and test matrices.
There was a problem hiding this comment.
Pull request overview
Adds a new gophish/ injector module to the OpenAEV injectors monorepo, implementing a thin Gophish REST API client + OpenAEV injector entrypoint + contract definition, and wires the injector into the CircleCI test/build/publish matrices.
Changes:
- Introduce the
gophish_injectorpackage (config loader, contracts, REST client, injector entrypoint) plus local dev artifacts (Dockerfile, compose, samples). - Add a minimal unit test suite for the Gophish client and contract builder.
- Update CircleCI matrices to include
gophishintest,build_docker_images, andpublish_images.
Reviewed changes
Copilot reviewed 18 out of 21 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| gophish/test/test_gophish.py | Adds unit tests for contract creation and basic REST client behavior (requests mocked). |
| gophish/test/init.py | Marks test directory as a package. |
| gophish/README.md | Documents injector purpose, usage/development, and icon requirements. |
| gophish/pyproject.toml | Defines packaging/dependencies and cmw metadata for the new injector. |
| gophish/manifest-metadata.json | Adds OpenAEV integration catalog metadata for the Gophish injector. |
| gophish/gophish_injector/openaev_gophish.py | Implements the injector entrypoint that creates/launches campaigns and reports results back to OpenAEV. |
| gophish/gophish_injector/img/README.md | Documents the expected icon asset placement/standard. |
| gophish/gophish_injector/contracts_gophish.py | Adds the Gophish campaign contract (fields + expectations). |
| gophish/gophish_injector/configuration/injector_config_override.py | Defines injector-level config overrides (id/name/icon filepath). |
| gophish/gophish_injector/configuration/gophish_config.py | Adds Gophish connection settings (base_url/api_key/verify_tls). |
| gophish/gophish_injector/configuration/config_loader.py | Wires OpenAEV + injector + gophish configs into a daemon Configuration. |
| gophish/gophish_injector/configuration/init.py | Marks configuration directory as a package. |
| gophish/gophish_injector/client/gophish_client.py | Implements a thin REST client for creating campaigns and fetching stats. |
| gophish/gophish_injector/client/init.py | Marks client directory as a package. |
| gophish/gophish_injector/init.py | Defines the package version marker. |
| gophish/Dockerfile | Adds multi-stage Docker build for the injector, including optional client-python override. |
| gophish/docker-compose.yml | Adds a compose service definition for running the injector container. |
| gophish/config.yml.sample | Adds a sample YAML config for local/dev runs. |
| gophish/.env.sample | Adds environment-variable sample values for Docker/compose usage. |
| gophish/.dockerignore | Adds docker ignore rules for local configs and caches. |
| .circleci/config.yml | Adds gophish to CircleCI test/build/publish matrices. |
Adds coverage for __init__, process_message and start to satisfy the codecov patch gate.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #321 +/- ##
==========================================
+ Coverage 69.27% 70.39% +1.12%
==========================================
Files 81 88 +7
Lines 3505 3665 +160
==========================================
+ Hits 2428 2580 +152
- Misses 1077 1085 +8
📢 Thoughts on this report? Let us know! 🚀 New features to boost your workflow:
|
- Load the injector icon defensively so a missing placeholder PNG no longer raises FileNotFoundError at startup (real artwork tracked in #305); log a warning and register without an icon instead. - Validate the mandatory campaign contract fields before calling the Gophish API and fail with a clear message listing the missing fields, rather than silently forwarding None values. - Emit execution_output_structured as a plain JSON object (campaign_id and stats) instead of double-encoded JSON wrapped in one-element lists, matching the sibling injector convention. - Extend tests to cover the missing-field validation, the flattened structured output shape, and the graceful missing-icon fallback.
Review and fix summaryReviewed the full changed files end to end (not just the diff) against sibling injector conventions (ai-redteam, netexec, nmap, teams, phishing) and Fixes applied
Verification
Follow-ups (non-blocking, out of scope here)
Blocker
|
The client-python override block used the bash-specific [[ ... ]] test, but the image is python:3.13-alpine whose /bin/sh is BusyBox ash, so the PYOAEV_GIT_BRANCH_OVERRIDE branch could be silently skipped. Switch to a POSIX [ -n "..." ] test with the variable quoted. Also expose the existing GOPHISH_VERIFY_TLS setting in .env.sample and docker-compose.yml so the TLS-verification option is configurable via the documented deployment path.
Second-pass review and fix summaryRe-ran the full review workflow after new review comments landed. Re-read every changed file end to end (not just the diff) and cross-checked against sibling injectors (nuclei, nmap, shodan, http-query) and New review comment addressed
Additional finding from the independent re-review
Verified good (no change needed)
Verification
Follow-ups (non-blocking, out of scope here)
Blocker
|
#311) - Default verify_tls to true (secure by default) in GophishConfig and the client, documenting the opt-out for self-signed / local servers in .env.sample and config.yml.sample. Skipping TLS verification exposed the API key to interception. - Validate injector_contract_id in process_message and fail with a clear "unsupported contract" error before calling the Gophish API, so a misrouted or stale-contract injection no longer produces confusing campaign-creation failures. - Send an explicit ISO 8601 UTC launch_date on campaign creation (defaults to now) instead of relying on the server clock for immediate launch. - Add tests for the unsupported-contract path, the launch_date payload and the secure verify_tls default.
Review and fix summary (final pass)Re-ran the full end-to-end review: re-read every changed file (not just the diff) against sibling injectors (nuclei, nmap, shodan, http-query, teams) and Review threads addressed (all resolved)
Tests
CI
Follow-ups (non-blocking, out of scope here)
Approval status
|
Improve operational diagnosability of the Gophish injector: - Log the injection failure at error level (with inject id) in the process_message exception path, per the common-implementation logging guidance, so container logs carry the failure context. - Enrich client HTTP error messages with the trimmed Gophish response body (which carries the actionable reason: missing template / page / group, permission or 404 details) instead of only the status line, and log it at error level via the previously unused client logger. - Cover the new behaviour: injector error logging, and campaign / stats HTTP errors including the response body.
Review and fix summary (diagnosability pass)Re-ran the full end-to-end review: re-read every changed file (not just the diff) against sibling injectors (nuclei, nmap, shodan, http-query, teams) and injector_common, addressed the remaining open review comments, and applied the fixes in 183249a. Review threads addressed (all resolved)
Independent finding fixed
Tests
CI
Follow-ups (non-blocking, out of scope here)
Approval status
|
Summary
gophishto the CircleCIbuild_docker_images,publish_imagesandtestmatrices.Notes
Review fixes
process_messagevalidatesinjector_contract_idand fails with a clear "unsupported contract" error before creating a campaign, so a misrouted or stale-contract injection no longer reaches the Gophish API.execution_output_structuredis a plain JSON object (campaign_id,stats) instead of double-encoded JSON wrapped in one-element lists.[ -n "..." ]test (quoted) so it evaluates correctly under the BusyBox/bin/shinpython:3.13-alpineinstead of the bash-only[[ ... ]]form.verify_tlsnow defaults totrueinGophishConfigand the client. The opt-out for self-signed / local servers is documented in.env.sampleandconfig.yml.sample. This avoids exposing the API key on untrusted networks.launch_date(defaults to now) for an unambiguous immediate launch instead of relying on the server clock.process_messageexception path now logs the failure at error level with the inject id (per the common-implementation logging guidance), and client HTTP errors surface the trimmed Gophish response body (missing template / page / group, permission or 404 details) in the returned message and logs, instead of only the status line. The previously unused client logger is now wired to these error paths.Test plan
Closes #311