Skip to content

fix: add pre-deploy validation for Python bundled mode#8624

Open
v1212 wants to merge 6 commits into
mainfrom
wujia/bundled-deploy-check
Open

fix: add pre-deploy validation for Python bundled mode#8624
v1212 wants to merge 6 commits into
mainfrom
wujia/bundled-deploy-check

Conversation

@v1212

@v1212 v1212 commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Problem

When users select "Bundled" during azd ai agent init but forget to run pip install --target . before azd deploy, the deployment succeeds but the container crashes at runtime with ModuleNotFoundError (see #8610).

Fix

  1. Post-init hint (azd ai agent init): When bundled mode is selected for a Python project with requirements.txt, print the correct platform-specific pip install example command targeting the deployment platform (Linux x86_64). Includes a note that --only-binary=:all: may need to be removed for packages lacking pre-built wheels.

  2. Pre-deploy check (azd deploy): When Python + bundled mode is configured and requirements.txt exists with content but no .dist-info directories are found in the source directory (top-level or one subdirectory deep), fail with a clear error message and remediation steps.

Changes

  • internal/cmd/init_validate.go — Added validateBundledHint() to print pip install guidance after init
  • internal/project/service_target_agent.go — Added validatePythonBundledDeps() pre-deploy check
  • internal/exterrors/codes.go — Added CodeBundledDepsNotFound error code
  • internal/cmd/init_validate_test.go — 4 new tests for the hint function
  • internal/project/service_target_agent_test.go — 6 new tests for the deploy check

Design Decisions

  • Advisory, not blocking at init: The hint is printed but does not prevent init from completing
  • Blocking at deploy: The pre-deploy check returns an error to prevent deploying a broken package
  • No false positives: Check passes if ANY .dist-info dir exists (top-level or one level deep). IO errors on ReadDir are surfaced (not silently skipped). Only os.ErrNotExist for requirements.txt is ignored.
  • Does not validate completeness: Only catches "didn't install at all", not partial installs
  • Shell-safe paths: srcDir is quoted in all user-facing commands to handle paths with spaces

Test Results

Unit tests pass (go test ./... -count=1).

Integration Tests (Windows, manual validation)

All 5 scenarios tested on Windows using extension built from this branch (bdc12a90e, 2026-06-12):

# Scenario Result Evidence
1 Python bundled init PASS NOTE hint printed with correct pip install command including --platform manylinux_2_17_x86_64 flags and quoted path
2 Python bundled deploy without deps PASS Deploy blocked at Packaging step: bundled mode is configured but no installed packages were found in the source directory
3 Python bundled deploy with deps PASS After installing packages (.dist-info present), deploy passes Packaging and proceeds to Publishing
4 Python remote_build deploy (non-regression) PASS No hint at init, no validation block at deploy — proceeds directly past Packaging without deps
5 .NET bundled init (non-regression) PASS dotnet_10 --dep-resolution bundled completes without printing the Python bundled hint

Note: Full end-to-end deploy to Azure was not tested (only validation gate behavior), as the validation fires locally before any Azure API calls.

Fixes #8610

When Python + bundled dependency resolution is selected but no packages
are installed in the source directory (no .dist-info dirs found), azd
deploy now fails with a clear error message instead of silently uploading
an incomplete ZIP that crashes at runtime.

Also prints a platform-specific pip install command after azd ai agent
init when bundled mode is selected for Python projects.

Fixes #8610

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@v1212 v1212 requested review from JeffreyCA and glharper as code owners June 12, 2026 02:38
Copilot AI review requested due to automatic review settings June 12, 2026 02:38
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown

📋 Prioritization Note

Thanks for the contribution! The linked issue isn't in the current milestone yet.
Review may take a bit longer — reach out to @rajeshkamal5050 or @kristenwomack if you'd like to discuss prioritization.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds guardrails for Python “bundled” dependency resolution in the azure.ai.agents extension so users get an actionable failure before deploy (and a post-init reminder) instead of a runtime ModuleNotFoundError.

Changes:

  • Add a deploy-time validation for Python bundled mode that checks for installed dependencies (*.dist-info) when requirements.txt is present.
  • Add a post-init note for Python bundled mode with a pip install --target . command tailored to the selected runtime.
  • Introduce a new external error code for the missing-bundled-deps scenario.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go Adds Python bundled dependency validation during code packaging and returns a typed dependency error when missing.
cli/azd/extensions/azure.ai.agents/internal/exterrors/codes.go Adds a new error code used by the bundled dependency validation failure.
cli/azd/extensions/azure.ai.agents/internal/cmd/init_validate.go Prints a post-init hint for Python bundled projects that have requirements.txt.

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/init_validate.go
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/init_validate.go Outdated
@github-actions github-actions Bot added the ext-agents azure.ai.{agents,connections,inspector,projects,routines,skills,toolboxes} extensions label Jun 12, 2026
Jian Wu and others added 4 commits June 12, 2026 10:45
- Make pip install command advisory with fallback note for packages
  lacking pre-built wheels
- Expand dist-info check to one subdirectory level (covers pip install
  to vendor/ or lib/ patterns) to prevent false positive deploy blocks

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Only ignore os.ErrNotExist for requirements.txt (surface IO errors)
- Return error when srcDir is unreadable instead of silently skipping
- Quote srcDir in shell commands for paths with spaces
- Add unit tests for validateBundledHint (4 tests)
- Add unit tests for validatePythonBundledDeps (6 tests)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use strings.SplitSeq (go fix modernization for Go 1.26)
- Handle os.WriteFile/MkdirAll errors in tests (gosec G104)
- Add 'manylinux' to cspell dictionary

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@v1212 v1212 enabled auto-merge (squash) June 12, 2026 06:55

@glharper glharper left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Python bundled mode pre-deploy validation

Overall: Solid, well-tested fix. Error handling follows the exterrors convention correctly (structured error created once, not re-wrapped), os.ErrNotExist is handled, paths are shell-quoted, and tests use a stdout-capture pipe rather than writing to real os.Stdout. One issue worth addressing before merge.

🟡 Medium — Deploy-error pip command is inconsistent with the init hint (can install wrong-ABI wheels)

The error returned by validatePythonBundledDeps (internal/project/service_target_agent.go) suggests:

pip install -r requirements.txt -t "<srcDir>" --platform manylinux_2_17_x86_64 \
  --platform linux_x86_64 --platform any --implementation cp --only-binary=:all:

But the init hint (internal/cmd/init_validate.go) deliberately includes --python-version (and --upgrade):

... --python-version 3.14 --implementation cp --only-binary=:all: --upgrade

A user who hits the deploy block and copies the suggested command will have pip resolve wheels for the local interpreter's version tag, not the Linux target's Python — which can install ABI-mismatched wheels and reproduce the very ModuleNotFoundError this PR prevents. The caller (packageCodeDeploy) already has agentDef.CodeConfiguration.Runtime available, so thread the version into validatePythonBundledDeps and add --python-version <ver> to keep both commands consistent.

🟢 Minor — Description/doc-comment slightly overstate behavior

  • The PR description says "IO errors on ReadDir are surfaced (not silently skipped)." That's true only for the top-level ReadDir. The one-level-deep scan silently continues on error. Reasonable as a best-effort choice, but the description should match.
  • The doc comment "avoids false positives" overstates the guarantee: dependencies installed more than one subdirectory deep, or a requirements.txt that only uses -r other.txt indirection, would trigger a false deploy-blocking error. The common pip install --target . case is handled correctly, so this is acceptable as a heuristic — just worth not claiming it's false-positive-free.

✅ Confirmed correct

  • .dist-info detection matches pip --target layout; the default .agentignore doesn't strip .dist-info, so validated deps land in the ZIP.
  • New CodeBundledDepsNotFound code is lowercase snake_case; manylinux added to cspell.
  • Tests don't write to real stdout; the error-code test properly asserts the new code.

Recommendation: Add --python-version to the deploy-error suggestion so it matches the init hint; everything else looks good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ext-agents azure.ai.{agents,connections,inspector,projects,routines,skills,toolboxes} extensions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

azd ai agent packaging the binaries for source code deployment when using local build

4 participants