Development documentation
Under this section, you will find the development documentation of Wazuh Indexer. This documentation contains instructions to compile, run, test and package the source code. Moreover, you will find instructions to set up a development environment in order to get started at developing the Wazuh Indexer.
This documentation assumes basic knowledge of certain tools and technologies, such as Docker, Bash (Linux) or Git.
Before you start coding, read the sections below: they cover how to open good pull requests and how our GitHub Actions behave when you do. Getting this right up front saves CI minutes and review cycles for everyone.
Pull requests
These are the standard procedures for creating, updating, and reviewing pull requests across the Wazuh Indexer repositories.
Lifecycle
┌──────────┐ ┌──────────────┐ ┌─────────────────┐ ┌───────┐
│ Draft │───▶│ Local build │───▶│ Ready for │───▶│ Merge │
│ PR │ │ & test │ │ review (CI runs)│ │ │
└──────────┘ └──────────────┘ └─────────────────┘ └───────┘
Every pull request must start in Draft status. Workflows do not run on Draft PRs — this is enforced across all repositories to avoid wasting GitHub Actions minutes on work in progress — so use Draft status freely while iterating on your changes.
Before marking the PR as ready, build the project successfully and run the tests locally to verify they pass. This prevents avoidable CI failures that waste runner time and delay reviews. Once everything is complete and locally validated, click “Ready for review” and move the linked issue to Pending review. This is the moment workflows are triggered for the first time.
To address review feedback, push new commits on top of the branch and re-request review once you have resolved all comments. Avoid amending or rebasing published commits during review, and if CI fails after pushing, investigate and fix it before requesting re-review. When the PR is approved and CI passes, it can be merged. Use squash merge for single-purpose PRs to keep a clean history.
Body template
Use the following template when creating a pull request:
## Description
<!--
Provide a brief description of the problem this pull request addresses. Include relevant context to help reviewers understand the purpose and scope of the changes.
If this pull request resolves an existing issue, reference it here. For example:
Closes #<issue_number>
-->
## Proposed Changes
<!--
Summarize the changes made in this pull request. Include:
- Features added
- Bugs fixed
- Any relevant technical details
-->
### Results and Evidence
<!--
Provide evidence of the changes made, such as:
- Logs
- Screenshots
- Before/after comparisons
-->
### Artifacts Affected
<!--
List the artifacts impacted by this pull request, such as:
- Executables (specify platforms if applicable)
- Default configuration files
- Packages
-->
### Configuration Changes
<!--
If applicable, list any configuration changes introduced by this pull request, including:
- New configuration parameters
- Changes to default values
- Backward compatibility notes
-->
### Documentation Updates
<!--
If applicable, list the sections of documentation that have been updated as part of this pull request.
-->
### Tests Introduced
<!--
If applicable, describe any new unit or integration tests added as part of this pull request. Include:
- Scope of the tests
- Any relevant details about test coverage
-->
## Review Checklist
<!--
List any manual tests completed to verify the functionality of the changes. Include any manual tests that are still required for final approval.
-->
- [ ] Code changes reviewed
- [ ] Relevant evidence provided
- [ ] Tests cover the new functionality
- [ ] Configuration changes documented
- [ ] Developer documentation reflects the changes
- [ ] Meets requirements and/or definition of done
- [ ] No unresolved dependencies with other issues
- [ ] PR is linked to the relevant issue(s)
- [ ] Correct labels applied (e.g., `no-changelog`)
- [ ] ...
Always link the related issue with Resolves #<number> so it auto-closes on merge, and describe why rather than just what — the diff already shows what changed, so the description should explain the motivation.
Include instructions to test your changes, and any other relevant information for reviewers. Use the checklist to indicate that you have completed all required steps before requesting review.
Reviewing a PR
Start from the linked issue to understand the context and acceptance criteria, then read the description and checklist before reading the code. Focus your feedback on correctness, clarity, and maintainability, and use GitHub’s suggestion feature for small fixes to speed up the process. Approve only when you are confident the changes are correct and complete.
Changelog
Every PR is expected to include a changelog entry, classified as Added, Changed, Removed, or Fixed. The 5_codequality_changelog.yml workflow enforces this. Apply the no-changelog label to bypass the check when the linked issue belongs to a private repository, or when the PR genuinely does not require a changelog update.
Changelog entries must always reference the issue, not the pull request, so the entry stays meaningful independently of how the change was implemented. An issue only belongs in the changelog if it affects the product and represents a change from a previously released version — internal/CI changes are never included, and neither are fixes for problems introduced in an unpublished version.
Best practices
- Keep PRs small and focused. One issue per PR whenever possible.
- Write descriptive commit messages. They should explain why, not just what.
- Do not trigger CI unnecessarily. Keep PRs in Draft until ready, and validate locally first.
Workflows and Actions
This section defines the naming conventions and operational rules for the GitHub Actions and Workflows used across the Wazuh Indexer repositories.
Naming convention
Both Actions and Workflows follow the same pattern:
<major>_<prefix>_<target>
| Component | Description |
|---|---|
| Major | Product major version (e.g. 4, 5). |
| Prefix | Category prefix from the use cases below. |
| Target | The action target: a component, module, subsystem, tool, language, etc. |
The prefix is drawn from the following set of use cases:
| Use case | Prefix | Target | Example |
|---|---|---|---|
| Code analysis (static/dynamic) | codeanalysis | Code analysis tool | 4_codeanalysis_coverity |
| Linter / auto-docs | codelinter | Linter | 5_codelinter_clangformat |
Code quality (groups codeanalysis + codelinter) | codequality | Repository | 5_codequality_changelog |
| Unit tests | testunit | Module | 5_testunit_engine |
| Component tests | testcomponent | Component/module | 5_testcomponent_indexerconnector |
| Integration tests | testintegration | Module | 4_testintegration_cluster |
| Package builder | builderpackage | Subsystem | 4_builderpackage_server |
| Precompiled object builder | builderprecompiled | Subsystem | 5_builderprecompiled_agent |
| Version bumping | bumper | Repository | 5_bumper_repository |
For workflows triggered on PR or push events, append _onpush to the name to distinguish them from their workflow_dispatch counterparts:
5_builderpackage_indexer.yml ← workflow_dispatch (manual)
5_builderpackage_indexer_onpush.yml ← PR / push trigger (automatic)
When composing jobs from Actions, a single job step cannot mix Actions with different prefixes, and steps must use matrices whenever possible.
Runners
Two types of runners are available:
- Default (GitHub-hosted) — used for all workflows unless there is a justified reason to use the dedicated runner.
- Dedicated (self-hosted) — reserved for resource-intensive workflows only. Currently used exclusively by
5_builderpackage_indexer(the full package builder).
Always prefer the default runner. The dedicated runner is a shared, limited resource — use it only when the workflow genuinely requires the extra capacity (e.g. the full product builder).
Draft PR enforcement
All PR workflows must be configured to skip Draft PRs, so that no CI minutes are consumed on work-in-progress PRs. This is enforced by adding the following condition to every PR-triggered workflow:
on:
pull_request:
types: [opened, synchronize, ready_for_review]
jobs:
<job_name>:
if: ${{ !github.event.pull_request.draft }}