Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
0301ad2
update actions workflow
Kbayero May 19, 2026
b11df8a
fix(workflows): unblock PR checks on large diffs + private go modules
Kbayero May 19, 2026
b0c5b52
fix(approver): use english in sticky PR comments
Kbayero May 19, 2026
bd2c9d2
Feature/cleanup rules and filters (#2091)
JocLRojas May 21, 2026
9682d0d
fix[frontend](soar/create-rule): added fixed create/edit rule undefin…
AlexSanchez-bit May 21, 2026
81165da
feat[backed](elasticSearchService): added batch processing of request…
AlexSanchez-bit May 21, 2026
6e169dd
fix[frontend](socai): added default template for empty previous socai…
AlexSanchez-bit May 22, 2026
471839f
fix[frontend](build): added environment.ts (#2099)
AlexSanchez-bit May 22, 2026
8849f1b
fix[backend](visualizations): removed utm-geoip legacy index referenc…
AlexSanchez-bit May 22, 2026
b9d2e20
Hotfix/socai custom header (#2101)
AlexSanchez-bit May 23, 2026
bea7ab7
fix(frontend): update nginx from 1.19.5 to 1.30.1
osmontero May 25, 2026
5d3910b
Backlog/fix/socai module disabled (#2102)
AlexSanchez-bit May 26, 2026
c2fc584
Backlog/fix/tag rules (#2106)
AlexSanchez-bit May 29, 2026
007d88b
fix[frontend](alerts-view): added a loading indicator and improved fa…
AlexSanchez-bit May 29, 2026
a9d5d3e
fix(deps): patch 5 Dependabot vulnerabilities (2 critical, 1 high, 2 …
osmontero Jun 3, 2026
aaaf34a
fix(deps): upgrade golang.org/x/sys from v0.44.0 to v0.45.0
osmontero Jun 3, 2026
a21ec9d
fix[frontend](alerts-view): add a duplication avoid on alert filter f…
AlexSanchez-bit Jun 4, 2026
368721a
refactor(rules): drop "now-" prefix from within field (#2176)
JocLRojas Jun 9, 2026
9f3cb3a
fix[backend](tags): removed false positive alerts from releaseToOpen …
AlexSanchez-bit Jun 9, 2026
3d82da3
fix[installer](setup): added lock on installer final phase (#2180)
AlexSanchez-bit Jun 9, 2026
3430ab8
fix[frontend](alerts): properly handle update alerts errors (#2193)
AlexSanchez-bit Jun 12, 2026
6ed54fc
feat(rules/o365): add Inbox Forward Rule with Email Exfiltration dete…
developutm Jun 15, 2026
a18b528
feat(rules/o365): add Audit Log Purge detection rule (#2220)
developutm Jun 15, 2026
2a7c8c8
feat(rules/o365): add Admin Role/Permission Granted detection rule (#…
developutm Jun 15, 2026
7f1ee2a
feat(rules/o365): add Admin Role Assignment detection rule (#2218)
developutm Jun 15, 2026
d8e8255
refactor(rules/google): update GCP correlation rules (#2194)
JocLRojas Jun 15, 2026
6173802
feature(rules/google): add rule GCS Sensitive Data Access (#2187)
developutm Jun 15, 2026
6fe13a1
feature(rules/google): add rule GCS Bucket Deleted (#2186)
developutm Jun 15, 2026
8bd0067
Tune bruteforce correlation and drop unreliable PTH rule (#2192)
JocLRojas Jun 15, 2026
10a181d
feature(rules/google): add rule Privileged Role Granted - Owner or Ed…
developutm Jun 15, 2026
fcf9820
feature(rules/google): add rule Cloud Logging Sink Modified (#2189)
developutm Jun 15, 2026
e67fc13
feature(rules/google): add rule Firewall Open Ingress (#2182)
developutm Jun 15, 2026
03681bb
Update filters: GCP, Sophos XG, Windows (#2175)
JocLRojas Jun 15, 2026
118814c
feature(rules/google): add rule Audit Logging Configuration Changed (…
developutm Jun 15, 2026
c160fc7
Add GCP rule: IAM Policy Changed - Privilege Escalation (#2188)
developutm Jun 15, 2026
3fc6a0a
feature(rules/google): add rule Firewall Rule Deleted (#2183)
developutm Jun 15, 2026
6468c5f
feature(rules/google): add rule GCS Bucket Created (#2185)
developutm Jun 15, 2026
55d1a6a
fix(rules/google): rebalance CIA impact scores for GCP rules (#2227)
JocLRojas Jun 15, 2026
b6cad63
feat[ci](pr-review): severity-based merge gate; exclude rules/filters…
Kbayero Jun 15, 2026
26641de
Merge branch 'release/v11.2.9' of https://github.com/utmstack/UTMStac…
Kbayero Jun 15, 2026
ba43613
fix[ci](pr-review): don't gate routine go.mod/go.sum bumps as Tier 3
Kbayero Jun 16, 2026
8b51f2d
fix[backend](alert_responses): reduces schedule time to executeRespon…
AlexSanchez-bit Jun 16, 2026
80c844c
fix[backend](alert_responses): fixed powershell commands syntax error…
AlexSanchez-bit Jun 16, 2026
8badb0d
fix[backend](incident_response_audit): enabled filters on agents-with…
AlexSanchez-bit Jun 16, 2026
6678f62
fix[backend](compilance_reports): migrated compilance reports from ol…
AlexSanchez-bit Jun 16, 2026
a71113a
chore: update golang dependencies
Kbayero Jun 17, 2026
913e5e0
fix[installer]: add -a flag to docker system prune to remove unused i…
Kbayero Jun 17, 2026
9f58b4b
fix[ci]: fix changelog script failing when tag doesn't exist yet and …
Kbayero Jun 17, 2026
d290989
Merge remote-tracking branch 'origin/v11' into release/v11.2.10
Kbayero Jun 17, 2026
d959803
ci: simplify v11 pipeline to trigger on release events instead of pus…
Kbayero Jun 17, 2026
54347d5
Merge remote-tracking branch 'origin/v11' into release/v11.2.10
Kbayero Jun 17, 2026
ded8070
Merge branch 'v11' into release/v11.2.10
Kbayero Jun 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions .github/workflows/installer-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
required: true
type: string
environment:
description: 'Environment (dev, rc, or production)'
description: 'Environment (dev or production)'
required: true
type: string
prerelease:
Expand Down Expand Up @@ -188,14 +188,12 @@ jobs:
sudo /usr/local/bin/utmstack_installer

# ============================================
# V11 RC / Production - Build installer and upload to GitHub release.
# The `prerelease` input controls whether the GitHub Release is marked as
# a prerelease (rc) or a normal release (production).
# V11 Production - Build installer and upload to GitHub release.
# ============================================
build_v11_release:
name: Build V11 Installer for Release
runs-on: ubuntu-24.04
if: inputs.version_major == 'v11' && (inputs.environment == 'rc' || inputs.environment == 'production')
if: inputs.version_major == 'v11' && inputs.environment == 'production'
steps:
- name: Check out code
uses: actions/checkout@v4
Expand Down Expand Up @@ -228,7 +226,7 @@ jobs:
GONOPROXY: github.com/utmstack
GONOSUMDB: github.com/utmstack
run: |
echo "Building V11 Installer for prerelease (branch=prod)"
echo "Building V11 Installer for release (branch=prod)"
go build -o installer -v -ldflags "\
-X 'github.com/utmstack/UTMStack/installer/config.DEFAULT_BRANCH=prod' \
-X 'github.com/utmstack/UTMStack/installer/config.INSTALLER_VERSION=${{ inputs.version }}' \
Expand All @@ -243,6 +241,5 @@ jobs:
tag_name: ${{ inputs.version }}
body_path: /tmp/CHANGELOG.md
draft: false
prerelease: ${{ inputs.prerelease }}
files: |
./installer/installer
183 changes: 28 additions & 155 deletions .github/workflows/v11-deployment-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ on:
push:
branches:
- 'release/v11**'
- 'v11'
release:
types: [ released ]
types: [published]

jobs:
setup_deployment:
Expand Down Expand Up @@ -61,109 +60,34 @@ jobs:
echo "event_processor_tag=${{ vars.TW_EVENT_PROCESSOR_VERSION_DEV }}" >> $GITHUB_OUTPUT

# =====================================================================
# RCpush to v11
# PRODUCTIONrelease.published (prerelease or not)
#
# Tag derivation walks two CMs to handle both the normal flow and
# the hotfix flow without divergent code paths:
#
# 1. CM DEV gives us the candidate BASE (strip `-dev.N`).
# 2. CM PROD gives us the latest version already in production.
# 3. If BASE > PROD → use BASE. Normal flow.
# If BASE <= PROD → BASE is already released (hotfix scenario)
# so bump the patch of PROD instead. Avoids overwriting an
# already-shipped tag and matches the roll-forward policy.
# =====================================================================
elif ${{ github.event_name == 'push' && github.ref == 'refs/heads/v11' }}; then
ENVIRONMENT="rc"
CM_URL="https://cm.utmstack.com"
CM_DEV_URL="https://cm.dev.utmstack.com"
echo "Environment: $ENVIRONMENT"
echo "CM URL (target): $CM_URL"
echo "CM URL (source for base): $CM_DEV_URL"

DEV_RESPONSE=$(curl -s "${CM_DEV_URL}/api/v1/versions/latest")
LATEST_DEV_VERSION=$(echo "$DEV_RESPONSE" | jq -r '.version // empty')
echo "Latest dev version from CM DEV: $LATEST_DEV_VERSION"

if [ -z "$LATEST_DEV_VERSION" ]; then
echo "❌ No dev version found in CM DEV — cannot derive RC base. Push a release/v11.x.x branch first."
exit 1
fi

BASE=$(echo "$LATEST_DEV_VERSION" | sed -E 's/-dev\.[0-9]+$//')
echo "BASE derived from CM DEV: $BASE"

if [[ ! "$BASE" =~ ^v11\. ]]; then
echo "❌ Derived BASE '$BASE' is not a v11 release."
exit 1
fi

# Double-check against production to detect the hotfix scenario.
PROD_RESPONSE=$(curl -s "${CM_URL}/api/v1/versions/latest")
PROD_LATEST=$(echo "$PROD_RESPONSE" | jq -r '.version // empty')
echo "Latest production version from CM PROD: ${PROD_LATEST:-<none>}"

if [ -n "$PROD_LATEST" ]; then
# sort -V puts the higher semver last.
HIGHER=$(printf '%s\n%s\n' "$BASE" "$PROD_LATEST" | sort -V | tail -1)
if [ "$HIGHER" = "$BASE" ] && [ "$BASE" != "$PROD_LATEST" ]; then
# BASE is strictly newer than PROD — use it as-is.
TAG="$BASE"
echo "BASE ($BASE) > PROD ($PROD_LATEST) — using BASE as RC tag."
else
# PROD is >= BASE → BASE was already released (hotfix case).
# Bump the patch of PROD.
MAJOR_MINOR=$(echo "$PROD_LATEST" | sed -E 's/^(v[0-9]+\.[0-9]+)\.[0-9]+.*$/\1/')
PATCH=$(echo "$PROD_LATEST" | sed -E 's/^v[0-9]+\.[0-9]+\.([0-9]+).*$/\1/')
NEW_PATCH=$((PATCH + 1))
TAG="${MAJOR_MINOR}.${NEW_PATCH}"
echo "BASE ($BASE) <= PROD ($PROD_LATEST) — hotfix scenario. Bumping patch: $TAG"
fi
else
# CM PROD has no versions yet — use BASE.
TAG="$BASE"
echo "CM PROD is empty — using BASE as RC tag."
fi

echo "RC tag: $TAG"

echo "tag=$TAG" >> $GITHUB_OUTPUT
echo "environment=$ENVIRONMENT" >> $GITHUB_OUTPUT
echo "cm_url=$CM_URL" >> $GITHUB_OUTPUT
echo "event_processor_tag=${{ vars.TW_EVENT_PROCESSOR_VERSION_PROD }}" >> $GITHUB_OUTPUT

# =====================================================================
# PRODUCTION — release.released (non-prerelease publish)
#
# Production does NOT rebuild anything. The images, installer, and
# changelog are all artifacts of the RC run. The production trigger
# only needs to tell CM "this version is now available to community
# instances" via a promote endpoint (TODO: define and wire up).
# The tag is taken directly from the release event — no CM queries.
# Always runs a full build and deploys to our production instances.
# =====================================================================
elif ${{ github.event_name == 'release' && github.event.action == 'released' }}; then
ENVIRONMENT="production"
elif ${{ github.event_name == 'release' }}; then
CM_URL="https://cm.utmstack.com"
echo "Environment: $ENVIRONMENT"
echo "CM URL: $CM_URL"

TAG="${{ github.event.release.tag_name }}"
echo "Tag from release: $TAG"
echo "Event: release, tag=$TAG"

if [[ ! "$TAG" =~ ^v11\. ]]; then
echo "⏭️ Skipping: tag '$TAG' is not a v11 release."
exit 0
fi

echo "Environment: production (our instances)"
echo "CM URL: $CM_URL"

echo "tag=$TAG" >> $GITHUB_OUTPUT
echo "environment=$ENVIRONMENT" >> $GITHUB_OUTPUT
echo "environment=production" >> $GITHUB_OUTPUT
echo "cm_url=$CM_URL" >> $GITHUB_OUTPUT
echo "event_processor_tag=${{ vars.TW_EVENT_PROCESSOR_VERSION_PROD }}" >> $GITHUB_OUTPUT
fi

build_agent:
name: Build Agent Binaries
needs: [setup_deployment]
if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }}
if: ${{ needs.setup_deployment.outputs.tag != '' }}
runs-on: ubuntu-24.04
steps:
- name: Check out code into the right branch
Expand Down Expand Up @@ -263,7 +187,7 @@ jobs:
sign_agent_windows:
name: Sign Windows Agent Binaries
needs: [build_agent, setup_deployment]
if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }}
if: ${{ needs.setup_deployment.outputs.tag != '' }}
uses: ./.github/workflows/reusable-sign-agent.yml
with:
os: windows
Expand All @@ -283,7 +207,7 @@ jobs:
sign_agent_macos:
name: Sign macOS Agent Binaries
needs: [build_agent, setup_deployment]
if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }}
if: ${{ needs.setup_deployment.outputs.tag != '' }}
uses: ./.github/workflows/reusable-sign-agent.yml
with:
os: macos
Expand All @@ -297,7 +221,7 @@ jobs:
build_utmstack_collector:
name: Build UTMStack Collector
needs: [setup_deployment]
if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }}
if: ${{ needs.setup_deployment.outputs.tag != '' }}
runs-on: ubuntu-24.04
steps:
- name: Check out code into the right branch
Expand Down Expand Up @@ -331,7 +255,7 @@ jobs:
build_agent_manager:
name: Build Agent Manager Microservice
needs: [sign_agent_windows, sign_agent_macos, build_utmstack_collector, setup_deployment]
if: ${{ always() && needs.sign_agent_windows.result == 'success' && needs.sign_agent_macos.result == 'success' && needs.build_utmstack_collector.result == 'success' && needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }}
if: ${{ always() && needs.sign_agent_windows.result == 'success' && needs.sign_agent_macos.result == 'success' && needs.build_utmstack_collector.result == 'success' && needs.setup_deployment.outputs.tag != '' }}
runs-on: ubuntu-24.04
steps:
- name: Check out code into the right branch
Expand Down Expand Up @@ -425,7 +349,7 @@ jobs:
build_event_processor:
name: Build Event Processor Microservice
needs: [setup_deployment]
if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }}
if: ${{ needs.setup_deployment.outputs.tag != '' }}
runs-on: ubuntu-24.04
steps:
- name: Check out code into the right branch
Expand Down Expand Up @@ -483,7 +407,7 @@ jobs:
build_backend:
name: Build Backend Microservice
needs: [setup_deployment]
if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }}
if: ${{ needs.setup_deployment.outputs.tag != '' }}
uses: ./.github/workflows/reusable-java.yml
with:
image_name: backend
Expand All @@ -496,7 +420,7 @@ jobs:
build_frontend:
name: Build Frontend Microservice
needs: [setup_deployment]
if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }}
if: ${{ needs.setup_deployment.outputs.tag != '' }}
uses: ./.github/workflows/reusable-node.yml
with:
image_name: frontend
Expand All @@ -505,7 +429,7 @@ jobs:
build_user_auditor:
name: Build User-Auditor Microservice
needs: [setup_deployment]
if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }}
if: ${{ needs.setup_deployment.outputs.tag != '' }}
uses: ./.github/workflows/reusable-java.yml
with:
image_name: user-auditor
Expand All @@ -517,7 +441,7 @@ jobs:
build_web_pdf:
name: Build Web-PDF Microservice
needs: [setup_deployment]
if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }}
if: ${{ needs.setup_deployment.outputs.tag != '' }}
uses: ./.github/workflows/reusable-java.yml
with:
image_name: web-pdf
Expand All @@ -541,33 +465,28 @@ jobs:
steps:
- run: echo "✅ All builds completed successfully."

# AI changelog runs only on RC. Production reuses the same release notes
# because the GitHub Release was already created during RC.
generate_changelog:
name: Generate Changelog
needs: [all_builds_complete, setup_deployment]
if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment == 'rc' }}
if: ${{ needs.setup_deployment.outputs.tag != '' && github.event_name == 'release' }}
uses: ./.github/workflows/generate-changelog.yml
with:
current_tag: ${{ needs.setup_deployment.outputs.tag }}
secrets:
THREATWINDS_API_KEY: ${{ secrets.THREATWINDS_API_KEY }}
THREATWINDS_API_SECRET: ${{ secrets.THREATWINDS_API_SECRET }}

# Installer build runs only on RC. The resulting binary is uploaded to the
# GitHub Release as a prerelease asset. When the release is later promoted
# to non-prerelease (which triggers production), the installer is already
# there — no rebuild needed.
# Installer build runs on any GitHub release event (prerelease or not).
# The binary is uploaded to the release that triggered this pipeline.
build_installer_release:
name: Build & Upload Installer
needs: [generate_changelog, setup_deployment]
if: ${{ always() && needs.setup_deployment.result == 'success' && needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment == 'rc' && needs.generate_changelog.result != 'cancelled' }}
if: ${{ always() && needs.setup_deployment.result == 'success' && needs.setup_deployment.outputs.tag != '' && github.event_name == 'release' && needs.generate_changelog.result != 'cancelled' }}
uses: ./.github/workflows/installer-release.yml
with:
version: ${{ needs.setup_deployment.outputs.tag }}
version_major: v11
environment: rc
prerelease: true
environment: ${{ needs.setup_deployment.outputs.environment }}
changelog: ${{ needs.generate_changelog.outputs.changelog }}
secrets:
API_SECRET: ${{ secrets.API_SECRET }}
Expand All @@ -588,12 +507,10 @@ jobs:
CM_ENCRYPT_SALT: ${{ secrets.CM_ENCRYPT_SALT }}
CM_SIGN_PUBLIC_KEY: ${{ secrets.CM_SIGN_PUBLIC_KEY }}

# Publish a new version to CM. Runs for dev and rc — production does NOT
# re-publish because the rc run already registered v11.x.x in CM PROD.
publish_new_version:
name: Publish New Version to Customer Manager
needs: [all_builds_complete, generate_changelog, setup_deployment]
if: ${{ always() && needs.all_builds_complete.result == 'success' && needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }}
if: ${{ always() && needs.all_builds_complete.result == 'success' && needs.setup_deployment.outputs.tag != '' }}
runs-on: ubuntu-24.04
steps:
- name: Check out code
Expand All @@ -606,7 +523,7 @@ jobs:
TAG: ${{ needs.setup_deployment.outputs.tag }}
CM_URL: ${{ needs.setup_deployment.outputs.cm_url }}
run: |
# Use AI changelog for rc / production, generic for dev.
# Use AI changelog for production releases, generic for dev.
if [ "$ENVIRONMENT" != "dev" ] && [ -n "$CHANGELOG_CONTENT" ]; then
changelog="$CHANGELOG_CONTENT"
else
Expand Down Expand Up @@ -641,13 +558,10 @@ jobs:

echo "Response: $response"

# Schedule the freshly-published version. For dev, this targets the dev
# instance list; for rc, the RC instance list. Production does NOT use this
# job — promotion to community lives in `promote_to_community` below.
schedule:
name: Schedule release to our instances
needs: [publish_new_version, setup_deployment]
if: ${{ always() && needs.publish_new_version.result == 'success' && needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }}
if: ${{ always() && needs.publish_new_version.result == 'success' && needs.setup_deployment.outputs.tag != '' }}
runs-on: ubuntu-24.04
env:
ENVIRONMENT: ${{ needs.setup_deployment.outputs.environment }}
Expand All @@ -665,7 +579,6 @@ jobs:
instance_ids="${{ vars.SCHEDULE_INSTANCES_DEV }}"
auth_json='${{ secrets.CM_SERVICE_ACCOUNT_DEV }}'
else
# rc uses prod variables
instance_ids="${{ vars.SCHEDULE_INSTANCES_PROD }}"
auth_json='${{ secrets.CM_SERVICE_ACCOUNT_PROD }}'
fi
Expand Down Expand Up @@ -703,45 +616,5 @@ jobs:

echo "✅ Scheduled release for all instances with version $TAG"

promote_to_community:
name: Promote to Community
needs: [setup_deployment]
if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment == 'production' }}
runs-on: ubuntu-24.04
env:
TAG: ${{ needs.setup_deployment.outputs.tag }}
CM_URL: ${{ needs.setup_deployment.outputs.cm_url }}
steps:
- name: Schedule update for all community instances
run: |
echo "🚀 Promoting $TAG to community"
echo " CM URL: $CM_URL"

cmAuth=$(echo '${{ secrets.CM_SERVICE_ACCOUNT_PROD }}' | jq -r '.')
auth_id=$(echo "$cmAuth" | jq -r '.id')
auth_key=$(echo "$cmAuth" | jq -r '.key')

body=$(jq -n \
--arg version "$TAG" \
'{version: $version, edition: "community"}')

response=$(curl -sS -w "\n%{http_code}" -X POST "${CM_URL}/api/v1/updates" \
-H "Content-Type: application/json" \
-H "id: $auth_id" \
-H "key: $auth_key" \
-d "$body")

http_code=$(echo "$response" | tail -n1)
payload=$(echo "$response" | sed '$d')

echo "HTTP $http_code"
echo "Response: $payload"

if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then
echo "✅ Community broadcast scheduled for $TAG"
else
echo "❌ Community broadcast failed (HTTP $http_code)"
exit 1
fi


Loading