Skip to content

fix(planstate): leave the plan unchanged when an appended layer fails validation - #937

Merged
hpidcock merged 2 commits into
canonical:masterfrom
lenamonj:planstate-append-rollback
Oct 20, 2026
Merged

hpidcock merged 2 commits into
canonical:masterfrom
lenamonj:planstate-append-rollback

Conversation

@lenamonj

@lenamonj lenamonj commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

A pebble add --inner whose layer parses but fails plan validation leaves the daemon's live layer list changed.

appendLayer inserted with slices.Insert(m.plan.Layers, ...). When the slice has spare capacity, slices.Insert shifts the existing elements in place, so the new layer was spliced into m.plan.Layers before updatePlanLayers validated the result; when validation failed, that mutation stayed. CombineLayer already copies before mutating.

Insert into slices.Clone(m.plan.Layers) instead. The success path is unchanged: same index, same Order, same returned plan.

The regression test appends five layers with the sub-directory layer first, so the insert index is not the end and the slice has spare capacity, then appends a layer that fails validation. On master it fails with the layer list read as [foo/one foo/two bbb ccc ddd].

go test -race ./..., go build ./cmd/pebble, gofmt, staticcheck pass.

… validation

appendLayer inserted with slices.Insert on m.plan.Layers itself. When the slice has spare capacity the insert shifts elements in place, so a layer that then failed plan validation was already spliced into the live layer list and stayed there. Insert into a clone; the success path is unchanged.
@hpidcock

Copy link
Copy Markdown
Member

@chapman-von-monty review this PR.

@chapman-von-monty

Copy link
Copy Markdown
Contributor

Understood. Reviewing PR #937 against Pebble's standards and test suites.

@chapman-von-monty

Copy link
Copy Markdown
Contributor

I reviewed the change and found no issues. Cloning the layer slice before slices.Insert fixes the in-place shift when the original slice has spare capacity, so a validation failure cannot alter m.plan.Layers. On success, updatePlanLayers installs the newly constructed plan (including the cloned-and-inserted layer slice), and the existing order assignment remains unchanged. CombineLayer already replaces an element in a separately allocated slice and only assigns m.plan after validation succeeds, so this fix does not leave a comparable mutation path there.

The regression test is meaningful: it creates a non-terminal sub-directory insertion with spare-capacity conditions, verifies both layer labels and combined services after rejection, then verifies a later append does not resurrect or lose state. It follows the package gocheck conventions and uses the dot import.

I ran:

  • PEBBLE_TEST_USER=ubuntu PEBBLE_TEST_GROUP=ubuntu go test -v ./internals/overlord/planstate/...
  • PEBBLE_TEST_USER=ubuntu PEBBLE_TEST_GROUP=ubuntu go test ./...
  • git diff --check

All passed. This is good to merge from my review.

@hpidcock
hpidcock enabled auto-merge (squash) October 20, 2026 11:22
@hpidcock
hpidcock merged commit 3a741f6 into canonical:master Oct 20, 2026
22 checks passed
@lenamonj
lenamonj deleted the planstate-append-rollback branch October 20, 2026 11:49
@chapman-von-monty

Copy link
Copy Markdown
Contributor

@hpidcock I checked the latest PR state and head. PR #937 is now merged (head 6e4da50, including the merge from current master), with no new discussion requiring action. The diff remains as previously reviewed: cloning before slices.Insert prevents failed validation from mutating the live layer slice, while successful updates and CombineLayer remain correct. The regression test still covers the spare-capacity insertion case and follows the package gocheck conventions.

I reran against the latest head:

  • PEBBLE_TEST_USER=ubuntu PEBBLE_TEST_GROUP=ubuntu go test -v ./internals/overlord/planstate/... — passed (11 tests)
  • PEBBLE_TEST_USER=ubuntu PEBBLE_TEST_GROUP=ubuntu go test ./... — passed
  • git diff --check — passed

No further issues found; the merged change is good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants