feat(ms-ai-architect): add plugin to open marketplace (v1.5.0 baseline)
Initial addition of ms-ai-architect plugin to the open-source marketplace. Private content excluded: orchestrator/ (Linear tooling), docs/utredning/ (client investigation), generated test reports and PDF export script. skill-gen tooling moved from orchestrator/ to scripts/skill-gen/. Security scan: WARNING (risk 20/100) — no secrets, no injection found. False positive fixed: added gitleaks:allow to Python variable reference in output-validation-grounding-verification.md line 109. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a8d79e4484
commit
6a7632146e
490 changed files with 213249 additions and 2 deletions
187
plugins/ms-ai-architect/tests/lib/e2e-helpers.sh
Executable file
187
plugins/ms-ai-architect/tests/lib/e2e-helpers.sh
Executable file
|
|
@ -0,0 +1,187 @@
|
|||
#!/bin/bash
|
||||
# e2e-helpers.sh — Shared validation functions for E2E regression tests
|
||||
set -euo pipefail
|
||||
|
||||
# Counters
|
||||
PASS=0
|
||||
FAIL=0
|
||||
WARN=0
|
||||
SUITE_NAME=""
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
init_suite() {
|
||||
SUITE_NAME="$1"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
WARN=0
|
||||
echo -e "${BLUE}═══════════════════════════════════════${NC}"
|
||||
echo -e "${BLUE} E2E Suite: $SUITE_NAME${NC}"
|
||||
echo -e "${BLUE}═══════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
pass() {
|
||||
PASS=$((PASS + 1))
|
||||
echo -e " ${GREEN}PASS${NC} $1"
|
||||
}
|
||||
|
||||
fail() {
|
||||
FAIL=$((FAIL + 1))
|
||||
echo -e " ${RED}FAIL${NC} $1"
|
||||
}
|
||||
|
||||
warn() {
|
||||
WARN=$((WARN + 1))
|
||||
echo -e " ${YELLOW}WARN${NC} $1"
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
local total=$((PASS + FAIL))
|
||||
echo ""
|
||||
echo -e "${BLUE}───────────────────────────────────────${NC}"
|
||||
echo -e " ${SUITE_NAME}: ${PASS}/${total} PASS, ${FAIL} FAIL, ${WARN} WARN"
|
||||
echo -e "${BLUE}───────────────────────────────────────${NC}"
|
||||
echo ""
|
||||
return $FAIL
|
||||
}
|
||||
|
||||
# --- Assertions ---
|
||||
|
||||
assert_has_section() {
|
||||
local file="$1"
|
||||
local header="$2"
|
||||
local description="${3:-Section: $header}"
|
||||
if grep -qE "^#{1,4} .*${header}" "$file"; then
|
||||
pass "$description"
|
||||
else
|
||||
fail "$description — header '$header' not found"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_min_lines() {
|
||||
local file="$1"
|
||||
local min="$2"
|
||||
local description="${3:-Minimum $min lines}"
|
||||
local count
|
||||
count=$(wc -l < "$file" | tr -d ' ')
|
||||
if [ "$count" -ge "$min" ]; then
|
||||
pass "$description ($count lines)"
|
||||
else
|
||||
fail "$description — only $count lines (min: $min)"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_encoding_ok() {
|
||||
local file="$1"
|
||||
local description="${2:-UTF-8 encoding valid}"
|
||||
# Check for common broken UTF-8 sequences
|
||||
if file "$file" | grep -qi "utf-8\|ascii\|unicode"; then
|
||||
pass "$description"
|
||||
else
|
||||
fail "$description — encoding not UTF-8/ASCII"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_no_ascii_approximation() {
|
||||
local file="$1"
|
||||
local description="${2:-No ASCII approximation of Norwegian chars}"
|
||||
# Check for ae/oe/aa used where æ/ø/å should be (Norwegian words)
|
||||
# Only flag common Norwegian words that should have æøå
|
||||
local violations=0
|
||||
for pattern in '\bvaere\b' '\bfoerste\b' '\bhoey\b' '\bgjoere\b' '\baarlig\b' '\bsaerlig\b' '\bnoedvendig\b'; do
|
||||
if grep -qiE "$pattern" "$file" 2>/dev/null; then
|
||||
violations=$((violations + 1))
|
||||
fi
|
||||
done
|
||||
if [ "$violations" -eq 0 ]; then
|
||||
pass "$description"
|
||||
else
|
||||
fail "$description — $violations ASCII approximation patterns found"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_scores_in_range() {
|
||||
local file="$1"
|
||||
local description="${2:-Scores in X/5 format within range}"
|
||||
# Match X/5 or X.X/5 patterns and verify range
|
||||
local bad_scores=0
|
||||
while IFS= read -r match; do
|
||||
local score="${match%%/*}"
|
||||
score=$(echo "$score" | tr -d ' ')
|
||||
# Check if it's a valid number between 0 and 5
|
||||
if echo "$score" | grep -qE '^[0-5](\.[0-9]+)?$'; then
|
||||
:
|
||||
else
|
||||
bad_scores=$((bad_scores + 1))
|
||||
fi
|
||||
done < <(grep -oE '[0-9]+\.?[0-9]*/5' "$file" 2>/dev/null || true)
|
||||
|
||||
local total_scores
|
||||
total_scores=$(grep -cE '[0-9]+\.?[0-9]*/5' "$file" 2>/dev/null || echo "0")
|
||||
if [ "$total_scores" -gt 0 ] && [ "$bad_scores" -eq 0 ]; then
|
||||
pass "$description ($total_scores scores found)"
|
||||
elif [ "$total_scores" -eq 0 ]; then
|
||||
fail "$description — no X/5 scores found"
|
||||
else
|
||||
fail "$description — $bad_scores out-of-range scores"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_has_nok_amounts() {
|
||||
local file="$1"
|
||||
local min="${2:-1}"
|
||||
local description="${3:-NOK amounts present}"
|
||||
local count
|
||||
count=$(grep -cE '([0-9]+[.,]?[0-9]*(M|K)\s*NOK|[0-9]+\s*NOK|NOK\s*[0-9]+|[0-9]+\s*000\s*NOK)' "$file" 2>/dev/null || echo "0")
|
||||
if [ "$count" -ge "$min" ]; then
|
||||
pass "$description ($count found)"
|
||||
else
|
||||
fail "$description — only $count NOK amounts (min: $min)"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_min_tables() {
|
||||
local file="$1"
|
||||
local min="$2"
|
||||
local description="${3:-Minimum $min markdown tables}"
|
||||
# Count lines starting with | that contain | somewhere after the first char (table rows)
|
||||
local table_separators
|
||||
table_separators=$(grep -cE '^\|.*\|.*\|' "$file" 2>/dev/null || echo "0")
|
||||
# Rough estimate: each table has header + separator + at least 1 row = 3 lines minimum
|
||||
local estimated_tables=$((table_separators / 3))
|
||||
if [ "$estimated_tables" -ge "$min" ]; then
|
||||
pass "$description (~$estimated_tables tables)"
|
||||
else
|
||||
fail "$description — only ~$estimated_tables tables (min: $min)"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_matches_pattern() {
|
||||
local file="$1"
|
||||
local pattern="$2"
|
||||
local description="${3:-Pattern match: $pattern}"
|
||||
if grep -qE "$pattern" "$file"; then
|
||||
pass "$description"
|
||||
else
|
||||
fail "$description"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_has_dimensions() {
|
||||
local file="$1"
|
||||
local min="$2"
|
||||
local description="${3:-Minimum $min security dimensions}"
|
||||
local count
|
||||
count=$(grep -cE '^\| .+ \| [0-9]+\.?[0-9]*/5' "$file" 2>/dev/null || echo "0")
|
||||
if [ "$count" -ge "$min" ]; then
|
||||
pass "$description ($count dimensions)"
|
||||
else
|
||||
fail "$description — only $count dimensions (min: $min)"
|
||||
fi
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue