guardian-framework 0.1.0
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/LICENSE +21 -0
- package/README.md +463 -0
- package/dist/cli.js +12958 -0
- package/dist/exports.js +12765 -0
- package/package.json +61 -0
- package/templates/languages/go-patterns.md +411 -0
- package/templates/languages/java-patterns.md +545 -0
- package/templates/languages/python-patterns.md +312 -0
- package/templates/languages/rust-patterns.md +232 -0
- package/templates/languages/typescript-patterns.md +313 -0
- package/templates/pi/INDEX.md +437 -0
- package/templates/pi/agent/AGENTS.md +166 -0
- package/templates/pi/agents/architecture-coordinator.md +40 -0
- package/templates/pi/agents/architecture-validator.md +36 -0
- package/templates/pi/agents/bootstrap-implementer.md +37 -0
- package/templates/pi/agents/issue-factory.md +31 -0
- package/templates/pi/agents/operations-validator.md +32 -0
- package/templates/pi/agents/security-validator.md +33 -0
- package/templates/pi/architecture/CHANGELOG.md +78 -0
- package/templates/pi/architecture/decisions/ADR-template.md +76 -0
- package/templates/pi/architecture/diagrams/system-overview.md +159 -0
- package/templates/pi/architecture/modules/module-template.md +152 -0
- package/templates/pi/context/checklists.md +91 -0
- package/templates/pi/context/domain-workflow.md +180 -0
- package/templates/pi/context/output-formats.md +135 -0
- package/templates/pi/context/patterns-base.md +47 -0
- package/templates/pi/context/patterns.md +38 -0
- package/templates/pi/context/project.md +88 -0
- package/templates/pi/domain/exploration.md +93 -0
- package/templates/pi/domain/ubiquitous-language.md +24 -0
- package/templates/pi/extensions/architect-lib/generators.ts +528 -0
- package/templates/pi/extensions/architect-lib/helpers.ts +344 -0
- package/templates/pi/extensions/architect-lib/types.ts +117 -0
- package/templates/pi/extensions/architect.ts +1425 -0
- package/templates/pi/extensions/ask-user-question.ts +579 -0
- package/templates/pi/extensions/bash-guard.ts +556 -0
- package/templates/pi/extensions/config-reload.ts +115 -0
- package/templates/pi/extensions/coordinator.ts +304 -0
- package/templates/pi/extensions/curator.ts +543 -0
- package/templates/pi/extensions/domain-explorer.ts +990 -0
- package/templates/pi/extensions/filechanges.ts +656 -0
- package/templates/pi/extensions/goal-loop.ts +717 -0
- package/templates/pi/extensions/hooks.ts +452 -0
- package/templates/pi/extensions/kanban.ts +547 -0
- package/templates/pi/extensions/pipeline.ts +1246 -0
- package/templates/pi/extensions/plan-mode.ts +209 -0
- package/templates/pi/extensions/project-scaffolder.ts +284 -0
- package/templates/pi/extensions/read-only-mode.ts +192 -0
- package/templates/pi/extensions/redaction.ts +128 -0
- package/templates/pi/extensions/session-persistence.ts +174 -0
- package/templates/pi/extensions/slash-commands.ts +229 -0
- package/templates/pi/extensions/snippets.ts +201 -0
- package/templates/pi/extensions/validation-runner.ts +100 -0
- package/templates/pi/github/agents/architecture-coordinator.agent.md +27 -0
- package/templates/pi/github/agents/architecture-validator.agent.md +20 -0
- package/templates/pi/github/agents/bootstrap-implementer.agent.md +20 -0
- package/templates/pi/github/agents/epic-planner.agent.md +70 -0
- package/templates/pi/github/agents/issue-factory.agent.md +20 -0
- package/templates/pi/github/agents/operations-validator.agent.md +20 -0
- package/templates/pi/github/agents/security-validator.agent.md +20 -0
- package/templates/pi/github/copilot/settings.json +16 -0
- package/templates/pi/github/copilot-instructions.md +155 -0
- package/templates/pi/github/instructions/architecture.instructions.md +71 -0
- package/templates/pi/github/instructions/validation.instructions.md +69 -0
- package/templates/pi/github/workflows/01-planning-workflow.md +75 -0
- package/templates/pi/github/workflows/02-issue-generation-workflow.md +69 -0
- package/templates/pi/github/workflows/03-implementation-workflow.md +80 -0
- package/templates/pi/github/workflows/04-validation-workflow.md +68 -0
- package/templates/pi/preflight_report.json +99 -0
- package/templates/pi/prompts/blueprint-update.md +262 -0
- package/templates/pi/prompts/blueprint-validate.md +218 -0
- package/templates/pi/prompts/bug-fix.md +50 -0
- package/templates/pi/prompts/ci-blueprint.md +131 -0
- package/templates/pi/prompts/context-refresh.md +258 -0
- package/templates/pi/prompts/epic-plan.md +356 -0
- package/templates/pi/prompts/epic-template.md +186 -0
- package/templates/pi/prompts/feature-development.md +131 -0
- package/templates/pi/prompts/git-issues.md +243 -0
- package/templates/pi/prompts/hotfix.md +71 -0
- package/templates/pi/prompts/issue-closeout.md +342 -0
- package/templates/pi/prompts/issue-draft.md +218 -0
- package/templates/pi/prompts/issue-implementation-series.md +173 -0
- package/templates/pi/prompts/issue-merge.md +372 -0
- package/templates/pi/prompts/issue-template-set.md +392 -0
- package/templates/pi/prompts/issue-template.md +207 -0
- package/templates/pi/prompts/pattern-extract.md +269 -0
- package/templates/pi/prompts/plan-to-issues.md +430 -0
- package/templates/pi/prompts/refactoring.md +82 -0
- package/templates/pi/prompts/scope-analyzer.md +254 -0
- package/templates/pi/prompts/sync-check.md +230 -0
- package/templates/pi/scripts/categorize-issues.sh +171 -0
- package/templates/pi/scripts/ci/check_architecture_conformance.sh +748 -0
- package/templates/pi/scripts/ci/check_planning_packet.py +228 -0
- package/templates/pi/scripts/ci/run_hardening_stages.sh +264 -0
- package/templates/pi/scripts/ci/run_preflight.sh +649 -0
- package/templates/pi/scripts/ci/run_stage.sh +193 -0
- package/templates/pi/scripts/ci/stage_docs_policy.sh +82 -0
- package/templates/pi/scripts/ci/stage_integration.sh +3 -0
- package/templates/pi/scripts/ci/stage_lint.sh +130 -0
- package/templates/pi/scripts/ci/stage_migration_verify.sh +3 -0
- package/templates/pi/scripts/ci/stage_package_build.sh +3 -0
- package/templates/pi/scripts/ci/stage_release_readiness.sh +3 -0
- package/templates/pi/scripts/ci/stage_remaining.sh +242 -0
- package/templates/pi/scripts/ci/stage_security.sh +3 -0
- package/templates/pi/scripts/ci/stage_static_analysis.sh +114 -0
- package/templates/pi/scripts/ci/stage_unit.sh +119 -0
- package/templates/pi/scripts/ci/validate_agent_output.py +181 -0
- package/templates/pi/scripts/ci/validate_agent_output.sh +243 -0
- package/templates/pi/scripts/create-feature-branch.sh +136 -0
- package/templates/pi/scripts/create-mr.sh +117 -0
- package/templates/pi/scripts/fetch-issues.sh +131 -0
- package/templates/pi/scripts/generate-architecture.sh +161 -0
- package/templates/pi/scripts/git/close-epic.sh +69 -0
- package/templates/pi/scripts/git/close-issue.sh +35 -0
- package/templates/pi/scripts/git/create-tracking-issue.sh +174 -0
- package/templates/pi/scripts/git/link-issue-to-epic.sh +51 -0
- package/templates/pi/scripts/git/update-tracking-issue.sh +66 -0
- package/templates/pi/scripts/languages/go/validate-architecture.sh +139 -0
- package/templates/pi/scripts/languages/go/validate-canonical.sh +129 -0
- package/templates/pi/scripts/languages/go/validate-ci.sh +132 -0
- package/templates/pi/scripts/languages/go/validate-integration.sh +156 -0
- package/templates/pi/scripts/languages/go/validate-operations.sh +146 -0
- package/templates/pi/scripts/languages/go/validate-security.sh +135 -0
- package/templates/pi/scripts/languages/go/validate-tests.sh +125 -0
- package/templates/pi/scripts/languages/java/validate-annotations.sh +185 -0
- package/templates/pi/scripts/languages/java/validate-architecture.sh +159 -0
- package/templates/pi/scripts/languages/java/validate-canonical.sh +114 -0
- package/templates/pi/scripts/languages/java/validate-ci.sh +269 -0
- package/templates/pi/scripts/languages/java/validate-integration.sh +149 -0
- package/templates/pi/scripts/languages/java/validate-operations.sh +142 -0
- package/templates/pi/scripts/languages/java/validate-security.sh +174 -0
- package/templates/pi/scripts/languages/java/validate-spring-architecture.sh +227 -0
- package/templates/pi/scripts/languages/java/validate-tests.sh +159 -0
- package/templates/pi/scripts/languages/python/validate-architecture.sh +99 -0
- package/templates/pi/scripts/languages/python/validate-canonical.sh +124 -0
- package/templates/pi/scripts/languages/python/validate-ci.sh +130 -0
- package/templates/pi/scripts/languages/python/validate-integration.sh +119 -0
- package/templates/pi/scripts/languages/python/validate-operations.sh +107 -0
- package/templates/pi/scripts/languages/python/validate-security.sh +68 -0
- package/templates/pi/scripts/languages/python/validate-tests.sh +102 -0
- package/templates/pi/scripts/languages/rust/validate-architecture.sh +188 -0
- package/templates/pi/scripts/languages/rust/validate-canonical.sh +146 -0
- package/templates/pi/scripts/languages/rust/validate-ci.sh +147 -0
- package/templates/pi/scripts/languages/rust/validate-integration.sh +149 -0
- package/templates/pi/scripts/languages/rust/validate-operations.sh +154 -0
- package/templates/pi/scripts/languages/rust/validate-security.sh +153 -0
- package/templates/pi/scripts/languages/rust/validate-tests.sh +150 -0
- package/templates/pi/scripts/languages/typescript/validate-architecture.sh +157 -0
- package/templates/pi/scripts/languages/typescript/validate-canonical.sh +135 -0
- package/templates/pi/scripts/languages/typescript/validate-ci.sh +244 -0
- package/templates/pi/scripts/languages/typescript/validate-integration.sh +166 -0
- package/templates/pi/scripts/languages/typescript/validate-operations.sh +162 -0
- package/templates/pi/scripts/languages/typescript/validate-security.sh +169 -0
- package/templates/pi/scripts/languages/typescript/validate-tests.sh +158 -0
- package/templates/pi/scripts/merge-mr.sh +95 -0
- package/templates/pi/scripts/mr-validation.sh +228 -0
- package/templates/pi/scripts/validate-architecture-readiness.sh +153 -0
- package/templates/pi/scripts/validate-architecture.sh +22 -0
- package/templates/pi/scripts/validate-canonical.sh +22 -0
- package/templates/pi/scripts/validate-ci.sh +37 -0
- package/templates/pi/scripts/validate-integration.sh +22 -0
- package/templates/pi/scripts/validate-operations.sh +22 -0
- package/templates/pi/scripts/validate-security.sh +22 -0
- package/templates/pi/scripts/validate-tests.sh +22 -0
- package/templates/pi/scripts/validate-ubiquitous-language.sh +291 -0
- package/templates/pi/scripts/validation-cache.sh +139 -0
- package/templates/pi/skills/agents/architecture-coordinator.md +178 -0
- package/templates/pi/skills/agents/architecture-generator.md +79 -0
- package/templates/pi/skills/agents/architecture-validator.md +74 -0
- package/templates/pi/skills/agents/ci-mr-validator.md +46 -0
- package/templates/pi/skills/agents/code-developer.md +76 -0
- package/templates/pi/skills/agents/commit.md +46 -0
- package/templates/pi/skills/agents/curator.md +71 -0
- package/templates/pi/skills/agents/debug.md +59 -0
- package/templates/pi/skills/agents/documentation-maintainer.md +36 -0
- package/templates/pi/skills/agents/goal-loop.md +125 -0
- package/templates/pi/skills/agents/hooks.md +122 -0
- package/templates/pi/skills/agents/integration-validator.md +35 -0
- package/templates/pi/skills/agents/issue-creator.md +75 -0
- package/templates/pi/skills/agents/issue-factory.md +143 -0
- package/templates/pi/skills/agents/kanban.md +85 -0
- package/templates/pi/skills/agents/land.md +59 -0
- package/templates/pi/skills/agents/operations-validator.md +43 -0
- package/templates/pi/skills/agents/pipeline.md +113 -0
- package/templates/pi/skills/agents/plan-mode.md +77 -0
- package/templates/pi/skills/agents/pull.md +40 -0
- package/templates/pi/skills/agents/push.md +41 -0
- package/templates/pi/skills/agents/security-validator.md +85 -0
- package/templates/pi/skills/agents/session-persistence.md +119 -0
- package/templates/pi/skills/agents/slash-commands.md +117 -0
- package/templates/pi/skills/agents/snippets.md +99 -0
- package/templates/pi/skills/agents/subagent-registry.md +78 -0
- package/templates/pi/skills/agents/test-validator.md +42 -0
- package/templates/pi/skills/validators/architecture-validator.md +43 -0
- package/templates/pi/skills/validators/ci-validator.md +27 -0
- package/templates/pi/skills/validators/context-compaction.md +73 -0
- package/templates/pi/skills/validators/integration-validator.md +38 -0
- package/templates/pi/skills/validators/model-registry.md +96 -0
- package/templates/pi/skills/validators/operations-validator.md +34 -0
- package/templates/pi/skills/validators/security-guards.md +72 -0
- package/templates/pi/skills/validators/security-validator.md +41 -0
- package/templates/pi/skills/validators/system-prompt-tiers.md +69 -0
- package/templates/pi/skills/validators/test-validator.md +33 -0
- package/templates/pi/types.ts +62 -0
- package/templates/pi/validators/README.md +93 -0
- package/templates/pi/validators/default.toml +209 -0
- package/templates/pi/validators/spring.toml +142 -0
- package/templates/pi/workpad.md +53 -0
- package/templates/project/java/Dockerfile +14 -0
- package/templates/project/java/README.md +40 -0
- package/templates/project/java/pom.xml +132 -0
- package/templates/project/typescript/Dockerfile +15 -0
- package/templates/project/typescript/README.md +29 -0
- package/templates/project/typescript/package.json +23 -0
- package/templates/project/typescript/tsconfig.json +21 -0
- package/templates/workflow.md +123 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# validate-canonical.sh — Python
|
|
4
|
+
# ============================================================================
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
if [ -f "poetry.lock" ] && command -v poetry &>/dev/null; then
|
|
8
|
+
POETRY_ENV=$(poetry env info --path 2>/dev/null || true)
|
|
9
|
+
if [ -n "$POETRY_ENV" ] && [ -f "$POETRY_ENV/bin/activate" ]; then
|
|
10
|
+
source "$POETRY_ENV/bin/activate"
|
|
11
|
+
fi
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
PASS_COUNT=0; ERRORS=(); WARNINGS=()
|
|
15
|
+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
|
16
|
+
pass() { echo -e "${GREEN}✅ PASS${NC} $1"; PASS_COUNT=$((PASS_COUNT + 1)); }
|
|
17
|
+
fail() { echo -e "${RED}❌ FAIL${NC} $1"; ERRORS+=("$1"); }
|
|
18
|
+
warn() { echo -e "${YELLOW}⚠️ WARN${NC} $1"; WARNINGS+=("$1"); }
|
|
19
|
+
|
|
20
|
+
echo "============================================"
|
|
21
|
+
echo " Canonical Validation (Python)"
|
|
22
|
+
echo "============================================"
|
|
23
|
+
echo ""
|
|
24
|
+
|
|
25
|
+
SRC_DIR="${1:-src}"
|
|
26
|
+
|
|
27
|
+
# ── Architecture reference tracing ──
|
|
28
|
+
echo "--- Architecture Reference Tracing ---"
|
|
29
|
+
TOTAL_PY_FILES=$(find "$SRC_DIR" -name "*.py" 2>/dev/null | wc -l | tr -d ' ')
|
|
30
|
+
if [ "$TOTAL_PY_FILES" -gt 0 ]; then
|
|
31
|
+
FILES_WITH_REFS=$(grep -rlE "(Canonical:|@canonical|Reference:.*\.pi/architecture)" "$SRC_DIR" --include="*.py" 2>/dev/null | wc -l | tr -d ' ')
|
|
32
|
+
PCT=$((FILES_WITH_REFS * 100 / TOTAL_PY_FILES))
|
|
33
|
+
if [ "$FILES_WITH_REFS" -gt 0 ]; then
|
|
34
|
+
pass "Canonical references detected in $FILES_WITH_REFS/$TOTAL_PY_FILES files (${PCT}%)"
|
|
35
|
+
else
|
|
36
|
+
fail "No canonical reference comments found in source files"
|
|
37
|
+
fi
|
|
38
|
+
else
|
|
39
|
+
warn "No source files found to check"
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# ── Module-to-implementation mapping ──
|
|
43
|
+
echo ""
|
|
44
|
+
echo "--- Module-to-Implementation Mapping ---"
|
|
45
|
+
if [ -d ".pi/architecture/modules" ]; then
|
|
46
|
+
MISSING=0
|
|
47
|
+
for module_file in .pi/architecture/modules/*.md; do
|
|
48
|
+
[ -f "$module_file" ] || continue
|
|
49
|
+
# Extract component file paths from the module doc
|
|
50
|
+
while IFS= read -r impl_path; do
|
|
51
|
+
impl_path=$(echo "$impl_path" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
52
|
+
[ -z "$impl_path" ] && continue
|
|
53
|
+
# Strip backticks and quotes
|
|
54
|
+
impl_path=$(echo "$impl_path" | tr -d '`"' | sed "s/'//g")
|
|
55
|
+
if [ -n "$impl_path" ]; then
|
|
56
|
+
if [ ! -f "$impl_path" ]; then
|
|
57
|
+
warn "Architecture references $impl_path but file does not exist"
|
|
58
|
+
((MISSING++))
|
|
59
|
+
fi
|
|
60
|
+
fi
|
|
61
|
+
done < <(grep -oE '`[a-z_/]+\.py`' "$module_file" 2>/dev/null || true)
|
|
62
|
+
done
|
|
63
|
+
if [ "$MISSING" -eq 0 ]; then
|
|
64
|
+
pass "All architecture-referenced implementation files exist"
|
|
65
|
+
else
|
|
66
|
+
warn "$MISSING referenced implementation file(s) missing"
|
|
67
|
+
fi
|
|
68
|
+
else
|
|
69
|
+
warn "No architecture modules directory found"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# ── Package documentation ──
|
|
73
|
+
echo ""
|
|
74
|
+
echo "--- Package Documentation ---"
|
|
75
|
+
INIT_DOCS=0
|
|
76
|
+
INIT_WITHOUT_DOCS=0
|
|
77
|
+
for init_file in $(find "$SRC_DIR" -name "__init__.py" 2>/dev/null | head -20); do
|
|
78
|
+
if grep -qE '"""|"""' "$init_file" 2>/dev/null; then
|
|
79
|
+
((INIT_DOCS++))
|
|
80
|
+
else
|
|
81
|
+
((INIT_WITHOUT_DOCS++))
|
|
82
|
+
fi
|
|
83
|
+
done
|
|
84
|
+
if [ "$INIT_DOCS" -gt 0 ]; then
|
|
85
|
+
pass "Package docstrings found in $INIT_DOCS __init__.py files"
|
|
86
|
+
fi
|
|
87
|
+
if [ "$INIT_WITHOUT_DOCS" -gt 0 ]; then
|
|
88
|
+
warn "$INIT_WITHOUT_DOCS __init__.py file(s) lack docstrings"
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# ── ADR linkage ──
|
|
92
|
+
echo ""
|
|
93
|
+
echo "--- ADR Linkage ---"
|
|
94
|
+
if [ -d ".pi/architecture/decisions" ]; then
|
|
95
|
+
ADR_COUNT=$(find .pi/architecture/decisions -name "ADR-*.md" 2>/dev/null | wc -l | tr -d ' ')
|
|
96
|
+
ADR_REFS=$(grep -rlE "ADR-[0-9]+" "$SRC_DIR" --include="*.py" 2>/dev/null | wc -l | tr -d ' ')
|
|
97
|
+
if [ "$ADR_REFS" -gt 0 ]; then
|
|
98
|
+
pass "ADR references found in $ADR_REFS source files ($ADR_COUNT ADRs exist)"
|
|
99
|
+
else
|
|
100
|
+
warn "No ADR references found in source files (consider documenting architectural decisions)"
|
|
101
|
+
fi
|
|
102
|
+
else
|
|
103
|
+
warn "No ADR directory found at .pi/architecture/decisions/"
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
# ── Summary ──
|
|
107
|
+
echo ""
|
|
108
|
+
echo "============================================"
|
|
109
|
+
echo " Summary"
|
|
110
|
+
echo "============================================"
|
|
111
|
+
echo -e " Passed: ${GREEN}${PASS_COUNT}${NC}"
|
|
112
|
+
echo -e " Failed: ${RED}${#ERRORS[@]}${NC}"
|
|
113
|
+
echo ""
|
|
114
|
+
|
|
115
|
+
if [ ${#ERRORS[@]} -gt 0 ]; then
|
|
116
|
+
echo "FAILURES:"
|
|
117
|
+
for err in "${ERRORS[@]}"; do
|
|
118
|
+
echo " - $err"
|
|
119
|
+
done
|
|
120
|
+
exit 1
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
echo -e "${GREEN}Canonical validation passed.${NC}"
|
|
124
|
+
exit 0
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# validate-ci.sh — Python (Poetry-based)
|
|
4
|
+
# ============================================================================
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
# Activate Poetry venv if available
|
|
8
|
+
if [ -f "poetry.lock" ] && command -v poetry &>/dev/null; then
|
|
9
|
+
POETRY_ENV=$(poetry env info --path 2>/dev/null || true)
|
|
10
|
+
if [ -n "$POETRY_ENV" ] && [ -f "$POETRY_ENV/bin/activate" ]; then
|
|
11
|
+
source "$POETRY_ENV/bin/activate"
|
|
12
|
+
fi
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
ERRORS=()
|
|
16
|
+
WARNINGS=()
|
|
17
|
+
PASS_COUNT=0
|
|
18
|
+
|
|
19
|
+
RED='\033[0;31m'
|
|
20
|
+
GREEN='\033[0;32m'
|
|
21
|
+
YELLOW='\033[1;33m'
|
|
22
|
+
NC='\033[0m'
|
|
23
|
+
|
|
24
|
+
pass() { echo -e "${GREEN}✅ PASS${NC} $1"; PASS_COUNT=$((PASS_COUNT + 1)); }
|
|
25
|
+
fail() { echo -e "${RED}❌ FAIL${NC} $1"; ERRORS+=("$1"); }
|
|
26
|
+
warn() { echo -e "${YELLOW}⚠️ WARN${NC} $1"; WARNINGS+=("$1"); }
|
|
27
|
+
|
|
28
|
+
echo "============================================"
|
|
29
|
+
echo " CI/MR Validation (Python)"
|
|
30
|
+
echo "============================================"
|
|
31
|
+
echo ""
|
|
32
|
+
|
|
33
|
+
# ---------------------------------------------------------------------------
|
|
34
|
+
# Build
|
|
35
|
+
# ---------------------------------------------------------------------------
|
|
36
|
+
echo "--- Build ---"
|
|
37
|
+
if [ -f "poetry.lock" ] && command -v poetry &>/dev/null; then
|
|
38
|
+
if poetry build 2>/dev/null; then
|
|
39
|
+
pass "Build succeeded"
|
|
40
|
+
else
|
|
41
|
+
fail "Build failed"
|
|
42
|
+
fi
|
|
43
|
+
else
|
|
44
|
+
pass "No build step (dev project)"
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
# Tests
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
echo ""
|
|
51
|
+
echo "--- Tests ---"
|
|
52
|
+
if command -v pytest &>/dev/null; then
|
|
53
|
+
if PYTHONPATH=src pytest -q 2>/dev/null; then
|
|
54
|
+
pass "All tests passed"
|
|
55
|
+
else
|
|
56
|
+
fail "Tests failed"
|
|
57
|
+
fi
|
|
58
|
+
else
|
|
59
|
+
warn "pytest not available, skipping tests"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
# Lint
|
|
64
|
+
# ---------------------------------------------------------------------------
|
|
65
|
+
echo ""
|
|
66
|
+
echo "--- Lint ---"
|
|
67
|
+
if command -v ruff &>/dev/null; then
|
|
68
|
+
if ruff check . 2>/dev/null; then
|
|
69
|
+
pass "Lint passed"
|
|
70
|
+
else
|
|
71
|
+
fail "Lint failed"
|
|
72
|
+
fi
|
|
73
|
+
else
|
|
74
|
+
warn "ruff not available, skipping lint"
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# ---------------------------------------------------------------------------
|
|
78
|
+
# Format
|
|
79
|
+
# ---------------------------------------------------------------------------
|
|
80
|
+
echo ""
|
|
81
|
+
echo "--- Format ---"
|
|
82
|
+
if command -v ruff &>/dev/null; then
|
|
83
|
+
if ruff format --check . 2>/dev/null; then
|
|
84
|
+
pass "Format check passed"
|
|
85
|
+
else
|
|
86
|
+
fail "Format check failed"
|
|
87
|
+
fi
|
|
88
|
+
else
|
|
89
|
+
warn "ruff not available, skipping format"
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# ---------------------------------------------------------------------------
|
|
93
|
+
# Security Audit
|
|
94
|
+
# ---------------------------------------------------------------------------
|
|
95
|
+
echo ""
|
|
96
|
+
echo "--- Security Audit ---"
|
|
97
|
+
if command -v pip-audit &>/dev/null && [ -f "pyproject.toml" ]; then
|
|
98
|
+
AUDIT_OUT=$(pip-audit 2>&1 || true)
|
|
99
|
+
if echo "$AUDIT_OUT" | grep -q "no known vulnerabilities"; then
|
|
100
|
+
pass "No known vulnerabilities"
|
|
101
|
+
elif echo "$AUDIT_OUT" | grep -q "Dependency not found on PyPI"; then
|
|
102
|
+
pass "Dependencies audited (local package skipped)"
|
|
103
|
+
else
|
|
104
|
+
warn "pip-audit reported findings (review manually)"
|
|
105
|
+
fi
|
|
106
|
+
else
|
|
107
|
+
warn "pip-audit not available, skipping audit"
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
# ---------------------------------------------------------------------------
|
|
111
|
+
# Summary
|
|
112
|
+
# ---------------------------------------------------------------------------
|
|
113
|
+
echo ""
|
|
114
|
+
echo "============================================"
|
|
115
|
+
echo " Summary"
|
|
116
|
+
echo "============================================"
|
|
117
|
+
echo -e " Passed: ${GREEN}${PASS_COUNT}${NC}"
|
|
118
|
+
echo -e " Failed: ${RED}${#ERRORS[@]}${NC}"
|
|
119
|
+
echo ""
|
|
120
|
+
|
|
121
|
+
if [ ${#ERRORS[@]} -gt 0 ]; then
|
|
122
|
+
echo "FAILURES:"
|
|
123
|
+
for err in "${ERRORS[@]}"; do
|
|
124
|
+
echo " - $err"
|
|
125
|
+
done
|
|
126
|
+
exit 1
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
echo -e "${GREEN}All CI checks passed.${NC}"
|
|
130
|
+
exit 0
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# validate-integration.sh — Python
|
|
4
|
+
# ============================================================================
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
if [ -f "poetry.lock" ] && command -v poetry &>/dev/null; then
|
|
8
|
+
POETRY_ENV=$(poetry env info --path 2>/dev/null || true)
|
|
9
|
+
if [ -n "$POETRY_ENV" ] && [ -f "$POETRY_ENV/bin/activate" ]; then
|
|
10
|
+
source "$POETRY_ENV/bin/activate"
|
|
11
|
+
fi
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
PASS_COUNT=0; ERRORS=(); WARNINGS=()
|
|
15
|
+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
|
16
|
+
pass() { echo -e "${GREEN}✅ PASS${NC} $1"; PASS_COUNT=$((PASS_COUNT + 1)); }
|
|
17
|
+
fail() { echo -e "${RED}❌ FAIL${NC} $1"; ERRORS+=("$1"); }
|
|
18
|
+
warn() { echo -e "${YELLOW}⚠️ WARN${NC} $1"; WARNINGS+=("$1"); }
|
|
19
|
+
|
|
20
|
+
echo "============================================"
|
|
21
|
+
echo " Integration Validation (Python)"
|
|
22
|
+
echo "============================================"
|
|
23
|
+
echo ""
|
|
24
|
+
|
|
25
|
+
# ── Integration Tests ──
|
|
26
|
+
echo "--- Integration Tests ---"
|
|
27
|
+
if [ -d "tests/integration" ] && command -v pytest &>/dev/null; then
|
|
28
|
+
if PYTHONPATH=src pytest tests/integration -q 2>/dev/null; then
|
|
29
|
+
pass "Integration tests passed"
|
|
30
|
+
else
|
|
31
|
+
fail "Integration tests failed"
|
|
32
|
+
fi
|
|
33
|
+
elif [ -d "tests/integration" ]; then
|
|
34
|
+
warn "Integration test directory exists but pytest is not available"
|
|
35
|
+
else
|
|
36
|
+
pass "No integration tests directory (skipped)"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# ── Docker/Compose Detection ──
|
|
40
|
+
echo ""
|
|
41
|
+
echo "--- Docker/Compose Detection ---"
|
|
42
|
+
if [ -f "docker-compose.yml" ] || [ -f "docker-compose.yaml" ]; then
|
|
43
|
+
warn "Docker Compose detected — integration tests may require running services"
|
|
44
|
+
pass "Docker Compose configuration present"
|
|
45
|
+
else
|
|
46
|
+
pass "No Docker Compose configuration"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# ── Contract Tests ──
|
|
50
|
+
echo ""
|
|
51
|
+
echo "--- Contract Tests ---"
|
|
52
|
+
CONTRACT_COUNT=$(find tests -name "*contract*" -o -name "*pact*" 2>/dev/null | wc -l | tr -d ' ')
|
|
53
|
+
if [ "$CONTRACT_COUNT" -gt 0 ]; then
|
|
54
|
+
pass "Contract test files found ($CONTRACT_COUNT)"
|
|
55
|
+
else
|
|
56
|
+
warn "No contract tests found"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# ── Mock/Stub Detection ──
|
|
60
|
+
echo ""
|
|
61
|
+
echo "--- Mock/Stub Detection ---"
|
|
62
|
+
HAS_MOCKS=false
|
|
63
|
+
for pattern in "unittest.mock" "mock.patch" "pytest-mock" "responses" "httpretty" "aioresponses" "responses.activate"; do
|
|
64
|
+
if grep -rq "$pattern" tests/ --include="*.py" 2>/dev/null; then
|
|
65
|
+
HAS_MOCKS=true
|
|
66
|
+
break
|
|
67
|
+
fi
|
|
68
|
+
done
|
|
69
|
+
if [ "$HAS_MOCKS" = true ]; then
|
|
70
|
+
pass "Mock/stub patterns detected in test suite"
|
|
71
|
+
else
|
|
72
|
+
warn "No mock patterns found in test suite"
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# ── Database Integration Tests ──
|
|
76
|
+
echo ""
|
|
77
|
+
echo "--- Database Integration Tests ---"
|
|
78
|
+
DB_TEST_COUNT=$(grep -rlE "(pytest.*db|session_scope|test_db|database_url|SQLALCHEMY)" tests/ --include="*.py" 2>/dev/null | wc -l | tr -d ' ')
|
|
79
|
+
if [ "$DB_TEST_COUNT" -gt 0 ]; then
|
|
80
|
+
pass "Database integration tests found ($DB_TEST_COUNT files)"
|
|
81
|
+
else
|
|
82
|
+
pass "No database integration tests (skipped if not applicable)"
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# ── HTTP Integration Tests ──
|
|
86
|
+
echo ""
|
|
87
|
+
echo "--- HTTP Integration Tests ---"
|
|
88
|
+
HAS_HTTP_TEST=false
|
|
89
|
+
for pattern in "TestClient" "httpx.AsyncClient" "aiohttp.test" "responses" "requests_mock"; do
|
|
90
|
+
if grep -rq "$pattern" tests/ --include="*.py" 2>/dev/null; then
|
|
91
|
+
HAS_HTTP_TEST=true
|
|
92
|
+
break
|
|
93
|
+
fi
|
|
94
|
+
done
|
|
95
|
+
if [ "$HAS_HTTP_TEST" = true ]; then
|
|
96
|
+
pass "HTTP integration test patterns detected"
|
|
97
|
+
else
|
|
98
|
+
pass "No HTTP integration test patterns found"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# ── Summary ──
|
|
102
|
+
echo ""
|
|
103
|
+
echo "============================================"
|
|
104
|
+
echo " Summary"
|
|
105
|
+
echo "============================================"
|
|
106
|
+
echo -e " Passed: ${GREEN}${PASS_COUNT}${NC}"
|
|
107
|
+
echo -e " Failed: ${RED}${#ERRORS[@]}${NC}"
|
|
108
|
+
echo ""
|
|
109
|
+
|
|
110
|
+
if [ ${#ERRORS[@]} -gt 0 ]; then
|
|
111
|
+
echo "FAILURES:"
|
|
112
|
+
for err in "${ERRORS[@]}"; do
|
|
113
|
+
echo " - $err"
|
|
114
|
+
done
|
|
115
|
+
exit 1
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
echo -e "${GREEN}Integration validation passed.${NC}"
|
|
119
|
+
exit 0
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# validate-operations.sh — Python
|
|
4
|
+
# ============================================================================
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
if [ -f "poetry.lock" ] && command -v poetry &>/dev/null; then
|
|
8
|
+
POETRY_ENV=$(poetry env info --path 2>/dev/null || true)
|
|
9
|
+
if [ -n "$POETRY_ENV" ] && [ -f "$POETRY_ENV/bin/activate" ]; then
|
|
10
|
+
source "$POETRY_ENV/bin/activate"
|
|
11
|
+
fi
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
PASS_COUNT=0; ERRORS=(); WARNINGS=()
|
|
15
|
+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
|
16
|
+
pass() { echo -e "${GREEN}✅ PASS${NC} $1"; PASS_COUNT=$((PASS_COUNT + 1)); }
|
|
17
|
+
fail() { echo -e "${RED}❌ FAIL${NC} $1"; ERRORS+=("$1"); }
|
|
18
|
+
warn() { echo -e "${YELLOW}⚠️ WARN${NC} $1"; WARNINGS+=("$1"); }
|
|
19
|
+
|
|
20
|
+
echo "============================================"
|
|
21
|
+
echo " Operations Validation (Python)"
|
|
22
|
+
echo "============================================"
|
|
23
|
+
echo ""
|
|
24
|
+
|
|
25
|
+
SRC_DIR="${1:-src}"
|
|
26
|
+
|
|
27
|
+
# ── Structured Logging ──
|
|
28
|
+
echo "--- Structured Logging ---"
|
|
29
|
+
if grep -rqE "(structlog|import logging|loguru|log\.info|log\.error|logger\.info|logger\.error)" "$SRC_DIR" --include="*.py" 2>/dev/null; then
|
|
30
|
+
pass "Structured logging detected"
|
|
31
|
+
else
|
|
32
|
+
warn "No structured logging framework detected"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# ── Health Checks ──
|
|
36
|
+
echo ""
|
|
37
|
+
echo "--- Health Checks ---"
|
|
38
|
+
if grep -rqE "(/health|/healthz|healthcheck)" "$SRC_DIR" --include="*.py" 2>/dev/null; then
|
|
39
|
+
pass "Health check endpoint(s) detected"
|
|
40
|
+
else
|
|
41
|
+
warn "No health check endpoints found"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# ── Graceful Shutdown ──
|
|
45
|
+
echo ""
|
|
46
|
+
echo "--- Graceful Shutdown ---"
|
|
47
|
+
if grep -rqE "signal\.(signal|SIGTERM|SIGINT)|atexit\.register|contextmanager" "$SRC_DIR" --include="*.py" 2>/dev/null; then
|
|
48
|
+
pass "Graceful shutdown patterns detected"
|
|
49
|
+
else
|
|
50
|
+
warn "No graceful shutdown patterns found"
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# ── Metrics ──
|
|
54
|
+
echo ""
|
|
55
|
+
echo "--- Metrics & Observability ---"
|
|
56
|
+
if grep -rqE "(prometheus_client|opentelemetry|datadog|statsd|metrics|counter|histogram|gauge)" "$SRC_DIR" --include="*.py" 2>/dev/null; then
|
|
57
|
+
pass "Metrics framework detected"
|
|
58
|
+
else
|
|
59
|
+
warn "No metrics framework detected"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# ── Distributed Tracing ──
|
|
63
|
+
echo ""
|
|
64
|
+
echo "--- Distributed Tracing ---"
|
|
65
|
+
if grep -rqE "(opentelemetry|jaeger|zipkin|sentry_sdk|ddtrace)" "$SRC_DIR" --include="*.py" 2>/dev/null; then
|
|
66
|
+
pass "Distributed tracing detected"
|
|
67
|
+
else
|
|
68
|
+
warn "No distributed tracing detected"
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
# ── Configuration Management ──
|
|
72
|
+
echo ""
|
|
73
|
+
echo "--- Configuration Management ---"
|
|
74
|
+
if grep -rqE "(pydantic\.BaseSettings|pydantic_settings|environ|os\.environ|dynaconf|python-dotenv)" "$SRC_DIR" --include="*.py" 2>/dev/null; then
|
|
75
|
+
pass "Configuration management framework detected"
|
|
76
|
+
else
|
|
77
|
+
warn "No configuration management detected (consider pydantic-settings or environs)"
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# ── Retry & Resilience ──
|
|
81
|
+
echo ""
|
|
82
|
+
echo "--- Retry & Resilience ---"
|
|
83
|
+
if grep -rqE "(tenacity|@retry|backoff|circuitbreaker)" "$SRC_DIR" --include="*.py" 2>/dev/null; then
|
|
84
|
+
pass "Retry/resilience patterns detected"
|
|
85
|
+
else
|
|
86
|
+
warn "No retry or circuit breaker patterns found"
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# ── Summary ──
|
|
90
|
+
echo ""
|
|
91
|
+
echo "============================================"
|
|
92
|
+
echo " Summary"
|
|
93
|
+
echo "============================================"
|
|
94
|
+
echo -e " Passed: ${GREEN}${PASS_COUNT}${NC}"
|
|
95
|
+
echo -e " Failed: ${RED}${#ERRORS[@]}${NC}"
|
|
96
|
+
echo ""
|
|
97
|
+
|
|
98
|
+
if [ ${#ERRORS[@]} -gt 0 ]; then
|
|
99
|
+
echo "FAILURES:"
|
|
100
|
+
for err in "${ERRORS[@]}"; do
|
|
101
|
+
echo " - $err"
|
|
102
|
+
done
|
|
103
|
+
exit 1
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
echo -e "${GREEN}Operations validation passed.${NC}"
|
|
107
|
+
exit 0
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# validate-security.sh — Python
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
# Activate Poetry venv if available
|
|
6
|
+
if [ -f "poetry.lock" ] && command -v poetry &>/dev/null; then
|
|
7
|
+
POETRY_ENV=$(poetry env info --path 2>/dev/null || true)
|
|
8
|
+
if [ -n "$POETRY_ENV" ] && [ -f "$POETRY_ENV/bin/activate" ]; then
|
|
9
|
+
source "$POETRY_ENV/bin/activate"
|
|
10
|
+
fi
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
SRC_DIR="${1:-src}"
|
|
14
|
+
PASS_COUNT=0; ERRORS=(); WARNINGS=()
|
|
15
|
+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
|
16
|
+
pass() { echo -e "${GREEN}✅ PASS${NC} $1"; PASS_COUNT=$((PASS_COUNT + 1)); }
|
|
17
|
+
fail() { echo -e "${RED}❌ FAIL${NC} $1"; ERRORS+=("$1"); }
|
|
18
|
+
warn() { echo -e "${YELLOW}⚠️ WARN${NC} $1"; WARNINGS+=("$1"); }
|
|
19
|
+
|
|
20
|
+
echo "============================================"
|
|
21
|
+
echo " Security Scan (Python)"
|
|
22
|
+
echo "============================================"
|
|
23
|
+
|
|
24
|
+
# Hardcoded secrets
|
|
25
|
+
echo "--- Hardcoded Secrets ---"
|
|
26
|
+
SECRET_COUNT=$(grep -rE "(api_key|secret_key|password|token)\s*=\s*['\"][^'\"]{8,}" "$SRC_DIR" --include="*.py" 2>/dev/null | grep -v "__init__" | grep -v "test" | wc -l | tr -d ' ')
|
|
27
|
+
if [ "$SECRET_COUNT" -eq 0 ]; then
|
|
28
|
+
pass "No hardcoded secrets detected"
|
|
29
|
+
else
|
|
30
|
+
warn "Potential hardcoded secrets ($SECRET_COUNT findings)"
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# SQL injection
|
|
34
|
+
echo ""
|
|
35
|
+
echo "--- Injection Patterns ---"
|
|
36
|
+
INJECT_COUNT=$(grep -rE "(execute|cursor\.execute)\s*\(\s*['\"]" "$SRC_DIR" --include="*.py" 2>/dev/null | wc -l | tr -d ' ')
|
|
37
|
+
if [ "$INJECT_COUNT" -eq 0 ]; then
|
|
38
|
+
pass "No obvious injection patterns"
|
|
39
|
+
else
|
|
40
|
+
warn "Potential injection patterns ($INJECT_COUNT findings — verify parameterized queries)"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Dependency audit
|
|
44
|
+
echo ""
|
|
45
|
+
echo "--- Dependency Audit ---"
|
|
46
|
+
if command -v pip-audit &>/dev/null && [ -f "pyproject.toml" ]; then
|
|
47
|
+
AUDIT_OUT=$(pip-audit 2>&1 || true)
|
|
48
|
+
if echo "$AUDIT_OUT" | grep -q "no known vulnerabilities"; then
|
|
49
|
+
pass "No known vulnerabilities"
|
|
50
|
+
elif echo "$AUDIT_OUT" | grep -q "Dependency not found on PyPI"; then
|
|
51
|
+
pass "Dependencies audited (local package skipped)"
|
|
52
|
+
else
|
|
53
|
+
warn "pip-audit reported findings (review manually)"
|
|
54
|
+
fi
|
|
55
|
+
else
|
|
56
|
+
warn "pip-audit not available"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Summary
|
|
60
|
+
echo ""
|
|
61
|
+
echo "============================================"
|
|
62
|
+
echo " Passed: ${GREEN}${PASS_COUNT}${NC} Failed: ${RED}${#ERRORS[@]}${NC} Warn: ${YELLOW}${#WARNINGS[@]}${NC}"
|
|
63
|
+
if [ ${#ERRORS[@]} -gt 0 ]; then
|
|
64
|
+
for err in "${ERRORS[@]}"; do echo " - $err"; done
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
echo -e "${GREEN}Security scan passed.${NC}"
|
|
68
|
+
exit 0
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# validate-tests.sh — Python (Poetry-based)
|
|
4
|
+
# ============================================================================
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
# Activate Poetry venv if available
|
|
8
|
+
if [ -f "poetry.lock" ] && command -v poetry &>/dev/null; then
|
|
9
|
+
POETRY_ENV=$(poetry env info --path 2>/dev/null || true)
|
|
10
|
+
if [ -n "$POETRY_ENV" ] && [ -f "$POETRY_ENV/bin/activate" ]; then
|
|
11
|
+
source "$POETRY_ENV/bin/activate"
|
|
12
|
+
fi
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
ERRORS=()
|
|
16
|
+
WARNINGS=()
|
|
17
|
+
PASS_COUNT=0
|
|
18
|
+
|
|
19
|
+
RED='\033[0;31m'
|
|
20
|
+
GREEN='\033[0;32m'
|
|
21
|
+
YELLOW='\033[1;33m'
|
|
22
|
+
NC='\033[0m'
|
|
23
|
+
|
|
24
|
+
pass() { echo -e "${GREEN}✅ PASS${NC} $1"; PASS_COUNT=$((PASS_COUNT + 1)); }
|
|
25
|
+
fail() { echo -e "${RED}❌ FAIL${NC} $1"; ERRORS+=("$1"); }
|
|
26
|
+
warn() { echo -e "${YELLOW}⚠️ WARN${NC} $1"; WARNINGS+=("$1"); }
|
|
27
|
+
|
|
28
|
+
echo "============================================"
|
|
29
|
+
echo " Test Validation (Python)"
|
|
30
|
+
echo "============================================"
|
|
31
|
+
echo ""
|
|
32
|
+
|
|
33
|
+
# ---------------------------------------------------------------------------
|
|
34
|
+
# Unit Tests
|
|
35
|
+
# ---------------------------------------------------------------------------
|
|
36
|
+
echo "--- Unit Tests ---"
|
|
37
|
+
if [ -d "tests/unit" ] && command -v pytest &>/dev/null; then
|
|
38
|
+
if PYTHONPATH=src pytest tests/unit -q 2>/dev/null; then
|
|
39
|
+
pass "Unit tests passed"
|
|
40
|
+
else
|
|
41
|
+
fail "Unit tests failed"
|
|
42
|
+
fi
|
|
43
|
+
else
|
|
44
|
+
pass "No unit tests (skipped)"
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
# Integration Tests
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
echo ""
|
|
51
|
+
echo "--- Integration Tests ---"
|
|
52
|
+
if [ -d "tests/integration" ] && command -v pytest &>/dev/null; then
|
|
53
|
+
if PYTHONPATH=src pytest tests/integration -q 2>/dev/null; then
|
|
54
|
+
pass "Integration tests passed"
|
|
55
|
+
else
|
|
56
|
+
fail "Integration tests failed"
|
|
57
|
+
fi
|
|
58
|
+
else
|
|
59
|
+
pass "No integration tests (skipped)"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
# Coverage
|
|
64
|
+
# ---------------------------------------------------------------------------
|
|
65
|
+
echo ""
|
|
66
|
+
echo "--- Coverage ---"
|
|
67
|
+
if command -v pytest &>/dev/null && command -v coverage &>/dev/null; then
|
|
68
|
+
COVERAGE_OUTPUT=$(PYTHONPATH=src pytest tests/ --cov=src --cov-report=term-missing 2>&1 || true)
|
|
69
|
+
COVERAGE_PCT=$(echo "$COVERAGE_OUTPUT" | grep "^TOTAL" | awk '{print $NF}' | tr -d '%' || echo "0")
|
|
70
|
+
if [ -z "$COVERAGE_PCT" ]; then
|
|
71
|
+
COVERAGE_PCT="0"
|
|
72
|
+
fi
|
|
73
|
+
if [ "$(echo "$COVERAGE_PCT >= 80" | bc -l 2>/dev/null || echo 0)" -eq 1 ]; then
|
|
74
|
+
pass "Coverage: ${COVERAGE_PCT}% (≥ 80%)"
|
|
75
|
+
else
|
|
76
|
+
fail "Coverage: ${COVERAGE_PCT}% (< 80%)"
|
|
77
|
+
fi
|
|
78
|
+
else
|
|
79
|
+
warn "coverage tools not available"
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# ---------------------------------------------------------------------------
|
|
83
|
+
# Summary
|
|
84
|
+
# ---------------------------------------------------------------------------
|
|
85
|
+
echo ""
|
|
86
|
+
echo "============================================"
|
|
87
|
+
echo " Summary"
|
|
88
|
+
echo "============================================"
|
|
89
|
+
echo -e " Passed: ${GREEN}${PASS_COUNT}${NC}"
|
|
90
|
+
echo -e " Failed: ${RED}${#ERRORS[@]}${NC}"
|
|
91
|
+
echo ""
|
|
92
|
+
|
|
93
|
+
if [ ${#ERRORS[@]} -gt 0 ]; then
|
|
94
|
+
echo "FAILURES:"
|
|
95
|
+
for err in "${ERRORS[@]}"; do
|
|
96
|
+
echo " - $err"
|
|
97
|
+
done
|
|
98
|
+
exit 1
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
echo -e "${GREEN}Test validation passed.${NC}"
|
|
102
|
+
exit 0
|