Fix the scan for secrets left in image layers
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 newFROM. Only the last stage ships, so forget every path tracked so far. Any instruction whose first field isstagedoes this, whatever follows it.write|<path>|<secret>is aRUNthat writes a file into a layer. If the secret field is not empty, the path holds a secret: track it.copy|<path>|<secret>is aCOPY --froman earlier stage. It also writes the file into a new layer of the current stage, so it follows the same rule aswrite.- For
writeandcopy, 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, sormchanges 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
Input
recoverable_secret_paths(["write|/root/.npmrc|NPM_TOKEN", "rm|/root/.npmrc"])Output
["/root/.npmrc"]Example 2
Input
recoverable_secret_paths(["mount|/root/.npmrc|NPM_TOKEN"])Output
[]Example 3
Input
recoverable_secret_paths(["write|/root/.npmrc|NPM_TOKEN", "stage|runtime", "copy|/app/dist|"])Output
[]