From d31d75e8ce84c1d4253812f9f9817e2c24e0da06 Mon Sep 17 00:00:00 2001 From: Tobias Kaupat Date: Wed, 21 Oct 2026 00:07:07 +0200 Subject: [PATCH] fix: set script modes in the image independent of the build umask COPY --chmod=755 for backup.sh, check.sh and entry.sh. Restore the exact -rwxr-xr-x checks in tests/structure.yml and drop the umask workaround in tests/sabotage.py. Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 3 +++ Dockerfile | 6 +++--- tests/sabotage.py | 4 ---- tests/structure.yml | 6 +++--- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb022ca..43a2e8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ * Test suites in `tests/` (compat, features, structure) that run the image as a real container, plus a `Test` GitHub Actions workflow running them on every pull request. The suites are written in Python (pytest) and run via `mise install` and `task test`; `task test:sabotage` proves they detect a broken backup * `.gitattributes` pinning shell scripts, the Dockerfile and YAML files to LF line endings. With a Windows checkout (`core.autocrlf=true`) the scripts were checked out with CRLF, which made the built image fail to start with `exec /entry.sh: no such file or directory` +### Changed +* The Dockerfile now sets the mode of `backup`, `check` and `entry.sh` itself (`COPY --chmod=755`), so the image no longer depends on the build host's umask or on the exec bit of the checked-out scripts. Building now needs BuildKit (default since Docker 23) + ### Removed * `config-broken.yml` and `docker-compose.test.broken.yml`, replaced by `tests/structure.yml` and the test workflow diff --git a/Dockerfile b/Dockerfile index 55a4b79..a7971e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -60,9 +60,9 @@ RUN mkdir /.cache && \ # /data is the dir where you have to put the data to be backed up VOLUME /data -COPY backup.sh /bin/backup -COPY check.sh /bin/check -COPY entry.sh /entry.sh +COPY --chmod=755 backup.sh /bin/backup +COPY --chmod=755 check.sh /bin/check +COPY --chmod=755 entry.sh /entry.sh ENTRYPOINT ["/entry.sh"] CMD ["tail","-fn0","/var/log/cron.log"] diff --git a/tests/sabotage.py b/tests/sabotage.py index 9d17637..3a9c272 100644 --- a/tests/sabotage.py +++ b/tests/sabotage.py @@ -54,10 +54,6 @@ def sabotage_tree(tmp: Path) -> None: if patched == lines: raise Invalid("sabotage patch did not apply, backup.sh changed shape") script.write_text("".join(patched)) - # Dockerfile COPY has no chmod: the image only works when the file is executable. - script.chmod(script.stat().st_mode | 0o111) - if not os.access(script, os.X_OK): - raise Invalid("sabotaged backup.sh is not executable") def red_tests(report: Path) -> tuple[set[str], set[str]]: diff --git a/tests/structure.yml b/tests/structure.yml index bb13b1c..7ebd244 100644 --- a/tests/structure.yml +++ b/tests/structure.yml @@ -34,15 +34,15 @@ fileExistenceTests: - name: 'backup script' path: '/bin/backup' shouldExist: true - isExecutableBy: 'other' + permissions: '-rwxr-xr-x' - name: 'check script' path: '/bin/check' shouldExist: true - isExecutableBy: 'other' + permissions: '-rwxr-xr-x' - name: 'entrypoint' path: '/entry.sh' shouldExist: true - isExecutableBy: 'other' + permissions: '-rwxr-xr-x' - name: 'default repository mount point' path: '/mnt/restic' shouldExist: true