In this lesson, you will learn how to weave automated formal verification and static analysis into your CI pipeline to catch critical logic errors before they reach your embedded hardware.
Moving Beyond Manual Verification
Up to this point, we have explored verifying system properties with model checking and analyzing worst-case execution time. However, performing these checks manually is error-prone and often skipped under tight deadlines. By integrating these tools directly into your CI pipeline (such as Jenkins, GitLab CI, or GitHub Actions), you ensure that every commit is automatically vetted against formal specifications.
The CI Pipeline Workflow
When a developer pushes code, the CI server should trigger a multi-stage verification gate:
- Static Analysis & Linting: First, enforce coding standards and detect data flow anomalies to catch common "low-hanging" bugs.
- Automated Unit Testing: Execute unit tests in a simulated environment to verify functional requirements.
- Formal Model Checking: Finally, run the model checker to prove that your critical system properties (e.g., "the motor controller never enters an unsafe state while the door is open") hold true for the current code implementation.
Practical Implementation
In a YAML-based CI pipeline, you define these as stages. If the model checker returns a counter-example, the CI build fails immediately:
stages:
- lint
- test
- formal_verify
formal_verify_job:
script:
- ./model_checker --spec safety_properties.smv --model system_impl.c
# The pipeline fails if the exit code is non-zero
allow_failure: false
By failing the build when formal proofs are violated, you prevent regressions in mission-critical logic that standard unit tests might miss. This creates a "trust but verify" loop: developers receive immediate feedback on whether their changes accidentally violated a safety property, ensuring that your system remains robust throughout the entire development lifecycle.
Key Takeaway: Integrating formal verification into CI transforms safety from a final, manual audit into a continuous, automated gate that prevents flawed logic from ever entering your codebase.