Repository navigation
fix(compile): keep package-feed credentials out of the AWF sandbox - #2310
jamesadevine wants to merge 1 commit into
Conversation
Azure Pipelines package-authenticate tasks export their credential as non-secret job variables (or an agent-visible .npmrc), which AWF --env-all forwarded to the agent. Stop emitting them in AWF jobs, reject them in pre-AWF operator steps, and exclude the static credential keys. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7b0ab0d4-23f4-4a89-90ea-3c40758ea550
|
Azure Pipelines: Successfully started running 1 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
/review |
|
✅ Rust Code Quality Reviewer completed the Rust code quality review.
|
There was a problem hiding this comment.
Security review: no regressions found
This diff is security-positive — it closes a real credential-leak class rather than weakening anything. Summary of what I checked:
awf_exclude_keysnow always includesPACKAGE_CREDENTIAL_ENV_KEYS(VSS_NUGET_ACCESSTOKEN,VSS_NUGET_EXTERNAL_FEED_ENDPOINTS,PIP_EXTRA_INDEX_URL,CARGO_REGISTRY_TOKEN) and is wired into both the Agent and Detection AWF invocations (agentic_pipeline.rs:351,354), matching the new--exclude-envdefense-in-depth claim.NuGetAuthenticate@1is removed from the Agent/Detection jobs (which run AWF with--env-all) and correctly retained only in non-AWF jobs (SafeOutputs/Conclusion/custom jobs), verified by the newtest_supply_chain_feed_never_authenticates_in_awf_jobstest which explicitly asserts both outcomes.npmAuthenticate@0/PipAuthenticate@1/the ensure-.npmrc/nuget.config-auth steps are removed from the Python/Node/.NET runtime extensions, replaced withfeed-url/configemitting only source-selection (no-credential) config plus an explicit compile warning (unauthenticated_feed_warning).- New
validate_no_package_authenticate_before_awfcloses the same hole for operator-authoredsteps:andsafe-outputs.threat-detection.steps, correctly scoped to only the pre-AWF windows (setup:/post-steps:/teardown:remain unaffected, confirmed by the paired test). - Docs (
docs/runtimes.md,docs/ado-proxy-design.md,docs/supply-chain.md) accurately reflect the new behavior and the consequences for authenticated feeds.
I traced every removed/added call site of feed_auth_step, nuget_authenticate_step, and install_and_download_steps_typed across the Agent/Detection/SafeOutputs/Conclusion job builders — behavior is consistent with the stated intent in each case. cargo build is clean. No further action needed from me.
🔒 Security review by PR Security Reviewer · auto · 68.3 AIC · ⌖ 2.02 AIC · ⊞ 11.4K
Comment /review to run again
There was a problem hiding this comment.
Reviewed the package-feed credential isolation changes against the compiler-contract checklist:
- Front-matter grammar — no field renames/removals in
types.rs; doc-comment-only edits plusdocs/front-matter.md/docs/runtimes.mdupdated in lockstep. No codemod needed. - Typed IR / tasks —
nuget_authenticate_stepvisibility narrowedpub(crate) -> privatewith its only remaining caller (feed_auth_step) in the same module; no external callers broken (verified via grep). - Shell scripts — the removed
ENSURE_NPMRCshell_script!registration is cleanly deleted along with its only caller and itsbash_lint_tests.rsrequired-display-name entry; no orphaned registry entries. - New validator (
validate_no_package_authenticate_before_awf) is wired intovalidate_pipeline_front_matterand covered by a unit test exercising all 4 listed tasks acrosssteps,safe-outputs.threat-detection.steps, and the three unaffected locations (setup,post-steps,teardown). - Docs —
docs/ado-proxy-design.md,docs/runtimes.md(new Package-feed credentials section),docs/supply-chain.md, anddocs/front-matter.mdall updated consistently with the code change. - Tests — ran the full targeted suite plus
cargo test --bin ado-aw(3408 passed),cargo test --test compiler_tests(244 passed), andcargo test --test bash_lint_tests(2 passed). All green.
No drift between the Rust source, generated behavior, and documentation found. Nothing merge-blocking from a compiler-contract perspective.
Warning
Firewall blocked 2 domains
The following domains were blocked by the firewall during workflow execution:
releaseassets.githubusercontent.comspsprodeus21.vssps.visualstudio.com
To allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "releaseassets.githubusercontent.com"
- "spsprodeus21.vssps.visualstudio.com"See Network Configuration for more information.
🏗️ Compiler contract review by Compiler Contract Reviewer · auto · 100.5 AIC · ⌖ 2.54 AIC · ⊞ 12.5K
Comment /review to run again
There was a problem hiding this comment.
Rust review: no merge-blocking issues found
Note: the rust-critic sub-agent failed to start (model access error: gpt-5.4-mini not accessible via /chat/completions), so this review reflects my own pass only.
Scope checked: src/compile/agentic_pipeline.rs, src/compile/common.rs, src/compile/extensions/ado_script.rs, src/compile/types.rs, src/runtimes/{dotnet,node,python}/{mod,extension}.rs, src/runtimes/mod.rs, tests/bash_lint_tests.rs, tests/compiler_tests.rs.
Verified:
cargo check --bin ado-aw— clean, no warnings (confirms no dead code/unused imports afternuget_authenticate_stepvisibility tightened to private and the npm/pip auth-step helpers were deleted).cargo test --bin ado-aw runtimes::— 28/28 pass.- New validator tests (
package_authenticate_tasks_are_rejected_only_before_awf,package_credential_keys_are_always_excluded_from_both_awf_runs) pass.
Quality observations (none rise to merge-blocking):
validate_no_package_authenticate_before_awfandPACKAGE_CREDENTIAL_ENV_KEYS/PACKAGE_AUTHENTICATE_TASKSconstants are well-documented with clear rationale comments explaining the credential-leak mechanism.- Task-name matching (
package_authenticate_task) correctly strips the@versionsuffix and does case-insensitive comparison — handles thenpmauthenticate@0lowercase test case correctly. - The three runtime extensions (
dotnet/node/python) apply the same warning pattern consistently via the sharedunauthenticated_feed_warninghelper — good DRY. - Test coverage is thorough: covers the allowed locations (
setup,post-steps,teardown) staying unaffected, and the rejected locations (steps,threat-detection.steps) for every listed task.
No panics, lossy casts, ordering/determinism issues, or weakened error handling introduced by this diff. The change is a surgical, well-tested removal of credential-leaking tasks from AWF-sandboxed jobs.
🦀 Rust code quality review by Rust Code Quality Reviewer · auto · 107.2 AIC · ⌖ 13.6 AIC · ⊞ 11.2K
Comment /review to run again
There was a problem hiding this comment.
Test coverage for this credential-isolation fix is strong: the common.rs validator has proper positive (setup/post-steps/teardown allowed) and negative (rejected in steps/threat-detection.steps) paths, the awf_exclude_keys tests assert exact key sets rather than just emptiness/non-emptiness, and the runtime extension tests (node/python/dotnet) were correctly flipped from "task present" to "task absent + warning present" assertions rather than just deleted. The new test_supply_chain_feed_never_authenticates_in_awf_jobs integration test also confirms the asymmetry is preserved: Agent/Detection never get NuGetAuthenticate@1 while SafeOutputs still does, and the existing per-job hoisting test (auth_count vs download_count) still exercises the kept code path. One minor gap noted inline.
🧪 Test quality analysis by Test Quality Sentinel · auto · 113.3 AIC · ⌖ 2.21 AIC · ⊞ 11K
Comment /review to run again
Summary
Package-feed credentials currently reach the AWF agent sandbox. Azure
Pipelines'
NuGetAuthenticate,PipAuthenticate, andCargoAuthenticatetasks must export their credentials as non-secret job variables so their
client tools can read them. These variables include
VSS_NUGET_ACCESSTOKENand a
https://build:<token>@…value inPIP_EXTRA_INDEX_URL.npmAuthenticateappends_authToken=<token>to its working.npmrc. AzurePipelines injects non-secret variables into every later step's environment,
and both AWF runs use
--env-all. That exposed the job's build-identity tokento the agent in these cases:
supply-chain.feedpipeline:NuGetAuthenticate@1ran in theAgent and Detection jobs, including the shared ado-script download path.
DownloadPackage@1does not need it; it authenticates itself throughSYSTEMVSSCONNECTION.runtimes.python,runtimes.node, andruntimes.dotnetwithfeed-urlorconfig:PipAuthenticate@1,npmAuthenticate@0writing tothe workspace
.npmrc, andNuGetAuthenticate@1all ran before AWF in theAgent job.
steps:orsafe-outputs.threat-detection.stepsusing any*Authenticatepackage task: these steps also ran before AWF.This PR:
NuGetAuthenticate@1from the Agent and Detection jobs and from theshared ado-script feed download. Non-AWF jobs, such as SafeOutputs and custom
safe-output jobs, still emit it;
PipAuthenticate@1,npmAuthenticate@0with its ensure-.npmrcstep, and
NuGetAuthenticate@1from the runtime extensions.feed-urlstillselects the source (
PIP_INDEX_URL,UV_DEFAULT_INDEX,NPM_CONFIG_REGISTRY, or the generatednuget.config), and the compilerwarns that the agent has no feed credential;
NuGetAuthenticate,npmAuthenticate,PipAuthenticate,TwineAuthenticate,CargoAuthenticate, andMavenAuthenticateinsteps:andsafe-outputs.threat-detection.steps;setup:,post-steps:,and
teardown:are unaffected;--exclude-envforVSS_NUGET_ACCESSTOKEN,VSS_NUGET_EXTERNAL_FEED_ENDPOINTS,PIP_EXTRA_INDEX_URL, andCARGO_REGISTRY_TOKENto both AWF runs as defense in depth.Behaviour change: authenticated private-feed restores from inside the
agent no longer work. They previously worked only by giving the agent the
credential. Credential-isolated feed access through the
ado-proxyis plannedas a follow-up.
Evidence from the task sources:
NuGetAuthenticateV1:credentialProviderUtils.ts:173-174,210(
setVariable(..., false)).PipAuthenticateV1:pipauthenticatemain.ts:94,100andutilities.ts:33-34.NpmAuthenticateV0:npmauthutils.ts:209.CargoAuthenticateV0:cargoauthenticatemain.ts:179-182.DownloadPackageV1:connections.ts:8-24andlocationUtilities.ts:122-128.Test plan
cargo build: passed.cargo test --no-fail-fast: passed, with 3721 passed, 0 failed, and 2ignored. New coverage:
test_supply_chain_feed_never_authenticates_in_awf_jobsverifies thatAgent and Detection have no
NuGetAuthenticate@1and excludeVSS_NUGET_ACCESSTOKEN, while SafeOutputs keeps the task.package_authenticate_tasks_are_rejected_only_before_awfverifies theoperator-step guard.
package_credential_keys_are_always_excluded_from_both_awf_runsverifiesthe exclusions.
feed-urlemits noauthenticate task or workspace
.npmrc.cargo clippy --all-targets: passed with no diagnostics.ENFORCE_BASH_LINT=1 cargo test --bin ado-aw compile::shell: passed.ENFORCE_BASH_LINT=1 cargo test --test bash_lint_tests: passed.git diff --check: only CR-at-EOL is reported on threeREADME.mdruntimetable rows; they preserve the CRLF endings that section already uses.