Pipeline help - Remote You are not allowed to upload code 403, best practices?

There are several earlier posts that reference this same error. For me, this is happening in a pipeline. And while I want to solve the error, I’m more interested in the proper way to automate working with the repo in the pipeline.

If I’m reading the docs correctly, a $CI_JOB_TOKEN and credentials are auto-generated for each job allowing interaction with the repo.

Here is the script section of my job code:

script:
    # Checkout the latest version of the main branch
    - git checkout main
    - git pull

    # Create a new branch for the user
    - git checkout -b ${NEW_MEMBER_USER_NAME}

    # Create a new folder for the new client
    - mkdir -p clients/${NEW_MEMBER_USER_NAME}

    # Copy client files into the new folder
    - cp -R files/default/* clients/${NEW_MEMBER_USER_NAME}

    # Commit changes to the new branch
    - git config --global user.email "${GITLAB_USER_EMAIL}"
    - git config --global user.name "${GITLAB_USER_NAME}"
    - git add .
    - git commit -m "Add new client files for ${NEW_MEMBER_USER_NAME}"
    - git push --set-upstream origin ${NEW_MEMBER_USER_NAME}
  rules:
    - if: $CI_PIPELINE_SOURCE == "trigger"
      when: always

The error happens on git push “Remote: You are not allowed to upload code. 403”

My next step was going to either use the $CI_JOB_TOKEN or create a dedicated token, add access it from the CI/CD Variables, but other posts imply that fails too.

Also, instead using raw git commands, I thought about installing gitlab cli and using it since I also need to create a related issue and merge request (later.)

Ultimately though, this feels like the wrong direction. Am I on the right track, or is there a better, “best practices” way to manipulate a repo, branches, merge requests, etc, in a pipeline?

The repo is private. I’m the owner / maintainer / only user.

3 Likes

Hey,

I believe you’re on the right path. But, what you didn’t configure here is authentication. GitLab Runner by default cannot make changes to the repo (push branches) - and this is exactly what is missing here.

To make sure - this part:

- git config --global user.email "${GITLAB_USER_EMAIL}"
- git config --global user.name "${GITLAB_USER_NAME}"

is just git config, not authentication. Authentication is defined by origin URL, which GitLab does for us behind the scenes and uses when cloning, etc. But now we need to change it.

What I do is change authentication method by defining new origin URL. And as authentication method, I use here https with OAuth.

Firstly, you need to decide which user will do the push - it can be you (as person), or a bot. In any case, you need to create an access token. I created a Project Access token (read_repo, write_repo permissions) and saved it on project level as CI/CD Variable OAUTH_TOKEN. This will basically result in a Bot pushing your branch. If you don’t want a Bot user, then you can also create your Personal Access Token and also store it as CI/CD variable in your project.

Then, you can use that variable to define a new origin:

before_script:
  - git remote remove origin
  - git remote add origin https://oauth2:$OAUTH_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git

After that you should be able to do what you are doing in your script part.

I’m not sure if this is the “best practice”, but this worked for me very well and I didn’t have time to further investigate. TBH I have no idea anymore where did I take this option from, probably some StackOverflow

I believe there are other ways as well, e.g. using Deploy Keys… have a look at inspiration here.

Hope this helps!

4 Likes

Thank you, that was helpful. I also found this resource, which I think is an official “how to” from the Gitlab group.

In the comments he’s unclear though as to what type of Token is best for the “Special Use” cases. Bot, Deploy, Project, Personal, Group, Job, Trigger … did I get them all? It’s a bit overwhelming to know which token type to use in which instance. I’ve read the docs several times for each one but still unclear. If anyone knows of a concise “cheat sheet” that highlights when tokens with what permissions in what situations, plz share!

Nice! It’s using the same idea, I see.

Yeah, TBH I’m also not very happy with GitLab’s permission/access management. However, I recently found this page which gives quite a good overview/summary, especially with the table at the bottom.

What is most annoying to me, is that not all parts of GitLab (e.g. Package Registry, Container Registry, API, etc) support all types of token/authentication. You’re quite forced to mix & match depending on the situation.

Just be aware of one thing I learned only a few weeks ago: CI_JOB_TOKEN has the scope of permissions depending on the triggerer. From the same page:

API authentication uses the job token, by using the authorization of the user triggering the job.

This sometimes can be really unfortunate, when you’re having some cross-project pipelines/dependencies and not all members have the same permissions in all different groups. So just to give you a heads up there :smiley:

Therefore, my suggestion is, if you have enough time - plan your CI/CD pipeline and project dependencies first, see what needs to access to what, what should be access limits, etc, and then decide which token to use.

Thank I was able to make it work. In my case, I just used a personal access token.

    - git remote remove origin
    - git remote add origin https://$GITLAB_USERNAME:$GITLAB_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git

Where $GITLAB_USERNAME is my Gitlab username.

@angelroma Happy to help.

However - just a hint: while personal access token will also do the job (and it’s okay for personal projects), in business organizations I would highly recommend to avoid using it in (non-personal) projects. If anything happens to your account - pipeline will not work anymore. This is why Project/Group Access Tokens are better suited for use in pipelines :slight_smile: