Validates, lints, and security-scans Azure DevOps Pipeline configurations (azure-pipelines.yml / azure-pipelines.yaml). Use when working with ADO pipelines, YAML pipeline files, or CI/CD configurations in Azure DevOps: including validating YAML syntax and schema, detecting hardcoded secrets or credentials, checking for deprecated or unpinned task versions, enforcing best practices (caching, timeouts, display names), performing pipeline security audits, or reviewing azure-pipelines.yml before merging. Trigger terms: azure-pipelines.yml, ADO pipeline, Azure Pipelines, YAML pipeline, CI/CD validation, pipeline security scan, DevOps configuration review.
69
87%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Validates, lints, and security-scans Azure DevOps Pipeline configurations (azure-pipelines.yml, azure-pipelines.yaml). Runs four validation layers via a single orchestrator script.
azure-pipelines.yml or azure-pipelines.yaml before merging a change.:latest container tags or curl | bash patterns.displayName, caching and timeouts on an existing pipeline.# Full validation (all layers)
bash scripts/validate_azure_pipelines.sh azure-pipelines.ymlLayers executed in order: 0. YAML lint (yamllint): formatting, indentation, trailing spaces
:latest tags# Targeted runs
bash scripts/validate_azure_pipelines.sh azure-pipelines.yml --syntax-only
bash scripts/validate_azure_pipelines.sh azure-pipelines.yml --best-practices
bash scripts/validate_azure_pipelines.sh azure-pipelines.yml --security-only
# Skip layers
bash scripts/validate_azure_pipelines.sh azure-pipelines.yml --skip-yaml-lint
bash scripts/validate_azure_pipelines.sh azure-pipelines.yml --no-best-practices
bash scripts/validate_azure_pipelines.sh azure-pipelines.yml --no-security
# Strict mode (fail on warnings)
bash scripts/validate_azure_pipelines.sh azure-pipelines.yml --strictpython3 scripts/validate_syntax.py azure-pipelines.yml
python3 scripts/check_best_practices.py azure-pipelines.yml
python3 scripts/check_security.py azure-pipelines.yml════════════════════════════════════════════════════════════════════════════════
Azure Pipelines Validator
════════════════════════════════════════════════════════════════════════════════
[1/3] Running syntax validation...
✓ Syntax validation passed
[2/3] Running best practices check...
SUGGESTIONS (2):
INFO: Line 15: Job 'BuildJob' should have displayName [missing-displayname]
💡 Add 'displayName: "Your Job Description"' to job 'BuildJob'
WARNING: Line 25: Task 'Npm@1' could benefit from caching [missing-cache]
💡 Add Cache@2 task to cache dependencies and speed up builds
[3/3] Running security scan...
MEDIUM SEVERITY (1):
MEDIUM: Line 8: Container 'linux' uses ':latest' tag [container-latest-tag]
🔒 Pin container images to specific versions or SHA digestsWhen validation fails:
[missing-displayname]): see references/ for rule details.--syntax-only, --security-only, etc.) to iterate quickly.MEDIUM/HIGH security findings, do not merge until resolved; INFO findings are advisory.bash scripts/validate_azure_pipelines.sh new-pipeline.ymlbash scripts/validate_azure_pipelines.sh azure-pipelines.yml --security-only --strictbash scripts/validate_azure_pipelines.sh azure-pipelines.yml --best-practicessteps:
- script: |
bash scripts/validate_azure_pipelines.sh azure-pipelines.yml --strict
displayName: 'Validate Pipeline Configuration'Run without arguments to auto-detect azure-pipelines*.yml files in the current directory (up to 3 levels deep).
The validator performs static analysis only. For dynamic lookups (task versions, input parameters, feature docs), use:
# Context7 MCP
mcp__context7__resolve-library-id("azure-pipelines")
mcp__context7__get-library-docs(context7CompatibleLibraryID, topic="deployment")
# Or WebSearch / WebFetch
WebSearch("Azure Pipelines Docker@2 task documentation 2025")
WebFetch("https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/docker-v2").venv if not available system-wide: no manual setup required.# Optional manual install
pip3 install PyYAML yamllint| Problem | Fix |
|---|---|
ModuleNotFoundError: PyYAML | pip3 install PyYAML |
Permission denied | chmod +x scripts/*.sh scripts/*.py |
| Unexpected validation errors | Check references/azure-pipelines-reference.md or Microsoft Learn |
WHY: Templates called from the main pipeline can contain schema violations, missing parameters, or invalid task references that only surface at runtime. Validating only the entry-point file leaves template errors undetected until the pipeline actually runs.
BAD: Validate only azure-pipelines.yml and skip all files under templates/*.yml.
GOOD: Run the validator on every .yml file in the pipeline directory, including all templates.
WHY: Azure Pipelines YAML is whitespace-significant. Indentation errors and trailing spaces can silently restructure the pipeline: turning a step into a job property, or merging two separate blocks: without any obvious parse error.
BAD: Ignore yamllint warnings such as "trailing spaces" or "wrong indentation" because the pipeline appears to run.
GOOD: Fix all YAML formatting issues before submitting; a clean yamllint pass is a prerequisite for a trustworthy pipeline.
WHY: --strict fails on all warnings, which is the correct setting for a CI gate. Applied to a brand-new pipeline with dozens of warnings, it produces so much noise that engineers discard the output entirely and disable validation rather than fix the root causes.
BAD: Run --strict on a new pipeline, see 30 warnings, and remove validation from the workflow because "it's too noisy."
GOOD: Run without --strict first, fix critical errors, then warnings, then graduate to strict mode as a CI gate.
WHY: A passing syntax validation does not imply a secure pipeline. Security scanning catches hardcoded credentials, injection vectors, and insecure patterns that syntax checks are not designed to detect.
BAD: Merge a pipeline change after syntax validation passes with no security check.
GOOD: Always run --security as part of the validation workflow, treating MEDIUM and HIGH findings as merge blockers.
WHY: The security layer flags hardcoded passwords, API keys, tokens, AWS and Azure credentials (for example [hardcoded-password], [hardcoded-api-key]). Anything committed to the repository stays in history even after the line is removed.
BAD: password: 'P@ssw0rd' written directly in a variables: block.
GOOD: Reference a secret variable or variable group, for example $(DB_PASSWORD), and mark it secret in Azure DevOps.
WHY: The best-practices layer reports [task-no-version], [task-version-zero] and [task-old-version]. An unpinned or outdated task can change behaviour between runs or run deprecated code.
BAD: - task: Npm with no @ version.
GOOD: - task: Npm@1 with the major version pinned.
:latest container images or ubuntu-latest blindlyWHY: The scanner reports [container-latest-tag] and [pool-latest-image]. A floating tag means the same commit can build differently on different days.
BAD: container: ubuntu:latest.
GOOD: Pin the image to a specific version or a SHA digest.
WHY: Patterns such as curl ... | bash and wget ... | sh are flagged by the security scan ([curl-pipe-shell], [wget-pipe-shell]). The pipeline executes whatever the remote host serves at that moment.
BAD: - script: curl -sSL https://example.com/install.sh | bash.
GOOD: Download the file, verify it, then run it, or use a pinned pipeline task.
WHY: The security scan flags SSL bypasses such as [insecure-ssl] and [git-disable-ssl]. Disabling verification exposes the build to man-in-the-middle tampering.
BAD: - script: git config --global http.sslVerify false.
GOOD: Fix the certificate chain or install the corporate CA on the agent.
WHY: The best-practices layer reports [missing-timeout] and [missing-cache]. A hung job without a timeout holds an agent until the platform default expires, and an uncached dependency install slows every run.
BAD: A build job with no timeoutInMinutes that reinstalls npm packages on every run.
GOOD: Set timeoutInMinutes on the job and add a Cache@2 step for dependencies.
references/azure-pipelines-reference.md: full YAML syntax reference and rule definitionsassets/examples/basic-pipeline.yml: simple CI pipelineassets/examples/docker-build.yml: Docker build and pushassets/examples/deployment-pipeline.yml: multi-environment deployment with approval gatesassets/examples/multi-platform.yml: multi-platform build matrixassets/examples/template-example.yml: reusable templates# Test with a bundled example
bash scripts/validate_azure_pipelines.sh assets/examples/basic-pipeline.ymlAdd custom rules to the appropriate script:
scripts/validate_syntax.pyscripts/check_best_practices.pyscripts/check_security.py# Example custom best-practice rule in check_best_practices.py
def _check_custom_rule(self):
for job in self._get_all_jobs():
job_name = job.get('job') or job.get('deployment')
if 'tags' not in pool:
self.issues.append(BestPracticeIssue(
'warning',
self._get_line(job_name),
f"Job '{job_name}' should specify agent tags",
'custom-missing-tags',
"Add 'tags' to pool to select appropriate agents"
))Note: This skill validates pipeline configurations but does not execute pipelines. Use Azure DevOps Pipeline validation or Azure CLI to test actual pipeline execution.
pantheon-org/tekhne
48ef197
Also appears in
last in sync Aug 28, 2026
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.