Skip to content

ci: also relock enterprise/poetry.lock in version-bump PR workflow#3244

Merged
csmith49 merged 2 commits into
mainfrom
av/version-bump-prs-also-bump-enterprise
May 13, 2026
Merged

ci: also relock enterprise/poetry.lock in version-bump PR workflow#3244
csmith49 merged 2 commits into
mainfrom
av/version-bump-prs-also-bump-enterprise

Conversation

@aivong-openhands

@aivong-openhands aivong-openhands commented May 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • The version-bump workflow that opens `Bump SDK packages to vX.Y.Z` PRs against `OpenHands/OpenHands` only re-locks the root `poetry.lock`. The `enterprise/` folder has its own `poetry.lock` that pins `openhands-sdk`, `openhands-tools`, and `openhands-agent-server` transitively (via `openhands-ai = { path = "../", develop = true }`), and that lockfile drifts behind.
  • Concretely: PR OpenHands#14350 bumped root to 1.21.1 but left `enterprise/poetry.lock` at 1.19.1, requiring manual follow-up OpenHands#14409.
  • This change adds a step that runs `poetry lock --no-cache` inside `enterprise/` whenever `enterprise/pyproject.toml` and `enterprise/poetry.lock` exist, then stages the file in the same commit/PR.

Why `--no-cache`

The manual PR notes — and reproducing locally confirms — that without `--no-cache` Poetry reuses the stale build of the path-installed `openhands-ai` package and leaves the transitive SDK entries pinned at the previous version. `--no-cache` forces a clean resolve.

Guardrail that stays

The existing check that `enterprise/pyproject.toml` does not list `openhands-sdk/tools/agent-server` explicitly is preserved. We still want those packages to flow transitively via `openhands-ai`; we just need to re-lock so the enterprise lockfile picks up the new pins.

Test plan

  • Trigger `Create Version Bump PRs` via `workflow_dispatch` against a recent SDK version and confirm the resulting PR against `OpenHands/OpenHands` modifies `enterprise/poetry.lock` in addition to `pyproject.toml`, `poetry.lock`, and `sandbox_spec_service.py`.
  • In the resulting PR, verify `cd enterprise && poetry show openhands-sdk openhands-agent-server openhands-tools` reports the new version.
  • Confirm a rerun on the same version is idempotent (no spurious commits on the existing branch).

Agent Server images for this PR

GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server

Variants & Base Images

Variant Architectures Base Image Docs / Tags
java amd64, arm64 eclipse-temurin:17-jdk Link
python amd64, arm64 nikolaik/python-nodejs:python3.13-nodejs22-slim Link
golang amd64, arm64 golang:1.21-bookworm Link

Pull (multi-arch manifest)

# Each variant is a multi-arch manifest supporting both amd64 and arm64
docker pull ghcr.io/openhands/agent-server:7f7fb21-python

Run

docker run -it --rm \
  -p 8000:8000 \
  --name agent-server-7f7fb21-python \
  ghcr.io/openhands/agent-server:7f7fb21-python

All tags pushed for this build

ghcr.io/openhands/agent-server:7f7fb21-golang-amd64
ghcr.io/openhands/agent-server:7f7fb219644cb33273a61e1901c81379b343dc5d-golang-amd64
ghcr.io/openhands/agent-server:av-version-bump-prs-also-bump-enterprise-golang-amd64
ghcr.io/openhands/agent-server:7f7fb21-golang_tag_1.21-bookworm-amd64
ghcr.io/openhands/agent-server:7f7fb21-golang-arm64
ghcr.io/openhands/agent-server:7f7fb219644cb33273a61e1901c81379b343dc5d-golang-arm64
ghcr.io/openhands/agent-server:av-version-bump-prs-also-bump-enterprise-golang-arm64
ghcr.io/openhands/agent-server:7f7fb21-golang_tag_1.21-bookworm-arm64
ghcr.io/openhands/agent-server:7f7fb21-java-amd64
ghcr.io/openhands/agent-server:7f7fb219644cb33273a61e1901c81379b343dc5d-java-amd64
ghcr.io/openhands/agent-server:av-version-bump-prs-also-bump-enterprise-java-amd64
ghcr.io/openhands/agent-server:7f7fb21-eclipse-temurin_tag_17-jdk-amd64
ghcr.io/openhands/agent-server:7f7fb21-java-arm64
ghcr.io/openhands/agent-server:7f7fb219644cb33273a61e1901c81379b343dc5d-java-arm64
ghcr.io/openhands/agent-server:av-version-bump-prs-also-bump-enterprise-java-arm64
ghcr.io/openhands/agent-server:7f7fb21-eclipse-temurin_tag_17-jdk-arm64
ghcr.io/openhands/agent-server:7f7fb21-python-amd64
ghcr.io/openhands/agent-server:7f7fb219644cb33273a61e1901c81379b343dc5d-python-amd64
ghcr.io/openhands/agent-server:av-version-bump-prs-also-bump-enterprise-python-amd64
ghcr.io/openhands/agent-server:7f7fb21-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim-amd64
ghcr.io/openhands/agent-server:7f7fb21-python-arm64
ghcr.io/openhands/agent-server:7f7fb219644cb33273a61e1901c81379b343dc5d-python-arm64
ghcr.io/openhands/agent-server:av-version-bump-prs-also-bump-enterprise-python-arm64
ghcr.io/openhands/agent-server:7f7fb21-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim-arm64
ghcr.io/openhands/agent-server:7f7fb21-golang
ghcr.io/openhands/agent-server:7f7fb219644cb33273a61e1901c81379b343dc5d-golang
ghcr.io/openhands/agent-server:av-version-bump-prs-also-bump-enterprise-golang
ghcr.io/openhands/agent-server:7f7fb21-golang_tag_1.21-bookworm
ghcr.io/openhands/agent-server:7f7fb21-java
ghcr.io/openhands/agent-server:7f7fb219644cb33273a61e1901c81379b343dc5d-java
ghcr.io/openhands/agent-server:av-version-bump-prs-also-bump-enterprise-java
ghcr.io/openhands/agent-server:7f7fb21-eclipse-temurin_tag_17-jdk
ghcr.io/openhands/agent-server:7f7fb21-python
ghcr.io/openhands/agent-server:7f7fb219644cb33273a61e1901c81379b343dc5d-python
ghcr.io/openhands/agent-server:av-version-bump-prs-also-bump-enterprise-python
ghcr.io/openhands/agent-server:7f7fb21-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim

About Multi-Architecture Support

  • Each variant tag (e.g., 7f7fb21-python) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., 7f7fb21-python-amd64) are also available if needed

The OpenHands repo bump PR (e.g. #14350) only re-locked the root
poetry.lock, leaving enterprise/poetry.lock pinned at the previous
SDK version and requiring a manual follow-up PR (#14409). enterprise
depends on the root via `openhands-ai = { path = "../" }` and keeps
its own lockfile, so it needs `poetry lock --no-cache` run inside
the enterprise directory too. --no-cache invalidates the stale build
of the path-installed openhands-ai package; without it the transitive
SDK entries stay on the previous version.
@github-actions

github-actions Bot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Python API breakage checks — ✅ PASSED

Result:PASSED

Action log

@github-actions

github-actions Bot commented May 13, 2026

Copy link
Copy Markdown
Contributor

REST API breakage checks (OpenAPI) — ✅ PASSED

Result:PASSED

Action log

@all-hands-bot all-hands-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟢 Good taste - Clean solution that eliminates manual follow-up work

[RISK ASSESSMENT]

  • [Overall PR] ⚠️ Risk Assessment: 🟢 LOW
    Straightforward CI change with proper conditional guards. Solves a real problem (PR #14409 manual follow-up) by ensuring enterprise/poetry.lock stays in sync with root lockfile. The --no-cache flag is correctly justified to force clean resolution. Worst-case scenario is the change doesn't work as expected and requires iteration - no production impact.

VERDICT:
Worth merging: Solid fix for lockfile drift issue

KEY INSIGHT:
Using subshell (cd enterprise && ...) and conditional file checks demonstrates good defensive scripting that won't break if the enterprise directory structure changes in the target repository.

@all-hands-bot all-hands-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟡 QA Report: PARTIAL

This PR addresses a real problem and the logic appears correct, but the actual workflow execution could not be fully verified in this QA environment.

Does this PR achieve its stated goal?

Partially verified. The PR aims to prevent enterprise/poetry.lock from drifting behind the root lockfile when the version-bump workflow runs. I confirmed the problem existed (PRs #14350/#14409 prove it), the workflow logic includes all necessary steps (conditional enterprise lockfile regeneration with --no-cache, git staging, commit message updates), and the bash syntax is valid. However, I could not trigger the actual workflow to verify end-to-end behavior because that requires a workflow_dispatch event targeting OpenHands/OpenHands after a real PyPI release—constraints outside this QA environment.

Phase Result
Environment Setup ✅ Repository cloned, workflow file validated
CI Status ✅ 17 checks passing, 9 pending (build jobs), 0 failing
Functional Verification 🟡 Logic verified, end-to-end execution not possible
Functional Verification

Test 1: Confirm the Historical Problem Existed

Step 1 — Verify PR #14350 missed enterprise/poetry.lock:

Ran:

gh pr view 14350 --repo OpenHands/OpenHands --json files \
  | jq -r '.files | map(.path) | join("\n")'

Output:

openhands/app_server/sandbox/sandbox_spec_service.py
poetry.lock
pyproject.toml

Interpretation: PR #14350 (automated version bump to 1.21.1) only modified root poetry.lock and pyproject.toml. The enterprise/poetry.lock file is not in the list, confirming the workflow did not update it.

Step 2 — Verify PR #14409 was the manual fix:

Ran:

gh pr view 14409 --repo OpenHands/OpenHands --json title,body

Key excerpt from PR body:

The root poetry.lock pins the OpenHands SDK packages at 1.21.1, but enterprise/poetry.lock was still on 1.19.1. This mismatch means cd enterprise && poetry install resolves a different SDK version than the root project...

Generated with poetry lock --no-cache in enterprise/. The --no-cache was needed to invalidate a stale build of the path-installed openhands-ai package; without it, poetry update openhands-sdk openhands-agent-server openhands-tools left the entries at 1.19.1.

Interpretation: This confirms (a) the enterprise lockfile drifted to 1.19.1 while root was at 1.21.1, and (b) --no-cache is required to force Poetry to invalidate the cached build. The problem this PR solves is real and documented.


Test 2: Verify the Fix Logic is Complete

Step 1 — Check workflow adds enterprise lockfile regeneration:

Inspected the diff:

git diff origin/main...HEAD -- .github/workflows/version-bump-prs.yml

The workflow now includes:

if [ -f "enterprise/poetry.lock" ] && [ -f "enterprise/pyproject.toml" ]; then
  echo "📝 Regenerating enterprise/poetry.lock..."
  (cd enterprise && poetry lock --no-cache)
  echo "✅ Updated enterprise/poetry.lock"
fi

Correct: Uses --no-cache as documented in PR #14409.

Correct: Conditional check ensures it only runs if enterprise folder exists.

Correct: Runs in subshell (cd enterprise && ...) to avoid changing working directory.

Step 2 — Check workflow stages enterprise/poetry.lock in git:

The commit step now includes:

git add pyproject.toml poetry.lock "$SANDBOX_SPEC_FILE" "$PYPROJECT_FMT_CONFIG"
if [ -f "enterprise/poetry.lock" ]; then
  git add enterprise/poetry.lock
fi

Correct: Conditionally stages the file if it exists.

Step 3 — Check commit message mentions the file:

Commit message now includes:

- Regenerated enterprise/poetry.lock to keep transitive SDK pins aligned

Correct: Explicitly documents the change.

Step 4 — Check PR body template mentions the file:

PR body template now includes:

- Regenerated `enterprise/poetry.lock` so its transitive SDK pins match the root

Correct: Communicates the change to reviewers.

Step 5 — Verify bash syntax:

Extracted the new script logic and validated:

bash -n /tmp/test_script.sh

Result: ✅ No syntax errors.

Step 6 — Verify poetry --no-cache flag exists:

Ran:

poetry lock --help | grep -A 2 '\-\-no-cache'

Output:

--no-cache             Disables Poetry source caches.

Correct: The flag exists and matches the intended use case.


Test 3: Verify enterprise Folder Structure in Target Repo

Checked the OpenHands/OpenHands repository structure:

Ran:

cd /tmp/OpenHands-test && ls -la enterprise/ | grep -E 'poetry|pyproject'

Output:

-rw-r--r--  1 runner runner 1210603 May 13 20:50 poetry.lock
-rw-r--r--  1 runner runner    2259 May 13 20:50 pyproject.toml

✅ Both enterprise/poetry.lock and enterprise/pyproject.toml exist, so the conditional check will pass.

Checked the dependency structure:

Ran:

grep 'openhands-ai' enterprise/pyproject.toml

Output:

openhands-ai = { path = "../", develop = true }

✅ Confirms the enterprise folder depends on the root via path dependency, so transitive SDK pins flow through as described.


Summary of Verification

✅ Verified:

  • The historical problem is real (PRs #14350 and #14409)
  • The workflow logic includes all necessary steps
  • Bash syntax is valid
  • The --no-cache flag exists and is correctly used
  • The target repository structure matches expectations
  • CI checks are passing

❌ Could NOT verify:

  • Actual end-to-end workflow execution (requires workflow_dispatch on OpenHands/OpenHands)
  • Whether the locked versions resolve correctly after the fix
  • Idempotency (rerunning on the same version)
Unable to Verify

Attempts Made

Attempt 1: Trigger the workflow via GitHub API

Considered using:

gh workflow run version-bump-prs.yml --repo OpenHands/software-agent-sdk \
  --field version=1.21.1

However, this would:

  1. Require a real PyPI release to exist
  2. Create actual PRs on OpenHands/OpenHands
  3. Potentially interfere with production workflows

Outcome: Not feasible in a QA environment.

Attempt 2: Simulate the workflow locally

Considered:

  1. Manually creating a version mismatch scenario
  2. Running the poetry commands locally

However:

  1. Would require setting up the entire OpenHands/OpenHands environment
  2. Would not replicate the exact GitHub Actions context
  3. Time constraints (3-attempt rule)

Outcome: Would not provide sufficient confidence in end-to-end behavior.

What Could Not Be Verified

  1. End-to-end workflow execution — The actual creation of a PR on OpenHands/OpenHands with the enterprise lockfile updated
  2. Version resolution correctness — Whether cd enterprise && poetry show openhands-sdk reports the correct version after the workflow runs
  3. Idempotency — Whether rerunning the workflow on the same version produces no spurious commits

Suggested AGENTS.md Guidance

For future QA runs of workflow changes that target external repositories:

  1. Create a test repository that mirrors the structure of OpenHands/OpenHands (with enterprise/ folder)
  2. Modify the workflow to optionally target a test repository via workflow input
  3. Set up a staging PyPI index or mock the version check step
  4. Document the test repository setup in AGENTS.md under a "Workflow Testing" section

This would enable QA to trigger test runs without affecting production repositories.

Issues Found

None. The logic appears correct and complete based on code analysis and historical evidence.


Recommendations

  1. Manual Testing Required: Before merging, manually trigger the workflow via workflow_dispatch with a recent SDK version (e.g., 1.21.1) and verify:

    • The resulting PR includes enterprise/poetry.lock in the file list
    • Running cd enterprise && poetry show openhands-sdk openhands-agent-server openhands-tools shows the target version
    • Rerunning on the same version is idempotent
  2. Consider Adding Integration Tests: The test plan in the PR description is comprehensive but unchecked. Consider creating a test repository to validate workflow changes before they affect production.

  3. Post-Merge Validation: After the next SDK release, verify the automated PR on OpenHands/OpenHands includes the enterprise lockfile update.


Verdict: Logic is sound and addresses the documented problem. End-to-end execution should be manually verified per the test plan before merging.

@aivong-openhands aivong-openhands marked this pull request as ready for review May 13, 2026 21:01

@all-hands-bot all-hands-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟢 Good taste - Clean solution that prevents manual follow-up work

[RISK ASSESSMENT]

  • [Overall PR] ⚠️ Risk Assessment: 🟢 LOW
    Straightforward CI change with proper conditional guards. Solves a real problem (manual follow-up PR #14409) by keeping enterprise/poetry.lock in sync with root. The --no-cache flag is correctly justified to force clean resolution. Worst-case scenario is the workflow needs iteration - no production impact.

VERDICT:
Worth merging: Eliminates toil and prevents lockfile drift

KEY INSIGHT:
The conditional check + --no-cache flag combination properly handles the transitive dependency resolution through the path-installed openhands-ai package.

@all-hands-bot all-hands-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟡 QA Report: PARTIAL

This is a GitHub Actions workflow that can only be fully verified by actually triggering it on a PyPI release. I validated syntax, logic, and CI status but could not execute the workflow end-to-end due to infrastructure constraints.

Does this PR achieve its stated goal?

Partially verifiable.

The PR's goal is to fix the version-bump workflow so it also regenerates enterprise/poetry.lock when bumping SDK packages, preventing the drift that occurred in PR #14350 (which left enterprise at 1.19.1 while root went to 1.21.1, requiring manual fix PR #14409).

The changes logically address this goal:

  • Added conditional logic to run poetry lock --no-cache in enterprise/ if those files exist
  • Updated git staging to include enterprise/poetry.lock
  • Updated commit message to document the enterprise lockfile update

However, I cannot verify the workflow actually works end-to-end because:

  1. It requires triggering via PyPI release or workflow_dispatch (no permissions in QA environment)
  2. It operates on a different repository (OpenHands/OpenHands) that I don't control
  3. The workflow's behavior can only be observed by inspecting the resulting PR it creates there

The test plan in the PR description outlines what needs to be verified manually after the next SDK release.

Phase Result
Environment Setup ✅ Workflow file checked out, dependencies confirmed
CI Status ✅ All 39 checks passing
Functional Verification 🟡 Syntax validated, logic verified by inspection, cannot execute workflow
Functional Verification

Test 1: YAML Syntax Validation

Step 1 — Validate workflow file:

python3 -c "import yaml; yaml.safe_load(open('.github/workflows/version-bump-prs.yml'))"
✅ YAML syntax is valid

This confirms the workflow file is parseable and won't fail on syntax errors.

Step 2 — Validate bash script syntax:

bash -n /tmp/test_script.sh
✅ Bash syntax is valid

This confirms the added bash script logic has no syntax errors.

Test 2: Problem Context Verification

Step 1 — Examine the problem PR #14350:

curl -s -H "Authorization: token $GITHUB_TOKEN" \
  "https://api.github.com/repos/OpenHands/OpenHands/pulls/14350/files" | \
  jq -r '.[] | .filename'
openhands/app_server/sandbox/sandbox_spec_service.py
poetry.lock
pyproject.toml

This confirms PR #14350 only updated 3 files and did NOT include enterprise/poetry.lock, demonstrating the bug.

Step 2 — Examine the manual fix PR #14409:

curl -s -H "Authorization: token $GITHUB_TOKEN" \
  "https://api.github.com/repos/OpenHands/OpenHands/pulls/14409/files" | \
  jq -r '.[] | .filename'
enterprise/poetry.lock
enterprise/tests/unit/test_user_store.py

The PR description states: "The root poetry.lock pins the OpenHands SDK packages at 1.21.1, but enterprise/poetry.lock was still on 1.19.1." This confirms the manual PR was needed to fix the drift.

Step 3 — Verify the fix logic:

The PR adds this logic (lines 270-283):

if [ -f "enterprise/poetry.lock" ] && [ -f "enterprise/pyproject.toml" ]; then
  echo "📝 Regenerating enterprise/poetry.lock..."
  (cd enterprise && poetry lock --no-cache)
  echo "✅ Updated enterprise/poetry.lock"
fi

And updates git staging (lines 310-312):

if [ -f "enterprise/poetry.lock" ]; then
  git add enterprise/poetry.lock
fi

This logic should address the problem by:

  1. Checking if enterprise Poetry files exist (conditional, won't break if missing)
  2. Re-locking with --no-cache to force fresh resolve (per PR description, this is critical)
  3. Staging the updated lockfile for commit

Test 3: CI Status Check

Step 1 — Check PR CI status:

gh pr view 3244 --json statusCheckRollup
All 39 checks passing (SUCCESS)

This confirms the workflow file passes all CI validation including syntax checks, tests, and builds.

Unable to Verify

Cannot Execute Workflow End-to-End

What was attempted:

  1. Looked for ways to trigger the workflow locally or in a test environment
  2. Checked if there's a test harness for version-bump workflows
  3. Looked for poetry in the environment to test the poetry lock --no-cache command

Why it failed:

  • The workflow is triggered by PyPI releases or manual workflow_dispatch (requires repo admin permissions)
  • The workflow checks out and modifies files in OpenHands/OpenHands repository, not this repo
  • No poetry installation in QA environment, and this repo doesn't have an enterprise/ directory to test against

What could not be verified:

  1. ❌ That the workflow actually triggers and runs without errors
  2. ❌ That the resulting PR in OpenHands/OpenHands includes all 4 files (pyproject.toml, poetry.lock, enterprise/poetry.lock, sandbox_spec_service.py)
  3. ❌ That poetry lock --no-cache successfully resolves the new SDK versions in enterprise/poetry.lock
  4. ❌ That poetry show reports the correct versions after the update
  5. ❌ That rerunning the workflow on the same version is idempotent (no spurious commits)

Suggested guidance for AGENTS.md:

For QA of cross-repository automation workflows like version-bump-prs.yml:

  • These workflows can only be fully verified by manual testing during actual releases
  • The PR author's test plan (in description) outlines the manual verification steps
  • QA should focus on: syntax validation, logic inspection, CI status, and verifying the problem context
  • Full functional verification requires triggering the workflow via release or workflow_dispatch with proper permissions

Issues Found

None in the parts that could be verified. The syntax is valid, CI passes, and the logic appears sound based on inspection.

Critical caveat: The workflow's actual behavior with poetry lock --no-cache in the enterprise directory cannot be verified without executing it. The PR author's test plan must be followed manually during or after the next SDK release.

@csmith49 csmith49 merged commit dc3528c into main May 13, 2026
61 checks passed
@csmith49 csmith49 deleted the av/version-bump-prs-also-bump-enterprise branch May 13, 2026 21:20
StressTestor pushed a commit to StressTestor/software-agent-sdk that referenced this pull request Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants