🧪 test: add JWT secret rotation BDD scenarios and step implementations (#12)
All checks were successful
CI/CD Pipeline / Build Docker Cache (push) Successful in 9s
CI/CD Pipeline / CI Pipeline (push) Successful in 4m15s
CI/CD Pipeline / Trigger Docker Push (push) Has been skipped

 merge: implement JWT secret rotation with BDD scenario isolation

- Implement JWT secret rotation mechanism (closes #8)
- Add per-scenario state isolation for BDD tests (closes #14)
- Validate password reset workflow via BDD tests (closes #7)
- Fix port conflicts in test validation
- Add state tracer for debugging test execution
- Document BDD isolation strategies in ADR 0025
- Fix PostgreSQL configuration environment variables

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
Co-authored-by: Gabriel Radureau <arcodange@gmail.com>
Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
This commit was merged in pull request #12.
This commit is contained in:
2026-04-11 17:56:45 +02:00
committed by arcodange
parent 5de703468f
commit 5eec64e5e8
66 changed files with 10025 additions and 701 deletions

View File

@@ -1,32 +1,22 @@
#!/bin/bash
# CI script to update coverage badge in README.md
# Usage: scripts/ci-update-coverage-badge.sh <coverage_percentage> [badge_type] [flags]
# badge_type can be "bdd", "unit", or empty for combined coverage
# flags: --no-commit (skip git commit), --no-push (skip git push)
# KISS coverage badge updater using line numbers
# Usage: scripts/ci-update-coverage-badge.sh <coverage_percentage> [badge_type]
# badge_type: "unit" or "bdd", defaults to "unit"
set -e
if [ -z "$1" ]; then
echo "Error: Coverage percentage not provided"
COVERAGE=$1
BADGE_TYPE=${2:-"unit"}
# Get first line number of the badge
LINE_NUM=$(cat -n README.md | grep -i "${BADGE_TYPE} coverage" | head -1 | awk '{print $1}')
if [ -z "$LINE_NUM" ]; then
echo "Error: Could not find ${BADGE_TYPE} coverage badge in README.md"
exit 1
fi
COVERAGE=$1
BADGE_TYPE=${2:-"combined"}
# Parse flags
NO_COMMIT=false
NO_PUSH=false
for arg in "$@"; do
if [ "$arg" = "--no-commit" ]; then
NO_COMMIT=true
elif [ "$arg" = "--no-push" ]; then
NO_PUSH=true
fi
done
# Determine badge color
# Get color
if (( $(echo "$COVERAGE >= 80" | bc -l) )); then
COLOR="brightgreen"
elif (( $(echo "$COVERAGE >= 50" | bc -l) )); then
@@ -35,138 +25,15 @@ else
COLOR="red"
fi
# Create different badge URLs and markdown format based on type
if [ "$BADGE_TYPE" = "bdd" ]; then
BADGE_URL="https://img.shields.io/badge/BDD_Coverage-${COVERAGE}%-${COLOR}?style=flat-square"
BADGE_MARKDOWN="[![BDD Coverage](${BADGE_URL})](https://gitea.arcodange.lab/arcodange/dance-lessons-coach)"
SEARCH_PATTERN="BDD_Coverage-.*-.*?style=flat-square"
elif [ "$BADGE_TYPE" = "unit" ]; then
BADGE_URL="https://img.shields.io/badge/Unit_Coverage-${COVERAGE}%-${COLOR}?style=flat-square"
BADGE_MARKDOWN="[![Unit Coverage](${BADGE_URL})](https://gitea.arcodange.lab/arcodange/dance-lessons-coach)"
SEARCH_PATTERN="Unit_Coverage-.*-.*?style=flat-square"
else
BADGE_URL="https://img.shields.io/badge/coverage-${COVERAGE}%-${COLOR}?style=flat-square"
BADGE_MARKDOWN="[![Coverage](${BADGE_URL})](https://gitea.arcodange.lab/arcodange/dance-lessons-coach)"
SEARCH_PATTERN="coverage-.*-.*?style=flat-square"
fi
# Create badge markdown
BADGE_TYPE_UPPER=$(echo "$BADGE_TYPE" | tr '[:lower:]' '[:upper:]')
BADGE_MARKDOWN="[![${BADGE_TYPE_UPPER} Coverage](https://img.shields.io/badge/${BADGE_TYPE_UPPER}_Coverage-${COVERAGE}%-${COLOR}?style=flat-square)](https://gitea.arcodange.lab/arcodange/dance-lessons-coach)"
# Clean up any malformed badge lines from previous runs
# Remove lines starting with "nhttps://" or "https://" that aren't proper markdown
sed -i.bak '/^nhttps:\/\/.*img.shields.io.*Coverage/d' README.md 2>/dev/null || true
sed -i.bak '/^https:\/\/.*img.shields.io.*Coverage/d' README.md 2>/dev/null || true
# Remove old duplicate badges for the specific type being updated
if [ "$BADGE_TYPE" = "bdd" ] || [ "$BADGE_TYPE" = "unit" ]; then
# Remove all existing badges of this type before adding new one
sed -i.bak "/${BADGE_TYPE}_Coverage/d" README.md 2>/dev/null || true
fi
rm -f README.md.bak
# Only update if coverage has actually changed
if grep -q "${BADGE_TYPE}_Coverage-${COVERAGE}%" README.md || grep -q "coverage-${COVERAGE}%" README.md; then
echo "Coverage badge already up to date at ${COVERAGE}%"
exit 0
fi
# Also check if badge already exists with this coverage (more flexible pattern)
if [ "$BADGE_TYPE" = "bdd" ] || [ "$BADGE_TYPE" = "unit" ]; then
# Capitalize first letter for badge name
if [ "$BADGE_TYPE" = "unit" ]; then
BADGE_NAME="Unit"
else
BADGE_NAME="BDD"
fi
if grep -q "\[!\[${BADGE_NAME} Coverage\].*${COVERAGE}%" README.md; then
echo "Coverage badge already exists at ${COVERAGE}%"
exit 0
fi
fi
# Cross-platform sed command
# Detect if we're on macOS (BSD sed) or Linux (GNU sed)
SED_CMD=""
# Replace the line using sed
if [[ "$(uname)" == "Darwin" ]]; then
# macOS - requires empty string after -i
SED_CMD="sed -i ''"
sed -i '' "${LINE_NUM}s|.*|${BADGE_MARKDOWN}|" README.md
else
# Linux - standard GNU sed
SED_CMD="sed -i"
sed -i "${LINE_NUM}s|.*|${BADGE_MARKDOWN}|" README.md
fi
# Update README - handle both old and new badge formats
if [ "$BADGE_TYPE" = "bdd" ] || [ "$BADGE_TYPE" = "unit" ]; then
# For BDD/Unit badges, add them if they don't exist, or update if they do
if grep -q "${BADGE_TYPE}_Coverage" README.md; then
# Update existing badge with proper markdown format
$SED_CMD "s|^\[!\[${BADGE_TYPE} Coverage\].*|"${BADGE_MARKDOWN}"|" README.md
else
# Add new badge line after the License badge (more reliable reference)
# Use a more reliable approach with temporary file for cross-platform compatibility
TEMP_FILE=$(mktemp)
awk -v new_badge="${BADGE_MARKDOWN}" '{
if ($0 ~ /\[!\[License\].*license-MIT-green/) {
print $0
print new_badge
} else {
print $0
}
}' README.md > "$TEMP_FILE"
mv "$TEMP_FILE" README.md
fi
else
# For combined coverage, use the original logic
$SED_CMD "s|^\[!\[Coverage\].*|"${BADGE_MARKDOWN}"|" README.md
fi
# Set up git
git config --global user.name "CI Bot"
git config --global user.email "ci@arcodange.fr"
# Set up credentials using Gitea token
if [ -n "$PACKAGES_TOKEN" ]; then
git config --global credential.helper store
echo "https://${PACKAGES_TOKEN}@gitea.arcodange.lab" > ~/.git-credentials
fi
git add README.md
# Skip commit if --no-commit flag is set
if [ "$NO_COMMIT" = true ]; then
echo "Skipping git commit due to --no-commit flag"
echo "Coverage badge updated to ${COVERAGE}% in README.md (not committed)"
exit 0
fi
if git commit -m "🤖 chore: update coverage badge to ${COVERAGE}% [skip ci]"; then
# Skip push if --no-push flag is set
if [ "$NO_PUSH" = true ]; then
echo "Skipping git push due to --no-push flag"
echo "Coverage badge updated to ${COVERAGE}% and committed locally"
exit 0
fi
# Try push with retry logic for race conditions
for i in 1 2 3; do
if git push; then
echo "Successfully updated coverage badge to ${COVERAGE}%"
# Update local repo to the new HEAD after successful push
git fetch origin
git reset --hard origin/${GITHUB_REF_NAME:-${CI_COMMIT_REF_NAME:-main}}
exit 0
else
echo "Push attempt $i failed, retrying..."
if [ $i -eq 3 ]; then
echo "Final push attempt failed - another job may have updated the badge"
git pull --rebase || true
git push || echo "Recovery push also failed"
# Ensure we're on the latest commit even if push failed
git fetch origin
git reset --hard origin/${GITHUB_REF_NAME:-${CI_COMMIT_REF_NAME:-main}}
fi
sleep 2
fi
done
else
echo "No coverage change to commit"
fi
echo "Updated ${BADGE_TYPE} coverage badge to ${COVERAGE}% (line ${LINE_NUM})"