ci: also relock enterprise/poetry.lock in version-bump PR workflow#3244
Conversation
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.
Python API breakage checks — ✅ PASSEDResult: ✅ PASSED |
REST API breakage checks (OpenAPI) — ✅ PASSEDResult: ✅ PASSED |
all-hands-bot
left a comment
There was a problem hiding this comment.
🟢 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-cacheflag 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
left a comment
There was a problem hiding this comment.
🟡 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,bodyKey excerpt from PR body:
The root
poetry.lockpins the OpenHands SDK packages at 1.21.1, butenterprise/poetry.lockwas still on 1.19.1. This mismatch meanscd enterprise && poetry installresolves a different SDK version than the root project...Generated with
poetry lock --no-cacheinenterprise/. The--no-cachewas needed to invalidate a stale build of the path-installedopenhands-aipackage; without it,poetry update openhands-sdk openhands-agent-server openhands-toolsleft 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.ymlThe 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.shResult: ✅ 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.tomlOutput:
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-cacheflag 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_dispatchon 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.1However, this would:
- Require a real PyPI release to exist
- Create actual PRs on
OpenHands/OpenHands - Potentially interfere with production workflows
Outcome: Not feasible in a QA environment.
Attempt 2: Simulate the workflow locally
Considered:
- Manually creating a version mismatch scenario
- Running the poetry commands locally
However:
- Would require setting up the entire OpenHands/OpenHands environment
- Would not replicate the exact GitHub Actions context
- Time constraints (3-attempt rule)
Outcome: Would not provide sufficient confidence in end-to-end behavior.
What Could Not Be Verified
- End-to-end workflow execution — The actual creation of a PR on
OpenHands/OpenHandswith the enterprise lockfile updated - Version resolution correctness — Whether
cd enterprise && poetry show openhands-sdkreports the correct version after the workflow runs - 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:
- Create a test repository that mirrors the structure of
OpenHands/OpenHands(withenterprise/folder) - Modify the workflow to optionally target a test repository via workflow input
- Set up a staging PyPI index or mock the version check step
- Document the test repository setup in
AGENTS.mdunder 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
-
Manual Testing Required: Before merging, manually trigger the workflow via
workflow_dispatchwith a recent SDK version (e.g., 1.21.1) and verify:- The resulting PR includes
enterprise/poetry.lockin the file list - Running
cd enterprise && poetry show openhands-sdk openhands-agent-server openhands-toolsshows the target version - Rerunning on the same version is idempotent
- The resulting PR includes
-
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.
-
Post-Merge Validation: After the next SDK release, verify the automated PR on
OpenHands/OpenHandsincludes 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.
all-hands-bot
left a comment
There was a problem hiding this comment.
🟢 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-cacheflag 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
left a comment
There was a problem hiding this comment.
🟡 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-cacheinenterprise/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:
- It requires triggering via PyPI release or workflow_dispatch (no permissions in QA environment)
- It operates on a different repository (OpenHands/OpenHands) that I don't control
- 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"
fiAnd updates git staging (lines 310-312):
if [ -f "enterprise/poetry.lock" ]; then
git add enterprise/poetry.lock
fiThis logic should address the problem by:
- Checking if enterprise Poetry files exist (conditional, won't break if missing)
- Re-locking with
--no-cacheto force fresh resolve (per PR description, this is critical) - Staging the updated lockfile for commit
Test 3: CI Status Check
Step 1 — Check PR CI status:
gh pr view 3244 --json statusCheckRollupAll 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:
- Looked for ways to trigger the workflow locally or in a test environment
- Checked if there's a test harness for version-bump workflows
- Looked for poetry in the environment to test the
poetry lock --no-cachecommand
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:
- ❌ That the workflow actually triggers and runs without errors
- ❌ That the resulting PR in OpenHands/OpenHands includes all 4 files (pyproject.toml, poetry.lock, enterprise/poetry.lock, sandbox_spec_service.py)
- ❌ That
poetry lock --no-cachesuccessfully resolves the new SDK versions in enterprise/poetry.lock - ❌ That
poetry showreports the correct versions after the update - ❌ 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.
Summary
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
Agent Server images for this PR
• GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server
Variants & Base Images
eclipse-temurin:17-jdknikolaik/python-nodejs:python3.13-nodejs22-slimgolang:1.21-bookwormPull (multi-arch manifest)
# Each variant is a multi-arch manifest supporting both amd64 and arm64 docker pull ghcr.io/openhands/agent-server:7f7fb21-pythonRun
All tags pushed for this build
About Multi-Architecture Support
7f7fb21-python) is a multi-arch manifest supporting both amd64 and arm647f7fb21-python-amd64) are also available if needed