Artifacts and cache downloaded in a job don't have write permission
Summary
Artifacts and cache files downloaded in a job has read permissions where the project folder is publicly writable. In jobs where non-root user is used, permission denied
errors happen because the files/folders are owned by root and no there is no write permission on them.
For example dependency-scanning
job fails if the package file that the scanner is looking for is in the artifacts/cache folder downloaded. The scanner tries to create a file (SBOM) in the folder where it finds the package file (like packages.lock.json
) but it cannot.
Steps to reproduce
- Create a project and add
.gitlab-ci.yml
:
include:
- component: $CI_SERVER_FQDN/components/dependency-scanning/main@0.8.0
build:
stage: build
script:
- mkdir -p ./publish
- touch publish/test.txt
- echo "hello, Moto!" > publish/test.txt
artifacts:
paths:
- publish/
dependency-scanning:
script:
- whoami
- ls -lar ./*
- touch publish/newfile.txt
- Commit your change and wait for the pipeline to run.
- Check the
test
job logs:
Click to expand
Running with gitlab-runner 18.4.0~pre.115.gb2218bab (b2218bab)
on blue-4.saas-linux-small-amd64.runners-manager.gitlab.com/default J2nyww-sK, system ID: s_cf1798852952
Resolving secrets
Preparing the "docker+machine" executor
00:10
Using Docker executor with image registry.gitlab.com/security-products/dependency-scanning:v0 ...
Using effective pull policy of [always] for container registry.gitlab.com/security-products/dependency-scanning:v0
Authenticating with credentials from job payload (GitLab Registry)
Pulling docker image registry.gitlab.com/security-products/dependency-scanning:v0 ...
Using docker image sha256:599c80b67eb7f0ae923949bcc838551455ff76c13112ed6e1c179705b813cf38 for registry.gitlab.com/security-products/dependency-scanning:v0 with digest registry.gitlab.com/security-products/dependency-scanning@sha256:0d4972b6dfbc76796adecdd1f29004ff67f51c07675a1c7ce53e2dc89b36bee3 ...
Preparing environment
00:03
Using effective pull policy of [always] for container sha256:450f6832502178cecd498a724ddb9884661f5e02976091f7950a0c039d806a18
Running on runner-j2nyww-sk-project-74794509-concurrent-0 via runner-j2nyww-sk-s-l-s-amd64-1760025039-793f9d5e...
Getting source from Git repository
00:02
Gitaly correlation ID: 976b61a368b54306a6112702381bb6c0
Fetching changes with git depth set to 20...
Initialized empty Git repository in /builds/e_munn_ultimate_group/tests/ci-tests/dep-scan-test/.git/
Created fresh repository.
Checking out 0fcb5933 as detached HEAD (ref is simple-test)...
Skipping Git submodules setup
$ git remote set-url origin "${CI_REPOSITORY_URL}" || echo 'Not a git repository; skipping'
Downloading artifacts
00:01
Downloading artifacts for build (11663742543)...
Downloading artifacts from coordinator... ok correlation_id=e5fadf89fef94a8b812d4a9cfb2c14d5 host=storage.googleapis.com id=11663742543 responseStatus=200 OK token=6b_QCbuJD
Executing "step_script" stage of the job script
00:01
Using effective pull policy of [always] for container registry.gitlab.com/security-products/dependency-scanning:v0
Using docker image sha256:599c80b67eb7f0ae923949bcc838551455ff76c13112ed6e1c179705b813cf38 for registry.gitlab.com/security-products/dependency-scanning:v0 with digest registry.gitlab.com/security-products/dependency-scanning@sha256:0d4972b6dfbc76796adecdd1f29004ff67f51c07675a1c7ce53e2dc89b36bee3 ...
$ whoami
gitlab
$ ls -lar ./*
-rw-rw-rw- 1 root root 6189 Oct 9 15:51 ./README.md
./publish:
total 12
-rw-r--r-- 1 root root 13 Oct 9 15:51 test.txt
drwxrwxrwx 4 root root 4096 Oct 9 15:51 ..
drwxr-xr-x 2 root root 4096 Oct 9 15:51 .
$ touch publish/newfile.txt
touch: cannot touch 'publish/newfile.txt': Permission denied
Uploading artifacts for failed job
00:01
Uploading artifacts...
WARNING: **/gl-sbom-*.cdx.json: no matching files. Ensure that the artifact path is relative to the working directory (/builds/e_munn_ultimate_group/tests/ci-tests/dep-scan-test)
ERROR: No files to upload
Cleaning up project directory and file based variables
00:00
ERROR: Job failed: exit code 1
The user in the container is gitlab
and it tries to create a file inside the downloaded artifacts folder (publish
) but it won't have permission to do this.
Example Project
https://gitlab.com/e_munn_ultimate_group/tests/ci-tests/dep-scan-test/-/pipelines/2090800220
What is the current bug behavior?
In CI/CD jobs where container is using a non-root user, permission denied
errors happen because the files/folders downloaded as artifact or cache are owned by root
and no there is no write permission on them.
What is the expected correct behavior?
Artifact or cache files should be writable for the user.
bash-5.1$ id -a
uid=1000(gitlab) gid=0(root) groups=0(root)
Relevant logs and/or screenshots
Click to expand
Running with gitlab-runner 18.4.0~pre.115.gb2218bab (b2218bab)
on blue-4.saas-linux-small-amd64.runners-manager.gitlab.com/default J2nyww-sK, system ID: s_cf1798852952
Resolving secrets
Preparing the "docker+machine" executor
00:10
Using Docker executor with image registry.gitlab.com/security-products/dependency-scanning:v0 ...
Using effective pull policy of [always] for container registry.gitlab.com/security-products/dependency-scanning:v0
Authenticating with credentials from job payload (GitLab Registry)
Pulling docker image registry.gitlab.com/security-products/dependency-scanning:v0 ...
Using docker image sha256:599c80b67eb7f0ae923949bcc838551455ff76c13112ed6e1c179705b813cf38 for registry.gitlab.com/security-products/dependency-scanning:v0 with digest registry.gitlab.com/security-products/dependency-scanning@sha256:0d4972b6dfbc76796adecdd1f29004ff67f51c07675a1c7ce53e2dc89b36bee3 ...
Preparing environment
00:03
Using effective pull policy of [always] for container sha256:450f6832502178cecd498a724ddb9884661f5e02976091f7950a0c039d806a18
Running on runner-j2nyww-sk-project-74794509-concurrent-0 via runner-j2nyww-sk-s-l-s-amd64-1760025039-793f9d5e...
Getting source from Git repository
00:02
Gitaly correlation ID: 976b61a368b54306a6112702381bb6c0
Fetching changes with git depth set to 20...
Initialized empty Git repository in /builds/e_munn_ultimate_group/tests/ci-tests/dep-scan-test/.git/
Created fresh repository.
Checking out 0fcb5933 as detached HEAD (ref is simple-test)...
Skipping Git submodules setup
$ git remote set-url origin "${CI_REPOSITORY_URL}" || echo 'Not a git repository; skipping'
Downloading artifacts
00:01
Downloading artifacts for build (11663742543)...
Downloading artifacts from coordinator... ok correlation_id=e5fadf89fef94a8b812d4a9cfb2c14d5 host=storage.googleapis.com id=11663742543 responseStatus=200 OK token=6b_QCbuJD
Executing "step_script" stage of the job script
00:01
Using effective pull policy of [always] for container registry.gitlab.com/security-products/dependency-scanning:v0
Using docker image sha256:599c80b67eb7f0ae923949bcc838551455ff76c13112ed6e1c179705b813cf38 for registry.gitlab.com/security-products/dependency-scanning:v0 with digest registry.gitlab.com/security-products/dependency-scanning@sha256:0d4972b6dfbc76796adecdd1f29004ff67f51c07675a1c7ce53e2dc89b36bee3 ...
$ whoami
gitlab
$ ls -lar ./*
-rw-rw-rw- 1 root root 6189 Oct 9 15:51 ./README.md
./publish:
total 12
-rw-r--r-- 1 root root 13 Oct 9 15:51 test.txt
drwxrwxrwx 4 root root 4096 Oct 9 15:51 ..
drwxr-xr-x 2 root root 4096 Oct 9 15:51 .
$ touch publish/newfile.txt
touch: cannot touch 'publish/newfile.txt': Permission denied
Uploading artifacts for failed job
00:01
Uploading artifacts...
WARNING: **/gl-sbom-*.cdx.json: no matching files. Ensure that the artifact path is relative to the working directory (/builds/e_munn_ultimate_group/tests/ci-tests/dep-scan-test)
ERROR: No files to upload
Cleaning up project directory and file based variables
00:00
ERROR: Job failed: exit code 1
Proposed fixes
- Set the user back to
root
. This effectively makes the analyzer less secure, and removes yet another improvement that we've added to the new analyzer. - Instruct users to
chmod
the cache and artifact dirs, so that theroot
group (GID 0) can create files in them. This maps to0775
oru=rwx,g=rwx,o=rx
. - Instruct users to
chown
the cache and artifact dirs, so that they're owned by GID1000
.
Implementation plan
WIP
Workarounds
If you need write permission on the files/folders downloaded as artifacts or cache, you can change the container user to root
.
- For Docker executor, use:
image:
name: <IMAGE>
docker:
user: "root" #OR "0"
- For Kubernetes executor, use:
image:
name: <IMAGE>
kubernetes:
user: "root" #OR "0"
- Change permissions of artifact and cache directories, so that they're executable by the
root
group.
Patch release information for backports
If the bug fix needs to be backported in a patch release to a version under the maintenance policy, please follow the steps on the patch release runbook for GitLab engineers.
Refer to the internal "Release Information" dashboard for information about the next patch release, including the targeted versions, expected release date, and current status.
High-severity bug remediation
To remediate high-severity issues requiring an internal release for single-tenant SaaS instances, refer to the internal release process for engineers.