Skip to main content

Secure a GitLab project for OpenClaw

Use separate GitLab environments, protected branches, and environment-scoped credentials to keep integration access out of production and production access out of feature pipelines. This example uses the CI Tools GitFlow component with develop for integration and main for production.

Delivery and access map​

SourceTarget branchGitLab environmentOpenClaw releaseCredential scopeWho can deploy
feat/*, fix/*developnone until mergenoneno deployment tokenDevelopers through a reviewed merge request
developdevelopintopenclaw-intGITLAB_TOKEN scoped to intDevelopers and Maintainers
hotfix/*mainnone until mergenoneno deployment tokenMaintainers through a reviewed merge request
mainmainprdopenclaw-prdGITLAB_TOKEN scoped to prdMaintainers only

The branch controls which code is eligible for deployment. The job's environment.name controls which token GitLab exposes. Both checks must match before OpenClaw can receive an environment credential.

Configure the project workflow​

Include the GitFlow component in .gitlab-ci.yml:

include:
- component: $CI_SERVER_FQDN/xrow-public/ci-tools/common@stable
- component: $CI_SERVER_FQDN/xrow-public/ci-tools/workflow-gitflow@stable
inputs:
development-branch: develop

The component creates and protects develop, protects main, requires successful pipelines and resolved discussions, and configures project approval behavior. Configure the merge request branch workflow in GitLab so feat/* and fix/* target develop, while hotfix/* targets main.

Keep the reviewer allowlist in the project AGENTS.md, for example:

### Settings

| Setting | Value |
| --- | --- |
| reviewers | [platform-maintainer](https://gitlab.com/platform-maintainer) |

The GitLab agent requests one eligible reviewer from this list only after the branch is rebased, its pipeline succeeds, and the final diff and discussions are clean. Reviewers should have Maintainer or Owner access so they can merge into the protected target branches.

Create the environments and tokens​

  1. Add deploy jobs whose environment.name values are exactly int and prd. Set deployment_tier to staging and production, respectively.
  2. Protect prd under Settings > CI/CD > Protected environments and allow only Maintainers to deploy. Protect int too when integration deployments should be limited to a dedicated group.
  3. Create a separate GitLab project access token for each OpenClaw release. Grant only the role and scopes the agent needs, set an expiry date, and plan rotation before expiry. Do not reuse a personal access token.
  4. Add both tokens under Settings > CI/CD > Variables with the same key, GITLAB_TOKEN, but different environment scopes: int and prd. Set each variable to Masked and hidden and Protected.
  5. Protect both develop and main. A protected variable is not exposed to a pipeline running only from an unprotected feature branch.

Environment-scoped variables are selected from the deployment job's environment.name, not from arbitrary rules. Do not use the secret variable itself in rules or include conditions.

Deploy each OpenClaw release​

Keep non-secret settings in version control and pass the environment token only to the matching deployment job:

.deploy-openclaw:
stage: deploy
image: registry.gitlab.com/xrow-public/ci-tools/tools:stable
script:
- umask 077
- secret_values="$(mktemp)"
- trap 'rm -f "${secret_values}"' EXIT
- >-
GITLAB_TOKEN_VALUE="${GITLAB_TOKEN}" yq -n
'.openclaw.secrets.GITLAB_TOKEN = strenv(GITLAB_TOKEN_VALUE)'
> "${secret_values}"
- >-
helm upgrade --install "openclaw-${CI_ENVIRONMENT_NAME}"
oci://registry.gitlab.com/xrow-public/helm-openclaw/charts/openclaw
--namespace "openclaw-${CI_ENVIRONMENT_NAME}"
--create-namespace
--values "${secret_values}"

deploy:int:
extends: .deploy-openclaw
environment:
name: int
deployment_tier: staging
rules:
- if: '$CI_COMMIT_BRANCH == "develop"'

deploy:prd:
extends: .deploy-openclaw
environment:
name: prd
deployment_tier: production
resource_group: openclaw-prd
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'

The temporary values file is readable only by the job user and is deleted when the job exits. GitLab masks the token in job output, but scripts must still avoid set -x, printing secret values, rendering Secrets into artifacts, or persisting the token in dotenv files. Prefer an external secrets manager when the platform supports one.

Verify the boundary​

Before enabling automatic production delivery, confirm:

  • A feat/* pipeline cannot read either deployment token.
  • The develop deployment receives the int token but not the prd token.
  • The main deployment receives the prd token and requires an allowed production deployer.
  • The integration and production OpenClaw releases use different namespaces, tokens, and persistent volumes.
  • The merge request has one reviewer selected from AGENTS.md, a successful pipeline, and no unresolved discussions before merge.
  • Token expiry and rotation are monitored without storing token values in the repository, job artifacts, or OpenClaw workspace files.

See the GitLab documentation for environment-scoped CI/CD variables, protected environments, and access token security.