Security teams can adopt DevOps principals to standardize how rules are authored, reviewed, tested, and deployed. Here’s I’ve created a mock deployment using GitHub Actions.

This post walks through a complete end to end CI/CD example that mirrors a lightweight Git pipeline. It uses two GitHub workflows, a pull request review gate, and a mock deployment target using RequestBin. Everything runs inside GitHub, and nothing requires external infrastructure.


Overview

The goal is to simulate a DaC pipeline with these phases:

  1. Edit a rule file in a local repository.
  2. Push to a feature branch.
  3. Open a pull request.
  4. GitHub runs a validation workflow on the PR.
  5. Approve the PR.
  6. Merge into main.
  7. A deployment workflow packages the rule, encodes it, and sends it to a mock endpoint.

Repository Structure

Create a simple repo with a rules/ directory and GitHub workflow definitions under .github/workflows/.

mock-dac-pipeline/
├── rules/
│   └── windows_lateral_movement.yaml
└── .github/
    └── workflows/
        ├── pr-validate.yaml
        └── deploy.yaml

A rule file can contain any content for demonstration purposes:

title: windows_lateral_movement
description: test rule
severity: high

This repository acts as the source of truth for all rules.


Step 1: Set Up a Mock Deployment Target

You need an external API endpoint where the workflow can POST the deployed rule. RequestBin is a simple disposable endpoint that shows incoming requests.

Create one at:

https://requestbin.com

It produces an endpoint similar to:

https://asdfasdfasdfasdf.m.pipedream.net

Store this in a GitHub secret so it remains private.

In the repo:

Settings -> Secrets and variables -> Actions -> New repository secret

Name: REQUESTBIN_URL
Value: https://<your-id>.m.pipedream.net

Step 2: Create the PR Validation Workflow

The validation workflow inspects rule changes in a pull request and prints the resulting JSON payload to the logs. This simulates a DaC validation stage.

Create .github/workflows/pr-validate.yaml:

name: PR Validation

on:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  validate:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Identify changed rule files
        id: diff
        run: |
          changed=$(git diff --name-only origin/main...HEAD | grep '^rules/' || true)
          echo "changed=$changed" >> $GITHUB_OUTPUT
          echo "Changed files:"
          echo "$changed"

      - name: Stop if no rule changes
        if: ${{ steps.diff.outputs.changed == '' }}
        run: echo "No rule changes in this PR"

      - name: Build JSON preview
        if: ${{ steps.diff.outputs.changed != '' }}
        run: |
          files="${{ steps.diff.outputs.changed }}"
          json="[]"

          for f in $files; do
            sha=$(sha256sum "$f" | awk '{print $1}')
            name=$(basename "$f")
            content_b64=$(base64 -w0 "$f")

            json=$(echo "$json" | jq ". += [{\"name\": \"$name\", \"hash\": \"$sha\", \"content_b64\": \"$content_b64\"}]")
          done

          echo "Preview JSON payload:"
          echo "$json"

This workflow verifies rule changes without pushing anything. It gives you visibility into exactly what will be deployed after merge.


Step 3: Set Up Branch Protection and PR Approvals

For a realistic DaC workflow, enforce pull request approvals. In a real engineering environment, this would require sign off from peers or code owners.

In GitHub:

Settings -> Branches -> Add Rule

Enable:

  • Require a pull request before merging
  • Require approvals
  • Required number of approvals: 1

If you want to test solo, add a second GitHub account as a collaborator so you can assign and approve reviews.


Step 4: Create the Deployment Workflow

The deployment workflow runs only on pushes to main. It packages rule files, base64 encodes content, and POSTs the payload to your mock endpoint.

Create .github/workflows/deploy.yaml:

name: Rule Deployment

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Identify changed rule files
        id: diff
        run: |
          echo "Before SHA: ${{ github.event.before }}"
          echo "After SHA:  ${{ github.sha }}"

          changed=$(git diff --name-only "${{ github.event.before }}" "${{ github.sha }}" | grep '^rules/' || true)

          echo "changed=$changed" >> $GITHUB_OUTPUT

      - name: Stop if no rule changes
        if: ${{ steps.diff.outputs.changed == '' }}
        run: echo "No rule changes detected"

      - name: Build JSON payload
        if: ${{ steps.diff.outputs.changed != '' }}
        id: build
        run: |
          files="${{ steps.diff.outputs.changed }}"
          json="[]"

          for f in $files; do
            sha=$(sha256sum "$f" | awk '{print $1}')
            name=$(basename "$f")
            content_b64=$(base64 -w0 "$f")

            json=$(echo "$json" | jq ". += [{\"name\": \"$name\", \"hash\": \"$sha\", \"content_b64\": \"$content_b64\"}]")
          done

          {
            echo "payload<<EOF"
            echo "$json"
            echo "EOF"
          } >> $GITHUB_OUTPUT

      - name: Send to RequestBin
        if: ${{ steps.build.outputs.payload != '' }}
        run: |
          curl -X POST \
            -H "Content-Type: application/json" \
            -d "${{ steps.build.outputs.payload }}" \
            "${{ secrets.REQUESTBIN_URL }}"

The last step sends the rule bundle to the secret URL. The resulting payload appears immediately in RequestBin for inspection.


Step 5: Full Workflow in Action

Create a Feature Branch

git checkout -b test-dac-change
echo "# new test change" >> rules/windows_lateral_movement.yaml
git commit -am "update rule"
git push --set-upstream origin test-dac-change

Open a Pull Request

GitHub automatically triggers the validation workflow. Under the Checks tab you can see:

  • Changed files
  • SHA256 hash
  • Base64 encoded rule contents
  • Generated JSON payload

This acts as your DaC review artifact.

Approve and Merge

Your second GitHub account (or collaborator) reviews and approves the PR.

Merge into main.

Deployment Workflow Executes

Under the Actions tab, the deployment workflow runs:

  • Detects changed rules
  • Encodes and packages them
  • Sends to the mock endpoint

You will see the incoming JSON payload in the RequestBin inspector.


Result

You now have:

  • A working CI/CD pipeline for mock Detection as Code
  • PR based approval gating
  • Payload bundling and encoding
  • Automated deployment using GitHub Actions
  • A fully contained environment suitable for demos and experimentation

This structure mirrors modern DaC implementations used in enterprise security engineering teams.


0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *