Skip to content

Slot rotation corrupts self-referential paths and immutable build trees (current-slot rotation) #769

Description

@kojiromike

Summary

The current-slot rotation (e.g. 8.0.0 → 8.1.0, surfaced in PR #760) rewrites the contents of the previous current's docker build tree by blind version-string substitution. This corrupts paths that are not version pins. The visible symptom is a ShellCheck CI failure; the underlying modeling error also mangles the 8.0.0 Dockerfile clone branch, build-800.yml, and the dependabot directory entry.

Symptom

ShellCheck on PR #760 fails:

Not following: docker/openemr/8.1.0/env.stub: openBinaryFile: does not exist (No such file or directory)
ShellCheck: docker/openemr/8.0.0/openemr.sh#L24

The rotator rewrote the self-referential directive inside docker/openemr/8.0.0/openemr.sh (and ssl.sh):

- # shellcheck source=docker/openemr/8.0.0/env.stub
+ # shellcheck source=docker/openemr/8.1.0/env.stub

But the file is still physically at docker/openemr/8.0.0/, and only 8.0.0/env.stub and 7.0.4/env.stub exist — there is no 8.1.0/env.stub.

Root cause

SlotRotator (tools/release/src/SlotRotator.php) rotates by pure string substitution: for the current slot it builds the pair "8.0.0" → "8.1.0" (from both full and docker_dir) and rewrites every matching token in the files the registry lists for that slot (SlotRotator.php:118-164).

versions.yml registers the 8.0.0 init scripts as current-slot pins:

# tools/release/versions.yml:125-134
- 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]

Two conceptual errors:

  1. A # shellcheck source= comment is not a version pin. It's a path that tracks the script's own directory. Slot rotation does not move that directory — 8.0.0/, 8.1.0/, and 8.1.1/ coexist as immutable per-version build trees. Substituting the version token into a self-referential path points it at a directory that was never meant to change (and here doesn't exist).

  2. The previous current's build tree is immutable history. Once 8.0.0 is tagged and shipped, its build files shouldn't be rewritten in place when the current pointer advances. The registry comment at versions.yml:125-134 half-acknowledges the fragility ("Only the 8.0.0/*.sh files currently have these refs").

Other files mangled by the same substitution in PR #760

These are arguably worse than the ShellCheck noise:

  • docker/openemr/8.0.0/Dockerfile: git clone --branch rel-800rel-810 — the 8.0.0 build tree would now clone 8.1.0 source.
  • .github/workflows/build-800.yml: renamed to "8.1.0" and context: repointed to docker/openemr/8.1.0, while the file is still build-800.yml and still carries the legacy :8.0.0.3 tags.
  • .github/dependabot.yml: the /docker/openemr/8.0.0 directory entry rewritten to /docker/openemr/8.1.0.

What rotation should do

Advancing current to 8.1.0 means pointing the :latest/current Docker build at the already-existing 8.1.0 tree — flipping build-workflow targets, tags, and dependabot entries — not rewriting the 8.0.0 tree's contents. Registering 8.0.0's own build files (shellcheck_source, docker_clone_branch) as current pins is the core mistake.

Suggested direction (for discussion)

  • Stop treating shellcheck_source self-referential paths as rotating pins — they track file location, not slot version. Either drop them from the registry or have the rotator skip path-self-references.
  • Reconsider whether the previous current's docker tree should be edited at all on rotation, vs. repointing build/tag/dependabot pointers at the next tree.
  • Add a rotator guard/test: after rotation, any # shellcheck source=<path> must resolve to an existing file.

Surfaced in #760.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugdockerphpPull requests that update php code

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions