Where does the runner take the exit code from?

I am trying to understand the output produced by the runner with the following config:

image: debian:9.3

before_script:
  - echo 'Starting new job'
  - mkdir artifacts
  - apt-get update
  - apt-get install --assume-yes pylint
  - python -V # Print out python version for debugging

after_script:
  - echo 'Job finished'

run_pylint:
  type: test
  script:
    - pylint --rcfile=.pylintrc --output-format=text *.py | tee artifacts/pylint.txt
    - score=$(sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' artifacts/pylint.txt)
    - echo "Pylint score was $score"
  artifacts:
    paths:
      - artifacts/

It results in this:

Global evaluation
-----------------
Your code has been rated at 9.01/10

Running after script...
$ echo 'Job finished'
Job finished
ERROR: Job failed: exit code 1

Where does exit code 1 come from? I see that not all the script steps are executed, though the first one (executing pylint itself) is started.

How can I troubleshoot this?