GitLab

You can configure a regular security analysis of your APEX applications using GitLab.

The examples here all use a private repository on GitLab.com: https://gitlab.com/recxtim/apexsectest

Do not use this guide on a public repository because your licensed version of ApexSec and the vulnerability scan results will all be accessible to everyone.

To start, create a new GitLab project and commit the following files:

  • A copy of ApexSec: apexsec-linux64.jar
  • Your APEX application and supporting PL/SQL schema, packages, procedures etc. (here, we’re using BigBadBlog.sql our demonstration vulnerable application)
  • The following .gitlab-ci.yml file:
stages:
  - analysis
run-apexsec:
  stage: analysis
  image: openjdk:17
  script:
    - mkdir -p apexsec-results
    - java -jar apexsec-linux64.jar --file src/ --report-csv apexsec-results/output.apexsec 
  allow_failure: true
  artifacts:
    when: always
    paths:
      - apexsec-results/
  only:
    - main

This pipeline will run on commit/push to main. Using allow_failure means the pipeline will produce warnings, not failures.

When committed, the pipeline executes:

Executing the pipeline runs ApexSec and detects security risks in the APEX application

The job failed because ApexSec returned a non-zero error code, indicating that vulnerabilities were identified.

The output from ApexSec is stored in an artifact:

Output stored in Gitlab artifact

Download artifacts.zip

$ unzip -t artifacts.zip
Archive:  artifacts.zip
    testing: apexsec-results/         OK
    testing: apexsec-results/output.apexsec   OK
    testing: apexsec-results/output.csv   OK

This is a simple way to integrate ApexSec with your GitLab development life cycle.

Check the results by vulnerability class

Check the results by vulnerability class

Now, let’s create a more complex example that passes/fails separate stages based on specific result vulnerability classes.

Update the .gitlab-ci.yml file

stages:
  - analysis
  - checksql
  - checkpotentialsql
run-apexsec:
  stage: analysis
  image: openjdk:17
  script:
    - mkdir -p apexsec-results
    - java -jar apexsec-linux64.jar --file src/ --report-csv apexsec-results/output.apexsec 
  allow_failure: true
  artifacts:
    when: always
    paths:
      - apexsec-results/
  only:
    - main

check-results-sql:
  stage: checksql
  dependencies:
    - run-apexsec
  script:
    - echo "Checking SQL Injection"
    - if grep "^SQL Injection" apexsec-results/output.csv; then exit 1; else exit 0; fi
  allow_failure: true

check-results-potential-sql:
  stage: checkpotentialsql
  dependencies:
    - run-apexsec
  script:
    - echo "Checking Potential SQL Injection"
    - if grep "^Potential SQL Injection" apexsec-results/output.csv; then exit 1; else exit 0; fi
  allow_failure: true

This executes on commit:

Execute the updated pipeline

This shows there were SQL Injection vulnerabilities (checksql has warnings), but no Potential SQL Injection issues (checkpotentialsql passed).

Commit the project

Using the following configuration we can push the ApexSec output back into the git repository. The ApexSec command line parameters have been modified to also output the JUnit XML file.

This output format will suppress issues that have been marked as false positive within the ApexSec project. The check stages now process this JUnit XML.

Update the .gitlab-ci.yml:

stages:
  - analysis
  - commitproject
  - checksql
  - checkpotentialsql

run-apexsec:
  stage: analysis
  image: openjdk:17
  script:
    - mkdir -p apexsec-results
    - java -jar apexsec-linux64.jar --file src/ --report-csv --junit apexsec-results/output.apexsec 
  allow_failure: true
  artifacts:
    when: always
    paths:
      - apexsec-results/
  only:
    - main

commit-project:
  stage: commitproject
  script:
    - git config --global user.email "<your email>"
    - git config --global user.name "<your name>"
    - git checkout ${CI_COMMIT_REF_NAME}
    - git add apexsec-results/output.apexsec apexsec-results/output.csv
    - git commit -m "apexsec results"
    - git push -o ci.skip "https://${GITLAB_USER_NAME}:${GIT_PUSH_TOKEN}@${CI_REPOSITORY_URL#*@}"

check-results-sql:
  stage: checksql
  dependencies:
    - run-apexsec
  script:
    - echo "Checking SQL Injection"
    - grep 'name="SQL Injection".*failures="0"' apexsec-results/output.junit.xml
  allow_failure: true

check-results-potential-sql:
  stage: checkpotentialsql
  dependencies:
    - run-apexsec
  script:
    - echo "Checking Potential SQL Injection"
    - grep 'name="Potential SQL Injection".*failures="0"' apexsec-results/output.junit.xml
  allow_failure: true

To be able to push to the repository, the pipeline needs a token. Configure this in Preferences, Access Token as “GIT_PUSH_TOKEN”:

Configure a token to use for pushing results to the repository

In GitLab configure the variables in Settings, CI/CD:

Make the token a protected and hidden variable

Now when the pipeline runs the results from ApexSec are committed to the repository in apexsec-results.

We can then open this project file in ApexSec Desktop, review the results, and mark issues as false positives.

(For more information see: https://apexsec.recx.co.uk/apexsec-3-usage-guides/usage-guides/opening-an-existing-project/)

The project can be saved and pushed back to the repository so that the next execution of the GitLab pipeline will use the project that contains the marked false positives. These are suppressed in the JUnit output and the pipeline output stages will then succeed if vulnerabilities were found, but they were marked as false positives.

To demonstrate, we mark all SQL Injection issue as false positives (we do not recommend you do this in a real-world scenario!):

Mark issues as false positive in ApexSec

Now when the pipeline runs, the check-results-sql passes:

Pipeline executing with the SQL Injection tests now passing

Summary

We’ve shown how to integrate ApexSec into your GitLab CI/CD processes by using a pipeline that executes when the main branch changes. A simple example was provided that runs ApexSec and saves the results to GitLab artifacts. Then this was extended to process the output as separate pipeline stages, to indicate the success or failure of the vulnerability scan on specific classes of vulnerability.

Then a complete end-to-end workflow was demonstrated:

  • ApexSec runs on commit
  • The ApexSec project file and JUnit output is saved to the repository
  • User’s can pull the repository, then open the project in ApexSec to review results, make comments and mark false positives
  • The project can be pushed back to the repository along with any APEX application changes
  • ApexSec then runs again, using this update project and APEX application
  • Separate stages indicate vulnerabilities are present for specific vulnerability classes