If incase you have followe d my previous projects and have done with the projects lets move even more further advancing it by integrating the secure ci/cd project with soc automation
by now you would have understood to start the vm connect to your ssh of wazuh and thehive Start your VMs and on the Linux machine where your SOC tools are installed, run these commands one by one:
this are commands below to restart you're wazuh instance
sudo systemctl start wazuh-manager
sudo systemctl status wazuh-manager
this commands are for the hive
sudo systemctl start elasticsearch
sudo systemctl status elasticsearch
sudo systemctl start filebeat
sudo systemctl status filebeat
sudo systemctl start cassandra
sudo systemctl status cassandra
sudo systemctl start thehive
sudo systemctl status thehive


Check your GitHub repo for the Secure CI/CD project
Now do only this:
Open your GitHub repository for the secure CI/CD project and check whether these are already present:
- sample app code
.github/workflows/- any workflow file like
ci.ymlormain.yml - check in ci.yml if the pipeline has this below steps ready. SAST,secrets scan,dependency scan,DAST,output/report handling

Add one more security scan for dependency vulnerabilities
Right now you have:
- SAST → Semgrep
- DAST → OWASP ZAP
But for proper secure CI/CD integration, you also need SCA for vulnerable packages.
- name: Run pip-audit Scan
run: |
pip install pip-audit
pip-auditwe are adding SCA (software composition analysis) basically this checks the packages you installed is safe or not (I hope you remeber where do we do this changes in )
if incase the VS code doesn't show up the semgrep scan try adding it again
1) Add Semgrep after Run app syntax check
- name: Run Semgrep Scan
run: |
pip install semgrep
semgrep scan --config auto
2) Add Flask start and OWASP ZAP after Scan Docker image with Trivy
- name: Start Flask App
run: |
nohup python app.py &
sleep 10
- name: Run OWASP ZAP Scan
uses: zaproxy/action-baseline@v0.12.0
with:
target: 'http://127.0.0.1:5000'
>run it in ther terminal of VS code
git add .github/workflows/ci.yml
git commit -m "Add Semgrep and OWASP ZAP to CI pipeline"
git push
we did find the semgrep is already finding an issuers of the projects
now change this above semgrep scan to this line so it converta to json file and send it to the wazuh
- name: Run Semgrep Scan
run: |
pip install semgrep
semgrep scan --config auto --json --output semgrep-report.json
git add .github/workflows/ci.yml
git commit -m "Generate Semgrep JSON report"
git push

Add one more step right after the Semgrep scan to upload that JSON file as a GitHub Actions artifact.
Paste this into ci.yml after the Semgrep step:
- name: Upload Semgrep report
uses: actions/upload-artifact@v4
with:
name: semgrep-report
path: semgrep-report.jsonThis saves the Semgrep report file in the workflow run so later we can use it for SOC integration.

git status
git add .github/workflows/ci.yml
git commit -m "semgrep uploaded file"
git push

In the above picture it means Semgrep JSON report file was successfully uploaded in GitHub Actions as an artifact named semgrep-report.
So now the scan result is not only shown on screen, it is also saved as a downloadable file, which we can later use to connect with Wazuh / SOC automation.
Add another step in ci.yml to also create a simple text log file from the Semgrep report.
This is useful because later it is easier to forward a simple log/text file into Wazuh.
Add this block after Upload Semgrep report:
Add another step in ci.yml to also create a simple text log file from the Semgrep report.
This is useful because later it is easier to forward a simple log/text file into Wazuh.
Add this block after Upload Semgrep report:Add this block right after Convert Semgrep JSON to text log:
- name: Upload Semgrep text log
uses: actions/upload-artifact@v4
with:
name: semgrep-log
path: semgrep-report.log
git add .github/workflows/ci.yml
git commit -m "Upload Semgrep text log artifact"
git push
Now let's move to Wazuh
sudo mkdir -p /var/log/semgrep
sudo touch /var/log/semgrep/semgrep-report.log
sudo chmod 644 /var/log/semgrep/semgrep-report.log
ls -l /var/log/semgrep/this creates the log location where wazuh will read the semgrep findings

sudo nano /var/ossec/etc/ossec.conf
<localfile>
<log_format>syslog</log_format>
<location>/var/log/semgrep/semgrep-report.log</location>
</localfile>ossec.conf is the main Wazuh configuration file. It tells Wazuh what logs to watch, where to read them from and how to process them

Now do only this on the Wazuh server:
sudo systemctl restart wazuh-manager
sudo systemctl status wazuh-manager
What proves the change was loaded is this line:
- Active: active (running)
and also the recent restart time:
- since Mon 2026–04–13 20:23:11 UTC; 24s ago
That means Wazuh restarted successfully after you edited ossec.conf, so it has reloaded the updated configuration.
Open the decoder/rules file area and first check whether a local rules file already exists:
ls -l /var/ossec/etc/rules/What we are going to do next is create a custom Wazuh rule so that when Semgrep log lines appear, Wazuh can recognize them as a security alert.

local_rules.xml already exists, so we will use this file for the custom Semgrep alert rule.<rule id="100500" level="10">
<match>Blocking</match>
<description>Semgrep security finding detected</description>
<group>semgrep,ci_cd,security_alert,</group>
</rule>rule idis just a unique number for each Wazuh rule. It should not repeat another rule number. It is not fully random, but people often choose a custom number range like100500,100501, etc for their own rules.matchtells Wazuh what word or text to look for in the log. In your case, if it seesBlocking, it triggers the rule.groupis like a tag/category name. It helps organize alerts, like putting them into folders such assemgrep,ci_cd, andsecurity_alert

Now we need to test whether Wazuh can detect a Semgrep-style finding.
On the Wazuh server, do only this:
echo "Blocking Semgrep security finding detected in CI/CD pipeline" | sudo tee -a /var/log/semgrep/semgrep-report.logWhy
This writes a test line into the Semgrep log file. Your custom Wazuh rule looks for the word Blocking, so this should trigger an alert.


rule.description: Semgrep security finding detectedrule.id: 100500rule.groups: semgrep, ci_cd, security_alertlocation:/var/log/semgrep/semgrep-report.log
That means the CI/CD → Semgrep log → Wazuh alert part is now working.


click on thehive
{
"title": "CI/CD Semgrep Alert",
"description": "Semgrep security finding received from Wazuh",
"severity": 3,
"source": "Wazuh",
"sourceRef": "semgrep-test-1",
"type": "external",
"tags": ["semgrep", "cicd", "wazuh"]
}


sudo nano /var/ossec/etc/ossec.conf
<integration>
<name>custom-webhook</name>
<hook_url>https://shuffler.io/api/v1/hooks/webhook_9db2dd6a-cebf-4ce1-a3f4-758c751b7396</hook_url>
<level>10</level>
<rule_id>100500</rule_id>
<alert_format>json</alert_format>
</integration>
sudo systemctl restart wazuh-manager
sudo systemctl status wazuh-managerOn the Wazuh server, trigger the test alert one more time so Wazuh sends it to Shuffle:
echo "Blocking Semgrep security finding detected in CI/CD pipelineWe are triggering it manually just for testing.
That command writes a fake Semgrep-style alert line into the log file so we can verify the full path works:
log file → Wazuh reads it → rule matches Blocking → alert is created → sent to Shuffle → then TheHive/email
In the real project, this line would not be typed by you manually. It would come from your CI/CD pipeline output/report
so incase you face an error in the execution in shuffle try running this command and check
curl -X POST "https://shuffler.io/api/v1/hooks/webhook_dd66026c-22ef-47db-acc4-d0eea74008cc" \
-H "Content-Type: application/json" \
-d '{
"title": "CI/CD Semgrep Alert",
"description": "Test alert sent directly from Wazuh server",
"source": "Wazuh",
"sourceRef": "semgrep-direct-test-1",
"severity": 3,
"type": "external",
"tags": ["semgrep","cicd","wazuh"]
}'


now we see that manual test is working so now we need to make changes in github ci.yml for automatically to trigger whenever we run semgrep
In your GitHub Actions ci.yml, add this step after Convert Semgrep JSON to text log:
- name: Create simple Semgrep alert line
run: |
echo "Blocking Semgrep security finding detected in CI/
git add .github/workflows/ci.yml
git commit -m "Update GitHub Actions workflow"
git push origin advanced-devsecopsadd this line after create simple semgrep alert line
- name: Send alert to Shuffle webhook (only if issues found)
run: |
if grep -q '"results": \[\]' semgrep-report.json; then
echo "No issues found, skipping alert"
else
curl -X POST "YOUR_SHUFFLE_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{\"title\":\"CI/CD Semgrep Alert\",\"description\":\"Semgrep security finding detected in CI/CD pipeline\",\"severity\":3,\"source\":\"GitHub Actions\",\"sourceRef\":\"semgrep-test-1\",\"type\":\"external\",\"tags\":[\"semgrep\",\"cicd\",\"github-actions\"]}"
fi
git add .github/workflows/ci.yml
git commit -m "Add Shuffle webhook step"
git push origin advanced-devsecopsChange the TheHive alert body from fixed test text to slightly better values.
Use this:
{
"title": "CI/CD Semgrep Alert",
"description": "Semgrep security finding detected from CI/CD pipeline and forwarded by Wazuh",
"severity": 3,
"source": "Wazuh",
"sourceRef": "semgrep-test-6",
"type": "external",
"tags": ["semgrep", "cicd", "wazuh", "security"]
}change the old password in app.py since it wasn't taking the previous password and git isn't seeing any differenc
password = "super_secret_test_999_xyz" api_key = "test_api_key_12345"



Replace this part:
- name: Send alert to Shuffle webhook (only if issues found)
run: |
if grep -q '"results": \[\]' semgrep-report.json; then
echo "No issues found, skipping alert"
else
curl -X POST "https://shuffler.io/api/v1/hooks/webhook_dd66026c-22ef-47db-acc4-d0eea74008cc" \
-H "Content-Type: application/json" \
-d "{\"title\":\"CI/CD Semgrep Alert\",\"description\":\"Semgrep security finding detected in CI/CD pipeline\",\"severity\":3,\"source\":\"GitHub Actions\",\"sourceRef\":\"semgrep-${GITHUB_RUN_ID}\",\"type\":\"external\",\"tags\":[\"semgrep\",\"cicd\",\"github-actions\"]}"
fichange this in shuffle which is for hive
{
"title": "$exec.title",
"description": "$exec.description",
"severity": $exec.severity,
"source": "$exec.source",
"sourceRef": "$exec.sourceRef",
"type": "$exec.type",
"tags": $exec.tags
}
git commit --allow-empty -m "Trigger pipeline"
git push origin advanced-devsecops
You now have a FULL DevSecOps + SOC Automation pipeline:
Flow:
- Code pushed to GitHub
- CI/CD pipeline runs
- Security tools scan:
- Gitleaks (secrets)
- Semgrep (SAST)
- Trivy (container scan)
- pip-audit (dependencies)
- Vulnerability detected
- Webhook triggered
- Shuffle processes it
- Alert created in TheHive
- Email notification sent