Run CAST Profiler with Docker

The CAST Profiler container image, how to mount source and retrieve results, and the file ownership constraint to plan for

Overview

CAST Profiler is published as a container image, which is the least intrusive way to run it on a build agent: no download step, no unzip, no executable to keep up to date. This page covers the image, the invocation, and the one constraint that catches most first attempts - the container runs as a non-root user.

The image

Property Value
Repository castimaging/profiler-cli
Tags latest, v2, and exact versions such as 2.0.3
Architectures linux/amd64 and linux/arm64
Base image Red Hat Universal Base Image 9 minimal
Working directory /app
Runs as UID 10001

The entrypoint passes every argument straight through to the CLI, so command-line options go directly after the image name and behave exactly as documented in the CLI reference.

Because the image is published for both linux/amd64 and linux/arm64, this is also the supported way to run CAST Profiler on macOS, where no native build is available. Docker pulls the architecture matching your Mac, so Apple Silicon runs the arm64 image and Intel the amd64 one, with no emulation layer in either case.

Verify Docker is available

$ docker --version

Scan a source folder

Mount the source read-only and mount an output folder to collect the results:

$ docker run --rm \
    -v /src/my-app:/source:ro \
    -v "$PWD/profiler-out:/out" \
    castimaging/profiler-cli:2.0.3 \
    --offline --clean-log --output /out --name my-app /source

To publish the full results page instead of keeping everything local, swap the mode and suppress the browser launch, which cannot work on an agent anyway:

$ docker run --rm \
    -v /src/my-app:/source:ro \
    castimaging/profiler-cli:2.0.3 \
    --complete-insight --no-browser --clean-log --name my-app /source

File ownership

The container runs as UID 10001, not root. On a Linux host, where bind mounts expose the host’s own ownership straight through, two things follow:

  • The mounted source must be readable by UID 10001. World-readable source is fine; source owned by another user with restrictive permissions is not.
  • The mounted output folder must be writable by UID 10001, otherwise the run fails when it writes the report files. Creating the folder on the host before the run and making it group- or world-writable is the simplest fix.

If your build agent’s permissions make that awkward, override the user. The entrypoint handles an overridden user by setting HOME to a writable location when it is unset, so this is a supported path rather than a workaround:

$ docker run --rm --user "$(id -u):$(id -g)" \
    -v /src/my-app:/source:ro \
    -v "$PWD/profiler-out:/out" \
    castimaging/profiler-cli:2.0.3 \
    --offline --clean-log --output /out --name my-app /source

On macOS and Windows this section rarely applies: Docker Desktop’s file sharing maps ownership across the virtual machine boundary for you, so mounted folders are readable and writable without any of the above. Expect bind-mount I/O to be slower than on Linux, which is noticeable when scanning a large tree.

Paths in the results

Every path in the result files is the path as seen inside the container. Scanning /source produces results whose root path is /source, not /src/my-app. This matters when you correlate an alert against a working copy on the host, and when you compare two scans of the same application that were mounted at different paths - the reported paths differ even though the content is identical. Mount at a consistent path across runs.

Pinning a version

Pin an exact tag in a pipeline:

$ docker run --rm ... castimaging/profiler-cli:2.0.3 ...

The reference knowledge base that decides which languages and technologies can be recognised is bundled in the image, so the tag determines the detection results as much as it determines the code. Two consequences:

  • Pinning a tag makes results comparable across runs, which is what you want when you are tracking an application over time.
  • Moving to a newer tag can change the inventory without the source code changing, because the reference data moves with it. Each evaluation records the reference data version and its content hashes under dataIntegrity, so you can tell the two causes apart - see Result files.

Using --pull always with a moving tag such as latest gives you the opposite trade-off: current detection, no comparability. Prefer an exact tag and upgrade deliberately.

Multiple source folders

Mount each one and list them all as positional arguments:

$ docker run --rm \
    -v /src/backend:/source/backend:ro \
    -v /src/frontend:/source/frontend:ro \
    -v "$PWD/profiler-out:/out" \
    castimaging/profiler-cli:2.0.3 \
    --offline --clean-log --output /out --name my-app /source/backend /source/frontend