CI/CD workflows and pipelines

July 10, 2026 · View on GitHub

GitHub Actions workflows live under .github/workflows/; Azure DevOps pipelines live under Pipelines/. The ADO version is the default source of truth — GitHub workflows mirror ADO behaviour except in the narrow documented cases covered under Hard rule 1 below. Reference doc: Docs/Pipelines/README.md.

File inventory

GitHub ActionsAzure DevOpsWhat
.github/workflows/sentinel-deploy.ymlPipelines/Sentinel-Deploy.ymlWeekly Mon 04:00 UTC: full deploy (Bicep + Content Hub + custom + Defender)
.github/workflows/sentinel-drift-detect.ymlPipelines/Sentinel-Drift-Detect.ymlDaily 06:00 UTC: detect portal-edited rules + auto-PR
.github/workflows/sentinel-dcr-inventory.ymlPipelines/Sentinel-DCR-Inventory.ymlOn change: deploy DCR inventory runbook
.github/workflows/sentinel-dependency-update.ymlPipelines/Sentinel-Dependency-Update.ymlDaily 02:00 UTC: refresh dependencies.json + auto-PR
.github/workflows/pr-validation.ymlPipelines/Sentinel-PR-Validation.ymlOn every PR: 5-job merge gate
.github/workflows/pr-template-validation.yml(GitHub-only)On every PR: fail if the PR description does not fill in .github/PULL_REQUEST_TEMPLATE.md
.github/workflows/sentinel-deploy-nightly.yml(GitHub-only)Daily 03:00 UTC: E2E smoke test against test workspace

Composite actions

Two composite actions live under .github/actions/. Use these instead of inlining Azure/login@v2 or Install-Module patterns:

  • ./.github/actions/azure-login-oidc — OIDC federated login. Inputs: client-id, tenant-id, subscription-id, enable-azps-session (default 'true').
  • ./.github/actions/setup-pwsh-modules — cached + pinned install of Pester + powershell-yaml. Inputs: pester-version, yaml-version, install-pester (set 'false' for yaml-only jobs like the dep-manifest gate).

Hard rules

  1. ADO is the default source of truth. When the two diverge, change ADO first, then port to GitHub. The reverse direction creates merge conflicts that are hard to spot in review.

    Documented divergence is allowed in the narrow cases below. Where it exists, justify it inline (workflow comment, commit message, or PR description) and reference the forcing constraint so future readers don't mistake the divergence for drift:

    • Platform-forced divergence. A constraint that exists on one platform but not the other forces a different shape. The canonical example is GitHub's 25-input workflow_dispatch cap (ADO has no equivalent limit), which is why sentinel-deploy.yml exposes a single skip_custom_content_types comma-separated string where Pipelines/Sentinel-Deploy.yml exposes nine separate boolean parameters. BusyBox vs GNU shell utilities in container images, GitHub-only gh issue create patterns in nightly workflows, and similar one-sided platform behaviours qualify.

    • One-direction-first bug fixes. When a bug affects both platforms but the fix lands on one first (typically because the maintainer hit the bug there first), this is acceptable short-term but the divergence is not the end state. Track the pending port as a follow-up issue or a TODO in the PR description so it doesn't become permanent by neglect.

    Drift caught in code review without a documented reason should be reverted, not retroactively justified.

  2. Pin versions for every PSGallery / NuGet / GitHub Action you add. Workflow-level env vars (PESTER_VERSION, YAML_VERSION, KUSTO_LANGUAGE_VERSION) are the convention. A breaking change shipped from a registry must NOT be able to silently fail a scheduled run on an unrelated repo change.

  3. Use actions/checkout@v4 (the latest pinned major). Don't pin to @main or @master.

  4. Auth via OIDC, not service principal secrets. All federated creds use the SP set up by Deploy/setup/Setup-ServicePrincipal.ps1; the workflow needs permissions: id-token: write.

  5. Schedule alignment — daily / weekly schedules must avoid stepping on each other. Current alignment:

    • 02:00 UTC daily: sentinel-dependency-update
    • 03:00 UTC daily: sentinel-deploy-nightly (GH-only)
    • 04:00 UTC Monday: sentinel-deploy
    • 06:00 UTC daily: sentinel-drift-detect
  6. concurrency: cancel-in-progress: true for PR-style workflows (re-runs invalidate the previous run's status check). cancel-in-progress: false for scheduled workflows that should accumulate (nightly E2E, drift sync — each run keeps its own context for diagnosis).

  7. workflow_dispatch inputs match parameters — when a workflow has both a schedule trigger and a manual workflow_dispatch trigger, every dispatch input must default to the same value the schedule run gets implicitly.

  8. Permissions block — declare permissions: explicitly on every job (or workflow-level). Default-permissive is the wrong default for any job that touches a write API.

Path filters (ADO build-validation)

The ADO PR-validation policy currently filters on these paths:

Content/AnalyticalRules/*;Content/HuntingQueries/*;Modules/*;Deploy/*;Tools/*;Tests/*;dependencies.json

If you add a new top-level folder that should trigger PR validation (e.g. a future Connectors/ folder), update this filter in two places:

  • Pipelines/Sentinel-PR-Validation.ymlpr.paths.include and trigger.paths.include
  • The build-validation policy in ADO (Project Settings → Repos → Repositories → <repo> → Policies → Branch policies for main → Build validation). The path filter on the policy is the enforcement boundary; the YAML's pr.paths.include is the trigger boundary.

Cross-references