To configure the Azure integration, follow these steps (either during the onboarding wizard, or once you have access to the Gomboc platform):
In Azure, create a Personal Access Token that has a Code (Read & Write) permissions and the name of the organization is was scoped to.
Note that we do not currently support the option "All accessible organizations". If you need to provide access to multiple organizations, please create a separate integration for each one.
Go to Settings > Integrations > Azure
Insert the token and org name you have created in step 1
3. Click "Integrate" to complete the initial SCM integration
Webhooks
In order for Gomboc.AI to keep the updated status of any PR's we create for you, you must include a webhook. In order to create a proper webhook, please follow these steps:
Go to our portal (app.gomboc.ai), click on your account icon on the top right > Settings
Create a 'Personal' or 'API' token.
Use a Personal token when you will be the only one using the token,
Use an API token with the appropriate roles if the token will be used within the webhook, or expect multiple people to use the token.
Be sure to copy the created token, and start to set up the Azure Devops webhook. Within your project settings, create a 'Web Hooks' service.
The trigger should be specified 'Pull Request Updated'. No additional filters will be required.
Within the 'Actions' settings, you will need the following values
URL: https://scan.app.gomboc.ai/webhook/azdo
HTTP headers: X-Gomboc-Authorization: <Token copied from the Gomboc settings>
Once completed, you can press finish and proceed to creating the pipeline or start to create pull requests through the portal.
CI/CD
Pull request pipeline
Azure devops pipeline can use the following yaml to run the Gomboc CLI on every pull request to main. Be sure to replace the {ORGANIZATION_NAME} fields within the yaml file with your your Azure DevOps organization name. When running the Gomboc cli command you can replace the submit-for-review argument with preview if no pull request is wanted. Please note that with preview, the pipelines will pass, regardless of any remediations we find.
# Example of a pipeline that runs on ever Pull Request
trigger:
branches:
include:
- main
pr:
branches:
include:
- main
pool:
vmImage: ubuntu-latest
jobs:
- job: CheckBranchPattern
steps:
- script: |
branchName="$(System.PullRequest.SourceBranch)"
regexPattern="^refs/heads/[A-Za-z]+-remediated-[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}-[0-9]+$"
echo $branchName
echo $branchName =~ $regexPattern
if [[ $branchName =~ $regexPattern ]]; then
echo "Branch matches the pattern."
echo "##vso[task.setvariable variable=branchMatchesPattern;isOutput=true]true"
else
echo "Branch does not match the pattern."
echo "##vso[task.setvariable variable=branchMatchesPattern;isOutput=true]false"
fi
name: 'match'
- job: 'Gomboc_CLI'
dependsOn: CheckBranchPattern
condition: eq(dependencies.CheckBranchPattern.outputs['match.branchMatchesPattern'], 'false') # Checks to see if the action was initiated by a bot, or the user
container:
image: gombocai/cli:latest
steps:
- checkout: self
fetchDepth: 0
- script: |
if [ $(Build.Reason) == "PullRequest" ]; then
TARGET_BRANCH_NAME=$(echo $(System.PullRequest.TargetBranch) | sed 's/refs\/heads\///')
SOURCE_BRANCH_NAME=$(echo $(System.PullRequest.SourceBranch) | sed 's/refs\/heads\///')
before=$(git rev-parse origin/$TARGET_BRANCH_NAME)
after=$(git rev-parse origin/$SOURCE_BRANCH_NAME)
target_directories=$(for i in $(git diff --name-only --diff-filter=ACMRT $before $after) ; do dirname $i ; done | sort -u | xargs)
if [ -z "$target_directories" ]; then
echo -e "\033[0;31mNo changes detected\033[0m"
exit 0
fi
gomboc terraform remediate remote submit-for-review --auth-token $(System.AccessToken) --azdo-collection-uri $(System.TeamFoundationCollectionUri) --azdo-organization-name {ORGANIZATION_NAME} --target-directories $target_directories
exit_code=$?
exit $exit_code
fi
if [ $(Build.Reason) == "IndividualCI" ]; then
SOURCE_BRANCH_NAME=$(echo $(Build.SourceBranch) | sed 's/refs\/heads\///')
before=$(git rev-parse origin/$SOURCE_BRANCH_NAME^1)
after=$(git rev-parse origin/$SOURCE_BRANCH_NAME)
target_directories=$(for i in $(git diff --name-only --diff-filter=ACMRT $before $after) ; do dirname $i ; done | sort -u | xargs)
if [ -z "$target_directories" ]; then
echo -e "\033[0;31mNo changes detected\033[0m"
exit 0
fi
gomboc terraform remediate remote submit-for-review --auth-token $(System.AccessToken) --azdo-collection-uri $(System.TeamFoundationCollectionUri) --azdo-organization-name {ORGANIZATION_NAME} --target-directories $target_directories
else
echo -e "\033[0;31mUnsupported event type: $CI_PIPELINE_SOURCE. Only the \"merge_request_event\" and \"push\" sources are currently supported\033[0m"
exit_code=$?
exit $exit_code
fi
Scheduled pipeline
The Gomboc pipeline also recognizes scheduled execution to support detecting remediations in code that happen due to changes in IaC modules or improvements in Gomboc remediation coverage. You can view the Azure DevOps Pipelines documentation to setup scheduled pipelines properly.
If more flexibility is desired, the Docker image can be used by using gombocai/cli:latest for the image value in your pipeline yaml file. From the image, you may use the gomboc command directly.
trigger:
branches:
include:
- main
pr:
branches:
include:
- main
pool:
vmImage: ubuntu-latest
# scheduled CI job execution
schedules:
- cron: '0 0 * * *' # Runs the job at midnight
displayName: "test-scheduled-pipeline"
branches:
include:
- main
always: false # should be made to true if runs should be started regardless if changes were made to the repo
jobs:
- job: CheckBranchPattern
steps:
- script: |
branchName="$(System.PullRequest.SourceBranch)"
regexPattern="^refs/heads/[A-Za-z]+-remediated-[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}-[0-9]+$"
echo $branchName
echo $branchName =~ $regexPattern
if [[ $branchName =~ $regexPattern ]]; then
echo "Branch matches the pattern."
echo "##vso[task.setvariable variable=branchMatchesPattern;isOutput=true]true"
else
echo "Branch does not match the pattern."
echo "##vso[task.setvariable variable=branchMatchesPattern;isOutput=true]false"
fi
name: 'match'
- job: 'Gomboc_CLI'
dependsOn: CheckBranchPattern
condition: eq(dependencies.CheckBranchPattern.outputs['match.branchMatchesPattern'], 'false') # Checks to see if the action was initiated by a bot, or the user
container:
image: gombocai/cli:latest
steps:
- checkout: self
fetchDepth: 0
- script: |
if [ $(Build.Reason) == "PullRequest" ]; then
TARGET_BRANCH_NAME=$(echo $(System.PullRequest.TargetBranch) | sed 's/refs\/heads\///')
SOURCE_BRANCH_NAME=$(echo $(System.PullRequest.SourceBranch) | sed 's/refs\/heads\///')
before=$(git rev-parse origin/$TARGET_BRANCH_NAME)
after=$(git rev-parse origin/$SOURCE_BRANCH_NAME)
target_directories=$(for i in $(git diff --name-only --diff-filter=ACMRT $before $after) ; do dirname $i ; done | sort -u | xargs)
if [ -z "$target_directories" ]; then
echo -e "\033[0;31mNo changes detected\033[0m"
exit 0
fi
gomboc terraform remediate remote submit-for-review --auth-token $(System.AccessToken) --azdo-collection-uri $(System.TeamFoundationCollectionUri) --azdo-organization-name {ORGANIZATION_NAME} --target-directories $target_directories
exit_code=$?
exit $exit_code
fi
if [ $(Build.Reason) == "IndividualCI" ]; then
SOURCE_BRANCH_NAME=$(echo $(Build.SourceBranch) | sed 's/refs\/heads\///')
before=$(git rev-parse origin/$SOURCE_BRANCH_NAME^1)
after=$(git rev-parse origin/$SOURCE_BRANCH_NAME)
target_directories=$(for i in $(git diff --name-only --diff-filter=ACMRT $before $after) ; do dirname $i ; done | sort -u | xargs)
if [ -z "$target_directories" ]; then
echo -e "\033[0;31mNo changes detected\033[0m"
exit 0
fi
gomboc terraform remediate remote submit-for-review --auth-token $(System.AccessToken) --azdo-collection-uri $(System.TeamFoundationCollectionUri) --azdo-organization-name {ORGANIZATION_NAME} --target-directories $target_directories
else
echo -e "\033[0;31mUnsupported event type: $CI_PIPELINE_SOURCE. Only the \"merge_request_event\" and \"push\" sources are currently supported\033[0m"
exit_code=$?
exit $exit_code
fi