Fix the scan for secrets printed in CI logs

Review the AI's codeEasy10 min

Your task

To debug a failing deploy, an assistant added env and an echo of the AWS secret key to a GitLab CI job. Both print secrets into a job log that many people can read, and GitLab's masking is easy to get around. The team now scans every CI script for lines that print secrets.

An assistant wrote find_secret_leaks(script_lines, secret_names). It is in the editor. It has a bug. Find it and fix it.

Input and output:

  • script_lines: the job's script, one shell command per line. Words are separated by spaces. The list can be empty.
  • secret_names: the names of the variables that hold secrets, such as "AWS_SECRET_ACCESS_KEY". An empty name is ignored.
  • Return the line numbers of the leaks, as a list of integers.

Rules the tests check:

  • Lines are numbered from 1, and every line counts, blank ones included.
  • Trim whitespace at both ends of each line. Skip a line that is then empty.
  • The first word is the text before the first space, or the whole line if it has no space.
  • A line that is exactly env, or whose first word is printenv, is a leak: it prints every variable. A line such as env --version is not.
  • A line whose first word is echo, printf or cat is a leak when it names a secret. A secret is named when the line contains $ followed by the name.
  • It is also named when the line contains the braced form: ${ followed by the name and then }.
  • Both are plain text searches and case sensitive. A name also matches as the start of a longer variable written without braces.
  • A line with any other first word is never a leak, even when it uses a secret. The value goes to that tool, not to the log.
  • Return the leak line numbers in ascending order, each once.

Examples

find_secret_leaks(script_lines: list[str], secret_names: list[str]) -> list[int]
Example 1
Inputfind_secret_leaks(["echo \"Deploying with config:\"", "env", "echo \"AWS key is $AWS_SECRET_ACCESS_KEY\"", "aws s3 sync ./build s3://acme-prod-site --delete"], ["AWS_SECRET_ACCESS_KEY"])
Output[2, 3]
Example 2
Inputfind_secret_leaks(["echo \"Deploying to prod\"", "aws s3 sync ./build s3://acme --delete"], ["AWS_SECRET_ACCESS_KEY"])
Output[]