Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/microwind/ai-skills --skill cicd명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | CI/CD验证器 |
| description | 当验证CI/CD流水线时,检查配置正确性,验证安全策略,分析性能瓶颈。审查工作流配置,检查部署流程,和最佳实践。 |
| license | MIT |
CI/CD验证器用于检查流水线配置的正确性和最佳实践。不当的CI/CD配置会导致安全漏洞、性能问题和部署失败。在部署到生产环境前需要全面验证流水线配置。
核心原则: 好的CI/CD验证应该全面、自动化、持续、安全。坏的CI/CD验证会遗漏关键问题,导致生产环境故障。
始终:
触发短语:
问题:
测试串行执行而非并行,构建时间30分钟
后果:
- 开发者反馈缓慢
- 部署频率低
- 形成瓶颈
解决方案:
1. 并行执行测试
2. 缓存依赖项
3. 优化构建步骤
4. 使用矩阵策略
问题:
测试覆盖率降低时流水线不会失败
后果:
- 代码质量随时间下降
- 缺陷无法捕获
- 技术债务累积
解决方案:
1. 添加覆盖率阈值检查
2. 低于阈值时失败
3. 设置覆盖率趋势监控
4. 集成质量门禁
问题:
任何提交都会自动部署到生产环境
后果:
- 损坏功能部署
- 可能数据丢失
- 停机风险
解决方案:
1. 生产部署前添加审批门禁
2. 设置多级审批流程
3. 配置环境保护规则
4. 实施部署策略
问题:
敏感信息泄露,权限配置不当
后果:
- 安全漏洞
- 数据泄露风险
- 合规问题
解决方案:
1. 使用密钥管理服务
2. 配置最小权限原则
3. 添加安全扫描
4. 实施访问控制
import yaml
import json
import re
import os
from pathlib import Path
from typing import List, Dict, Any, Optional, Set
from dataclasses import dataclass
from enum import Enum
class Severity(Enum):
"""问题严重程度"""
CRITICAL = "critical"
HIGH = "high"
MEDIUM = "medium"
LOW = "low"
class ValidationType(Enum):
"""验证类型"""
SECURITY = "security"
PERFORMANCE = "performance"
RELIABILITY = "reliability"
COMPLIANCE = "compliance"
@dataclass
class ValidationIssue:
"""验证问题"""
severity: Severity
type: ValidationType
file: str
resource: str
field: str
message: str
suggestion: str
line: Optional[int] = None
@dataclass
class ValidationResult:
"""验证结果"""
is_valid:
issues: [ValidationIssue]
score:
summary: [, ]
:
():
.repo_path = Path(repo_path)
.issues: [ValidationIssue] = []
.validation_rules = ._load_validation_rules()
() -> ValidationResult:
:
._scan_ci_files()
._validate_github_actions()
._validate_gitlab_ci()
._validate_jenkins()
._validate_security()
._validate_performance()
._generate_result()
Exception e:
.issues.append(ValidationIssue(
severity=Severity.CRITICAL,
=ValidationType.RELIABILITY,
file=,
resource=,
field=,
message=,
suggestion=
))
._generate_result()
() -> [, ]:
{
: {
: Severity.CRITICAL,
: Severity.HIGH,
: Severity.MEDIUM,
: Severity.CRITICAL
},
: {
: Severity.MEDIUM,
: Severity.LOW,
: Severity.MEDIUM,
: Severity.LOW
},
: {
: Severity.HIGH,
: Severity.MEDIUM,
: Severity.HIGH,
: Severity.MEDIUM
},
: {
: Severity.MEDIUM,
: Severity.LOW,
: Severity.HIGH,
: Severity.MEDIUM
}
}
() -> :
ci_files = []
github_workflows = .repo_path / /
github_workflows.exists():
ci_files.extend(github_workflows.glob())
ci_files.extend(github_workflows.glob())
gitlab_ci = .repo_path /
gitlab_ci.exists():
ci_files.append(gitlab_ci)
jenkinsfile = .repo_path /
jenkinsfile.exists():
ci_files.append(jenkinsfile)
azure_pipelines = .repo_path /
azure_pipelines.exists():
ci_files.append(azure_pipelines)
ci_files:
.issues.append(ValidationIssue(
severity=Severity.HIGH,
=ValidationType.COMPLIANCE,
file=,
resource=,
field=,
message=,
suggestion=
))
() -> :
github_workflows = .repo_path / /
github_workflows.exists():
workflow_file github_workflows.glob():
:
(workflow_file, , encoding=) f:
content = f.read()
._validate_github_workflow(content, (workflow_file))
Exception e:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.RELIABILITY,
file=(workflow_file),
resource=,
field=,
message=,
suggestion=
))
() -> :
:
yaml_data = yaml.safe_load(content)
._check_triggers(yaml_data, file_path)
yaml_data:
._validate_jobs(yaml_data[], file_path)
._check_env_vars(yaml_data, file_path)
._check_workflow_security(yaml_data, file_path)
._check_workflow_performance(yaml_data, file_path)
yaml.YAMLError e:
.issues.append(ValidationIssue(
severity=Severity.CRITICAL,
=ValidationType.RELIABILITY,
file=file_path,
resource=,
field=,
message=,
suggestion=
))
() -> :
yaml_data yaml_data:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.COMPLIANCE,
file=file_path,
resource=,
field=,
message=,
suggestion=
))
yaml_data:
triggers = yaml_data[]
(triggers, ) triggers:
schedule = triggers[]
(schedule, ) (schedule) > :
.issues.append(ValidationIssue(
severity=Severity.LOW,
=ValidationType.PERFORMANCE,
file=file_path,
resource=,
field=,
message=,
suggestion=
))
() -> :
job_name, job_config jobs.items():
job_config:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.RELIABILITY,
file=file_path,
resource=job_name,
field=,
message=,
suggestion=
))
job_config:
.issues.append(ValidationIssue(
severity=Severity.HIGH,
=ValidationType.RELIABILITY,
file=file_path,
resource=job_name,
field=,
message=,
suggestion=
))
:
._validate_job_steps(job_config[], job_name, file_path)
job_config job_name.lower():
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.PERFORMANCE,
file=file_path,
resource=job_name,
field=,
message=,
suggestion=
))
() -> :
has_checkout =
has_test =
has_security_scan =
step steps:
step:
step[]:
has_checkout =
step[].lower() step[].lower():
has_security_scan =
step[].lower():
has_test =
step:
command = step[]
command.lower() command.lower():
has_checkout =
command.lower():
has_test =
command.lower() command.lower():
has_security_scan =
has_checkout:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.RELIABILITY,
file=file_path,
resource=job_name,
field=,
message=,
suggestion=
))
has_test job_name.lower():
.issues.append(ValidationIssue(
severity=Severity.HIGH,
=ValidationType.RELIABILITY,
file=file_path,
resource=job_name,
field=,
message=,
suggestion=
))
has_security_scan job_name.lower():
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.SECURITY,
file=file_path,
resource=job_name,
field=,
message=,
suggestion=
))
() -> :
content = (yaml_data)
sensitive_patterns = [
,
,
,
,
]
pattern sensitive_patterns:
re.search(pattern, content, re.IGNORECASE):
.issues.append(ValidationIssue(
severity=Severity.CRITICAL,
=ValidationType.SECURITY,
file=file_path,
resource=,
field=,
message=,
suggestion=
))
content content:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.SECURITY,
file=file_path,
resource=,
field=,
message=,
suggestion=
))
() -> :
yaml_data:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.SECURITY,
file=file_path,
resource=,
field=,
message=,
suggestion=
))
content = (yaml_data)
content:
uses_pattern =
matches = re.findall(uses_pattern, content)
action, version matches:
version [, , ]:
.issues.append(ValidationIssue(
severity=Severity.HIGH,
=ValidationType.SECURITY,
file=file_path,
resource=,
field=,
message=,
suggestion=
))
() -> :
content = (yaml_data)
content:
.issues.append(ValidationIssue(
severity=Severity.LOW,
=ValidationType.PERFORMANCE,
file=file_path,
resource=,
field=,
message=,
suggestion=
))
content:
.issues.append(ValidationIssue(
severity=Severity.LOW,
=ValidationType.PERFORMANCE,
file=file_path,
resource=,
field=,
message=,
suggestion=
))
() -> :
gitlab_ci = .repo_path /
gitlab_ci.exists():
:
(gitlab_ci, , encoding=) f:
content = f.read()
yaml_data = yaml.safe_load(content)
yaml_data:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.COMPLIANCE,
file=(gitlab_ci),
resource=,
field=,
message=,
suggestion=
))
jobs = {k: v k, v yaml_data.items() k != k.startswith()}
job_name, job_config jobs.items():
._validate_gitlab_job(job_config, job_name, (gitlab_ci))
Exception e:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.RELIABILITY,
file=(gitlab_ci),
resource=,
field=,
message=,
suggestion=
))
() -> :
job_config:
.issues.append(ValidationIssue(
severity=Severity.HIGH,
=ValidationType.RELIABILITY,
file=file_path,
resource=job_name,
field=,
message=,
suggestion=
))
job_config:
artifacts = job_config[]
(artifacts, ) artifacts:
.issues.append(ValidationIssue(
severity=Severity.LOW,
=ValidationType.PERFORMANCE,
file=file_path,
resource=job_name,
field=,
message=,
suggestion=
))
job_config job_config job_config:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.COMPLIANCE,
file=file_path,
resource=job_name,
field=,
message=,
suggestion=
))
() -> :
jenkinsfile = .repo_path /
jenkinsfile.exists():
:
(jenkinsfile, , encoding=) f:
content = f.read()
content:
.issues.append(ValidationIssue(
severity=Severity.HIGH,
=ValidationType.COMPLIANCE,
file=(jenkinsfile),
resource=,
field=,
message=,
suggestion=
))
content:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.RELIABILITY,
file=(jenkinsfile),
resource=,
field=,
message=,
suggestion=
))
stages = re.findall(, content)
(stages) == :
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.COMPLIANCE,
file=(jenkinsfile),
resource=,
field=,
message=,
suggestion=
))
Exception e:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.RELIABILITY,
file=(jenkinsfile),
resource=,
field=,
message=,
suggestion=
))
() -> :
security_files = [
,
,
,
]
security_config_found =
security_file security_files:
(.repo_path / security_file).exists():
security_config_found =
security_config_found:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.SECURITY,
file=,
resource=,
field=,
message=,
suggestion=
))
() -> :
build_files = [
,
,
,
,
]
build_file build_files:
file_path = .repo_path / build_file
file_path.exists():
._validate_build_file(file_path)
() -> :
:
(build_file, , encoding=) f:
content = f.read()
build_file.name == :
._validate_package_json(content, (build_file))
build_file.name == :
._validate_pom_xml(content, (build_file))
Exception e:
.issues.append(ValidationIssue(
severity=Severity.LOW,
=ValidationType.RELIABILITY,
file=(build_file),
resource=,
field=,
message=,
suggestion=
))
() -> :
:
package_data = json.loads(content)
package_data:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.COMPLIANCE,
file=file_path,
resource=,
field=,
message=,
suggestion=
))
json.JSONDecodeError e:
.issues.append(ValidationIssue(
severity=Severity.HIGH,
=ValidationType.RELIABILITY,
file=file_path,
resource=,
field=,
message=,
suggestion=
))
() -> :
content:
.issues.append(ValidationIssue(
severity=Severity.MEDIUM,
=ValidationType.COMPLIANCE,
file=file_path,
resource=,
field=,
message=,
suggestion=
))
() -> ValidationResult:
score = ._calculate_score()
summary = ._generate_summary()
is_valid = score >= (
issue.severity == Severity.CRITICAL issue .issues
)
ValidationResult(
is_valid=is_valid,
issues=.issues,
score=score,
summary=summary
)
() -> :
score =
issue .issues:
issue.severity == Severity.CRITICAL:
score -=
issue.severity == Severity.HIGH:
score -=
issue.severity == Severity.MEDIUM:
score -=
issue.severity == Severity.LOW:
score -=
(, score)
() -> [, ]:
issue_counts = {
: (.issues),
: ([i i .issues i.severity == Severity.CRITICAL]),
: ([i i .issues i.severity == Severity.HIGH]),
: ([i i .issues i.severity == Severity.MEDIUM]),
: ([i i .issues i.severity == Severity.LOW])
}
type_counts = {}
issue .issues:
type_name = issue..value
type_counts[type_name] = type_counts.get(type_name, ) +
{
: issue_counts,
: type_counts,
: ._generate_recommendations()
}
() -> []:
recommendations = []
type_counts = {}
issue .issues:
type_name = issue..value
type_counts[type_name] = type_counts.get(type_name, ) +
type_counts.get(, ) > :
recommendations.append()
type_counts.get(, ) > :
recommendations.append()
type_counts.get(, ) > :
recommendations.append()
type_counts.get(, ) > :
recommendations.append()
recommendations
():
validator = CICDValidator()
result = validator.validate_pipeline()
()
()
()
()
summary = result.summary
issue_counts = summary[]
()
()
()
()
()
()
rec summary[]:
()
()
issue result.issues:
()
()
__name__ == :
main()