5.7: Support Process Tools and Automation
Tool Landscape Overview
The following diagram maps the support process tool ecosystem, showing how QA, verification, configuration management, and problem resolution tools interconnect across the SUP process group.
Tool Comparison Matrix
QA and Verification Tools
Note: Tool costs use relative indicators; verify current pricing with vendors.
| Tool | Type | AI Features | ASPICE Fit | Cost |
|---|---|---|---|---|
| Jira | Issue tracking | Basic AI (Atlassian Intelligence) | SUP.1, SUP.9, SUP.10 | Medium-High |
| Azure DevOps | ALM | Copilot integration | Full SUP | Medium-High |
| Polarion | ALM | Limited AI | Full SUP | High |
| codebeamer | ALM | AI roadmap | Full SUP | High |
| SonarQube | Static analysis | AI rules | SUP.2 | Free-High |
| Crucible | Code review | None | SUP.2 | Medium |
| Gerrit | Code review | None | SUP.2 | Free |
| CodeRabbit | AI review | Full AI | SUP.2 | Medium |
Configuration Management Tools
| Tool | Hosting | AI Features | Embedded Fit | Scalability |
|---|---|---|---|---|
| GitLab | Self/Cloud | Duo (AI) | Excellent | High |
| GitHub | Cloud/Enterprise | Copilot | Good | High |
| Bitbucket | Self/Cloud | Limited | Good | Medium |
| Azure Repos | Cloud | Copilot | Good | High |
| Subversion | Self | None | Legacy | Medium |
| Perforce | Self/Cloud | None | Large binary | Very High |
Integrated Support Process Platform
Architecture Overview
The diagram below shows the architecture of an integrated support process platform, illustrating how an AI analysis engine connects to QA, CM, and problem resolution subsystems through a unified data layer.
GitLab-Based SUP Implementation
Complete CI/CD Pipeline
# .gitlab-ci.yml - Complete SUP Process Pipeline
stages:
- validate
- analyze
- review
- build
- test
- baseline
- release
variables:
ASPICE_PROJECT: "BCM-DoorLock"
BASELINE_BRANCH: "main"
# ============================================================
# SUP.8 Configuration Management
# ============================================================
cm_validation:
stage: validate
script:
# Commit message convention check
- |
PATTERN="^(feat|fix|docs|refactor|test|chore)\([a-zA-Z0-9-]+\): .{10,}"
if ! echo "$CI_COMMIT_MESSAGE" | head -1 | grep -qE "$PATTERN"; then
echo "ERROR: Commit message does not follow convention"
echo "Expected: type(scope): description (min 10 chars)"
echo "Got: $(echo "$CI_COMMIT_MESSAGE" | head -1)"
exit 1
fi
# Branch naming validation
- |
BRANCH_PATTERN="^(main|develop|feature/|bugfix/|release/|hotfix/)"
if ! echo "$CI_COMMIT_BRANCH" | grep -qE "$BRANCH_PATTERN"; then
echo "ERROR: Branch name does not follow convention"
exit 1
fi
# Check required files exist
- test -f VERSION
- test -f CHANGELOG.md
# Validate version format
- grep -qE "^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$" VERSION
rules:
- if: $CI_PIPELINE_SOURCE == "push"
# ============================================================
# SUP.2 Verification - Static Analysis
# ============================================================
static_analysis:
stage: analyze
image: sonarqube-scanner:latest
script:
# Run MISRA compliance check
- cppcheck --enable=all --std=c11 --addon=misra.json src/ 2>&1 | tee misra_report.txt
# Run static analysis
- sonar-scanner \
-Dsonar.projectKey=${ASPICE_PROJECT} \
-Dsonar.sources=src \
-Dsonar.tests=test \
-Dsonar.c.coverage.reportPaths=coverage.xml
# Check quality gate
- |
GATE_STATUS=$(curl -s "$SONAR_HOST/api/qualitygates/project_status?projectKey=${ASPICE_PROJECT}" | jq -r '.projectStatus.status')
if [ "$GATE_STATUS" != "OK" ]; then
echo "Quality gate failed: $GATE_STATUS"
exit 1
fi
artifacts:
paths:
- misra_report.txt
- sonar-report.json
reports:
codequality: sonar-report.json
ai_code_review:
stage: analyze
image: python:3.11
script:
# AI-assisted code review
- pip install openai gitpython
- python scripts/ai_review.py --diff "$CI_COMMIT_SHA~1..$CI_COMMIT_SHA"
artifacts:
paths:
- ai_review_report.md
allow_failure: true # AI review is advisory
# ============================================================
# SUP.9 Problem Resolution - Automated Checks
# ============================================================
problem_check:
stage: analyze
script:
# Check for TODO/FIXME markers that should be issues
- |
TODO_COUNT=$(grep -rn "TODO\|FIXME" src/ --include="*.c" --include="*.h" | wc -l)
if [ "$TODO_COUNT" -gt 10 ]; then
echo "WARNING: $TODO_COUNT TODO/FIXME markers found"
grep -rn "TODO\|FIXME" src/ --include="*.c" --include="*.h"
fi
# Check for linked issues in commit
- |
if echo "$CI_COMMIT_MESSAGE" | grep -qE "(Fixes|Closes|Resolves) #[0-9]+"; then
ISSUE_ID=$(echo "$CI_COMMIT_MESSAGE" | grep -oE "#[0-9]+" | head -1)
echo "Commit linked to issue: $ISSUE_ID"
fi
allow_failure: true
# ============================================================
# SUP.10 Change Request Verification
# ============================================================
change_impact:
stage: analyze
script:
# Generate impact report for changes
- python scripts/impact_analysis.py \
--base $CI_MERGE_REQUEST_TARGET_BRANCH_SHA \
--head $CI_COMMIT_SHA \
--output impact_report.json
# Check if high-impact changes require CR
- |
HIGH_IMPACT=$(jq '.high_impact_files | length' impact_report.json)
if [ "$HIGH_IMPACT" -gt 0 ]; then
echo "High-impact changes detected. Ensure CR is approved."
jq '.high_impact_files' impact_report.json
fi
artifacts:
paths:
- impact_report.json
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# ============================================================
# Build Stage
# ============================================================
build:
stage: build
image: arm-gcc:12.2
script:
- mkdir -p build && cd build
- cmake -DCMAKE_BUILD_TYPE=Release ..
- make -j$(nproc)
- make install DESTDIR=../artifacts
artifacts:
paths:
- artifacts/
- build/bcm_doorlock.elf
- build/bcm_doorlock.map
# ============================================================
# Test Stage
# ============================================================
unit_tests:
stage: test
script:
- cd build
- ctest --output-on-failure --output-junit test_results.xml
- gcovr --xml-pretty -o coverage.xml
artifacts:
paths:
- build/test_results.xml
- build/coverage.xml
reports:
junit: build/test_results.xml
coverage_report:
coverage_format: cobertura
path: build/coverage.xml
# ============================================================
# SUP.8 Baseline Management
# ============================================================
baseline_create:
stage: baseline
script:
# Verify all work products present
- python scripts/verify_work_products.py --process SWE
# Generate baseline manifest
- |
cat > baseline_manifest.json << EOF
{
"baseline_id": "BL-${CI_COMMIT_TAG}",
"date": "$(date -Iseconds)",
"git_tag": "${CI_COMMIT_TAG}",
"git_sha": "${CI_COMMIT_SHA}",
"artifacts": {
"binary": "bcm_doorlock.elf",
"map": "bcm_doorlock.map",
"version": "$(cat VERSION)"
},
"verification": {
"tests_passed": true,
"coverage": "$(grep -oP 'line-rate="\K[^"]+' build/coverage.xml)",
"static_analysis": "pass"
}
}
EOF
# Archive baseline
- tar -czf baseline-${CI_COMMIT_TAG}.tar.gz \
artifacts/ \
baseline_manifest.json \
build/test_results.xml \
build/coverage.xml
artifacts:
paths:
- baseline-*.tar.gz
- baseline_manifest.json
rules:
- if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/
release:
stage: release
script:
# Create release notes from changelog
- python scripts/extract_changelog.py --version ${CI_COMMIT_TAG} > release_notes.md
# Upload to release registry
- |
curl -X POST "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/releases" \
-H "PRIVATE-TOKEN: ${CI_JOB_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"tag_name\": \"${CI_COMMIT_TAG}\",
\"name\": \"Release ${CI_COMMIT_TAG}\",
\"description\": \"$(cat release_notes.md)\"
}"
rules:
- if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/
AI-Powered Review Automation
Code Review Bot
#!/usr/bin/env python3
"""
AI-assisted code review for SUP.2 compliance.
"""
import os
import subprocess
from dataclasses import dataclass
from typing import List, Dict, Optional
from openai import OpenAI
@dataclass
class ReviewFinding:
"""Single review finding."""
file: str
line: int
severity: str # critical, major, minor, suggestion
category: str
description: str
suggestion: Optional[str] = None
class AICodeReviewer:
"""AI-assisted code reviewer for embedded software."""
def __init__(self):
# Configure for your preferred LLM provider (OpenAI, Anthropic, etc.)
self.client = OpenAI()
self.model = "gpt-4" # Or use Claude, other models as appropriate
def get_diff(self, commit_range: str) -> str:
"""Get git diff for analysis."""
result = subprocess.run(
["git", "diff", commit_range, "--", "*.c", "*.h"],
capture_output=True,
text=True
)
return result.stdout
def analyze_diff(self, diff: str, context: Dict) -> List[ReviewFinding]:
"""Perform AI analysis of code changes."""
prompt = f"""
Review this embedded C code change for an automotive BCM project.
Standards to check:
- MISRA C:2012 compliance
- Safety-critical coding practices
- Memory safety (no buffer overflows, null pointers)
- Timing considerations (no blocking in ISR)
- Error handling completeness
Project context:
- Target: ARM Cortex-M4
- RTOS: FreeRTOS
- Safety: ISO 26262 ASIL-B
Code diff:
```diff
{diff}
```
Provide findings in this format:
FINDING:
- File: <filename>
- Line: <line number>
- Severity: <critical|major|minor|suggestion>
- Category: <safety|misra|performance|maintainability>
- Description: <what is wrong>
- Suggestion: <how to fix>
Focus on actual issues, not style preferences.
"""
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": "You are an expert embedded software reviewer."},
{"role": "user", "content": prompt}
],
temperature=0.1
)
return self._parse_findings(response.choices[0].message.content)
def _parse_findings(self, response: str) -> List[ReviewFinding]:
"""Parse AI response into structured findings."""
findings = []
current = {}
for line in response.split('\n'):
line = line.strip()
if line.startswith('- File:'):
current['file'] = line.split(':', 1)[1].strip()
elif line.startswith('- Line:'):
current['line'] = int(line.split(':', 1)[1].strip())
elif line.startswith('- Severity:'):
current['severity'] = line.split(':', 1)[1].strip().lower()
elif line.startswith('- Category:'):
current['category'] = line.split(':', 1)[1].strip()
elif line.startswith('- Description:'):
current['description'] = line.split(':', 1)[1].strip()
elif line.startswith('- Suggestion:'):
current['suggestion'] = line.split(':', 1)[1].strip()
# Complete finding
if all(k in current for k in ['file', 'line', 'severity', 'category', 'description']):
findings.append(ReviewFinding(**current))
current = {}
return findings
def generate_report(self, findings: List[ReviewFinding]) -> str:
"""Generate markdown review report."""
report = ["# AI Code Review Report\n"]
report.append(f"**Generated**: {subprocess.run(['date', '-Iseconds'], capture_output=True, text=True).stdout.strip()}\n")
# Summary
summary = {
'critical': len([f for f in findings if f.severity == 'critical']),
'major': len([f for f in findings if f.severity == 'major']),
'minor': len([f for f in findings if f.severity == 'minor']),
'suggestion': len([f for f in findings if f.severity == 'suggestion'])
}
report.append("## Summary\n")
report.append(f"| Severity | Count |")
report.append(f"|----------|-------|")
for sev, count in summary.items():
report.append(f"| {sev.title()} | {count} |")
# Recommendation
if summary['critical'] > 0:
recommendation = "BLOCK - Critical issues must be resolved"
elif summary['major'] > 0:
recommendation = "REVIEW - Major issues require attention"
else:
recommendation = "APPROVE - No blocking issues"
report.append(f"\n**Recommendation**: {recommendation}\n")
# Detailed findings
report.append("## Findings\n")
for i, finding in enumerate(findings, 1):
icon = {'critical': '[HIGH]', 'major': '🟠', 'minor': '[MED]', 'suggestion': '[TIP]'}
report.append(f"### {icon.get(finding.severity, '❓')} Finding {i}: {finding.category.title()}\n")
report.append(f"**File**: `{finding.file}:{finding.line}`\n")
report.append(f"**Severity**: {finding.severity.title()}\n")
report.append(f"\n{finding.description}\n")
if finding.suggestion:
report.append(f"\n**Suggestion**: {finding.suggestion}\n")
report.append("---\n")
report.append("\n*This report was generated by AI and requires human review for final decision.*\n")
return '\n'.join(report)
def main():
"""Main entry point for CI/CD integration."""
import argparse
parser = argparse.ArgumentParser(description='AI Code Review')
parser.add_argument('--diff', required=True, help='Commit range for diff')
parser.add_argument('--output', default='ai_review_report.md', help='Output file')
args = parser.parse_args()
reviewer = AICodeReviewer()
# Get diff
diff = reviewer.get_diff(args.diff)
if not diff:
print("No changes to review")
return
# Analyze
findings = reviewer.analyze_diff(diff, {})
# Generate report
report = reviewer.generate_report(findings)
# Write output
with open(args.output, 'w') as f:
f.write(report)
print(f"Review report written to {args.output}")
print(f"Found {len(findings)} issues")
# Exit code based on findings
critical_count = len([f for f in findings if f.severity == 'critical'])
if critical_count > 0:
print(f"BLOCKED: {critical_count} critical issues found")
exit(1)
if __name__ == '__main__':
main()
Impact Analysis Automation
Change Impact Analyzer
#!/usr/bin/env python3
"""
AI-assisted change impact analysis for SUP.10.
"""
import subprocess
import json
from dataclasses import dataclass, asdict
from typing import List, Dict, Set
from pathlib import Path
@dataclass
class ImpactAssessment:
"""Impact assessment for a changed file."""
file: str
impact_level: str # high, medium, low
requirements_affected: List[str]
tests_affected: List[str]
estimated_effort: str
risk_factors: List[str]
class ChangeImpactAnalyzer:
"""Analyze impact of code changes."""
def __init__(self, repo_root: str = '.'):
self.repo_root = Path(repo_root)
self.requirement_map = self._load_requirement_map()
self.test_map = self._load_test_map()
def _load_requirement_map(self) -> Dict[str, List[str]]:
"""Load file-to-requirement mapping from traceability."""
# In real implementation, load from Polarion/DOORS export
return {
'src/app/door_lock_control.c': ['SWE-BCM-100', 'SWE-BCM-101', 'SWE-BCM-102'],
'src/driver/gpio_driver.c': ['SWE-BCM-120', 'SWE-BCM-121'],
'src/service/safety_monitor.c': ['SWE-BCM-200', 'SWE-BCM-201'],
}
def _load_test_map(self) -> Dict[str, List[str]]:
"""Load file-to-test mapping."""
return {
'src/app/door_lock_control.c': ['test_door_lock_*.c', 'SWE-IT-BCM-001'],
'src/driver/gpio_driver.c': ['test_gpio_*.c', 'SWE-IT-GPIO-001'],
'src/service/safety_monitor.c': ['test_safety_*.c', 'SWE-IT-SAFETY-001'],
}
def get_changed_files(self, base: str, head: str) -> List[str]:
"""Get list of changed files between commits."""
result = subprocess.run(
['git', 'diff', '--name-only', f'{base}..{head}'],
capture_output=True,
text=True,
cwd=self.repo_root
)
return [f for f in result.stdout.strip().split('\n') if f]
def assess_file_impact(self, file_path: str) -> ImpactAssessment:
"""Assess impact of changes to a single file."""
# Determine impact level
impact_level = self._calculate_impact_level(file_path)
# Get affected requirements
requirements = self.requirement_map.get(file_path, [])
# Get affected tests
tests = self.test_map.get(file_path, [])
# Estimate effort
effort = self._estimate_effort(file_path, requirements, tests)
# Identify risk factors
risks = self._identify_risks(file_path)
return ImpactAssessment(
file=file_path,
impact_level=impact_level,
requirements_affected=requirements,
tests_affected=tests,
estimated_effort=effort,
risk_factors=risks
)
def _calculate_impact_level(self, file_path: str) -> str:
"""Calculate impact level based on file characteristics."""
# High impact patterns
high_impact = [
'safety', 'security', 'driver', 'mcal',
'interface', 'protocol', 'config'
]
# Medium impact patterns
medium_impact = ['service', 'app', 'component']
file_lower = file_path.lower()
if any(p in file_lower for p in high_impact):
return 'high'
elif any(p in file_lower for p in medium_impact):
return 'medium'
else:
return 'low'
def _estimate_effort(self, file_path: str,
requirements: List[str],
tests: List[str]) -> str:
"""Estimate effort for change implementation and verification."""
req_effort = len(requirements) * 0.5 # hours per requirement update
test_effort = len(tests) * 1.0 # hours per test update
total = req_effort + test_effort + 2 # base implementation time
if total < 4:
return "< 4 hours"
elif total < 16:
return "4-16 hours (1-2 days)"
else:
return f"{total:.0f} hours ({total/8:.1f} days)"
def _identify_risks(self, file_path: str) -> List[str]:
"""Identify risk factors for the change."""
risks = []
file_lower = file_path.lower()
if 'safety' in file_lower:
risks.append("Safety-critical component - requires safety review")
if 'driver' in file_lower or 'mcal' in file_lower:
risks.append("Low-level driver - hardware dependency")
if 'interface' in file_lower or 'api' in file_lower:
risks.append("Interface change - may affect dependent components")
if 'config' in file_lower:
risks.append("Configuration change - deployment impact")
return risks
def analyze_changes(self, base: str, head: str) -> Dict:
"""Perform complete impact analysis."""
changed_files = self.get_changed_files(base, head)
assessments = [self.assess_file_impact(f) for f in changed_files]
# Aggregate results
high_impact = [a for a in assessments if a.impact_level == 'high']
medium_impact = [a for a in assessments if a.impact_level == 'medium']
low_impact = [a for a in assessments if a.impact_level == 'low']
# Collect all affected requirements
all_requirements: Set[str] = set()
all_tests: Set[str] = set()
for a in assessments:
all_requirements.update(a.requirements_affected)
all_tests.update(a.tests_affected)
return {
'summary': {
'total_files': len(changed_files),
'high_impact': len(high_impact),
'medium_impact': len(medium_impact),
'low_impact': len(low_impact)
},
'requirements_affected': list(all_requirements),
'tests_affected': list(all_tests),
'high_impact_files': [asdict(a) for a in high_impact],
'all_assessments': [asdict(a) for a in assessments],
'recommendation': self._generate_recommendation(assessments)
}
def _generate_recommendation(self, assessments: List[ImpactAssessment]) -> str:
"""Generate change management recommendation."""
high_count = len([a for a in assessments if a.impact_level == 'high'])
if high_count > 0:
return "CCB_REQUIRED - High-impact changes require Change Control Board approval"
elif len(assessments) > 5:
return "REVIEW_RECOMMENDED - Multiple files affected, recommend technical review"
else:
return "PROCEED - Low-impact changes, standard review process"
def main():
"""Main entry point."""
import argparse
parser = argparse.ArgumentParser(description='Change Impact Analysis')
parser.add_argument('--base', required=True, help='Base commit')
parser.add_argument('--head', required=True, help='Head commit')
parser.add_argument('--output', default='impact_report.json', help='Output file')
args = parser.parse_args()
analyzer = ChangeImpactAnalyzer()
report = analyzer.analyze_changes(args.base, args.head)
with open(args.output, 'w') as f:
json.dump(report, f, indent=2)
print(f"Impact report written to {args.output}")
print(f"Summary: {report['summary']}")
print(f"Recommendation: {report['recommendation']}")
if __name__ == '__main__':
main()
Dashboard Integration
Metrics Collection
Note: Prometheus expressions are templates; adapt metric names and thresholds to your monitoring infrastructure.
# prometheus/sup_metrics.yml
# Support Process Metrics for Monitoring
groups:
- name: sup_metrics
rules:
# SUP.1 Quality Assurance Metrics
- record: sup1_audit_compliance_rate
expr: |
sum(audit_findings_resolved) / sum(audit_findings_total)
labels:
process: "SUP.1"
- record: sup1_ncr_aging_days
expr: |
(time() - ncr_created_timestamp) / 86400
labels:
process: "SUP.1"
# SUP.2 Verification Metrics
- record: sup2_review_finding_density
expr: |
sum(review_findings_total) / sum(review_items_total)
labels:
process: "SUP.2"
- record: sup2_ai_contribution_rate
expr: |
sum(review_findings_ai) / sum(review_findings_total)
labels:
process: "SUP.2"
# SUP.8 Configuration Management Metrics
- record: sup8_baseline_success_rate
expr: |
sum(baseline_created_success) / sum(baseline_created_total)
labels:
process: "SUP.8"
- record: sup8_branch_staleness_days
expr: |
(time() - branch_last_commit_timestamp) / 86400
labels:
process: "SUP.8"
# SUP.9 Problem Resolution Metrics
- record: sup9_mttr_hours
expr: |
avg(problem_resolution_time_seconds) / 3600
labels:
process: "SUP.9"
- record: sup9_first_time_fix_rate
expr: |
sum(problems_fixed_first_time) / sum(problems_resolved_total)
labels:
process: "SUP.9"
# SUP.10 Change Management Metrics
- record: sup10_cr_approval_time_hours
expr: |
avg(cr_approval_time_seconds) / 3600
labels:
process: "SUP.10"
- record: sup10_ai_impact_accuracy
expr: |
sum(ai_impact_correct) / sum(ai_impact_total)
labels:
process: "SUP.10"
# Alerting Rules
alerting_rules:
- alert: SUP1_HighNCRBacklog
expr: sum(ncr_open_total) > 20
for: 24h
labels:
severity: warning
annotations:
summary: "High NCR backlog ({{ $value }} open)"
- alert: SUP9_SlowResolution
expr: sup9_mttr_hours > 120
for: 1h
labels:
severity: warning
annotations:
summary: "Problem resolution time exceeds 5 days"
Work Products
| WP ID | Work Product | SUP Process | AI Automation |
|---|---|---|---|
| 15-01 | QA plan | SUP.1 | L1 Template |
| 15-02 | QA report | SUP.1 | L2 Generation |
| 08-28 | Non-conformance record | SUP.1 | L2 Classification |
| 08-12 | Verification plan | SUP.2 | L1 Template |
| 13-04 | Review record | SUP.2 | L2 Documentation |
| 06-01 | CM plan | SUP.8 | L1 Template |
| 06-02 | Baseline report | SUP.8 | L3 Generation |
| 08-27 | Problem report | SUP.9 | L2 RCA |
| 08-13 | Change request | SUP.10 | L2 Impact analysis |
Summary
Support Process Tools and Automation:
- SUP.1 QA: L2 automated compliance checking
- SUP.2 Verification: L2-L3 AI-assisted reviews
- SUP.8 CM: L2-L3 CI/CD automation
- SUP.9 Problem: L2 AI root cause analysis
- SUP.10 Change: L2 AI impact analysis
Key Integration Points:
- GitLab/GitHub for CM and CI/CD
- Issue trackers for problem/change management
- AI services for analysis and review
- Dashboards for metrics and reporting