CI integration
Run SecureAI as a build check. Scan on every pull request, test on a schedule, and fail the build only where failing is warranted.
Authenticating a build agent
Browser login cannot run on a runner. An org admin issues a scoped CLI token from CLI access, you store it as a CI secret, and the CLI picks it up from SECUREAI_TOKEN.
| Variable | Required | Purpose |
|---|---|---|
SECUREAI_TOKEN | For upload and for TEST | Scoped CLI token issued from the dashboard. |
SECUREAI_SERVER | Yes | Control-plane URL, e.g. https://api.corelayersecurity.com. |
SECUREAI_TOKEN takes precedence over any stored session, so a runner with a cached credentials file still uses the token the pipeline supplied.
Scope the token down
Issue a separate token per pipeline, scoped to the project and environment that pipeline covers. Rotate it when someone leaves the team, and revoke rather than reuse when a repository is archived.
GitHub Actions
Scan every pull request. BUILD is offline and costs nothing, so it belongs on the critical path.
name: SecureAI
on:
pull_request:
push:
branches: [main]
jobs:
build-phase:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install SecureAI
run: |
curl -fsSL https://get.corelayersecurity.com/install.sh \
| SECUREAI_INSTALL_DIR="$HOME/.secureai/bin" sh
echo "$HOME/.secureai/bin" >> "$GITHUB_PATH"
- name: Static risk scan
env:
SECUREAI_SERVER: https://api.corelayersecurity.com
SECUREAI_TOKEN: ${{ secrets.SECUREAI_TOKEN }}
run: |
secureai scan ./prompts \
--fail-on high \
--format json \
--report assessment.html > findings.json
- name: Upload assessment
if: always()
uses: actions/upload-artifact@v4
with:
name: secureai-assessment
path: |
assessment.html
findings.jsonif: always() matters. A failing gate is exactly when you want the report.
Adversarial testing on a schedule
TEST sends real traffic and consumes tokens, so run it nightly against staging rather than on every push.
name: SecureAI nightly
on:
schedule:
- cron: '0 3 * * *'
workflow_dispatch:
jobs:
test-phase:
runs-on: ubuntu-latest
steps:
- name: Install SecureAI
run: |
curl -fsSL https://get.corelayersecurity.com/install.sh \
| SECUREAI_INSTALL_DIR="$HOME/.secureai/bin" sh
echo "$HOME/.secureai/bin" >> "$GITHUB_PATH"
- name: Adversarial probing
env:
SECUREAI_SERVER: https://api.corelayersecurity.com
SECUREAI_TOKEN: ${{ secrets.SECUREAI_TOKEN }}
run: |
secureai test \
--target ${{ vars.STAGING_ENDPOINT }} \
--api-key ${{ secrets.MODEL_API_KEY }} \
--intensity full \
--fail-asr 2 \
--rps 5You can also scaffold this file directly: secureai test init-ci.
GitLab CI
secureai:scan:
image: alpine:3.20
variables:
SECUREAI_SERVER: https://api.corelayersecurity.com
before_script:
- apk add --no-cache curl
- curl -fsSL https://get.corelayersecurity.com/install.sh | sh
script:
- secureai scan ./prompts --fail-on high --report assessment.html
artifacts:
when: always
paths:
- assessment.htmlExit codes
| Code | Meaning | What to do |
|---|---|---|
0 | Gate passed | Continue the pipeline. |
1 | Gate failed. Findings exceeded the threshold | Fail the job. This is a real result, not a malfunction. |
2 | The CLI errored. Bad flags, unreachable server, unreadable file | Fail the job and investigate the pipeline, not the findings. |
1 and 2 are deliberately different
Treating them the same hides broken automation behind “security failed the build.” If you alert on SecureAI failures, alert differently on 2. That is your token expiring or your endpoint being unreachable.
Choosing gates
- Start non-blocking. Run without
--fail-onfor a week and look at what a real codebase produces before you make anything mandatory. - Then gate on critical only.
--fail-on criticalblocks the things nobody argues about. - Tighten to high once the backlog is clear.
- Silence known-acceptable rules in config, not by loosening the gate for everything. See Configuration.
Catching it earlier
A pre-commit hook gives the same feedback before CI ever runs:
secureai scan install-hook