Adding the runner to your CI pipeline
Analysis runs in the CI pipeline where your code already lives - your source code never leaves your infrastructure. In the examples below, the runner is invoked with the project-specific token.
All examples pull the image from the AppArch Hub; see that page for authentication, language matching and common errors.
GitHub Actions
Section titled “GitHub Actions”name: AppArchon: [pull_request]jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # the target branch is then in the clone: the change's own files and its merge base - run: | echo "$APPARCH_INSTALLATION_KEY" | docker login hub.apparch.io -u "$APPARCH_INSTALLATION_ID" --password-stdin docker run --rm -v "$PWD:/workspace:ro" \ -e APPARCH_Collector__Token="$APPARCH_TOKEN" \ -e APPARCH_Collector__ApiUrl="https://api.yourdomain.com" \ -e GITHUB_EVENT_NAME -e GITHUB_REF -e GITHUB_REPOSITORY \ -e GITHUB_SERVER_URL -e GITHUB_BASE_REF -e GITHUB_SHA \ hub.apparch.io/collectors/dotnet:latest /workspace env: APPARCH_TOKEN: ${{ secrets.APPARCH_TOKEN }} APPARCH_INSTALLATION_ID: ${{ secrets.APPARCH_INSTALLATION_ID }} APPARCH_INSTALLATION_KEY: ${{ secrets.APPARCH_INSTALLATION_KEY }}GitLab CI
Section titled “GitLab CI”# Image pulls are authorized with your INSTALLATION credential, not the project token# (Settings → CI/CD → Variables):# DOCKER_AUTH_CONFIG = {"auths":{"hub.apparch.io":{"auth":"base64(<installation-id>:<installation-key>)"}}}archpilot: image: hub.apparch.io/collectors/dotnet:latest rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" variables: APPARCH_Collector__Token: "$APPARCH_TOKEN" APPARCH_Collector__ApiUrl: "https://api.yourdomain.com" script: # Optional flags: --modules archpilot,archscan (pin what runs). # --modules archpilot alone reads ONLY the merge request's changed files - the fast option # for MR pipelines; archscan / archsecurity are repository reports and read everything. # --fail-on critical (fail this step when findings at/above the level exist) - apparch "$CI_PROJECT_DIR"Bitbucket Pipelines
Section titled “Bitbucket Pipelines”pipelines: pull-requests: '**': - step: image: name: hub.apparch.io/collectors/dotnet:latest username: $APPARCH_INSTALLATION_ID password: $APPARCH_INSTALLATION_KEY run-as-user: 0 # the clone belongs to root; a PR run fetches the target branch into it script: - export APPARCH_Collector__Token="$APPARCH_TOKEN" - export APPARCH_Collector__ApiUrl="https://api.yourdomain.com" - apparch "$BITBUCKET_CLONE_DIR"Azure DevOps
Section titled “Azure DevOps”trigger: nonepr: ['*']pool: { vmImage: ubuntu-latest }steps: - checkout: self fetchDepth: 0 # the target branch is then in the clone: the change's own files and its merge base - script: | echo "$(APPARCH_INSTALLATION_KEY)" | docker login hub.apparch.io -u "$(APPARCH_INSTALLATION_ID)" --password-stdin docker run --rm -v "$(Build.SourcesDirectory):/workspace:ro" \ -e APPARCH_Collector__Token="$(APPARCH_TOKEN)" \ -e APPARCH_Collector__ApiUrl="https://api.yourdomain.com" \ -e SYSTEM_PULLREQUEST_PULLREQUESTID="$(System.PullRequest.PullRequestId)" \ -e SYSTEM_PULLREQUEST_TARGETBRANCH="$(System.PullRequest.TargetBranch)" \ -e SYSTEM_TEAMPROJECT="$(System.TeamProject)" \ -e BUILD_REPOSITORY_NAME="$(Build.Repository.Name)" \ -e SYSTEM_COLLECTIONURI="$(System.CollectionUri)" \ -e BUILD_SOURCEVERSION="$(Build.SourceVersion)" \ hub.apparch.io/collectors/dotnet:latest /workspaceJenkins
Section titled “Jenkins”pipeline { agent { docker { image 'hub.apparch.io/collectors/dotnet:latest' registryUrl 'https://hub.apparch.io' registryCredentialsId 'apparch-hub' } } environment { APPARCH_Collector__Token = credentials('APPARCH_TOKEN') APPARCH_Collector__ApiUrl = 'https://api.yourdomain.com' // PR review (ArchPilot) needs the MR context set explicitly; without these the run is a full scan (ArchScan). APPARCH_Collector__Provider__Type = 'gitlab' // gitlab | github | bitbucket | azuredevops APPARCH_Collector__Provider__ProjectId = 'group/project' APPARCH_Collector__Provider__PullRequestId = "${env.CHANGE_ID}" } stages { stage('AppArch') { steps { sh 'apparch "$WORKSPACE"' } } }}The next time a PR/MR is opened, ArchPilot leaves line-by-line comments. The runner picks the mode automatically: a PR/MR pipeline runs the fast review (ArchPilot), a push pipeline runs the full scan (ArchScan).
The container user
Section titled “The container user”The collector images run as a non-root user (uid 10001) and only read the checkout, which may belong to another user. On a pull request the collector compares the change with its target branch (the change’s own files, its merge base), so that branch must be in the clone:
- GitHub Actions and Azure DevOps: the examples check out the whole history (
fetch-depth: 0,fetchDepth: 0); the target branch is then already there and nothing is written. - GitLab CI and Jenkins: work as written (GitLab’s clone is writable for the job, Jenkins runs the container as its own user).
- Bitbucket Pipelines: the clone always belongs to root and the collector fetches the target branch
into it, so the example runs the step as root (
run-as-user: 0).
Without this the run still passes, but it reviews every finding instead of the change’s and skips the
checks that compare with the target branch (a removed authorization, a new dependency cycle). If your
runner insists on root elsewhere, say so explicitly: docker run --user 0 ..., a Kubernetes
securityContext.runAsUser: 0.
Self-signed or internal-CA certificates
Section titled “Self-signed or internal-CA certificates”If your AppArch installation is served with a certificate the CI runner does not trust - an internal CA, or a self-signed cert - the run fails at the rule fetch with a TLS error. Two ways out, in order of preference:
- Trust the CA in the runner image. The certificate is then verified like any other and nothing about the collector changes.
- Turn verification off with
SslVerify:
SslVerify=false # or SSL_VERIFY, or APPARCH_Collector__SslVerifyfalse, 0, no and off disable it; anything else - empty included - leaves it on. The .NET
collector also accepts the --no-ssl-verify flag. Every run prints ssl verify on or
ssl verify OFF - server certificate not checked in its boot block, so a pipeline that weakens
it says so in its own log.