# DAST Scanner

## Table of Contents

1. [Purpose](#purpose)
2. [Installation](#installation)
3. [Quick Start](#quick_start)
4. [Usage](#usage)
5. [Built-in Scan Profiles](#profiles)
6. [Authentication](#authentication)
7. [CI/CD Integration](#cicd)
8. [Command Reference](#command_reference)
9. [Exit Codes](#exit_codes)

### Purpose <a href="#purpose" id="purpose"></a>

The **DAST Scanner** (`xy-dast`) performs automated **dynamic security testing** of running web applications and REST APIs. It tests applications from the outside -- simulating real-world attacks against live endpoints -- to identify vulnerabilities that are only exploitable at runtime.

The scanner supports different application types:

* **Traditional** server-rendered web apps (PHP, JSP, ASP.NET)
* **SPA** JavaScript-heavy Single Page Applications (React, Angular, Vue)
* **REST API** with OpenAPI/Swagger specifications

### Installation <a href="#installation" id="installation"></a>

The DAST scanner is distributed as a Docker image (`xygeni/xy-dast`). Install a lightweight wrapper directly from the image — no separate download is needed. The wrapper is a small, signed script that delegates to `docker compose run`, so once installed you invoke `xy-dast` as if it were a native command.

**Requirements**

* **Docker Engine 20.10+** (or Docker Desktop) with Compose v2 — i.e. the `docker compose ...` subcommand. The legacy `docker-compose` v1 binary is not supported.
* A directory on your `PATH` to drop the wrapper into. This guide uses `~/.local/bin` (Linux/macOS) and `%USERPROFILE%\.local\bin` (Windows).

#### Step 1 — Create the install directory and ensure it is on your `PATH`

This is the most common source of "command not found: xy-dast" issues. The install directory **must exist before the install command** (Docker creates it as `root` if it does not, which then fails to write), and it **must be on your `PATH`** for the short `xy-dast` command to work.

{% hint style="warning" %}
On **Windows** and **macOS** the `~/.local/bin` directory is **not** on the default `PATH`. On most Linux distributions it *is* added by `~/.profile`, but **only if the directory exists at login** — if you create it now in an existing shell, you still need to add it to `PATH` for the current session (or open a new login shell after creating it).
{% endhint %}

{% tabs %}
{% tab title="Linux" %}

```bash
# 1. Create the directory (idempotent)
mkdir -p ~/.local/bin

# 2. Make sure it is on PATH for the current shell
case ":$PATH:" in *":$HOME/.local/bin:"*) ;; *) export PATH="$HOME/.local/bin:$PATH" ;; esac

# 3. Persist for future shells (only needed once per shell rc)
grep -q '\.local/bin' ~/.bashrc 2>/dev/null \
  || echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
# zsh users: replace ~/.bashrc with ~/.zshrc
```

Verify:

```bash
echo "$PATH" | tr ':' '\n' | grep -F "$HOME/.local/bin"   # should print the path
```

{% endtab %}

{% tab title="macOS" %}

```bash
# 1. Create the directory
mkdir -p ~/.local/bin

# 2. Add to PATH for the current shell
export PATH="$HOME/.local/bin:$PATH"

# 3. Persist for future shells (zsh is the default since macOS Catalina)
grep -q '\.local/bin' ~/.zshrc 2>/dev/null \
  || echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
# bash users: replace ~/.zshrc with ~/.bash_profile
```

Verify:

```bash
echo "$PATH" | tr ':' '\n' | grep -F "$HOME/.local/bin"
```

{% endtab %}

{% tab title="Windows (PowerShell)" %}

```powershell
# 1. Create the directory
New-Item -ItemType Directory -Force -Path "$HOME\.local\bin" | Out-Null

# 2. Add to PATH for the current shell
$env:PATH = "$HOME\.local\bin;$env:PATH"

# 3. Persist for future shells (User scope, no admin needed)
$userPath = [Environment]::GetEnvironmentVariable('PATH', 'User')
if ($userPath -notlike "*$HOME\.local\bin*") {
  [Environment]::SetEnvironmentVariable('PATH', "$HOME\.local\bin;$userPath", 'User')
}
```

Verify (open a **new** PowerShell window after persisting):

```powershell
$env:PATH -split ';' | Select-String '\.local\\bin'
```

{% hint style="info" %}
The Windows wrapper is a PowerShell script (`xy-dast.ps1`) signed with an Authenticode certificate. If your execution policy blocks running scripts, run `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` once.
{% endhint %}
{% endtab %}
{% endtabs %}

#### Step 2 — Install the wrapper from the Docker image

The image's `install` subcommand drops two files into the mounted directory: the `xy-dast` wrapper script itself and a sidecar `xy-dast-compose.yml` that holds the image reference, environment forwarding, and runtime parameters.

{% tabs %}
{% tab title="Linux / macOS" %}

```bash
docker run --rm -v ~/.local/bin:/mnt/install xygeni/xy-dast install
```

{% endtab %}

{% tab title="Windows (PowerShell)" %}

```powershell
docker run --rm -v "${HOME}\.local\bin:/mnt/install" xygeni/xy-dast install --powershell
```

`--powershell` produces the signed `.ps1` wrapper (and matching sidecar) instead of the bash one.
{% endtab %}
{% endtabs %}

Verify:

```bash
xy-dast --version
```

If you get `command not found` (or `not recognized as ... cmdlet`), revisit Step 1 — the directory is almost certainly not on your `PATH` yet.

#### Quick install vs. secure install

The plain `install` command above is a **quick install**: convenient for desktop and ad-hoc use. The wrapper itself is signed at release time, but the image reference written into `xy-dast-compose.yml` is a mutable tag (e.g. `xygeni/xy-dast:6.7.0`).

For production environments — and any setting that needs defence-in-depth against registry-side supply-chain attacks — use the **secure install** flow, which pins the image to its immutable digest and verifies the cosign (Sigstore keyless) signature before installing:

```bash
TAG=xygeni/xy-dast:6.7.0     # or :latest

# 1. Pull the image so the digest is in your local image cache.
docker pull "$TAG"

# 2. Verify the cosign signature, signed by the xy-dast GitHub Actions identity.
cosign verify \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity-regexp 'github\.com/xygeni/xy-dast' \
  "$TAG"

# 3. Resolve the immutable digest the registry served us.
DIGEST=$(docker image inspect "$TAG" --format '{{index .RepoDigests 0}}')

# 4. Install. --image rewrites only the `image:` line in xy-dast-compose.yml
#    to pin the resolved digest — wrapper bytes stay byte-identical.
docker run --rm -v ~/.local/bin:/mnt/install "$TAG" install --image "$DIGEST"
```

To upgrade later, repeat the four-step flow with the new version.

#### How the wrapper works

* It is a pre-built, byte-stable script signed at release time (Authenticode for `.ps1`); `install` copies it byte-exact so the signature is preserved.
* It delegates to `docker compose -f xy-dast-compose.yml run --rm xy-dast …`. Compose handles env forwarding (`XYGENI_TOKEN`, `XYGENI_URL`, `XYGENI_DASHBOARD_URL`, `XYGENI_DAST_DIR`), `network_mode: host`, and `shm_size: 2gb`.
* When you pass `-o <file>`, the wrapper mounts the output directory into the container so the report appears on your host filesystem.
* It looks for the sidecar at `<wrapper-dir>/xy-dast-compose.yml` by default. Override the location with the `XY_DAST_COMPOSE_FILE` environment variable. To pin a different image, edit the `image:` line in the sidecar or re-run `install --image <ref>`.

### Quick Start <a href="#quick_start" id="quick_start"></a>

Scan a web application:

```bash
xy-dast scan -u https://example.com
```

Results are uploaded to the Xygeni platform by default. To save a local report instead, use `-o`:

```bash
xy-dast scan -u https://example.com -o report.json
```

Scan a REST API with an OpenAPI specification:

```bash
xy-dast scan -u https://api.example.com \
  -p openapi \
  --openapi https://api.example.com/v3/api-docs \
  --bearer-token env:API_TOKEN
```

Scan a Single Page Application:

```bash
xy-dast scan -u https://app.example.com -p spa
```

Scan a GraphQL API:

```bash
# With schema URL
xy-dast scan -u https://api.example.com \
  -p graphql \
  --graphql https://api.example.com/graphql/schema

# With introspection (no schema needed)
xy-dast scan -u https://api.example.com -p graphql
```

Scan a SOAP web service:

```bash
xy-dast scan -u https://api.example.com \
  --wsdl https://api.example.com/service?wsdl
```

### Usage <a href="#usage" id="usage"></a>

The DAST Scanner is launched using the `xy-dast scan [options]` command.

To view all available options, use the `--help` flag:

```bash
xy-dast scan --help
```

The most important options are:

* **Target URL** (`-u` or `--url`) -- the base URL of the application to scan (required).
* **Scan profile** (`-p` or `--profile`) -- selects the scan strategy: `traditional`, `spa`, `openapi`, `quick`, or `deep`.
* **OpenAPI spec** (`--openapi`) -- URL or file path to an OpenAPI/Swagger specification (for REST API scans).
* **Output file** (`-o` or `--output`) -- path for the JSON report. Use `-` for stdout.
* **Project name** (`-n` or `--project-name`) -- identifies the project in the Xygeni platform.
* **Upload** -- reports are uploaded to the Xygeni backend by default. Disable with `--no-upload`.
* **Filtering** -- use `--exclude-rules` to skip noisy rules, or `--risk-threshold` to set a minimum severity.

#### Custom Scan Settings

Override timing defaults directly from the command line:

```bash
xy-dast scan -u https://example.com \
  --spider-duration 15 \
  --ajax-spider-duration 10 \
  --active-scan-duration 30 \
  --timeout 90 \
  -o report.json
```

Run a passive-only scan (no active attacks):

```bash
xy-dast scan -u https://example.com \
  --passive-only \
  -o report.json
```

#### Filtering Results

```bash
# Exclude noisy rules by ID
xy-dast scan -u https://api.example.com \
  --exclude-rules 10094,10038 \
  -o report.json

# Only report findings at MEDIUM risk or above
xy-dast scan -u https://api.example.com \
  --risk-threshold MEDIUM \
  -o report.json

# Set attack strength
xy-dast scan -u https://example.com \
  --policy-strength LOW \
  -o report.json
```

#### Deep Crawl

The `--deep-crawl` option runs a headless browser-based crawler before the main scan. It discovers URLs that traditional spiders miss, especially in JavaScript-heavy applications where content is rendered dynamically.

```bash
xy-dast scan -u https://app.example.com --deep-crawl
```

Discovered URLs are fed as seed URLs into the scanner's spider, improving coverage.

You can tune the crawl depth and timeout:

```bash
xy-dast scan -u https://app.example.com \
  --deep-crawl \
  --crawl-depth 5 \
  --crawl-timeout 10m
```

The `deep` profile enables deep crawl by default.

#### Vulnerability Check

The `--vuln-check` option runs a template-based vulnerability scanner after the main scan completes. It checks the discovered endpoints against thousands of known CVEs, misconfigurations, and exposures — complementing the active scanning with signature-based detection.

```bash
xy-dast scan -u https://app.example.com --vuln-check
```

Both features can be combined for maximum coverage:

```bash
xy-dast scan -u https://app.example.com -n my-app \
  --deep-crawl --vuln-check
```

Vulnerability check findings appear in the same report as regular scan findings, with detector IDs prefixed by `vuln/` (e.g., `vuln/CVE-2021-44228`). See [DAST Detectors](/xygeni-products/dast-security/dast-detectors.md) for details.

You can filter by severity and control the scan rate:

```bash
xy-dast scan -u https://app.example.com \
  --vuln-check \
  --vuln-check-severity critical,high \
  --vuln-check-timeout 5m
```

The `deep` profile enables vulnerability check by default.

#### Automatic Profile Selection

If you are unsure which profile fits your target, use `--auto-profile` to let the scanner probe the application and select the most appropriate profile:

```bash
xy-dast scan -u https://app.example.com --auto-profile
```

This detects the technology stack (e.g., React SPA, REST API with OpenAPI) and selects the corresponding profile. If `--profile` is also specified, it takes precedence.

To see the available profiles:

```bash
xy-dast scan --list-profiles
```

### Built-in Scan Profiles <a href="#profiles" id="profiles"></a>

Profiles control how the scanner behaves for different types of applications. Select a profile with `--profile <name>`.

| Profile       | Best For                                      | Spider           | AJAX Spider        | Active Scan                                       |
| ------------- | --------------------------------------------- | ---------------- | ------------------ | ------------------------------------------------- |
| `traditional` | Server-rendered apps (PHP, JSP, etc.)         | 10 min, depth 5  | 5 min, 2 browsers  | 15 min                                            |
| `spa`         | JS-heavy SPAs (React, Angular, Vue)           | 5 min, depth 3   | 15 min, 4 browsers | 20 min                                            |
| `openapi`     | REST APIs with OpenAPI spec                   | 2 min, depth 2   | Skipped            | 10 min, API-Scan policy                           |
| `graphql`     | GraphQL APIs (schema import or introspection) | 2 min, depth 2   | Skipped            | 10 min                                            |
| `soap`        | SOAP web services with WSDL import            | 2 min, depth 2   | Skipped            | 10 min                                            |
| `quick`       | Fast smoke test                               | 3 min, depth 3   | Skipped            | 10 min, LOW strength                              |
| `deep`        | Maximum coverage                              | 20 min, depth 10 | 20 min, 4 browsers | 60 min, INSANE strength + deep crawl + vuln check |

List all available profiles (including custom ones):

```bash
xy-dast scan --list-profiles
```

{% hint style="info" %}
Custom profiles can be placed in `$XYGENI_DAST_DIR/profiles/`, `./profiles/`, or `./conf/profiles/`. See [DAST Scanner Configuration](/xygeni-products/dast-security/dast-scanner/dast-scanner-configuration.md) for the full profile schema and examples.
{% endhint %}

### Authentication <a href="#authentication" id="authentication"></a>

The DAST scanner supports authenticated scanning to test areas of the application behind login.

#### Form-Based Login

```bash
xy-dast scan -u https://app.example.com \
  --login-url https://app.example.com/login \
  --username testuser \
  --password testpass \
  -o report.json
```

#### Bearer Token

Read the token from an environment variable to avoid exposing secrets in command history:

```bash
export API_TOKEN=your-secret-token
xy-dast scan -u https://api.example.com \
  --bearer-token env:API_TOKEN \
  -o report.json
```

#### API Key / Custom Header

For APIs that authenticate via a custom header (e.g., `X-API-Key`):

```bash
xy-dast scan -u https://api.example.com \
  --api-key-header X-API-Key \
  --api-key-value env:MY_API_KEY \
  -o report.json
```

#### HTTP Basic Authentication

For targets protected with HTTP Basic auth (RFC 7617):

```bash
xy-dast scan -u https://app.example.com \
  --basic-username admin \
  --basic-password env:BASIC_PASS \
  -o report.json
```

#### Client Certificate (mTLS)

For targets that require mutual TLS, supply a PKCS#12 (`.p12` / `.pfx`) certificate. The password is read from an environment variable and is redacted from any log output:

```bash
export CERT_PASSWORD=cert-secret
xy-dast scan -u https://mtls.example.com \
  --client-cert /path/to/client.p12 \
  --client-cert-password env:CERT_PASSWORD \
  -o report.json
```

mTLS is orthogonal to the other authentication methods — combine it with `--bearer-token`, `--api-key-*`, `--basic-*`, or form login when the target requires both transport-level and application-level auth. The certificate path can also be set via the `clientCertificate` block in a profile YAML.

{% hint style="warning" %}
Always use `env:VAR_NAME` syntax for secrets (tokens, passwords, API keys, certificate passwords) rather than passing values directly on the command line, to prevent accidental exposure in shell history and process listings.
{% endhint %}

### CI/CD Integration <a href="#cicd" id="cicd"></a>

Use `--quiet` for minimal output and `--fail-on` to gate builds on vulnerability severity:

```bash
xy-dast scan -u https://example.com \
  --quiet \
  --fail-on high \
  -o report.json

# Exit code 128 means alerts were found at or above the threshold
if [ $? -eq 128 ]; then
  echo "Security vulnerabilities found!"
  exit 1
fi
```

The `--quiet` flag outputs a single summary line:

```
Scan completed in 5m 23s | 42 URLs | 15 alerts (2 critical, 5 high, 4 low, 4 info)
```

Pipe JSON to stdout for downstream processing:

```bash
xy-dast scan -u https://example.com --quiet --output - | jq '.vulnerabilities | length'
```

#### SARIF output for GitHub Code Scanning

`--format sarif` produces SARIF v2.1.0 output that GitHub Code Scanning, Azure DevOps, the VS Code SARIF Viewer, and most CI/CD security dashboards ingest natively. Findings appear in the repo's **Security → Code scanning** tab alongside SAST/SCA results.

```yaml
# .github/workflows/dast.yml
- name: Run xy-dast scan
  run: |
    xy-dast scan -u https://staging.example.com \
      --format sarif \
      --branch ${{ github.ref_name }} \
      --no-upload \
      -o dast.sarif

- name: Upload SARIF to GitHub Code Scanning
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: dast.sarif
    category: dast/xygeni-dast
```

{% hint style="info" %}
DAST findings reference HTTP URLs rather than source-tree files, so they appear in the Security tab but **do not** produce inline PR annotations. This is a known limitation of all DAST tooling that emits SARIF.
{% endhint %}

The `--format` flag only affects the file written by `-o`. The Xygeni backend upload payload (when `--no-upload` is omitted) is always Xygeni JSON regardless of `--format`.

#### Saving raw scan artifacts

Use `--keep-details` to save the underlying scanner output and the generated automation plan alongside the report. This is the easiest way to debug a scan that does not produce expected findings:

```bash
xy-dast scan -u https://example.com -o report.json --keep-details
# Creates: report.json, report.scan.json, report.plan.yml
```

#### GitHub Actions Example

```yaml
- name: DAST Scan
  run: |
    xy-dast scan \
      -u ${{ vars.APP_URL }} \
      --profile spa \
      --fail-on high \
      --quiet \
      -n ${{ github.repository }} \
      -o dast-report.json
  env:
    XYGENI_TOKEN: ${{ secrets.XYGENI_TOKEN }}

- name: Upload DAST Report
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: dast-report
    path: dast-report.json
```

#### GitLab CI Example

```yaml
dast_scan:
  image: xygeni/xy-dast:latest
  stage: test
  script:
    - xy-dast scan
        -u $APP_URL
        --profile spa
        --fail-on high
        --quiet
        -n $CI_PROJECT_NAME
        -o dast-report.json
  artifacts:
    paths:
      - dast-report.json
    when: always
  variables:
    XYGENI_TOKEN: $XYGENI_TOKEN
```

### Command Reference <a href="#command_reference" id="command_reference"></a>

```
Usage: xy-dast scan [OPTIONS] -u <url>

Target Options:
  -u, --url=<url>           Base URL of the target application (required)
  --context-name=<name>     Scanner context name
  --openapi=<url>           OpenAPI/Swagger specification URL
  --graphql=<url|file>      GraphQL schema URL or file (introspection if omitted)
  --wsdl=<url|file>         WSDL definition URL or file for SOAP web services
  --url-list=<file>         File with additional URLs
  --include=<patterns>      URL patterns to include (regex)
  --exclude=<patterns>      URL patterns to exclude (regex)

Scan Options:
  -p, --profile=<name>      Scan profile: openapi, spa, traditional, quick,
                            deep, or custom
  --auto-profile            Auto-detect target technology and select profile
  --list-profiles           List available profiles and exit
  --timeout=<duration>      Overall scan timeout (default: 60m)
  --spider-duration=<dur>   Override spider duration
  --ajax-spider-duration=<dur>  Override AJAX spider duration
  --active-scan-duration=<dur>  Override active scan duration
  --passive-only            Run only passive scan
  --lenient                 Continue scan despite OpenAPI validation errors
  --policy-strength=<level> Attack strength: LOW, MEDIUM (default), HIGH,
                            INSANE
  --exclude-rules=<ids>     Comma-separated rule IDs to exclude
  --risk-threshold=<level>  Minimum risk level: HIGH, MEDIUM, LOW, INFO

Deep Crawl:
  --deep-crawl              Run deep crawl before scanning to discover
                            URLs with headless JS support
  --crawl-depth=<n>         Deep crawl max depth (default: 3)
  --crawl-timeout=<dur>     Deep crawl timeout (default: 5m)

Vulnerability Check:
  --vuln-check                   Run vulnerability check after scanning for
                                 CVE detection and known vulnerability checks
  --vuln-check-severity=<s>      Severity filter (default: critical,high,medium)
  --vuln-check-rate-limit=<n>    Requests per second (default: 50)
  --vuln-check-timeout=<dur>     Vulnerability check timeout (default: 15m)

Authentication:
  --login-url=<url>         Login form URL
  --username=<user>         Form authentication username
  --password=<pass>         Form authentication password
  --username-field=<name>   Username field name (default: username)
  --password-field=<name>   Password field name (default: password)
  --bearer-token=<token>    Bearer token (supports env:VAR_NAME)
  --api-key-header=<name>   Header name for API key auth (e.g., X-API-Key)
  --api-key-value=<value>   Header value for API key auth (supports env:VAR_NAME)
  --basic-username=<user>   Username for HTTP Basic authentication
  --basic-password=<pass>   Password for HTTP Basic auth (supports env:VAR_NAME)
  --client-cert=<file>      PKCS#12 client certificate for mTLS targets
  --client-cert-password=<pw> Certificate password (supports env:VAR_NAME)

Output Options:
  -o, --output=<file>       Output file (use '-' for stdout)
  --format=<json|sarif>     Output format for the file written by -o
                            (default: json). 'sarif' emits SARIF v2.1.0
                            for GitHub Code Scanning. The Xygeni upload
                            payload is always JSON.
  -n, --project-name=<name> Project name for report
  --pretty                  Pretty-print the report (JSON or SARIF)
  --work-dir=<dir>          Working directory for artifacts
  --no-upload               Disable report upload to Xygeni backend
  --branch=<name>           Branch name for report upload
  --keep-details            Keep raw scanner output (.scan.json) and
                            generated automation plan (.plan.yml)
  -q, --quiet               Suppress progress output, show only summary
  --fail-on=<severity>      Exit with code 128 if alerts at or above severity
                            (info, low, high, critical)

Global Options:
  -v, --verbose             Enable verbose output
  -nb, --no-banner          Suppress the startup banner
  -h, --help                Show help message
  -V, --version             Show version information
```

### Exit Codes <a href="#exit_codes" id="exit_codes"></a>

| Code | Description                                |
| ---- | ------------------------------------------ |
| 0    | Scan completed successfully                |
| 1    | General error                              |
| 2    | Scanner engine not found                   |
| 3    | Scanner engine execution failed            |
| 4    | Invalid input arguments                    |
| 128  | Alert threshold exceeded (see `--fail-on`) |

### Environment Variables

| Variable               | Description                                                                                                                                            | Default                             |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------- |
| `XYGENI_TOKEN`         | API access token (required for report upload)                                                                                                          | --                                  |
| `XYGENI_URL`           | Xygeni API endpoint                                                                                                                                    | `https://api.xygeni.io`             |
| `XYGENI_DASHBOARD_URL` | Xygeni dashboard URL                                                                                                                                   | `https://in.xygeni.io/dashboard`    |
| `XYGENI_DIR`           | Base directory for logs                                                                                                                                | Current directory                   |
| `XYGENI_DAST_DIR`      | Configuration directory (containing `conf/`)                                                                                                           | Script directory                    |
| `XY_DAST_COMPOSE_FILE` | Override the location of the wrapper's `xy-dast-compose.yml` sidecar (which holds the image reference, environment forwarding, and runtime parameters) | `<wrapper-dir>/xy-dast-compose.yml` |
| `PROXY_HOST`           | Proxy hostname                                                                                                                                         | --                                  |
| `PROXY_PORT`           | Proxy port                                                                                                                                             | `3128`                              |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.xygeni.io/xygeni-products/dast-security/dast-scanner.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
