ADO Branch Policy Violation Alert
Triggered on push events to Azure DevOps repos. Detects direct pushes to main or release branches that bypass branch policies (no PR, no reviewers). Posts an immediate alert to both a Teams security channel and a Slack dev channel with the committer, branch, commit hash, and repo name.
Provided as-is, without warranty of any kind. Review and test each pattern in a non-production environment before deploying it to live automations. See our Terms.
Overview
This flow monitors Azure DevOps repositories for direct pushes to protected branches (main, master, release/*) that bypass branch policies. When a push is detected that did not originate from a pull request merge, the flow sends immediate alerts to both a Microsoft Teams security channel and a Slack developer channel. Alerts include the committer name, branch, commit hash, and repository details.
Use Case
Branch policies are a critical guardrail in Azure DevOps — they enforce pull request reviews, build validation, and approval gates before code lands on protected branches. However, administrators or users with elevated permissions can bypass these policies with direct pushes. This flow provides a real-time detection and notification layer so that security and development teams are immediately aware when a bypass occurs, enabling rapid investigation and remediation.
Trigger scenario: A developer force-pushes directly to main without going through a pull request. Within 5 minutes, the flow detects the push event, determines it was not a PR merge commit, and fires alerts to Teams and Slack with full context.
Flow Architecture
When code is pushed (OnGitPush)
Azure DevOps — OnGitPushPolls the configured Azure DevOps repository for new push events every 5 minutes using the OnGitPush operation on the shared_visualstudioteamservices connector.
Initialize variables (6 in parallel)
Initialize variableSix parallel InitializeVariable actions hydrate environment variables into flow variables: varAdoOrganization, varAdoProject, varAdoRepository, varTeamsGroupId, varTeamsChannelId, and varSlackChannel. Each uses the @parameters('flowlibs_<SchemaName> (flowlibs_<schemaname>)') pattern.
Compose_Branch_Name
ComposeExtracts the short branch name from the trigger's refUpdates[0].name field by stripping the refs/heads/ prefix. Expression: replace(triggerBody()?['resource']?['refUpdates'][0]?['name'], 'refs/heads/', '').
Check_If_Protected_Branch
If conditionEvaluates whether the branch name starts with main, master, or release/. Expression: @or(startsWith(outputs('Compose_Branch_Name'), 'main'), startsWith(outputs('Compose_Branch_Name'), 'master'), startsWith(outputs('Compose_Branch_Name'), 'release/')).
- Get_Push_Details_Via_ADO — Azure DevOps HttpRequest action calls the ADO REST API to fetch full push details including commits. GET https://dev.azure.com/@{variables('varAdoOrganization')}/@{variables('varAdoProject')}/_apis/git/repositories/@{variables('varAdoRepository')}/pushes/@{triggerBody()?['resource']?['pushId']}?api-version=7.1
- Parse_Push_Details — Parses the JSON response from the ADO API call. Schema extracts pushedBy.displayName and commits[0].comment.
- Check_If_PR_Merge_Commit (If condition) — Checks whether the first commit comment does NOT start with 'Merged PR'. If not, the push bypassed branch policies. Expression: @not(startsWith(body('Parse_Push_Details')?['commits'][0]?['comment'], 'Merged PR')). When true: Post_Teams_Alert (PostMessageToConversation) sends an alert to the Teams security channel with committer, branch, commit comment, push ID and repo; Post_Slack_Alert (PostMessage) sends the same violation details to the configured Slack channel. When false: no action (PR merge — policy honored).
Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_AdoOrganization | String | <configure> | Azure DevOps organization name (the segment after dev.azure.com/). |
| flowlibs_AdoProject | String | <configure> | Azure DevOps project name within the organization. |
| flowlibs_ADORepository | String | <configure> | Target Azure DevOps repository name to monitor for branch policy violations. |
| flowlibs_TeamsGroupId | String | <configure> | Microsoft 365 Group ID for the Teams team that owns the alert channel. |
| flowlibs_TeamsChannelId | String | <configure> | Teams channel ID where security/violation alerts will be posted. |
| flowlibs_SlackChannel | String | <configure> | Slack channel name or ID where developer alerts will be posted. |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| Azure DevOps | shared_visualstudioteamservices | OnGitPush (trigger) HttpRequest |
| Microsoft Teams | shared_teams | PostMessageToConversation |
| Slack | shared_slack | PostMessage |
Note — All connections are referenced as solution connection references; the flow is portable between environments as long as a connection is mapped at import time.
Customization Guide
Almost every realistic variant of this flow can be implemented by changing environment variable values. A few cases require small edits inside the flow definition — those are called out explicitly below.
- Activate the flow
- Navigate to the FlowLibsAdoBranchPolicyViolationAlert solution in make.powerautomate.com, open the flow, and click Turn on. Ensure all six environment variables have current values for your target environment, and verify the three connection references (Azure DevOps, Teams, Slack) are authenticated with valid credentials.
- Adapt for different protected branches
- Modify the Check_If_Protected_Branch condition to include or exclude branch patterns. The default logic matches branches starting with main, master, or release/. Add startsWith() clauses to the @or() expression to cover additional patterns such as hotfix/ or develop.
- Add additional notification channels
- Add new actions after the Teams and Slack posts inside the 'not a PR merge' branch. Follow the connector-first pattern — use a real connector action (e.g., Outlook SendEmail, PagerDuty CreateIncident) rather than the built-in HTTP action so the flow keeps consistent auth and retry behavior.
- Change the polling interval
- Update the trigger's recurrence object. The current setting is frequency: Minute, interval: 5. Lower the interval for faster detection (at the cost of more API calls) or raise it for noisier repos.
Key Expressions
The flow is intentionally light on Power Fx / WDL gymnastics — the heaviest expressions are the branch-name concatenation and the approval outcome check. They are listed below in the order they appear in the flow.
EXPR.01Branch name extraction
Used in the Compose_Branch_Name step to strip the refs/heads/ prefix from the ref returned by the OnGitPush trigger.
EXPR.02Protected branch check
Evaluated by the Check_If_Protected_Branch condition; returns true when the push targets a guarded branch.
EXPR.03PR merge detection
Evaluated by the Check_If_PR_Merge_Commit condition; returns true when the first commit comment does NOT start with 'Merged PR', indicating a direct push that bypassed branch policies.
EXPR.04Environment variable parameter reference
Standard FlowLibs pattern for reading a solution-aware environment variable inside an Initialize variable action.
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.