GitHub AST Orchestrator
The Conviso Platform GitHub AST Orchestrator runs Conviso AST from one GitHub repository (the orchestrator). Application repositories do not need a Conviso workflow.
When an eligible pull request is merged, Conviso calls GitHub Actions workflow_dispatch on the orchestrator and passes the target repository and branch. The workflow obtains a short-lived clone credential from the Platform (using your API key), checks out the target repository, runs conviso-ast, and sends findings to the mapped asset.
You do not store a GitHub Personal Access Token for cloning.
How it worksβ
What Conviso checks before dispatching:
- The event is a pull request that was merged (
action: closedandmerged: true). - AST Scans is enabled on the GitHub integration.
- The repository is an imported asset that is enabled.
- The PR base branch matches the configured merge target (see Merge target branch below).
The Actions run always appears on the orchestrator repository (not on the application repository).
Execution costs: Jobs run on your GitHub Actions runners and consume your organizationβs Actions minutes.
Before you beginβ
Work in this order: GitHub setup first, then Conviso Platform.
You need:
- GitHub Integration connected (GitHub App installed).
- At least one application repository imported as an asset and enabled.
- A dedicated orchestrator repository (or an empty repo you will use only for this). Example / template: convisoappsec/pipeline-orchestrator.
- Permission to create an Actions repository secret on the orchestrator.
- A Conviso API key for the same environment you will scan against (production or staging).
- The GitHub App must have access to the orchestrator and to every target repository you will scan. Prefer All repositories on the App installation.
| Term | Exact meaning |
|---|---|
| Orchestrator repository | GitHub repo that contains .github/workflows/ast.yml. Conviso triggers this repo only. |
| Target repository | Application repo imported as an asset. It must not rely on a local Conviso workflow for this flow. |
| Ref | Branch or tag of the orchestrator where GitHub loads ast.yml when Conviso calls workflow_dispatch. If you leave Ref empty in Conviso, dispatch defaults to main. |
| Merge target branch | The PR base branch on the target repo that is allowed to trigger a scan (for example main). See below. |
| Asset | Imported repository in Conviso (owner/repo) where findings are stored. |
Merge target branchβ
Conviso compares the merged PRβs base branch to:
- The assetβs configured AST / branch mapping, if set; otherwise
- The integration Ref (
orchestrator_ref).
| Configuration | What triggers a scan |
|---|---|
Asset branch = master, Ref = main | Only merges into master on that asset |
Asset branch empty, Ref = main | Only merges into main on that asset |
| Asset branch empty and Ref empty | No branch filter (any base branch can trigger). Prefer setting Ref explicitly. |
Ref is still the orchestrator branch that holds the workflow. It is reused as the default merge-target filter when the asset has no branch of its own. Those are two roles of the same field β do not confuse βwhere ast.yml livesβ with βany branch on the targetβ.
Part 1 β GitHub setupβ
Step 1 β Create the orchestrator repositoryβ
- Create a GitHub repository (recommended name:
conviso-ast-orchestrator), or copy from convisoappsec/pipeline-orchestrator and keep only.github/workflows/ast.yml. - Choose the branch that will contain the workflow (almost always
main). That value is what you will set as Ref in Conviso.
Step 2 β Create the CONVISO_API_KEY secretβ
In the orchestrator repository (not the target):
- Open Settings β Secrets and variables β Actions.
- Under Repository secrets, create:
| Name | Type | Required |
|---|---|---|
CONVISO_API_KEY | Repository secret | Yes |
Use the API key for the same Conviso environment as the Platform you configured (production vs staging).
Repository secret CONVISO_API_KEY under Settings β Secrets and variables β Actions.

You may add an Actions variable CONVISO_COMPANY_ID. The workflow uses it only when the company_id input is empty (typical for a manual Run workflow). When Conviso dispatches after a merge or Run AST, it sends company_id in the inputs, so the variable is not required for Platform-triggered runs.
Do not create a GitHub PAT for clone. The workflow calls conviso-ast-repository-token --provider github, and the Platform returns a GitHub App installation token scoped to the single target repository, with read-only contents access, valid for about one hour.
Step 3 β Add .github/workflows/ast.ymlβ
GitHub Actions only loads workflows from .github/workflows/. A file at the repository root is ignored.
Public template: convisoappsec/pipeline-orchestrator
Workflow file: .github/workflows/ast.yml
On the orchestrator branch you will set as Ref (usually main):
- Create
.github/workflows/if needed. - Create
ast.ymlso the full path is exactly.github/workflows/ast.yml. - Paste the YAML below (or copy it from the example repo).
Orchestrator repository with .github/workflows/ast.yml on main.

name: AST Scan Orchestrator
on:
workflow_dispatch:
inputs:
repo_full_name:
description: "Repository to scan (owner/repo)"
required: true
type: string
branch:
description: "Branch to scan"
required: true
type: string
commit_sha:
description: "Merge commit SHA (post-merge)"
required: false
type: string
pr_number:
description: "Pull request number (post-merge)"
required: false
type: string
api_url:
description: "Conviso API URL"
required: false
type: string
default: https://api.convisoappsec.com
company_id:
description: "Conviso company id"
required: false
type: string
asset_id:
description: "Conviso asset id"
required: false
type: string
scan_run_id:
description: "Scan run id from the platform"
required: false
type: string
jobs:
run-ast-scan:
runs-on: ubuntu-latest
container:
image: convisoappsec/convisoast_v2:latest
steps:
- name: Get repository token
id: repo_token
env:
CONVISO_APIKEY: ${{ secrets.CONVISO_API_KEY }}
API_URL: ${{ inputs.api_url }}
CONVISO_REPO_FULL_NAME: ${{ inputs.repo_full_name }}
ASSET_ID: ${{ inputs.asset_id }}
SCAN_RUN_ID: ${{ inputs.scan_run_id }}
run: |
set -euo pipefail
export CONVISO_BASE_URL="${API_URL:-https://api.convisoappsec.com}"
CONVISO_BASE_URL="${CONVISO_BASE_URL%/}"
case "$CONVISO_BASE_URL" in
https://app.convisoappsec.com)
export CONVISO_BASE_URL="https://api.convisoappsec.com"
;;
https://staging.convisoappsec.com)
export CONVISO_BASE_URL="https://api.staging.convisoappsec.com"
;;
esac
case "${ASSET_ID:-}" in
""|none|0) unset CONVISO_ASSET_ID || true ;;
*) export CONVISO_ASSET_ID="$ASSET_ID" ;;
esac
case "${SCAN_RUN_ID:-}" in
""|none|0) unset CONVISO_SCAN_RUN_ID || true ;;
*) export CONVISO_SCAN_RUN_ID="$SCAN_RUN_ID" ;;
esac
TOKEN=$(conviso-ast-repository-token --provider github)
echo "::add-mask::$TOKEN"
echo "token=$TOKEN" >> "$GITHUB_OUTPUT"
echo "base_url=$CONVISO_BASE_URL" >> "$GITHUB_OUTPUT"
- name: Checkout target repository
uses: actions/checkout@v6
with:
repository: ${{ inputs.repo_full_name }}
ref: ${{ inputs.branch }}
fetch-depth: 0
token: ${{ steps.repo_token.outputs.token }}
- name: Run Conviso AST
env:
CONVISO_APIKEY: ${{ secrets.CONVISO_API_KEY }}
CONVISO_BASE_URL: ${{ steps.repo_token.outputs.base_url }}
CONVISO_COMPANY_ID: ${{ inputs.company_id || vars.CONVISO_COMPANY_ID }}
ASSET_ID: ${{ inputs.asset_id }}
SCAN_RUN_ID: ${{ inputs.scan_run_id }}
CONVISO_BRANCH: ${{ inputs.branch }}
GIT_CONFIG_COUNT: "1"
GIT_CONFIG_KEY_0: safe.directory
GIT_CONFIG_VALUE_0: "*"
run: |
set -euo pipefail
case "${ASSET_ID:-}" in
""|none|0) unset CONVISO_ASSET_ID || true ;;
*) export CONVISO_ASSET_ID="$ASSET_ID" ;;
esac
case "${SCAN_RUN_ID:-}" in
""|none|0) unset CONVISO_SCAN_RUN_ID || true ;;
*) export CONVISO_SCAN_RUN_ID="$SCAN_RUN_ID" ;;
esac
conviso-ast -p . -o /tmp/conviso-ast-session.zip
- name: Upload session log
if: always()
uses: actions/upload-artifact@v4
with:
name: conviso-ast-session
path: /tmp/conviso-ast-session.zip
if-no-files-found: ignore
- Commit and push to that Ref branch.
- Path on disk:
.github/workflows/ast.ymlonly. - In Conviso, set the workflow field to the file name
ast.yml(not.github/workflows/ast.yml). Conviso normalizes a full path to the basename, but the UI expects the file name used by the GitHub Actions API. - This template checks out
inputs.branch(the PR base branch after merge). Conviso also sendscommit_shaandpr_numberfor correlation; the template above does not passcommit_shaintoactions/checkout.
Part 2 β Conviso Platform setupβ
Step 4 β Configure the orchestratorβ
- Open Integrations β GitHub.
- Turn AST Scans on.
(GitHub Advanced Security is a separate toggle. It is not required for the orchestrator merge flow described here.) - Fill Orchestrator Configuration:
- Orchestrator Repo β
owner/repoof the orchestrator. - Workflow Filename or ID β
ast.yml. - Ref β orchestrator branch/tag that contains
.github/workflows/ast.yml(e.g.main). If empty, Conviso dispatches with refmain.
- Orchestrator Repo β
- Save.

Step 5 β Assets and merge targetβ
- Confirm each application repository is imported and enabled.
- Set the asset branch mapping when the merge target is not the same as Ref (example: Ref
mainon the orchestrator, merges intomasteron the asset β map the asset tomaster). - If the asset has no branch mapping, merges must go into the branch named by Ref (or any branch only if Ref is also empty β avoid that setup).
End-to-end flow (after setup)β
- Developer merges a PR into the configured merge target on an imported, enabled asset.
- Conviso validates the event and configuration, then calls
workflow_dispatchonowner/orchestrator/ast.yml/ Ref. - Inputs include at least:
repo_full_name,branch(PR base),commit_sha,pr_number,api_url,company_id,asset_id(blank values may be omitted). - Job steps: issue repository token β checkout target at
branchβ runconviso-astβ upload session artifact. - Findings appear on the asset in Conviso Platform.
- In GitHub, open the orchestrator β Actions β AST Scan Orchestrator to inspect the run.
Validation checklistβ
| Check | Expected |
|---|---|
| Secret | CONVISO_API_KEY exists on the orchestrator |
| Path | .github/workflows/ast.yml is on the Ref branch |
| Conviso | Orchestrator owner/repo + ast.yml + Ref saved; AST Scans on |
| Asset | Target repo imported, enabled; merge target branch matches mapping or Ref |
| After merge | New run under orchestrator Actions; findings (or a clean result) on the asset |
Successful orchestrator run: Get repository token β Checkout β Run Conviso AST.

Scan result on the asset in Conviso Platform (Conviso AST).

Manual test (optional): on the orchestrator, Actions β AST Scan Orchestrator β Run workflow. Set repo_full_name and branch to an imported asset. Set api_url if you are not on production defaults. Set company_id or define CONVISO_COMPANY_ID.
Troubleshootingβ
| Symptom | Cause / fix |
|---|---|
| Merge done, no Actions run | AST Scans off; orchestrator fields incomplete; asset disabled or not imported; PR base branch β asset branch / Ref; GitHub App cannot see the repos |
| Workflow never listed | File not under .github/workflows/, or not on the Ref branch Conviso uses |
| Token step fails (HTTP 4xx) | repo_full_name not an imported asset for that API key/company; wrong environment (CONVISO_API_KEY vs api_url) |
| Checkout 403 | GitHub App lacks access to the target repository |
Scanner missing CONVISO_COMPANY_ID | Manual run without company_id input and without variable CONVISO_COMPANY_ID |
| Wrong code scanned | Merge target / branch input mismatch; confirm you merged into the configured base branch |
Related guidesβ
Contribute to the Docs
Found something outdated or missing? Help us improve the documentation with a quick suggestion or edit.
How to contributeResources
By exploring our content, you'll find resources that will enhance your understanding of the importance of a Security Application Program.
Conviso Blog: Explore our blog, which offers a collection of articles and posts covering a wide range of AppSec topics. The content on the blog is primarily in English.
Conviso's YouTube Channel: Access a wealth of informative videos covering various topics related to AppSec. Please note that the content is primarily in Portuguese.