feat(compile): add Node.js runtime extension with optional internal-feed config#398
Draft
Copilot wants to merge 2 commits intofeat/runtime-prompt-injectionfrom
Draft
feat(compile): add Node.js runtime extension with optional internal-feed config#398Copilot wants to merge 2 commits intofeat/runtime-prompt-injectionfrom
Copilot wants to merge 2 commits intofeat/runtime-prompt-injectionfrom
Conversation
…eed config Agent-Logs-Url: https://github.com/githubnext/ado-aw/sessions/95561fa8-831b-4585-aa32-5f91ed749208 Co-authored-by: jamesadevine <4742697+jamesadevine@users.noreply.github.com>
Agent-Logs-Url: https://github.com/githubnext/ado-aw/sessions/95561fa8-831b-4585-aa32-5f91ed749208 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:07
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.
Summary
Implements a Node.js runtime extension for the
runtimes: node:front-matter field, following the same pattern as the existing Lean 4 runtime.What it does
When
runtimes: node:is enabled in an agent's front matter, the compiler:NodeTool@0step into{{ prepare_steps }}(runs before the agent), using the sharednode_tool_step()helper introduced in feat(compile): runtime prompt injection via prompt.js bundle #395. NodeTool@0 is idempotent, so it is safe even whenprompt.jsalso emits the step.node,npm,npxto the bash command allow-list."node"ecosystem to the AWF network allowlist (expands toregistry.npmjs.org,nodejs.org, etc.).tools.bashis empty (Node.js requires bash access).With optional
internal-feedconfiguration, an additionalbashstep is injected that runsnpm config set registryto redirect npm commands to a private registry (e.g., Azure Artifacts). Whenauth-token-varis also set, the step configures the per-registry_authTokenusing a value read from a pipeline variable at runtime — it is never embedded in the compiled YAML.Usage
Files changed
src/compile/extensions/mod.rs—node_tool_step()now accepts aversion_spec: &strparameter; updated two existing callers to pass"20.x"explicitly.src/runtimes/node/mod.rs(new) —NodeRuntimeConfig,NodeOptions,NodeInternalFeedConfig,NODE_BASH_COMMANDS,generate_node_install(),generate_node_feed_config().src/runtimes/node/extension.rs(new) —NodeExtensionimplementingCompilerExtension.src/runtimes/mod.rs— addedpub mod node;.src/compile/types.rs— addednodefield toRuntimesConfig; updatedsanitize_config_fields.src/compile/extensions/mod.rs— re-exportedNodeExtension; addedNode(NodeExtension)toExtensionenum; wiredcollect_extensions.docs/runtimes.md— documentedruntimes.nodewith examples and aninternal-feedoption table.AGENTS.md— addednode/to the source tree overview.Tests
cargo build✓cargo test— 1117 + 78 + others pass; no regressionscargo clippy --all-targets --all-features— clean