Fix the scan for secrets left in image layers

Review the AI's codeEasy10 min

Your task

An assistant's Dockerfile wrote an npm token to ~/.npmrc in one RUN step and deleted it in a later one. The image builds, but the token is still in it. Each step saves its changes as a layer, a snapshot that later steps cannot change, so the file is still readable from the earlier layer. The team now replays each Dockerfile to list the secrets anyone can recover from the shipped image.

An assistant wrote recoverable_secret_paths(instructions). It is in the editor. It has a bug. Find it and fix it.

Input and output:

  • instructions: the build steps in order, one string each, with fields separated by |. The first field is the operation. The list can be empty.
  • Return the paths of secret files that the shipped image still holds, as a list of strings with no repeats, sorted in ascending order.

Rules the tests check:

  • stage|<name> is a new FROM. Only the last stage ships, so forget every path tracked so far. Any instruction whose first field is stage does this, whatever follows it.
  • write|<path>|<secret> is a RUN that writes a file into a layer. If the secret field is not empty, the path holds a secret: track it.
  • copy|<path>|<secret> is a COPY --from an earlier stage. It also writes the file into a new layer of the current stage, so it follows the same rule as write.
  • For write and copy, ignore the instruction unless it splits on | into exactly 3 fields and both the path and the secret are non-empty.
  • rm|<path> deletes a file from the final view only. The layer that wrote it still ships, so rm changes nothing.
  • mount|<path>|<secret> is a secret mount (RUN --mount=type=secret). The file exists only during that step and is never saved to a layer, so it changes nothing.
  • Ignore any other operation. Operations and paths are case sensitive.

Examples

recoverable_secret_paths(instructions: list[str]) -> list[str]
Example 1
Inputrecoverable_secret_paths(["write|/root/.npmrc|NPM_TOKEN", "rm|/root/.npmrc"])
Output["/root/.npmrc"]
Example 2
Inputrecoverable_secret_paths(["mount|/root/.npmrc|NPM_TOKEN"])
Output[]
Example 3
Inputrecoverable_secret_paths(["write|/root/.npmrc|NPM_TOKEN", "stage|runtime", "copy|/app/dist|"])
Output[]