Skip to content

Commit

Permalink
add sync integration rules workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
orouz committed Mar 13, 2024
1 parent 36b608b commit d856e33
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 0 deletions.
54 changes: 54 additions & 0 deletions .github/workflows/sync-rule-templates.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Sync CIS Rule Templates

on:
push:
branches:
- main
paths:
- "security-policies/bundle/compliance/**/rules/**/data.yaml"

env:
GITHUB_TOKEN: ${{ secrets.CLOUDSEC_MACHINE_TOKEN }}

jobs:
Sync-Templates:
name: Sync CIS Rule Templates
runs-on: ubuntu-22.04
timeout-minutes: 60
steps:
- name: Checkout Integrations repo
uses: actions/checkout@v4
with:
token: ${{ secrets.CLOUDSEC_MACHINE_TOKEN }}
repository: elastic/integrations
path: integrations
fetch-depth: 0

- name: Checkout Cloudbeat repo
uses: actions/checkout@v4
with:
token: ${{ secrets.CLOUDSEC_MACHINE_TOKEN }}
path: cloudbeat

- name: Init Hermit
working-directory: cloudbeat
run: ./bin/hermit env -r >> $GITHUB_ENV

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.9"

- name: Install Poetry
working-directory: cloudbeat
run: |
curl -sSL https://install.python-poetry.org | python3 -
poetry --version
- name: Install dependencies
working-directory: cloudbeat/security-policies
run: poetry install

- name: Sync CIS Rules with integrations repo
working-directory: cloudbeat
run: scripts/sync_rule_templates.sh
69 changes: 69 additions & 0 deletions scripts/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,72 @@ restart_agents() {
exec_pod $POD "elastic-agent restart"
done
}

bump_preview_version() {
local current_version="${1:?Missing current version}"
preview_number="${current_version##*-preview}"
((next_preview_number = 10#${preview_number} + 1))
echo "${current_version%-*}-preview$(printf "%02d" $next_preview_number)"
}

bump_minor_version() {
local version="${1:?Missing version}"
IFS='.' read -r major minor _ <<<"$1"
((minor++))
echo "$major.$minor.0"
}

get_integration_version() {
local changelog_path="${1:?Missing changelog.yml path}"
current_version=$(yq '.[0].version' "$changelog_path" | tr -d '"')
echo "$current_version"
}

get_new_integration_version_map_entry() {
local latest_version="${1:?Missing latest versions entry}"
IFS='-' read -r group1 group2 <<<"$latest_version"
IFS='.' read -r major1 minor1 _ <<<"$group1"
IFS='.' read -r major2 minor2 _ <<<"$group2"
((minor1++))
((minor2++))
local first_version="${major1}.${minor1}.x"
local second_version="$(echo "${major2}.${minor2}.x" | xargs)"
echo "$first_version - $second_version"
}

# bumps existing preview version: 1.0.0-preview01 -> 1.0.0-preview02, or
# creates a new preview version: 1.0.0 -> 1.1.0-preview01, and
# updates the manifest and changelog files
bump_integration_version() {
changelog_path="${1:?Missing changelog.yml path}"
manifest_path="${2:?Missing manifest.yml path}"
pr_url="${3:?Missing PR URL}"
changelog_description="${4:-Bump version}"
# exports required for yq's env()
export changelog_description
export pr_url
version="$(get_integration_version "$changelog_path")"
if [[ $version == *"preview"* ]]; then
next_version=$(bump_preview_version "$version")
export next_version
# update current version and add new changes entry
yq -i ".[0].version = \"$next_version\"" "$changelog_path"
yq -i '.[0].changes += [{"description": env(changelog_description), "type": "enhancement", "link": env(pr_url) }]' "$changelog_path"
else
next_version="$(bump_minor_version "$version")-preview01"
export next_version
# add new version + changes entry
yq -i '. = [{"version": env(next_version), "changes": [{"description": env(changelog_description), "type": "enhancement", "link": env(pr_url) }]}] + .' "$changelog_path"

# add new version map for integration - kibana
latest_entry="$(sed -n '3p' "$changelog_path")"
next_entry=$(get_new_integration_version_map_entry "$latest_entry")
sed -i '' -e '3i\'$'\n'"$next_entry" "$changelog_path"

# update manifest with new kibana version
IFS='-' read -r _ next_kibana_version <<<"$next_entry"
IFS='.' read -r major minor _ _ <<<"$(echo "$next_kibana_version" | xargs)"
yq -i ".conditions.kibana.version = \"^$major.$minor.0\"" "$manifest_path"
fi
yq -i ".version = \"$next_version\"" "$manifest_path"
}
80 changes: 80 additions & 0 deletions scripts/sync_rule_templates.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/bin/bash
set -euo pipefail

source scripts/common.sh

git config --global user.email "cloudsecmachine@users.noreply.github.com"
git config --global user.name "Cloud Security Machine"

branch_name="sync-cis-rule-templates"
repo="repos/elastic/integrations"
pr_number=$(gh api $repo/pulls -q ".[] | select(.head.ref == \"$branch_name\" and .state == \"open\") | .number")
templates_path="packages/cloud_security_posture/kibana/csp_rule_template"
manifest_path="packages/cloud_security_posture/manifest.yml"
changelog_path="packages/cloud_security_posture/changelog.yml"

# get new or existing sync-cis-rule-templates branch
cd ../integrations
if git fetch origin main "$branch_name" &>/dev/null; then
git checkout "$branch_name"
git reset origin/main --hard # reset to main, avoids conflicts
else
git checkout -b "$branch_name" origin/main
fi

# generate the rule templates
cd ../cloudbeat
poetry run -C security-policies python security-policies/dev/generate_rule_templates.py

# commit and push the changes
cd ../integrations
git add "$templates_path"
git commit -m "Sync CIS rule templates"
git push origin "$branch_name" -f

# create a PR if it doesn't exist and assign labels
if [[ -z "$pr_number" ]]; then
pr=$(gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/$repo/pulls \
-f title='[Cloud Security][TEST] Sync CIS rule templates' \
-f body='' \
-f head="$branch_name" \
-f base='main')

pr_number=$(echo "$pr" | jq -r '.html_url' | awk -F'/' '{print $NF}')

gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/$repo/issues/$pr_number/labels" \
-f "labels[]=Team:Cloud Security" -f "labels[]=enhancement"
fi

pr_url=$(gh api $repo/pulls -q ".[] | select(.head.ref == \"$branch_name\" and .state == \"open\") | .html_url")
bump_integration_version "$changelog_path" "$manifest_path" "$pr_url" "Add CIS rule templates"
git add "$changelog_path" "$manifest_path"
git commit -m "Bump integration version"
git push origin "$branch_name"

# create PR body
rows="$(git diff --name-only origin/main -- "$templates_path" | while read -r file; do jq --arg a "$pr_url/files#diff-$(echo -n "$file" | openssl dgst -sha256 | awk '{print $2}')" -r '.attributes.metadata.benchmark | "\(.id): \(.rule_number): \($a)"' "$file"; done | awk '{split($0, a, ": "); b[a[1]] = (b[a[1]] == "" ? "" : b[a[1]] ", ") "["a[2]"]""("a[3]")"} END {for (i in b) printf("| %s | %s |\n", i, b[i])}')"
body=$(
cat <<EOF
Added rule templates for CIS rules:
| benchmark.id | benchmark.rule_number |
|--------------|-----------------------|
$rows
EOF
)

# update PR body
gh api \
--method PATCH \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/elastic/integrations/pulls/$pr_number" \
-f body="$body"

0 comments on commit d856e33

Please sign in to comment.