skip to content

Your Gatekeeper mutator must add ALL to every container's dropped capabilities — Assign or ModifySet?

level: middleimportance: should knowfreq 50%

answer

  1. whole value versus set membership
  2. Assign replaces, it does not append
  3. merge adds, prune removes
  4. a set has no ordering

basics

~20 s

ModifySet. Assign writes the whole value at the location, so it would replace whatever drop list the author already had. ModifySet treats the list as a set and merges the new member in, leaving the existing entries alone.

solid answer

~40 s

`Assign` is a whole-value write: point it at a list and the list becomes exactly the value you supplied, discarding anything the author put there. `ModifySet` exists for the other case. It takes the same `applyTo`, `match` and `location`, plus `parameters.operation` of `merge` or `prune` and `parameters.values.fromList`. With `merge`, each value in the list is added if it is not already a member; with `prune`, each is removed if present. So a mutator adding `ALL` to `spec.containers[name:*].securityContext.capabilities.drop` uses `merge`, and a team that already dropped two specific capabilities keeps them. Because it is set semantics you get no control over ordering, which is why ModifySet suits capability names and does not suit a container's `args`, where position changes meaning.

code

yaml · 15 lines
yaml
apiVersion: mutations.gatekeeper.sh/v1
kind: ModifySet
metadata:
  name: drop-all-capabilities
spec:
  applyTo:
    - groups: [""]
      versions: ["v1"]
      kinds: ["Pod"]
  location: "spec.containers[name:*].securityContext.capabilities.drop"
  parameters:
    operation: merge
    values:
      fromList:
        - ALL

go deeper

for a junior

Remember the one-line difference: Assign sets the value, ModifySet changes which members a list contains. Knowing that merge adds and prune removes covers most of what is asked here.

for a middle

Be ready to explain why Assign on a list is destructive and to write the ModifySet spec — operation plus values.fromList — from memory for a concrete field.

for a senior

Show the review instinct: spot an Assign pointing at a list in a pull request and ask whether the platform really means to own that field, and reason about ordered lists where set semantics do not apply.

for a principal

Frame it as ownership. Decide which fields the platform declares itself the sole author of and which it only contributes a member to, and make that split legible to teams rather than discovered field by field.

## Whole value versus set member The two mutators differ in one dimension only: what the write does to what is already there. - **`Assign`** replaces the value at `location` with `parameters.assign.value`. On a scalar that is obviously what you want. On a list it means the platform now owns that field outright — every entry the author wrote is gone. - **`ModifySet`** treats the value at `location` as a **set** and changes its membership. `parameters.operation: merge` adds each value in `parameters.values.fromList` that is not already present; `parameters.operation: prune` removes each one that is. ## Why the capability case wants merge Adding `ALL` to a container's dropped capabilities is exactly a membership change. A team may already drop specific capabilities deliberately, and a `merge` respects that: their entries stay, `ALL` joins them. An `Assign` on the same path would silently reduce their list to the single value you supplied — a change they did not make, did not see, and will only discover when something behaves differently. That the result is arguably still safe is beside the point; the mutator destroyed information it had no reason to touch. The mirror case is `prune`. If a rule needs to strip a value out of a list — a capability that should never be added back, a flag that must not appear — `prune` removes just that member and leaves the rest of the list intact. ## Set semantics have consequences Three of them matter in interviews: 1. **Idempotent membership.** Merging a value that is already present is a no-op. Re-running the same mutator does not accumulate duplicates. 2. **No ordering guarantee.** A set has no positions. You cannot say "put this first", which rules ModifySet out for ordered lists — a container's `args` are interpreted positionally, and merging a flag in without control over where it lands is not a safe operation. 3. **Scalars, in practice.** ModifySet is used for lists of simple values — capability names, string flags. It is not the tool for adding a structured object such as a whole container or volume to a list. ## Choosing between them Ask who owns the field. | Intent | Mutator | |---|---| | The platform owns this field entirely; author input is irrelevant | `Assign` | | The platform requires this member to be present, alongside whatever else | `ModifySet` with `merge` | | The platform requires this member to be absent | `ModifySet` with `prune` | | Set a default only when the author was silent | `Assign` with a `MustNotExist` pathTest | The last row is worth keeping distinct from the second: a pathTest gates on whether the *field* exists, while `merge` gates on whether the *member* exists. On a list field they answer different questions, and picking the wrong one produces a rule that works on empty objects and misbehaves on populated ones. ## What goes wrong in review The defect to look for in a pull request is an `Assign` whose location ends at a list. It is not always wrong — sometimes the platform genuinely owns the whole list — but it should always be deliberate and called out, because the destructive behaviour is invisible in the YAML. The rule reads like "make sure this value is in the list" and behaves like "make the list be this value".

  • What does parameters.operation: prune do?
    It removes each value listed in `parameters.values.fromList` from the target list, if present, and leaves every other member alone. It is how you strip a specific capability or flag out of workloads without owning the whole field.
  • When is using Assign on a list actually the right call?
    When the platform genuinely owns the field and author input carries no meaning — the value should be exactly this, regardless of what was submitted. Make that intent explicit in review, because the YAML reads the same as an additive rule while behaving destructively.
  • Would you use ModifySet to add a flag to a container's args?
    No. `args` is positional and ModifySet treats the list as an unordered set, so you cannot control where the value lands. Merging a flag into an ordered argument list is how you get a container that starts with a subtly different command line than anyone intended.

saying these in an interview costs you the question

  • Uses Assign on a list and wipes existing entries
  • Thinks ModifySet appends at a chosen position
  • Expects merge to duplicate an existing member
  • Reaches for ModifySet to add a whole container object

context