fix(python-sdk): chmod CLI binary at build time instead of runtime#3179
fix(python-sdk): chmod CLI binary at build time instead of runtime#3179mattConnHarbour wants to merge 1 commit intomainfrom
Conversation
Fixes Docker issue where root installs but non-root user runs. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
hey @mattConnHarbour! good call moving chmod out of runtime, kills two failure modes at once :)
three things, only the middle one has teeth.
packages/sdk/langs/python/platforms/superdoc-sdk-cli-darwin-arm64/setup.py:3
os is imported but never used. same in the other three Unix setup.py files.
-import os
import stat
from pathlib import Pathpackages/sdk/langs/python/superdoc/embedded_cli.py:106
repro:
PKG=packages/sdk/langs/python/platforms/superdoc-sdk-cli-darwin-arm64
chmod 0644 $PKG/superdoc_sdk_cli_darwin_arm64/bin/superdoc
pip install -e $PKG
python -c "from superdoc.embedded_cli import resolve_embedded_cli_path; import subprocess; subprocess.run([resolve_embedded_cli_path()])"
# PermissionError: [Errno 13]editable installs skip the build hook, so they see the source binary as-is. normal flow is fine because stage-python-companion-cli.mjs:106 chmods to 0755 first - but that chmod sits in a try/except marked "runtime will surface execution errors" (lines 107-109). the runtime chmod you just removed was that surfacing. tighten the staging chmod to fail loudly, or update that comment?
packages/sdk/langs/python/platforms/superdoc-sdk-cli-darwin-arm64/setup.py:16
# After files are copied to build dir, chmod the binary just restates the next four lines. drop it, or swap for the why. same in the other three Unix setup.py files.
(posted as one comment because GitHub's review-comment API kept returning 422 "internal error" on inline anchors for this PR.)
andrii-harbour
left a comment
There was a problem hiding this comment.
This PR is about shipping packages to customers. If it doesn't work - no matter how good our code is - nobody would know that.
2 very important things :
- The follow-up item mentioned in the description, imo, should be done here. It is directly related to what we are trying to fix.
- This setup must be tested manually on a separate CI/CD pipeline to ensure that the build is correct.
| # After files are copied to build dir, chmod the binary | ||
| if self.build_lib: | ||
| binary_path = Path(self.build_lib) / 'superdoc_sdk_cli_darwin_arm64' / 'bin' / 'superdoc' | ||
| if binary_path.exists(): |
There was a problem hiding this comment.
if the path doesn't exist it will just fail silently.
| @@ -10,15 +10,15 @@ | |||
|
|
|||
There was a problem hiding this comment.
The four Unix setup.py files are byte-identical except for one string (the module name); the Windows one is a stub. Five files, one logical thing.
Duplication like this is fine in a code-only PR — a small surface, easy to revisit. This PR is infrastructure: wheel builds ship binaries to every consumer, and we're literally fixing a wheel-build bug right now. The next permission edge case will be fixed in one file and forgotten in the other three, and we'll ship asymmetric wheels.
Generate from python-embedded-cli-targets.mjs (already the source of truth), or extract a shared _build_helpers.py so each setup.py is a one-line shim. Worth doing in this PR — the duplication exists because of this change, and "we'll unify it later" is how five copies become eight.
Problem
CLI binary shipped without execute permissions (Python wheels strip them). In Docker: root installs, non-root user tries to exec, and is denied. Runtime
os.chmod()fails for the same reason—non-root can't chmod a root-owned file.Fix
Add
setup.pybuild hooks that chmod the binary during wheel creation. Binary ships with execute permissions baked in, no runtime chmod needed.Follow-up
Platform packages are nearly identical—could be generated from
python-embedded-cli-targets.mjsinstead of maintained manually.