@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.12 → 0.1.28
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 +12 -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 +131 -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 +33 -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/scripts/probe-ado-rules.ts +311 -0
- 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 +44 -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-ladder.csv +241 -0
- package/packages/azdo/src/workflow-rules-matrix.csv +85 -0
- package/packages/azdo/src/workflow-rules.ts +194 -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 +258 -2
- 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/plan_metadata.py +9 -4
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/check.py +1 -1
- 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 +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +3 -3
- 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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `adl.human-azdo-bypass` —
|
|
2
|
+
* `adl.human-azdo-bypass` — the human pass-through in `bin/git-ado` fails
|
|
3
|
+
* closed and the human opts in (Tarun, 2026-09-29):
|
|
3
4
|
* `ADL_HUMAN_AZDO=1` marks Tarun's own interactive terminal (`bin/git-ado`'s
|
|
4
5
|
* and `resolveAgentIdentity`'s shared human-pass-through check,
|
|
5
6
|
* `packages/azdo/src/lib/agent-identity.ts`'s `isMarkedHumanAzdoCaller`:
|
|
@@ -11,17 +12,17 @@
|
|
|
11
12
|
* the whole standard exists to close — just aimed at the marker itself
|
|
12
13
|
* instead of at `ADL_AGENT_ID_AGENT`.
|
|
13
14
|
*
|
|
14
|
-
*
|
|
15
|
-
* `export ADL_HUMAN_AZD''O=1;
|
|
16
|
-
* git push origin feat/x`
|
|
17
|
-
* pass-through via a faked pty.
|
|
15
|
+
* Three shapes are denied (a/b/c below). An independent review
|
|
16
|
+
* (2026-09-29) found the live bypass they close: `export ADL_HUMAN_AZD''O=1;
|
|
17
|
+
* unset ADL_AGENT_ID_AGENT; script -q /dev/null git push origin feat/x`
|
|
18
|
+
* reached `bin/git-ado`'s human pass-through via a faked pty.
|
|
18
19
|
*
|
|
19
|
-
*
|
|
20
|
-
* `git commit -m "ADL_HUMAN_AZDO=1 is denied now"`, `git log -S
|
|
20
|
+
* Detection is POSITIONAL, not "any word anywhere", because a looser scan
|
|
21
|
+
* over-matched: `git commit -m "ADL_HUMAN_AZDO=1 is denied now"`, `git log -S
|
|
21
22
|
* "ADL_HUMAN_AZDO=1"`, `declare -p ADL_HUMAN_AZDO` (a READ, not a set),
|
|
22
23
|
* `grep -c '...'` (grep's COUNT flag, mistaken for shell `-c`), and `node -e
|
|
23
|
-
* "console.log('pty')"` (a bare word 'pty' in unrelated code)
|
|
24
|
-
* wrongly denied
|
|
24
|
+
* "console.log('pty')"` (a bare word 'pty' in unrelated code) would all be
|
|
25
|
+
* wrongly denied:
|
|
25
26
|
*
|
|
26
27
|
* (a) A setter is recognized only in a real setter POSITION — a leading
|
|
27
28
|
* `NAME=value` assignment before a piece's own command word, or the
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
* (b) Clearing `ADL_AGENT_ID_AGENT` is denied in every named form: `unset
|
|
49
50
|
* NAME` (as an operand of `unset`, the piece's own command), `env -u
|
|
50
51
|
* NAME`/`--unset[=]NAME`, an empty leading assignment (`NAME=`),
|
|
51
|
-
* `export -n NAME`, `declare +x NAME`/`typeset +x NAME` (
|
|
52
|
+
* `export -n NAME`, `declare +x NAME`/`typeset +x NAME` (`+x`
|
|
52
53
|
* removes the export attribute). `env -i`/`--ignore-environment`/bare
|
|
53
54
|
* `env -` clears the WHOLE environment, but is denied ONLY when the
|
|
54
55
|
* command it wraps is ITSELF identity-bearing (`isLikelyIdentityBearing`
|
|
@@ -62,8 +63,8 @@
|
|
|
62
63
|
* `delete $ENV{X}` (perl) — same "-c/-e/--eval argument only" scoping
|
|
63
64
|
* as the setter check.
|
|
64
65
|
* (c) `script`/`unbuffer`/`expect`, `socat` with a `pty` argument, `tmux`/
|
|
65
|
-
* `screen` starting a detached session with a command
|
|
66
|
-
* `new-session`/`-dm`/`-dmS`), `zsh`'s `zpty` module command, a
|
|
66
|
+
* `screen` starting a detached session with a command
|
|
67
|
+
* (`new-session`/`-dm`/`-dmS`), `zsh`'s `zpty` module command, a
|
|
67
68
|
* python/node/ruby/perl one-liner or flag that actually loads a pty
|
|
68
69
|
* module (`import pty`/`pty.spawn(...)`, `require('pty'|'node-pty')`,
|
|
69
70
|
* `-rpty`, `-MIO::Pty` — never a bare word), launching a real terminal
|
|
@@ -84,7 +85,7 @@
|
|
|
84
85
|
* missed because the literal first word was a wrapper.
|
|
85
86
|
*
|
|
86
87
|
* Word collection deliberately does NOT walk into here-documents, here-
|
|
87
|
-
* strings, or `$(...)`/backtick substitutions (out of scope for this
|
|
88
|
+
* strings, or `$(...)`/backtick substitutions (out of scope for this rule);
|
|
88
89
|
* it only reaches one level into a REAL shell's `-c`/`--command` script
|
|
89
90
|
* string, depth-capped — matching this rule's own "coarse, not a precise
|
|
90
91
|
* parser" contract.
|
|
@@ -98,8 +99,8 @@
|
|
|
98
99
|
* managed repo's own normal rule pass — this rule fires the same way any
|
|
99
100
|
* other enabled rule does, nothing baseline-specific about it.
|
|
100
101
|
*
|
|
101
|
-
* THE PTY-FAKING-WRAPPER CLASS IS UNBOUNDED (
|
|
102
|
-
*
|
|
102
|
+
* THE PTY-FAKING-WRAPPER CLASS IS UNBOUNDED (independent review,
|
|
103
|
+
* 2026-09-29: widen once, then stop).
|
|
103
104
|
* `pieceUsesPtyFakingWrapper` recognizes a widened but still FINITE list of
|
|
104
105
|
* named tools (`script`/`unbuffer`/`expect`/`zpty`, `socat`, `tmux`/`screen`,
|
|
105
106
|
* `ssh` to a loopback host, terminal-launching `open`/`osascript`, and a
|
|
@@ -109,12 +110,11 @@
|
|
|
109
110
|
* helper, a language runtime this list does not name, a future terminal
|
|
110
111
|
* emulator, a creative combination of otherwise-ordinary tools). Widening
|
|
111
112
|
* this list further, one reported gap at a time, has a naturally
|
|
112
|
-
* diminishing return:
|
|
113
|
-
*
|
|
114
|
-
* pass for the foreseeable future — the credential-level fix (removing the
|
|
113
|
+
* diminishing return: the list as it stands is the last widening pass for
|
|
114
|
+
* the foreseeable future — the credential-level fix (removing the
|
|
115
115
|
* SHARED-machine TTY signal `bin/git-ado` relies on as a proxy for "is this
|
|
116
|
-
* a human") is
|
|
117
|
-
*
|
|
116
|
+
* a human") is a separate track with Tarun, not something this rule can
|
|
117
|
+
* substitute for by enumerating tools forever.
|
|
118
118
|
*/
|
|
119
119
|
|
|
120
120
|
import type { Invocation } from '../shell/invocation.ts'
|
|
@@ -132,13 +132,13 @@ import { tokenize, tokenValue, type Token } from '../shell/token.ts'
|
|
|
132
132
|
export const RULE_ID = 'adl.human-azdo-bypass'
|
|
133
133
|
|
|
134
134
|
/**
|
|
135
|
-
* The exact env var name
|
|
135
|
+
* The exact env var name `bin/git-ado` checks for the human pass-through. Not exported as
|
|
136
136
|
* a standalone string constant from `packages/azdo/src/lib/agent-identity.ts`
|
|
137
137
|
* (only the combined TTY+value check, `isMarkedHumanAzdoCaller`, is) — this
|
|
138
138
|
* is the one place in this package that spells it, rather than a second,
|
|
139
139
|
* independent literal duplicated across detection helpers below.
|
|
140
140
|
*/
|
|
141
|
-
|
|
141
|
+
const ADL_HUMAN_AZDO_ENV_VAR = 'ADL_HUMAN_AZDO'
|
|
142
142
|
|
|
143
143
|
/** `os.environ['ADL_HUMAN_AZDO'] = ...` / `os.environ.setdefault('ADL_HUMAN_AZDO', ...)` — Python. Checked against ONLY the `-c`/`-e`/`--eval` code argument (see this file's own header). */
|
|
144
144
|
const PYTHON_HUMAN_AZDO_SET_RE = /os\.environ\s*(?:\[\s*['"]ADL_HUMAN_AZDO['"]\s*\]|\.setdefault\(\s*['"]ADL_HUMAN_AZDO['"])\s*[=(]/
|
|
@@ -161,7 +161,7 @@ const INTERPRETER_NAMES: ReadonlySet<string> = new Set(['python', 'python2', 'py
|
|
|
161
161
|
const AZ_NAMES: ReadonlySet<string> = new Set(['az', 'az.exe'])
|
|
162
162
|
|
|
163
163
|
/**
|
|
164
|
-
*
|
|
164
|
+
* Dynamic names (independent review, 2026-09-29): a strict leading
|
|
165
165
|
* assignment shape (`^[A-Za-z_][A-Za-z0-9_]*=`), but permitting
|
|
166
166
|
* `$`/backtick/`{`/`}` in the identifier portion too —
|
|
167
167
|
* `ADL_HUMAN_AZ${EMPTY}DO=1` is one word after `tokenize` (confirmed
|
|
@@ -185,7 +185,7 @@ function isAssignmentTo(value: string, name: string): boolean {
|
|
|
185
185
|
* know what such a word actually names — `v=ADL_HUMAN_AZDO; export "$v=1"`
|
|
186
186
|
* and `X=ADL_AGENT_ID_AGENT; unset $X` both hide the real name behind a
|
|
187
187
|
* variable this static scan never resolves — so any setter/clearer-shaped
|
|
188
|
-
* position holding one is treated as a match (
|
|
188
|
+
* position holding one is treated as a match (dynamic names,
|
|
189
189
|
* fail-closed) for whichever name the caller is checking.
|
|
190
190
|
*/
|
|
191
191
|
function isNameOperandDynamic(value: string): boolean {
|
|
@@ -223,9 +223,8 @@ interface WordPiece {
|
|
|
223
223
|
* (private) `isShellCommandOption` one-line check, kept in sync
|
|
224
224
|
* deliberately rather than exported, to recognize a shell invoked with
|
|
225
225
|
* combined flags (`zsh -ic '...'`, `bash -lc '...'`, `sh -ec '...'`) the
|
|
226
|
-
* same way the rest of the engine already does (
|
|
227
|
-
*
|
|
228
|
-
* '...'` defeat it entirely).
|
|
226
|
+
* same way the rest of the engine already does (an exact-`-c`-only
|
|
227
|
+
* check would let `zsh -ic '...'` defeat this rule entirely).
|
|
229
228
|
*/
|
|
230
229
|
function isShellScriptOption(value: string): boolean {
|
|
231
230
|
return value === '-c' || /^-[^-]*c$/.test(value) || value === '--command' || value.startsWith('--command=')
|
|
@@ -235,9 +234,9 @@ function isShellScriptOption(value: string): boolean {
|
|
|
235
234
|
* Every piece of `command` (one `WordPiece` per top-level piece), collected
|
|
236
235
|
* into `out`. Recurses one level into a `-c`-shaped shell script string
|
|
237
236
|
* ONLY when the piece's own RESOLVED command (past a leading assignment and
|
|
238
|
-
* a chain of transparent wrappers
|
|
239
|
-
* -c '...'`
|
|
240
|
-
* word
|
|
237
|
+
* a chain of transparent wrappers: `nohup bash -c '...'`/`FOO=1 bash
|
|
238
|
+
* -c '...'` would be invisible if only the piece's literal FIRST
|
|
239
|
+
* word were checked) is a real shell (`SHELL_NAMES`) — never for an
|
|
241
240
|
* unrelated `-c` flag on some other command (`grep -c`, `curl -c`, `ssh
|
|
242
241
|
* -c`, …). Quote concatenation and backslash escapes are already resolved
|
|
243
242
|
* by `tokenize`.
|
|
@@ -286,7 +285,7 @@ function interpreterInlineCode(args: readonly string[]): string | null {
|
|
|
286
285
|
* begin — past a leading `NAME=value` assignment and a chain of transparent
|
|
287
286
|
* wrappers (`sudo`/`env`/`timeout`/`nice`/`caffeinate`/`arch`/`exec`/`time`/
|
|
288
287
|
* `stdbuf`/`setsid`/`command`/`doas`/`nohup`/`gtimeout`) and THEIR OWN
|
|
289
|
-
* arguments (
|
|
288
|
+
* arguments (detection is by the walker's RESOLVED command). Reuses
|
|
290
289
|
* `../shell/prefixes.ts`'s own `skipPrefixes` — the SAME, already-tested
|
|
291
290
|
* wrapper-argument-skipping logic every other rule's classification is
|
|
292
291
|
* built on (`shell/invocation.ts`'s `walk()` calls it too) — rather than a
|
|
@@ -303,7 +302,7 @@ function resolvedCommand(piece: WordPiece): { readonly name: string | undefined;
|
|
|
303
302
|
return { name: basenameOf(piece.values[index] as string).toLowerCase(), argsStart: index + 1 }
|
|
304
303
|
}
|
|
305
304
|
|
|
306
|
-
/** A network git verb, a curl/wget/httpie/xh call to Azure DevOps, `az`, or an `adl`/`adl-agent-id` entry point — the shapes `env -i`/bare `env -` is worth denying for (
|
|
305
|
+
/** A network git verb, a curl/wget/httpie/xh call to Azure DevOps, `az`, or an `adl`/`adl-agent-id` entry point — the shapes `env -i`/bare `env -` is worth denying for (clearing the WHOLE environment for a command that never needed an identity is harmless). Coarse, matching the same tradeoff every other check in this file makes. */
|
|
307
306
|
function isLikelyIdentityBearing(name: string, args: readonly string[]): boolean {
|
|
308
307
|
if (name === 'git' || name === 'git.exe') {
|
|
309
308
|
const subIndex = args.findIndex((value) => !value.startsWith('-'))
|
|
@@ -317,8 +316,7 @@ function isLikelyIdentityBearing(name: string, args: readonly string[]): boolean
|
|
|
317
316
|
}
|
|
318
317
|
|
|
319
318
|
/**
|
|
320
|
-
*
|
|
321
|
-
* still missed when it is NOT `values[0]` — `if true; then export
|
|
319
|
+
* A setter/clearer keyword can be missed when it is NOT `values[0]` — `if true; then export
|
|
322
320
|
* ADL_HUMAN_AZDO=1; fi` splits (on `;`) into a piece whose first word is
|
|
323
321
|
* the keyword `then`, not `export`; `builtin export …`/`command export …`
|
|
324
322
|
* explicitly invoke the builtin/external form, bypassing any shell
|
|
@@ -356,7 +354,7 @@ function pieceSetsHumanAzdo(values: readonly string[], heredocs: readonly string
|
|
|
356
354
|
const rest = resolved.slice(1)
|
|
357
355
|
if (head === 'export') {
|
|
358
356
|
// `-f` (functions) is unrelated; `-p` (print) is deliberately NOT
|
|
359
|
-
// excluded here
|
|
357
|
+
// excluded here — `export -p ADL_HUMAN_AZDO=1` still
|
|
360
358
|
// carries an assignment and real bash still exports it, `-p` or not; a
|
|
361
359
|
// bare `export -p ADL_HUMAN_AZDO` (no `=`, a genuine list/print with no
|
|
362
360
|
// real effect) is a coarse, low-cost over-match this file already
|
|
@@ -387,8 +385,7 @@ function pieceSetsHumanAzdo(values: readonly string[], heredocs: readonly string
|
|
|
387
385
|
return false
|
|
388
386
|
}
|
|
389
387
|
if (INTERPRETER_NAMES.has(head)) {
|
|
390
|
-
//
|
|
391
|
-
// (`python3 - <<'EOF' ... EOF`) have no `-c`/`-e`/`--eval` argument at
|
|
388
|
+
// Heredoc-fed interpreters (`python3 - <<'EOF' ... EOF`) have no `-c`/`-e`/`--eval` argument at
|
|
392
389
|
// all — the real code is the heredoc BODY, passed in from `match()`
|
|
393
390
|
// (computed once from the whole command, not per-piece).
|
|
394
391
|
const inline = interpreterInlineCode(rest)
|
|
@@ -430,7 +427,7 @@ function pieceClearsAgentIdentity(piece: WordPiece, heredocs: readonly string[])
|
|
|
430
427
|
return false
|
|
431
428
|
}
|
|
432
429
|
if (INTERPRETER_NAMES.has(head)) {
|
|
433
|
-
//
|
|
430
|
+
// Heredoc-fed interpreters.
|
|
434
431
|
const inline = interpreterInlineCode(rest)
|
|
435
432
|
const candidates = inline !== null ? [inline] : heredocs
|
|
436
433
|
return candidates.some((code) => PYTHON_AGENT_ID_DELETE_RE.test(code) || NODE_AGENT_ID_DELETE_RE.test(code) || PERL_AGENT_ID_DELETE_RE.test(code))
|
|
@@ -441,7 +438,7 @@ function pieceClearsAgentIdentity(piece: WordPiece, heredocs: readonly string[])
|
|
|
441
438
|
const LOOPBACK_EXACT: ReadonlySet<string> = new Set(['localhost', '::1', '0'])
|
|
442
439
|
|
|
443
440
|
/**
|
|
444
|
-
*
|
|
441
|
+
* `user@host` (ssh's own
|
|
445
442
|
* `user@` prefix) is stripped before checking; `127.1`/`127.0.1` (partial
|
|
446
443
|
* IPv4 notation — every major OS resolves these to the `127.0.0.1` range)
|
|
447
444
|
* are accepted alongside the full four-octet form.
|
|
@@ -453,7 +450,7 @@ function isLoopbackHost(rawValue: string): boolean {
|
|
|
453
450
|
return /^127(?:\.\d{1,3}){1,3}$/.test(lower)
|
|
454
451
|
}
|
|
455
452
|
|
|
456
|
-
/** An unresolved shell expansion in a host-shaped position (
|
|
453
|
+
/** An unresolved shell expansion in a host-shaped position (`ssh -tt $(hostname) …`) — cannot be proven non-loopback, so treated as a match (fail-closed), the same "dynamic names" tradeoff this file already makes elsewhere. */
|
|
457
454
|
const isDynamicHostCandidate = (value: string): boolean => /\$\(|`|\$\{/.test(value)
|
|
458
455
|
|
|
459
456
|
function sshForcesTty(args: readonly string[]): boolean {
|
|
@@ -467,10 +464,10 @@ function sshForcesTty(args: readonly string[]): boolean {
|
|
|
467
464
|
return false
|
|
468
465
|
}
|
|
469
466
|
|
|
470
|
-
/** No legitimate use on an agent surface — see this file's own
|
|
467
|
+
/** No legitimate use on an agent surface — see this file's own header, part (c). `zpty` is zsh's own pty module command — invoked as `zsh -c 'zpty ...'`, this scanner's own `-c` recursion (real shells only) makes `zpty` the RESOLVED command of the nested piece, not merely an argument to `zsh`. */
|
|
471
468
|
const UNCONDITIONAL_PTY_WRAPPERS: ReadonlySet<string> = new Set(['script', 'unbuffer', 'expect', 'zpty'])
|
|
472
469
|
|
|
473
|
-
/** True when `args` is nothing but `--help`/`-h`/`--version`/`-V` — a string-value mirror of `shell/invocation.ts`'s own (Token-based) `isHelpOrVersionOnly`.
|
|
470
|
+
/** True when `args` is nothing but `--help`/`-h`/`--version`/`-V` — a string-value mirror of `shell/invocation.ts`'s own (Token-based) `isHelpOrVersionOnly`. `expect --version` has no script to run at all — harmless. */
|
|
474
471
|
function isHelpOrVersionOnlyValues(args: readonly string[]): boolean {
|
|
475
472
|
let sawHelp = false
|
|
476
473
|
for (const arg of args) {
|
|
@@ -485,7 +482,7 @@ function isHelpOrVersionOnlyValues(args: readonly string[]): boolean {
|
|
|
485
482
|
return sawHelp
|
|
486
483
|
}
|
|
487
484
|
|
|
488
|
-
/** Every `-e CODE` occurrence (
|
|
485
|
+
/** Every `-e CODE` occurrence (`osascript` accepts MULTIPLE `-e` flags, each one a line of the same script — reading only the first, as `interpreterInlineCode` does, missed a script split across several). */
|
|
489
486
|
function allDashEArgs(args: readonly string[]): readonly string[] {
|
|
490
487
|
const values: string[] = []
|
|
491
488
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -495,7 +492,7 @@ function allDashEArgs(args: readonly string[]): readonly string[] {
|
|
|
495
492
|
}
|
|
496
493
|
|
|
497
494
|
const TMUX_ACTIONS: ReadonlySet<string> = new Set(['new-session', 'new', 'new-window', 'split-window', 'send-keys'])
|
|
498
|
-
/** Bundle IDs for `open -b <id
|
|
495
|
+
/** Bundle IDs for `open -b <id>`: the app-name check (`open -a Terminal`) has no bundle-id equivalent to match against. */
|
|
499
496
|
const TERMINAL_BUNDLE_IDS: ReadonlySet<string> = new Set([
|
|
500
497
|
'com.apple.terminal',
|
|
501
498
|
'com.googlecode.iterm2',
|
|
@@ -505,10 +502,10 @@ const TERMINAL_BUNDLE_IDS: ReadonlySet<string> = new Set([
|
|
|
505
502
|
'org.alacritty',
|
|
506
503
|
'com.github.wez.wezterm',
|
|
507
504
|
])
|
|
508
|
-
/** Terminal-app names `open -a`/AppleScript/JXA name by —
|
|
505
|
+
/** Terminal-app names `open -a`/AppleScript/JXA name by — covers every common terminal emulator, not only Terminal/iTerm. */
|
|
509
506
|
const TERMINAL_APP_NAME_RE = /\b(?:terminal|iterm|ghostty|warp|kitty|alacritty|wezterm)\b/i
|
|
510
507
|
|
|
511
|
-
/** True when `piece` (one piece's words) invokes a pty-faking wrapper, resolved past a leading assignment and a chain of transparent wrappers. See this file's own
|
|
508
|
+
/** True when `piece` (one piece's words) invokes a pty-faking wrapper, resolved past a leading assignment and a chain of transparent wrappers. See this file's own header, part (c), for which shapes are unconditional vs. narrowed to a loopback host. */
|
|
512
509
|
function pieceUsesPtyFakingWrapper(piece: WordPiece): boolean {
|
|
513
510
|
const resolved = resolvedCommand(piece)
|
|
514
511
|
const name = resolved.name
|
|
@@ -530,7 +527,7 @@ function pieceUsesPtyFakingWrapper(piece: WordPiece): boolean {
|
|
|
530
527
|
if (INTERPRETER_NAMES.has(name)) {
|
|
531
528
|
const code = interpreterInlineCode(args)
|
|
532
529
|
if (code === null) return false
|
|
533
|
-
//
|
|
530
|
+
// Comma-form imports (`import os, pty`) and `__import__('pty')`.
|
|
534
531
|
if (name.startsWith('python')) {
|
|
535
532
|
return (
|
|
536
533
|
/(?:^|[\s;])import\s+(?:[\w.]+\s*,\s*)*pty\b|\bfrom\s+pty\s+import\b|\bpty\.(?:spawn|fork|openpty)\s*\(|__import__\(\s*['"]pty['"]\s*\)/.test(
|
|
@@ -549,7 +546,7 @@ function pieceUsesPtyFakingWrapper(piece: WordPiece): boolean {
|
|
|
549
546
|
if (name === 'open') {
|
|
550
547
|
for (let index = 0; index < args.length; index += 1) {
|
|
551
548
|
const value = args[index] as string
|
|
552
|
-
//
|
|
549
|
+
// Combined flags (`-na` = -n new-instance + -a app) — any
|
|
553
550
|
// combined short-flag string containing `a`/`b` still takes the
|
|
554
551
|
// NEXT word as the app name / bundle id, same as the bare flag.
|
|
555
552
|
if (/^-[a-zA-Z]*a[a-zA-Z]*$/.test(value) && TERMINAL_APP_NAME_RE.test(args[index + 1] ?? '')) return true
|
|
@@ -562,7 +559,7 @@ function pieceUsesPtyFakingWrapper(piece: WordPiece): boolean {
|
|
|
562
559
|
if (codes.length === 0) return false
|
|
563
560
|
const combined = codes.join('\n')
|
|
564
561
|
if (!TERMINAL_APP_NAME_RE.test(combined)) return false
|
|
565
|
-
//
|
|
562
|
+
// AppleScript's `do script` and JXA's (`-l JavaScript`) `.doScript(`
|
|
566
563
|
// are the same operation in the two languages osascript accepts.
|
|
567
564
|
return /\bdo script\b/i.test(combined) || /\.\s*doScript\s*\(/i.test(combined)
|
|
568
565
|
}
|
|
@@ -577,7 +574,7 @@ export const adlHumanAzdoBypass: RuleSpec = {
|
|
|
577
574
|
severity: 'deny',
|
|
578
575
|
enabledByDefault: true,
|
|
579
576
|
summary:
|
|
580
|
-
"Deny an agent command that sets/exports/assigns ADL_HUMAN_AZDO, clears ADL_AGENT_ID_AGENT, or fakes a TTY to defeat bin/git-ado's human/agent decision
|
|
577
|
+
"Deny an agent command that sets/exports/assigns ADL_HUMAN_AZDO, clears ADL_AGENT_ID_AGENT, or fakes a TTY to defeat bin/git-ado's human/agent decision.",
|
|
581
578
|
params: noParams,
|
|
582
579
|
match(inv: Invocation, ctx: RuleContext<Record<string, never>>): Finding | null {
|
|
583
580
|
// A tool-call payload (a real MCP call) carries no shell command text
|
|
@@ -586,7 +583,7 @@ export const adlHumanAzdoBypass: RuleSpec = {
|
|
|
586
583
|
const command = ctx.command ?? ''
|
|
587
584
|
if (command.trim().length === 0) return null
|
|
588
585
|
const pieces = wordPiecesFor(command)
|
|
589
|
-
//
|
|
586
|
+
// Heredoc-fed interpreters
|
|
590
587
|
// (`python3 - <<'EOF' ... EOF`) have no `-c`/`-e`/`--eval` argument at
|
|
591
588
|
// all — computed once from the whole command, not per-piece.
|
|
592
589
|
const heredocs = heredocBodies(command)
|
|
@@ -623,7 +620,7 @@ export const adlHumanAzdoBypass: RuleSpec = {
|
|
|
623
620
|
agent:
|
|
624
621
|
`DENIED ${user}. unset/env -u/env -i (wrapping an identity-bearing command)/an empty inline assignment/export -n/` +
|
|
625
622
|
`declare or typeset +x on ${ADL_AGENT_ID_ENV_VAR} removes the one thing that routes a network git command as this ` +
|
|
626
|
-
`agent instead of falling through to bin/git-ado's own default
|
|
623
|
+
`agent instead of falling through to bin/git-ado's own default. Never clear it; prefix the ` +
|
|
627
624
|
`command with ${ADL_AGENT_ID_ENV_VAR}=<agent> instead. Blocked: ${ctx.snippet}`,
|
|
628
625
|
}
|
|
629
626
|
}
|
|
@@ -634,7 +631,7 @@ export const adlHumanAzdoBypass: RuleSpec = {
|
|
|
634
631
|
user,
|
|
635
632
|
agent:
|
|
636
633
|
`DENIED ${user}. These tools exist to make a program's isatty() check pass when nothing real is attached to it — ` +
|
|
637
|
-
"bin/git-ado's own human-vs-agent decision is exactly such a check, and faking it
|
|
634
|
+
"bin/git-ado's own human-vs-agent decision is exactly such a check, and faking it is how a " +
|
|
638
635
|
'session with no agent identity reaches the human credential path undetected. There is no legitimate use of a ' +
|
|
639
636
|
`pty-faking wrapper on an agent surface; run the command directly instead. Blocked: ${ctx.snippet}`,
|
|
640
637
|
}
|
|
@@ -645,7 +642,7 @@ export const adlHumanAzdoBypass: RuleSpec = {
|
|
|
645
642
|
agent:
|
|
646
643
|
`DENIED ${user}. ${ADL_HUMAN_AZDO_ENV_VAR}=1 tells bin/git-ado this is Tarun's own interactive terminal - setting, exporting, ` +
|
|
647
644
|
`or assigning it from an agent surface (inline, export, env, declare/typeset -x, printf -v, read, a nested REAL shell — ` +
|
|
648
|
-
`quote-split or backslash-escaped included
|
|
645
|
+
`quote-split or backslash-escaped included — or an interpreter's own os.environ/process.env/$ENV) would let ` +
|
|
649
646
|
`git-ado's human pass-through apply with no agent identity involved. Unset it (or use \`env -u ${ADL_HUMAN_AZDO_ENV_VAR}\`) ` +
|
|
650
647
|
`if you need it absent; prefix the command with ADL_AGENT_ID_AGENT=<agent-tarun|agent-vivek|agent-reviewer> instead. ` +
|
|
651
648
|
`Blocked: ${ctx.snippet}`,
|
|
@@ -664,7 +661,7 @@ export const adlHumanAzdoBypass: RuleSpec = {
|
|
|
664
661
|
`python3 -c "import os; os.environ['ADL_HUMAN_AZDO'] = '1'"`,
|
|
665
662
|
`node -e "process.env.ADL_HUMAN_AZDO = '1'"`,
|
|
666
663
|
`node -e "process.env['ADL_HUMAN_AZDO'] = '1'"`,
|
|
667
|
-
//
|
|
664
|
+
// Shell quote-splitting / backslash-escaping cannot defeat the
|
|
668
665
|
// check any more — the tokenizer resolves both before matching.
|
|
669
666
|
`export ADL_HUMAN_AZD''O=1`,
|
|
670
667
|
`export ADL_HUMAN_AZ\\DO=1`,
|
|
@@ -675,7 +672,7 @@ export const adlHumanAzdoBypass: RuleSpec = {
|
|
|
675
672
|
// also what makes the loop run at all.
|
|
676
673
|
`printf -v ADL_HUMAN_AZDO '1'; git push origin main`,
|
|
677
674
|
'read ADL_HUMAN_AZDO',
|
|
678
|
-
//
|
|
675
|
+
// Clearing ADL_AGENT_ID_AGENT in any form.
|
|
679
676
|
'unset ADL_AGENT_ID_AGENT',
|
|
680
677
|
'unset ADL_AGENT_ID_AGENT; git push origin feat/x',
|
|
681
678
|
'env -u ADL_AGENT_ID_AGENT git push origin feat/x',
|
|
@@ -686,7 +683,7 @@ export const adlHumanAzdoBypass: RuleSpec = {
|
|
|
686
683
|
'ADL_AGENT_ID_AGENT= git push origin feat/x',
|
|
687
684
|
'export -n ADL_AGENT_ID_AGENT',
|
|
688
685
|
'declare +x ADL_AGENT_ID_AGENT',
|
|
689
|
-
//
|
|
686
|
+
// Pty-faking wrappers, unconditional.
|
|
690
687
|
'script -q /dev/null git push origin feat/x',
|
|
691
688
|
'unbuffer git push origin feat/x',
|
|
692
689
|
'expect -c "spawn git push origin feat/x"',
|
|
@@ -694,7 +691,7 @@ export const adlHumanAzdoBypass: RuleSpec = {
|
|
|
694
691
|
`python3 -c "import pty; pty.spawn(['git','push','origin','feat/x'])"`,
|
|
695
692
|
'ssh -t localhost git push origin feat/x',
|
|
696
693
|
'ssh -t 127.0.0.1 git push origin feat/x',
|
|
697
|
-
// The live
|
|
694
|
+
// The live bypass found by the independent review, combined.
|
|
698
695
|
"export ADL_HUMAN_AZD''O=1; unset ADL_AGENT_ID_AGENT; script -q /dev/null git push origin feat/x",
|
|
699
696
|
],
|
|
700
697
|
allow: [
|
|
@@ -712,7 +709,7 @@ export const adlHumanAzdoBypass: RuleSpec = {
|
|
|
712
709
|
'socat TCP:example.com:80 -',
|
|
713
710
|
// A bare python/node one-liner naming neither variable: untouched.
|
|
714
711
|
`python3 -c "print('hello')"`,
|
|
715
|
-
//
|
|
712
|
+
// False positives a looser scan produced on normal
|
|
716
713
|
// agent work — a mention of the name in an unrelated command's
|
|
717
714
|
// argument, a read (not a set), an unrelated `-c` flag mistaken for
|
|
718
715
|
// shell `-c`, a bare 'pty' word, and env -i clearing the WHOLE
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `ADL_AGENT_ID_AGENT`, read the same way by every rule that keys behaviour
|
|
3
|
-
* off the session's agent identity (docs/operations/agent-permissions.md,
|
|
4
|
-
*
|
|
3
|
+
* off the session's agent identity (docs/operations/agent-permissions.md,
|
|
4
|
+
* docs/architecture/cli-design.md §1c).
|
|
5
5
|
*
|
|
6
|
-
* The one-agent-identity standard (
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The one-agent-identity standard (Tarun, 2026-09-28) makes
|
|
7
|
+
* `packages/azdo/src/lib/agent-identity.ts` the ONE Azure DevOps identity
|
|
8
|
+
* resolver in this repo; this file keeps no copy of
|
|
9
9
|
* `VALID_AGENTS`/`NO_AGENT_IDENTITY_MESSAGE`/the default-agent-file read — it
|
|
10
10
|
* imports them, and `BUILDER_AGENTS` derives from `VALID_AGENTS` rather than
|
|
11
11
|
* naming `AGENT_TARUN`/`AGENT_VIVEK` a second time.
|
|
@@ -15,16 +15,13 @@ import {
|
|
|
15
15
|
NO_AGENT_IDENTITY_MESSAGE,
|
|
16
16
|
resolveAgentIdentity,
|
|
17
17
|
VALID_AGENTS,
|
|
18
|
-
type ValidAgent,
|
|
19
18
|
} from '../../../../azdo/src/lib/agent-identity.ts'
|
|
20
19
|
import type { EnvPort } from '../ports.ts'
|
|
21
20
|
|
|
22
|
-
export { isValidAgent, NO_AGENT_IDENTITY_MESSAGE
|
|
21
|
+
export { isValidAgent, NO_AGENT_IDENTITY_MESSAGE }
|
|
23
22
|
|
|
24
23
|
export const ADL_AGENT_ID_ENV_VAR = 'ADL_AGENT_ID_AGENT'
|
|
25
24
|
export const AGENT_REVIEWER = 'agent-reviewer'
|
|
26
|
-
export const AGENT_TARUN = 'agent-tarun'
|
|
27
|
-
export const AGENT_VIVEK = 'agent-vivek'
|
|
28
25
|
|
|
29
26
|
/** The two-branch standard's builders (docs/specs/two-branch-standard-2026-09-27.md §1b.1): cut a feature branch from `integration`, create their own PRs into it. Every VALID_AGENTS member except agent-reviewer. */
|
|
30
27
|
export const BUILDER_AGENTS: ReadonlySet<string> = new Set(VALID_AGENTS.filter((name) => name !== AGENT_REVIEWER))
|
|
@@ -38,21 +35,18 @@ export const BUILDER_AGENTS: ReadonlySet<string> = new Set(VALID_AGENTS.filter((
|
|
|
38
35
|
* set it to a path that does not exist -- see `resolveFromEnvOrFile`'s doc.
|
|
39
36
|
* Never the real system path (AGENTS.md: tests are hermetic).
|
|
40
37
|
*/
|
|
41
|
-
|
|
38
|
+
const DEFAULT_AGENT_FILE_OVERRIDE_ENV = 'ADL_DEFAULT_AGENT_FILE'
|
|
42
39
|
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
// `../../hooks/lean-ctx/scope-rewrite.ts`'s `sessionIdentityOf` — was
|
|
46
|
-
// removed here (not merely superseded) once that caller switched to
|
|
40
|
+
// There is deliberately no session-env-only `currentAgent` read here:
|
|
41
|
+
// `../../hooks/lean-ctx/scope-rewrite.ts`'s `sessionIdentityOf` calls
|
|
47
42
|
// `resolveFromEnvOrFile` (steps 2-3 of the standard: env, THEN the machine
|
|
48
|
-
// default-agent file)
|
|
49
|
-
//
|
|
50
|
-
// needs — bunfig.toml's coverage policy has no ignore-list for exactly this
|
|
43
|
+
// default-agent file), so a function that read the env alone would have no
|
|
44
|
+
// caller. bunfig.toml's coverage policy has no ignore-list for exactly this
|
|
51
45
|
// reason: a function nothing calls gets deleted, not exempted.
|
|
52
46
|
|
|
53
|
-
|
|
47
|
+
type IdentitySource = 'env' | 'default-file'
|
|
54
48
|
|
|
55
|
-
|
|
49
|
+
interface ResolvedIdentity {
|
|
56
50
|
readonly ok: true
|
|
57
51
|
readonly agent: string
|
|
58
52
|
readonly source: IdentitySource
|
|
@@ -68,7 +62,7 @@ export interface ResolvedIdentity {
|
|
|
68
62
|
* identity, here is how to set one" is a different problem from "an agent
|
|
69
63
|
* identity IS configured and it is wrong."
|
|
70
64
|
*/
|
|
71
|
-
|
|
65
|
+
interface UnresolvedIdentity {
|
|
72
66
|
readonly ok: false
|
|
73
67
|
readonly reason: 'none' | 'invalid'
|
|
74
68
|
readonly message: string
|
|
@@ -77,9 +71,8 @@ export interface UnresolvedIdentity {
|
|
|
77
71
|
export type IdentityResolution = ResolvedIdentity | UnresolvedIdentity
|
|
78
72
|
|
|
79
73
|
/**
|
|
80
|
-
* Steps 2-3 of the standard
|
|
81
|
-
*
|
|
82
|
-
* machine default-agent file, else unresolved. Step 1 (an inline
|
|
74
|
+
* Steps 2-3 of the standard: `ADL_AGENT_ID_AGENT` from the session
|
|
75
|
+
* environment, else the machine default-agent file, else unresolved. Step 1 (an inline
|
|
83
76
|
* `ADL_AGENT_ID_AGENT=<agent>` prefix on the command itself) is NOT this
|
|
84
77
|
* function's job — that is a property of the command text, resolved by
|
|
85
78
|
* `../shell/git-identity.ts`'s scanner, which calls this function only for
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `adl mcp cli <command> [options]` → the equivalent MCP tool call, for the
|
|
3
|
-
* role rules that must grade it EXACTLY like the real MCP tool call
|
|
4
|
-
*
|
|
3
|
+
* role rules that must grade it EXACTLY like the real MCP tool call.
|
|
4
|
+
* MCP is the primary route to Azure DevOps operations and `adl mcp cli` is
|
|
5
|
+
* the fallback for when MCP is not working, so both surfaces share one grade:
|
|
6
|
+
* `docs/operations/agent-permissions.md`
|
|
5
7
|
* gates the tool, not the surface it was invoked through, and `adl mcp cli`
|
|
6
8
|
* (`packages/azdo/src/cli.ts`'s `runCli`) dispatches to the SAME
|
|
7
9
|
* `dispatchTool` the MCP server itself calls — a caller who runs
|
|
@@ -134,7 +136,7 @@ export function adlMcpCliCall(inv: Invocation): AdlMcpCliCall | null {
|
|
|
134
136
|
|
|
135
137
|
/**
|
|
136
138
|
* The `{tool, input}` pair for `inv`, whether it is a real MCP tool-call
|
|
137
|
-
* payload or an equivalent `adl mcp cli <command>` shell invocation
|
|
139
|
+
* payload or an equivalent `adl mcp cli <command>` shell invocation —
|
|
138
140
|
* or `null` when `inv` is neither. Every role rule that used to check only
|
|
139
141
|
* `inv.kind === 'tool-call'` calls this instead, so a caller cannot route
|
|
140
142
|
* around role grading just by using the CLI form of the same tool.
|
|
@@ -145,19 +147,20 @@ export function toolCallFor(inv: Invocation): AdlMcpCliCall | null {
|
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
/**
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
* `
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* that will actually run is
|
|
150
|
+
* The EFFECTIVE identity for THIS specific `adl mcp cli <command>`
|
|
151
|
+
* invocation — the same per-piece correlation
|
|
152
|
+
* `impl/adl-git-push-policy.ts`'s `effectiveIdentityForPush` gives
|
|
153
|
+
* `git push`, extended to this command class. The role rules
|
|
154
|
+
* (`adl-workitem-role.ts`/`adl-pr-role.ts`/`adl-pr-review-role.ts`) grade this
|
|
155
|
+
* value, not `resolveFromEnvOrFile(ctx.env)` alone, because a valid inline
|
|
156
|
+
* `ADL_AGENT_ID_AGENT=` override on the very piece being graded wins. Grading
|
|
157
|
+
* the session identity alone would be wrong in both directions: a reviewer
|
|
158
|
+
* session's own inline `agent-tarun` override on
|
|
159
|
+
* `adl mcp cli workitem-create-or-update` would be denied as `agent-reviewer`
|
|
160
|
+
* (a false deny), and — the more dangerous direction — an `agent-tarun`
|
|
161
|
+
* SESSION with an inline `ADL_AGENT_ID_AGENT=agent-reviewer` override would be
|
|
162
|
+
* graded as `agent-tarun` (a false ALLOW: the piece that will actually run is
|
|
163
|
+
* `agent-reviewer`'s).
|
|
161
164
|
*
|
|
162
165
|
* A `tool-call`-kind `inv` (a real MCP tool call, not the CLI shell form)
|
|
163
166
|
* carries no command text at all — no inline override is possible for it —
|
|
@@ -36,10 +36,10 @@ export const adlPrCompletePendingDecision: RuleSpec = {
|
|
|
36
36
|
severity: 'deny',
|
|
37
37
|
enabledByDefault: true,
|
|
38
38
|
summary:
|
|
39
|
-
'Deny PR completion / auto-complete for every identity — open decision (docs/operations/agent-permissions.md row 9) — the MCP tool AND its adl mcp cli equivalent
|
|
39
|
+
'Deny PR completion / auto-complete for every identity — open decision (docs/operations/agent-permissions.md row 9) — the MCP tool AND its adl mcp cli equivalent.',
|
|
40
40
|
params: noParams,
|
|
41
41
|
match(inv: Invocation): Finding | null {
|
|
42
|
-
//
|
|
42
|
+
// `adl mcp cli
|
|
43
43
|
// pr-create-or-update` is the SAME tool `adl.pr-create-update-role`
|
|
44
44
|
// steps aside for on this shape — without this, the CLI form of a
|
|
45
45
|
// completion call would sail through both rules.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `adl.pr-review-role` — docs/operations/agent-permissions.md rows 6-8 (PR comment; PR
|
|
3
3
|
* vote on `main`; PR vote on `integration`), the sibling `adl-pr-role.ts`'s
|
|
4
4
|
* own header named as PENDING until `packages/azdo` shipped a comment/vote
|
|
5
|
-
* tool (
|
|
5
|
+
* tool (`pr_review`). Gates the ONE MCP tool that ships that shape,
|
|
6
6
|
* `pr_review({ pullRequestId, comment?, vote?, targetBranch?, repository? })`
|
|
7
7
|
* — see `packages/azdo/src/azdo-pr-review.ts`.
|
|
8
8
|
*
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* caller cannot route around by skipping the hook.
|
|
32
32
|
*
|
|
33
33
|
* Requires an identity to already be present (`ADL_AGENT_ID_AGENT`
|
|
34
|
-
* non-blank) — with no identity at all, `adl.
|
|
34
|
+
* non-blank) — with no identity at all, `adl.run-required-for-writes`
|
|
35
35
|
* denies the call first (a different problem: no session, not the wrong
|
|
36
36
|
* role or branch), so this rule returns null when the env var is absent or
|
|
37
37
|
* blank, matching `adl-pr-role.ts`'s own convention exactly.
|
|
@@ -72,16 +72,14 @@ export const adlPrReviewRole: RuleSpec = {
|
|
|
72
72
|
'Gate pr_review: comment for a builder or agent-reviewer (row 6); vote for agent-reviewer only, main only, fail-closed without a declared target (rows 7-8).',
|
|
73
73
|
params: noParams,
|
|
74
74
|
match(inv: Invocation, ctx: RuleContext<Record<string, never>>): Finding | null {
|
|
75
|
-
//
|
|
76
|
-
// pr-review` dispatches to the same tool the MCP server calls.
|
|
75
|
+
// `adl mcp cli pr-review` dispatches to the same tool the MCP server calls.
|
|
77
76
|
const call = toolCallFor(inv)
|
|
78
77
|
if (call === null) return null
|
|
79
78
|
if (mcpToolName(call.tool) !== 'pr_review') return null
|
|
80
79
|
|
|
81
|
-
//
|
|
82
|
-
// grade the EFFECTIVE identity for THIS specific piece — a valid inline
|
|
80
|
+
// Grade the EFFECTIVE identity for THIS specific piece — a valid inline
|
|
83
81
|
// `ADL_AGENT_ID_AGENT=` override on the same `adl mcp cli` invocation
|
|
84
|
-
// still wins, exactly like
|
|
82
|
+
// still wins, exactly like it does for `git push` (see
|
|
85
83
|
// `effectiveIdentityForMcpCli`'s own doc). A real MCP tool-call payload
|
|
86
84
|
// carries no command text at all (no inline override possible), so this
|
|
87
85
|
// still resolves to the plain session identity for that shape — env,
|
|
@@ -90,19 +88,18 @@ export const adlPrReviewRole: RuleSpec = {
|
|
|
90
88
|
const resolution = resolveFromEnvOrFile(ctx.env)
|
|
91
89
|
const fallback = resolution.ok ? resolution.agent : null
|
|
92
90
|
const agent = effectiveIdentityForMcpCli(inv, ctx.command ?? '', fallback)
|
|
93
|
-
if (agent === null) return null // no identity at all: adl.
|
|
91
|
+
if (agent === null) return null // no identity at all: adl.run-required-for-writes's job
|
|
94
92
|
|
|
95
93
|
const input = call.input as PrReviewInput
|
|
96
94
|
|
|
97
95
|
// Row 6: comment — the more fundamental restriction when present, same
|
|
98
96
|
// allow-set as row 5, checked first regardless of whether a vote is ALSO
|
|
99
|
-
// on this call.
|
|
97
|
+
// on this call. `agent` is guaranteed
|
|
100
98
|
// a VALID_AGENTS member whenever it is non-null (resolveFromEnvOrFile
|
|
101
99
|
// validates it), and BUILDER_AGENTS ∪ {agent-reviewer} already IS all of
|
|
102
100
|
// VALID_AGENTS for this row — so `!isAllowedToComment(agent)` can never
|
|
103
|
-
// be true through any real resolved identity
|
|
104
|
-
// adl-pr-role.ts's sibling check already
|
|
105
|
-
// this widening). Kept as defense in depth for a future VALID_AGENTS
|
|
101
|
+
// be true through any real resolved identity (same fact
|
|
102
|
+
// adl-pr-role.ts's sibling check already lives with). Kept as defense in depth for a future VALID_AGENTS
|
|
106
103
|
// member this allow-set does not name, in the same single-physical-line
|
|
107
104
|
// shape adl-pr-role.ts already uses for its own now-unreachable check —
|
|
108
105
|
// see rules-adl-pr-role.test.ts's "denial message is exact" describe
|