# GitLab CI & hidden code in variables You can hide code within GitLab CI environment variables, but it will behave in unexpected ways, depending on which flags are enabled. > [!CAUTION] > **Please, do not do this.**
> This guide purely explains what you might see in cursed repositories. > > Good luck to you, if you must read this kind of cursed code.
> If you are considering doing this, **DO NOT**. You should think of future developers that might work on it as manic serial killers that know your address. > [!CAUTION] > There are MANY downsides to this, including that nothing is versioned, and it can impact everything and nothing, and break everything. > [!NOTE] > The alternative is simple: hide your code in a Git repository, clone it, and do a simple `./run.sh` or the like. ## Environment variables Each CI variable has 2 flags, including the following: > **Expand variable reference**
> `$` will be treated as the start of a reference to another variable. If you're doing advanced variables, that mention other variables, you might want to enable this flag. In that case, the following applies: - `$VAR` will be ***replaced*** by the value of the corresponding GitLab CI variable - ✅ `$GITLAB_CI` (Pre-pipeline) - ✅ `$CI_JOB_IMAGE` (Job-only) - ✅ `$CI_COMMIT_REF_NAME` (Pre-pipeline) - `$$VAR` will be ***replaced*** by `$VAR` - ⚠️ Required for variable set within the variable "script" - ⚠️ Required for **complex variable operations**: e.g. `$${#CI_COMMIT_REF_NAME}` (counting length) ## Properly quoting the CI variable Proper quoting of variables makes the difference between a one-liner and a multi-line file: ```console $ cat > test < ascii.txt < As such, if you want fancy usages of GitLab variables, you must still use $$ case "$${#CI_COMMIT_REF_NAME}" in 4) echo "Double - works - $${#CI_COMMIT_REF_NAME}" ;; *) echo "Double - fail - $${#CI_COMMIT_REF_NAME}" ;; esac ``` ### `ONELINER.sh` ```sh BRANCH=main; case "$BRANCH" in main) echo "Single - works - ${BRANCH}" ;; master|*) echo "Single - fail - ${BRANCH}" ;; esac && case "$$BRANCH" in main) echo "Double - works - $${BRANCH}" ;; master|*) echo "Double - fail - $${BRANCH}" ;; esac # You **must** use operators such as && between commands (it is interpreted as a one-liner) # Empty lines are allowed (they are squashed) # Comments are only allowed AT THE END of the variable (at end of file, as it is treated like a one-liner) ``` ### `gitlab-ci-log-output.cap` ```sh Using docker image sha256:... for debian with digest debian@sha256:... ... $ echo "hi. this is horrible and you should never do this..." hi. this is horrible and you should never do this... $ cat > ascii.txt < As such, if you want fancy usages of GitLab variables, you must still use $ case "${#CI_COMMIT_REF_NAME}" in 4) echo "Double - works - ${#CI_COMMIT_REF_NAME}" ;; *) echo "Double - fail - ${#CI_COMMIT_REF_NAME}" ;; esac $ eval "${MULTILINER}" SingleA - works - main SingleB - fail - Double - works - 4 $ eval ${MULTILINER} /usr/bin/bash: eval: line 216: syntax error near unexpected token `case' Cleaning up project directory and file based variables 00:00 ERROR: Job failed: exit code 2 ```