feat(runtimes): add Python runtime extension with UsePythonVersion@0 and internal feed support#399
Draft
feat(runtimes): add Python runtime extension with UsePythonVersion@0 and internal feed support#399
Conversation
…and internal feed support Agent-Logs-Url: https://github.com/githubnext/ado-aw/sessions/c1dc19f4-a62e-4e64-8add-7e292dcf7e0b Co-authored-by: jamesadevine <4742697+jamesadevine@users.noreply.github.com>
…ation and escaping docs Agent-Logs-Url: https://github.com/githubnext/ado-aw/sessions/c1dc19f4-a62e-4e64-8add-7e292dcf7e0b Co-authored-by: jamesadevine <4742697+jamesadevine@users.noreply.github.com>
Copilot created this pull request from a session on behalf of
jamesadevine
May 5, 2026 08:13
View session
jamesadevine
added a commit
that referenced
this pull request
May 5, 2026
* feat(runtimes): add unified Node.js and Python runtime extensions Add Python and Node.js runtimes with consistent architecture matching the existing Lean runtime pattern: - Python: UsePythonVersion@0, PipAuthenticate@1, PIP_INDEX_URL/UV_DEFAULT_INDEX env vars - Node.js: NodeTool@0 (inline, decoupled from ado-script), npmAuthenticate@0, NPM_CONFIG_REGISTRY env var - Both use flat feed-url: field with env var injection via agent_env_vars() - Both accept config: field (recognized but errors if used, reserved for AWF proxy-auth) - Shared validate_feed_url() in validate.rs for injection checks - agent_env_vars() trait method on CompilerExtension with BLOCKED_ENV_KEYS validation - No AWF mounts/PATH prepends needed (hostedtoolcache auto-mounted by AWF) Unifies the approaches from PRs #398 and #399 into a single consistent implementation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(runtimes): ensure .npmrc exists before npmAuthenticate@0 npmAuthenticate@0 requires workingFile to point at an existing file, unlike PipAuthenticate@1. Emit a bash step that creates a minimal .npmrc (with the configured registry or default npmjs) when one does not already exist, preserving any repo-checked-in .npmrc. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(runtimes): fix dead-code validation ordering, accept node config with warning - Python: swap mutual-exclusivity check before not-yet-supported error so both paths are reachable - Node: accept config: with a warning that .npmrc won't be available inside AWF yet (instead of hard error), check mutual exclusivity first - Add tests for mutual-exclusivity errors on both runtimes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(runtimes): reject double-quote in feed URLs and agent env var values A double-quote in a feed-url or extension env var value would produce malformed YAML in the generated pipeline (the value is emitted as KEY: "value"). Reject at validation time in both validate_feed_url() and collect_agent_env_vars() with clear error messages. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(runtimes): Python config: produces warning instead of error Align with Node.js behavior — accept config: with a warning that the config file will not be available inside the AWF agent environment yet, rather than a hard compile error. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(runtimes): make auth tasks conditional on feed-url or config PipAuthenticate@1 and npmAuthenticate@0 (plus ensure-npmrc) are now only emitted when feed-url: or config: is set. Users who enable runtimes: python: true or runtimes: node: true without an internal feed no longer get unnecessary auth steps in their pipeline. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(runtimes): reject single-quote in feed URLs, fix doc comments, soften uv prompt Three fixes: 1. validate_feed_url() now rejects single-quote characters alongside double-quotes — a single quote in the feed URL would break the bash single-quoted string in generate_ensure_npmrc's echo command. 2. Doc comments on generate_pip_authenticate() and generate_npm_authenticate() corrected to say "emitted when feed-url or config is set" instead of "emitted unconditionally", matching the actual conditional behavior in prepare_steps(). 3. Python prompt supplement no longer claims uv is "pre-installed" — ADO hosted runners don't ship uv. Now says "install it first with pip install uv" to avoid command-not-found errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(runtimes): harden env var collection, fix docs and bash quoting Security & correctness fixes: 1. collect_agent_env_vars now calls reject_pipeline_injection (covers ADO expressions, pipeline commands, template markers, newlines) instead of only contains_pipeline_command. Also rejects single quotes alongside double quotes. 2. collect_agent_env_vars now deduplicates env var keys — bails on collision instead of silently emitting duplicate YAML keys. 3. generate_ensure_npmrc diagnostic echo lines switched from double-quotes to single-quotes, preventing ${VAR} shell expansion if a feed URL contained that pattern. 4. docs/runtimes.md corrected: auth tasks are conditional on feed-url or config being set, not unconditional. Config field descriptions updated to reflect warning-not-error behavior. Added note about PipAuthenticate@1 empty artifactFeeds limitation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(runtimes): PipAuthenticate requires feed-url, not config alone PipAuthenticate@1 with empty artifactFeeds doesn't authenticate to any specific feed. Only emit it when feed-url is set — config alone is not sufficient since the config file won't be available in AWF yet anyway. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a Python runtime extension (
runtimes: python:) that installs Python via theUsePythonVersion@0ADO task and optionally redirectspip/uvto internal package feeds by injecting env vars into the AWF agent sandbox.Changes
New: Python runtime (
src/runtimes/python/)PythonRuntimeConfig— acceptstrue(simple enablement) or object withversion,index-url,extra-index-urlPythonExtension— implementsCompilerExtension:UsePythonVersion@0task step intoprepare_stepswhenversion:is setpython,python3,pip,pip3to bash allow-listpythonecosystem identifier to AWF domain allowlist (expands to PyPI domains)PIP_INDEX_URL+UV_DEFAULT_INDEX(fromindex-url:) andPIP_EXTRA_INDEX_URL(fromextra-index-url:) into the agentenv:blockNew:
agent_env_vars()extension hookagent_env_vars() -> Vec<(String, String)>toCompilerExtensiontrait — lets any extension contribute env vars to the AWF agent step'senv:blockcollect_agent_env_vars()incompile_shared()collects, deduplicates (first-wins), and YAML-formats these into the engine env blockFront matter example
Validation
Feed URLs are validated against: ADO expression injection (
$(,${{), pipeline commands (##vso[), template markers ({{), newlines, and ASCII control characters.Test plan
cargo test— all existing tests pass; new tests added forPythonExtensionbehavior (prepare steps, agent env vars, validation) andcollect_agent_env_vars(deduplication, YAML escaping).