Sast vulnerability not reported in job output

I have added semgrep-sast to my build pipeline, the process runs and generates a json output. The output includes vulnerabilities but the build does not report it or fail. I’m trying to work out why. the gl-sast-report.json is

{
    "version": "15.1.4",
    "vulnerabilities": [
        {
            "id": "b5c31d95604519bb203b828e70fe36c1fc2999993c3939bf2f3dfd16953c5686",
            "category": "sast",
            "name": "Improper neutralization of special elements used in an OS command ('OS Command Injection')",
            "description": "OS command injection is a critical vulnerability that can lead to a full system\ncompromise as it may allow an adversary to pass in arbitrary commands or arguments\nto be executed.\n\nUser input should never be used in constructing commands or command arguments\nto functions which execute OS commands. This includes filenames supplied by\nuser uploads or downloads.\n\nEnsure your application does not:\n\n- Use user-supplied information in the process name to execute.\n- Use user-supplied information in an OS command execution function which does\nnot escape shell meta-characters.\n- Use user-supplied information in arguments to OS commands.\n\nThe application should have a hardcoded set of arguments that are to be passed\nto OS commands. If filenames are being passed to these functions, it is\nrecommended that a hash of the filename be used instead, or some other unique\nidentifier. It is strongly recommended that a native library that implements\nthe same functionality be used instead of using OS system commands, due to the\nrisk of unknown attacks against third party commands.\n\nWhen specifying the OS command, ensure the application uses the full path\ninformation, otherwise the OS may attempt to look up which process to execute\nand could be vulnerable to untrusted search path vulnerabilities (CWE-426).\n\nExample of safely executing an OS command:\n```\npublic void ExecuteCommand(string userFileData) {\n    // generate a random filename, do not using user input\n    string fileName = \"C:\\\\Temp\\\\\" + Guid.NewGuid();\n    File.WriteAllText(fileName, userFileData);\n\n    using (Process process = new Process())\n    {\n        // hardcode the full process path\n        ProcessStartInfo processInfo = new ProcessStartInfo(\"C:\\\\App\\\\FileReader.exe\");\n        // only pass in trust arguments, and never direct user input.\n        processInfo.Arguments = fileName;\n        processInfo.UseShellExecute = false;\n        process.StartInfo = processInfo;\n        process.Start();\n    }\n}\n```\n\nFor more information on OS command injection, see OWASP's guide:\nhttps://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html\n",
            "cve": "semgrep_id:security_code_scan.SCS0001-1:78:78",
            "severity": "High",
            "scanner": {
                "id": "semgrep",
                "name": "Semgrep"
            },
            "location": {
                "file": "Code/PlayNicely.Execution/PN.Executor/AbstractProcessRunner.cs",
                "start_line": 78
            },
            "identifiers": [
                {
                    "type": "semgrep_id",
                    "name": "security_code_scan.SCS0001-1",
                    "value": "security_code_scan.SCS0001-1"
                },
                {
                    "type": "cwe",
                    "name": "CWE-78",
                    "value": "78",
                    "url": "https://cwe.mitre.org/data/definitions/78.html"
                },
                {
                    "type": "owasp",
                    "name": "A03:2021 - Injection",
                    "value": "A03:2021"
                },
                {
                    "type": "owasp",
                    "name": "A1:2017 - Injection",
                    "value": "A1:2017"
                },
                {
                    "type": "security_code_scan_rule_id",
                    "name": "SCS0001",
                    "value": "SCS0001"
                }
            ]
        }
    ],
    "scan": {
        "analyzer": {
            "id": "semgrep",
            "name": "Semgrep",
            "url": "https://gitlab.com/gitlab-org/security-products/analyzers/semgrep",
            "vendor": {
                "name": "GitLab"
            },
            "version": "5.10.0"
        },
        "scanner": {
            "id": "semgrep",
            "name": "Semgrep",
            "url": "https://github.com/returntocorp/semgrep",
            "vendor": {
                "name": "GitLab"
            },
            "version": "1.74.0"
        },
        "type": "sast",
        "start_time": "2024-08-13T10:01:45",
        "end_time": "2024-08-13T10:01:59",
        "status": "success"
    }
}

Any idea why a sast job, that uploads an artifact with a vulnerability, wouldn’t report that as part of the pipeline?

The MR widget fetches the report and provides the security summary, and tracking. The vulnerability reports view also shows found vulnerabilities, based on the scanner reports, including SAST. Both features require an Ultimate subscription. Which GitLab version and tier are you using?

Free, project is public

So if reporting on SAST artifacts is an ultimate feature, why bother making adding SAST scanning to your build pipeline free?