WIP: feat(docker): move a pinned image to a newer version #5

Closed
thisilike wants to merge 1 commit from feat/docker-pinned-versions into feat/docker-jobs-and-status
Owner

Last of four; stacked on #4.

A pinned tag cannot be updated by pulling — nginx:1.25 is nginx:1.25 forever — so the module reported "up to date" for images with years of releases behind them.

  • tags.ts parses versions and offers what exists at each component, scoped by OPSDECK_MOD_DOCKER_UPGRADE_SCOPE (patch by default, because applying one rewrites a file).
  • The pin route rewrites the one line and commits just that line. The file is the operators and may hold work in progress, so git commit <file> is not an option — it commits the working tree copy and would sweep their edits in. commit.ts applies a one-hunk patch to the index instead, serialised per repository, and declines with a reason if the index is already dirty.

Ordered to fail safely: validate the tag against the registry first, keep the original text in hand, prove the edited file still parses before anything is started, put the original back if it does not.

This is why the containers write permission now covers the host mount, which docs/security.md states rather than leaving implied.

Verified in the rig end to end: chooser → apply → compose rewrite → chore(heavy): python:3.12-slim -> python:3.13-slim committed with a clean work tree → pull → recreate → the container runs the new image.

Last of four; stacked on #4. A pinned tag cannot be updated by pulling — `nginx:1.25` is `nginx:1.25` forever — so the module reported "up to date" for images with years of releases behind them. - `tags.ts` parses versions and offers what exists at each component, scoped by `OPSDECK_MOD_DOCKER_UPGRADE_SCOPE` (patch by default, because applying one rewrites a file). - The pin route rewrites the one line and commits **just** that line. The file is the operators and may hold work in progress, so `git commit <file>` is not an option — it commits the working tree copy and would sweep their edits in. `commit.ts` applies a one-hunk patch to the index instead, serialised per repository, and declines with a reason if the index is already dirty. Ordered to fail safely: validate the tag against the registry first, keep the original text in hand, prove the edited file still parses before anything is started, put the original back if it does not. This is why the containers write permission now covers the host mount, which docs/security.md states rather than leaving implied. Verified in the rig end to end: chooser → apply → compose rewrite → `chore(heavy): python:3.12-slim -> python:3.13-slim` committed with a clean work tree → pull → recreate → the container runs the new image.
A pinned tag cannot be updated by pulling — `nginx:1.25` is `nginx:1.25`
forever — so the module reported "up to date" for images with years of
releases behind them. Answering "is there a newer version" means reading the
registry's tag list, and applying the answer means editing the operator's
compose file.

Both halves are here:

- `tags.ts` parses versions and offers what exists at each component, scoped
  by OPSDECK_MOD_DOCKER_UPGRADE_SCOPE (patch by default, because applying one
  rewrites a file). `updates.ts` lists tags once per repository, paginated,
  and only for images whose tag looks like a version at all.
- The pin route rewrites the one line and commits just that line. The file is
  the operator's and may hold work in progress, so `git commit <file>` is not
  an option: it commits the working tree copy and would sweep their edits in.
  `commit.ts` applies a one-hunk patch to the index instead, serialised per
  repository, and declines with a reason if the index is already dirty.

The route is ordered to fail safely: validate the tag against the registry
first, keep the original text in hand, prove the edited file still parses
before anything is started, and put the original back if it does not. The
chooser is per image rather than one button — a database may be worth a patch
and nothing more while a sidecar can take the major — and its rules live in
`pin_model.ts`, where they can be tested without clicking.

This is why the container's write permission now covers the host mount, which
docs/security.md states rather than leaving implied.
thisilike changed title from feat(docker): move a pinned image to a newer version to WIP: feat(docker): move a pinned image to a newer version 2026-08-09 19:03:42 +02:00
thisilike closed this pull request 2026-08-09 23:01:41 +02:00

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
OpsDeck/core!5
No description provided.