Tutorial 45: Shift-Left Governance

July 30, 2026 · View on GitHub

Time: 25 minutes · Level: Intermediate · Prerequisites: Tutorial 01 (Policy Engine), Tutorial 25 (Security Hardening)

Catch governance violations before they reach production. This tutorial walks through every layer of AGT's shift-left story: from pre-commit hooks that validate policy files on your laptop, through PR-time gates that enforce dependency review and secret scanning, to CI/CD checks that run governance verification, binary analysis, and supply chain verification on every build.

Scope: commit-time, PR-time, CI/build-time, and release-time governance Tools: pre-commit hooks, GitHub Actions, GitHub CI workflows Audience: Platform engineers, DevOps teams, and security teams integrating AGT into their SDLC


What You'll Learn

SectionTopic
Why Shift-Left?The case for catching violations before runtime
Commit-TimePre-commit hooks for policy and plugin validation
PR-Time: Contributor ReputationAutomated screening for coordinated inauthentic behavior
PR-TimeDependency review, secret scanning, supply chain checks
CI/Build-TimeGovernance verify, policy validation, static analysis, binary analysis
Language-Specific Build Checks.NET, TypeScript, Python build-time enforcement
Release-TimeSBOM generation, artifact signing, attestation
Reference ArchitectureHow all the pieces fit together
Cross-ReferenceRelated tutorials

Why Shift-Left?

Most AGT tutorials focus on runtime governance: policy evaluation when an agent acts, trust scoring when agents communicate, audit logging when decisions are made. Runtime governance is essential, but it is the last line of defense.

Shift-left governance moves checks earlier in the development lifecycle:

  Commit        PR           CI/Build        Release        Runtime
    │            │              │               │              │
    ▼            ▼              ▼               ▼              ▼
  Contributor   Commit        PR           CI/Build        Release        Runtime
     │            │            │              │               │              │
     ▼            ▼            ▼              ▼               ▼              ▼
  ┌──────┐  ┌──────┐  ┌─────────┐  ┌────────────┐  ┌───────────┐  ┌──────────┐
  │author│  │ pre- │  │ dep +   │  │ governance │  │ SBOM +    │  │ policy   │
  │screen│  │commit│  │ secret  │  │ verify +   │  │ signing + │  │ engine + │
  │check │  │hooks │  │ scans   │  │ CodeQL +   │  │ provenance│  │ trust +  │
  │      │  │      │  │         │  │ BinSkim    │  │           │  │ audit    │
  └──────┘  └──────┘  └─────────┘  └────────────┘  └───────────┘  └──────────┘
    Earliest feedback                                        Most comprehensive

Why it matters:

  • A social engineering contributor caught at PR open never gets code reviewed
  • A malformed policy file caught at commit time costs zero CI minutes
  • A secret caught in PR review never reaches the default branch
  • A dependency confusion attack blocked in CI never reaches production
  • An unsigned artifact blocked at release time never reaches users

Commit-Time: Pre-Commit Hooks

AGT ships three pre-commit hooks in .pre-commit-hooks.yaml and a rollout template with additional quality gates.

§1.1 Built-In Hooks

Hook IDWhat It ChecksTriggers On
validate-policyYAML/JSON policy file schema and structure*polic*.yaml, *polic*.yml, *polic*.json
validate-plugin-manifestPlugin manifest required fields and schemaplugin.json, plugin.yaml
evaluate-plugin-policyPlugin manifests against a governance policyplugin.json, plugin.yaml

§1.2 Setup

Add AGT as a pre-commit hook source in your .pre-commit-config.yaml:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/microsoft/agent-governance-toolkit
    rev: main  # pin to a release tag in production
    hooks:
      - id: validate-policy
      - id: validate-plugin-manifest
      - id: evaluate-plugin-policy
        args: ['--policy', 'policies/marketplace-policy.yaml']

Install and run:

pip install pre-commit
pre-commit install
pre-commit run --all-files   # validate existing files

§1.3 Extended Quality Gates

The pre-commit hook rollout template adds governance-specific quality gates beyond schema validation:

HookPurpose
agt-validateRuns agent_os.cli validate --strict on policy files
agt-doctorHealth check on pre-push (runs before pushing to remote)
agency-json-requiredEnsures every plugin directory has an agency.json
no-stubsBlocks TODO, FIXME, HACK markers in staged production code
no-custom-cryptoBlocks raw crypto imports outside security modules
detect-secretsSecret scanning via Yelp's detect-secrets

§1.4 Phased Rollout

For teams adopting AGT incrementally:

  1. Week 1: Install with --permissive mode, hooks warn but don't block
  2. Week 2: Switch to --strict for policy validation only
  3. Week 3: Enable all hooks as blocking
  4. Week 4: Graduate to full blocking per the graduation checklist

PR-Time: Contributor Reputation

The leftmost check in AGT's shift-left pipeline. Before reviewing code, before running CI, the contributor reputation action screens the author's GitHub profile for signals of coordinated inauthentic behavior.

What It Detects

SignalSeverityDescription
Following farmingMEDIUM/HIGHExtreme following:follower ratios (e.g., 2000 following, 50 followers)
Repo velocityMEDIUM/HIGHUnnatural repo creation rate (e.g., 60 repos in 90 days)
Cross-repo sprayHIGHSame issue template filed across dozens of repos in days
Self-promotion sprayMEDIUM/HIGHIssues promoting the author's own repos across multiple orgs
Credential launderingHIGHCiting merged PRs as credentials in spray issues across other repos
Governance theme concentrationMEDIUMRepos overwhelmingly themed around governance/security topics
Awesome fork burstHIGHRapid forking of curated/awesome lists (credibility farming)
Batch repo namingMEDIUM/HIGHTemplated repo creation (e.g., 5+ *-mcp repos in 48 hours)
Feature overlapMEDIUM/HIGHRepo clones AGT's feature set across 3+ of 6 feature buckets
Thin credibilityMEDIUM/HIGHYoung, low-star repos promoted via issues across multiple orgs
Coordinated promotionHIGHMultiple thin repos targeting overlapping org sets
Network coordinationMEDIUM/HIGHShared forks, synchronized filing, co-comment patterns (opt-in)

Add It to Your Repo

AGT ships a reusable composite action. Add this workflow to any repository:

# .github/workflows/contributor-check.yml
name: Contributor Reputation Check

on:
  pull_request_target:        # Use pull_request_target, not pull_request
    types: [opened]
  issues:
    types: [opened]

permissions:
  contents: read
  issues: write
  pull-requests: write

jobs:
  check:
    runs-on: ubuntu-latest
    if: github.actor != 'dependabot[bot]'
    steps:
      - name: Checkout AGT action
        uses: actions/checkout@v4
        with:
          repository: microsoft/agent-governance-toolkit
          sparse-checkout: |
            scripts
            .github/actions/contributor-check
          path: agt

      - name: Run contributor check
        uses: ./agt/.github/actions/contributor-check
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          checks: profile,credential    # Add 'cluster' for deep analysis
          risk-threshold: MEDIUM        # MEDIUM or HIGH

How It Works

  1. On every PR or issue open, the action runs two checks (profile + credential audit) using only the GitHub REST API and Python stdlib. No dependencies to install.

  2. Risk is computed as the max across all checks:

    • LOW: No action taken (silent pass)
    • MEDIUM: Posts a collapsible comment, adds needs-review:MEDIUM label
    • HIGH: Posts a detailed comment, adds needs-review:HIGH label
  3. Comments are idempotent: re-runs update the same comment instead of creating duplicates. Old risk labels are removed before applying the current one.

  4. Cluster detection (opt-in) maps coordination networks from a seed account via shared forks, co-comments, and synchronized filing. It is API-heavy and recommended only for manual dispatch investigations.

Important: Use pull_request_target (not pull_request) so the action has write permissions to comment and label on fork PRs. Do not run untrusted PR code before this action in the same workflow.


PR-Time Gates

When code reaches a pull request, independent workflows enforce governance before merge.

§2.1 Dependency Review

AGT's dependency review workflow blocks PRs that introduce dependencies with known CVEs or disallowed licenses:

# From .github/workflows/dependency-review.yml
- uses: actions/dependency-review-action@v4
  with:
    fail-on-severity: moderate
    comment-summary-in-pr: always
    allow-licenses: >
      MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC,
      PSF-2.0, Python-2.0, 0BSD, Unlicense, CC0-1.0,
      CC-BY-4.0, Zlib, BSL-1.0, MPL-2.0

This runs on every PR that touches dependency manifests and flags:

  • Dependencies with moderate+ CVEs
  • Dependencies with licenses not on the allow list

§2.2 Secret Scanning

The secret scanning workflow (secret-scanning.yml) runs on every PR to main and weekly on schedule. It combines:

  1. Gitleaks for pattern-based secret detection across the full git history
  2. High-entropy string scanning for API keys, GitHub tokens, AWS keys, and Slack tokens using regex patterns

§2.3 Supply Chain Checks

The supply chain check workflow (supply-chain-check.yml) runs when dependency manifests change and enforces:

  • Exact version pinning: no ^ or ~ version ranges in package.json
  • Lockfile presence: every package with dependencies must have a lockfile

§2.4 Quality Gates

The quality gates workflow (quality-gates.yml) runs on every PR and blocks merge if:

GateWhat It Catches
No stubs/TODOsTODO, FIXME, HACK markers in production code
No unauthorized cryptoRaw crypto imports outside designated security modules
Security audit requiredChanges to security-sensitive paths require audit documentation
Dependency audit trailVendored patches must have an audit trail

These mirror the pre-commit hooks from Section 1.3, providing defense in depth: pre-commit catches issues at the developer's machine, quality gates catch anything that bypasses hooks.


CI/Build-Time Checks

Once a PR passes the gate workflows, the main CI pipeline and specialized workflows perform deeper analysis.

§3.1 Governance Verify Action

The Agent Governance Verify action (action/action.yml) is the primary CI-time governance check. It runs the compliance CLI against your repository:

# .github/workflows/governance-ci.yml
name: Governance CI
on: [push, pull_request]

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: microsoft/agent-governance-toolkit/action@main
        with:
          command: all              # governance-verify + marketplace-verify + policy-evaluate
          policy-path: policies/    # path to policy files
          manifest-path: plugin.json
          output-format: json
          fail-on-warning: 'true'

The command input supports four modes:

CommandWhat It Does
governance-verifyRuns the full compliance verification suite
marketplace-verifyValidates a plugin manifest against marketplace requirements
policy-evaluateEvaluates a specific policy against a context
allRuns governance-verify, then marketplace-verify and policy-evaluate if paths are provided

§3.2 Policy Validation Workflow

The policy validation workflow (policy-validation.yml) triggers when any YAML file or the policy engine source changes. It:

  1. Discovers all policy files matching *policy* naming
  2. Validates each native manifest using agt lint-policy
  3. Runs policy CLI unit tests to verify evaluation behavior

This ensures that policy file changes don't break the policy engine.

§3.3 CodeQL and Static Analysis

AGT uses CodeQL for semantic static analysis of Python and TypeScript code. The CodeQL workflow (codeql.yml) runs on pushes and PRs, uploading SARIF results to GitHub's security tab.

§3.4 Dependency Confusion Scan

A dedicated CI job runs scripts/check_dependency_confusion.py --strict on every build. This checks that:

  • Internal package names don't collide with public PyPI/npm packages
  • Notebook pip install commands only reference registered packages

§3.5 Workflow Security Audit

When GitHub Actions workflow files change, a workflow security job scans for:

  • Expression injection vulnerabilities (${{ github.event.* }} in run:)
  • Overly permissive permissions
  • Unpinned action references

§3.6 .NET Binary Analysis (BinSkim)

For the .NET SDK, the CI pipeline runs Microsoft BinSkim binary analysis on compiled assemblies:

- name: BinSkim binary security analysis
  run: |
    dotnet tool install --global Microsoft.CodeAnalysis.BinSkim --version 4.*
    BinSkim analyze "src/AgentGovernance/bin/Release/net8.0/*.dll" \
      --output binskim-results.sarif --verbose

Results are uploaded as SARIF to GitHub's code scanning dashboard.


Language-Specific Build-Time Enforcement

Each AGT SDK uses its language's native tooling to enforce governance standards at compile time. These are implemented today in the repository.

§4.1 .NET (Microsoft.AgentGovernance)

The .NET SDK enforces the strictest compile-time checks via MSBuild properties in Directory.Build.props and Directory.Build.targets:

FeatureConfigurationEffect
Nullable reference types<Nullable>enable</Nullable>Compiler warns on possible null dereference
Warnings as errors<TreatWarningsAsErrors>true</TreatWarningsAsErrors>All compiler warnings fail the build (packable projects)
Strong-name signing<SignAssembly>true</SignAssembly>Assemblies are signed with AgentGovernance.snk
Deterministic builds<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>Identical source produces identical binaries in CI
SourceLinkMicrosoft.SourceLink.GitHub packageUsers can step into AGT source when debugging
Symbol packages<IncludeSymbols>true</IncludeSymbols>.snupkg symbol packages published alongside NuGet packages

These are enforced automatically for any project in the agent-governance-dotnet/ directory tree.

§4.2 TypeScript (@microsoft/agent-governance-sdk)

The TypeScript SDK uses strict compiler settings in tsconfig.json:

FeatureConfigurationEffect
Strict mode"strict": trueEnables all strict type-checking options
Consistent casing"forceConsistentCasingInFileNames": truePrevents cross-platform filename issues
Declaration files"declaration": trueGenerates .d.ts files for consumers
ESLint@typescript-eslint/parser + @typescript-eslint/eslint-pluginStatic analysis during build

§4.3 Python (agent-governance-python)

Python packages use typed package markers and static analysis tooling:

FeatureConfigurationEffect
py.typed markerpy.typed file in packageSignals type-checker support to consumers
mypytool.mypy in pyproject.tomlStatic type checking in dev/CI
rufftool.ruff in pyproject.tomlFast Python linting, enforced in CI

The following patterns are not yet enforced in AGT's own CI but are recommended for teams consuming AGT:

LanguageToolPurpose
Rustcargo clippyLint-level warnings beyond rustc
Rustcargo denyLicence and vulnerability checks for dependencies
GostaticcheckAdvanced static analysis beyond go vet
Gogolangci-lintAggregated linter suite

Release-Time Gates

Before artifacts reach users, the release pipeline adds a final layer of verification. These are covered in depth by Tutorial 26, but here is how they fit into the shift-left lifecycle:

GateToolWhat It Produces
SBOM generationAnchore/SyftSPDX and CycloneDX software bills of materials
Artifact signingSigstore/provenance attestations and registry-native verificationCryptographic proof of publisher identity
Build provenanceactions/attest-build-provenanceSLSA provenance attestation
SBOM attestationactions/attest-sbomBinds SBOM to the specific release artifact
OpenSSF Scorecardossf/scorecard-actionAutomated security posture scoring

Reference Architecture

Here is how all the shift-left governance layers compose into a single pipeline:

Developer Machine          GitHub PR              CI Pipeline              Release
─────────────────          ─────────              ───────────              ───────
pre-commit hooks           Dependency review      Main CI                  SBOM
├─ validate-policy         ├─ CVE check           ├─ lint (ruff, ESLint)   ├─ SPDX
├─ validate-plugin         ├─ license check       ├─ build (.NET, TS,      ├─ CycloneDX
│  -manifest               │                      │  Rust, Go, Python)     │
├─ evaluate-plugin         Secret scanning        ├─ test (all SDKs)       Signing
│  -policy                 ├─ Gitleaks            ├─ governance-verify     ├─ Sigstore
├─ agt-validate            ├─ entropy scan        ├─ policy-validation     ├─ provenance
├─ agt-doctor (pre-push)   │                      ├─ CodeQL / SAST        │
├─ detect-secrets          │                      ├─ BinSkim (.NET)       Provenance
├─ no-stubs                Supply chain check     ├─ dependency-scan       ├─ SLSA
├─ no-custom-crypto        ├─ version pinning     ├─ workflow-security     ├─ SBOM
                           ├─ lockfile presence   │                        │  attestation
                           │                      ├─ ci-complete gate      │
                           Quality gates          │  (required status      Scorecard
                           ├─ no stubs            │   check)               └─ OpenSSF
                           ├─ no crypto
                           ├─ security audit
                           ├─ dep audit trail

Required Status Checks

The CI pipeline uses a ci-complete gate job as a single required status check. This job:

  1. Runs if: always() regardless of skip conditions
  2. Depends on all other CI jobs
  3. Checks that no jobs failed (skipped is acceptable)
  4. Reports a single pass/fail to branch protection

This pattern lets individual jobs skip based on path filters while still enforcing that nothing that ran has failed.


Cross-Reference

ConceptTutorial
Policy engine fundamentalsTutorial 01 -- Policy Engine
CI/CD security toolingTutorial 25 -- Security Hardening
SBOM and artifact signingTutorial 26 -- SBOM & Signing
MCP tool scanningTutorial 27 -- MCP Scan CLI
Multi-stage policy pipelineTutorial 37 -- Multi-Stage Pipeline
Contributor reputation deep diveTutorial 46 -- Contributor Governance
.NET SDKTutorial 19 -- .NET package
TypeScript SDKTutorial 20 -- TypeScript package
Plugin marketplaceTutorial 10 -- Plugin Marketplace
Pre-commit rollout templateOperations: Pre-Commit Hook Template

Source Files

ComponentLocation
Pre-commit hooks.pre-commit-hooks.yaml
Governance Verify actionaction/action.yml
Policy validation workflow.github/workflows/policy-validation.yml
Secret scanning workflow.github/workflows/secret-scanning.yml
Dependency review workflow.github/workflows/dependency-review.yml
Supply chain check workflow.github/workflows/supply-chain-check.yml
Quality gates workflow.github/workflows/quality-gates.yml
CI pipeline (all jobs).github/workflows/ci.yml
SBOM workflow.github/workflows/sbom.yml
.NET build propsagent-governance-dotnet/Directory.Build.props
.NET build targetsagent-governance-dotnet/Directory.Build.targets
TS compiler configagent-governance-typescript/tsconfig.json
TS ESLint configagent-governance-typescript/eslint.config.js
Python package configagent-governance-python/agent-primitives/pyproject.toml
Pre-commit rollout templatedocs/operations/pre-commit-hook-template.md

Next Steps

  • Set up pre-commit hooks in your repository using the rollout template
  • Add the Governance Verify action to your CI pipeline for automated compliance checks
  • Enable dependency review to catch CVE and license issues at PR time
  • Read Tutorial 25 (Security Hardening) for deeper coverage of CodeQL, fuzzing, and Scorecard
  • Read Tutorial 26 (SBOM & Signing) for release-time artifact signing and SBOM attestation