feat: Azure DevOps repo support - #47
Draft
splashthree wants to merge 7 commits into
Draft
Conversation
First slice of Azure DevOps repo support (plan: docs/proposals/ado-repo-support-matrix.md). - profiles/ado-enterprise/ — microsoft-enterprise's stack (C#/.NET 8 + Angular 17 + Azure, SOC 2 gates) with platform: azure-devops, so /sdlc-setup composes the existing Azure Pipelines CI/CD pack. Purely additive; auto-discovered. - docs/proposals/ado-repo-support-matrix.md — the folded fix matrix (Folds 0/A-E): installer platform-awareness, pack-aware doctor, PR-flow rails, prose sweep, keyless Foundry+RBAC gate auth; additive guarantee + platform-switch runbook. - Profile added to the five curated enumerations (sdlc-setup command, README, SKILL.md, docs/commands.md, docs/profiles.md, docs/architecture.md tree). - New TestOnDiskProfiles guard: every profiles/*/profile.yaml must pass the real schema and profile_id must equal the directory name (the compliance-gate lookup contract). Future profiles get CI coverage the moment the directory exists. - Fixed fictional plugin.json profile-registry docs (architecture.md 1.1/1.2, profiles.md Step 5): profiles are directory-listing auto-discovered; the real .claude-plugin/plugin.json is metadata-only. Verified: 818 tests pass; fresh-repo e2e drill (init -> harness install -> gates -> upgrade dry-run: 0 CONFLICT / 0 RETIRED); byte-level diff vs sibling profile clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… (Fold A) _copy_core now consults stack.ci_cd.platform via _CORE_LAYOUT_BY_PLATFORM: azure-devops installs drop the GitHub-only payload (workflows/, rulesets, CODEOWNERS, apply-branch-protection.sh) and redirect the neutral governance content (rubrics, eval-bypasses, dependency-exceptions ledgers) to .azuredevops/rails/ — where the ADO pipelines actually read them (fixes the live bug where <<RUBRIC_DIR>> pointed at a path nothing created). rails-telemetry.schema.json intentionally stays at .github/: both packs' telemetry pipelines commit their report to .github/rails-telemetry.json on purpose (one canonical path so the operator-side fleet collector reads a mixed GitHub/Azure fleet); the schema stays beside its report. github-actions and core-only installs fall through to the identity layout — byte-for-byte unchanged, proven by the untouched enterprise-tree.txt golden. New: ado-enterprise golden-repo test + tree snapshot, synthetic core-layout unit tests, upgrade-idempotency coverage. Suite: 834 passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
splashthree
marked this pull request as draft
August 9, 2026 01:34
installed_platform() reads the manifest's composed pack ids; on cicd/azure-devops the platform-facing checks follow the platform: - Tools: require az (+ azure-devops extension), never gh — demanding gh on an ADO repo is telling the user to fix a working setup - Repo secrets: required_variable_groups() reads `- group: NAME` references from the installed pipelines (quote-aware — exotic legal names survive; <<VARIABLE_GROUP>>/sentinel/template expressions are unfinished setup, not missing groups) and checks them via az pipelines variable-group list - Branch protection: az repos policy list; enforcing = isEnabled AND isBlocking (an enabled-but-optional policy is advice, not a gate) - Residual tokens: .azuredevops/ joined the scan roots — <<GATED_PATHS>> in security.yml was invisible before az hardening from adversarial review: shutil.which resolution (az.cmd on Windows), cwd=repo so org/project detection reads --repo's remote not the doctor's CWD, --only-show-errors so az stderr chatter never corrupts the JSON parse, list-shape guard, TypeError-safe manifest read. GitHub/core-only installs are byte-identical (verified against the HEAD doctor on scratch installs: offline+online outputs diff-clean); the gh check bodies are renamed originals. Existing tests unmodified; +30 beside them. Suite: 867 passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…iter (Fold C)
- review-gate.{sh,ps1}: `az repos pr create` joins git push / gh pr create as
a gated trigger (segment-anchored; a mention inside echo/quotes still walks
free). Shared-payload hardening that also strengthens the GitHub twins,
stated plainly: leading VAR=value prefixes are stripped before matching
(AZURE_DEVOPS_EXT_PAT=... az repos pr create is a documented az auth
pattern and was a bypass — as was FOO=1 git push), and the ps1 twin now
splits segments on newlines like the sh twin always did (a multi-line
command with the trigger on a later line walked past it on Windows).
- New ADO pack settings fragment merged into .claude/settings.json:
read-only az queries allowed (az repos pr SHOW — az has no 'pr view'; the
adversarial review caught that gh-vocabulary bug after unit tests had
pinned it), mutating az + configure-branch-policies.sh behind ask,
.azuredevops/** gated like .github/**. GitHub installs get none of it
(starter-install test pins the absence).
- pr-writer skill names both platforms (az repos pr create, --labels
risk:high — flag verified against the live CLI).
Verified: install+upgrade agree byte-for-byte on the merged settings (68/68
IDENTICAL dry-run); GitHub control matches the golden tree exactly; the real
.sh hook drilled against a 14-case trigger table incl. adversarial forms
(pwsh twin runs the same table where pwsh exists). Suite: 886 passed.
Deferred, documented: wrapper/subshell forms (env/nohup/bash -c) remain the
parser's coverage boundary, in parity with git push since day one.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…forms (Fold D) One editorial rule applied everywhere: prose that named only the GitHub mechanism now names the ADO analogue that already exists. Setup Step 7 offers configure-branch-policies.sh beside apply-branch-protection.sh; sdlc-doctor.md describes the pack-aware doctor (gh/az); the harness tour (HARNESS.md, README.md install map, CLAUDE.md.template examples) covers the .azuredevops/ layout the platform-aware installer actually produces; phases 03/08/09 pair Key Vault+variable groups, Azure Artifacts, ADO Boards; the close-phase harness audit checks either pipelines home; doctor's DEV_ENVIRONMENT token owner text goes platform-neutral. New: "Switching CI platform" runbook in sdlc-upgrade.md — the profile edit → dry-run → RETIRED/NEW swap report → human deletes retired files → doctor + shakedown drills flow, clean since Fold A made the core platform-aware. Also: sdlc-setup.md's stale <<ADO_ORGANIZATION>> references corrected to the ADO_ORGANIZATION_NOT_SET sentinel the pack actually installs (argv-safe form, per the pack's own docs). The .github/RAILS.md path is deliberately unchanged everywhere — the ADO pack overlays that path by design. Plan doc updated to match reality: folds 0/A–D consolidated in PR MCKRUZ#47 (one commit per fold), E separate and spike-first; per-fold DONE markers with landed SHAs. Suite: 886 passed, command-contract lint green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Windows CI (first run of the new review-gate hook tests) checked out review-gate.sh with CRLF via autocrlf; bash rejects `set -uo pipefail\r` and exits 1 before the hook runs — every sh trigger test failed at the exit-0 assertion. Same class as d67db30, but here the shipped artifact itself was at risk: a plugin cloned on Windows would install broken hooks and rails scripts. .gitattributes pins *.sh to LF everywhere; .ps1 stays platform-default (pwsh is CRLF-tolerant — its 15 Windows tests passed). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
Author
|
CI note: the |
The Windows CI leg's `bash` resolves to C:\Windows\System32\bash.exe — the
WSL shim, which with no distro installed exits 1 ("Windows Subsystem for
Linux has no installed distributions") before the hook ever runs; all 17 sh
trigger tests failed on the exit-0 assertion. Git Bash is the bash a real
Windows install executes hooks with, so _bash() finds it explicitly
(ProgramFiles, then the git.exe-relative path) and never falls back to the
shim. Runners now also surface stderr in every assertion so the next
environmental failure names itself instead of reading "got 1".
(The prior .gitattributes fix stands on its own: a CRLF checkout would break
the hooks for real Windows installs regardless of which bash runs them.)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
First slice of making the plugin fully usable on Azure DevOps repos. Two artifacts plus their supporting changes:
profiles/ado-enterprise/— microsoft-enterprise's stack (C#/.NET 8 + Angular 17 + Azure, SOC 2 gates, 80% coverage, TDD) withstack.ci_cd.platform: azure-devops, so/sdlc-setupcomposes the existing Azure DevOps CI/CD pack (harness/packs/cicd/azure-devops/). Only intended deltas from the sibling profile:profile_id, the platform line, template wording, and the copiedswitchboard-rules.jsonself-id.docs/proposals/ado-repo-support-matrix.md— the plan for the remaining work, folded into five packages (one spec = one branch = one PR each): A installer platform-awareness (P0 — installs currently dump.github/payload on every platform and put rubrics where the ADO pipelines don't look), B pack-aware doctor, C PR-flow rails (az repos pr createin hooks/skills/permissions), D prose sweep + platform-switch runbook, E keyless gate auth via Azure AI Foundry + Entra ID RBAC (spike first).Supporting changes:
TestOnDiskProfiles: everyprofiles/*/profile.yamlmust pass the real schema, andprofile_idmust equal the directory name (theprofiles/<profile_id>/compliance/lookup contract). Future profiles get CI coverage the moment their directory exists.docs/architecture.md§1.1–1.2 anddocs/profiles.mdStep 5 described aprofilesregistry insideplugin.jsonthat does not exist — rewritten to describe the real mechanism (directory-listing auto-discovery;.claude-plugin/plugin.jsonis metadata-only).Why
The ADO pipelines pack has existed since the harness landed, but no shipped profile exercises it and the docs steered profile authors to a fictional registration step. This PR gives ADO a first-class, menu-selectable entry point and lays down the reviewed plan for removing the remaining GitHub-only assumptions — additively (see the proposal's "Additive guarantee": GitHub-profile installs and API-key auth stay byte/behavior-identical; a fold that must edit an existing test has broken the rule).
Reviewer notes
stacks/dotnet+cicd/azure-devops+ Angular) → gate check → artifact snapshot → upgrade dry-run idempotent (0 CONFLICT / 0 RETIRED); byte-leveldiff -rvs microsoft-enterprise shows only the intended delta; repo-wide sweep for profile enumerations and stale registration claims..github/workflows/files, and rubrics land at.github/profile/rubrics/instead of.azuredevops/rails/rubrics/. This PR ships the profile that Fold A's golden-tree test will install from.creative-toolingbefore this PR; only theado-enterpriseentries were added to keep the diff on-message.🤖 Generated with Claude Code