xp-gate 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapter-common.sh +192 -0
- package/adapters/cpp.sh +76 -0
- package/adapters/dart.sh +41 -0
- package/adapters/flutter.sh +41 -0
- package/adapters/go.sh +59 -0
- package/adapters/iac.sh +189 -0
- package/adapters/java.sh +191 -0
- package/adapters/kotlin.sh +77 -0
- package/adapters/objectivec.sh +38 -0
- package/adapters/powershell.sh +138 -0
- package/adapters/python.sh +104 -0
- package/adapters/shell.sh +55 -0
- package/adapters/swift.sh +44 -0
- package/adapters/typescript.sh +61 -0
- package/bin/xp-gate.js +157 -0
- package/hooks/adapter-common.sh +192 -0
- package/hooks/pre-commit +1667 -0
- package/hooks/pre-push +395 -0
- package/lib/__tests__/detect-deps.test.js +209 -0
- package/lib/__tests__/doctor.test.js +448 -0
- package/lib/__tests__/download-skill.test.js +281 -0
- package/lib/__tests__/init.test.js +327 -0
- package/lib/__tests__/install-skill.test.js +326 -0
- package/lib/__tests__/migrate.test.js +212 -0
- package/lib/__tests__/rollback.test.js +183 -0
- package/lib/__tests__/ui-detector.test.ts +200 -0
- package/lib/__tests__/uninstall-skill.test.js +189 -0
- package/lib/__tests__/uninstall.test.js +589 -0
- package/lib/__tests__/update-skill.test.js +276 -0
- package/lib/detect-deps.js +157 -0
- package/lib/doctor.js +370 -0
- package/lib/download-skill.js +96 -0
- package/lib/init.js +367 -0
- package/lib/install-skill.js +184 -0
- package/lib/migrate.js +120 -0
- package/lib/rollback.js +78 -0
- package/lib/ui-detector.ts +99 -0
- package/lib/uninstall-skill.js +69 -0
- package/lib/uninstall.js +401 -0
- package/lib/update-skill.js +90 -0
- package/package.json +39 -0
- package/plugins/claude-code/.claude-plugin/plugin.json +21 -0
- package/plugins/claude-code/bin/delphi-review-guard.sh +68 -0
- package/plugins/claude-code/bin/xp-gate-check +47 -0
- package/plugins/claude-code/hooks/hooks.json +37 -0
- package/skills/delphi-review/.delphi-config.json.example +45 -0
- package/skills/delphi-review/AGENTS.md +54 -0
- package/skills/delphi-review/INSTALL.md +152 -0
- package/skills/delphi-review/SKILL.md +371 -0
- package/skills/delphi-review/evals/evals.json +82 -0
- package/skills/delphi-review/opencode.json.delphi.example +56 -0
- package/skills/delphi-review/references/code-walkthrough.md +486 -0
- package/skills/ralph-loop/SKILL.md +330 -0
- package/skills/ralph-loop/evals/evals.json +311 -0
- package/skills/ralph-loop/evolution-history.json +59 -0
- package/skills/ralph-loop/evolution-log.md +16 -0
- package/skills/ralph-loop/references/components/memory.md +55 -0
- package/skills/ralph-loop/references/components/middleware.md +54 -0
- package/skills/ralph-loop/references/components/skill-invocations.md +39 -0
- package/skills/ralph-loop/references/components/system-prompt.md +24 -0
- package/skills/ralph-loop/references/components/tool-descriptions.md +32 -0
- package/skills/ralph-loop/references/phase-2-build-ralph.md +89 -0
- package/skills/ralph-loop/templates/progress-log.md +36 -0
- package/skills/sprint-flow/SKILL.md +600 -0
- package/skills/sprint-flow/evals/evals.json +78 -0
- package/skills/sprint-flow/evolution-history.json +39 -0
- package/skills/sprint-flow/evolution-log.md +23 -0
- package/skills/sprint-flow/references/components/memory.md +87 -0
- package/skills/sprint-flow/references/components/middleware.md +72 -0
- package/skills/sprint-flow/references/components/skill-invocations.md +104 -0
- package/skills/sprint-flow/references/components/system-prompt.md +27 -0
- package/skills/sprint-flow/references/components/tool-descriptions.md +96 -0
- package/skills/sprint-flow/references/phase-0-think.md +115 -0
- package/skills/sprint-flow/references/phase-1-plan.md +178 -0
- package/skills/sprint-flow/references/phase-2-build.md +198 -0
- package/skills/sprint-flow/references/phase-3-review.md +213 -0
- package/skills/sprint-flow/references/phase-4-uat.md +125 -0
- package/skills/sprint-flow/references/phase-5-feedback.md +100 -0
- package/skills/sprint-flow/references/phase-6-ship.md +193 -0
- package/skills/sprint-flow/references/phase-7-land.md +140 -0
- package/skills/sprint-flow/references/phase-8-cleanup.md +192 -0
- package/skills/sprint-flow/templates/emergent-issues-template.md +120 -0
- package/skills/sprint-flow/templates/pain-document-template.md +115 -0
- package/skills/sprint-flow/templates/sprint-summary-template.md +120 -0
- package/skills/test-specification-alignment/AGENTS.md +59 -0
- package/skills/test-specification-alignment/SKILL.md +605 -0
- package/skills/test-specification-alignment/evals/evals.json +75 -0
- package/skills/test-specification-alignment/references/alignment-verification-algorithm.md +493 -0
- package/skills/test-specification-alignment/references/phase2-constraint-enforcement.md +431 -0
- package/skills/test-specification-alignment/references/specification-format.md +348 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Common adapter functions for language detection and routing
|
|
4
|
+
|
|
5
|
+
detect_project_lang() {
|
|
6
|
+
if [[ -f "tsconfig.json" ]]; then
|
|
7
|
+
echo "typescript"
|
|
8
|
+
elif [[ -f "pyproject.toml" ]] || [[ -f "requirements.txt" ]] || [[ -f "setup.py" ]]; then
|
|
9
|
+
echo "python"
|
|
10
|
+
elif [[ -f "go.mod" ]]; then
|
|
11
|
+
echo "go"
|
|
12
|
+
elif [[ -f "build.gradle" ]] || [[ -f "build.gradle.kts" ]]; then
|
|
13
|
+
if [[ -n "$(find . -name "*.kt" -type f | head -n 1)" ]]; then
|
|
14
|
+
echo "kotlin"
|
|
15
|
+
else
|
|
16
|
+
echo "java"
|
|
17
|
+
fi
|
|
18
|
+
elif [[ -f "pom.xml" ]]; then
|
|
19
|
+
echo "java"
|
|
20
|
+
elif [[ -f "pubspec.yaml" ]]; then
|
|
21
|
+
if grep -q "flutter:" "pubspec.yaml" 2>/dev/null || [[ -f ".metadata" ]]; then
|
|
22
|
+
echo "flutter"
|
|
23
|
+
else
|
|
24
|
+
echo "dart"
|
|
25
|
+
fi
|
|
26
|
+
elif [[ -n "$(find . -name "*.ps1" -type f | head -n 1)" ]]; then
|
|
27
|
+
echo "powershell"
|
|
28
|
+
elif [[ -f "Package.swift" ]]; then
|
|
29
|
+
echo "swift"
|
|
30
|
+
elif [[ -f "CMakeLists.txt" ]] || [[ -n "$(find . -name "*.cpp" -o -name "*.cc" -type f | head -n 1)" ]]; then
|
|
31
|
+
echo "cpp"
|
|
32
|
+
elif [[ -n "$(find . -name "*.m" -o -name "*.mm" -type f | head -n 1)" ]]; then
|
|
33
|
+
echo "objectivec"
|
|
34
|
+
elif [[ -n "$(find . -name "*.sh" -type f | head -n 1)" ]] || [[ -n "$(find . -name "Dockerfile" -o -name "*.dockerfile" -type f | head -n 1)" ]]; then
|
|
35
|
+
echo "shell"
|
|
36
|
+
elif [[ -n "$(find . -name "*.ps1" -type f -not -path "./.git/*" | head -n 1)" ]]; then
|
|
37
|
+
echo "powershell"
|
|
38
|
+
else
|
|
39
|
+
if [[ -n "$(find . -name "*.ts" -o -name "*.tsx" -type f | head -n 1)" ]]; then
|
|
40
|
+
echo "typescript"
|
|
41
|
+
elif [[ -n "$(find . -name "*.py" -type f | head -n 1)" ]]; then
|
|
42
|
+
echo "python"
|
|
43
|
+
elif [[ -n "$(find . -name "*.go" -type f | head -n 1)" ]]; then
|
|
44
|
+
echo "go"
|
|
45
|
+
elif [[ -n "$(find . -name "*.kt" -type f | head -n 1)" ]]; then
|
|
46
|
+
echo "kotlin"
|
|
47
|
+
elif [[ -n "$(find . -name "*.java" -type f | head -n 1)" ]]; then
|
|
48
|
+
echo "java"
|
|
49
|
+
elif [[ -n "$(find . -name "*.dart" -type f | head -n 1)" ]]; then
|
|
50
|
+
if grep -q "flutter:" "pubspec.yaml" 2>/dev/null || [[ -f ".flutter" ]]; then
|
|
51
|
+
echo "flutter"
|
|
52
|
+
else
|
|
53
|
+
echo "dart"
|
|
54
|
+
fi
|
|
55
|
+
elif [[ -n "$(find . -name "*.swift" -type f | head -n 1)" ]]; then
|
|
56
|
+
echo "swift"
|
|
57
|
+
elif [[ -n "$(find . -name "*.cpp" -o -name "*.cc" -o -name "*.c" -o -name "*.h" -type f | head -n 1)" ]]; then
|
|
58
|
+
echo "cpp"
|
|
59
|
+
elif [[ -n "$(find . -name "*.m" -o -name "*.mm" -type f | head -n 1)" ]]; then
|
|
60
|
+
echo "objectivec"
|
|
61
|
+
elif [[ -n "$(find . -name "*.sh" -type f | head -n 1)" ]]; then
|
|
62
|
+
echo "shell"
|
|
63
|
+
elif [[ -n "$(find . -name "*.ps1" -type f -not -path "./.git/*" | head -n 1)" ]]; then
|
|
64
|
+
echo "powershell"
|
|
65
|
+
else
|
|
66
|
+
echo "unknown"
|
|
67
|
+
fi
|
|
68
|
+
fi
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
route_to_adapter() {
|
|
72
|
+
local action="$1"
|
|
73
|
+
local lang
|
|
74
|
+
lang=$(detect_project_lang)
|
|
75
|
+
|
|
76
|
+
# Source the appropriate adapter
|
|
77
|
+
if [[ -f "githooks/adapters/${lang}.sh" ]]; then
|
|
78
|
+
# shellcheck source=githooks/adapters/"${lang}".sh
|
|
79
|
+
source "githooks/adapters/${lang}.sh"
|
|
80
|
+
|
|
81
|
+
# Execute the requested action
|
|
82
|
+
case "$action" in
|
|
83
|
+
"static_analysis") run_static_analysis ;;
|
|
84
|
+
"lint") run_lint ;;
|
|
85
|
+
"tests") run_tests ;;
|
|
86
|
+
"coverage") run_coverage ;;
|
|
87
|
+
*) return 1 ;;
|
|
88
|
+
esac
|
|
89
|
+
elif [[ -f "./githooks/adapters/${lang}.sh" ]]; then
|
|
90
|
+
# Alternative: source with ./ prefix
|
|
91
|
+
# shellcheck source=./githooks/adapters/"${lang}".sh
|
|
92
|
+
source "./githooks/adapters/${lang}.sh"
|
|
93
|
+
|
|
94
|
+
# Execute the requested action
|
|
95
|
+
case "$action" in
|
|
96
|
+
"static_analysis") run_static_analysis ;;
|
|
97
|
+
"lint") run_lint ;;
|
|
98
|
+
"tests") run_tests ;;
|
|
99
|
+
"coverage") run_coverage ;;
|
|
100
|
+
*) return 1 ;;
|
|
101
|
+
esac
|
|
102
|
+
else
|
|
103
|
+
echo "No adapter found for language: $lang"
|
|
104
|
+
return 1
|
|
105
|
+
fi
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
check_if_tool_available() {
|
|
109
|
+
local tool_name="$1"
|
|
110
|
+
|
|
111
|
+
# Check if command exists
|
|
112
|
+
if command -v "$tool_name" >/dev/null 2>&1; then
|
|
113
|
+
return 0
|
|
114
|
+
else
|
|
115
|
+
return 1
|
|
116
|
+
fi
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
require_tool() {
|
|
120
|
+
local tool_name="$1"
|
|
121
|
+
local gate_name="${2:-Gate}"
|
|
122
|
+
local install_hint="${3:-}"
|
|
123
|
+
|
|
124
|
+
if command -v "$tool_name" >/dev/null 2>&1; then
|
|
125
|
+
return 0
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
if command -v npx >/dev/null 2>&1 && npx --no-install "$tool_name" --version >/dev/null 2>&1; then
|
|
129
|
+
return 0
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
echo "❌ BLOCKED - Required tool '$tool_name' not available for $gate_name"
|
|
133
|
+
if [[ -n "$install_hint" ]]; then
|
|
134
|
+
echo " Install: $install_hint"
|
|
135
|
+
fi
|
|
136
|
+
echo " Per QUALITY-GATES-CODE-OF-CONDUCT.md: tool unavailable = BLOCK, not SKIP"
|
|
137
|
+
return 1
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
# Detect if project has IaC files (Terraform, Kubernetes, Docker)
|
|
141
|
+
detect_iac_project() {
|
|
142
|
+
local has_iac=false
|
|
143
|
+
|
|
144
|
+
# Check for Terraform files
|
|
145
|
+
if [[ -n "$(find . -maxdepth 2 -name "*.tf" -not -path "./.git/*" 2>/dev/null | head -1)" ]]; then
|
|
146
|
+
has_iac=true
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
# Check for Kubernetes manifests (YAML with apiVersion/kind)
|
|
150
|
+
if [[ -n "$(find . -maxdepth 2 \( -name "*.yaml" -o -name "*.yml" \) -not -path "./.git/*" 2>/dev/null | head -1)" ]]; then
|
|
151
|
+
local yaml_file=$(find . -maxdepth 2 \( -name "*.yaml" -o -name "*.yml" \) -not -path "./.git/*" 2>/dev/null | head -1)
|
|
152
|
+
if grep -qE "^(apiVersion|kind):" "$yaml_file" 2>/dev/null; then
|
|
153
|
+
has_iac=true
|
|
154
|
+
fi
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
# Check for Dockerfiles
|
|
158
|
+
if [[ -n "$(find . -maxdepth 2 -name "Dockerfile" -o -name "*.dockerfile" -not -path "./.git/*" 2>/dev/null | head -1)" ]]; then
|
|
159
|
+
has_iac=true
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
if [ "$has_iac" = true ]; then
|
|
163
|
+
echo "iac"
|
|
164
|
+
else
|
|
165
|
+
echo ""
|
|
166
|
+
fi
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
# Stryker 9.x config files (new format, takes priority)
|
|
170
|
+
detect_mutation_testable() {
|
|
171
|
+
if [[ -f "stryker.config.mjs" ]] || [[ -f "stryker.config.js" ]] || \
|
|
172
|
+
[[ -f "stryker.config.cjs" ]] || [[ -f "stryker.config.json" ]]; then
|
|
173
|
+
if [[ -f "package.json" ]] && grep -qE '"@stryker-mutator[^"]*"' package.json 2>/dev/null; then
|
|
174
|
+
return 0
|
|
175
|
+
fi
|
|
176
|
+
if command -v npx >/dev/null 2>&1 && npx --no-install stryker --version >/dev/null 2>&1; then
|
|
177
|
+
return 0
|
|
178
|
+
fi
|
|
179
|
+
fi
|
|
180
|
+
|
|
181
|
+
# Legacy Stryker config files (backwards compatibility)
|
|
182
|
+
if [[ -f "stryker.conf.json" ]] || [[ -f "stryker.prepush.conf.json" ]]; then
|
|
183
|
+
if [[ -f "package.json" ]] && grep -qE '"@stryker-mutator[^"]*"' package.json 2>/dev/null; then
|
|
184
|
+
return 0
|
|
185
|
+
fi
|
|
186
|
+
if command -v npx >/dev/null 2>&1 && npx --no-install stryker --version >/dev/null 2>&1; then
|
|
187
|
+
return 0
|
|
188
|
+
fi
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
return 1
|
|
192
|
+
}
|
package/adapters/cpp.sh
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
_detect_cpp_build() {
|
|
4
|
+
if command -v cmake &>/dev/null && [ -f "CMakeLists.txt" ]; then
|
|
5
|
+
echo "cmake"
|
|
6
|
+
elif [ -f "Makefile" ]; then
|
|
7
|
+
echo "make"
|
|
8
|
+
else
|
|
9
|
+
echo "none"
|
|
10
|
+
fi
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
run_static_analysis() {
|
|
14
|
+
if command -v clang-tidy &>/dev/null; then
|
|
15
|
+
local files
|
|
16
|
+
files=$(find . -name "*.cpp" -o -name "*.cc" -o -name "*.c" -o -name "*.h" 2>/dev/null | head -20)
|
|
17
|
+
if [ -n "$files" ]; then
|
|
18
|
+
echo "$files" | xargs clang-tidy 2>&1 | head -20
|
|
19
|
+
fi
|
|
20
|
+
elif command -v cppcheck &>/dev/null; then
|
|
21
|
+
cppcheck --enable=all --inline-suppr . 2>&1 | head -20
|
|
22
|
+
else
|
|
23
|
+
echo "No C++ analysis tools (clang-tidy/cppcheck)"
|
|
24
|
+
return 1
|
|
25
|
+
fi
|
|
26
|
+
return 0
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
run_lint() {
|
|
30
|
+
run_static_analysis
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
run_tests() {
|
|
34
|
+
local build_system
|
|
35
|
+
build_system=$(_detect_cpp_build)
|
|
36
|
+
|
|
37
|
+
if [ "$build_system" = "cmake" ]; then
|
|
38
|
+
if [ -d "build" ]; then
|
|
39
|
+
cmake --build build/ 2>&1 | tail -5
|
|
40
|
+
cd build && ctest --output-on-failure 2>&1 | tail -15
|
|
41
|
+
return ${PIPESTATUS[1]}
|
|
42
|
+
else
|
|
43
|
+
cmake -B build -G Ninja 2>/dev/null || cmake -B build 2>/dev/null
|
|
44
|
+
cmake --build build/ 2>&1 | tail -5
|
|
45
|
+
cd build && ctest --output-on-failure 2>&1 | tail -15
|
|
46
|
+
return ${PIPESTATUS[1]}
|
|
47
|
+
fi
|
|
48
|
+
elif [ "$build_system" = "make" ]; then
|
|
49
|
+
make 2>&1 | tail -5
|
|
50
|
+
make test 2>&1 | tail -15
|
|
51
|
+
return ${PIPESTATUS[1]}
|
|
52
|
+
else
|
|
53
|
+
echo "No C++ build system detected"
|
|
54
|
+
return 1
|
|
55
|
+
fi
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
run_coverage() {
|
|
59
|
+
local build_system
|
|
60
|
+
build_system=$(_detect_cpp_build)
|
|
61
|
+
|
|
62
|
+
if command -v gcovr &>/dev/null; then
|
|
63
|
+
if [ "$build_system" = "cmake" ] && [ -d "build" ]; then
|
|
64
|
+
cd build && gcovr --root .. 2>&1 | tail -10
|
|
65
|
+
return $?
|
|
66
|
+
fi
|
|
67
|
+
gcovr --root . 2>&1 | tail -10
|
|
68
|
+
return $?
|
|
69
|
+
elif command -v llvm-cov &>/dev/null; then
|
|
70
|
+
llvm-cov report 2>&1 | tail -10
|
|
71
|
+
return $?
|
|
72
|
+
else
|
|
73
|
+
echo "No C++ coverage tools (gcovr/llvm-cov)"
|
|
74
|
+
return 1
|
|
75
|
+
fi
|
|
76
|
+
}
|
package/adapters/dart.sh
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
run_static_analysis() {
|
|
4
|
+
if command -v dart &>/dev/null; then
|
|
5
|
+
dart analyze 2>&1 | head -30
|
|
6
|
+
return $?
|
|
7
|
+
else
|
|
8
|
+
echo "Dart SDK not available"
|
|
9
|
+
return 1
|
|
10
|
+
fi
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
run_lint() {
|
|
14
|
+
if command -v dart &>/dev/null; then
|
|
15
|
+
dart format --output=none --set-exit-if-changed . 2>&1 | head -30
|
|
16
|
+
return $?
|
|
17
|
+
else
|
|
18
|
+
echo "Dart SDK not available"
|
|
19
|
+
return 1
|
|
20
|
+
fi
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
run_tests() {
|
|
24
|
+
if command -v dart &>/dev/null; then
|
|
25
|
+
dart test 2>&1 | tail -20
|
|
26
|
+
return $?
|
|
27
|
+
else
|
|
28
|
+
echo "Dart SDK not available"
|
|
29
|
+
return 1
|
|
30
|
+
fi
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
run_coverage() {
|
|
34
|
+
if command -v dart &>/dev/null; then
|
|
35
|
+
dart test --coverage=coverage 2>&1 | tail -10
|
|
36
|
+
return $?
|
|
37
|
+
else
|
|
38
|
+
echo "Dart SDK not available"
|
|
39
|
+
return 1
|
|
40
|
+
fi
|
|
41
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
run_static_analysis() {
|
|
4
|
+
if command -v flutter &>/dev/null; then
|
|
5
|
+
flutter analyze 2>&1 | head -30
|
|
6
|
+
return $?
|
|
7
|
+
else
|
|
8
|
+
echo "Flutter SDK not available"
|
|
9
|
+
return 1
|
|
10
|
+
fi
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
run_lint() {
|
|
14
|
+
if command -v flutter &>/dev/null; then
|
|
15
|
+
flutter format --output=none --set-exit-if-changed . 2>&1 | head -30
|
|
16
|
+
return $?
|
|
17
|
+
else
|
|
18
|
+
echo "Flutter SDK not available"
|
|
19
|
+
return 1
|
|
20
|
+
fi
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
run_tests() {
|
|
24
|
+
if command -v flutter &>/dev/null; then
|
|
25
|
+
flutter test 2>&1 | tail -20
|
|
26
|
+
return $?
|
|
27
|
+
else
|
|
28
|
+
echo "Flutter SDK not available"
|
|
29
|
+
return 1
|
|
30
|
+
fi
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
run_coverage() {
|
|
34
|
+
if command -v flutter &>/dev/null; then
|
|
35
|
+
flutter test --coverage 2>&1 | tail -10
|
|
36
|
+
return $?
|
|
37
|
+
else
|
|
38
|
+
echo "Flutter SDK not available"
|
|
39
|
+
return 1
|
|
40
|
+
fi
|
|
41
|
+
}
|
package/adapters/go.sh
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Go adapter for quality gates
|
|
4
|
+
# Tools: go vet, golangci-lint, arch-go (architecture), go test
|
|
5
|
+
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
source "$SCRIPT_DIR/../adapter-common.sh" 2>/dev/null || true
|
|
8
|
+
|
|
9
|
+
run_static_analysis() {
|
|
10
|
+
require_tool go "Go SDK" || return 1
|
|
11
|
+
|
|
12
|
+
echo "Running Go static analysis (go vet)..."
|
|
13
|
+
go vet ./...
|
|
14
|
+
return $?
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
run_lint() {
|
|
18
|
+
if ! require_tool golangci-lint "golangci-lint" 2>/dev/null; then
|
|
19
|
+
echo "⚠ golangci-lint not available, installing..."
|
|
20
|
+
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest 2>/dev/null
|
|
21
|
+
require_tool golangci-lint "golangci-lint" || return 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
echo "Running Go linting (golangci-lint)..."
|
|
25
|
+
golangci-lint run ./...
|
|
26
|
+
return $?
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
run_architecture() {
|
|
30
|
+
if ! require_tool arch-go "arch-go (Go architecture checker)" 2>/dev/null; then
|
|
31
|
+
echo "⚠ arch-go not available, installing..."
|
|
32
|
+
go install github.com/arch-go/arch-go@latest 2>/dev/null
|
|
33
|
+
require_tool arch-go "arch-go" || return 0
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
echo "Running Go architecture checks (arch-go)..."
|
|
37
|
+
arch-go check
|
|
38
|
+
return $?
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
run_tests() {
|
|
42
|
+
require_tool go "Go SDK" || return 1
|
|
43
|
+
|
|
44
|
+
echo "Running Go tests..."
|
|
45
|
+
go test ./...
|
|
46
|
+
return $?
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
run_coverage() {
|
|
50
|
+
require_tool go "Go SDK" || return 1
|
|
51
|
+
|
|
52
|
+
echo "Running Go coverage..."
|
|
53
|
+
go test -coverprofile=coverage.out ./...
|
|
54
|
+
local rc=$?
|
|
55
|
+
if [ $rc -eq 0 ]; then
|
|
56
|
+
go tool cover -func=coverage.out 2>/dev/null | tail -1
|
|
57
|
+
fi
|
|
58
|
+
return $rc
|
|
59
|
+
}
|
package/adapters/iac.sh
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# IaC (Infrastructure as Code) adapter for quality gates
|
|
4
|
+
# Supports: Terraform (.tf), Kubernetes (K8s *.yaml), Docker, CloudFormation
|
|
5
|
+
# Tools: checkov (primary), hadolint (Docker), kube-score (K8s)
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
+
source "$SCRIPT_DIR/../adapter-common.sh" 2>/dev/null || true
|
|
9
|
+
|
|
10
|
+
# Detect IaC files in changed files
|
|
11
|
+
detect_iac_files() {
|
|
12
|
+
local files="$1"
|
|
13
|
+
local tf_files=""
|
|
14
|
+
local yaml_files=""
|
|
15
|
+
local dockerfile_files=""
|
|
16
|
+
|
|
17
|
+
for file in $files; do
|
|
18
|
+
case "$file" in
|
|
19
|
+
*.tf)
|
|
20
|
+
tf_files="$tf_files $file"
|
|
21
|
+
;;
|
|
22
|
+
*.yaml|*.yml)
|
|
23
|
+
# Check if it's a K8s manifest (has apiVersion and kind)
|
|
24
|
+
if grep -qE "^(apiVersion|kind):" "$file" 2>/dev/null; then
|
|
25
|
+
yaml_files="$yaml_files $file"
|
|
26
|
+
fi
|
|
27
|
+
;;
|
|
28
|
+
Dockerfile|*.dockerfile|Dockerfile.*)
|
|
29
|
+
dockerfile_files="$dockerfile_files $file"
|
|
30
|
+
;;
|
|
31
|
+
esac
|
|
32
|
+
done
|
|
33
|
+
|
|
34
|
+
echo "TERRAFORM:$tf_files"
|
|
35
|
+
echo "KUBERNETES:$yaml_files"
|
|
36
|
+
echo "DOCKER:$dockerfile_files"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
run_static_analysis() {
|
|
40
|
+
local changed_files="$1"
|
|
41
|
+
local iac_files=$(detect_iac_files "$changed_files")
|
|
42
|
+
|
|
43
|
+
# Check if any IaC files are present
|
|
44
|
+
local has_iac=false
|
|
45
|
+
if echo "$iac_files" | grep -qE "TERRAFORM:.*[^\s]|KUBERNETES:.*[^\s]|DOCKER:.*[^\s]"; then
|
|
46
|
+
has_iac=true
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
if [ "$has_iac" = false ]; then
|
|
50
|
+
return 0 # No IaC files, skip
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
54
|
+
echo " GATE: IaC Security Scan"
|
|
55
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
56
|
+
|
|
57
|
+
local exit_code=0
|
|
58
|
+
|
|
59
|
+
# Try checkov first (recommended - supports multiple platforms)
|
|
60
|
+
if command -v checkov >/dev/null 2>&1; then
|
|
61
|
+
echo "Running checkov IaC security scan..."
|
|
62
|
+
|
|
63
|
+
# Run checkov on all detected IaC files
|
|
64
|
+
local tf_files=$(echo "$iac_files" | grep "TERRAFORM:" | sed 's/TERRAFORM://')
|
|
65
|
+
local k8s_files=$(echo "$iac_files" | grep "KUBERNETES:" | sed 's/KUBERNETES://')
|
|
66
|
+
local docker_files=$(echo "$iac_files" | grep "DOCKER:" | sed 's/DOCKER://')
|
|
67
|
+
|
|
68
|
+
if [ -n "$tf_files" ]; then
|
|
69
|
+
echo "Scanning Terraform files..."
|
|
70
|
+
for file in $tf_files; do
|
|
71
|
+
if [ -f "$file" ]; then
|
|
72
|
+
checkov --file "$file" --compact 2>&1 | tail -20
|
|
73
|
+
local tf_exit=${PIPESTATUS[0]}
|
|
74
|
+
if [ $tf_exit -ne 0 ]; then
|
|
75
|
+
exit_code=$tf_exit
|
|
76
|
+
fi
|
|
77
|
+
fi
|
|
78
|
+
done
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
if [ -n "$k8s_files" ]; then
|
|
82
|
+
echo "Scanning Kubernetes manifests..."
|
|
83
|
+
for file in $k8s_files; do
|
|
84
|
+
if [ -f "$file" ]; then
|
|
85
|
+
checkov --file "$file" --compact 2>&1 | tail -20
|
|
86
|
+
local k8s_exit=${PIPESTATUS[0]}
|
|
87
|
+
if [ $k8s_exit -ne 0 ]; then
|
|
88
|
+
exit_code=$k8s_exit
|
|
89
|
+
fi
|
|
90
|
+
fi
|
|
91
|
+
done
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
if [ -n "$docker_files" ]; then
|
|
95
|
+
echo "Scanning Dockerfiles..."
|
|
96
|
+
for file in $docker_files; do
|
|
97
|
+
if [ -f "$file" ]; then
|
|
98
|
+
checkov --file "$file" --compact 2>&1 | tail -20
|
|
99
|
+
local docker_exit=${PIPESTATUS[0]}
|
|
100
|
+
if [ $docker_exit -ne 0 ]; then
|
|
101
|
+
exit_code=$docker_exit
|
|
102
|
+
fi
|
|
103
|
+
fi
|
|
104
|
+
done
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
echo "checkov scan completed with exit code: $exit_code"
|
|
108
|
+
return $exit_code
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
# Fallback to individual tools if checkov not available
|
|
112
|
+
|
|
113
|
+
# Try hadolint for Docker
|
|
114
|
+
local docker_files=$(echo "$iac_files" | grep "DOCKER:" | sed 's/DOCKER://')
|
|
115
|
+
if [ -n "$docker_files" ] && command -v hadolint >/dev/null 2>&1; then
|
|
116
|
+
echo "Running hadolint for Dockerfiles..."
|
|
117
|
+
for file in $docker_files; do
|
|
118
|
+
if [ -f "$file" ]; then
|
|
119
|
+
hadolint "$file" 2>&1 | tail -20
|
|
120
|
+
local hadolint_exit=${PIPESTATUS[0]}
|
|
121
|
+
if [ $hadolint_exit -ne 0 ]; then
|
|
122
|
+
exit_code=$hadolint_exit
|
|
123
|
+
fi
|
|
124
|
+
fi
|
|
125
|
+
done
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
# Try kube-score for Kubernetes
|
|
129
|
+
local k8s_files=$(echo "$iac_files" | grep "KUBERNETES:" | sed 's/KUBERNETES://')
|
|
130
|
+
if [ -n "$k8s_files" ] && command -v kube-score >/dev/null 2>&1; then
|
|
131
|
+
echo "Running kube-score for Kubernetes..."
|
|
132
|
+
for file in $k8s_files; do
|
|
133
|
+
if [ -f "$file" ]; then
|
|
134
|
+
kube-score score "$file" 2>&1 | tail -20
|
|
135
|
+
local kube_exit=${PIPESTATUS[0]}
|
|
136
|
+
if [ $kube_exit -ne 0 ]; then
|
|
137
|
+
exit_code=$kube_exit
|
|
138
|
+
fi
|
|
139
|
+
fi
|
|
140
|
+
done
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
# Try tflint for Terraform
|
|
144
|
+
local tf_files=$(echo "$iac_files" | grep "TERRAFORM:" | sed 's/TERRAFORM://')
|
|
145
|
+
if [ -n "$tf_files" ] && command -v tflint >/dev/null 2>&1; then
|
|
146
|
+
echo "Running tflint for Terraform..."
|
|
147
|
+
for file in $tf_files; do
|
|
148
|
+
if [ -f "$file" ]; then
|
|
149
|
+
tflint --chdir "$(dirname "$file")" 2>&1 | tail -20
|
|
150
|
+
local tflint_exit=${PIPESTATUS[0]}
|
|
151
|
+
if [ $tflint_exit -ne 0 ]; then
|
|
152
|
+
exit_code=$tflint_exit
|
|
153
|
+
fi
|
|
154
|
+
fi
|
|
155
|
+
done
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# If no tools available but IaC files detected, warn user
|
|
159
|
+
if [ $exit_code -eq 0 ]; then
|
|
160
|
+
echo "⚠ IaC files detected but no scanning tools available."
|
|
161
|
+
echo " Install checkov (recommended) or individual tools:"
|
|
162
|
+
echo " - checkov: pip install checkov"
|
|
163
|
+
echo " - hadolint: https://github.com/hadolint/hadolint"
|
|
164
|
+
echo " - kube-score: https://github.com/zegl/kube-score"
|
|
165
|
+
echo " - tflint: https://github.com/terraform-linters/tflint"
|
|
166
|
+
echo ""
|
|
167
|
+
echo " Per QUALITY-GATES-CODE-OF-CONDUCT.md: tool unavailable = BLOCK, not SKIP"
|
|
168
|
+
return 1
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
return $exit_code
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
run_lint() {
|
|
175
|
+
# IaC linting is handled by run_static_analysis
|
|
176
|
+
run_static_analysis "$1"
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
run_tests() {
|
|
180
|
+
# IaC typically doesn't have unit tests in the traditional sense
|
|
181
|
+
# Could add integration tests with terratest (Go) or pytest (Python)
|
|
182
|
+
echo "IaC tests not configured"
|
|
183
|
+
return 0
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
run_coverage() {
|
|
187
|
+
echo "IaC coverage not available"
|
|
188
|
+
return 0
|
|
189
|
+
}
|