Configuration file for the CI/CD
The SAFE CLI should generate a configuration for SAFE CI/CD, but you can also configure it manually.
The configuration file should be named config.json and should be placed in the .safe folder in the target Repository.
Project configuration
Example configuration for a project:
{
"output": ["stdio", "file"],
"version": "1.1",
"project": {
"name": "appname",
"type": "beam",
"apps": [
{
"name": "appname",
"additional_includes": []
},
{
"name": "appname2",
"additional_includes": []
}
],
"paths": [
"_build/prod/lib"
]
}
}
Advanced: Explicit App File Paths
For projects with complex build configurations or when auto-discovery is slow, you can explicitly specify the .app file location for each application:
{
"output": ["stdio"],
"version": "1.1",
"project": {
"name": "my_project",
"type": "beam",
"paths": ["_build/prod/lib"],
"apps": [
{
"name": "my_app",
"app_file": "_build/prod/lib/my_app/ebin/my_app.app"
},
{
"name": "my_dependency",
"app_file": "_build/prod/lib/my_dependency/ebin/my_dependency.app"
}
]
}
}
Benefits:
- Faster cache loading (no filesystem search)
- Explicit control in monorepo setups
- Consistent across different build tools
Requirements:
- Paths must be relative to project root
- Files must exist and be readable
- Either specify for all apps or none (mixed mode uses auto-discovery)
-
output: Available options:"stdio": Prints the results directly to standard output (console)"checkmarx"Sends the vulnerabilities to Checkmarx"file"Saves the report file."sarif"Saves the vulnerabilities into a sarif file format.
-
project: A JSON object.name: The name of the project as string.type: The type of the project, currently"beam"is supported, that can be used for Erlang and Elixir projects as well.apps: A list of JSON objects, each object represents an application in the project. (Note: we are searching for apps recursively as well in thepaths)name: The name of the application as string.app_file: (Optional) Relative path from project root to the specific.appfile for this application. When specified for all apps, SAFE will use these exact paths instead of searching for.appfiles. This improves performance and reliability in complex build setups.- Must be relative to project root
- Can be located anywhere in the project (not restricted to
pathsdirectories) - If any app omits this field, SAFE will search for all
.appfiles automatically - Example:
"_build/prod/lib/my_app/ebin/my_app.app"
additional_includes: A list of strings, each string is a path to something that should be included in the analysis but might not be included by default. These paths are relative to the project root, and may be either:- a directory, in which case every
.beambeneath it is included — example:"../my_dep/_build/prod/lib/my_dep/ebin" - a single
.beamfile — example:"build/dev/erlang/my_app/ebin/my_app_ffi.beam"
- a directory, in which case every
paths: A list of strings, each string is a path to a directory where the applications are located.config_files: (Optional) A list of Elixir config file paths (relative to the project root). SAFE reads these files to detect configuration-based vulnerabilities — for example, checking whether TLS is properly enabled or insecure defaults are present. Files are merged in the order listed. Default:[].config_env: (Optional) The Mix environment used when readingconfig_files. Must be one of"dev","test","prod". Default:"prod".
Gleam Projects
A Gleam project does not need this file while Gleam analysis is in beta: safe analyse run from
the directory holding gleam.toml works without one, and without a license.
Adding a config does not change that — a Gleam project stays free during the beta either way — so
create one when you want file/SARIF/Checkmarx output or additional_includes.
safe setup gleam generates the config for you — see the
safe setup gleam. A generated Gleam config looks like this:
{
"output": ["stdio", "file"],
"version": "1.1",
"project": {
"name": "my_app",
"type": "beam",
"config_env": "prod",
"apps": [
{
"name": "my_app",
"additional_includes": []
}
],
"paths": [
"build/dev/erlang"
],
"config_files": []
}
}
typestays"beam". Gleam compiles to the BEAM, so it shares the project type with Erlang and Elixir; there is no"gleam"type. SAFE recognises Gleam-compiled applications from the build output itself, so nothing in the config marks the project as Gleam.pathsisbuild/dev/erlang, the output of a plaingleam build.appsnames only your own package. Dependencies are compiled intobuild/dev/erlangas well, but listing just your package keeps them out of the analysis.
For a Gleam application, SAFE analyses the modules compiled from the package's src/ directory
and skips dev/ and test/. To bring one of those modules into the report anyway, name its
compiled .beam in additional_includes:
"apps": [
{
"name": "my_app",
"additional_includes": ["build/dev/erlang/my_app/ebin/my_app_test.beam"]
}
]
See Gleam projects for the details.
Elixir Config Files
SAFE can analyse your Elixir configuration files to detect vulnerabilities that arise from misconfiguration rather than code bugs — for example, TLS being disabled, insecure cipher suites, or missing endpoint hardening.
Specify the config files to load and the environment to evaluate them under:
{
"output": ["stdio"],
"version": "1.1",
"project": {
"name": "my_app",
"type": "beam",
"paths": ["_build/prod/lib"],
"apps": [{ "name": "my_app" }],
"config_files": ["config/config.exs", "config/prod.exs"],
"config_env": "prod"
}
}
SAFE reads and merges the listed files in order using the specified environment. Use the environment that matches your deployment target (typically "prod") to catch production misconfigurations.
Handling BEAM Files Without Abstract Code
SAFE requires abstract code (debug info) to analyse BEAM files. If any file lacks it, the analysis is aborted with an error listing every offending file.
The most common cause is compiling with encrypt_debug_info (rebar3/erlc) or without the debug_info flag. The fix is to recompile with unencrypted debug info.
If recompiling is not possible — for example, a third-party dependency ships pre-compiled — pass --no-abstract-code-check to the CLI. This skips all BEAM files lacking abstract code and continues analysis with the remaining files.
Security note: Excluded files are not analysed. Use --no-abstract-code-check only when necessary and be aware of the coverage gap it introduces.