Skip to content

MSDO Toolchain Version Probe #10

MSDO Toolchain Version Probe

MSDO Toolchain Version Probe #10

name: MSDO Toolchain Version Probe
# Runs MSDO to install tools as a side effect, then scrapes the install
# directories to record exact resolved versions into toolchain-versions.json.
# The breach monitor reads this file instead of guessing "latest" from registries.
#
# Guardian installs all tool wrappers as NuGet packages into:
# /home/runner/work/_msdo/packages/nuget/{PackageName}.{version}/
# ESLint is installed via npm into:
# /home/runner/work/_msdo/packages/node_modules/eslint/
# Package names confirmed from run 23433052319.
on:
schedule:
- cron: '0 4 * * 1' # Weekly Monday 04:00 UTC
workflow_dispatch:
permissions:
contents: write
jobs:
probe:
name: Resolve and record MSDO tool versions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# Run MSDO — scan may find nothing (no real targets), that's fine.
# Side effect: Guardian downloads all tool packages into _msdo/packages/nuget/.
- name: Install MSDO tools
uses: microsoft/security-devops-action@main
continue-on-error: true
with:
tools: bandit,binskim,checkov,eslint,templateanalyzer,terrascan,trivy
- name: Collect resolved tool versions from install dirs
run: |
python3 - <<'PYEOF'
import os, json, re, pathlib, datetime
NUGET_DIR = pathlib.Path('/home/runner/work/_msdo/packages/nuget')
NPM_DIR = pathlib.Path('/home/runner/work/_msdo/packages/node_modules')
VER_PAT = re.compile(r'^(.+?)\.(v?\d+\.\d+(?:\.\d+)*(?:[-+][0-9A-Za-z.-]+)?)$', re.IGNORECASE)
# Guardian NuGet wrapper package names → canonical tool names.
# Confirmed from run 23433052319 (_msdo/packages/nuget/ directory listing).
PKG_TO_TOOL = {
'microsoft.guardian.banditredist_linux_amd64': 'bandit',
'microsoft.codeanalysis.binskim': 'binskim',
'microsoft.guardian.checkovredist_linux_amd64': 'checkov',
'azure.templates.analyzer.commandline.linux-x64': 'templateanalyzer',
'microsoft.guardian.terrascanredist_linux_amd64': 'terrascan',
'microsoft.guardian.trivyredist_linux_amd64': 'trivy',
}
# Internal packages — skip
SKIP_PKGS = {
'microsoft.security.devops.cli',
'microsoft.security.devops.cli.linux-x64',
'microsoft.security.devops.cli.linux-arm64',
'microsoft.security.devops.cli.win-x64',
'microsoft.security.devops.policy.names',
'microsoft.security.devops.policy.github',
}
tools = {}
raw_dirs = []
if NUGET_DIR.exists():
entries = sorted(d.name for d in NUGET_DIR.iterdir() if d.is_dir())
raw_dirs = entries
for name in entries:
m = VER_PAT.match(name)
if not m:
continue
pkg_lower = m.group(1).lower()
version = m.group(2)
if pkg_lower in SKIP_PKGS:
continue
canonical = PKG_TO_TOOL.get(pkg_lower)
if canonical:
tools[canonical] = version
# ESLint: installed via npm, read version from package.json
eslint_pkg = NPM_DIR / 'eslint' / 'package.json'
if eslint_pkg.exists():
tools['eslint'] = json.loads(eslint_pkg.read_text())['version']
print('raw_dirs:', raw_dirs)
print('resolved:', tools)
if not tools:
raise SystemExit('ERROR: no versions resolved — _msdo/packages/nuget/ empty or missing. Aborting.')
missing = (set(PKG_TO_TOOL.values()) | {'eslint'}) - set(tools.keys())
if missing:
print(f'WARNING: expected tools not found: {sorted(missing)}')
output = {
'generated_at': datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ'),
'msdo_cli_version': os.environ.get('MSDO_INSTALLEDVERSION', 'unknown'),
'tools': tools,
'raw_dirs': raw_dirs,
}
out = pathlib.Path('.github/toolchain-versions.json')
out.parent.mkdir(parents=True, exist_ok=True)
out.write_text(json.dumps(output, indent=2) + '\n')
print(json.dumps(output, indent=2))
PYEOF
- name: Commit updated versions
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .github/toolchain-versions.json
if git diff --cached --quiet; then
echo "toolchain-versions.json unchanged — nothing to commit"
else
git commit -m "chore(ci): update toolchain-versions.json [skip ci]"
# Push to dedicated unprotected branch — main has branch protection
# requiring PRs. The breach monitor reads from this branch via API.
git push origin HEAD:bot/toolchain-versions --force
fi