From 2c9b80569cece5d3cd574a997a8fab3ff30fa53c Mon Sep 17 00:00:00 2001 From: "Michael A. Smith" Date: Mon, 1 Jun 2026 13:50:57 -0400 Subject: [PATCH 1/3] fix(release): stop slot rotation corrupting self-referential shellcheck paths (#769) The env.stub shellcheck directive in the 8.0.0 init scripts used a repo-relative path carrying a version token, so rotating the current slot rewrote it to a sibling dir that never exists, breaking shellcheck CI on the auto rotation PR (#760). Switch the directive to the version-agnostic SCRIPTDIR form (matching the existing convention) and drop the now-tokenless *.sh entries from the rotation registry. A SlotRotator regression test locks in that SCRIPTDIR directives survive rotation byte-for-byte. --- docker/openemr/8.0.0/openemr.sh | 2 +- docker/openemr/8.0.0/ssl.sh | 2 +- tools/release/tests/SlotRotatorTest.php | 42 +++++++++++++++++++++++++ tools/release/versions.yml | 11 ------- 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/docker/openemr/8.0.0/openemr.sh b/docker/openemr/8.0.0/openemr.sh index b2aa7138..9829ca99 100644 --- a/docker/openemr/8.0.0/openemr.sh +++ b/docker/openemr/8.0.0/openemr.sh @@ -20,7 +20,7 @@ set -e # source-follower without ever running it — BusyBox ash treats `.` as a # special builtin and exits the shell on file-not-found even with `|| true`. if false; then - # shellcheck source=docker/openemr/8.0.0/env.stub + # shellcheck source=SCRIPTDIR/env.stub . /root/env.stub fi diff --git a/docker/openemr/8.0.0/ssl.sh b/docker/openemr/8.0.0/ssl.sh index 30c97299..e3843b16 100644 --- a/docker/openemr/8.0.0/ssl.sh +++ b/docker/openemr/8.0.0/ssl.sh @@ -16,7 +16,7 @@ set -e # source-follower without ever running it — BusyBox ash treats `.` as a # special builtin and exits the shell on file-not-found even with `|| true`. if false; then - # shellcheck source=docker/openemr/8.0.0/env.stub + # shellcheck source=SCRIPTDIR/env.stub . /root/env.stub fi diff --git a/tools/release/tests/SlotRotatorTest.php b/tools/release/tests/SlotRotatorTest.php index 1ddcb21a..57e4d058 100644 --- a/tools/release/tests/SlotRotatorTest.php +++ b/tools/release/tests/SlotRotatorTest.php @@ -195,6 +195,37 @@ public function testReplacementAvoidsPartialVersionMatches(): void self::assertStringContainsString('rel-820', $after); } + public function testRotationLeavesScriptdirShellcheckDirectiveIntact(): void + { + $rotator = new SlotRotator($this->tmpDir, $this->registryPath); + + $rotator->rotate([ + 'current' => [ + 'minor' => '8.2', + 'full' => '8.2.0', + 'branch' => 'rel-820', + 'docker_dir' => '8.2.0', + ], + ]); + + $script = (string) file_get_contents($this->tmpDir . '/docker/openemr/8.0.0/openemr.sh'); + self::assertStringContainsString( + '# shellcheck source=SCRIPTDIR/env.stub', + $script, + 'self-referential SCRIPTDIR directive must survive rotation byte-for-byte', + ); + self::assertStringNotContainsString( + 'source=docker/openemr', + $script, + 'rotation must never inject a version path into a shellcheck source directive', + ); + self::assertStringContainsString( + "echo 'init for docker/openemr/8.2.0'", + $script, + 'sanity: the genuine rotating docker_dir token should have been rewritten', + ); + } + private function seedFixtures(): void { $this->writeFile('tools/release/versions.yml', <<<'YAML' @@ -230,6 +261,9 @@ private function seedFixtures(): void - path: docker/openemr/8.0.0/Dockerfile slot: current kinds: [docker_clone_branch] + - path: docker/openemr/8.0.0/openemr.sh + slot: current + kinds: [docker_dir_ref] - path: docker/openemr/8.1.0/Dockerfile slot: next kinds: [docker_arg_branch] @@ -256,6 +290,14 @@ private function seedFixtures(): void $this->writeFile('docker/openemr/8.1.0/Dockerfile', "FROM alpine:3.21\nARG OPENEMR_VERSION=rel-810\n"); $this->writeFile('docker/openemr/8.1.1/Dockerfile', "FROM alpine:3.21\nARG OPENEMR_VERSION=master\n"); + // In-container init script for the current slot. It carries a rotating + // docker_dir token (the comment path) alongside a self-referential + // `SCRIPTDIR` shellcheck directive that must never be rewritten. + $this->writeFile( + 'docker/openemr/8.0.0/openemr.sh', + "#!/bin/sh\nset -e\n# shellcheck source=SCRIPTDIR/env.stub\n. /root/env.stub\necho 'init for docker/openemr/8.0.0'\n", + ); + $this->writeFile( 'docker/openemr/OVERVIEW.md', "| 8.0.0 | latest |\n| 8.1.0 | next |\n| 8.1.1 | dev |\n", diff --git a/tools/release/versions.yml b/tools/release/versions.yml index 67030411..bff5101e 100644 --- a/tools/release/versions.yml +++ b/tools/release/versions.yml @@ -122,17 +122,6 @@ files: slot: all kinds: [dependabot_directory] - # In-container init scripts; reference their own dir as shellcheck source - # comments, so they rotate with the slot's docker_dir. Only the 8.0.0/*.sh - # files currently have these refs; the next/dev variants have no path - # comments and will be picked up by the linter only if added later. - - path: docker/openemr/8.0.0/openemr.sh - slot: current - kinds: [shellcheck_source] - - path: docker/openemr/8.0.0/ssl.sh - slot: current - kinds: [shellcheck_source] - # Container-benchmarking docs reference the next-slot version as defaults. - path: utilities/container_benchmarking/README.md slot: next From 4a4794fe3819675f77c2d33def1d170343b8b386 Mon Sep 17 00:00:00 2001 From: "Michael A. Smith" Date: Mon, 1 Jun 2026 13:59:26 -0400 Subject: [PATCH 2/3] style(release): wrap long fixture line in SlotRotator test (phpcs) --- tools/release/tests/SlotRotatorTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/release/tests/SlotRotatorTest.php b/tools/release/tests/SlotRotatorTest.php index 57e4d058..c0054992 100644 --- a/tools/release/tests/SlotRotatorTest.php +++ b/tools/release/tests/SlotRotatorTest.php @@ -295,7 +295,9 @@ private function seedFixtures(): void // `SCRIPTDIR` shellcheck directive that must never be rewritten. $this->writeFile( 'docker/openemr/8.0.0/openemr.sh', - "#!/bin/sh\nset -e\n# shellcheck source=SCRIPTDIR/env.stub\n. /root/env.stub\necho 'init for docker/openemr/8.0.0'\n", + "#!/bin/sh\nset -e\n" + . "# shellcheck source=SCRIPTDIR/env.stub\n. /root/env.stub\n" + . "echo 'init for docker/openemr/8.0.0'\n", ); $this->writeFile( From 6844d9bec9299f82b00a6b9a261f5efdd0dbaa93 Mon Sep 17 00:00:00 2001 From: "Michael A. Smith" Date: Mon, 1 Jun 2026 14:07:03 -0400 Subject: [PATCH 3/3] docs(release): correct fixture comment on rotating token location --- tools/release/tests/SlotRotatorTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/release/tests/SlotRotatorTest.php b/tools/release/tests/SlotRotatorTest.php index c0054992..485a1eb9 100644 --- a/tools/release/tests/SlotRotatorTest.php +++ b/tools/release/tests/SlotRotatorTest.php @@ -291,8 +291,9 @@ private function seedFixtures(): void $this->writeFile('docker/openemr/8.1.1/Dockerfile', "FROM alpine:3.21\nARG OPENEMR_VERSION=master\n"); // In-container init script for the current slot. It carries a rotating - // docker_dir token (the comment path) alongside a self-referential - // `SCRIPTDIR` shellcheck directive that must never be rewritten. + // docker_dir token (the path in the echo line) alongside a + // self-referential `SCRIPTDIR` shellcheck directive that must never be + // rewritten. $this->writeFile( 'docker/openemr/8.0.0/openemr.sh', "#!/bin/sh\nset -e\n"