Skip to content

Commit 6fa7bce

Browse files
committed
Add sample scheduled assessment pipeline (issue #3)
Add examples/azure-pipelines.yml: a schedule-only pipeline that runs adoqr on a weekly cron and publishes the generated reports as a pipeline artifact. It authenticates with an ARM service connection via the AzureCLI@2 task (no PAT), exposes organization/projects/maxParallel/outputFormat as queue-time parameters, and writes output to the artifact staging directory. Sets ADOQR_NO_OPEN=1 so the headless agent never attempts to open a browser. Documents setup in a new README 'Scheduled Assessments' section. Addresses #3.
1 parent 0abe4fc commit 6fa7bce

3 files changed

Lines changed: 137 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to Semantic Versioning.
88
## [Unreleased]
99

1010
### Added
11+
- Sample scheduled Azure DevOps pipeline (`examples/azure-pipelines.yml`) that runs adoqr on a cron schedule and publishes the reports as a pipeline artifact, with setup docs in the README.
1112
- Executive summary now includes an Organization Extensions section that lists all extensions with Installed vs Default classification and installed-first ordering.
1213
- Top navigation now includes an Extensions anchor placed before Run Comparison for faster access to extension findings.
1314

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,26 @@ assessment concurrently at three levels:
203203
Falls back to sequential execution automatically on PowerShell 5.1 or when
204204
only one project is being assessed.
205205

206+
### Scheduled Assessments
207+
208+
To get a recurring, archived posture review without running the tool by hand,
209+
schedule it as an Azure DevOps pipeline. A ready-to-use sample lives at
210+
[`examples/azure-pipelines.yml`](examples/azure-pipelines.yml): it runs adoqr on
211+
a cron schedule and publishes the reports (Markdown + executive/remediation HTML
212+
+ JSON) as a pipeline artifact.
213+
214+
1. Import it as a new pipeline (**Pipelines ▸ New pipeline ▸ Existing Azure
215+
Pipelines YAML file**) and point it at `/examples/azure-pipelines.yml`.
216+
2. Create an ARM **service connection** and grant its service principal access
217+
to the target organization (**Organization settings ▸ Users**, at least
218+
*Project Collection Valid Users*). The pipeline signs in with it via the
219+
`AzureCLI@2` task, so adoqr obtains an Azure DevOps token with no PAT needed.
220+
3. Set the `organization` parameter (and optionally `projects`, `maxParallel`,
221+
`outputFormat`) and adjust the `cron` schedule.
222+
223+
The sample defaults to a weekly run (Mondays 06:00 UTC) and sets
224+
`ADOQR_NO_OPEN=1` so the agent never tries to open a browser.
225+
206226
## Troubleshooting
207227

208228
### Common Issues

examples/azure-pipelines.yml

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# ---------------------------------------------------------------------------
2+
# adoqr — scheduled Azure DevOps best-practice assessment
3+
# ---------------------------------------------------------------------------
4+
# Runs invoke-adoqr.ps1 on a schedule and publishes the generated reports
5+
# (Markdown + executive/remediation HTML + JSON) as a pipeline artifact, so you
6+
# get a recurring, archived posture review without anyone running the tool by
7+
# hand.
8+
#
9+
# SETUP
10+
# 1. Import this file as a new pipeline (Pipelines ▸ New pipeline ▸
11+
# "Existing Azure Pipelines YAML file" ▸ /examples/azure-pipelines.yml).
12+
# 2. Create an ARM service connection (Project settings ▸ Service connections)
13+
# and grant its service principal access to the Azure DevOps organization
14+
# you want to assess:
15+
# - Add the SP as a member of the org (Organization settings ▸ Users)
16+
# with at least "Project Collection Valid Users"; use "Project
17+
# Collection Administrators" for full admin/audit coverage.
18+
# 3. Set the pipeline variables below (Edit ▸ Variables), or override them at
19+
# queue time via the parameters.
20+
#
21+
# AUTHENTICATION
22+
# The AzureCLI@2 task signs in with the service connection, so adoqr's
23+
# `az account get-access-token` call obtains an Azure DevOps bearer token with
24+
# no PAT required — the same auth path as an interactive `az login`.
25+
#
26+
# SCHEDULE
27+
# The cron below runs every Monday at 06:00 UTC. `always: true` makes it run
28+
# even when main has not changed since the last assessment. Adjust as needed:
29+
# https://learn.microsoft.com/azure/devops/pipelines/process/scheduled-triggers
30+
# ---------------------------------------------------------------------------
31+
32+
# Schedule-only: do not run on pushes or pull requests.
33+
trigger: none
34+
pr: none
35+
36+
schedules:
37+
- cron: '0 6 * * 1' # 06:00 UTC every Monday
38+
displayName: Weekly adoqr assessment
39+
branches:
40+
include:
41+
- main
42+
always: true
43+
44+
parameters:
45+
- name: organization
46+
displayName: ADO organization (URL or short name)
47+
type: string
48+
default: 'https://dev.azure.com/MyOrg'
49+
- name: projects
50+
displayName: Projects (space-separated; empty = all projects)
51+
type: string
52+
default: ''
53+
- name: maxParallel
54+
displayName: Max projects assessed concurrently
55+
type: number
56+
default: 3
57+
- name: outputFormat
58+
displayName: Output format
59+
type: string
60+
default: 'all'
61+
values:
62+
- markdown
63+
- html
64+
- json
65+
- all
66+
67+
variables:
68+
# Name of the ARM service connection authorized against the target ADO org.
69+
azureServiceConnection: 'adoqr-assessment'
70+
71+
pool:
72+
vmImage: ubuntu-latest
73+
74+
steps:
75+
- checkout: self
76+
displayName: Check out adoqr
77+
78+
- task: AzureCLI@2
79+
displayName: Run adoqr assessment
80+
env:
81+
# No interactive browser on a build agent; don't try to auto-open the
82+
# report. adoqr also auto-detects CI via TF_BUILD, so this is belt-and-
83+
# suspenders for self-hosted agents that don't set it.
84+
ADOQR_NO_OPEN: '1'
85+
inputs:
86+
azureSubscription: $(azureServiceConnection)
87+
scriptType: pscore
88+
scriptLocation: inlineScript
89+
inlineScript: |
90+
$ErrorActionPreference = 'Stop'
91+
92+
# Ensure the Azure DevOps CLI extension is present (adoqr also installs
93+
# it automatically, but doing it here keeps the assessment output clean).
94+
az extension add --name azure-devops --only-show-errors --output none 2>$null
95+
96+
# Build argument list. Splatting keeps optional args (projects) clean.
97+
$adoqrArgs = @{
98+
Organization = '${{ parameters.organization }}'
99+
MaxParallel = ${{ parameters.maxParallel }}
100+
OutputFormat = '${{ parameters.outputFormat }}'
101+
OutputPath = '$(Build.ArtifactStagingDirectory)'
102+
}
103+
104+
$projects = '${{ parameters.projects }}'.Trim()
105+
if ($projects) {
106+
$adoqrArgs.Project = $projects -split '\s+'
107+
}
108+
109+
./invoke-adoqr.ps1 @adoqrArgs
110+
111+
- task: PublishPipelineArtifact@1
112+
displayName: Publish assessment reports
113+
condition: always()
114+
inputs:
115+
targetPath: $(Build.ArtifactStagingDirectory)
116+
artifactName: adoqr-assessment

0 commit comments

Comments
 (0)