refactor(compile): centralize ado-script bundle env contract#1315
Conversation
Every compiler step that runs an ado-script bundle previously hand-wrote its env: block, which is how the Conclusion step drifted and shipped without an ADO bearer token (#1307). Introduce src/compile/ado_bundle.rs as the single source of truth for the bundles' auth contract: - Bundle enum (path + auth) for every ado-script bundle. - apply_bundle_auth(): the one chokepoint that projects SYSTEM_ACCESSTOKEN (a secret; the one ADO predefined var that is NOT auto-injected) into every REST-calling bundle step, so no call site can forget it again. - token_source_for(): unifies the System.AccessToken vs SC_WRITE_TOKEN selection shared by the Conclusion job and the Stage 3 executor. - is_redundant_ado_mirror(): identifies redundant re-projections of auto-injected predefined vars, asserted by the contract tests. Route all bundle call sites (gate, synthetic-PR, the exec-context contributors, conclusion, executor) through the applier, and strip the ~40 redundant SYSTEM_*/BUILD_* env projections that ADO already auto-injects into every script step. Bundles read those auto-injected names directly (verified against each bundle's process.env reads), so the projections were pure noise. Migrate the synthetic-PR bundle off its renamed ADO_PROJECT/ADO_REPO_ID onto the auto-injected SYSTEM_TEAMPROJECT / BUILD_REPOSITORY_ID so those two can be dropped as well. Add a contract test over Bundle::ALL (auth projected for AdoRest bundles only) and a compiled-YAML churn guard asserting no bundle step re-projects an auto-injected ADO variable. Token wire form is byte-identical, so no committed lock fixture changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🔍 Rust PR ReviewSummary: Looks good — solid fix for a real bug class with clean abstraction. Two minor observations worth noting. Findings
|
Address PR review feedback: - Add CONCLUSION_PATH const in ado_script.rs and reference it from both Bundle::Conclusion.path() and the Conclusion job's shell body, so the two copies of the path cannot diverge (previously a hardcoded literal in each place, only format-checked by tests). - Document why the manual contributor's BUILD_REQUESTEDFOR / BUILD_REQUESTEDFOREMAIL identity vars are exempted from the redundant- mirror strip, in both the churn guard's RETAINED list and the is_redundant_ado_mirror doc comment. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🔍 Rust PR ReviewSummary: Looks good — clean structural fix, well-tested, and the TypeScript bundle migration is correctly coordinated. One minor doc inaccuracy in the new Findings
|
Address PR review feedback: - BundleAuth::AdoRest was inaccurate: ExecContextPr uses SYSTEM_ACCESSTOKEN for git bearer auth (bearerEnv), not the ADO REST getWebApi() path. Rename the variant to BundleAuth::Bearer and reword its doc + auth() comment + docs to describe the real invariant: "the bundle reads SYSTEM_ACCESSTOKEN (ADO REST, git bearer, or both)". - Document that apply_bundle_auth is a no-op for BundleAuth::None and ignores the token argument in that case. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🔍 Rust PR ReviewSummary: Looks good — the core fix is correct, the abstraction is well-designed, and test coverage is solid. A few minor items worth addressing before merge. Findings
|
Address third PR review: - Make is_redundant_ado_mirror #[cfg(test)] (it is genuinely test-only; the churn guard reimplements the rule inline). ALL/path() stay #[allow(dead_code)] deliberately — gating them behind cfg(test) makes the four None-auth Bundle variants (only named in ALL) trip dead_code in release builds, so keeping ALL production-compiled avoids that cascade. - Align the two fully-qualified apply_bundle_auth call sites (filter_ir gate step, agentic_pipeline conclusion job) with the `use` import pattern used by the exec_context contributors. - Extend the churn guard to also compile pr-filter-tier1-agent.md and pipeline-filter-agent.md so the filter gate.js step is covered, not just the exec-context/synth/conclusion steps. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🔍 Rust PR ReviewSummary: Looks good — clean structural fix for the auth-contract drift class. No bugs found. Findings✅ What Looks Good
|
src/compile/ado_bundle.rs was added in refactor(compile) #1315 to centralize the ado-script bundle env contract, but the AGENTS.md architecture tree was not updated. - Add ado_bundle.rs entry to the compile/ module tree with a concise description of the Bundle enum, apply_bundle_auth() chokepoint, and token_source_for() helper. - Update the docs/ado-script.md index summary to mention the bundle env contract modelled in src/compile/ado_bundle.rs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
src/compile/ado_bundle.rs was introduced in #1315 (centralize ado-script bundle env contract) but was omitted from the architecture tree in AGENTS.md. Add the entry with a description matching the module's docstring and public API (Bundle, apply_bundle_auth, token_source_for, is_redundant_ado_mirror). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…kspace layout The site's ado-script reference page still said the workspace produces 'three bundles' (gate.js, import.js, exec-context-pr.js). The actual count is now thirteen. Concretely: - Fix intro: 'three bundles' → 'thirteen bundles' with full annotated list (all exec-context-* variants, conclusion.js, approval-summary.js). - Update frontmatter description to match the broader scope. - Fix import.js section: replace the old 'no env vars / argv[2]' description with the real CLI contract (--base, --var flags); rename section heading from 'Env-var contract' to 'CLI contract'. - Update workspace layout: add the promoted shared/ modules (git.ts, merge-base.ts, validate.ts, prompt.ts, build.ts) and all nine new source directories + ten new bundle outputs. - Update release packaging paragraph to list all thirteen bundles. - Fix 'three independent features' → 'two' in AdoScriptExtension note (exec-context bundles are owned by ExecContextExtension, not AdoScriptExtension); rewrite the Agent-job subsection accordingly. - Replace the per-column 'What gets emitted, by case' table with the more accurate two-table form from docs/ado-script.md (separate synth-PR variant rows). - Fix stale module path: src/safeoutputs/*.rs → src/safe_outputs/*.rs. - Update 'See also' exec-context link to reference all contributors, not just exec-context-pr.js. All accuracy claims verified against docs/ado-script.md (updated in PR #1315) and the src/compile/ and scripts/ado-script/ sources. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
src/compile/ado_bundle.rs was introduced in #1315 (centralize ado-script bundle env contract) but was omitted from the architecture tree in AGENTS.md. Add the entry with a description matching the module's docstring and public API (Bundle, apply_bundle_auth, token_source_for, is_redundant_ado_mirror). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…kspace layout (#1332) The site's ado-script reference page still said the workspace produces 'three bundles' (gate.js, import.js, exec-context-pr.js). The actual count is now thirteen. Concretely: - Fix intro: 'three bundles' → 'thirteen bundles' with full annotated list (all exec-context-* variants, conclusion.js, approval-summary.js). - Update frontmatter description to match the broader scope. - Fix import.js section: replace the old 'no env vars / argv[2]' description with the real CLI contract (--base, --var flags); rename section heading from 'Env-var contract' to 'CLI contract'. - Update workspace layout: add the promoted shared/ modules (git.ts, merge-base.ts, validate.ts, prompt.ts, build.ts) and all nine new source directories + ten new bundle outputs. - Update release packaging paragraph to list all thirteen bundles. - Fix 'three independent features' → 'two' in AdoScriptExtension note (exec-context bundles are owned by ExecContextExtension, not AdoScriptExtension); rewrite the Agent-job subsection accordingly. - Replace the per-column 'What gets emitted, by case' table with the more accurate two-table form from docs/ado-script.md (separate synth-PR variant rows). - Fix stale module path: src/safeoutputs/*.rs → src/safe_outputs/*.rs. - Update 'See also' exec-context link to reference all contributors, not just exec-context-pr.js. All accuracy claims verified against docs/ado-script.md (updated in PR #1315) and the src/compile/ and scripts/ado-script/ sources. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Follow-up to #1311. Fixes the class of bug behind #1307: every compiler step that runs an ado-script bundle previously hand-wrote its
env:block, so the Conclusion step drifted and shipped without an ADO bearer token.Introduces
src/compile/ado_bundle.rsas the single source of truth for the bundles' env/auth contract, and (per maintainer direction) strips the redundant auto-injected env projections.The registry (
src/compile/ado_bundle.rs)Bundle— every ado-script bundle, withpath()andauth()(BundleAuth::Bearerwhen the bundle readsSYSTEM_ACCESSTOKEN(ADO REST viagetWebApi()and/or git bearer auth), elseNone).apply_bundle_auth(step, bundle, token)— the single chokepoint that projectsSYSTEM_ACCESSTOKENinto every bearer-requiring bundle step.SYSTEM_ACCESSTOKENis the one ADO predefined var that is not auto-injected, so it must be projected — the structural guarantee that no step can ship without a bearer again.token_source_for(write_sc)— unifies theSystem.AccessTokenvsSC_WRITE_TOKENselection previously duplicated between the Conclusion job and the Stage 3 executor.is_redundant_ado_mirror(key, value)— flags redundant re-projections of auto-injected predefined vars.Migration + strip
Every bundle call site (gate, synthetic-PR, the 8 exec-context contributors, conclusion, executor) now routes auth through the applier. The ~40 redundant
SYSTEM_*/BUILD_*env projections that ADO already auto-injects into every script step are removed — verified against each bundle's actualprocess.envreads that the bundles consume the auto-injected SCREAMING_SNAKE names directly.The synthetic-PR bundle read the renamed
ADO_PROJECT/ADO_REPO_ID; migrated it onto auto-injectedSYSTEM_TEAMPROJECT/BUILD_REPOSITORY_IDso those two projections could be dropped too.Retained (documented): the
SYSTEM_ACCESSTOKENbearer, the mode-dependent synth PR-id overrides (pipeline_var(AW_PR_*)), the manual contributor's identity vars behind the email-hygiene gate, and all computed inputs (GATE_SPEC,PR_SYNTH_SPEC,AW_*,PARAM_*).Tests
Bundle::ALL:apply_bundle_authprojects the token for Bearer bundles only;token_source_forselection;is_redundant_ado_mirrorcorrectness.Secret.tests/compiler_tests.rs: walks the emitted pipeline and fails if any bundle step re-projects an auto-injected ADO variable.No lock churn
The token wire form is byte-identical (
secret("System.AccessToken")and the previousado_macro(...)/secret(...)both lower to$(System.AccessToken)), and the committedtests/**/*.lock.ymlfixtures don't exercise exec-context/gate/synth — confirmed zero drift after recompiling.Validation
vitest run— 441/441.cargo build(0 warnings),cargo test(all suites green),cargo clippy --all-targets --all-features— clean.