← Back to issue list

bash gets built with a /bin/bash that is missing the executable bit

View original Github issue

Metadata

Project
snapcraft
Number
#5114
Type
issue
State
open
Author
basak
Labels
—
Created
Updated
Closed
—

Current evaluation

Staging bash+quilt in a classic core24 snap produces a non-executable bin/bash: craft-parts' normalize.py _try_copy_local uses shutil.copyfile, which drops file modes. Confirmed root cause, no fix landed.

Suggested action: keep open

Reason: Reproducible with a minimal snapcraft.yaml, and @lengau traced it precisely to craft_parts/packages/normalize.py#L148-L157, which I verified still calls shutil.copyfile() — content-only, so the 0755 mode of /usr/bin/bash is lost (the sibling `elif path.exists(): _fix_filemode(path)` branch is skipped for symlinks, so nothing repairs it). The fix is a one-line switch to shutil.copy2/copystat plus an existing snapcraft spread test asserting the mode. Inactivity is expected because the defect lives in craft-parts, not snapcraft; that is a cross-repo ownership reason for the silence, not evidence the bug is obsolete. Kept open rather than closed because nothing in the source shows resolution.

Evaluated by: mr-cal-bot

Impact: 45 Quick Win: 33 Complexity: 15 Confidence: 88 Actionability: 85

Issue body

### Bug Description If I stage the `bash` and `quilt` packages in a part in a classic snap, then the snap gets built with a `bin/bash` file that is not executable. Subsequent attempts to use it fail. ### To Reproduce On a fresh Noble VM: ``` sudo snap install --classic snapcraft # installs 8.4.3 (12823) mkdir -p demo/snap cat > demo/snap/snapcraft.yaml <<EOT name: demo version: 1 summary: demo description: demo confinement: classic grade: devel base: core24 apps: demo: command: usr/bin/bash parts: demo: build-attributes: [enable-patchelf] plugin: nil stage-packages: [bash, quilt] EOT cd demo snapcraft build --destructive-mode ``` Expected result: `parts/demo/install/bin/bash` is executable, and this passes through to the final snap (if you continue you should also see it in `prime/bin/bash` as executable, etc). Actual result: `parts/demo/install/bin/bash` is not executable and this passes through to the final snap. Then scripts that try to use it fail. ### Environment Ubuntu 24.04 cloud image, snapcraft in destructive mode. Snapcraft snap 8.4.3 (12823). ### snapcraft.yaml ```yaml name: demo version: 1 summary: demo description: demo confinement: classic grade: devel base: core24 apps: demo: command: usr/bin/bash parts: demo: build-attributes: [enable-patchelf] plugin: nil stage-packages: [bash, quilt] ``` ### Relevant log output ```shell 2024-10-13 13:12:26.879 Building demo 2024-10-13 13:12:26.893 execute action demo:Action(part_name='demo', step=Step.BUILD, action_type=ActionType.RUN, reason=None, project_vars=None, properties=ActionProperties(changed_files=None, changed_dirs=None)) 2024-10-13 13:12:26.894 load state file: /home/ubuntu/demo/parts/demo/state/pull 2024-10-13 13:12:28.158 fix artifacts: unpack_dir='/home/ubuntu/demo/parts/demo/install' 2024-10-13 13:12:28.175 fix symlink: path='/home/ubuntu/demo/parts/demo/install/usr/share/quilt/compat/bash', unpack_dir='/home/ubuntu/demo/parts/demo/install', root='/home/ubuntu/demo/parts/demo/install/usr/share/quilt/compat' 2024-10-13 13:12:28.207 fix symlink: target='/home/ubuntu/demo/parts/demo/install/bin/bash' 2024-10-13 13:12:28.207 Copying needed target link from the system: /usr/bin/bash 2024-10-13 13:12:30.039 remove directory /home/ubuntu/demo/parts/demo/build 2024-10-13 13:12:30.041 Executing PosixPath('/home/ubuntu/demo/parts/demo/run/build.sh') ``` ### Additional context The trace output suggests that snapcraft is doing something because `usr/share/quilt/compat/bash` is a symlink. If I drop `quilt` from `stage-packages`, then `bin/bash` isn't created. I found this when trying to move the git-ubuntu snap to core24. That's complex enough so I came up with a minimal reproducer. Workaround: I did this: ``` override-stage: | craftctl default chmod 755 bin/bash ```

Evaluation history

Date Model Scores Action Summary
stealth/space-bunny-alpha
Impact: 45
Quick Win: 33
Complexity: 15
Confidence: 88
Actionability: 85
keep open Staging bash+quilt in a classic core24 snap produces a non-executable bin/bash: craft-parts' normalize.py _try_copy_local uses shutil.copyfile, which drops file modes. Confirmed root cause, no fix landed.
stealth/space-bunny-alpha
Impact: 38
Quick Win: 14
Complexity: 42
Confidence: 78
Actionability: 62
keep open Staging quilt alongside bash yields a non-executable bin/bash: craft-parts' _try_copy_local uses shutil.copyfile, dropping file modes. Maintainers pinpointed normalize.py; workaround is override-stage chmod. Unfixed.
stealth/space-bunny-alpha
Impact: 45
Quick Win: 23
Complexity: 35
Confidence: 80
Actionability: 78
keep open Staging bash+quilt in a classic core24 snap yields a non-executable bin/bash (lost mode when craft-parts copies the symlink target); maintainers traced it to craft_parts/packages/normalize.py, still unresolved
qwen/qwen3.6-35b-a3b
Impact: 70
Quick Win: 39
Complexity: 30
Confidence: 85
Actionability: 80
keep open bash staged via craft-parts loses executable bit when quilt's absolute symlink is resolved, due to shutil.copyfile not preserving permissions
qwen/qwen3.8-27b
Impact: 45
Quick Win: 32
Staleness: 70
Complexity: 30
Confidence: 70
Support Request: 10
keep open Staging bash+quilt in a classic snap yields a non-executable bin/bash because craft-parts normalize copies the symlink target from the system via shutil.copyfile, dropping the executable bit. Unfixed in craft-parts; reporter has a chmod workaround.
qwen/qwen3.6-35b-a3b
Staleness: 88
Complexity: 55
Confidence: 75
Support Request: 10
close stale Staging bash and quilt in a classic snap causes /bin/bash to lose its executable bit due to craft-parts symlink normalization. The issue has been inactive for over a year with a provided workaround but no fix.
qwen3.6-35b-a3b-mtp-q6
Staleness: 95
Complexity: 45
Confidence: 85
Support Request: 15
close stale Staging bash and quilt in a classic snap causes bin/bash to lose its executable bit. Currently inactive for over 630 days with a workaround available.

Update history

No update history recorded yet.

Related work

  • Blocked By: canonical/craft-parts (confidence 90%)

    The defect is in craft_parts/packages/normalize.py::_try_copy_local, not snapcraft; fixing it requires an upstream craft-parts change (shutil.copyfile -> copy2/copystat). @lengau and @mr-cal/@cmatsuoka were already pinged about it.

Related issues

No related issues found above the similarity threshold.