@amsterdamdatalabs/adl-agent-control-darwin-arm64 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/adl +4 -0
- package/bin/cursor-settings +14 -0
- package/bin/default-agent-file +14 -0
- package/bin/git +670 -0
- package/bin/git-ado +425 -0
- package/bin/global-agents +14 -0
- package/bin/global-surface-sweep +14 -0
- package/bin/health-check +38 -0
- package/bin/kimi-hooks +14 -0
- package/bin/lean-ctx-observe-strip +361 -0
- package/bin/lib/bun-compile-build.sh +34 -0
- package/bin/lib/lean-ctx-observe-hooks.sh +634 -0
- package/bin/managed-settings +14 -0
- package/bin/opencode-hooks +14 -0
- package/bin/reconcile +2648 -0
- package/bin/scratch-reap +14 -0
- package/bin/shell-path-policy +64 -0
- package/bin/surface-policy +14 -0
- package/bin/sync-and-reconcile +215 -0
- package/bin/update-azure-agent-pool +29 -0
- package/bin/validate-manifest +171 -0
- package/bin/vscode-settings +14 -0
- package/package.json +44 -0
- package/packages/agent-hooks/README.md +411 -0
- package/packages/agent-hooks/assets/hooks.json +97 -0
- package/packages/agent-hooks/assets/opencode-plugin.template.ts +224 -0
- package/packages/agent-hooks/bunfig.toml +27 -0
- package/packages/agent-hooks/deploy-profile.json +53 -0
- package/packages/agent-hooks/deploy-profile.schema.json +120 -0
- package/packages/agent-hooks/package.json +23 -0
- package/packages/agent-hooks/src/cli/args.ts +99 -0
- package/packages/agent-hooks/src/cli/doctor.ts +241 -0
- package/packages/agent-hooks/src/cli/rules.ts +133 -0
- package/packages/agent-hooks/src/deploy/deploy.ts +181 -0
- package/packages/agent-hooks/src/deploy/doctor.ts +158 -0
- package/packages/agent-hooks/src/deploy/index.ts +17 -0
- package/packages/agent-hooks/src/deploy/json-merge.ts +115 -0
- package/packages/agent-hooks/src/deploy/legacy-lock.ts +213 -0
- package/packages/agent-hooks/src/deploy/list.ts +117 -0
- package/packages/agent-hooks/src/deploy/lock.ts +65 -0
- package/packages/agent-hooks/src/deploy/opencode-template.ts +74 -0
- package/packages/agent-hooks/src/deploy/profile.ts +117 -0
- package/packages/agent-hooks/src/deploy/render.ts +162 -0
- package/packages/agent-hooks/src/deploy/source.ts +84 -0
- package/packages/agent-hooks/src/gating/config.ts +514 -0
- package/packages/agent-hooks/src/gating/root.ts +117 -0
- package/packages/agent-hooks/src/hooks/briefing/handler.ts +22 -0
- package/packages/agent-hooks/src/hooks/briefing/index.ts +320 -0
- package/packages/agent-hooks/src/hooks/contract.ts +112 -0
- package/packages/agent-hooks/src/hooks/crg/handler.ts +22 -0
- package/packages/agent-hooks/src/hooks/crg/index.ts +209 -0
- package/packages/agent-hooks/src/hooks/lean-ctx/handler.ts +22 -0
- package/packages/agent-hooks/src/hooks/lean-ctx/index.ts +173 -0
- package/packages/agent-hooks/src/hooks/lean-ctx/mapping.ts +121 -0
- package/packages/agent-hooks/src/hooks/lean-ctx/scope-rewrite.ts +207 -0
- package/packages/agent-hooks/src/hooks/log.ts +233 -0
- package/packages/agent-hooks/src/hooks/user-prompt-submit/config.ts +58 -0
- package/packages/agent-hooks/src/hooks/user-prompt-submit/constants.ts +149 -0
- package/packages/agent-hooks/src/hooks/user-prompt-submit/handler.ts +72 -0
- package/packages/agent-hooks/src/hooks/user-prompt-submit/index.ts +203 -0
- package/packages/agent-hooks/src/hooks/user-prompt-submit/match.ts +212 -0
- package/packages/agent-hooks/src/hooks/user-prompt-submit/skill-roots.ts +73 -0
- package/packages/agent-hooks/src/hooks/user-prompt-submit/skills.ts +98 -0
- package/packages/agent-hooks/src/hooks/user-prompt-submit/tokenizer.ts +115 -0
- package/packages/agent-hooks/src/hooks/user-prompt-submit/vector.ts +174 -0
- package/packages/agent-hooks/src/hosts/impl/claude.ts +47 -0
- package/packages/agent-hooks/src/hosts/impl/codex.ts +47 -0
- package/packages/agent-hooks/src/hosts/impl/cursor.ts +40 -0
- package/packages/agent-hooks/src/hosts/impl/kimi.ts +47 -0
- package/packages/agent-hooks/src/hosts/impl/opencode.ts +54 -0
- package/packages/agent-hooks/src/hosts/registry.ts +29 -0
- package/packages/agent-hooks/src/hosts/spec.ts +113 -0
- package/packages/agent-hooks/src/lean-ctx/env.ts +106 -0
- package/packages/agent-hooks/src/lean-ctx/mcp.ts +140 -0
- package/packages/agent-hooks/src/lib/spawn-with-timeout.ts +120 -0
- package/packages/agent-hooks/src/log/writer.ts +230 -0
- package/packages/agent-hooks/src/main.ts +269 -0
- package/packages/agent-hooks/src/pre-tool-use/handler.ts +549 -0
- package/packages/agent-hooks/src/rules/engine.ts +293 -0
- package/packages/agent-hooks/src/rules/impl/adl-build-run-denied.ts +51 -0
- package/packages/agent-hooks/src/rules/impl/adl-git-credential-bypass.ts +320 -0
- package/packages/agent-hooks/src/rules/impl/adl-git-identity.ts +249 -0
- package/packages/agent-hooks/src/rules/impl/adl-git-push-policy.ts +258 -0
- package/packages/agent-hooks/src/rules/impl/adl-human-azdo-bypass.ts +731 -0
- package/packages/agent-hooks/src/rules/impl/adl-identity.ts +128 -0
- package/packages/agent-hooks/src/rules/impl/adl-mcp-cli.ts +179 -0
- package/packages/agent-hooks/src/rules/impl/adl-pr-complete-pending.ts +65 -0
- package/packages/agent-hooks/src/rules/impl/adl-pr-review-role.ts +156 -0
- package/packages/agent-hooks/src/rules/impl/adl-pr-role.ts +121 -0
- package/packages/agent-hooks/src/rules/impl/adl-session-required.ts +403 -0
- package/packages/agent-hooks/src/rules/impl/adl-token-minting-role.ts +92 -0
- package/packages/agent-hooks/src/rules/impl/adl-workitem-role.ts +74 -0
- package/packages/agent-hooks/src/rules/impl/advisory-coverage.ts +43 -0
- package/packages/agent-hooks/src/rules/impl/advisory-finder.ts +62 -0
- package/packages/agent-hooks/src/rules/impl/agent-secrets-stay-unread.ts +173 -0
- package/packages/agent-hooks/src/rules/impl/agent-tamper-protection.ts +508 -0
- package/packages/agent-hooks/src/rules/impl/fs-canonical-checkout.ts +86 -0
- package/packages/agent-hooks/src/rules/impl/fs-git-internals.ts +75 -0
- package/packages/agent-hooks/src/rules/impl/fs-mv.ts +66 -0
- package/packages/agent-hooks/src/rules/impl/fs-rm.ts +83 -0
- package/packages/agent-hooks/src/rules/impl/fs-trash.ts +140 -0
- package/packages/agent-hooks/src/rules/impl/git-core.ts +101 -0
- package/packages/agent-hooks/src/rules/impl/git-helpers.ts +408 -0
- package/packages/agent-hooks/src/rules/impl/git-history.ts +77 -0
- package/packages/agent-hooks/src/rules/impl/git-paths.ts +139 -0
- package/packages/agent-hooks/src/rules/impl/git-plumbing.ts +167 -0
- package/packages/agent-hooks/src/rules/impl/git-protected-tree.ts +132 -0
- package/packages/agent-hooks/src/rules/impl/git-transitions.ts +292 -0
- package/packages/agent-hooks/src/rules/impl/git-verify.ts +95 -0
- package/packages/agent-hooks/src/rules/impl/git-worktree.ts +265 -0
- package/packages/agent-hooks/src/rules/impl/mcp-tool.ts +76 -0
- package/packages/agent-hooks/src/rules/impl/messages.ts +128 -0
- package/packages/agent-hooks/src/rules/impl/parse-uncertain.ts +143 -0
- package/packages/agent-hooks/src/rules/impl/pr-completion.ts +35 -0
- package/packages/agent-hooks/src/rules/impl/shell-remote-script-exec.ts +63 -0
- package/packages/agent-hooks/src/rules/impl/tool-azure-devops.ts +283 -0
- package/packages/agent-hooks/src/rules/impl/tool-bun-test.ts +81 -0
- package/packages/agent-hooks/src/rules/impl/tool-cargo.ts +66 -0
- package/packages/agent-hooks/src/rules/impl/tool-chmod-hook.ts +42 -0
- package/packages/agent-hooks/src/rules/impl/tool-find.ts +82 -0
- package/packages/agent-hooks/src/rules/impl/tool-frontend.ts +83 -0
- package/packages/agent-hooks/src/rules/impl/tool-grep.ts +93 -0
- package/packages/agent-hooks/src/rules/impl/tool-lean-ctx-global.ts +594 -0
- package/packages/agent-hooks/src/rules/impl/tool-native-search.ts +77 -0
- package/packages/agent-hooks/src/rules/ports.ts +178 -0
- package/packages/agent-hooks/src/rules/registry.ts +233 -0
- package/packages/agent-hooks/src/rules/shell/git-identity.ts +1415 -0
- package/packages/agent-hooks/src/rules/shell/git-internals.ts +186 -0
- package/packages/agent-hooks/src/rules/shell/invocation.ts +1083 -0
- package/packages/agent-hooks/src/rules/shell/piped-script.ts +201 -0
- package/packages/agent-hooks/src/rules/shell/prefixes.ts +214 -0
- package/packages/agent-hooks/src/rules/shell/protected-carrier-writes.ts +108 -0
- package/packages/agent-hooks/src/rules/shell/protected-carriers.ts +149 -0
- package/packages/agent-hooks/src/rules/shell/split.ts +179 -0
- package/packages/agent-hooks/src/rules/shell/substitution.ts +394 -0
- package/packages/agent-hooks/src/rules/shell/token.ts +180 -0
- package/packages/agent-hooks/src/rules/shell/xargs.ts +81 -0
- package/packages/agent-hooks/src/rules/spec.ts +152 -0
- package/packages/agent-hooks/src/surface-policy.ts +37 -0
- package/packages/agent-hooks/tsconfig.json +23 -0
- package/packages/agent-settings/assets/GLOBAL-AGENTS.md +107 -0
- package/packages/agent-settings/assets/agents/architect.toml +30 -0
- package/packages/agent-settings/assets/agents/code-reviewer.toml +27 -0
- package/packages/agent-settings/assets/agents/critic.toml +35 -0
- package/packages/agent-settings/assets/agents/executor.toml +28 -0
- package/packages/agent-settings/assets/agents/explore.toml +25 -0
- package/packages/agent-settings/assets/agents/planner.toml +29 -0
- package/packages/agent-settings/assets/lean-ctx/config.toml +39 -0
- package/packages/agent-settings/assets/lean-ctx/gitignore +6 -0
- package/packages/agent-settings/assets/lean-ctx/layout.toml +5 -0
- package/packages/agent-settings/assets/mcp.json +20 -0
- package/packages/agent-settings/managed/README.md +331 -0
- package/packages/agent-settings/managed/claude-managed-settings.json +150 -0
- package/packages/agent-settings/managed/codex-requirements.toml +105 -0
- package/packages/agent-settings/protected.json +470 -0
- package/packages/agent-settings/src/deploy/agent-render.ts +94 -0
- package/packages/agent-settings/src/deploy/agent-toml.ts +76 -0
- package/packages/agent-settings/src/deploy/agents-deploy.ts +129 -0
- package/packages/agent-settings/src/deploy/doctor.ts +201 -0
- package/packages/agent-settings/src/deploy/index.ts +33 -0
- package/packages/agent-settings/src/deploy/json-pretty.ts +66 -0
- package/packages/agent-settings/src/deploy/lean-ctx-deploy.ts +138 -0
- package/packages/agent-settings/src/deploy/legacy-lock.ts +286 -0
- package/packages/agent-settings/src/deploy/list.ts +135 -0
- package/packages/agent-settings/src/deploy/lock.ts +112 -0
- package/packages/agent-settings/src/deploy/mcp-deploy.ts +175 -0
- package/packages/agent-settings/src/deploy/mcp-inspect.ts +56 -0
- package/packages/agent-settings/src/deploy/mcp-merge.ts +164 -0
- package/packages/agent-settings/src/deploy/mcp-render.ts +80 -0
- package/packages/agent-settings/src/deploy/mcp-source.ts +43 -0
- package/packages/agent-settings/src/deploy/profile.ts +296 -0
- package/packages/agent-settings/src/deploy/settings.ts +65 -0
- package/packages/agent-settings/src/global-agents.ts +230 -0
- package/packages/agent-settings/src/global-surface-sweep.ts +2179 -0
- package/packages/agent-settings/src/kimi-hooks.ts +455 -0
- package/packages/agent-settings/src/opencode-hooks.ts +76 -0
- package/packages/agent-settings/src/surface-policy.ts +441 -0
- package/packages/agent-settings/surface-policy.json +20 -0
- package/packages/agent-skills/assets/code-review/SKILL.md +100 -0
- package/packages/agent-skills/assets/codebase-design/SKILL.md +98 -0
- package/packages/agent-skills/assets/codebase-design/references/DEEPENING.md +37 -0
- package/packages/agent-skills/assets/codebase-design/references/DESIGN-IT-TWICE.md +44 -0
- package/packages/agent-skills/assets/codebase-design/references/TESTABILITY.md +29 -0
- package/packages/agent-skills/assets/debug-issue/SKILL.md +40 -0
- package/packages/agent-skills/assets/diagnosing-bugs/SKILL.md +100 -0
- package/packages/agent-skills/assets/diagnosing-bugs/references/FEEDBACK-LOOP-TACTICS.md +34 -0
- package/packages/agent-skills/assets/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
- package/packages/agent-skills/assets/domain-modeling/SKILL.md +86 -0
- package/packages/agent-skills/assets/domain-modeling/references/ADR-FORMAT.md +47 -0
- package/packages/agent-skills/assets/domain-modeling/references/CONTEXT-FORMAT.md +60 -0
- package/packages/agent-skills/assets/explore-codebase/SKILL.md +41 -0
- package/packages/agent-skills/assets/handoff/SKILL.md +28 -0
- package/packages/agent-skills/assets/implement/SKILL.md +28 -0
- package/packages/agent-skills/assets/refactor-safely/SKILL.md +44 -0
- package/packages/agent-skills/assets/review-changes/SKILL.md +45 -0
- package/packages/agent-skills/assets/tdd/SKILL.md +49 -0
- package/packages/agent-skills/assets/tdd/references/mocking.md +59 -0
- package/packages/agent-skills/assets/tdd/references/tests.md +77 -0
- package/packages/agent-skills/assets/testing/SKILL.md +54 -0
- package/packages/agent-skills/assets/to-feature/SKILL.md +91 -0
- package/packages/agent-skills/assets/to-feature/references/FEATURE-SPEC-TEMPLATE.md +88 -0
- package/packages/agent-skills/assets/to-workitems/SKILL.md +90 -0
- package/packages/agent-skills/assets/to-workitems/references/AZURE-DEVOPS-HIERARCHY.md +118 -0
- package/packages/agent-skills/assets/to-workitems/references/TICKET-TEMPLATES.md +70 -0
- package/packages/agent-skills/assets/wayfinder/SKILL.md +100 -0
- package/packages/agent-skills/assets/wayfinder/references/TEMPLATES.md +35 -0
- package/packages/agent-skills/assets/wayfinder/references/TICKET-TYPES.md +8 -0
- package/packages/agent-skills/deploy-profile.json +9 -0
- package/packages/agent-skills/deploy-profile.schema.json +45 -0
- package/packages/agent-skills/dist/deploy.d.ts +27 -0
- package/packages/agent-skills/dist/deploy.d.ts.map +1 -0
- package/packages/agent-skills/dist/deploy.js +186 -0
- package/packages/agent-skills/dist/deploy.js.map +1 -0
- package/packages/agent-skills/dist/doctor.d.ts +24 -0
- package/packages/agent-skills/dist/doctor.d.ts.map +1 -0
- package/packages/agent-skills/dist/doctor.js +141 -0
- package/packages/agent-skills/dist/doctor.js.map +1 -0
- package/packages/agent-skills/dist/fs-utils.d.ts +8 -0
- package/packages/agent-skills/dist/fs-utils.d.ts.map +1 -0
- package/packages/agent-skills/dist/fs-utils.js +40 -0
- package/packages/agent-skills/dist/fs-utils.js.map +1 -0
- package/packages/agent-skills/dist/index.d.ts +8 -0
- package/packages/agent-skills/dist/index.d.ts.map +1 -0
- package/packages/agent-skills/dist/index.js +8 -0
- package/packages/agent-skills/dist/index.js.map +1 -0
- package/packages/agent-skills/dist/legacy-lock.d.ts +44 -0
- package/packages/agent-skills/dist/legacy-lock.d.ts.map +1 -0
- package/packages/agent-skills/dist/legacy-lock.js +121 -0
- package/packages/agent-skills/dist/legacy-lock.js.map +1 -0
- package/packages/agent-skills/dist/list.d.ts +23 -0
- package/packages/agent-skills/dist/list.d.ts.map +1 -0
- package/packages/agent-skills/dist/list.js +75 -0
- package/packages/agent-skills/dist/list.js.map +1 -0
- package/packages/agent-skills/dist/manifest.d.ts +15 -0
- package/packages/agent-skills/dist/manifest.d.ts.map +1 -0
- package/packages/agent-skills/dist/manifest.js +57 -0
- package/packages/agent-skills/dist/manifest.js.map +1 -0
- package/packages/agent-skills/dist/profile.d.ts +41 -0
- package/packages/agent-skills/dist/profile.d.ts.map +1 -0
- package/packages/agent-skills/dist/profile.js +86 -0
- package/packages/agent-skills/dist/profile.js.map +1 -0
- package/packages/agent-skills/dist/skill-config.d.ts +24 -0
- package/packages/agent-skills/dist/skill-config.d.ts.map +1 -0
- package/packages/agent-skills/dist/skill-config.js +68 -0
- package/packages/agent-skills/dist/skill-config.js.map +1 -0
- package/packages/agent-skills/dist/skill-meta.d.ts +17 -0
- package/packages/agent-skills/dist/skill-meta.d.ts.map +1 -0
- package/packages/agent-skills/dist/skill-meta.js +67 -0
- package/packages/agent-skills/dist/skill-meta.js.map +1 -0
- package/packages/agent-skills/package.json +31 -0
- package/packages/agent-skills/src/deploy.ts +222 -0
- package/packages/agent-skills/src/doctor.ts +178 -0
- package/packages/agent-skills/src/fs-utils.ts +40 -0
- package/packages/agent-skills/src/index.ts +29 -0
- package/packages/agent-skills/src/legacy-lock.ts +152 -0
- package/packages/agent-skills/src/list.ts +94 -0
- package/packages/agent-skills/src/manifest.ts +66 -0
- package/packages/agent-skills/src/profile.ts +128 -0
- package/packages/agent-skills/src/skill-config.ts +75 -0
- package/packages/agent-skills/src/skill-meta.ts +78 -0
- package/packages/agent-skills/tsconfig.build.json +13 -0
- package/packages/agent-skills/tsconfig.json +23 -0
- package/packages/azdo/README.md +111 -0
- package/packages/azdo/package.json +21 -0
- package/packages/azdo/src/azdo-pl.ts +275 -0
- package/packages/azdo/src/azdo-pr-review.ts +160 -0
- package/packages/azdo/src/azdo-pr.ts +289 -0
- package/packages/azdo/src/azdo-repo-doctor.ts +839 -0
- package/packages/azdo/src/azdo-wit.ts +145 -0
- package/packages/azdo/src/cli.ts +251 -0
- package/packages/azdo/src/lib/agent-identity.ts +198 -0
- package/packages/azdo/src/lib/agent-token.ts +167 -0
- package/packages/azdo/src/lib/client.ts +259 -0
- package/packages/azdo/src/lib/graph-identity.ts +153 -0
- package/packages/azdo/src/lib/validate-pr-metadata.ts +57 -0
- package/packages/azdo/src/mcp-server.ts +209 -0
- package/packages/azdo/src/tool-dispatch.ts +204 -0
- package/packages/azdo/tsconfig.json +13 -0
- package/packages/fleet/jobs/git-maintain/src/main.ts +588 -0
- package/packages/fleet/manifest.json +207 -0
- package/packages/fleet/manifest.schema.json +283 -0
- package/packages/fleet/src/default-agent-file.ts +144 -0
- package/packages/fleet/src/install-adl-package.ts +178 -0
- package/packages/fleet/src/install-embedding-model.ts +412 -0
- package/packages/fleet/src/launch-agents.ts +649 -0
- package/packages/fleet/src/managed-settings.ts +278 -0
- package/packages/fleet/src/scratch-reap.ts +601 -0
- package/packages/fleet/src/vscode-settings.ts +705 -0
- package/packages/fleet/systemd/adl-azure-agent-update.service +13 -0
- package/packages/fleet/systemd/adl-azure-agent-update.timer +10 -0
- package/packages/repo-controls/AGENTS.md +96 -0
- package/packages/repo-controls/CLAUDE.md +1 -0
- package/packages/repo-controls/LICENSE +20 -0
- package/packages/repo-controls/README.md +493 -0
- package/packages/repo-controls/assets/enable-integration-auto-complete.mjs +79 -0
- package/packages/repo-controls/assets/promote.ts +371 -0
- package/packages/repo-controls/assets/version-bump.sh +189 -0
- package/packages/repo-controls/azure-pipelines.yml +274 -0
- package/packages/repo-controls/bin/adl-repo-controls.ts +10 -0
- package/packages/repo-controls/bunfig.toml +58 -0
- package/packages/repo-controls/package/adl-compliance/AGENTS.md +163 -0
- package/packages/repo-controls/package/adl-compliance/CLAUDE.md +1 -0
- package/packages/repo-controls/package/adl-compliance/conftest.py +78 -0
- package/packages/repo-controls/package/adl-compliance/pyproject.toml +31 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/__init__.py +50 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/__init__.py +98 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/__init__.py +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/check.py +210 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-bad-status/docs/architecture/overview.md +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-bad-status/docs/decisions/adr-901-proposed.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-broken-backlink/docs/decisions/adr-902-dangling.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-clean/docs/architecture/overview.md +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-clean/docs/decisions/adr-900-example.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-frontmatter-mismatch/.plans/b_committed/26-08-08-lifecycle-fixture.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-frontmatter-mismatch/.specs/demo/lifecycle.md +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-frontmatter-mismatch/docs/decisions/adr-903-frontmatter-mismatch.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-inactive-plan/.plans/c_done/26-08-08-completed-fixture.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-inactive-plan/.specs/demo/lifecycle.md +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/fixtures/adr-lifecycle-inactive-plan/docs/decisions/adr-904-completed-plan.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/test_check.py +127 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/__init__.py +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/check.py +91 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/AGENTS.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/CLAUDE.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/architecture/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/compliance/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/decisions/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/index.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/operations/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/research/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/stray-root-file.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/totally-made-up/nonsense.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/test_check.py +106 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/__init__.py +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/check.py +291 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/fixtures/clean/backend/clean.rs +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/fixtures/excluded/frontend/mobile/src/i18n/locales/zh-CN/strings.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/fixtures/violation/backend/escaped.rs +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/fixtures/violation/backend/raw.rs +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/fixtures/violation/backend//346/226/207/344/273/266.rs +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/test_check.py +193 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/check.py +140 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/fixtures/index-updated-clean/docs/architecture/foo.md +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/fixtures/index-updated-clean/docs/architecture/index.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/fixtures/index-updated-violation/docs/architecture/foo.md +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/fixtures/index-updated-violation/docs/architecture/index.md +9 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/index_updated/test_check.py +98 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/check.py +378 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/docs-knowledge-indexes.yaml +192 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-clean/docs/index.md +14 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-clean/docs/one.md +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-clean/docs/two.md +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-clean/docs-knowledge-indexes.yaml +20 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-duplicate/docs/index.md +15 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-duplicate/docs/one.md +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-duplicate/docs/two.md +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-duplicate/docs-knowledge-indexes.yaml +16 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-missing-entry/docs/index.md +13 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-missing-entry/docs/one.md +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-missing-entry/docs/two.md +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-missing-entry/docs-knowledge-indexes.yaml +16 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/test_check.py +102 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/check.py +387 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/fixtures/ledger-bad-date/plans/LEDGER.md +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/fixtures/ledger-clean/plans/LEDGER.md +6 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/fixtures/ledger-empty-table/plans/LEDGER.md +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/fixtures/ledger-long-event/plans/LEDGER.md +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/fixtures/ledger-violation/plans/LEDGER.md +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/test_check.py +427 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/__init__.py +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/check.py +84 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/fixtures/markdown-structure-bad-fence/docs/bad-fence.md +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/fixtures/markdown-structure-bad-fence/docs/valid.md +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/fixtures/markdown-structure-bad-frontmatter/docs/bad-front-matter.md +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/fixtures/markdown-structure-bad-frontmatter/docs/valid.md +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/fixtures/markdown-structure-clean/docs/valid.md +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/markdown_ast/test_check.py +126 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/check.py +210 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/docs-okf-profiles.yaml +119 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs/architecture/demo.md +17 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs-okf-profiles.yaml +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-violation/docs/architecture/bad-status.md +17 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-violation/docs-okf-profiles.yaml +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/test_check.py +49 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/register.py +159 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/check.py +578 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-clean/docs/architecture/backend/crate-overview.md +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-clean/docs/architecture/team/team-overview.md +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-clean/docs/compliance/controls/control-matrix.md +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-clean/docs/compliance/controls/control-matrix.yaml +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-clean/docs/research/benchmarks/note.md +24 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/backend/crate-overview.md +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/product/stable-delivery.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/product/stable-recommendation.md +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/product/target-narration.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/architecture/team/team-overview.md +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/compliance/controls/control-matrix.md +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/compliance/controls/control-matrix.yaml +17 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/fixtures/semantics-violations/docs/research/benchmarks/bad-research.md +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/test_check.py +461 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/__init__.py +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/check.py +124 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/.workflows/AGENTS.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/.workflows/CLAUDE.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/CLAUDE.md +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/INVARIANTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/bad-pointer/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/bad-pointer/CLAUDE.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/docs/AGENTS.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/docs/CLAUDE.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/missing-pair/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/owned/AGENTS.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/fixtures/owned/CLAUDE.md +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/agents_layout/test_check.py +116 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/ci_paths/__init__.py +13 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/ci_paths/check.py +380 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/ci_paths/fixtures/redeclared-workflows-tree/automation/pipelines/pr-validation.yaml +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/ci_paths/test_check.py +274 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/check.py +227 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/grants.yaml +6 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/fresh/fresh.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub1/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub10/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub11/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub2/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub3/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub4/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub5/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub6/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub7/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub8/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/many/sub9/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/services/i18n/locales/de/common.json +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/frontend/packages/desktop/src/vendored-crate/Cargo.toml +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/grants.yaml +6 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/fresh/fresh.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub1/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub10/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub11/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub2/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub3/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub4/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub5/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub6/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub7/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub8/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/many/sub9/only.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/frontend/packages/desktop/src/renderer/solo/item.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/grants.yaml +6 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/test_check.py +138 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/check.py +240 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/fixtures/markdown-trees-clean/.plans/a_new/plan.md +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/fixtures/markdown-trees-clean/backend/AGENTS.md +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/fixtures/markdown-trees-clean/docs/page.md +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/fixtures/markdown-trees-stray/backend/notes.md +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/fixtures/markdown-trees-stray/docs/page.md +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/test_check.py +220 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/__init__.py +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/check.py +225 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/fixtures/open-work-cap-clean/plans/GAPS-AND-FINDINGS.md +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/fixtures/open-work-cap-clean/plans/features/az601-clean/spec.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/test_check.py +330 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/check.py +240 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/agent/crates/enact-providers/src/snapshots/README.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/backend/crates/enact-app/assets/builtin-assistants/avatars/assistant.jpg +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/backend/crates/enact-assets/assets/logos/tools/coding/tool.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/backend/crates/enact-session/src/backend/codex_init_prompt.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/mobile/assets/images/icon.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/packages/desktop/src/renderer/assets/logos/brand/app.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/packages/desktop/src/renderer/assets/themes/default-theme.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/public/pwa/icon-192.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-allowed/frontend/resources/product.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-stray/apps/legacy/file.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-stray/backend/crates/enact-session/src/backend/README.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/fixtures/placement-stray/frontend/unapproved/screenshot.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/test_check.py +230 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plan_metadata.py +53 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/__init__.py +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/check.py +438 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/AGENTS.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/items/az351-restore-entrypoint.md +9 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/spec.md +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/templates/feature.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-violation/plans/features/az347-test-coverage/items/az351-restore-entrypoint.md +9 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-violation/plans/features/az347-test-coverage/spec.md +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +461 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/__init__.py +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/check.py +62 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/NotAMigration.sql +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/0001_long_prefix.sql +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/001_init.sql +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/002_add_index.sql +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/003-dashed-slug.sql +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/004_MixedCase.sql +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/005_trailing space.sql +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/01_short_prefix.sql +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/fixtures/migration-filenames/backend/crates/demo/migrations/not-a-migration.sql +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/profile_data/test_check.py +116 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/__init__.py +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/check.py +188 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/.plans/c_done/26-07-27-history.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/README.md +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/architecture/product/links.md +20 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-broken/docs/architecture/product/route-target.md +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/.plans/c_done/26-07-27-history.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/README.md +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/architecture/product/links.md +20 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/fixtures/link-targets-clean/docs/architecture/product/route-target.md +8 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/test_check.py +166 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/__init__.py +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/check.py +135 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.agents/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.changeset/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.claude/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.code-review-graph/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.code-review-graph_old/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.codex/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.cursor/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.cursorrules +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.dockerignore +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.docs/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.donors/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.gitattributes +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.kimi-code/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.lfsconfig +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.mcp.json +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.opencode/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/.workflows/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/AGENTS.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/CHANGELOG.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/CLAUDE-INVARIANTS.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/CLAUDE.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/INDEPENDENT-VERIFICATION.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/INVARIANTS.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/LICENSE +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/NOTICE +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/README.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/RELEASE.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/VERSION +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/backend/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/compliance/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/dev/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/docker/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/docs/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/frontend/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/infra/declared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/justfile +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/opencode.jsonc +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/rule-tests/undeclared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/rules/undeclared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/unapproved-root/undeclared.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/fixtures/undeclared-root-file.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/test_check.py +122 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/check.py +290 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/.changeset/some-change.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/.plans/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/.specs/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/.workflows/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/CHANGELOG.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/CLAUDE.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/INDEPENDENT-VERIFICATION.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/INVARIANTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/README.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/RELEASE.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/STRAY.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/docs/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/docs/architecture/note.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-clean/frontend/README.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-missing-guide/.workflows/AGENTS.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-missing-guide/AGENTS.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-missing-guide/README.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-missing-guide/docs/overview.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/fixtures/root-markdown-missing-guide/plans/AGENTS.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/test_check.py +329 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/check.py +127 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/a/b/c/d/at-limit.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/a/b/c/d/e/too-deep.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-01.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-02.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-03.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-04.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-05.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-06.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-07.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-08.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-09.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-10.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-11.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-12.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-13.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-14.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-15.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/fixtures/scripts-layout/.workflows/scripts/direct-16.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/test_check.py +163 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/__init__.py +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/__init__.py +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/check.py +169 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/attribute-without-conversion/.gitattributes +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/attribute-without-conversion/large file.bin +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/clean/.gitattributes +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/clean/large file.bin +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/clean/small.txt +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/missing-filter/large file.bin +0 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/unmatched-extension/.gitattributes +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/unmatched-extension/payload.dat +0 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/test_check.py +133 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/__init__.py +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/check.py +129 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/fixtures/disjoint/gate-registry.yaml +13 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/fixtures/empty/gate-registry.yaml +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/fixtures/overlapping/gate-registry.yaml +13 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/pipeline/phase_disjoint/test_check.py +109 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/__init__.py +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/__init__.py +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/check.py +149 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/fixtures/clean/docs/readme.md +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/fixtures/relevant/VERSION +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/changeset_plan/test_check.py +151 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/__init__.py +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/check.py +202 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/.workflows/changesets/package.json +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/.workflows/package.json +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/CHANGELOG.md +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/aligned/VERSION +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/.workflows/changesets/package.json +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/.workflows/package.json +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/CHANGELOG.md +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/fixtures/mismatched/VERSION +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/release/version_release/test_check.py +162 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/__init__.py +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/check.py +103 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/git-bad.sh +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/git-note.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/good.sh +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/grep-bad.sh +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/grep-note.sh +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/grep-trailing.sh +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/compliance_py/checks/notes.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/elsewhere/loose-git.sh +6 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/fixtures/no-banned-commands/elsewhere/loose-grep.sh +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/banned_commands/test_check.py +117 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/__init__.py +13 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/check.py +265 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/fixtures/ignored-paths/keep.log +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/fixtures/ignored-paths/src/main.rs +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/test_check.py +180 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/license_declared/__init__.py +12 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/license_declared/check.py +84 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/license_declared/fixtures/license-declared-clean/LICENSE +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/license_declared/fixtures/license-declared-mismatch/LICENSE +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/license_declared/fixtures/license-declared-missing/README.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/license_declared/test_check.py +66 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/__init__.py +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/check.py +167 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/Cargo.lock +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/Cargo.toml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/rust-toolchain.toml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/backend/src/main.rs +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/clean/frontend/bun.lock +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/Cargo.lock +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/Cargo.toml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/rust-toolchain.toml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/backend/src/main.rs +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/fixtures/empty-bun-lock/frontend/bun.lock +0 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_check.py +109 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/cli.py +483 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/__init__.py +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/ast_grep.py +199 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/batch.py +52 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/check.py +303 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/constants.py +106 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/context.py +99 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/errors.py +32 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/finding.py +65 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/models.py +40 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/receipt.py +63 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/scope.py +82 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/verdict.py +161 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/__init__.py +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.py +131 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.toml +30 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/docs_shape.py +65 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.alt.yaml +791 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.schema.yaml +176 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml +791 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/grants-registry.yaml +112 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/grants.py +129 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/registry.py +281 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/root_shape.py +250 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/severity-policy.yaml +114 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/providers/__init__.py +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/runner.py +371 -0
- package/packages/repo-controls/package/adl-compliance/uv.lock +199 -0
- package/packages/repo-controls/package.json +33 -0
- package/packages/repo-controls/scripts/hooks/commit-msg +63 -0
- package/packages/repo-controls/scripts/hooks/lib/hook-log.sh +62 -0
- package/packages/repo-controls/scripts/hooks/post-checkout +15 -0
- package/packages/repo-controls/scripts/hooks/post-commit +18 -0
- package/packages/repo-controls/scripts/hooks/pre-commit +82 -0
- package/packages/repo-controls/scripts/hooks/pre-push +144 -0
- package/packages/repo-controls/src/azdo-push.ts +463 -0
- package/packages/repo-controls/src/azure-devops-governance.ts +248 -0
- package/packages/repo-controls/src/azure-devops-remote.ts +61 -0
- package/packages/repo-controls/src/cli.ts +188 -0
- package/packages/repo-controls/src/compliance-config.ts +200 -0
- package/packages/repo-controls/src/config.ts +690 -0
- package/packages/repo-controls/src/constants.ts +97 -0
- package/packages/repo-controls/src/coverage-ratchet.ts +153 -0
- package/packages/repo-controls/src/doc-freshness.ts +172 -0
- package/packages/repo-controls/src/doctor.ts +304 -0
- package/packages/repo-controls/src/findings-ratchet.ts +163 -0
- package/packages/repo-controls/src/gitignore-block.ts +253 -0
- package/packages/repo-controls/src/hook-log.ts +72 -0
- package/packages/repo-controls/src/hook.ts +694 -0
- package/packages/repo-controls/src/install.ts +506 -0
- package/packages/repo-controls/src/integrity.ts +104 -0
- package/packages/repo-controls/src/promote.ts +25 -0
- package/packages/repo-controls/src/runtime.ts +110 -0
- package/packages/repo-controls/src/workflows-drift.ts +106 -0
- package/packages/repo-controls/src/worktree-guard.ts +272 -0
- package/packages/repo-controls/src/worktree-limit.ts +11 -0
- package/packages/repo-controls/tsconfig.json +14 -0
- package/packages/repo-controls/workflows/scripts/release/verify-npm-artifact.ts +119 -0
|
@@ -0,0 +1,839 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* C9 (docs/specs/two-branch-standard-2026-09-27.md §3.3, §1a): read-only
|
|
3
|
+
* check of one repository against the two-branch standard. Same token path
|
|
4
|
+
* as every other tool in this package (the session's own agent identity via
|
|
5
|
+
* lib/agent-identity.ts) — no separate credential, no mutation.
|
|
6
|
+
*
|
|
7
|
+
* REPO_STANDARD below is the single place the standard's expected values
|
|
8
|
+
* live; every check reads from it rather than repeating a literal.
|
|
9
|
+
*
|
|
10
|
+
* REST APIs used (verified against Microsoft's docs 2026-09-27):
|
|
11
|
+
* - Git Repositories — Get Repository
|
|
12
|
+
* GET {org}/{project}/_apis/git/repositories/{repository}?api-version=7.1
|
|
13
|
+
* https://learn.microsoft.com/en-us/rest/api/azure/devops/git/repositories/get-repository
|
|
14
|
+
* - Git Refs — List (branches)
|
|
15
|
+
* GET {org}/{project}/_apis/git/repositories/{repositoryId}/refs?filter=heads/&api-version=7.1
|
|
16
|
+
* https://learn.microsoft.com/en-us/rest/api/azure/devops/git/refs/list
|
|
17
|
+
* - Build Definitions — List (has-a-pipeline probe; already used by azdo-pl.ts)
|
|
18
|
+
* GET {org}/{project}/_apis/build/definitions?repositoryId=..&repositoryType=TfsGit&api-version=7.1
|
|
19
|
+
* - Git-scoped Policy Configurations (repository + branch scoped; the plain
|
|
20
|
+
* /_apis/policy/configurations List doc itself names this as the one to
|
|
21
|
+
* use for scope filtering: "Instead, use the /_apis/git/policy/configurations
|
|
22
|
+
* API, which provides first class scope filtering support." Already used
|
|
23
|
+
* the same way by packages/repo-controls/src/azure-devops-governance.ts.)
|
|
24
|
+
* GET {org}/{project}/_apis/git/policy/configurations?repositoryId=..&refName=refs/heads/{branch}&api-version=7.1
|
|
25
|
+
* https://learn.microsoft.com/en-us/rest/api/azure/devops/policy/configurations/list
|
|
26
|
+
* - Security — Access Control Lists Query (Git Repositories namespace)
|
|
27
|
+
* GET {org}/_apis/accesscontrollists/{namespaceId}?token=repoV2/{projectId}/{repositoryId}
|
|
28
|
+
* &descriptors=<comma-separated>&includeExtendedInfo=true&api-version=7.1
|
|
29
|
+
* https://learn.microsoft.com/en-us/rest/api/azure/devops/security/access-control-lists/query
|
|
30
|
+
* (namespace id, token shape and the READ/CONTRIBUTE/PR_CONTRIBUTE bit
|
|
31
|
+
* values below are the same ones already read live and recorded in
|
|
32
|
+
* ADL-ISMS-Policies/docs/scripts/enact-agent-git-permissions.py and
|
|
33
|
+
* .../docs/evidence/vanta-documents/100-.../azure-devops-git-security-namespace.json)
|
|
34
|
+
* - Graph — Subject Query (resolve a service principal's descriptor by display name)
|
|
35
|
+
* POST https://vssps.dev.azure.com/{org}/_apis/graph/subjectquery?api-version=7.1-preview.1
|
|
36
|
+
* body: { query: <displayName>, subjectKind: ['User'] }
|
|
37
|
+
* https://learn.microsoft.com/en-us/rest/api/azure/devops/graph/subject-query/query
|
|
38
|
+
* - Identities — Read Identities (resolve a BUILD SERVICE's descriptor by
|
|
39
|
+
* exact display name — a build service is not a Graph 'User'/'Group'
|
|
40
|
+
* subject, so Subject Query above cannot find it; used only by
|
|
41
|
+
* checkBuildServiceCanRelease() below, lib/graph-identity.ts's
|
|
42
|
+
* resolveIdentityByDisplayName())
|
|
43
|
+
* GET https://vssps.dev.azure.com/{org}/_apis/identities?searchFilter=General&filterValue=<name>&queryMembership=None&api-version=7.1
|
|
44
|
+
* https://learn.microsoft.com/en-us/rest/api/azure/devops/ims/identities/read-identities
|
|
45
|
+
* - Build — General Settings — Get (which build service identity actually
|
|
46
|
+
* runs the pipeline: `enforceJobAuthScope` is "Limit job authorization
|
|
47
|
+
* scope to current project" in the UI — true means the PROJECT-scoped
|
|
48
|
+
* build service runs the job, false means the ORG/COLLECTION-scoped one
|
|
49
|
+
* does; used only by checkBuildServiceCanRelease() below)
|
|
50
|
+
* GET {org}/{project}/_apis/build/generalsettings?api-version=7.1
|
|
51
|
+
* https://learn.microsoft.com/en-us/rest/api/azure/devops/build/general-settings/get
|
|
52
|
+
*
|
|
53
|
+
* checkBuildServiceCanRelease() (C9 follow-up, Tarun 2026-09-29): a real
|
|
54
|
+
* pipeline failure — agent-identities build 4897, stage "Create integration
|
|
55
|
+
* to main PR" (packages/repo-controls/assets/promote.ts) — 403'd with
|
|
56
|
+
* `TF401027: You need the Git 'PullRequestContribute' permission ... identity
|
|
57
|
+
* 'Build\<projectId>', scope 'repository'`. checkBuildServicePermissions()
|
|
58
|
+
* above already checks a DIFFERENT, finer-grained set of per-branch bits for
|
|
59
|
+
* a different purpose (branch-scoped PolicyExempt allow/deny) and stops at
|
|
60
|
+
* "not found" for an unresolvable identity; it does not name the exact
|
|
61
|
+
* identity display name or the fix path, and a 403 reading the ACL itself
|
|
62
|
+
* propagates out of `repoDoctorCheck()` uncaught rather than being reported
|
|
63
|
+
* as its own finding. checkBuildServiceCanRelease() answers one narrow
|
|
64
|
+
* question directly, per the real failure above: can the identity that
|
|
65
|
+
* ACTUALLY RUNS THE PIPELINE (repo scope) push a `***NO_CI***` bump commit
|
|
66
|
+
* to `integration` (GenericContribute), bypass `integration`'s own policies
|
|
67
|
+
* while doing so (PolicyExempt), and create/update the `integration -> main`
|
|
68
|
+
* PR and set auto-complete (PullRequestContribute) — and it FAILS loudly,
|
|
69
|
+
* naming the permission, the identity's display name and the fix path, on
|
|
70
|
+
* any of: the permission not effectively allowed, the identity not
|
|
71
|
+
* resolvable, or the ACL itself not readable by the calling agent.
|
|
72
|
+
*
|
|
73
|
+
* Policy type GUIDs (verified against the azure-devops-cli-extension source,
|
|
74
|
+
* packages/repo-controls already hardcodes the first three the same way):
|
|
75
|
+
* minimum reviewers fa4e907d-c16b-4a4c-9dfa-4906e5d171dd
|
|
76
|
+
* required reviewers fd2167ab-b0be-447a-8ec8-39368250530e
|
|
77
|
+
* build validation 0609b952-1397-4640-95ec-e00a01b2c241
|
|
78
|
+
* merge strategy fa4e907d-c16b-4a4c-9dfa-4916e5d171ab
|
|
79
|
+
* comment requirements c6a1889d-b943-4856-b76f-9e46bb6b0df2
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
import { resolveAgentIdentity } from "./lib/agent-identity.ts";
|
|
83
|
+
import { AdoClient, resolveOrg, resolveProject, resolveRepository } from "./lib/client.ts";
|
|
84
|
+
import { fetchJson, resolveAgentDescriptor, resolveIdentityByDisplayName } from "./lib/graph-identity.ts";
|
|
85
|
+
|
|
86
|
+
/** Treat blank and whitespace-only env overrides as unset, like lib/client.ts's own `configured()`. */
|
|
87
|
+
function configured(value: string | undefined): string | undefined {
|
|
88
|
+
const trimmed = value?.trim();
|
|
89
|
+
return trimmed ? trimmed : undefined;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** The org-root REST base (no project segment) — accesscontrollists lives here, not under a project. */
|
|
93
|
+
function orgBaseUrl(): string {
|
|
94
|
+
return configured(process.env.AZURE_DEVOPS_ORG_BASE_URL) ?? `https://dev.azure.com/${resolveOrg()}`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// fetchJson/postJson (bearer-token GET/POST against an arbitrary Azure DevOps
|
|
98
|
+
// host) and resolveAgentDescriptor (Graph Subject Query) live in
|
|
99
|
+
// ./lib/graph-identity.ts — this file only adds its own orgBaseUrl() (the
|
|
100
|
+
// accesscontrollists host); vsspsBaseUrl() moved with the Graph helpers.
|
|
101
|
+
|
|
102
|
+
// -------------------------------------------------------------------------
|
|
103
|
+
// The standard, in one place.
|
|
104
|
+
// -------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
export const POLICY_TYPE = {
|
|
107
|
+
minimumReviewers: "fa4e907d-c16b-4a4c-9dfa-4906e5d171dd",
|
|
108
|
+
requiredReviewers: "fd2167ab-b0be-447a-8ec8-39368250530e",
|
|
109
|
+
build: "0609b952-1397-4640-95ec-e00a01b2c241",
|
|
110
|
+
mergeStrategy: "fa4e907d-c16b-4a4c-9dfa-4916e5d171ab",
|
|
111
|
+
commentRequirements: "c6a1889d-b943-4856-b76f-9e46bb6b0df2",
|
|
112
|
+
} as const;
|
|
113
|
+
|
|
114
|
+
/** Git Repositories security namespace (2e9eb7ed-3c0a-47d4-87c1-0ffdd275fd87) permission bits, read live 2026-09-26 — see the file header for the source. */
|
|
115
|
+
export const GIT_REPO_PERMISSION_BIT = {
|
|
116
|
+
genericRead: 2,
|
|
117
|
+
genericContribute: 4,
|
|
118
|
+
forcePush: 8,
|
|
119
|
+
policyExempt: 128,
|
|
120
|
+
pullRequestContribute: 16384,
|
|
121
|
+
pullRequestBypassPolicy: 32768,
|
|
122
|
+
} as const;
|
|
123
|
+
|
|
124
|
+
export const GIT_REPOSITORIES_NAMESPACE_ID = "2e9eb7ed-3c0a-47d4-87c1-0ffdd275fd87";
|
|
125
|
+
|
|
126
|
+
type PermissionBitName = keyof typeof GIT_REPO_PERMISSION_BIT;
|
|
127
|
+
|
|
128
|
+
export const REPO_STANDARD = {
|
|
129
|
+
branches: {
|
|
130
|
+
required: ["integration", "main"] as const,
|
|
131
|
+
forbidden: ["develop"] as const,
|
|
132
|
+
defaultBranch: "main",
|
|
133
|
+
},
|
|
134
|
+
integration: {
|
|
135
|
+
// No human gate: neither a minimum-reviewer nor a required-reviewer
|
|
136
|
+
// policy may be enabled here.
|
|
137
|
+
forbiddenReviewerPolicies: [POLICY_TYPE.minimumReviewers, POLICY_TYPE.requiredReviewers] as const,
|
|
138
|
+
mergeStrategy: { allowSquash: true, allowRebase: false, allowRebaseMerge: false, allowNoFastForward: false },
|
|
139
|
+
buildValidationRequiredWhenPipelineExists: true,
|
|
140
|
+
},
|
|
141
|
+
main: {
|
|
142
|
+
minimumReviewers: { minimumApproverCount: 1, creatorVoteCounts: false, resetOnSourcePush: true, isBlocking: true },
|
|
143
|
+
// A named required reviewer is forbidden, not merely optional: Tarun,
|
|
144
|
+
// 2026-09-27, "I should not be required for it" — the promotion PR
|
|
145
|
+
// (raised by the pipeline, not directed by a human) is approved by ANY
|
|
146
|
+
// one human via the minimum-reviewer policy above; naming one reviewer
|
|
147
|
+
// would make that person a standing approval bottleneck the standard
|
|
148
|
+
// never asked for. docs/specs/two-branch-standard-2026-09-27.md §1b.1,
|
|
149
|
+
// §1b.6; ADL-ISMS-Policies docs/questions.md A121.
|
|
150
|
+
forbiddenReviewerPolicies: [POLICY_TYPE.requiredReviewers] as const,
|
|
151
|
+
mergeStrategy: { allowSquash: false, allowRebase: false, allowRebaseMerge: false, allowNoFastForward: true },
|
|
152
|
+
commentRequirementsRequired: true,
|
|
153
|
+
buildValidationRequiredWhenPipelineExists: true,
|
|
154
|
+
},
|
|
155
|
+
// One table for every effective-permission expectation this checker reads
|
|
156
|
+
// via the Git Repositories security namespace ACL, so the standard never
|
|
157
|
+
// repeats a bit name or a token shape in two places.
|
|
158
|
+
permissions: {
|
|
159
|
+
namespaceId: GIT_REPOSITORIES_NAMESPACE_ID,
|
|
160
|
+
agents: {
|
|
161
|
+
"agent-tarun": {
|
|
162
|
+
allow: ["genericContribute", "pullRequestContribute"],
|
|
163
|
+
deny: ["forcePush", "policyExempt", "pullRequestBypassPolicy"],
|
|
164
|
+
},
|
|
165
|
+
"agent-vivek": {
|
|
166
|
+
allow: ["genericContribute", "pullRequestContribute"],
|
|
167
|
+
deny: ["forcePush", "policyExempt", "pullRequestBypassPolicy"],
|
|
168
|
+
},
|
|
169
|
+
"agent-reviewer": { allow: ["pullRequestContribute"], deny: ["genericContribute"] },
|
|
170
|
+
} as Record<string, { allow: readonly PermissionBitName[]; deny: readonly PermissionBitName[] }>,
|
|
171
|
+
/**
|
|
172
|
+
* The project's build service identity (display name `Build\<projectId>`,
|
|
173
|
+
* descriptor `Microsoft.TeamFoundation.ServiceIdentity;...<projectId>...`
|
|
174
|
+
* — Tarun, 2026-09-27, cross-checked against
|
|
175
|
+
* /Users/tarunrana/Documents/ADL-ISMS-Policies/.scratchpad/ci_build_service_grant.py,
|
|
176
|
+
* which grants exactly these bits on adl-agent-control). CI needs to push
|
|
177
|
+
* tags/branches and complete PRs on the repo, and needs PolicyExempt only
|
|
178
|
+
* on `integration` (so a version-bump commit made by CI itself is not
|
|
179
|
+
* blocked by its own policies) — never on `main`.
|
|
180
|
+
*/
|
|
181
|
+
buildService: {
|
|
182
|
+
repo: { allow: ["genericContribute", "forcePush", "pullRequestContribute"] } as {
|
|
183
|
+
allow: readonly PermissionBitName[];
|
|
184
|
+
},
|
|
185
|
+
integrationRef: { allow: ["policyExempt"] } as { allow: readonly PermissionBitName[] },
|
|
186
|
+
mainRef: { deny: ["policyExempt"] } as { deny: readonly PermissionBitName[] },
|
|
187
|
+
},
|
|
188
|
+
/**
|
|
189
|
+
* checkBuildServiceCanRelease() (file header, "checkBuildServiceCanRelease()"):
|
|
190
|
+
* the exact three repo-scope permissions the release flow needs from
|
|
191
|
+
* whichever build service identity actually runs the pipeline — the real
|
|
192
|
+
* failure this check exists for was a 403 on the third one.
|
|
193
|
+
*/
|
|
194
|
+
buildServiceRelease: {
|
|
195
|
+
required: ["genericContribute", "policyExempt", "pullRequestContribute"] as const,
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
} as const;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* The Azure DevOps Repos "Security" tab's own label for each permission bit
|
|
202
|
+
* (Set Git repository permissions —
|
|
203
|
+
* https://learn.microsoft.com/en-us/azure/devops/repos/git/set-git-repository-permissions),
|
|
204
|
+
* used only to build the fix-path message a human follows in that same UI.
|
|
205
|
+
*/
|
|
206
|
+
export const GIT_REPO_PERMISSION_UI_LABEL: Record<PermissionBitName, string> = {
|
|
207
|
+
genericRead: "Read",
|
|
208
|
+
genericContribute: "Contribute",
|
|
209
|
+
forcePush: "Force push (rewrite history, delete branches and tags)",
|
|
210
|
+
policyExempt: "Bypass policies when pushing",
|
|
211
|
+
pullRequestContribute: "Contribute to pull requests",
|
|
212
|
+
pullRequestBypassPolicy: "Bypass policies when completing pull requests",
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// -------------------------------------------------------------------------
|
|
216
|
+
// Azure DevOps response shapes (only the fields this checker reads).
|
|
217
|
+
// -------------------------------------------------------------------------
|
|
218
|
+
|
|
219
|
+
interface GitRepositoryResponse {
|
|
220
|
+
id: string;
|
|
221
|
+
defaultBranch?: string;
|
|
222
|
+
project?: { id?: string };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
interface GitRefsResponse {
|
|
226
|
+
value?: Array<{ name: string }>;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
interface BuildDefinitionsResponse {
|
|
230
|
+
value?: Array<{ id: number }>;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Build — General Settings — Get response (only the field this checker reads). */
|
|
234
|
+
interface BuildGeneralSettingsResponse {
|
|
235
|
+
enforceJobAuthScope?: boolean;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
interface PolicyConfiguration {
|
|
239
|
+
id?: number;
|
|
240
|
+
isEnabled?: boolean;
|
|
241
|
+
isBlocking?: boolean;
|
|
242
|
+
type?: { id?: string };
|
|
243
|
+
settings?: {
|
|
244
|
+
minimumApproverCount?: number;
|
|
245
|
+
creatorVoteCounts?: boolean;
|
|
246
|
+
resetOnSourcePush?: boolean;
|
|
247
|
+
buildDefinitionId?: number;
|
|
248
|
+
allowSquash?: boolean;
|
|
249
|
+
allowRebase?: boolean;
|
|
250
|
+
allowRebaseMerge?: boolean;
|
|
251
|
+
allowNoFastForward?: boolean;
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
interface PolicyConfigurationsResponse {
|
|
256
|
+
value?: PolicyConfiguration[];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
interface AccessControlListsResponse {
|
|
260
|
+
value?: Array<{
|
|
261
|
+
acesDictionary?: Record<
|
|
262
|
+
string,
|
|
263
|
+
{ allow?: number; deny?: number; extendedInfo?: { effectiveAllow?: number; effectiveDeny?: number } }
|
|
264
|
+
>;
|
|
265
|
+
}>;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export interface RepoDoctorDrift {
|
|
269
|
+
id: string;
|
|
270
|
+
message: string;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export interface RepoDoctorReport {
|
|
274
|
+
repository: string;
|
|
275
|
+
compliant: boolean;
|
|
276
|
+
drifts: RepoDoctorDrift[];
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export interface RepoDoctorOptions {
|
|
280
|
+
/** Repository name; defaults to the current checkout's origin (via resolveRepository()). */
|
|
281
|
+
repository?: string;
|
|
282
|
+
/** Test seam: an AdoClient pointed at a stub, in place of the default singleton. */
|
|
283
|
+
client?: AdoClient;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function enabledPolicyOfType(
|
|
287
|
+
policies: readonly PolicyConfiguration[],
|
|
288
|
+
typeId: string,
|
|
289
|
+
): PolicyConfiguration | undefined {
|
|
290
|
+
return policies.find((policy) => policy.type?.id === typeId && policy.isEnabled === true);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async function fetchBranchPolicies(c: AdoClient, repositoryId: string, branch: string): Promise<PolicyConfiguration[]> {
|
|
294
|
+
const result = await c.get<PolicyConfigurationsResponse>("/git/policy/configurations", {
|
|
295
|
+
repositoryId,
|
|
296
|
+
refName: `refs/heads/${branch}`,
|
|
297
|
+
"api-version": "7.1",
|
|
298
|
+
});
|
|
299
|
+
return result.value ?? [];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async function repositoryHasAPipeline(c: AdoClient, repositoryId: string): Promise<boolean> {
|
|
303
|
+
const result = await c.get<BuildDefinitionsResponse>("/build/definitions", {
|
|
304
|
+
repositoryId,
|
|
305
|
+
repositoryType: "TfsGit",
|
|
306
|
+
"api-version": "7.1",
|
|
307
|
+
});
|
|
308
|
+
return (result.value ?? []).length > 0;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function checkIntegrationPolicies(
|
|
312
|
+
policies: readonly PolicyConfiguration[],
|
|
313
|
+
hasPipeline: boolean,
|
|
314
|
+
drifts: RepoDoctorDrift[],
|
|
315
|
+
): void {
|
|
316
|
+
const minReviewer = enabledPolicyOfType(policies, POLICY_TYPE.minimumReviewers);
|
|
317
|
+
if (minReviewer) {
|
|
318
|
+
drifts.push({
|
|
319
|
+
id: "integration.minimum-reviewers-enabled",
|
|
320
|
+
message: `integration has an enabled minimum-reviewer policy (#${minReviewer.id}); integration must have no human reviewer gate`,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
const requiredReviewer = enabledPolicyOfType(policies, POLICY_TYPE.requiredReviewers);
|
|
324
|
+
if (requiredReviewer) {
|
|
325
|
+
drifts.push({
|
|
326
|
+
id: "integration.required-reviewer-enabled",
|
|
327
|
+
message: `integration has an enabled required-reviewer policy (#${requiredReviewer.id}); integration must have no human reviewer gate`,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const merge = enabledPolicyOfType(policies, POLICY_TYPE.mergeStrategy);
|
|
332
|
+
if (!merge) {
|
|
333
|
+
drifts.push({
|
|
334
|
+
id: "integration.merge-strategy-missing",
|
|
335
|
+
message: "integration is missing an enabled merge-strategy policy restricting merges to squash",
|
|
336
|
+
});
|
|
337
|
+
} else {
|
|
338
|
+
const settings = merge.settings ?? {};
|
|
339
|
+
const expected = REPO_STANDARD.integration.mergeStrategy;
|
|
340
|
+
const squashOnly =
|
|
341
|
+
Boolean(settings.allowSquash) === expected.allowSquash &&
|
|
342
|
+
Boolean(settings.allowRebase) === expected.allowRebase &&
|
|
343
|
+
Boolean(settings.allowRebaseMerge) === expected.allowRebaseMerge &&
|
|
344
|
+
Boolean(settings.allowNoFastForward) === expected.allowNoFastForward;
|
|
345
|
+
if (!squashOnly) {
|
|
346
|
+
drifts.push({
|
|
347
|
+
id: "integration.merge-strategy-not-squash-only",
|
|
348
|
+
message: `integration merge-strategy policy (#${merge.id}) does not restrict merges to squash only`,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (hasPipeline) {
|
|
354
|
+
const build = enabledPolicyOfType(policies, POLICY_TYPE.build);
|
|
355
|
+
if (!build) drifts.push({ id: "integration.build-validation-missing", message: "missing build validation" });
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// A named required reviewer on main is DRIFT (A121: "I should not be
|
|
360
|
+
// required for it" — see REPO_STANDARD.main's comment above).
|
|
361
|
+
function checkMainRequiredReviewer(policies: readonly PolicyConfiguration[], drifts: RepoDoctorDrift[]): void {
|
|
362
|
+
const requiredReviewer = enabledPolicyOfType(policies, POLICY_TYPE.requiredReviewers);
|
|
363
|
+
if (!requiredReviewer) return;
|
|
364
|
+
drifts.push({
|
|
365
|
+
id: "main.required-reviewer-enabled",
|
|
366
|
+
message: `main has an enabled required-reviewer policy (#${requiredReviewer.id}); no human may be named — any one approver satisfies the minimum-reviewer policy (A121)`,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function checkMainMinimumReviewers(policies: readonly PolicyConfiguration[], drifts: RepoDoctorDrift[]): void {
|
|
371
|
+
const minReviewer = enabledPolicyOfType(policies, POLICY_TYPE.minimumReviewers);
|
|
372
|
+
if (!minReviewer) {
|
|
373
|
+
drifts.push({
|
|
374
|
+
id: "main.minimum-reviewers-missing",
|
|
375
|
+
message: "main is missing an enabled minimum-reviewer policy",
|
|
376
|
+
});
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
const settings = minReviewer.settings ?? {};
|
|
380
|
+
const expected = REPO_STANDARD.main.minimumReviewers;
|
|
381
|
+
const problems: string[] = [];
|
|
382
|
+
if (minReviewer.isBlocking !== expected.isBlocking) problems.push(`isBlocking must be ${expected.isBlocking}`);
|
|
383
|
+
if ((settings.minimumApproverCount ?? 0) < expected.minimumApproverCount)
|
|
384
|
+
problems.push(`minimumApproverCount must be at least ${expected.minimumApproverCount}`);
|
|
385
|
+
if (Boolean(settings.creatorVoteCounts) !== expected.creatorVoteCounts)
|
|
386
|
+
problems.push(`creatorVoteCounts must be ${expected.creatorVoteCounts}`);
|
|
387
|
+
if (Boolean(settings.resetOnSourcePush) !== expected.resetOnSourcePush)
|
|
388
|
+
problems.push(`resetOnSourcePush must be ${expected.resetOnSourcePush}`);
|
|
389
|
+
if (problems.length === 0) return;
|
|
390
|
+
drifts.push({
|
|
391
|
+
id: "main.minimum-reviewers-misconfigured",
|
|
392
|
+
message: `main minimum-reviewer policy (#${minReviewer.id}) is misconfigured: ${problems.join("; ")}`,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function checkMainMergeStrategy(policies: readonly PolicyConfiguration[], drifts: RepoDoctorDrift[]): void {
|
|
397
|
+
const merge = enabledPolicyOfType(policies, POLICY_TYPE.mergeStrategy);
|
|
398
|
+
if (!merge) {
|
|
399
|
+
drifts.push({
|
|
400
|
+
id: "main.merge-strategy-missing",
|
|
401
|
+
message: "main is missing an enabled merge-strategy policy restricting merges to no-fast-forward",
|
|
402
|
+
});
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
const settings = merge.settings ?? {};
|
|
406
|
+
const expected = REPO_STANDARD.main.mergeStrategy;
|
|
407
|
+
const noFastForwardOnly =
|
|
408
|
+
Boolean(settings.allowSquash) === expected.allowSquash &&
|
|
409
|
+
Boolean(settings.allowRebase) === expected.allowRebase &&
|
|
410
|
+
Boolean(settings.allowRebaseMerge) === expected.allowRebaseMerge &&
|
|
411
|
+
Boolean(settings.allowNoFastForward) === expected.allowNoFastForward;
|
|
412
|
+
if (noFastForwardOnly) return;
|
|
413
|
+
drifts.push({
|
|
414
|
+
id: "main.merge-strategy-not-no-ff-only",
|
|
415
|
+
message: `main merge-strategy policy (#${merge.id}) does not restrict merges to no-fast-forward only`,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function checkMainCommentsAndBuild(
|
|
420
|
+
policies: readonly PolicyConfiguration[],
|
|
421
|
+
hasPipeline: boolean,
|
|
422
|
+
drifts: RepoDoctorDrift[],
|
|
423
|
+
): void {
|
|
424
|
+
const comments = enabledPolicyOfType(policies, POLICY_TYPE.commentRequirements);
|
|
425
|
+
if (!comments) {
|
|
426
|
+
drifts.push({
|
|
427
|
+
id: "main.comment-requirements-missing",
|
|
428
|
+
message: "main is missing an enabled comment-requirements policy",
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (!hasPipeline) return;
|
|
433
|
+
const build = enabledPolicyOfType(policies, POLICY_TYPE.build);
|
|
434
|
+
if (!build) drifts.push({ id: "main.build-validation-missing", message: "missing build validation" });
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function checkMainPolicies(
|
|
438
|
+
policies: readonly PolicyConfiguration[],
|
|
439
|
+
hasPipeline: boolean,
|
|
440
|
+
drifts: RepoDoctorDrift[],
|
|
441
|
+
): void {
|
|
442
|
+
checkMainRequiredReviewer(policies, drifts);
|
|
443
|
+
checkMainMinimumReviewers(policies, drifts);
|
|
444
|
+
checkMainMergeStrategy(policies, drifts);
|
|
445
|
+
checkMainCommentsAndBuild(policies, hasPipeline, drifts);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* One Access Control Lists Query call for `token`. `descriptors` narrows the
|
|
450
|
+
* ACEs returned (comma-separated, per the REST docs); omitted or empty means
|
|
451
|
+
* "every ACE on this token", which is how `resolveBuildServiceDescriptor()`
|
|
452
|
+
* below finds a descriptor it does not know yet.
|
|
453
|
+
*/
|
|
454
|
+
async function fetchAccessControlLists(
|
|
455
|
+
namespaceId: string,
|
|
456
|
+
token: string,
|
|
457
|
+
descriptors?: readonly string[],
|
|
458
|
+
): Promise<AccessControlListsResponse> {
|
|
459
|
+
const params = new URLSearchParams({ token, includeExtendedInfo: "true", "api-version": "7.1" });
|
|
460
|
+
if (descriptors && descriptors.length > 0) params.set("descriptors", descriptors.join(","));
|
|
461
|
+
const url = `${orgBaseUrl()}/_apis/accesscontrollists/${namespaceId}?${params.toString()}`;
|
|
462
|
+
return fetchJson<AccessControlListsResponse>(url, "Access control lists query");
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
async function fetchEffectivePermissions(
|
|
466
|
+
namespaceId: string,
|
|
467
|
+
token: string,
|
|
468
|
+
descriptors: readonly string[],
|
|
469
|
+
): Promise<Map<string, { allow: number; deny: number }>> {
|
|
470
|
+
const byDescriptor = new Map<string, { allow: number; deny: number }>();
|
|
471
|
+
if (descriptors.length === 0) return byDescriptor;
|
|
472
|
+
const result = await fetchAccessControlLists(namespaceId, token, descriptors);
|
|
473
|
+
for (const acl of result.value ?? []) {
|
|
474
|
+
for (const [descriptor, ace] of Object.entries(acl.acesDictionary ?? {})) {
|
|
475
|
+
byDescriptor.set(descriptor, {
|
|
476
|
+
allow: ace.extendedInfo?.effectiveAllow ?? ace.allow ?? 0,
|
|
477
|
+
deny: ace.extendedInfo?.effectiveDeny ?? ace.deny ?? 0,
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return byDescriptor;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/** Resolves every agent's Graph descriptor, reporting an unresolved name as its own drift rather than throwing. */
|
|
485
|
+
async function resolveAgentDescriptors(drifts: RepoDoctorDrift[]): Promise<Map<string, string>> {
|
|
486
|
+
const descriptorByAgent = new Map<string, string>();
|
|
487
|
+
for (const name of Object.keys(REPO_STANDARD.permissions.agents)) {
|
|
488
|
+
const descriptor = await resolveAgentDescriptor(name);
|
|
489
|
+
if (!descriptor) {
|
|
490
|
+
drifts.push({
|
|
491
|
+
id: `permissions.${name}.not-found`,
|
|
492
|
+
message: `could not resolve a Graph descriptor for '${name}' (Graph subject query returned no exact display-name match)`,
|
|
493
|
+
});
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
descriptorByAgent.set(name, descriptor);
|
|
497
|
+
}
|
|
498
|
+
return descriptorByAgent;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function checkAgentBits(
|
|
502
|
+
name: string,
|
|
503
|
+
ace: { allow: number; deny: number },
|
|
504
|
+
expected: { allow: readonly PermissionBitName[]; deny: readonly PermissionBitName[] },
|
|
505
|
+
drifts: RepoDoctorDrift[],
|
|
506
|
+
): void {
|
|
507
|
+
for (const bitName of expected.allow) {
|
|
508
|
+
if ((ace.allow & GIT_REPO_PERMISSION_BIT[bitName]) === 0) {
|
|
509
|
+
drifts.push({
|
|
510
|
+
id: `permissions.${name}.missing-${bitName}`,
|
|
511
|
+
message: `${name} does not effectively have ${bitName} on this repository`,
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
for (const bitName of expected.deny) {
|
|
516
|
+
if ((ace.allow & GIT_REPO_PERMISSION_BIT[bitName]) !== 0) {
|
|
517
|
+
drifts.push({
|
|
518
|
+
id: `permissions.${name}.has-${bitName}`,
|
|
519
|
+
message: `${name} effectively has ${bitName} on this repository, which the standard forbids`,
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
async function checkAgentPermissions(
|
|
526
|
+
projectId: string | undefined,
|
|
527
|
+
repositoryId: string,
|
|
528
|
+
drifts: RepoDoctorDrift[],
|
|
529
|
+
): Promise<void> {
|
|
530
|
+
if (!projectId) {
|
|
531
|
+
drifts.push({
|
|
532
|
+
id: "permissions.no-project-id",
|
|
533
|
+
message: "could not determine the project id needed to build the permissions token",
|
|
534
|
+
});
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
const descriptorByAgent = await resolveAgentDescriptors(drifts);
|
|
538
|
+
|
|
539
|
+
const token = `repoV2/${projectId}/${repositoryId}`;
|
|
540
|
+
const effective = await fetchEffectivePermissions(REPO_STANDARD.permissions.namespaceId, token, [
|
|
541
|
+
...descriptorByAgent.values(),
|
|
542
|
+
]);
|
|
543
|
+
|
|
544
|
+
for (const [name, expected] of Object.entries(REPO_STANDARD.permissions.agents)) {
|
|
545
|
+
const descriptor = descriptorByAgent.get(name);
|
|
546
|
+
if (!descriptor) continue; // already reported above
|
|
547
|
+
checkAgentBits(name, effective.get(descriptor) ?? { allow: 0, deny: 0 }, expected, drifts);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* The Git Repositories token for a branch is `<repoToken>/refs/heads/<hex>`,
|
|
553
|
+
* where `<hex>` is the branch's ref name UTF-16LE-encoded and hex-dumped —
|
|
554
|
+
* https://devblogs.microsoft.com/devops/git-repo-tokens-for-the-security-service/,
|
|
555
|
+
* the same encoding
|
|
556
|
+
* ADL-ISMS-Policies/.scratchpad/ci_build_service_grant.py uses
|
|
557
|
+
* (`"integration".encode("utf-16-le")`). Branch names here are ASCII, so a
|
|
558
|
+
* plain per-character two-byte little-endian dump matches it exactly.
|
|
559
|
+
*/
|
|
560
|
+
export function refNameHexUtf16Le(name: string): string {
|
|
561
|
+
let hex = "";
|
|
562
|
+
for (let i = 0; i < name.length; i += 1) {
|
|
563
|
+
const code = name.charCodeAt(i);
|
|
564
|
+
hex += (code & 0xff).toString(16).padStart(2, "0");
|
|
565
|
+
hex += ((code >> 8) & 0xff).toString(16).padStart(2, "0");
|
|
566
|
+
}
|
|
567
|
+
return hex;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* The project's build service identity is not resolved through Graph (it is
|
|
572
|
+
* a `Microsoft.TeamFoundation.ServiceIdentity` descriptor, not a Graph
|
|
573
|
+
* subject) — it is found the same way
|
|
574
|
+
* ADL-ISMS-Policies/.scratchpad/ci_build_service_grant.py finds it: read the
|
|
575
|
+
* PROJECT-level ACL for this namespace (token `repoV2/<projectId>`, no
|
|
576
|
+
* descriptor filter — every ACE on that token comes back) and take the one
|
|
577
|
+
* service-identity descriptor that carries the project id.
|
|
578
|
+
*/
|
|
579
|
+
async function resolveBuildServiceDescriptor(namespaceId: string, projectId: string): Promise<string | undefined> {
|
|
580
|
+
const result = await fetchAccessControlLists(namespaceId, `repoV2/${projectId}`);
|
|
581
|
+
for (const acl of result.value ?? []) {
|
|
582
|
+
for (const descriptor of Object.keys(acl.acesDictionary ?? {})) {
|
|
583
|
+
if (descriptor.startsWith("Microsoft.TeamFoundation.ServiceIdentity") && descriptor.includes(projectId))
|
|
584
|
+
return descriptor;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return undefined;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* CI needs to push and complete PRs on the repo itself, and needs to bypass
|
|
592
|
+
* policy only on `integration` (so its own version-bump commit is not
|
|
593
|
+
* blocked by the very policies it satisfies) — never on `main`, where a
|
|
594
|
+
* bypass would defeat the human-reviewer gate entirely.
|
|
595
|
+
*/
|
|
596
|
+
async function checkBuildServicePermissions(
|
|
597
|
+
namespaceId: string,
|
|
598
|
+
projectId: string | undefined,
|
|
599
|
+
repositoryId: string,
|
|
600
|
+
drifts: RepoDoctorDrift[],
|
|
601
|
+
): Promise<void> {
|
|
602
|
+
if (!projectId) return; // already reported by checkAgentPermissions()
|
|
603
|
+
|
|
604
|
+
const descriptor = await resolveBuildServiceDescriptor(namespaceId, projectId);
|
|
605
|
+
if (!descriptor) {
|
|
606
|
+
drifts.push({
|
|
607
|
+
id: "permissions.build-service.not-found",
|
|
608
|
+
message: `could not resolve the project's build service identity (Microsoft.TeamFoundation.ServiceIdentity;...${projectId}...) on the Git Repositories namespace`,
|
|
609
|
+
});
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const repoToken = `repoV2/${projectId}/${repositoryId}`;
|
|
614
|
+
const repoEffective = (await fetchEffectivePermissions(namespaceId, repoToken, [descriptor])).get(descriptor) ?? {
|
|
615
|
+
allow: 0,
|
|
616
|
+
deny: 0,
|
|
617
|
+
};
|
|
618
|
+
for (const bitName of REPO_STANDARD.permissions.buildService.repo.allow) {
|
|
619
|
+
if ((repoEffective.allow & GIT_REPO_PERMISSION_BIT[bitName]) === 0) {
|
|
620
|
+
drifts.push({
|
|
621
|
+
id: `permissions.build-service.missing-${bitName}`,
|
|
622
|
+
message: `the project build service does not effectively have ${bitName} on this repository`,
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const integrationToken = `${repoToken}/refs/heads/${refNameHexUtf16Le("integration")}`;
|
|
628
|
+
const integrationEffective = (await fetchEffectivePermissions(namespaceId, integrationToken, [descriptor])).get(
|
|
629
|
+
descriptor,
|
|
630
|
+
) ?? { allow: 0, deny: 0 };
|
|
631
|
+
for (const bitName of REPO_STANDARD.permissions.buildService.integrationRef.allow) {
|
|
632
|
+
if ((integrationEffective.allow & GIT_REPO_PERMISSION_BIT[bitName]) === 0) {
|
|
633
|
+
drifts.push({
|
|
634
|
+
id: `permissions.build-service.missing-${bitName}-integration`,
|
|
635
|
+
message: `the project build service does not effectively have ${bitName} on refs/heads/integration`,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
const mainToken = `${repoToken}/refs/heads/${refNameHexUtf16Le("main")}`;
|
|
641
|
+
const mainEffective = (await fetchEffectivePermissions(namespaceId, mainToken, [descriptor])).get(descriptor) ?? {
|
|
642
|
+
allow: 0,
|
|
643
|
+
deny: 0,
|
|
644
|
+
};
|
|
645
|
+
for (const bitName of REPO_STANDARD.permissions.buildService.mainRef.deny) {
|
|
646
|
+
if ((mainEffective.allow & GIT_REPO_PERMISSION_BIT[bitName]) !== 0) {
|
|
647
|
+
drifts.push({
|
|
648
|
+
id: `permissions.build-service.has-${bitName}-main`,
|
|
649
|
+
message: `the project build service effectively has ${bitName} on refs/heads/main, which the standard forbids`,
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/** "<project> Build Service (<org>)" / "Project Collection Build Service (<org>)" — the exact Security-tab display names of the two identities that could actually be running the pipeline. */
|
|
656
|
+
function buildServiceDisplayNames(org: string, project: string): { projectScoped: string; collectionScoped: string } {
|
|
657
|
+
return {
|
|
658
|
+
projectScoped: `${project} Build Service (${org})`,
|
|
659
|
+
collectionScoped: `Project Collection Build Service (${org})`,
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/** Stable, readable drift-id fragment from a display name, e.g. "Enact Build Service (amsterdamdatalabs)" -> "enact-build-service-amsterdamdatalabs". */
|
|
664
|
+
function identitySlug(displayName: string): string {
|
|
665
|
+
return displayName
|
|
666
|
+
.toLowerCase()
|
|
667
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
668
|
+
.replace(/^-+|-+$/g, "");
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
function releaseFixPath(repository: string, identityDisplayName: string, bitName: PermissionBitName): string {
|
|
672
|
+
return `Project settings → Repositories → \`${repository}\` → Security → \`${identityDisplayName}\` → \`${GIT_REPO_PERMISSION_UI_LABEL[bitName]}\` = Allow`;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Which build service identity actually runs the pipeline, per Build —
|
|
677
|
+
* General Settings — Get's `enforceJobAuthScope` (file header) — "Limit job
|
|
678
|
+
* authorization scope to current project" in the UI: true means the
|
|
679
|
+
* PROJECT-scoped build service runs the job, false means the
|
|
680
|
+
* ORG/COLLECTION-scoped one does. `undefined` means the read itself failed
|
|
681
|
+
* (the calling agent may lack rights to read project settings) — "could not
|
|
682
|
+
* determine", not "assume project-scoped": the caller checks BOTH identities
|
|
683
|
+
* in that case rather than guessing one and staying silent about the other.
|
|
684
|
+
*/
|
|
685
|
+
async function fetchEnforceJobAuthScope(c: AdoClient): Promise<boolean | undefined> {
|
|
686
|
+
try {
|
|
687
|
+
const result = await c.get<BuildGeneralSettingsResponse>("/build/generalsettings", { "api-version": "7.1" });
|
|
688
|
+
return result.enforceJobAuthScope;
|
|
689
|
+
} catch {
|
|
690
|
+
return undefined;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* One identity's answer to "can it release": resolve its descriptor by exact
|
|
696
|
+
* display name (Identities — Read Identities, file header), then check the
|
|
697
|
+
* three REPO_STANDARD.permissions.buildServiceRelease.required bits on the
|
|
698
|
+
* repository token. Every failure mode is its own loud, distinct drift — an
|
|
699
|
+
* unresolvable identity, an ACL the calling agent cannot read, and each
|
|
700
|
+
* missing permission named with its fix path — never a silent pass.
|
|
701
|
+
*/
|
|
702
|
+
async function checkOneBuildServiceCanRelease(
|
|
703
|
+
namespaceId: string,
|
|
704
|
+
repoToken: string,
|
|
705
|
+
repository: string,
|
|
706
|
+
displayName: string,
|
|
707
|
+
drifts: RepoDoctorDrift[],
|
|
708
|
+
): Promise<void> {
|
|
709
|
+
const slug = identitySlug(displayName);
|
|
710
|
+
|
|
711
|
+
let descriptor: string | undefined;
|
|
712
|
+
try {
|
|
713
|
+
descriptor = await resolveIdentityByDisplayName(displayName);
|
|
714
|
+
} catch (error) {
|
|
715
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
716
|
+
drifts.push({
|
|
717
|
+
id: `permissions.release.${slug}.identity-lookup-failed`,
|
|
718
|
+
message: `could not look up the Azure DevOps identity '${displayName}' (Identities - Read Identities call failed) — cannot confirm it can release: ${detail}`,
|
|
719
|
+
});
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
if (!descriptor) {
|
|
723
|
+
drifts.push({
|
|
724
|
+
id: `permissions.release.${slug}.not-found`,
|
|
725
|
+
message: `could not resolve an Azure DevOps identity named '${displayName}' (Identities - Read Identities returned no exact display-name match) — cannot confirm it can release`,
|
|
726
|
+
});
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
let effective: { allow: number; deny: number };
|
|
731
|
+
try {
|
|
732
|
+
effective = (await fetchEffectivePermissions(namespaceId, repoToken, [descriptor])).get(descriptor) ?? {
|
|
733
|
+
allow: 0,
|
|
734
|
+
deny: 0,
|
|
735
|
+
};
|
|
736
|
+
} catch (error) {
|
|
737
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
738
|
+
drifts.push({
|
|
739
|
+
id: `permissions.release.${slug}.acl-read-forbidden`,
|
|
740
|
+
message: `could not read the Git Repositories security ACL for '${displayName}' on '${repository}' — the calling agent identity may lack rights to read repository security, so this cannot be confirmed either way: ${detail}`,
|
|
741
|
+
});
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
for (const bitName of REPO_STANDARD.permissions.buildServiceRelease.required) {
|
|
746
|
+
if ((effective.allow & GIT_REPO_PERMISSION_BIT[bitName]) !== 0) continue;
|
|
747
|
+
drifts.push({
|
|
748
|
+
id: `permissions.release.${slug}.missing-${bitName}`,
|
|
749
|
+
message: `'${displayName}' does not effectively have ${GIT_REPO_PERMISSION_UI_LABEL[bitName]} on '${repository}' — the release pipeline will 403 the way agent-identities build 4897 did. Fix: ${releaseFixPath(repository, displayName, bitName)}`,
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* checkBuildServiceCanRelease() — see the file header for the real failure
|
|
756
|
+
* (agent-identities build 4897, TF401027 on PullRequestContribute) this
|
|
757
|
+
* exists to catch loudly instead of at pipeline-run time. Picks ONE identity
|
|
758
|
+
* to check when the project's own pipeline settings say which one runs the
|
|
759
|
+
* job; when that read itself fails, checks BOTH the project-scoped and the
|
|
760
|
+
* collection-scoped identity and reports each on its own.
|
|
761
|
+
*/
|
|
762
|
+
async function checkBuildServiceCanRelease(
|
|
763
|
+
c: AdoClient,
|
|
764
|
+
namespaceId: string,
|
|
765
|
+
projectId: string | undefined,
|
|
766
|
+
repositoryId: string,
|
|
767
|
+
repository: string,
|
|
768
|
+
drifts: RepoDoctorDrift[],
|
|
769
|
+
): Promise<void> {
|
|
770
|
+
if (!projectId) return; // already reported by checkAgentPermissions()
|
|
771
|
+
|
|
772
|
+
const { projectScoped, collectionScoped } = buildServiceDisplayNames(resolveOrg(), resolveProject());
|
|
773
|
+
const enforceJobAuthScope = await fetchEnforceJobAuthScope(c);
|
|
774
|
+
const displayNames =
|
|
775
|
+
enforceJobAuthScope === true
|
|
776
|
+
? [projectScoped]
|
|
777
|
+
: enforceJobAuthScope === false
|
|
778
|
+
? [collectionScoped]
|
|
779
|
+
: [projectScoped, collectionScoped];
|
|
780
|
+
|
|
781
|
+
const repoToken = `repoV2/${projectId}/${repositoryId}`;
|
|
782
|
+
for (const displayName of displayNames) {
|
|
783
|
+
await checkOneBuildServiceCanRelease(namespaceId, repoToken, repository, displayName, drifts);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Read-only check of `repository` (default: the current checkout's origin)
|
|
789
|
+
* against the two-branch standard (REPO_STANDARD above). Never mutates
|
|
790
|
+
* anything in Azure DevOps. Throws only on identity/auth/transport failure —
|
|
791
|
+
* a compliance drift is reported in the returned list, not thrown.
|
|
792
|
+
*/
|
|
793
|
+
export async function repoDoctorCheck(options: RepoDoctorOptions = {}): Promise<RepoDoctorReport> {
|
|
794
|
+
resolveAgentIdentity();
|
|
795
|
+
const repository = resolveRepository(options.repository);
|
|
796
|
+
const c = options.client ?? new AdoClient();
|
|
797
|
+
const drifts: RepoDoctorDrift[] = [];
|
|
798
|
+
|
|
799
|
+
const repoInfo = await c.get<GitRepositoryResponse>(`/git/repositories/${repository}`, { "api-version": "7.1" });
|
|
800
|
+
const repositoryId = repoInfo.id;
|
|
801
|
+
const projectId = repoInfo.project?.id;
|
|
802
|
+
|
|
803
|
+
const refs = await c.get<GitRefsResponse>(`/git/repositories/${repositoryId}/refs`, {
|
|
804
|
+
filter: "heads/",
|
|
805
|
+
"api-version": "7.1",
|
|
806
|
+
});
|
|
807
|
+
const branchNames = new Set((refs.value ?? []).map((ref) => ref.name.replace(/^refs\/heads\//, "")));
|
|
808
|
+
|
|
809
|
+
for (const required of REPO_STANDARD.branches.required) {
|
|
810
|
+
if (!branchNames.has(required))
|
|
811
|
+
drifts.push({ id: `branches.missing-${required}`, message: `branch '${required}' does not exist` });
|
|
812
|
+
}
|
|
813
|
+
for (const forbidden of REPO_STANDARD.branches.forbidden) {
|
|
814
|
+
if (branchNames.has(forbidden))
|
|
815
|
+
drifts.push({
|
|
816
|
+
id: `branches.forbidden-${forbidden}`,
|
|
817
|
+
message: `branch '${forbidden}' exists and must be removed`,
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
const defaultBranch = (repoInfo.defaultBranch ?? "").replace(/^refs\/heads\//, "");
|
|
821
|
+
if (defaultBranch !== REPO_STANDARD.branches.defaultBranch) {
|
|
822
|
+
drifts.push({
|
|
823
|
+
id: "branches.default-branch",
|
|
824
|
+
message: `default branch is '${defaultBranch || "(unset)"}', expected '${REPO_STANDARD.branches.defaultBranch}'`,
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
const hasPipeline = await repositoryHasAPipeline(c, repositoryId);
|
|
829
|
+
const integrationPolicies = await fetchBranchPolicies(c, repositoryId, "integration");
|
|
830
|
+
const mainPolicies = await fetchBranchPolicies(c, repositoryId, "main");
|
|
831
|
+
checkIntegrationPolicies(integrationPolicies, hasPipeline, drifts);
|
|
832
|
+
checkMainPolicies(mainPolicies, hasPipeline, drifts);
|
|
833
|
+
|
|
834
|
+
await checkAgentPermissions(projectId, repositoryId, drifts);
|
|
835
|
+
await checkBuildServicePermissions(REPO_STANDARD.permissions.namespaceId, projectId, repositoryId, drifts);
|
|
836
|
+
await checkBuildServiceCanRelease(c, REPO_STANDARD.permissions.namespaceId, projectId, repositoryId, repository, drifts);
|
|
837
|
+
|
|
838
|
+
return { repository, compliant: drifts.length === 0, drifts };
|
|
839
|
+
}
|