@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.12 → 0.1.26
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 +2 -2
- package/bin/git +16 -17
- package/bin/git-ado +25 -24
- package/bin/git-defaults +173 -0
- package/bin/health-check +8 -1
- package/bin/kimi-hooks +1 -1
- package/bin/lib/adl-package.sh +257 -0
- package/bin/lib/fleet-host.sh +8 -5
- package/bin/reconcile +482 -232
- package/bin/reconcile-host +30 -20
- package/bin/setup +20 -17
- package/bin/shell-path-policy +15 -5
- package/bin/sync-and-reconcile +62 -64
- package/bin/validate-manifest +33 -9
- package/package.json +2 -10
- package/packages/agent-hooks/README.md +14 -9
- package/packages/agent-hooks/assets/hooks.json +0 -20
- package/packages/agent-hooks/src/cli/args.ts +1 -1
- package/packages/agent-hooks/src/cli/doctor.ts +6 -58
- package/packages/agent-hooks/src/deploy/deploy.ts +12 -41
- package/packages/agent-hooks/src/deploy/doctor.ts +8 -11
- package/packages/agent-hooks/src/deploy/index.ts +14 -14
- package/packages/agent-hooks/src/deploy/json-merge.ts +7 -8
- package/packages/agent-hooks/src/deploy/legacy-lock.ts +2 -2
- package/packages/agent-hooks/src/deploy/list.ts +1 -1
- package/packages/agent-hooks/src/deploy/lock.ts +31 -12
- package/packages/agent-hooks/src/deploy/profile.ts +3 -4
- package/packages/agent-hooks/src/deploy/source.ts +1 -1
- package/packages/agent-hooks/src/gating/config.ts +10 -24
- package/packages/agent-hooks/src/gating/root.ts +3 -3
- package/packages/agent-hooks/src/hooks/briefing/handler.ts +2 -2
- package/packages/agent-hooks/src/hooks/briefing/index.ts +27 -287
- package/packages/agent-hooks/src/hooks/contract.ts +17 -17
- package/packages/agent-hooks/src/hooks/crg/background.ts +27 -0
- package/packages/agent-hooks/src/hooks/crg/index.ts +7 -6
- package/packages/agent-hooks/src/hooks/log.ts +8 -10
- package/packages/agent-hooks/src/hooks/user-prompt-submit/match.ts +1 -1
- package/packages/agent-hooks/src/hooks/user-prompt-submit/tokenizer.ts +1 -1
- package/packages/agent-hooks/src/hooks/user-prompt-submit/vector.ts +6 -5
- package/packages/agent-hooks/src/hosts/registry.ts +1 -1
- package/packages/agent-hooks/src/log/adl-dir.ts +44 -0
- package/packages/agent-hooks/src/log/writer.ts +16 -2
- package/packages/agent-hooks/src/main.ts +7 -41
- package/packages/agent-hooks/src/pre-tool-use/handler.ts +71 -82
- package/packages/agent-hooks/src/rules/engine.ts +13 -17
- package/packages/agent-hooks/src/rules/impl/adl-build-run-denied.ts +3 -3
- package/packages/agent-hooks/src/rules/impl/adl-git-credential-bypass.ts +12 -14
- package/packages/agent-hooks/src/rules/impl/adl-git-identity.ts +28 -28
- package/packages/agent-hooks/src/rules/impl/adl-git-push-policy.ts +8 -9
- package/packages/agent-hooks/src/rules/impl/adl-human-azdo-bypass.ts +56 -59
- package/packages/agent-hooks/src/rules/impl/adl-identity.ts +16 -23
- package/packages/agent-hooks/src/rules/impl/adl-mcp-cli.ts +19 -16
- package/packages/agent-hooks/src/rules/impl/adl-pr-complete-pending.ts +2 -2
- package/packages/agent-hooks/src/rules/impl/adl-pr-review-role.ts +9 -12
- package/packages/agent-hooks/src/rules/impl/adl-pr-role.ts +5 -7
- package/packages/agent-hooks/src/rules/impl/adl-run-required.ts +411 -0
- package/packages/agent-hooks/src/rules/impl/adl-token-minting-role.ts +4 -5
- package/packages/agent-hooks/src/rules/impl/adl-workitem-role.ts +6 -7
- package/packages/agent-hooks/src/rules/impl/agent-tamper-protection.ts +77 -70
- package/packages/agent-hooks/src/rules/impl/deny-allowlist.ts +159 -0
- package/packages/agent-hooks/src/rules/impl/git-helpers.ts +21 -23
- package/packages/agent-hooks/src/rules/impl/git-worktree.ts +14 -28
- package/packages/agent-hooks/src/rules/impl/mcp-tool.ts +3 -3
- package/packages/agent-hooks/src/rules/impl/messages.ts +1 -1
- package/packages/agent-hooks/src/rules/impl/pr-completion.ts +1 -1
- package/packages/agent-hooks/src/rules/impl/tool-azure-devops.ts +35 -46
- package/packages/agent-hooks/src/rules/impl/tool-find.ts +34 -7
- package/packages/agent-hooks/src/rules/impl/tool-grep.ts +34 -12
- package/packages/agent-hooks/src/rules/impl/tool-native-search.ts +52 -9
- package/packages/agent-hooks/src/rules/ports.ts +5 -7
- package/packages/agent-hooks/src/rules/registry.ts +4 -6
- package/packages/agent-hooks/src/rules/shell/git-identity.ts +86 -101
- package/packages/agent-hooks/src/rules/shell/git-internals.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/invocation.ts +24 -118
- package/packages/agent-hooks/src/rules/shell/piped-script.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/prefixes.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/protected-carrier-writes.ts +11 -10
- package/packages/agent-hooks/src/rules/shell/protected-carriers.ts +26 -26
- package/packages/agent-hooks/src/rules/shell/substitution.ts +1 -1
- package/packages/agent-hooks/src/rules/shell/xargs.ts +2 -2
- package/packages/agent-hooks/src/rules/spec.ts +2 -2
- package/packages/agent-settings/README.md +287 -0
- package/packages/agent-settings/assets/GLOBAL-AGENTS.md +14 -16
- package/packages/agent-settings/assets/agents/architect.toml +2 -0
- package/packages/agent-settings/assets/agents/code-reviewer.toml +2 -0
- package/packages/agent-settings/assets/agents/executor.toml +2 -0
- package/packages/agent-settings/assets/agents/explore.toml +2 -0
- package/packages/agent-settings/assets/agents/planner.toml +2 -0
- package/packages/agent-settings/assets/mcp.json +0 -4
- package/packages/agent-settings/deploy-profile.json +139 -0
- package/packages/agent-settings/deploy-profile.schema.json +147 -0
- package/packages/agent-settings/managed/README.md +29 -30
- package/packages/agent-settings/managed/codex-requirements.toml +9 -9
- package/packages/agent-settings/package.json +20 -0
- package/packages/agent-settings/src/deploy/agent-render.ts +2 -2
- package/packages/agent-settings/src/deploy/agent-toml.ts +1 -1
- package/packages/agent-settings/src/deploy/agents-deploy.ts +17 -3
- package/packages/agent-settings/src/deploy/doctor.ts +3 -83
- package/packages/agent-settings/src/deploy/index.ts +6 -33
- package/packages/agent-settings/src/deploy/legacy-lock.ts +6 -6
- package/packages/agent-settings/src/deploy/list.ts +5 -19
- package/packages/agent-settings/src/deploy/lock.ts +8 -18
- package/packages/agent-settings/src/deploy/mcp-deploy.ts +10 -5
- package/packages/agent-settings/src/deploy/mcp-merge.ts +22 -3
- package/packages/agent-settings/src/deploy/mcp-source.ts +1 -1
- package/packages/agent-settings/src/deploy/profile.ts +11 -35
- package/packages/agent-settings/src/deploy/retire-lean-ctx.ts +184 -0
- package/packages/agent-settings/src/deploy/settings.ts +17 -22
- package/packages/agent-settings/src/global-surface-sweep.ts +0 -2
- package/packages/agent-settings/src/kimi-hooks.ts +339 -192
- package/packages/agent-settings/src/opencode-hooks.ts +1 -1
- package/packages/agent-settings/tsconfig.json +23 -0
- package/packages/agent-skills/assets/agent-search-tool-audit/SKILL.md +120 -0
- package/packages/agent-skills/assets/agent-search-tool-audit/scripts/audit.sh +276 -0
- package/packages/agent-skills/assets/debug-issue/SKILL.md +8 -7
- package/packages/agent-skills/assets/explore-codebase/SKILL.md +13 -13
- package/packages/agent-skills/assets/refactor-safely/SKILL.md +12 -11
- package/packages/agent-skills/assets/review-changes/SKILL.md +7 -7
- package/packages/agent-skills/assets/testing/references/e2e.md +37 -0
- package/packages/agent-skills/assets/testing/references/integration.md +37 -0
- package/packages/agent-skills/assets/testing/references/unit.md +32 -0
- package/packages/agent-skills/dist/deploy.d.ts +2 -0
- package/packages/agent-skills/dist/deploy.d.ts.map +1 -1
- package/packages/agent-skills/dist/deploy.js +27 -1
- package/packages/agent-skills/dist/deploy.js.map +1 -1
- package/packages/agent-skills/dist/doctor.d.ts +0 -2
- package/packages/agent-skills/dist/doctor.d.ts.map +1 -1
- package/packages/agent-skills/dist/doctor.js +1 -1
- package/packages/agent-skills/dist/doctor.js.map +1 -1
- package/packages/agent-skills/dist/fs-utils.d.ts +0 -1
- package/packages/agent-skills/dist/fs-utils.d.ts.map +1 -1
- package/packages/agent-skills/dist/fs-utils.js +1 -1
- package/packages/agent-skills/dist/fs-utils.js.map +1 -1
- package/packages/agent-skills/src/deploy.ts +29 -1
- package/packages/agent-skills/src/doctor.ts +1 -1
- package/packages/agent-skills/src/fs-utils.ts +1 -1
- package/packages/azdo/README.md +10 -9
- package/packages/azdo/package.json +1 -3
- package/packages/azdo/src/azdo-pl.ts +2 -54
- package/packages/azdo/src/azdo-pr-review.ts +4 -4
- package/packages/azdo/src/azdo-repo-doctor.ts +101 -52
- package/packages/azdo/src/azdo-wit.ts +41 -2
- package/packages/azdo/src/lib/agent-identity.ts +12 -14
- package/packages/azdo/src/lib/agent-token.ts +2 -2
- package/packages/azdo/src/lib/client.ts +0 -5
- package/packages/azdo/src/lib/graph-identity.ts +4 -4
- package/packages/azdo/src/workflow-rules-matrix.csv +85 -0
- package/packages/azdo/src/workflow-rules.ts +128 -0
- package/packages/fleet/manifest.json +35 -11
- package/packages/fleet/manifest.schema.json +62 -10
- package/packages/fleet/src/default-agent-file.ts +3 -3
- package/packages/fleet/src/install-adl-package.ts +73 -15
- package/packages/fleet/src/install-embedding-model.ts +13 -13
- package/packages/fleet/src/managed-settings.ts +7 -7
- package/packages/fleet/src/repo-maintain.ts +91 -55
- package/packages/fleet/src/scratch-reap.ts +5 -5
- package/packages/fleet/src/vscode-settings.ts +5 -5
- package/packages/repo-controls/README.md +141 -43
- package/packages/repo-controls/assets/promote.ts +4 -4
- package/packages/repo-controls/assets/reconcile-guard.sh +10 -46
- package/packages/repo-controls/assets/version-bump.sh +31 -84
- package/packages/repo-controls/bunfig.toml +6 -7
- package/packages/repo-controls/package/adl-compliance/AGENTS.md +5 -6
- package/packages/repo-controls/package/adl-compliance/conftest.py +3 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/__init__.py +4 -16
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/adr_lifecycle/test_check.py +9 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/fixtures/docs/notes.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/test_check.py +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/__init__.py +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/check.py +266 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/.drafts/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/.drafts/d.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/.hidden.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/data.csv +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/diagram.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/mock.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs/guide/sub/nested.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/docs.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p1.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p2.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p3.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p4.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-assets/plans/deep/p5.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/architecture/build.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/architecture/overview.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/guide/install.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/docs/guide/start.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-clean/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/adr-001-tenancy.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/adr-002-carrier.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/adr-003-cli.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/archive/adr-000-old.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/decisions/archive/adr-000-older.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-decisions/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-01.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-02.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-03.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-04.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-05.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-06.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-07.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-08.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-09.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-10.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-11.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-12.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-13.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-14.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-15.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/docs/guide/page-16.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-default-cap/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-exempt/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-grew/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/d.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/docs/guide/e.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-no-section/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/docs/short/only.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-over-cap/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/held/d.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/shrunk/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/docs/shrunk/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-stale/grants.yaml +6 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/a.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/b.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/docs/guide/c.md +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/fixtures/docs-size-unusable/grants.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/directory_size/test_check.py +345 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/check.py +18 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/english_only/test_check.py +35 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/__init__.py +7 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/check.py +91 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/CLAUDE.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/-leading-hyphen.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/AGENTS.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/double--hyphen.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/getting started.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/nested/page-here.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/trailing-hyphen-.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/ui-contract.md +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/architecture/user_profile.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/assets/UI-CONTRACT.png +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/assets/diagram.png +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/index.md +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/notes.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/reference.html +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/research/2026-10-experiment.md +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs/research/UI-CONTRACT.md +6 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/fixtures/docs.md +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/test_check.py +194 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/check.py +14 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/docs-knowledge-indexes.yaml +5 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-shipped-register-legacy/docs/compliance/index.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/fixtures/knowledge-indexes-shipped-register-type/docs/compliance/index.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/indexes/test_check.py +58 -6
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/test_check.py +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/check.py +64 -17
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/docs-okf-profiles.yaml +60 -9
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-clean/docs/notes.md +17 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-ledger-no-lines/docs/notes.md +13 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs/architecture/demo.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-clean/docs-okf-profiles.yaml +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/no-type.md +9 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-experiment.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-research.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs-okf-profiles.yaml +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-violation/docs/architecture/bad-status.md +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-violation/docs-okf-profiles.yaml +0 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/experiment-ok.md +15 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-key.md +15 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-keys.md +16 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-created.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-description.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-last-update.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-sources.md +10 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-status.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-title.md +11 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/optional-keys.md +16 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/research-ok.md +14 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research-neighbours/docs/architecture/created-date.md +21 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research-neighbours/docs/architecture/research-shaped.md +19 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research-neighbours/docs/operations/runbook.md +26 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/test_check.py +228 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/register.py +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/semantics/test_check.py +11 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/__init__.py +5 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/check.py +160 -44
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-clean/grants.yaml +0 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/frontend/packages/desktop/src/a.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/frontend/packages/desktop/src/b.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-empty-register/grants.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-excluded/grants.yaml +0 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-missing-tree/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-missing-tree/grants.yaml +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/frontend/packages/desktop/src/a.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/frontend/packages/desktop/src/b.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/frontend/packages/desktop/src/c.ts +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-no-ceilings/grants.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-stale-entry/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-stale-entry/grants.yaml +5 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unbaselined/grants.yaml +0 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/fixtures/directory-ratchet-unusable-register/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-unusable-register/grants.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/register.py +127 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/directory_ratchet/test_check.py +265 -29
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/check.py +75 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/markdown_trees/test_check.py +194 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/check.py +56 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/test_check.py +256 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/check.py +40 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/placement/test_check.py +108 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/references/check.py +2 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/check.py +23 -6
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_closed_set/test_check.py +76 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/check.py +58 -17
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/root_markdown_allowlist/test_check.py +161 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/check.py +35 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/scripts_size_depth/test_check.py +108 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/check.py +281 -61
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/absolute-path.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/backslash-path.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/baseline-is-a-list.yaml +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/boolean-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/dot-segment.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/duplicate-path.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/empty-file.yaml +0 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/empty-segment.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/float-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/negative-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/no-over-limit-baseline.yaml +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/no-schema-version.yaml +1 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/non-string-path.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/not-yaml.yaml +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/null-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/parent-segment.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/string-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/top-level-is-a-list.yaml +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/trailing-slash.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/unknown-key.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/wrong-schema-version.yaml +2 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/malformed/zero-size.yaml +3 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/fixtures/valid.yaml +4 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/lfs/integrity/test_check.py +758 -45
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/check.py +4 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/ignored_paths/test_check.py +2 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/cargo_lock.py +490 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/check.py +368 -55
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_check.py +4 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_declared_paths.py +523 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/repository/lockfile_integrity/test_stale_lock.py +1179 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/cli.py +122 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/check.py +33 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/constants.py +0 -11
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/core/context.py +16 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/config.py +1 -2
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/docs_shape.py +12 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.alt.yaml +133 -147
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml +133 -147
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/registry.py +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/root_shape.py +52 -10
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/runner.py +23 -4
- package/packages/repo-controls/package.json +2 -9
- package/packages/repo-controls/scripts/hooks/post-merge +13 -0
- package/packages/repo-controls/scripts/hooks/pre-push +3 -3
- package/packages/repo-controls/src/azdo-push.ts +64 -36
- package/packages/repo-controls/src/azure-devops-governance.ts +7 -9
- package/packages/repo-controls/src/azure-devops-remote.ts +1 -1
- package/packages/repo-controls/src/cli.ts +29 -8
- package/packages/repo-controls/src/compliance-config.ts +410 -2
- package/packages/repo-controls/src/config.ts +133 -60
- package/packages/repo-controls/src/constants.ts +13 -27
- package/packages/repo-controls/src/coverage-ratchet.ts +4 -4
- package/packages/repo-controls/src/doctor.ts +46 -19
- package/packages/repo-controls/src/gitignore-block.ts +5 -29
- package/packages/repo-controls/src/hook-log.ts +1 -2
- package/packages/repo-controls/src/hook.ts +201 -45
- package/packages/repo-controls/src/install.ts +14 -8
- package/packages/repo-controls/src/integrity.ts +3 -3
- package/packages/repo-controls/src/lfs.ts +111 -0
- package/packages/repo-controls/src/promote.ts +8 -8
- package/packages/repo-controls/src/runtime.ts +9 -1
- package/packages/repo-controls/src/workflows-drift.ts +4 -5
- package/packages/repo-controls/src/worktree-guard.ts +3 -3
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
* matching a guessed tool name now.
|
|
42
42
|
*
|
|
43
43
|
* Requires an identity to already be present (`ADL_AGENT_ID_AGENT`
|
|
44
|
-
* non-blank) — with no identity at all, `adl.
|
|
44
|
+
* non-blank) — with no identity at all, `adl.run-required-for-writes`
|
|
45
45
|
* denies the call first (a different problem: no session, not the wrong
|
|
46
46
|
* role), so this rule returns null when the env var is absent or blank.
|
|
47
47
|
*/
|
|
@@ -70,16 +70,14 @@ export const adlPrCreateUpdateRole: RuleSpec = {
|
|
|
70
70
|
'Deny pr_create_or_update for any identity other than a builder (agent-tarun/agent-vivek) or agent-reviewer (docs/operations/agent-permissions.md row 5).',
|
|
71
71
|
params: noParams,
|
|
72
72
|
match(inv: Invocation, ctx: RuleContext<Record<string, never>>): Finding | null {
|
|
73
|
-
//
|
|
74
|
-
// pr-create-or-update` dispatches to the same tool the MCP server calls.
|
|
73
|
+
// `adl mcp cli pr-create-or-update` dispatches to the same tool the MCP server calls.
|
|
75
74
|
const call = toolCallFor(inv)
|
|
76
75
|
if (call === null) return null
|
|
77
76
|
if (mcpToolName(call.tool) !== 'pr_create_or_update') return null
|
|
78
77
|
|
|
79
|
-
//
|
|
80
|
-
// grade the EFFECTIVE identity for THIS specific piece — a valid inline
|
|
78
|
+
// Grade the EFFECTIVE identity for THIS specific piece — a valid inline
|
|
81
79
|
// `ADL_AGENT_ID_AGENT=` override on the same `adl mcp cli` invocation
|
|
82
|
-
// still wins, exactly like
|
|
80
|
+
// still wins, exactly like it does for `git push` (see
|
|
83
81
|
// `effectiveIdentityForMcpCli`'s own doc). A real MCP tool-call payload
|
|
84
82
|
// carries no command text at all (no inline override possible), so this
|
|
85
83
|
// still resolves to the plain session identity for that shape — env,
|
|
@@ -88,7 +86,7 @@ export const adlPrCreateUpdateRole: RuleSpec = {
|
|
|
88
86
|
const resolution = resolveFromEnvOrFile(ctx.env)
|
|
89
87
|
const fallback = resolution.ok ? resolution.agent : null
|
|
90
88
|
const agent = effectiveIdentityForMcpCli(inv, ctx.command ?? '', fallback)
|
|
91
|
-
if (agent === null) return null // no identity at all: adl.
|
|
89
|
+
if (agent === null) return null // no identity at all: adl.run-required-for-writes's job
|
|
92
90
|
|
|
93
91
|
// Not a builder and not agent-reviewer: denied regardless of shape — this
|
|
94
92
|
// is the more fundamental restriction, so it reports even for a call that
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `adl.run-required-for-writes` — the managed baseline hook (docs/architecture/cli-design.md
|
|
3
|
+
* §2/§3).
|
|
4
|
+
*
|
|
5
|
+
* Widened 2026-09-28 by the one-agent-identity standard (Tarun): the rule id
|
|
6
|
+
* is kept stable, but this rule's job is no longer "writes only". Every Azure DevOps access
|
|
7
|
+
* — reads included — needs a resolvable agent identity now: the session env
|
|
8
|
+
* (set by the surface's managed default), the machine default-agent file
|
|
9
|
+
* (`adl-identity.ts`'s `resolveFromEnvOrFile`, steps 2-3 of the standard),
|
|
10
|
+
* or a valid inline `ADL_AGENT_ID_AGENT=<agent>` override on the command
|
|
11
|
+
* itself (step 1, detected via `../shell/git-identity.ts`'s
|
|
12
|
+
* `commandHasValidInlineIdentity` — see `checkResolvableIdentity` below). With
|
|
13
|
+
* NONE of those present, this rule denies every identity-bearing command
|
|
14
|
+
* class (git network reads/writes, the azdo MCP tools including their reads,
|
|
15
|
+
* `adl mcp cli`/`adl repo doctor`/`adl repo controls azdo-push`/`adl id
|
|
16
|
+
* token`/`adl-agent-id exec`, and curl/wget/httpie/xh to
|
|
17
|
+
* dev.azure.com/*.visualstudio.com under any HTTP method) with the
|
|
18
|
+
* standard's own message; every other command is left alone. Once an
|
|
19
|
+
* identity resolves, this rule gets out of the way entirely — `git-ado`/
|
|
20
|
+
* `adl`'s own rules, and the role rules, police what an authenticated
|
|
21
|
+
* run may do.
|
|
22
|
+
*
|
|
23
|
+
* Four write surfaces, each inspected in the shape the shell/tool-call
|
|
24
|
+
* classifier already hands every other rule:
|
|
25
|
+
*
|
|
26
|
+
* - `git push` (`../shell/invocation.ts`'s `'git'` kind). The hook cannot run
|
|
27
|
+
* `git remote get-url` (it decides before the child runs, statically, off
|
|
28
|
+
* argv alone) the way the deployed `bin/git` front controller can — so an
|
|
29
|
+
* explicit `https://.../dev.azure.com/...` URL anywhere in the push's
|
|
30
|
+
* arguments is authoritative, and otherwise the destination is UNRESOLVED
|
|
31
|
+
* (a bare `git push`, or `git push origin main` naming a remote this rule
|
|
32
|
+
* cannot look up) and fails closed: unresolved is treated exactly like
|
|
33
|
+
* "proven Azure DevOps", because the rule cannot prove otherwise. Only an
|
|
34
|
+
* explicit NON-Azure-DevOps URL is provably safe and lets a write through
|
|
35
|
+
* without an identity. `git-verify.ts`'s `git.no-verify` corpus already
|
|
36
|
+
* anticipates this: its own `allow` list deliberately never contains a bare
|
|
37
|
+
* `git push` or `git push -n`, see the comment there and
|
|
38
|
+
* `rules-corpus-executed.test.ts`'s "corrected corpus entries" check.
|
|
39
|
+
* - `az devops|repos|pipelines|boards|artifacts ...` (the `'azure-devops'`
|
|
40
|
+
* kind). `tool.azure-devops` (`./tool-azure-devops.ts`) already denies
|
|
41
|
+
* EVERY direct invocation of this family outright, read or write,
|
|
42
|
+
* identity or not, steering everything at the MCP server — and it is
|
|
43
|
+
* registered ahead of this rule, so in the real engine it always reports
|
|
44
|
+
* first. This rule's own az-CLI classification (read verbs `list`/`show`/
|
|
45
|
+
* `get`/`query` vs. everything else, fail-closed to "write" when neither
|
|
46
|
+
* matches) is therefore defense in depth for a repository that disables
|
|
47
|
+
* `tool.azure-devops` (`[rules."tool.azure-devops"] enabled = false`), not
|
|
48
|
+
* something reachable through `decide()` today — see
|
|
49
|
+
* `tests/unit/rules-adl-run-required.test.ts`, which exercises it via
|
|
50
|
+
* a direct `match()` call rather than the shared corpus (which runs
|
|
51
|
+
* through the real engine and would otherwise always see `tool.azure-devops`
|
|
52
|
+
* win first).
|
|
53
|
+
* - `curl`/`wget`/httpie (`http`/`https`)/`xh` (the generic `'command'` kind)
|
|
54
|
+
* with a non-GET method against a `dev.azure.com` URL. curl's method is
|
|
55
|
+
* explicit (`-X`/`--request`) or implied by a data flag (`-d`/`--data*`,
|
|
56
|
+
* `-F`/`--form`, `--json`); wget's by `--method=`/`--post-data`/
|
|
57
|
+
* `--post-file`; httpie/xh's by an explicit leading method argument or a
|
|
58
|
+
* request-item/`--form`/`--raw` implying a body (httpie's own semantics:
|
|
59
|
+
* a request with data defaults to POST, one without defaults to GET).
|
|
60
|
+
* - An Azure DevOps MCP write tool (the `'tool-call'` kind), named
|
|
61
|
+
* `mcp__<prefix>__<tool>` where `<tool>` is one of the four mutating
|
|
62
|
+
* tools `packages/azdo/src/mcp-server.ts` actually registers:
|
|
63
|
+
* `pr_create_or_update`, `pr_review`, `build_run`, `workitem_create_or_update`. The
|
|
64
|
+
* match is on the TOOL NAME alone, not the server prefix — the package is
|
|
65
|
+
* `azdo`, P4 folds the server under `adl`, and Claude Code's plugin-scoped
|
|
66
|
+
* form (`mcp__plugin_<plugin>_<server>__<tool>`) adds a third spelling —
|
|
67
|
+
* so `mcp__azdo__...`, `mcp__adl__...`, `mcp__azure-devops-mcp__...` and
|
|
68
|
+
* `mcp__plugin_adl_azdo__...` are all matched the same way. Its three read
|
|
69
|
+
* tools (`pr_list_or_get`, `build_list_or_get`, `workitem_list_or_get`)
|
|
70
|
+
* are left alone under every one of those prefixes too.
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
import type { Invocation } from '../shell/invocation.ts'
|
|
74
|
+
import type { Token } from '../shell/token.ts'
|
|
75
|
+
import { dynamicToken, tokenValue } from '../shell/token.ts'
|
|
76
|
+
import { commandHasValidInlineIdentity, isNetworkGitInvocation } from '../shell/git-identity.ts'
|
|
77
|
+
import type { EnvPort } from '../ports.ts'
|
|
78
|
+
import type { Finding, MessageContext, RuleContext, RuleSpec } from '../spec.ts'
|
|
79
|
+
import { noParams } from '../spec.ts'
|
|
80
|
+
import {
|
|
81
|
+
ADL_AGENT_ID_BINARY_NAMES,
|
|
82
|
+
ADL_AGENT_ID_COMMAND_SHAPES,
|
|
83
|
+
ADL_BINARY_NAMES,
|
|
84
|
+
ADL_IDENTITY_COMMAND_SHAPES,
|
|
85
|
+
classifyGitPushDestination,
|
|
86
|
+
containsIdentityBearingToken,
|
|
87
|
+
HTTP_CLIENT_BINARY_NAMES,
|
|
88
|
+
httpClientMethod,
|
|
89
|
+
isAdoUrl,
|
|
90
|
+
isHelpOnlyInvocation,
|
|
91
|
+
matchesIdentityShape,
|
|
92
|
+
skipLeadingDashFlags,
|
|
93
|
+
} from './git-helpers.ts'
|
|
94
|
+
import { NO_AGENT_IDENTITY_MESSAGE, resolveFromEnvOrFile } from './adl-identity.ts'
|
|
95
|
+
import { detailString } from './messages.ts'
|
|
96
|
+
import { mcpToolName } from './mcp-tool.ts'
|
|
97
|
+
|
|
98
|
+
const RULE_ID = 'adl.run-required-for-writes'
|
|
99
|
+
const ENV_VAR = 'ADL_AGENT_ID_AGENT'
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Whether an identity is
|
|
103
|
+
* resolvable for `command`, and if not, the EXACT message to show — the
|
|
104
|
+
* one standard `NO_AGENT_IDENTITY_MESSAGE` when nothing is configured at
|
|
105
|
+
* all, or the SPECIFIC named error when something IS configured but is
|
|
106
|
+
* invalid (an unrecognized `ADL_AGENT_ID_AGENT` value, or a default-agent
|
|
107
|
+
* file naming an agent outside `VALID_AGENTS`) — `resolveFromEnvOrFile`'s
|
|
108
|
+
* own `UnresolvedIdentity.message` already carries exactly the right text
|
|
109
|
+
* for either case (see `adl-identity.ts`'s `resolveFromEnvOrFile`: it is
|
|
110
|
+
* `NO_AGENT_IDENTITY_MESSAGE` verbatim for `reason: 'none'`, and the named
|
|
111
|
+
* `invalidAgentError` text for `reason: 'invalid'`), so this reads that
|
|
112
|
+
* message through rather than reporting the SAME generic "run the fleet
|
|
113
|
+
* reconcile" text regardless of which of the two actually happened — an
|
|
114
|
+
* invalid identity is a materially different, more actionable diagnosis
|
|
115
|
+
* than none configured at all, and reporting the generic text for both
|
|
116
|
+
* hid that distinction from the agent.
|
|
117
|
+
*
|
|
118
|
+
* A valid inline `ADL_AGENT_ID_AGENT=<agent>` override anywhere on the
|
|
119
|
+
* command line (step 1 of the standard — coarse, whole-command; see
|
|
120
|
+
* `commandHasValidInlineIdentity`'s own doc for what that trades off)
|
|
121
|
+
* resolves too, without needing the session env / machine default-agent
|
|
122
|
+
* file (steps 2-3) at all.
|
|
123
|
+
*/
|
|
124
|
+
type IdentityCheck = { readonly resolvable: true } | { readonly resolvable: false; readonly message: string }
|
|
125
|
+
|
|
126
|
+
function checkResolvableIdentity(command: string, env: EnvPort): IdentityCheck {
|
|
127
|
+
if (commandHasValidInlineIdentity(command)) return { resolvable: true }
|
|
128
|
+
const resolution = resolveFromEnvOrFile(env)
|
|
129
|
+
return resolution.ok ? { resolvable: true } : { resolvable: false, message: resolution.message }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const classifyPush = classifyGitPushDestination
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* az CLI verbs that only read. Fail-closed by design: anything NOT
|
|
136
|
+
* recognized here (including a verb this list simply does not know about
|
|
137
|
+
* yet) is treated as a write, never the reverse. Recognized against the
|
|
138
|
+
* FULL args after `az` (the subcommand group included, e.g. `repos pr
|
|
139
|
+
* list`) — a flag's VALUE (`--status active`) could in principle collide
|
|
140
|
+
* with a verb spelling, an accepted heuristic risk given `tool.azure-devops`
|
|
141
|
+
* denies the whole family outright regardless (see header).
|
|
142
|
+
*/
|
|
143
|
+
const AZ_READ_VERBS: ReadonlySet<string> = new Set(['list', 'show', 'get', 'query'])
|
|
144
|
+
|
|
145
|
+
function azCommandIsWrite(args: readonly Token[]): boolean {
|
|
146
|
+
for (const token of args) {
|
|
147
|
+
const value = tokenValue(token).toLowerCase()
|
|
148
|
+
if (value.startsWith('-')) continue
|
|
149
|
+
if (AZ_READ_VERBS.has(value)) return false
|
|
150
|
+
}
|
|
151
|
+
return true
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* The name set and the per-binary method detection live in
|
|
156
|
+
* `git-helpers.ts`'s `HTTP_CLIENT_BINARY_NAMES`/`httpClientMethod` — shared
|
|
157
|
+
* with `tool-azure-devops.ts`'s WRITE-outright deny
|
|
158
|
+
* (docs/operations/agent-permissions.md row 13), so the two cannot classify
|
|
159
|
+
* the same command two different ways.
|
|
160
|
+
*/
|
|
161
|
+
const HTTP_CLIENT_NAMES = HTTP_CLIENT_BINARY_NAMES
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Azure DevOps MCP write tools, derived from `packages/azdo/src/mcp-server.ts`'s
|
|
165
|
+
* `ListToolsRequestSchema` handler (re-checked 2026-10-01) — the
|
|
166
|
+
* complete tool roster there is `pr_list_or_get`/`pr_create_or_update`/
|
|
167
|
+
* `pr_review`, `build_list_or_get`/`build_run`, `workitem_list_or_get`/
|
|
168
|
+
* `workitem_create_or_update`; the three not in this set are the read half.
|
|
169
|
+
* `pr_review` (docs/operations/agent-permissions.md rows 6-8: comment + vote) is
|
|
170
|
+
* in this set because `adl-pr-review-role.ts` gates it by role —
|
|
171
|
+
* a caller with no run identity at all must be denied here FIRST, the
|
|
172
|
+
* same "no session, not merely the wrong role" ordering `adl-pr-role.ts`
|
|
173
|
+
* documents for `pr_create_or_update`.
|
|
174
|
+
*/
|
|
175
|
+
const ADO_MCP_WRITE_TOOLS: ReadonlySet<string> = new Set([
|
|
176
|
+
'pr_create_or_update',
|
|
177
|
+
'pr_review',
|
|
178
|
+
'build_run',
|
|
179
|
+
'workitem_create_or_update',
|
|
180
|
+
])
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* The standard requires an identity for every Azure
|
|
184
|
+
* DevOps MCP tool call, reads included — the read half gets no
|
|
185
|
+
* pass just because it cannot mutate anything. `mcp-server.ts`'s complete
|
|
186
|
+
* roster: `pr_list_or_get`, `build_list_or_get`, `workitem_list_or_get`
|
|
187
|
+
* (reads) alongside the four writes above.
|
|
188
|
+
*/
|
|
189
|
+
/** The leading words of the `identityBearingReason` for an Azure DevOps MCP tool call — `message()` keys the MCP-only CLI advice off it. */
|
|
190
|
+
const MCP_REASON_PREFIX = 'Azure DevOps MCP tool'
|
|
191
|
+
|
|
192
|
+
const ADO_MCP_ALL_TOOLS: ReadonlySet<string> = new Set([...ADO_MCP_WRITE_TOOLS, 'pr_list_or_get', 'build_list_or_get', 'workitem_list_or_get'])
|
|
193
|
+
|
|
194
|
+
/** `adl <...>` shapes that need an identity even with no HTTP client or git verb involved — see `git-helpers.ts`'s `ADL_IDENTITY_COMMAND_SHAPES`. */
|
|
195
|
+
const ADL_BINARY_ALL_NAMES: ReadonlySet<string> = ADL_BINARY_NAMES
|
|
196
|
+
const ADL_AGENT_ID_BINARY_ALL_NAMES: ReadonlySet<string> = ADL_AGENT_ID_BINARY_NAMES
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Interpreter one-liners whose `-c`/`-e`/`--eval` code string names an
|
|
200
|
+
* identity-bearing operation — `../shell/invocation.ts`'s walker classifies
|
|
201
|
+
* these as a plain, unclassified `'command'` Invocation (it only re-parses
|
|
202
|
+
* `-c` as shell for `sh`/`bash`/`zsh`/`dash`/`ksh`/`fish`, never an
|
|
203
|
+
* interpreter's own code), so
|
|
204
|
+
* `python3 -c "import subprocess; subprocess.run(['git','push'])"` would be
|
|
205
|
+
* invisible to this rule without this check. Deliberately coarse
|
|
206
|
+
* (`containsIdentityBearingToken`, textual) — precise parsing of arbitrary
|
|
207
|
+
* Python/JS/Perl/Ruby/AppleScript source is not this rule's job.
|
|
208
|
+
*/
|
|
209
|
+
const INTERPRETER_ONE_LINER_NAMES: ReadonlySet<string> = new Set([
|
|
210
|
+
'python', 'python.exe', 'python2', 'python2.exe', 'python3', 'python3.exe',
|
|
211
|
+
'node', 'node.exe', 'perl', 'perl.exe', 'ruby', 'ruby.exe', 'bun', 'bun.exe',
|
|
212
|
+
'osascript', 'osascript.exe',
|
|
213
|
+
])
|
|
214
|
+
const INTERPRETER_CODE_FLAGS: ReadonlySet<string> = new Set(['-c', '-e', '--eval'])
|
|
215
|
+
|
|
216
|
+
/** Every code string passed via `-c`/`-e`/`--eval` among `args` — the token immediately following the flag. */
|
|
217
|
+
function interpreterCodeStrings(args: readonly Token[]): readonly string[] {
|
|
218
|
+
const codes: string[] = []
|
|
219
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
220
|
+
if (!INTERPRETER_CODE_FLAGS.has(tokenValue(args[index] as Token))) continue
|
|
221
|
+
const next = args[index + 1]
|
|
222
|
+
if (next !== undefined) codes.push(tokenValue(next))
|
|
223
|
+
}
|
|
224
|
+
return codes
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Whether `inv` is a candidate this rule cares about at all, and if so, the
|
|
229
|
+
* "reason" text for its Finding — computed WITHOUT ever resolving an
|
|
230
|
+
* identity (see `match`'s own comment on resolution order for why the ordering matters). The
|
|
231
|
+
* four surfaces are exactly the ones documented in this file's header.
|
|
232
|
+
*/
|
|
233
|
+
/**
|
|
234
|
+
* Exported for `../../pre-tool-use/handler.ts`'s own broader net: a
|
|
235
|
+
* walker-visible identity-bearing shape the narrow `adl.git-identity` rewrite scanner does not recognize (buried
|
|
236
|
+
* inside `if`/`!`/`for..do`/`xargs`/a heredoc or here-string/a piped-into
|
|
237
|
+
* shell) still needs denying when the resolved identity cannot actually
|
|
238
|
+
* reach THIS specific host/tool-class's child process — this rule alone
|
|
239
|
+
* cannot make that call (it has no host/tool-class in its `RuleContext`),
|
|
240
|
+
* but it IS the one place that already classifies every one of those shapes
|
|
241
|
+
* correctly (see this file's header), so the handler reuses this function
|
|
242
|
+
* rather than re-deriving the same walker-based classification a second
|
|
243
|
+
* time.
|
|
244
|
+
*/
|
|
245
|
+
export function identityBearingReason(inv: Invocation): string | null {
|
|
246
|
+
if (inv.kind === 'git') {
|
|
247
|
+
// Wider than a plain
|
|
248
|
+
// `NETWORK_GIT_VERBS.has(inv.subcommand)` gate — see
|
|
249
|
+
// `isNetworkGitInvocation`'s own doc for the additional network-reaching
|
|
250
|
+
// shapes now covered (git remote show/prune/update/set-head -a, git
|
|
251
|
+
// maintenance run --task=prefetch, the remote-https/remote-http/
|
|
252
|
+
// http-fetch transport helpers, git submodule update/sync --recursive,
|
|
253
|
+
// git archive --remote).
|
|
254
|
+
if (!isNetworkGitInvocation(inv.subcommand, inv.rest.map(tokenValue))) return null
|
|
255
|
+
if (isHelpOnlyInvocation(inv.rest)) return null
|
|
256
|
+
const risk = classifyPush(inv.rest)
|
|
257
|
+
if (risk === 'non-ado') return null
|
|
258
|
+
const verbLabel = inv.subcommand === 'push' ? 'git push' : `git ${inv.subcommand}`
|
|
259
|
+
return risk === 'ado' ? `${verbLabel} against a dev.azure.com remote` : `${verbLabel} with an unresolved (implicit) remote destination`
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (inv.kind === 'azure-devops') {
|
|
263
|
+
// Defense in depth only — tool.azure-devops (registered ahead of this
|
|
264
|
+
// rule in ../registry.ts) already denies the whole `az devops|repos|
|
|
265
|
+
// pipelines|boards|artifacts` family outright, read or write, identity
|
|
266
|
+
// or not. See this file's header.
|
|
267
|
+
return azCommandIsWrite(inv.args) ? 'az CLI Azure DevOps write' : null
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (inv.kind === 'command') {
|
|
271
|
+
if (HTTP_CLIENT_NAMES.has(inv.name)) {
|
|
272
|
+
const targetsAdo = inv.args.some((token) => isAdoUrl(tokenValue(token)))
|
|
273
|
+
if (!targetsAdo) return null
|
|
274
|
+
// Every method needs an identity, GET included — the standard covers
|
|
275
|
+
// reads too, not only the mutating methods.
|
|
276
|
+
const method = httpClientMethod(inv.name, inv.args)
|
|
277
|
+
return `${inv.name} ${method} to dev.azure.com/visualstudio.com`
|
|
278
|
+
}
|
|
279
|
+
if (ADL_BINARY_ALL_NAMES.has(inv.name)) {
|
|
280
|
+
const values = inv.args.map((token) => tokenValue(token))
|
|
281
|
+
if (inv.args.some((token) => dynamicToken(token))) return null
|
|
282
|
+
if (!matchesIdentityShape(values, ADL_IDENTITY_COMMAND_SHAPES)) return null
|
|
283
|
+
return `${inv.name} ${values.slice(0, 3).join(' ')}`
|
|
284
|
+
}
|
|
285
|
+
if (ADL_AGENT_ID_BINARY_ALL_NAMES.has(inv.name)) {
|
|
286
|
+
const values = inv.args.map((token) => tokenValue(token))
|
|
287
|
+
if (inv.args.some((token) => dynamicToken(token))) return null
|
|
288
|
+
// Leading dash-prefixed
|
|
289
|
+
// global flags are skipped before matching the `['exec']` shape —
|
|
290
|
+
// see git-helpers.ts's skipLeadingDashFlags doc.
|
|
291
|
+
if (!matchesIdentityShape(skipLeadingDashFlags(values), ADL_AGENT_ID_COMMAND_SHAPES)) return null
|
|
292
|
+
return `${inv.name} ${values.slice(0, 3).join(' ')}`
|
|
293
|
+
}
|
|
294
|
+
if (INTERPRETER_ONE_LINER_NAMES.has(inv.name)) {
|
|
295
|
+
const identityBearing = interpreterCodeStrings(inv.args).some((code) => containsIdentityBearingToken(code))
|
|
296
|
+
return identityBearing ? `${inv.name} interpreter one-liner` : null
|
|
297
|
+
}
|
|
298
|
+
return null
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (inv.kind === 'tool-call') {
|
|
302
|
+
const toolName = mcpToolName(inv.tool)
|
|
303
|
+
if (toolName === null || !ADO_MCP_ALL_TOOLS.has(toolName)) return null
|
|
304
|
+
return `${MCP_REASON_PREFIX} ${inv.tool}`
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return null
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export const adlRunRequiredForWrites: RuleSpec = {
|
|
311
|
+
id: RULE_ID,
|
|
312
|
+
category: 'tool-call',
|
|
313
|
+
severity: 'deny',
|
|
314
|
+
enabledByDefault: true,
|
|
315
|
+
summary: 'Deny Azure DevOps access (git, az CLI, curl/wget/httpie, adl entry points, MCP tools) with no resolvable ADL agent identity.',
|
|
316
|
+
params: noParams,
|
|
317
|
+
match(inv: Invocation, ctx: RuleContext<Record<string, never>>): Finding | null {
|
|
318
|
+
// The shape check runs
|
|
319
|
+
// FIRST, entirely without touching `ctx.env` — `checkResolvableIdentity`
|
|
320
|
+
// can hit the real filesystem (the machine default-agent file) once
|
|
321
|
+
// neither the command's own inline override nor the session env
|
|
322
|
+
// resolves, so it must not run for every invocation this rule is asked
|
|
323
|
+
// about. The vast majority (ls, cat, git status, an unrelated tool
|
|
324
|
+
// call, …) are not identity-bearing at all and, with this ordering,
|
|
325
|
+
// never reach `checkResolvableIdentity` — only a genuine candidate does.
|
|
326
|
+
const reason = identityBearingReason(inv)
|
|
327
|
+
if (reason === null) return null
|
|
328
|
+
|
|
329
|
+
const identity = checkResolvableIdentity(ctx.command ?? '', ctx.env)
|
|
330
|
+
if (identity.resolvable) return null
|
|
331
|
+
// The exact message this specific failure earns — NOT a fixed
|
|
332
|
+
// generic string — carried in the Finding so message() reports it
|
|
333
|
+
// faithfully instead of a constant that cannot distinguish "nothing
|
|
334
|
+
// configured" from "something IS configured but it's wrong".
|
|
335
|
+
return { ruleId: RULE_ID, severity: 'deny', detail: { reason, identityMessage: identity.message } }
|
|
336
|
+
},
|
|
337
|
+
message(finding: Finding, ctx: MessageContext) {
|
|
338
|
+
const reason = detailString(finding, 'reason')
|
|
339
|
+
const identityMessage = detailString(finding, 'identityMessage')
|
|
340
|
+
// NO_AGENT_IDENTITY_MESSAGE (the "nothing configured at all" case) IS
|
|
341
|
+
// ALREADY "prefix the command with ADL_AGENT_ID_AGENT=<agent-...>" —
|
|
342
|
+
// appending the same advice a second time, in slightly different
|
|
343
|
+
// wording, would say it twice. The INVALID case (something IS configured, but names an agent
|
|
344
|
+
// outside VALID_AGENTS) has no such text at all, so the "how to fix it"
|
|
345
|
+
// sentence is the only place that advice appears for it and stays.
|
|
346
|
+
const advice = identityMessage === NO_AGENT_IDENTITY_MESSAGE ? '' : ` Prefix the command with ${ENV_VAR}=<agent>.`
|
|
347
|
+
// An MCP tool call carries no command text, so "prefix the command"
|
|
348
|
+
// cannot apply to it (Tarun, 2026-10-01): its identity comes from the
|
|
349
|
+
// environment or the machine default-agent file. MCP stays the primary
|
|
350
|
+
// route; `adl mcp cli <command>` is the FALLBACK when no identity
|
|
351
|
+
// resolves for the MCP server, and it takes the inline prefix like any
|
|
352
|
+
// command. Never `adl run` / "start the session" — see
|
|
353
|
+
// docs/operations/agent-permissions.md.
|
|
354
|
+
const cliAdvice = reason.startsWith(MCP_REASON_PREFIX)
|
|
355
|
+
? ` An MCP tool call cannot carry an inline prefix; its identity comes from the environment or the machine default-agent file. Until one resolves, use the fallback: ${ENV_VAR}=<agent> adl mcp cli <command>.`
|
|
356
|
+
: ''
|
|
357
|
+
return {
|
|
358
|
+
user: `${identityMessage}${cliAdvice}`,
|
|
359
|
+
agent: `DENIED ${reason} without an ADL agent identity. ${identityMessage}${advice}${cliAdvice} Blocked: ${ctx.snippet}`,
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
corpus: {
|
|
363
|
+
deny: [
|
|
364
|
+
'git push https://dev.azure.com/org/project/_git/repo main',
|
|
365
|
+
'git push origin main',
|
|
366
|
+
'git push',
|
|
367
|
+
// Git network READS need an identity too — every Azure DevOps access
|
|
368
|
+
// does, not only writes.
|
|
369
|
+
'git fetch origin main',
|
|
370
|
+
'git clone https://dev.azure.com/org/project/_git/repo',
|
|
371
|
+
'git ls-remote https://dev.azure.com/org/project/_git/repo',
|
|
372
|
+
'curl -X POST https://dev.azure.com/org/project/_apis/git/repositories',
|
|
373
|
+
'wget --method=POST https://dev.azure.com/org/project/_apis/git/repositories',
|
|
374
|
+
// A plain GET to dev.azure.com needs an identity too.
|
|
375
|
+
'curl https://dev.azure.com/org/project/_apis/git/repositories',
|
|
376
|
+
'wget https://dev.azure.com/org/project/_apis/git/repositories',
|
|
377
|
+
// The adl entry points that reach Azure DevOps.
|
|
378
|
+
'adl mcp cli pr-list-or-get',
|
|
379
|
+
'adl repo doctor',
|
|
380
|
+
'adl repo controls azdo-push',
|
|
381
|
+
'adl id token agent-tarun',
|
|
382
|
+
'adl-agent-id exec --agent agent-tarun -- adl id token agent-tarun --json',
|
|
383
|
+
// Already denied outright by tool.azure-devops (steers at the MCP server) —
|
|
384
|
+
// kept here too so this rule's own corpus is non-empty and honest about
|
|
385
|
+
// az CLI being a write surface it cares about; see the header for why
|
|
386
|
+
// its OWN read/write split is exercised in a dedicated unit test instead.
|
|
387
|
+
'az repos pr create --title x',
|
|
388
|
+
],
|
|
389
|
+
allow: [
|
|
390
|
+
// Explicit non-ADO destination: provably safe without an identity.
|
|
391
|
+
'git push https://github.com/org/repo main',
|
|
392
|
+
'git fetch https://github.com/org/repo main',
|
|
393
|
+
'curl https://github.com/org/repo',
|
|
394
|
+
'wget https://github.com/org/repo',
|
|
395
|
+
// Non-identity-bearing local commands and adl subcommands are untouched.
|
|
396
|
+
'git status',
|
|
397
|
+
'ls -la',
|
|
398
|
+
'adl run -- claude',
|
|
399
|
+
'adl repo controls compliance --repo .',
|
|
400
|
+
// A valid inline override supplies its own identity. A feature-branch
|
|
401
|
+
// destination (not `main`/`integration`) is used here so this stays a
|
|
402
|
+
// clean example of THIS rule's own concern — adl.git-push-branch-policy
|
|
403
|
+
// grades the command's EFFECTIVE identity too, so an inline-only
|
|
404
|
+
// override does not bypass branch protection:
|
|
405
|
+
// `ADL_AGENT_ID_AGENT=agent-tarun git push origin main` is denied by
|
|
406
|
+
// that rule, not allowed by this one.
|
|
407
|
+
'ADL_AGENT_ID_AGENT=agent-tarun git push origin feat/x',
|
|
408
|
+
'ADL_AGENT_ID_AGENT=agent-tarun adl id token agent-tarun',
|
|
409
|
+
],
|
|
410
|
+
},
|
|
411
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `adl.token-minting-role` —
|
|
3
|
-
* (STATUS.md 12p): an agent may mint a bearer
|
|
2
|
+
* `adl.token-minting-role` — one-agent-identity standard: an agent may mint a bearer
|
|
4
3
|
* token, or exec as an agent identity, only for its OWN effective identity —
|
|
5
4
|
* never for a different agent whose passport happens to be installed on the
|
|
6
5
|
* same machine. Covers the two token-minting entry points the standard
|
|
@@ -12,7 +11,7 @@
|
|
|
12
11
|
* `ADL_AGENT_ID_AGENT=<value>` on the command wins (step 1); otherwise the
|
|
13
12
|
* session's resolved identity, env then the machine default-agent file
|
|
14
13
|
* (`adl-identity.ts`'s `resolveFromEnvOrFile`, steps 2-3). With no identity
|
|
15
|
-
* at all, this rule stays silent — `adl.
|
|
14
|
+
* at all, this rule stays silent — `adl.run-required-for-writes` denies
|
|
16
15
|
* the call first (no session, not the wrong agent); with an invalid/empty
|
|
17
16
|
* inline override or an unrewritable sudo/doas wrapper, `adl.git-identity`
|
|
18
17
|
* denies first (registered ahead of this rule — see `../registry.ts`). This
|
|
@@ -56,7 +55,7 @@ export const adlTokenMintingRole: RuleSpec = {
|
|
|
56
55
|
if (scanGitIdentityConflicts(command, fallback) !== null) return null
|
|
57
56
|
|
|
58
57
|
for (const piece of scanTokenMintingPieces(command, fallback)) {
|
|
59
|
-
if (piece.effectiveAgent === null) continue // adl.
|
|
58
|
+
if (piece.effectiveAgent === null) continue // adl.run-required-for-writes's job
|
|
60
59
|
if (piece.effectiveAgent === piece.requestedAgent) continue
|
|
61
60
|
return {
|
|
62
61
|
ruleId: RULE_ID,
|
|
@@ -84,7 +83,7 @@ export const adlTokenMintingRole: RuleSpec = {
|
|
|
84
83
|
// adl.git-identity / adl.git-push-branch-policy — the shared corpus
|
|
85
84
|
// fixture (tests/fixtures/decide.ts) is hermetically identity-less, so
|
|
86
85
|
// even a bare `adl id token`/`adl-agent-id exec` there is denied by
|
|
87
|
-
// adl.
|
|
86
|
+
// adl.run-required-for-writes first, not usable as an allow entry
|
|
88
87
|
// here. Real coverage is tests/unit/rules-adl-token-minting-role.test.ts.
|
|
89
88
|
deny: [],
|
|
90
89
|
allow: ['ls -la', 'git status'],
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* order"); `tool.azure-devops` keeps denying the raw `az` form unchanged.
|
|
13
13
|
*
|
|
14
14
|
* Requires an identity to already be present (`ADL_AGENT_ID_AGENT`
|
|
15
|
-
* non-blank) — with no identity at all, `adl.
|
|
15
|
+
* non-blank) — with no identity at all, `adl.run-required-for-writes`
|
|
16
16
|
* denies the call first, so this rule returns null when the env var is
|
|
17
17
|
* absent or blank.
|
|
18
18
|
*/
|
|
@@ -32,20 +32,19 @@ export const adlWorkitemRequiresTarunOrVivek: RuleSpec = {
|
|
|
32
32
|
category: 'tool-call',
|
|
33
33
|
severity: 'deny',
|
|
34
34
|
enabledByDefault: true,
|
|
35
|
-
summary: 'Deny workitem_create_or_update for agent-reviewer (docs/operations/agent-permissions.md row 10) — the MCP tool AND its adl mcp cli equivalent
|
|
35
|
+
summary: 'Deny workitem_create_or_update for agent-reviewer (docs/operations/agent-permissions.md row 10) — the MCP tool AND its adl mcp cli equivalent.',
|
|
36
36
|
params: noParams,
|
|
37
37
|
match(inv: Invocation, ctx: RuleContext<Record<string, never>>): Finding | null {
|
|
38
|
-
//
|
|
38
|
+
// `adl mcp cli
|
|
39
39
|
// workitem-create-or-update` dispatches to the same tool the MCP server
|
|
40
40
|
// calls — graded identically, not only the tool-call payload shape.
|
|
41
41
|
const call = toolCallFor(inv)
|
|
42
42
|
if (call === null) return null
|
|
43
43
|
if (mcpToolName(call.tool) !== 'workitem_create_or_update') return null
|
|
44
44
|
|
|
45
|
-
//
|
|
46
|
-
// grade the EFFECTIVE identity for THIS specific piece — a valid inline
|
|
45
|
+
// Grade the EFFECTIVE identity for THIS specific piece — a valid inline
|
|
47
46
|
// `ADL_AGENT_ID_AGENT=` override on the same `adl mcp cli` invocation
|
|
48
|
-
// still wins, exactly like
|
|
47
|
+
// still wins, exactly like it does for `git push`
|
|
49
48
|
// (effectiveIdentityForMcpCli's own doc has the full "why"). A real MCP
|
|
50
49
|
// tool-call payload carries no command text at all (no inline override
|
|
51
50
|
// possible), so this still resolves to the plain session identity for
|
|
@@ -54,7 +53,7 @@ export const adlWorkitemRequiresTarunOrVivek: RuleSpec = {
|
|
|
54
53
|
const resolution = resolveFromEnvOrFile(ctx.env)
|
|
55
54
|
const fallback = resolution.ok ? resolution.agent : null
|
|
56
55
|
const agent = effectiveIdentityForMcpCli(inv, ctx.command ?? '', fallback)
|
|
57
|
-
if (agent === null) return null // no identity at all: adl.
|
|
56
|
+
if (agent === null) return null // no identity at all: adl.run-required-for-writes's job
|
|
58
57
|
if (agent !== AGENT_REVIEWER) return null
|
|
59
58
|
|
|
60
59
|
return { ruleId: RULE_ID, severity: 'deny', detail: { tool: call.tool } }
|