# 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
```