CI/CD¶
This is where you create and run application pipelines. The API lives under
/api/v1/cicd/**, and all three roles can call it.
CI/CD TemplatePick a base template and go to the App Deploy screen.
Golden PathsRecommended paths with a fixed tool combination. They lead to stack install.
CI/CD ListPipeline status, resources, vulnerabilities, and run history.
CI/CD HistoryDeployment records in chronological order.
App DeployThe developer's landing screen. Puts one app on a pipeline.
Stages a pipeline actually runs¶
The CI definition that Nullus writes to the repository lays out jobs in the order below. Stages whose conditions are not met are left out.
graph LR
S[SecretScan] --> D[DependencyScan] --> B[Build] --> A[SAST] --> I[ImageScan] --> P[Deploy]
| Stage | Tool | Enabled when |
|---|---|---|
SecretScan |
gitleaks | Always. The only way to turn it off is NULLUS_SECRET_DETECTION=off at run time |
DependencyScan |
Trivy (filesystem) | The stack provides an SCA endpoint |
Build |
docker build / docker push |
Always |
SAST |
sonar-scanner (-Dsonar.qualitygate.wait=true) |
The stack provides SonarQube. Default branch only |
ImageScan |
Trivy (image) | The stack provides Trivy |
Deploy |
Changes the manifest tag, then commits and pushes with [skip ci] |
Always |
SAST tells a Quality Gate failure (stack policy: block or warn) apart from an analysis failure
(analyzer-outage policy). sonar-scanner ends both with exit code 3, so only a run that uploaded its
analysis to SonarQube counts as a gate failure — a run that could not analyze is never passed, even under
the warn policy.
No job depends on the app type (web/backend/batch). The only difference is
that web also gets React source and a Dockerfile.
Argo CD does the actual deployment
The generated CI contains no argocd CLI call or sync job. The Deploy stage
stops at committing a new image tag to the deployment manifest; Argo CD
follows that commit and applies it.
The CI platform decides the definition file¶
What matters is the CI platform, not the source repository.
| CI platform | File written |
|---|---|
| GitLab CI | .gitlab-ci.yml |
| GitHub Actions | .github/workflows/nullus-ci.yml |
| Jenkins | Jenkinsfile |
The defaults per repository are GitLab → GitLab CI, GitHub → GitHub Actions, and Gitea → Jenkins.
Files committed together: the CI definition, Dockerfile, README.md,
deploy/deployment.yaml, deploy/service.yaml, .pre-commit-config.yaml, and
.gitleaks.toml. If gateway information is available, deploy/httproute.yaml is
included too. The route attaches to the gateway that actually exists in the stack namespace — its name
differs depending on whether the stack was installed from the screen or by the runbook, so it is looked
up when the pipeline is created.
deploy/ingress.yaml is not generated
The "Reload Deploy YAML files" button on the App Deploy screen
tries to fetch three files — deployment.yaml, service.yaml, and
ingress.yaml — but the third is never generated, so it always returns 404.
The six built-in templates¶
Migrations insert them into the pipeline_templates table.
| ID | Name | App type | Recorded stages |
|---|---|---|---|
web-backend-v1 |
User Custom Pipeline | backend | Build, Deploy |
batch-job-v1 |
Batch Job Pipeline | batch | Build, Deploy |
nullus-sample-backend-v1 |
Nullus Sample App — Backend | backend | GitClone, DockerBuild, ImageLoad, Deploy |
nullus-sample-frontend-v1 |
Nullus Sample App — Frontend | web | Same as above |
egovframe-boot-sample-v1 |
eGovFrame Boot Sample (Spring Boot) | backend | Build, Deploy |
egovframe-web-sample-v1 |
eGovFrame Web Sample (JSP) | backend | Same as above |
The two eGovFrame templates import their source repository when a pipeline is created — see CI/CD Template.
Template stages list fewer stages than actually run
The seed data was computed with SecretScan turned off, so the recorded stages
are at least one short of the stages that actually run. The real stages of
each pipeline are recorded separately in pipelines.stages when the pipeline
is created.
Templates do not bundle tools — tool choice comes from the stack.