To develop an application, you usually perform multiple iterations of the following activities:

  • Commit the source code to implement a new or changed feature or a bug fix
  • Build the solution
  • Deploy a test environment containing the solution
  • Run QA tests against the test environment to confirm whether the tests pass
  • Notify the development team of test failures or of a successful test run
  • Destroy the test environment once the cycle is complete
  • Wait for the next code commit to start the cycle again

If you automate these activities, the development lifecycle becomes much more efficient. With well-built automated tests, it also becomes much more effective because you reduce manual intervention as much as possible.

Summary of the steps

This example shows you how to leverage the integration of Acunetix with GitHub – it runs a full test cycle every time there is a pull request. In this cycle, you perform the following steps:

  • Connect to your Docker host:
    • Create a folder to hold files for building a staging container with the web application
    • Copy relevant files to build a staging container on the Docker host
    • Build an image of the staging container and run an instance of it
  • Check that the web application in the staging instance is responding to requests with 200 OK
  • Run a script to get Acunetix to:
    • Create the staging target
    • Trigger a scan of the staging target
    • Wait for the scan to complete
    • Check the number of vulnerabilities found; if at least 1 is found, the process will be considered as failed
  • Connect to the Docker host:
    • Stop and remove the staging container and its underlying image
    • Remove the folder created for the staging container files

Create a GitHub repository for your web application

  1. Sign in to your GitHub account
  2. Click on the New button to create a new repository
  3. Enter the information for your new repository:
    • Set your repository name to test-php-site
    • Set your repository description to My Test PHP Site
    • Enable the Add a README file checkbox to initialize your source code repository

  4. Click on the Create repository button

Create a repository folder with your web application and its associated Docker file

  1. On your repository page, click on the Add file button and select the Create new file option from the drop-down menu
  2. Create the product/index.php file as follows:
      • Set the file name to product/index.php
      • Set the contents to:
    <html>
     <head>
      <title>PHP Test</title>
     </head>
     <body>
     <?php echo '<p>Hello World</p>'; ?> 
     </body>
    </html>
    

  3. Click on the Commit new file button
  4. On your repository page, click on the Add file button and select the Create new file option from the drop-down menu
  5. Create the product/Dockerfile file as follows:
      • Set the file name to product/Dockerfile
      • Set the contents to:
    FROM php:7.3.28-apache
    #setup the web pages
    COPY --chown=www-data:www-data index.php /var/www/html
    

  6. Click on the Commit new file button

Create a repository folder to contain your Acunetix scan script

  1. On your repository page, click on the Add file button and select the Create new file option from the drop-down menu
  2. Create the scripts/axscript.sh file as follows:
      • Set the file name to scripts/axscript.sh
      • Set the contents to:
    #!/bin/bash
     
    # Declare functions
    cleanup(){
    # Delete the scan
    Dummy=`curl -sS -k -X DELETE "$MyAXURL/scans/{$MyScanID}" -H "Accept: application/json" -H "X-Auth: $MyAPIKEY"`
    # Delete the target
    Dummy=`curl -sS -k -X DELETE "$MyAXURL/targets/{$MyTargetID}" -H "Accept: application/json" -H "X-Auth: $MyAPIKEY"`
    }
    
    # Create our intended target
    MyTargetID=`curl -sS -k -X POST $MyAXURL/targets -H "Content-Type: application/json" -H "X-Auth: $MyAPIKEY" --data "{\"address\":\"$MyTargetURL\",\"description\":\"$MyTargetDESC\",\"type\":\"default\",\"criticality\":10}" | grep -Po '"target_id": *\K"[^"]*"' | tr -d '"'`
    
    # Trigger a scan of the target
    MyScanID=`curl -i -sS -k -X POST $MyAXURL/scans -H "Content-Type: application/json" -H "X-Auth: $MyAPIKEY" --data "{\"profile_id\":\"$ScanProfileID\",\"incremental\":false,\"schedule\":{\"disable\":false,\"start_date\":null,\"time_sensitive\":false},\"user_authorized_to_scan\":\"yes\",\"target_id\":\"$MyTargetID\"}" | grep "Location: " | sed "s/Location: \/api\/v1\/scans\///" | sed "s/\r//g" | sed -z "s/\n//g"`
    
    while true; do
     MyScanStatus=`curl -sS -k -X GET "$MyAXURL/scans/{$MyScanID}" -H "Accept: application/json" -H "X-Auth: $MyAPIKEY"`
     if [[ "$MyScanStatus" == *"\"status\": \"processing\""* ]]; then
       echo "Scan Status: Processing - waiting 30 seconds"
     elif [[ "$MyScanStatus" == *"\"status\": \"scheduled\""* ]]; then
       echo "Scan Status: Scheduled - waiting 30 seconds"
     elif [[ "$MyScanStatus" == *"\"status\": \"completed\""* ]]; then
       echo "Scan Status: Completed"
       # Break out of loop
       break
     else
       echo "Invalid Scan Status: Aborting"
       # Clean Up and Exit script
       cleanup
       exit 1
     fi
     sleep 30
    done
    
    # Obtain the scan session ID
    MyScanSessionID=`echo "$MyScanStatus" | grep -Po '"scan_session_id": *\K"[^"]*"' | tr -d '"'`
    
    # Obtain the scan result ID
    MyScanResultID=`curl -sS -k -X GET "$MyAXURL/scans/{$MyScanID}/results" -H "Accept: application/json" -H "X-Auth: $MyAPIKEY" | grep -Po '"result_id": *\K"[^"]*"' | tr -d '"'`
    
    # Obtain scan vulnerabilities
    MyScanVulnerabilities=`curl -sS -k -X GET "$MyAXURL/scans/{$MyScanID}/results/{$MyScanResultID}/vulnerabilities" -H "Accept: application/json" -H "X-Auth: $MyAPIKEY"`
    
    # Count vulnerabilities
    MyVulnerabilityCount=$(echo $MyScanVulnerabilities | jq '.vulnerabilities | length')
    
    # Exit with error if we find vulnerabilities; exit WITHOUT error if vulnerabilities count is 0
    if [ $MyVulnerabilityCount -gt 0 ] ; then exit 1 ; else exit 0 ; fi
    

  3. Click on the Commit new file button

Create secrets for your repository

  1. On your repository page, click on the Settings icon
  2. Click on the Secrets option in the sidebar
  3. On the Action secrets page, click on the New repository secret button
  4. Create 4 secrets as follows:
    • DOCKER_HOST – this must contain the public IP Address of your Docker host
    • DOCKER_USER – this must contain the user name used to connect to the Docker host via SSH
    • DOCKER_KEY – this must contain the SSH key used to connect (securely but without using a password) to the Docker host; this would typically begin with —–BEGIN OPENSSH PRIVATE KEY—– and end with —–END OPENSSH PRIVATE KEY—–
    • MYAPIKEY – this must contain the API key for your Acunetix account, which you can retrieve from the Acunetix profile page:

Create your workflow file

    • On your repository page, click on the Add file button and select the Create new file option from the drop-down menu
    • Create the .github/workflows/main.yml file as follows:
        • Set the file name to .github/workflows/main.yml
        • Set the contents to:
      # main.yml
      name: Vulnerability testing
      on:
        push:
          branches:
            - main
      env:
        MyAXURL: 'https://online.acunetix.com/api/v1'
        MyTargetURL: 'http://acunetixexample.com:8080'
        MyTargetDESC: 'Test PHP Site - created via GitHub-to-Acunetix CI/CD integration'
        ScanProfileID: '11111111-1111-1111-1111-111111111111'
      jobs:
        deploy:
          name: Deploy product to the Docker host
          runs-on: ubuntu-latest
          steps:
            - name: checkout_code
              uses: actions/checkout@v2
            - name: create_docker_folder
              uses: garygrossgarten/github-action-ssh@release
              with:
                host: ${{ secrets.DOCKER_HOST }}
                username: ${{ secrets.DOCKER_USER }}
                privateKey: ${{ secrets.DOCKER_KEY}}
                command: mkdir -p ~/test-php-site
            - name: copy_files_to_docker_folder
              uses: garygrossgarten/github-action-scp@release
              with: 
                host: ${{ secrets.DOCKER_HOST }}
                username: ${{ secrets.DOCKER_USER }}
                privateKey: ${{ secrets.DOCKER_KEY}}
                local: ./product
                remote: test-php-site/
            - name: build_and_run_docker_container
              uses: garygrossgarten/github-action-ssh@release
              with:
                host: ${{ secrets.DOCKER_HOST }}
                username: ${{ secrets.DOCKER_USER }}
                privateKey: ${{ secrets.DOCKER_KEY}}
                command: |
                  cd ~/test-php-site
                  docker build -t test-php-site .
                  docker run -d -p 8080:80 --name mytest test-php-site
        check:
          if: always()
          needs: deploy
          name: Check if the deployed product is functional
          runs-on: ubuntu-latest
          steps:
            - name: check_deployment
              run: wget -qO- -T 5 $MyTargetURL >/dev/null ; if [ $? != 0 ] ; then exit 1 ; fi
        scan:
          if: always()
          needs: check
          name: Scan product with Acunetix
          runs-on: ubuntu-latest
          steps:
            - name: install_packages
              run: sudo apt-get -y install jq
            - name: checkout_code
              uses: actions/checkout@v2
            - name: scan_product
              env:
                MyAPIKEY: ${{ secrets.MyAPIKEY }}
              run: |
                chmod +x scripts/axscript.sh
                scripts/axscript.sh
        destroy:
          if: always()
          needs: scan
          name: Destroy deployment
          runs-on: ubuntu-latest
          steps:
            - name: destroy_deployment
              uses: garygrossgarten/github-action-ssh@release
              with:
                host: ${{ secrets.DOCKER_HOST }}
                username: ${{ secrets.DOCKER_USER }}
                privateKey: ${{ secrets.DOCKER_KEY}}
                command: |
                  docker stop mytest
                  docker rm mytest
                  docker rmi test-php-site
                  rm -rf ~/test-php-site
      

    • Adjust the lines highlighted in red to reflect your staging instance details; for example:
      MyTargetURL: 'http://yourstagingdomain.com:8080'
      MyTargetDESC: 'Test PHP Site - created via GitHub-to-Acunetix CI/CD integration'
      
    • Click on the Commit new file button

This will immediately trigger the first run of the workflow. Go to the Actions page and click on the currently running workflow link to look at the progress of the workflow:

When the workflow has been completed, you can see the success or failure of each of the main steps in the workflow. A run with zero vulnerabilities would show as follows:

Whereas a run that finds vulnerabilities would show as follows:

SHARE THIS POST
THE AUTHOR
Kevin Attard Compagno
Technical Writer
Kevin Attard Compagno is a Technical Writer working for Acunetix. A technical writer, translator, and general IT buff for over 30 years, Kevin used to run Technical Support teams and create training documents and other material for in-house technical staff.