FortiCNAPP Code Security integration for Azure DevOps. Runs SCA (Software Composition Analysis) and IaC (Infrastructure as Code) scanning on your repositories, posting comparison results as PR comments.
- A FortiCNAPP account with API credentials
- An Azure DevOps project with a Git repository
- Go to Pipelines > Library in your Azure DevOps project
- Click + Variable group and name it
forticnapp-credentials(or any name you prefer) - Add the following variables:
| Variable | Description | Secret? |
|---|---|---|
LW_ACCOUNT |
FortiCNAPP account name (e.g., mycompany.lacework.net) |
No |
LW_API_KEY |
FortiCNAPP API key | Yes |
LW_API_SECRET |
FortiCNAPP API secret | Yes |
- Click Save
You can find your API credentials in the FortiCNAPP console under Settings > API Keys.
Create an azure-pipelines.yml in the root of your repository:
trigger:
- main
pr:
- main
variables:
- group: forticnapp-credentials
pool:
vmImage: 'ubuntu-latest'
steps:
- checkout: self
fetchDepth: 0
- script: |
docker run \
-v $(Build.SourcesDirectory):/app/src \
-e WORKSPACE=src \
-e LW_ACCOUNT="$(LW_ACCOUNT)" \
-e LW_API_KEY="$(LW_API_KEY)" \
-e LW_API_SECRET="$(LW_API_SECRET)" \
-e TF_BUILD \
-e BUILD_REASON \
-e BUILD_SOURCEBRANCHNAME \
-e BUILD_SOURCEBRANCH \
-e BUILD_REPOSITORY_ID \
-e BUILD_REPOSITORY_NAME \
-e BUILD_BUILDID \
-e BUILD_BUILDNUMBER \
-e BUILD_DEFINITIONNAME \
-e SYSTEM_COLLECTIONURI \
-e SYSTEM_TEAMFOUNDATIONCOLLECTIONURI \
-e SYSTEM_TEAMPROJECT \
-e SYSTEM_DEFINITIONID \
-e SYSTEM_PULLREQUEST_SOURCEBRANCH \
-e SYSTEM_PULLREQUEST_TARGETBRANCH \
-e SYSTEM_PULLREQUEST_PULLREQUESTID \
-e SYSTEM_ACCESSTOKEN \
lacework/code-security-azure:latest
displayName: 'FortiCNAPP Code Security Scan'
env:
LW_API_KEY: $(LW_API_KEY)
LW_API_SECRET: $(LW_API_SECRET)
SYSTEM_ACCESSTOKEN: $(System.AccessToken)Important notes:
fetchDepth: 0is required so the scanner can fetch and check out the target branch during PR comparison scans.- Secret variables (
LW_API_KEY,LW_API_SECRET,SYSTEM_ACCESSTOKEN) must be explicitly mapped in theenv:block — Azure DevOps does not automatically pass secrets to scripts.
- Go to Pipelines in the left navigation
- Click New pipeline
- Select Azure Repos Git and pick your repository
- Choose Existing Azure Pipelines YAML file and select
/azure-pipelines.yml - Click Run (or Save, then Run)
After this initial setup, the pipeline will trigger automatically on pushes and PRs.
For the integration to post PR comments, the build service account needs write access to pull requests:
- Go to Project Settings > Repos > Repositories
- Select your repository
- Click the Security tab
- Find the build service account — it will be named something like
<Project Name> Build Service (<Org Name>) - Set Contribute to pull requests to Allow
Without this permission, scanning will work but PR comments will fail with a TF401027 error.
Azure DevOps YAML pr: triggers may not fire in all configurations. For reliable PR scanning, set up a branch policy:
- Go to Repos > Branches
- Click the
...menu on your target branch (e.g.,main) and select Branch policies - Under Build Validation, click + Add build policy
- Select your pipeline, leave defaults, and save
This ensures the scan runs automatically whenever a PR targets that branch.
| Variable | Default | Description |
|---|---|---|
LW_SUBACCOUNT |
(empty) | FortiCNAPP sub-account for multi-tenant setups |
Add these as additional -e flags in the docker run command.
When code is pushed to a branch, the scanner runs SCA and IaC analysis and uploads results to the FortiCNAPP platform.
When a PR is created or updated:
- Scans the source branch (new code)
- Checks out and scans the target branch (existing code)
- Compares results to identify newly introduced issues
- Posts (or updates) a PR comment thread with the findings
The PR comment thread is updated in-place on subsequent pushes — no duplicate comments are created.
| Symptom | Cause | Fix |
|---|---|---|
TF401027: You need the Git 'PullRequestContribute' permission |
Build service lacks PR write access | Follow step 4 above to grant permissions |
| PR scan doesn't trigger automatically | YAML PR triggers not active or branch policy missing | Set up Build Validation as described in step 5 |
fatal: could not read Password errors in scan logs |
Scanner tries git remote show origin inside the container — this is expected and non-fatal |
No action needed; the scanner continues successfully |
ERROR unknown command "sca" for "lacework" |
Container running with wrong HOME directory | Ensure you're using lacework/code-security-azure:latest (not the base lacework/codesec image directly) |
| Scan exits with code 160 | Violations found that exceed the severity threshold | This is expected behavior — the scan completed successfully and found issues |
Apache 2.0 — see LICENSE.txt.
The scanning tools included in the Docker image are licensed separately.