skip to content

A build context included a signing key and a broad copy instruction swept it into the image — what is the real fix?

level: middleimportance: must knowfreq 51%

answer

  1. a copy can only take what crossed
  2. instruction fix is per-instruction
  3. the context root is the chokepoint
  4. packaged is exposed, even if uncopied
  5. verify the set, not the rules file

basics

~20 s

Keep the file out of the set that is sent. A copy instruction can only take files that were packaged, so ignore rules at the context root close the hole for every instruction and every future one; narrowing that single copy only closes it once.

solid answer

~50 s

There are two levers here and they are not equivalent. Narrowing the copy instruction to name only what the image needs fixes *this* instruction: it is a good change and it is also the one a future edit quietly undoes when someone adds a broad copy back. Excluding the key with **ignore rules at the context root** means the file is never packaged at all, so no instruction — present or future — can take it, because it is not there to take. That is the durable fix, and it is reviewable: it is a file next to the code rather than a detail of one instruction. Do both, but understand which one is the boundary. Best of all, the key should not live in the tree the build is pointed at in the first place; ignore rules are the guard for the files you cannot move out.

go deeper

for a junior

Recall the direction: an instruction can only copy files that were already sent to the builder, so the first question about any leaked file is why it was in the context at all.

for a middle

Contrast the two fixes and say which is the boundary — a narrowed copy fixes one instruction, ignore rules at the context root mean no instruction can take the file because it was never packaged.

for a senior

Separate reaching the image from reaching the builder, and say how you would verify the exclusion by inspecting what was actually packaged rather than by re-reading the rules file.

for a principal

Treat the context root as a trust boundary your organisation sets deliberately: what may be under a path any build is pointed at, and what is guarded by rules everyone inherits rather than by each author's care.

## Why the set is the boundary and the instruction is not Work the sequence backwards. The instruction copied the key, so the key was in the bundle the builder received. It was in the bundle because it was under the path the build was pointed at and no ignore rule matched it. That is the causal chain, and it has an obvious property: **the copy instruction could only ever take files that were sent in the first place.** That makes the packaged set the chokepoint. Compare the two candidate fixes honestly: | fix | what it prevents | how it fails | |---|---|---| | narrow the copy instruction to name what the image needs | this instruction taking the key | a later edit adds a broad copy back, and the key is still sitting there to be taken | | exclude the key with ignore rules at the context root | any instruction taking it, now or later, because it was never packaged | a rule that mis-anchors or never matched does nothing, silently | | keep the key out of the tree entirely | the file being reachable by any build pointed anywhere in that tree | someone needs it locally and puts it back | The honest answer in an interview names all three and says which is the boundary: the set. The instruction fix is per-instruction and per-author; the set fix is per-context and applies to everyone who builds from that root. ## What was actually exposed, and to whom It is worth separating two different exposures, because candidates collapse them: 1. **The key reached the image.** Anyone who can pull that image has it. This is the loud problem and the one that triggers the incident. 2. **The key reached the builder.** That happened the moment it was packaged, *whether or not any instruction copied it.* If the thing performing the build is a shared service, a remote host or a pool of machines, the file crossed a trust boundary before step one and may persist wherever that builder keeps what it receives. So "no instruction copied it, therefore it is fine" is a weaker statement than it sounds. It means the file is not in the image; it does not mean the file never left. That second exposure is precisely why the fix belongs at the set, not at the instruction — trimming the context is the only one of the three levers that addresses both. ## The shape of the mistake The broad copy is not a strange thing to write. It is the natural first instruction: take the project and put it in the image. It is also what makes the size of the context equal to the size of what an image can accidentally contain. So the same working tree that made the build slow makes it leaky, and both symptoms have one cure: **decide deliberately what crosses.** What tends to be in a real tree that should never cross: - credentials of any kind — signing keys, tokens, service credentials, personal configuration that happens to hold one; - fixture and sample data drawn from real records; - prior exports and reports generated from real data; - version-control metadata, which carries historical versions of files that were later removed from the checkout; - local environment files that were never meant to leave the machine. ## Verifying the fix Writing the rule is not the same as the rule working, and this is the step most people skip. Two checks: - **Check the set, not the rules file.** Have the builder report what it packaged and confirm the path is absent. A rule with a typo, or one anchored differently than you assumed, produces a rules file that reads correctly and changes nothing. - **Check every build path into the same tree.** If a second invocation points at a different root, the rules file that sits at the first root is not necessarily the one in force. The rules are a property of the context root, not of the repository. ## The part that is not this question One thing to be careful about in the interview: once a credential has been written into a shipped image, what it takes to make it safe again is a separate discussion with its own mechanics — and it is not "remove the file in a later step". Here the subject is upstream of that: which files crossed, who decided, and how to make the decision deliberate so that the later discussion never has to happen.

  • The key was packaged but no instruction copied it. Is that safe?
    It is not in the image, which is the main thing — but the file still crossed to whatever performed the build. If that is a shared or remote builder, it may retain what it received. "Not copied" is a statement about the image, not about where the bytes went.
  • Why not just rely on scanning the finished image for credentials?
    Scanning is a useful backstop and a poor boundary: it finds what it recognises, after the fact, and only for the patterns it knows. Keeping the file out of the packaged set prevents the class rather than detecting instances of it, and it costs nothing at build time.
  • Which files should never be in a build context even when no instruction would copy them?
    Credentials, data drawn from real records, exports and reports generated from it, local environment files, and version-control metadata — the last because it carries historical versions of files that were deleted from the checkout, so removing a secret from the working tree does not remove it from the history the walk would package.

saying these in an interview costs you the question

  • Narrowing that one copy instruction closes the hole for good.
  • The file only exists once an instruction copies it into the image.
  • A file that no instruction copies never leaves the developer's machine.
  • Scanning the finished image is enough; the context does not matter.
  • Writing the ignore rule proves the file was excluded from the set.