Building a Hardened, Containerized CI/CD Pipeline - 4

Phase 4: Implementing the Standardized 3-Stage Pipeline Configuration

Posted by yuanhang on June 02, 2026

With the runner provisioned and the compiler image safely versioned in our registry, we can now orchestrate the target firmware repository's continuous lifecycle.

The pipeline strictly enforces a 3-stage sequential validation architecture: Lint → Build → Test.

[ Commit ] ──> [ Stage: lint ] ──> [ Stage: build ] ──> [ Stage: test ] (cppcheck) (ARM Binary) (GoogleTest)

Complete Target .gitlab-ci.yml Template

stages:
  - lint
  - build
  - test
# Global variables across jobs
variables:
  COMPILER_IMAGE: "gitlab-tae.zofre.de:5005/devsecops/ci-pipeline_crosscompile/renesas-cross-compile-toolchain:v10.3"
# --- STAGE 1: LINTING ---
run-cppcheck:
  stage: lint
  image: neszt/cppcheck:latest  # Specialized tool container keeps images isolated
  tags:
    - renesas-project
  script:
    - cppcheck --enable=all --error-exitcode=1 src/
# --- STAGE 2: FIRMWARE COMPILATION ---
compile-firmware:
  stage: build
  image: $COMPILER_IMAGE
  tags:
    - renesas-project
  script:
    - mkdir build && cd build
    - cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm-none-eabi.cmake ..
    - make -j$(nproc)
  artifacts:
    name: "firmware-production-$CI_COMMIT_SHORT_SHA"
    expire_in: 14 days
    paths:
      - build/*.hex
      - build/*.elf
# --- STAGE 3: UNIT TESTING ---
unit-tests:
  stage: test
  image: ubuntu:24.04  # Native test runner environment
  tags:
    - renesas-project
  before_script:
    - apt-get update && apt-get install -y libgtest-dev cmake make g++
  script:
    - mkdir test_build && cd test_build
    - cmake ../tests
    - make
    - ./run_unit_tests

Key Architectural Engineering Wins

1. Hardened Error Separation

By utilizing specialized standalone validation images for static analysis (neszt/cppcheck), native environments for host testing (ubuntu), and an optimized toolchain image explicitly for cross-compilation, we guarantee maximum resource segregation.

2. Traceable Artifact Preservation

The production artifacts (.hex and .elf files) are securely preserved in GitLab for 14 days following successful compilation. This enables QA teams or hardware flashing fixtures to instantly download verified binaries mapped down to the specific git commit ID hash.

3. Immutable Infrastructure as Code (IaC)

Because every system parameter—from the runner config, network hooks, and toolchain dependencies up to pipeline execution states—is fully articulated via text files (.yml, Dockerfile, toml), our complete development infrastructure can be instantly recovered, audited, or replicated on a completely blank target server in minutes.