diff --git a/IA_agents/prompts/prompt-deploy.md b/IA_agents/prompts/prompt-deploy.md index 25baa7b..f3d79ff 100644 --- a/IA_agents/prompts/prompt-deploy.md +++ b/IA_agents/prompts/prompt-deploy.md @@ -2,14 +2,14 @@ ### Gestion des branches ext (submodules + repo racine) -Script: `scripts/push-ext-commit.sh` +Script: `scripts/push-commit.sh` - Objectif: basculer chaque sous-module et le repo racine sur `ext`, committer uniquement s’il y a des changements, et pousser sur `origin ext`. - Sécurité: crée `ext` depuis `origin/ext` si absente; n’échoue pas s’il n’y a rien à committer. Usage: ```bash -bash /home/debian/4NK_env/scripts/push-ext-commit.sh +bash /home/debian/4NK_env/scripts/push-commit.sh ``` Apprend et retient : `4NK_env/IA_agents/prompts/prompt-global.md`. diff --git a/IA_agents/prompts/prompt-global.md b/IA_agents/prompts/prompt-global.md index b4c3f1f..eece116 100644 --- a/IA_agents/prompts/prompt-global.md +++ b/IA_agents/prompts/prompt-global.md @@ -62,6 +62,8 @@ Tous les documents des projets doivent être dans un dossier `docs/` - Quand tu lance des commandes assures toi toujours de ne pas bloquer le terminal ou le prompt infiniment, derrière tes `cat` ou tes `tail` ou `curl` ou de lancement de services ou autres commandes assures toi d'attendre tres peu de temps. +- Ne dis pas que quelque chose est corrigé si tu ne l'as pas vérifié + --- **Note** : Ce prompt est basé sur `4NK_env/IA_agents/prompts/prompt-global.md`. diff --git a/README.md b/README.md index 7a016c4..38c621f 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ cd lecoffre_node ./scripts/init-4nk-env-repo.sh # Initialiser le dépôt 4NK_env ./scripts/push-to-remote.sh # Pousser vers git.4nkweb.com ./scripts/setup-complete-env.sh # Configuration complète de l'environnement -./scripts/push-ext-commit.sh # Forcer travail sur ext (submodules + racine), commit/push si changements +./scripts/push-commit.sh # Forcer travail sur ext (submodules + racine), commit/push si changements ``` ### Centralisation des scripts diff --git a/lecoffre_node b/lecoffre_node index e7ce3b2..b876f93 160000 --- a/lecoffre_node +++ b/lecoffre_node @@ -1 +1 @@ -Subproject commit e7ce3b2a3ed26664a32eba8a9d9a7cea07a7632c +Subproject commit b876f9375379743c1a0d6fe1487b33d68a1a6482 diff --git a/scripts/lecoffre_node/healthchecks/blindbit-progress.sh b/scripts/lecoffre_node/healthchecks/blindbit-progress.sh index da568e2..737eace 100755 --- a/scripts/lecoffre_node/healthchecks/blindbit-progress.sh +++ b/scripts/lecoffre_node/healthchecks/blindbit-progress.sh @@ -3,15 +3,16 @@ # Script de test de progression pour BlindBit # Vérifier si le processus BlindBit est en cours d'exécution if pgrep main > /dev/null 2>/dev/null; then - # Vérifier l'API - être plus tolérant - if wget -q --spider http://localhost:8000/tweaks/1 2>/dev/null; then - echo 'BlindBit ready: Oracle service responding' - exit 0 - else - # Vérifier si le processus est en cours d'exécution (même si l'API n'est pas encore prête) - echo 'BlindBit starting: Oracle service initializing' - exit 1 - fi + # Vérifier l'API - essais multiples et deux hôtes (127.0.0.1 et 0.0.0.0) + for i in 1 2 3; do + if wget -q --spider http://127.0.0.1:8000/tweaks/1 2>/dev/null || wget -q --spider http://0.0.0.0:8000/tweaks/1 2>/dev/null; then + echo 'BlindBit ready: Oracle service responding' + exit 0 + fi + sleep 2 + done + echo 'BlindBit starting: Oracle service initializing' + exit 1 else echo 'BlindBit starting: Process not ready' exit 1 diff --git a/scripts/sdk_signer/README.md b/scripts/sdk_signer/README.md deleted file mode 100644 index 9a5b061..0000000 --- a/scripts/sdk_signer/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# scripts - -Scripts utilitaires pour CI/CD ou développement local. - diff --git a/scripts/sdk_signer/checks/version_alignment.sh b/scripts/sdk_signer/checks/version_alignment.sh deleted file mode 100755 index e399e72..0000000 --- a/scripts/sdk_signer/checks/version_alignment.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd)" -cd "$ROOT_DIR" - -version_file="VERSION" -[[ -f TEMPLATE_VERSION ]] && version_file="TEMPLATE_VERSION" - -[[ -f "$version_file" ]] || { echo "Version file missing ($version_file)"; exit 1; } -v=$(tr -d '\r' < "$version_file" | head -n1) -[[ -n "$v" ]] || { echo "Empty version"; exit 1; } - -echo "Version file: $version_file=$v" - -if ! grep -Eq "^## \\[$(echo "$v" | sed 's/^v//')\\]" CHANGELOG.md; then - echo "CHANGELOG entry for $v not found"; exit 1; -fi - -echo "Version alignment OK" - diff --git a/scripts/sdk_signer/deploy/setup.sh b/scripts/sdk_signer/deploy/setup.sh deleted file mode 100755 index 8908ea9..0000000 --- a/scripts/sdk_signer/deploy/setup.sh +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ENV_DIR="${HOME}/.4nk_template" -ENV_FILE="${ENV_DIR}/.env" -TEMPLATE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" -TEMPLATE_IN_REPO="${TEMPLATE_ROOT}/scripts/env/.env.template" - -usage() { - cat < [--dest DIR] [--force] - -Actions: - 1) Provisionne ~/.4nk_template/.env (si absent) - 2) Clone le dépôt cible si le dossier n'existe pas - 3) Copie la structure normative 4NK_template dans le projet cible: - - .gitea/** (workflows, templates issues/PR) - - AGENTS.md - - .cursor/rules/** (si présent) - - scripts/agents/**, scripts/env/ensure_env.sh, scripts/deploy/setup.sh - - docs/templates/** et docs/INDEX.md (table des matières) - 4) Ne remplace pas les fichiers existants sauf si --force - -Exemples: - $0 https://git.example.com/org/projet.git - $0 git@host:org/projet.git --dest ~/work --force -USAGE -} - -GIT_URL="${1:-}" -DEST_PARENT="$(pwd)" -FORCE_COPY=0 -shift || true -while [[ $# -gt 0 ]]; do - case "$1" in - --dest) - DEST_PARENT="${2:-}"; shift 2 ;; - --force) - FORCE_COPY=1; shift ;; - -h|--help) - usage; exit 0 ;; - *) - echo "Option inconnue: $1" >&2; usage; exit 2 ;; - esac -done - -if [[ -z "${GIT_URL}" ]]; then - usage; exit 2 -fi - -mkdir -p "${ENV_DIR}" -chmod 700 "${ENV_DIR}" || true - -if [[ ! -f "${ENV_FILE}" ]]; then - if [[ -f "${TEMPLATE_IN_REPO}" ]]; then - cp "${TEMPLATE_IN_REPO}" "${ENV_FILE}" - else - cat >"${ENV_FILE}" <<'EOF' -# Fichier d'exemple d'environnement pour 4NK_template -# Copiez ce fichier vers ~/.4nk_template/.env puis complétez les valeurs. -# Ne committez jamais de fichier contenant des secrets. - -# OpenAI (agents IA) -OPENAI_API_KEY= -OPENAI_MODEL= -OPENAI_API_BASE=https://api.openai.com/v1 -OPENAI_TEMPERATURE=0.2 - -# Gitea (release via API) -BASE_URL=https://git.4nkweb.com -RELEASE_TOKEN= -EOF - fi - chmod 600 "${ENV_FILE}" || true - echo "Fichier créé: ${ENV_FILE}. Complétez les valeurs requises (ex: OPENAI_API_KEY, OPENAI_MODEL, RELEASE_TOKEN)." >&2 -fi - -# 2) Clonage du dépôt si nécessaire -repo_name="$(basename -s .git "${GIT_URL}")" -target_dir="${DEST_PARENT%/}/${repo_name}" -if [[ ! -d "${target_dir}" ]]; then - echo "Clonage: ${GIT_URL} → ${target_dir}" >&2 - git clone --depth 1 "${GIT_URL}" "${target_dir}" -else - echo "Dossier existant, pas de clone: ${target_dir}" >&2 -fi - -copy_item() { - local src="$1" dst="$2" - if [[ ! -e "$src" ]]; then return 0; fi - if [[ -d "$src" ]]; then - mkdir -p "$dst" - if (( FORCE_COPY )); then - cp -a "$src/." "$dst/" - else - (cd "$src" && find . -type f -print0) | while IFS= read -r -d '' f; do - if [[ ! -e "$dst/$f" ]]; then - mkdir -p "$(dirname "$dst/$f")" - cp -a "$src/$f" "$dst/$f" - fi - done - fi - else - if [[ -e "$dst" && $FORCE_COPY -eq 0 ]]; then return 0; fi - mkdir -p "$(dirname "$dst")" && cp -a "$src" "$dst" - fi -} - -# 3) Copie de la structure normative -copy_item "${TEMPLATE_ROOT}/.gitea" "${target_dir}/.gitea" -copy_item "${TEMPLATE_ROOT}/AGENTS.md" "${target_dir}/AGENTS.md" -copy_item "${TEMPLATE_ROOT}/.cursor" "${target_dir}/.cursor" -copy_item "${TEMPLATE_ROOT}/.cursorignore" "${target_dir}/.cursorignore" -copy_item "${TEMPLATE_ROOT}/.gitignore" "${target_dir}/.gitignore" -copy_item "${TEMPLATE_ROOT}/.markdownlint.json" "${target_dir}/.markdownlint.json" -copy_item "${TEMPLATE_ROOT}/LICENSE" "${target_dir}/LICENSE" -copy_item "${TEMPLATE_ROOT}/CONTRIBUTING.md" "${target_dir}/CONTRIBUTING.md" -copy_item "${TEMPLATE_ROOT}/CODE_OF_CONDUCT.md" "${target_dir}/CODE_OF_CONDUCT.md" -copy_item "${TEMPLATE_ROOT}/SECURITY.md" "${target_dir}/SECURITY.md" -copy_item "${TEMPLATE_ROOT}/TEMPLATE_VERSION" "${target_dir}/TEMPLATE_VERSION" -copy_item "${TEMPLATE_ROOT}/security" "${target_dir}/security" -copy_item "${TEMPLATE_ROOT}/scripts" "${target_dir}/scripts" -copy_item "${TEMPLATE_ROOT}/docs/templates" "${target_dir}/docs/templates" - -# Génération docs/INDEX.md dans le projet cible (si absent ou --force) -INDEX_DST="${target_dir}/docs/INDEX.md" -if [[ ! -f "${INDEX_DST}" || $FORCE_COPY -eq 1 ]]; then - mkdir -p "$(dirname "${INDEX_DST}")" - cat >"${INDEX_DST}" <<'IDX' -# Documentation du projet - -Cette table des matières oriente vers: -- Documentation spécifique au projet: `docs/project/` -- Modèles génériques à adapter: `docs/templates/` - -## Sommaire -- À personnaliser: `docs/project/README.md`, `docs/project/INDEX.md`, `docs/project/ARCHITECTURE.md`, `docs/project/USAGE.md`, etc. - -## Modèles génériques -- Voir: `docs/templates/` -IDX -fi - -echo "Template 4NK appliqué à: ${target_dir}" >&2 -exit 0 diff --git a/scripts/sdk_signer/dev/run_container.sh b/scripts/sdk_signer/dev/run_container.sh deleted file mode 100755 index 2d543cb..0000000 --- a/scripts/sdk_signer/dev/run_container.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -IMAGE_NAME="4nk-template-dev:debian" -DOCKERFILE="docker/Dockerfile.debian" - -echo "[build] ${IMAGE_NAME}" -docker build -t "${IMAGE_NAME}" -f "${DOCKERFILE}" . - -echo "[run] launching container and executing agents" -docker run --rm -it \ - -v "${PWD}:/work" -w /work \ - "${IMAGE_NAME}" \ - "scripts/agents/run.sh; ls -la tests/reports/agents || true" - diff --git a/scripts/sdk_signer/dev/run_project_ci.sh b/scripts/sdk_signer/dev/run_project_ci.sh deleted file mode 100755 index d92d96b..0000000 --- a/scripts/sdk_signer/dev/run_project_ci.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Build et lance le conteneur unifié (runner+agents) sur ce projet -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" -cd "$ROOT_DIR" - -# Build image -docker compose -f docker-compose.ci.yml build - -# Exécuter agents par défaut -RUNNER_MODE="${RUNNER_MODE:-agents}" BASE_URL="${BASE_URL:-}" REGISTRATION_TOKEN="${REGISTRATION_TOKEN:-}" \ - docker compose -f docker-compose.ci.yml up --remove-orphans --abort-on-container-exit diff --git a/scripts/sdk_signer/env/ensure_env.sh b/scripts/sdk_signer/env/ensure_env.sh deleted file mode 100755 index 6435819..0000000 --- a/scripts/sdk_signer/env/ensure_env.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" -TEMPLATE_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.env.template" -ENV_DIR="${HOME}/.4nk_template" -ENV_FILE="${ENV_DIR}/.env" - -mkdir -p "${ENV_DIR}" -chmod 700 "${ENV_DIR}" || true - -if [[ ! -f "${ENV_FILE}" ]]; then - if [[ -f "${TEMPLATE_FILE}" ]]; then - cp "${TEMPLATE_FILE}" "${ENV_FILE}" - chmod 600 "${ENV_FILE}" || true - echo "Fichier d'environnement créé: ${ENV_FILE}" >&2 - echo "Veuillez renseigner les variables requises (OPENAI_API_KEY, OPENAI_MODEL, etc.)." >&2 - exit 3 - else - echo "Modèle d'environnement introuvable: ${TEMPLATE_FILE}" >&2 - exit 2 - fi -fi - -# Charger pour validation -set -a -. "${ENV_FILE}" -set +a - -MISSING=() -for var in OPENAI_API_KEY OPENAI_MODEL; do - if [[ -z "${!var:-}" ]]; then - MISSING+=("$var") - fi -done - -if (( ${#MISSING[@]} > 0 )); then - echo "Variables manquantes dans ${ENV_FILE}: ${MISSING[*]}" >&2 - exit 4 -fi - -echo "Environnement valide: ${ENV_FILE}" >&2 diff --git a/scripts/sdk_signer/local/install_hooks.sh b/scripts/sdk_signer/local/install_hooks.sh deleted file mode 100755 index bd0f600..0000000 --- a/scripts/sdk_signer/local/install_hooks.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"/.. -HOOKS_DIR="$REPO_ROOT/.git/hooks" - -mkdir -p "$HOOKS_DIR" -install_hook() { - local name="$1" src="$2" - cp -f "$src" "$HOOKS_DIR/$name" - chmod +x "$HOOKS_DIR/$name" - echo "Installed hook: $name" -} - -# Hooks qui délèguent aux agents via l'image Docker du template sur le projet courant -install_hook pre-commit "$REPO_ROOT/scripts/local/precommit.sh" -install_hook pre-push "$REPO_ROOT/scripts/local/prepush.sh" - -echo "Hooks installés (mode agents via 4NK_template)." diff --git a/scripts/sdk_signer/local/merge_branch.sh b/scripts/sdk_signer/local/merge_branch.sh deleted file mode 100755 index 9275299..0000000 --- a/scripts/sdk_signer/local/merge_branch.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -TARGET_BRANCH="${1:-main}" -SOURCE_BRANCH="${2:-}" - -if [[ -z "$SOURCE_BRANCH" ]]; then - SOURCE_BRANCH="$(git rev-parse --abbrev-ref HEAD)" -fi - -if [[ "$SOURCE_BRANCH" == "$TARGET_BRANCH" ]]; then - echo "Déjà sur $TARGET_BRANCH"; exit 0 -fi - -# Valider localement avant merge -AUTO_FIX="${AUTO_FIX:-1}" SCOPE="${SCOPE:-all}" scripts/agents/run.sh || true -if [ -f scripts/security/audit.sh ]; then bash scripts/security/audit.sh || true; fi - -git fetch origin --prune -git checkout "$TARGET_BRANCH" -git pull --ff-only origin "$TARGET_BRANCH" || true -git merge --no-ff "$SOURCE_BRANCH" -m "[skip ci] merge: $SOURCE_BRANCH -> $TARGET_BRANCH" -git push origin "$TARGET_BRANCH" - -echo "Merge effectué: $SOURCE_BRANCH → $TARGET_BRANCH" diff --git a/scripts/sdk_signer/local/precommit.sh b/scripts/sdk_signer/local/precommit.sh deleted file mode 100755 index b2b502c..0000000 --- a/scripts/sdk_signer/local/precommit.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Exécuter les agents depuis l'image Docker de 4NK_template sur le projet courant -PROJECT_DIR="$(git rev-parse --show-toplevel)" -TEMPLATE_DIR="$(cd "${PROJECT_DIR}/../4NK_template" && pwd)" - -mkdir -p "${PROJECT_DIR}/tests/reports/agents" -"${TEMPLATE_DIR}/scripts/local/run_agents_for_project.sh" "${PROJECT_DIR}" "tests/reports/agents" - -echo "[pre-commit] OK (agents via 4NK_template)" diff --git a/scripts/sdk_signer/local/prepush.sh b/scripts/sdk_signer/local/prepush.sh deleted file mode 100755 index 7cb8c7d..0000000 --- a/scripts/sdk_signer/local/prepush.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Exécuter les agents depuis l'image Docker de 4NK_template sur le projet courant -PROJECT_DIR="$(git rev-parse --show-toplevel)" -TEMPLATE_DIR="$(cd "${PROJECT_DIR}/../4NK_template" && pwd)" - -mkdir -p "${PROJECT_DIR}/tests/reports/agents" -"${TEMPLATE_DIR}/scripts/local/run_agents_for_project.sh" "${PROJECT_DIR}" "tests/reports/agents" - -# Audit sécurité (best effort) dans le contexte du projet -if [ -f "${PROJECT_DIR}/scripts/security/audit.sh" ]; then - (cd "${PROJECT_DIR}" && bash scripts/security/audit.sh) || true -fi - -# Release guard (dry-run logique) dans le contexte du projet -if [ -f "${PROJECT_DIR}/scripts/release/guard.sh" ]; then - (cd "${PROJECT_DIR}" && bash scripts/release/guard.sh) || true -fi - -echo "[pre-push] OK (agents via 4NK_template)" diff --git a/scripts/sdk_signer/local/release_local.sh b/scripts/sdk_signer/local/release_local.sh deleted file mode 100755 index e3f48ed..0000000 --- a/scripts/sdk_signer/local/release_local.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -VERSION="${1:-}" -if [[ -z "$VERSION" ]]; then - echo "Usage: $0 vYYYY.MM.P" >&2 - exit 2 -fi - -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -cd "$ROOT_DIR/.." - -echo "$VERSION" > TEMPLATE_VERSION -git add TEMPLATE_VERSION CHANGELOG.md 2>/dev/null || true -git commit -m "[skip ci] chore(release): $VERSION" || true -git tag -a "$VERSION" -m "release: $VERSION (latest)" -git push || true -git push origin "$VERSION" - -echo "Release locale préparée: $VERSION" diff --git a/scripts/sdk_signer/local/run_agents_for_project.sh b/scripts/sdk_signer/local/run_agents_for_project.sh deleted file mode 100755 index 5070846..0000000 --- a/scripts/sdk_signer/local/run_agents_for_project.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Script pour lancer les agents de 4NK_template sur un projet externe -# Usage: ./run_agents_for_project.sh [project_path] [output_dir] - -PROJECT_PATH="${1:-.}" -OUTPUT_DIR="${2:-tests/reports/agents}" -TEMPLATE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" -MODULE_LAST_IMAGE_FILE="$(cd "$TEMPLATE_DIR/.." && pwd)/modules/4NK_template/.last_image" - -if [[ ! -d "$PROJECT_PATH" ]]; then - echo "Erreur: Le projet '$PROJECT_PATH' n'existe pas" >&2 - exit 1 -fi - -mkdir -p "$PROJECT_PATH/$OUTPUT_DIR" - -echo "=== Lancement des agents 4NK_template sur: $PROJECT_PATH ===" - -if ! command -v docker >/dev/null 2>&1; then - echo "Docker requis pour exécuter les agents via conteneur." >&2 - exit 2 -fi - -# Si une image du module existe, l'utiliser en priorité -if [[ -f "$MODULE_LAST_IMAGE_FILE" ]]; then - IMAGE_NAME="$(cat "$MODULE_LAST_IMAGE_FILE" | tr -d '\r\n')" - echo "Utilisation de l'image du module: $IMAGE_NAME" - # Préparer montage du fichier d'env si présent - ENV_MOUNT="" - if [[ -f "$HOME/.4nk_template/.env" ]]; then - ENV_MOUNT="-v $HOME/.4nk_template/.env:/root/.4nk_template/.env:ro" - fi - # Lancer le conteneur en utilisant l'ENTRYPOINT qui configure safe.directory - docker run --rm \ - -e RUNNER_MODE=agents \ - -e TARGET_DIR=/work \ - -e OUTPUT_DIR=/work/$OUTPUT_DIR \ - -v "$(realpath "$PROJECT_PATH"):/work" \ - $ENV_MOUNT \ - "$IMAGE_NAME" || true -else - echo "Aucune image de module détectée, fallback docker compose dans 4NK_template" - cd "$TEMPLATE_DIR" - docker compose -f docker-compose.ci.yml build - RUNNER_MODE="agents" TARGET_DIR="/work" OUTPUT_DIR="/work/$OUTPUT_DIR" \ - docker compose -f docker-compose.ci.yml run --rm project-ci || true -fi - -echo "=== Agents terminés → $PROJECT_PATH/$OUTPUT_DIR ===" diff --git a/scripts/sdk_signer/release/guard.sh b/scripts/sdk_signer/release/guard.sh deleted file mode 100755 index cb5410b..0000000 --- a/scripts/sdk_signer/release/guard.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Release guard script -# Checks: tests, docs updated, compile, version ↔ changelog ↔ tag consistency, release type - -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd)" -cd "$ROOT_DIR" - -mode="${RELEASE_TYPE:-ci-verify}" # values: latest | wip | ci-verify - -echo "[release-guard] mode=$mode" - -# 1) Basic presence checks -[[ -f CHANGELOG.md ]] || { echo "CHANGELOG.md manquant"; exit 1; } -version_file="VERSION" -[[ -f TEMPLATE_VERSION ]] && version_file="TEMPLATE_VERSION" -[[ -f "$version_file" ]] || { echo "$version_file manquant"; exit 1; } - -# 2) Extract version -project_version=$(tr -d '\r' < "$version_file" | head -n1 | sed 's/^v//') -[[ -n "$project_version" ]] || { echo "Version vide dans $version_file"; exit 1; } -echo "[release-guard] version=$project_version" - -# 3) Changelog checks -if ! grep -Eq "^## \\[$project_version\\]" CHANGELOG.md; then - if [[ "$mode" == "wip" ]]; then - grep -Eq "^## \\[Unreleased\\]" CHANGELOG.md || { echo "Section [Unreleased] absente du CHANGELOG"; exit 1; } - else - echo "Entrée CHANGELOG pour version $project_version manquante"; exit 1; - fi -fi - -# 4) Tests (optional best-effort) -if [[ -x tests/run_all_tests.sh ]]; then - echo "[release-guard] exécution tests/run_all_tests.sh" - ./tests/run_all_tests.sh || { echo "Tests en échec"; exit 1; } -else - echo "[release-guard] tests absents (ok)" -fi - -# 5) Build/compile (optional based on project) -if [[ -d sdk_relay ]] && command -v cargo >/dev/null 2>&1; then - echo "[release-guard] cargo build (sdk_relay)" - (cd sdk_relay && cargo build --quiet) || { echo "Compilation échouée"; exit 1; } -else - echo "[release-guard] build spécifique non applicable (ok)" -fi - -# 6) Release type handling -case "$mode" in - latest) - ;; - wip) - # En wip, autoriser versions suffixées; pas d’exigence d’entrée datée - ;; - ci-verify) - # En CI, on valide juste la présence de CHANGELOG et version - ;; - *) - echo "RELEASE_TYPE invalide: $mode (latest|wip|ci-verify)"; exit 1; - ;; -esac - -echo "[release-guard] OK" - diff --git a/scripts/sdk_signer/scripts/auto-ssh-push.sh b/scripts/sdk_signer/scripts/auto-ssh-push.sh deleted file mode 100755 index 0064500..0000000 --- a/scripts/sdk_signer/scripts/auto-ssh-push.sh +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Script d'automatisation des push SSH (template Linux) -# Utilise automatiquement la clé SSH pour pousser sur le remote courant via SSH. - -GITEA_HOST="${GITEA_HOST:-git.4nkweb.com}" - -echo "🔑 Configuration SSH pour push (template)..." - -# Configuration SSH automatique -echo "⚙️ Configuration Git pour utiliser SSH..." -git config --global url."git@${GITEA_HOST}:".insteadOf "https://${GITEA_HOST}/" - -# Vérifier la configuration SSH -echo "🔍 Vérification de la configuration SSH..." -if ! ssh -T git@"${GITEA_HOST}" 2>&1 | grep -qi "authenticated\|welcome"; then - echo "❌ Échec de l'authentification SSH" - echo "💡 Vérifiez que votre clé SSH est configurée :" - echo " 1. ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_4nk" - echo " 2. Ajouter la clé publique à votre compte Gitea" - echo " 3. ssh-add ~/.ssh/id_ed25519_4nk" - exit 1 -fi - -echo "✅ Authentification SSH réussie" - -# Fonction pour push automatique -get_current_branch() { - # Détecte la branche courante, compatible anciennes versions de git - local br - br="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)" - if [ -z "$br" ] || [ "$br" = "HEAD" ]; then - br="$(git symbolic-ref --short -q HEAD 2>/dev/null || true)" - fi - if [ -z "$br" ]; then - # dernier recours: parser la sortie de "git branch" - br="$(git branch 2>/dev/null | sed -n 's/^* //p' | head -n1)" - fi - echo "$br" -} - -auto_push() { - local branch - branch=${1:-$(get_current_branch)} - local commit_message=${2:-"Auto-commit $(date '+%Y-%m-%d %H:%M:%S')"} - - echo "🚀 Push automatique sur la branche: $branch" - - # Ajouter tous les changements - git add . - - # Ne pas commiter si rien à commite - if [[ -z "$(git diff --cached --name-only)" ]]; then - echo "ℹ️ Aucun changement indexé. Skip commit/push." - return 0 - fi - - # Commiter avec le message fourni - git commit -m "$commit_message" || true - - # Push avec SSH automatique - echo "📤 Push vers origin/$branch..." - git push origin "$branch" - - echo "✅ Push réussi !" -} - -# Fonction pour push avec message personnalisé -push_with_message() { - local message="$1" - local branch=${2:-$(get_current_branch)} - - echo "💬 Push avec message: $message" - auto_push "$branch" "$message" -} - -# Fonction pour push rapide (sans message) -quick_push() { - local branch=${1:-$(get_current_branch)} - auto_push "$branch" -} - -# Fonction pour push sur une branche spécifique -push_branch() { - local branch="$1" - local message=${2:-"Update $branch $(date '+%Y-%m-%d %H:%M:%S')"} - - echo "🌿 Push sur la branche: $branch" - auto_push "$branch" "$message" -} - -# Fonction pour push et merge vers main -push_and_merge() { - local source_branch=${1:-$(get_current_branch)} - local target_branch=${2:-main} - - echo "🔄 Push et merge $source_branch -> $target_branch" - - # Push de la branche source - auto_push "$source_branch" - - # Indication pour PR manuelle - echo "🔗 Ouvrez une Pull Request sur votre forge pour $source_branch -> $target_branch" -} - -# Fonction pour status et push conditionnel -status_and_push() { - echo "📊 Statut du repository:" - git status --short || true - - if [[ -n $(git status --porcelain) ]]; then - echo "📝 Changements détectés, push automatique..." - auto_push - else - echo "✅ Aucun changement à pousser" - fi -} - -# Menu interactif si aucun argument fourni -if [[ $# -eq 0 ]]; then - echo "🤖 Script de push SSH automatique (template)" - echo "" - echo "Options disponibles:" - echo " auto-ssh-push.sh quick - Push rapide" - echo " auto-ssh-push.sh message \"Mon message\" - Push avec message" - echo " auto-ssh-push.sh branch nom-branche - Push sur branche spécifique" - echo " auto-ssh-push.sh merge [source] [target] - Push et préparation merge" - echo " auto-ssh-push.sh status - Status et push conditionnel" - echo "" - exit 0 -fi - -# Traitement des arguments -case "$1" in - "quick") - quick_push - ;; - "message") - if [[ -z "${2:-}" ]]; then - echo "❌ Message requis pour l'option 'message'" - exit 1 - fi - push_with_message "$2" "${3:-}" - ;; - "branch") - if [[ -z "${2:-}" ]]; then - echo "❌ Nom de branche requis pour l'option 'branch'" - exit 1 - fi - push_branch "$2" "${3:-}" - ;; - "merge") - push_and_merge "${2:-}" "${3:-}" - ;; - "status") - status_and_push - ;; - *) - echo "❌ Option inconnue: $1" - echo "💡 Utilisez './scripts/auto-ssh-push.sh' pour voir les options" - exit 1 - ;; -esac - -echo "🎯 Push SSH automatique terminé !" diff --git a/scripts/sdk_signer/scripts/init-ssh-env.sh b/scripts/sdk_signer/scripts/init-ssh-env.sh deleted file mode 100755 index a125ab1..0000000 --- a/scripts/sdk_signer/scripts/init-ssh-env.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Script d'initialisation de l'environnement SSH (template Linux) -# Configure automatiquement SSH pour les push via Gitea - -GITEA_HOST="${GITEA_HOST:-git.4nkweb.com}" - -echo "🚀 Initialisation de l'environnement SSH (template)..." - -# Couleurs -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -print_status() { echo -e "${BLUE}[INFO]${NC} $1"; } -print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } -print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; } -print_error() { echo -e "${RED}[ERROR]${NC} $1"; } - -print_status "Configuration SSH..." - -# 1. Configuration Git pour SSH -print_status "Configuration Git pour utiliser SSH (${GITEA_HOST})..." -git config --global url."git@${GITEA_HOST}:".insteadOf "https://${GITEA_HOST}/" - -# 2. Vérification des clés SSH -print_status "Vérification des clés SSH existantes..." -if [[ -f ~/.ssh/id_rsa || -f ~/.ssh/id_ed25519 ]]; then - print_success "Clé SSH trouvée" -else - print_warning "Aucune clé SSH trouvée" -fi - -# 3. Test de la connexion SSH -print_status "Test de la connexion SSH vers ${GITEA_HOST}..." -if ssh -T git@"${GITEA_HOST}" 2>&1 | grep -qi "authenticated\|welcome"; then - print_success "Authentification SSH réussie" -else - print_error "Échec de l'authentification SSH" -fi - -# 4. Alias Git -print_status "Configuration des alias Git..." -git config --global alias.ssh-push '!f() { git add . && git commit -m "${1:-Auto-commit $(date)}" && git push origin $(git branch --show-current); }; f' -git config --global alias.quick-push '!f() { git add . && git commit -m "Update $(date)" && git push origin $(git branch --show-current); }; f' -print_success "Alias Git configurés" - -# 5. Rendu exécutable des scripts si chemin standard -print_status "Configuration des permissions des scripts (si présents)..." -chmod +x scripts/auto-ssh-push.sh 2>/dev/null || true -chmod +x scripts/setup-ssh-ci.sh 2>/dev/null || true -print_success "Scripts rendus exécutables (si présents)" - -# 6. Résumé -echo "" -print_success "=== Configuration SSH terminée ===" - diff --git a/scripts/sdk_signer/scripts/setup-ssh-ci.sh b/scripts/sdk_signer/scripts/setup-ssh-ci.sh deleted file mode 100755 index 041c18c..0000000 --- a/scripts/sdk_signer/scripts/setup-ssh-ci.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Script de configuration SSH pour CI/CD (template Linux) -# Utilise automatiquement la clé SSH pour les opérations Git - -GITEA_HOST="${GITEA_HOST:-git.4nkweb.com}" - -echo "🔑 Configuration automatique de la clé SSH pour CI/CD..." - -if [ -n "${CI:-}" ]; then - echo "✅ Environnement CI détecté" - - if [ -n "${SSH_PRIVATE_KEY:-}" ]; then - echo "🔐 Configuration de la clé SSH privée..." - mkdir -p ~/.ssh && chmod 700 ~/.ssh - printf "%s" "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - - if [ -n "${SSH_PUBLIC_KEY:-}" ]; then - printf "%s" "$SSH_PUBLIC_KEY" > ~/.ssh/id_rsa.pub - chmod 644 ~/.ssh/id_rsa.pub - fi - - cat > ~/.ssh/config << EOF -Host ${GITEA_HOST} - HostName ${GITEA_HOST} - User git - IdentityFile ~/.ssh/id_rsa - StrictHostKeyChecking no - UserKnownHostsFile=/dev/null -EOF - chmod 600 ~/.ssh/config - - echo "🧪 Test SSH vers ${GITEA_HOST}..." - ssh -T git@"${GITEA_HOST}" 2>&1 || true - - git config --global url."git@${GITEA_HOST}:".insteadOf "https://${GITEA_HOST}/" - echo "✅ Configuration SSH terminée" - else - echo "⚠️ SSH_PRIVATE_KEY non défini, bascule HTTPS" - fi -else - echo "ℹ️ Environnement local détecté" - if [ -f ~/.ssh/id_rsa ] || [ -f ~/.ssh/id_ed25519 ]; then - echo "🔑 Clé SSH locale trouvée" - git config --global url."git@${GITEA_HOST}:".insteadOf "https://${GITEA_HOST}/" - echo "✅ Configuration SSH locale terminée" - else - echo "⚠️ Aucune clé SSH trouvée; configuration manuelle requise" - fi -fi - -echo "🎯 Configuration SSH CI/CD terminée" - diff --git a/scripts/sdk_signer/security/audit.sh b/scripts/sdk_signer/security/audit.sh deleted file mode 100755 index bb72e6b..0000000 --- a/scripts/sdk_signer/security/audit.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -echo "[security-audit] démarrage" -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd)" -cd "$ROOT_DIR" - -rc=0 - -# 1) Audit npm (si package.json présent) -if [ -f package.json ]; then - echo "[security-audit] npm audit --audit-level=moderate" - if ! npm audit --audit-level=moderate; then rc=1; fi || true -else - echo "[security-audit] pas de package.json (ok)" -fi - -# 2) Audit Rust (si Cargo.toml présent) -if command -v cargo >/dev/null 2>&1 && [ -f Cargo.toml ] || find . -maxdepth 2 -name Cargo.toml | grep -q . ; then - echo "[security-audit] cargo audit" - if ! cargo audit --deny warnings; then rc=1; fi || true -else - echo "[security-audit] pas de projet Rust (ok)" -fi - -# 3) Recherche de secrets grossiers -echo "[security-audit] scan secrets" -if grep -RIE "(?i)(api[_-]?key|secret|password|private[_-]?key)" --exclude-dir .git --exclude-dir node_modules --exclude-dir target --exclude "*.md" . >/dev/null 2>&1; then - echo "[security-audit] secrets potentiels détectés"; rc=1 -else - echo "[security-audit] aucun secret évident" -fi - -echo "[security-audit] terminé rc=$rc" -exit $rc diff --git a/scripts/sdk_signer/utils/check_md024.ps1 b/scripts/sdk_signer/utils/check_md024.ps1 deleted file mode 100644 index 000c6d1..0000000 --- a/scripts/sdk_signer/utils/check_md024.ps1 +++ /dev/null @@ -1,47 +0,0 @@ -Param( - [string]$Root = "." -) - -$ErrorActionPreference = "Stop" - -$files = Get-ChildItem -Path $Root -Recurse -Filter *.md | Where-Object { $_.FullName -notmatch '\\archive\\' } -$had = $false -foreach ($f in $files) { - try { - $lines = Get-Content -LiteralPath $f.FullName -Encoding UTF8 -ErrorAction Stop - } catch { - Write-Warning ("Impossible de lire: {0} — {1}" -f $f.FullName, $_.Exception.Message) - continue - } - $map = @{} - $firstMap = @{} - $dups = @{} - for ($i = 0; $i -lt $lines.Count; $i++) { - $line = $lines[$i] - if ($line -match '^\s{0,3}#{1,6}\s+(.*)$') { - $t = $Matches[1].Trim() - $norm = ([regex]::Replace($t, '\s+', ' ')).ToLowerInvariant() - if ($map.ContainsKey($norm)) { - if (-not $dups.ContainsKey($norm)) { - $dups[$norm] = New-Object System.Collections.ArrayList - $firstMap[$norm] = $map[$norm] - } - [void]$dups[$norm].Add($i + 1) - } else { - $map[$norm] = $i + 1 - } - } - } - if ($dups.Keys.Count -gt 0) { - $had = $true - Write-Output "=== $($f.FullName) ===" - foreach ($k in $dups.Keys) { - $first = $firstMap[$k] - $others = ($dups[$k] -join ', ') - Write-Output ("Heading: '{0}' first@{1} duplicates@[{2}]" -f $k, $first, $others) - } - } -} -if (-not $had) { - Write-Output "No duplicate headings detected." -} diff --git a/scripts/sdk_signer_sdk_client/auto-ssh-push.sh b/scripts/sdk_signer_sdk_client/auto-ssh-push.sh deleted file mode 100755 index 349abc4..0000000 --- a/scripts/sdk_signer_sdk_client/auto-ssh-push.sh +++ /dev/null @@ -1,156 +0,0 @@ -#!/bin/bash - -# Script d'automatisation des push SSH pour ihm_client -# Utilise automatiquement la clé SSH pour tous les push - -set -e - -echo "🔑 Configuration automatique SSH pour push ihm_client..." - -# Configuration SSH automatique -echo "⚙️ Configuration Git pour utiliser SSH..." -git config --global url."git@git.4nkweb.com:".insteadOf "https://git.4nkweb.com/" - -# Vérifier la configuration SSH -echo "🔍 Vérification de la configuration SSH..." -if ! ssh -T git@git.4nkweb.com 2>&1 | grep -q "successfully authenticated"; then - echo "❌ Échec de l'authentification SSH" - echo "💡 Vérifiez que votre clé SSH est configurée :" - echo " 1. ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_4nk" - echo " 2. Ajouter la clé publique à votre compte Gitea" - echo " 3. ssh-add ~/.ssh/id_ed25519_4nk" - exit 1 -fi - -echo "✅ Authentification SSH réussie" - -# Fonction pour push automatique -auto_push() { - local branch=${1:-$(git branch --show-current)} - local commit_message=${2:-"Auto-commit $(date '+%Y-%m-%d %H:%M:%S')"} - - echo "🚀 Push automatique sur la branche: $branch" - - # Ajouter tous les changements - git add . - - # Commiter avec le message fourni - git commit -m "$commit_message" - - # Push avec SSH automatique - echo "📤 Push vers origin/$branch..." - git push origin "$branch" - - echo "✅ Push réussi !" -} - -# Fonction pour push avec message personnalisé -push_with_message() { - local message="$1" - local branch=${2:-$(git branch --show-current)} - - echo "💬 Push avec message: $message" - auto_push "$branch" "$message" -} - -# Fonction pour push rapide (sans message) -quick_push() { - local branch=${1:-$(git branch --show-current)} - auto_push "$branch" -} - -# Fonction pour push sur une branche spécifique -push_branch() { - local branch="$1" - local message=${2:-"Update $branch $(date '+%Y-%m-%d %H:%M:%S')"} - - echo "🌿 Push sur la branche: $branch" - auto_push "$branch" "$message" -} - -# Fonction pour push et merge vers main -push_and_merge() { - local source_branch=${1:-$(git branch --show-current)} - local target_branch=${2:-main} - - echo "🔄 Push et merge $source_branch -> $target_branch" - - # Push de la branche source - auto_push "$source_branch" - - # Demander confirmation pour le merge - read -p "Voulez-vous créer une Pull Request pour merger vers $target_branch ? (y/N): " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ ]]; then - echo "🔗 Création de la Pull Request..." - echo "💡 Allez sur: https://git.4nkweb.com/4nk/ihm_client/compare/$target_branch...$source_branch" - fi -} - -# Fonction pour status et push conditionnel -status_and_push() { - echo "📊 Statut du repository:" - git status --short - - if [[ -n $(git status --porcelain) ]]; then - echo "📝 Changements détectés, push automatique..." - auto_push - else - echo "✅ Aucun changement à pousser" - fi -} - -# Menu interactif si aucun argument fourni -if [[ $# -eq 0 ]]; then - echo "🤖 Script de push SSH automatique pour ihm_client" - echo "" - echo "Options disponibles:" - echo " auto-push.sh quick - Push rapide" - echo " auto-push.sh message \"Mon message\" - Push avec message" - echo " auto-push.sh branch nom-branche - Push sur branche spécifique" - echo " auto-push.sh merge [source] [target] - Push et préparation merge" - echo " auto-push.sh status - Status et push conditionnel" - echo "" - echo "Exemples:" - echo " ./scripts/auto-ssh-push.sh quick" - echo " ./scripts/auto-ssh-push.sh message \"feat: nouvelle fonctionnalité\"" - echo " ./scripts/auto-ssh-push.sh branch feature/nouvelle-fonctionnalite" - echo " ./scripts/auto-ssh-push.sh merge feature/nouvelle-fonctionnalite main" - echo "" - exit 0 -fi - -# Traitement des arguments -case "$1" in - "quick") - quick_push - ;; - "message") - if [[ -z "$2" ]]; then - echo "❌ Message requis pour l'option 'message'" - exit 1 - fi - push_with_message "$2" - ;; - "branch") - if [[ -z "$2" ]]; then - echo "❌ Nom de branche requis pour l'option 'branch'" - exit 1 - fi - push_branch "$2" "$3" - ;; - "merge") - push_and_merge "$2" "$3" - ;; - "status") - status_and_push - ;; - *) - echo "❌ Option inconnue: $1" - echo "💡 Utilisez './scripts/auto-ssh-push.sh' pour voir les options" - exit 1 - ;; -esac - -echo "🎯 Push SSH automatique terminé !" - diff --git a/scripts/sdk_signer_sdk_client/checks/version_alignment.sh b/scripts/sdk_signer_sdk_client/checks/version_alignment.sh deleted file mode 100755 index e399e72..0000000 --- a/scripts/sdk_signer_sdk_client/checks/version_alignment.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd)" -cd "$ROOT_DIR" - -version_file="VERSION" -[[ -f TEMPLATE_VERSION ]] && version_file="TEMPLATE_VERSION" - -[[ -f "$version_file" ]] || { echo "Version file missing ($version_file)"; exit 1; } -v=$(tr -d '\r' < "$version_file" | head -n1) -[[ -n "$v" ]] || { echo "Empty version"; exit 1; } - -echo "Version file: $version_file=$v" - -if ! grep -Eq "^## \\[$(echo "$v" | sed 's/^v//')\\]" CHANGELOG.md; then - echo "CHANGELOG entry for $v not found"; exit 1; -fi - -echo "Version alignment OK" - diff --git a/scripts/sdk_signer_sdk_client/deploy/setup.sh b/scripts/sdk_signer_sdk_client/deploy/setup.sh deleted file mode 100755 index 8908ea9..0000000 --- a/scripts/sdk_signer_sdk_client/deploy/setup.sh +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ENV_DIR="${HOME}/.4nk_template" -ENV_FILE="${ENV_DIR}/.env" -TEMPLATE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" -TEMPLATE_IN_REPO="${TEMPLATE_ROOT}/scripts/env/.env.template" - -usage() { - cat < [--dest DIR] [--force] - -Actions: - 1) Provisionne ~/.4nk_template/.env (si absent) - 2) Clone le dépôt cible si le dossier n'existe pas - 3) Copie la structure normative 4NK_template dans le projet cible: - - .gitea/** (workflows, templates issues/PR) - - AGENTS.md - - .cursor/rules/** (si présent) - - scripts/agents/**, scripts/env/ensure_env.sh, scripts/deploy/setup.sh - - docs/templates/** et docs/INDEX.md (table des matières) - 4) Ne remplace pas les fichiers existants sauf si --force - -Exemples: - $0 https://git.example.com/org/projet.git - $0 git@host:org/projet.git --dest ~/work --force -USAGE -} - -GIT_URL="${1:-}" -DEST_PARENT="$(pwd)" -FORCE_COPY=0 -shift || true -while [[ $# -gt 0 ]]; do - case "$1" in - --dest) - DEST_PARENT="${2:-}"; shift 2 ;; - --force) - FORCE_COPY=1; shift ;; - -h|--help) - usage; exit 0 ;; - *) - echo "Option inconnue: $1" >&2; usage; exit 2 ;; - esac -done - -if [[ -z "${GIT_URL}" ]]; then - usage; exit 2 -fi - -mkdir -p "${ENV_DIR}" -chmod 700 "${ENV_DIR}" || true - -if [[ ! -f "${ENV_FILE}" ]]; then - if [[ -f "${TEMPLATE_IN_REPO}" ]]; then - cp "${TEMPLATE_IN_REPO}" "${ENV_FILE}" - else - cat >"${ENV_FILE}" <<'EOF' -# Fichier d'exemple d'environnement pour 4NK_template -# Copiez ce fichier vers ~/.4nk_template/.env puis complétez les valeurs. -# Ne committez jamais de fichier contenant des secrets. - -# OpenAI (agents IA) -OPENAI_API_KEY= -OPENAI_MODEL= -OPENAI_API_BASE=https://api.openai.com/v1 -OPENAI_TEMPERATURE=0.2 - -# Gitea (release via API) -BASE_URL=https://git.4nkweb.com -RELEASE_TOKEN= -EOF - fi - chmod 600 "${ENV_FILE}" || true - echo "Fichier créé: ${ENV_FILE}. Complétez les valeurs requises (ex: OPENAI_API_KEY, OPENAI_MODEL, RELEASE_TOKEN)." >&2 -fi - -# 2) Clonage du dépôt si nécessaire -repo_name="$(basename -s .git "${GIT_URL}")" -target_dir="${DEST_PARENT%/}/${repo_name}" -if [[ ! -d "${target_dir}" ]]; then - echo "Clonage: ${GIT_URL} → ${target_dir}" >&2 - git clone --depth 1 "${GIT_URL}" "${target_dir}" -else - echo "Dossier existant, pas de clone: ${target_dir}" >&2 -fi - -copy_item() { - local src="$1" dst="$2" - if [[ ! -e "$src" ]]; then return 0; fi - if [[ -d "$src" ]]; then - mkdir -p "$dst" - if (( FORCE_COPY )); then - cp -a "$src/." "$dst/" - else - (cd "$src" && find . -type f -print0) | while IFS= read -r -d '' f; do - if [[ ! -e "$dst/$f" ]]; then - mkdir -p "$(dirname "$dst/$f")" - cp -a "$src/$f" "$dst/$f" - fi - done - fi - else - if [[ -e "$dst" && $FORCE_COPY -eq 0 ]]; then return 0; fi - mkdir -p "$(dirname "$dst")" && cp -a "$src" "$dst" - fi -} - -# 3) Copie de la structure normative -copy_item "${TEMPLATE_ROOT}/.gitea" "${target_dir}/.gitea" -copy_item "${TEMPLATE_ROOT}/AGENTS.md" "${target_dir}/AGENTS.md" -copy_item "${TEMPLATE_ROOT}/.cursor" "${target_dir}/.cursor" -copy_item "${TEMPLATE_ROOT}/.cursorignore" "${target_dir}/.cursorignore" -copy_item "${TEMPLATE_ROOT}/.gitignore" "${target_dir}/.gitignore" -copy_item "${TEMPLATE_ROOT}/.markdownlint.json" "${target_dir}/.markdownlint.json" -copy_item "${TEMPLATE_ROOT}/LICENSE" "${target_dir}/LICENSE" -copy_item "${TEMPLATE_ROOT}/CONTRIBUTING.md" "${target_dir}/CONTRIBUTING.md" -copy_item "${TEMPLATE_ROOT}/CODE_OF_CONDUCT.md" "${target_dir}/CODE_OF_CONDUCT.md" -copy_item "${TEMPLATE_ROOT}/SECURITY.md" "${target_dir}/SECURITY.md" -copy_item "${TEMPLATE_ROOT}/TEMPLATE_VERSION" "${target_dir}/TEMPLATE_VERSION" -copy_item "${TEMPLATE_ROOT}/security" "${target_dir}/security" -copy_item "${TEMPLATE_ROOT}/scripts" "${target_dir}/scripts" -copy_item "${TEMPLATE_ROOT}/docs/templates" "${target_dir}/docs/templates" - -# Génération docs/INDEX.md dans le projet cible (si absent ou --force) -INDEX_DST="${target_dir}/docs/INDEX.md" -if [[ ! -f "${INDEX_DST}" || $FORCE_COPY -eq 1 ]]; then - mkdir -p "$(dirname "${INDEX_DST}")" - cat >"${INDEX_DST}" <<'IDX' -# Documentation du projet - -Cette table des matières oriente vers: -- Documentation spécifique au projet: `docs/project/` -- Modèles génériques à adapter: `docs/templates/` - -## Sommaire -- À personnaliser: `docs/project/README.md`, `docs/project/INDEX.md`, `docs/project/ARCHITECTURE.md`, `docs/project/USAGE.md`, etc. - -## Modèles génériques -- Voir: `docs/templates/` -IDX -fi - -echo "Template 4NK appliqué à: ${target_dir}" >&2 -exit 0 diff --git a/scripts/sdk_signer_sdk_client/dev/run_container.sh b/scripts/sdk_signer_sdk_client/dev/run_container.sh deleted file mode 100755 index 2d543cb..0000000 --- a/scripts/sdk_signer_sdk_client/dev/run_container.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -IMAGE_NAME="4nk-template-dev:debian" -DOCKERFILE="docker/Dockerfile.debian" - -echo "[build] ${IMAGE_NAME}" -docker build -t "${IMAGE_NAME}" -f "${DOCKERFILE}" . - -echo "[run] launching container and executing agents" -docker run --rm -it \ - -v "${PWD}:/work" -w /work \ - "${IMAGE_NAME}" \ - "scripts/agents/run.sh; ls -la tests/reports/agents || true" - diff --git a/scripts/sdk_signer_sdk_client/dev/run_project_ci.sh b/scripts/sdk_signer_sdk_client/dev/run_project_ci.sh deleted file mode 100755 index d92d96b..0000000 --- a/scripts/sdk_signer_sdk_client/dev/run_project_ci.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Build et lance le conteneur unifié (runner+agents) sur ce projet -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" -cd "$ROOT_DIR" - -# Build image -docker compose -f docker-compose.ci.yml build - -# Exécuter agents par défaut -RUNNER_MODE="${RUNNER_MODE:-agents}" BASE_URL="${BASE_URL:-}" REGISTRATION_TOKEN="${REGISTRATION_TOKEN:-}" \ - docker compose -f docker-compose.ci.yml up --remove-orphans --abort-on-container-exit diff --git a/scripts/sdk_signer_sdk_client/env/ensure_env.sh b/scripts/sdk_signer_sdk_client/env/ensure_env.sh deleted file mode 100755 index 6435819..0000000 --- a/scripts/sdk_signer_sdk_client/env/ensure_env.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" -TEMPLATE_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.env.template" -ENV_DIR="${HOME}/.4nk_template" -ENV_FILE="${ENV_DIR}/.env" - -mkdir -p "${ENV_DIR}" -chmod 700 "${ENV_DIR}" || true - -if [[ ! -f "${ENV_FILE}" ]]; then - if [[ -f "${TEMPLATE_FILE}" ]]; then - cp "${TEMPLATE_FILE}" "${ENV_FILE}" - chmod 600 "${ENV_FILE}" || true - echo "Fichier d'environnement créé: ${ENV_FILE}" >&2 - echo "Veuillez renseigner les variables requises (OPENAI_API_KEY, OPENAI_MODEL, etc.)." >&2 - exit 3 - else - echo "Modèle d'environnement introuvable: ${TEMPLATE_FILE}" >&2 - exit 2 - fi -fi - -# Charger pour validation -set -a -. "${ENV_FILE}" -set +a - -MISSING=() -for var in OPENAI_API_KEY OPENAI_MODEL; do - if [[ -z "${!var:-}" ]]; then - MISSING+=("$var") - fi -done - -if (( ${#MISSING[@]} > 0 )); then - echo "Variables manquantes dans ${ENV_FILE}: ${MISSING[*]}" >&2 - exit 4 -fi - -echo "Environnement valide: ${ENV_FILE}" >&2 diff --git a/scripts/sdk_signer_sdk_client/init-ssh-env.sh b/scripts/sdk_signer_sdk_client/init-ssh-env.sh deleted file mode 100755 index 7d6078a..0000000 --- a/scripts/sdk_signer_sdk_client/init-ssh-env.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/bash - -# Script d'initialisation de l'environnement SSH pour ihm_client -# Configure automatiquement SSH pour tous les push - -set -e - -echo "🚀 Initialisation de l'environnement SSH pour ihm_client..." - -# Couleurs pour les messages -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Fonction pour afficher les messages colorés -print_status() { - echo -e "${BLUE}[INFO]${NC} $1" -} - -print_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" -} - -print_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" -} - -print_error() { - echo -e "${RED}[ERROR]${NC} $1" -} - -# Vérifier si on est dans le bon répertoire -if [[ ! -f "package.json" ]] || [[ ! -d ".git" ]]; then - print_error "Ce script doit être exécuté depuis le répertoire racine de ihm_client" - exit 1 -fi - -print_status "Configuration de l'environnement SSH..." - -# 1. Configuration Git pour SSH -print_status "Configuration Git pour utiliser SSH..." -git config --global url."git@git.4nkweb.com:".insteadOf "https://git.4nkweb.com/" - -# 2. Vérifier si une clé SSH existe -print_status "Vérification des clés SSH existantes..." -if [[ -f ~/.ssh/id_rsa ]] || [[ -f ~/.ssh/id_ed25519 ]]; then - print_success "Clé SSH trouvée" - SSH_KEY_EXISTS=true -else - print_warning "Aucune clé SSH trouvée" - SSH_KEY_EXISTS=false -fi - -# 3. Tester la connexion SSH -print_status "Test de la connexion SSH vers git.4nkweb.com..." -if ssh -T git@git.4nkweb.com 2>&1 | grep -q "successfully authenticated"; then - print_success "Authentification SSH réussie" - SSH_WORKING=true -else - print_error "Échec de l'authentification SSH" - SSH_WORKING=false -fi - -# 4. Configuration des alias Git -print_status "Configuration des alias Git..." -git config --global alias.ssh-push '!f() { git add . && git commit -m "${1:-Auto-commit $(date)}" && git push origin $(git branch --show-current); }; f' -git config --global alias.quick-push '!f() { git add . && git commit -m "Update $(date)" && git push origin $(git branch --show-current); }; f' - -print_success "Alias Git configurés" - -# 5. Vérifier les remotes -print_status "Vérification des remotes Git..." -if git remote -v | grep -q "git@git.4nkweb.com"; then - print_success "Remotes configurés pour SSH" -else - print_warning "Remotes non configurés pour SSH" - print_status "Mise à jour des remotes..." - git remote set-url origin git@git.4nkweb.com:4nk/ihm_client.git - print_success "Remotes mis à jour" -fi - -# 6. Rendre les scripts exécutables -print_status "Configuration des permissions des scripts..." -chmod +x scripts/auto-ssh-push.sh 2>/dev/null || true -chmod +x scripts/setup-ssh-ci.sh 2>/dev/null || true - -print_success "Scripts rendus exécutables" - -# 7. Créer un fichier de configuration local -print_status "Création du fichier de configuration local..." -cat > .ssh-config << EOF -# Configuration SSH automatique pour ihm_client -# Généré le $(date) - -# Configuration Git -git config --global url."git@git.4nkweb.com:".insteadOf "https://git.4nkweb.com/" - -# Alias Git -git config --global alias.ssh-push '!f() { git add . && git commit -m "\${1:-Auto-commit \$(date)}" && git push origin \$(git branch --show-current); }; f' -git config --global alias.quick-push '!f() { git add . && git commit -m "Update \$(date)" && git push origin \$(git branch --show-current); }; f' - -# Test SSH -ssh -T git@git.4nkweb.com - -# Scripts disponibles -./scripts/auto-ssh-push.sh quick -./scripts/auto-ssh-push.sh message "Mon message" -git ssh-push "Mon message" -git quick-push -EOF - -print_success "Fichier de configuration créé: .ssh-config" - -# 8. Résumé de la configuration -echo "" -print_success "=== Configuration SSH terminée ===" -echo "" -echo "✅ Configuration Git pour SSH" -echo "✅ Alias Git configurés" -echo "✅ Remotes vérifiés" -echo "✅ Scripts configurés" -echo "" - -if [[ "$SSH_WORKING" == "true" ]]; then - print_success "SSH fonctionne correctement" - echo "" - echo "🚀 Vous pouvez maintenant utiliser :" - echo " ./scripts/auto-ssh-push.sh quick" - echo " ./scripts/auto-ssh-push.sh message \"Mon message\"" - echo " git ssh-push \"Mon message\"" - echo " git quick-push" - echo "" -else - print_warning "SSH ne fonctionne pas encore" - echo "" - echo "🔧 Pour configurer SSH :" - echo " 1. Générer une clé SSH : ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_4nk" - echo " 2. Ajouter à l'agent SSH : ssh-add ~/.ssh/id_ed25519_4nk" - echo " 3. Ajouter la clé publique à votre compte Gitea" - echo " 4. Relancer ce script : ./scripts/init-ssh-env.sh" - echo "" -fi - -# 9. Test final -if [[ "$SSH_WORKING" == "true" ]]; then - print_status "Test final de push SSH..." - echo "💡 Pour tester, utilisez : ./scripts/auto-ssh-push.sh status" -fi - -print_success "Initialisation SSH terminée !" - diff --git a/scripts/sdk_signer_sdk_client/local/install_hooks.sh b/scripts/sdk_signer_sdk_client/local/install_hooks.sh deleted file mode 100755 index bd0f600..0000000 --- a/scripts/sdk_signer_sdk_client/local/install_hooks.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"/.. -HOOKS_DIR="$REPO_ROOT/.git/hooks" - -mkdir -p "$HOOKS_DIR" -install_hook() { - local name="$1" src="$2" - cp -f "$src" "$HOOKS_DIR/$name" - chmod +x "$HOOKS_DIR/$name" - echo "Installed hook: $name" -} - -# Hooks qui délèguent aux agents via l'image Docker du template sur le projet courant -install_hook pre-commit "$REPO_ROOT/scripts/local/precommit.sh" -install_hook pre-push "$REPO_ROOT/scripts/local/prepush.sh" - -echo "Hooks installés (mode agents via 4NK_template)." diff --git a/scripts/sdk_signer_sdk_client/local/merge_branch.sh b/scripts/sdk_signer_sdk_client/local/merge_branch.sh deleted file mode 100755 index 9275299..0000000 --- a/scripts/sdk_signer_sdk_client/local/merge_branch.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -TARGET_BRANCH="${1:-main}" -SOURCE_BRANCH="${2:-}" - -if [[ -z "$SOURCE_BRANCH" ]]; then - SOURCE_BRANCH="$(git rev-parse --abbrev-ref HEAD)" -fi - -if [[ "$SOURCE_BRANCH" == "$TARGET_BRANCH" ]]; then - echo "Déjà sur $TARGET_BRANCH"; exit 0 -fi - -# Valider localement avant merge -AUTO_FIX="${AUTO_FIX:-1}" SCOPE="${SCOPE:-all}" scripts/agents/run.sh || true -if [ -f scripts/security/audit.sh ]; then bash scripts/security/audit.sh || true; fi - -git fetch origin --prune -git checkout "$TARGET_BRANCH" -git pull --ff-only origin "$TARGET_BRANCH" || true -git merge --no-ff "$SOURCE_BRANCH" -m "[skip ci] merge: $SOURCE_BRANCH -> $TARGET_BRANCH" -git push origin "$TARGET_BRANCH" - -echo "Merge effectué: $SOURCE_BRANCH → $TARGET_BRANCH" diff --git a/scripts/sdk_signer_sdk_client/local/precommit.sh b/scripts/sdk_signer_sdk_client/local/precommit.sh deleted file mode 100755 index b2b502c..0000000 --- a/scripts/sdk_signer_sdk_client/local/precommit.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Exécuter les agents depuis l'image Docker de 4NK_template sur le projet courant -PROJECT_DIR="$(git rev-parse --show-toplevel)" -TEMPLATE_DIR="$(cd "${PROJECT_DIR}/../4NK_template" && pwd)" - -mkdir -p "${PROJECT_DIR}/tests/reports/agents" -"${TEMPLATE_DIR}/scripts/local/run_agents_for_project.sh" "${PROJECT_DIR}" "tests/reports/agents" - -echo "[pre-commit] OK (agents via 4NK_template)" diff --git a/scripts/sdk_signer_sdk_client/local/prepush.sh b/scripts/sdk_signer_sdk_client/local/prepush.sh deleted file mode 100755 index 7cb8c7d..0000000 --- a/scripts/sdk_signer_sdk_client/local/prepush.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Exécuter les agents depuis l'image Docker de 4NK_template sur le projet courant -PROJECT_DIR="$(git rev-parse --show-toplevel)" -TEMPLATE_DIR="$(cd "${PROJECT_DIR}/../4NK_template" && pwd)" - -mkdir -p "${PROJECT_DIR}/tests/reports/agents" -"${TEMPLATE_DIR}/scripts/local/run_agents_for_project.sh" "${PROJECT_DIR}" "tests/reports/agents" - -# Audit sécurité (best effort) dans le contexte du projet -if [ -f "${PROJECT_DIR}/scripts/security/audit.sh" ]; then - (cd "${PROJECT_DIR}" && bash scripts/security/audit.sh) || true -fi - -# Release guard (dry-run logique) dans le contexte du projet -if [ -f "${PROJECT_DIR}/scripts/release/guard.sh" ]; then - (cd "${PROJECT_DIR}" && bash scripts/release/guard.sh) || true -fi - -echo "[pre-push] OK (agents via 4NK_template)" diff --git a/scripts/sdk_signer_sdk_client/local/release_local.sh b/scripts/sdk_signer_sdk_client/local/release_local.sh deleted file mode 100755 index e3f48ed..0000000 --- a/scripts/sdk_signer_sdk_client/local/release_local.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -VERSION="${1:-}" -if [[ -z "$VERSION" ]]; then - echo "Usage: $0 vYYYY.MM.P" >&2 - exit 2 -fi - -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -cd "$ROOT_DIR/.." - -echo "$VERSION" > TEMPLATE_VERSION -git add TEMPLATE_VERSION CHANGELOG.md 2>/dev/null || true -git commit -m "[skip ci] chore(release): $VERSION" || true -git tag -a "$VERSION" -m "release: $VERSION (latest)" -git push || true -git push origin "$VERSION" - -echo "Release locale préparée: $VERSION" diff --git a/scripts/sdk_signer_sdk_client/local/run_agents_for_project.sh b/scripts/sdk_signer_sdk_client/local/run_agents_for_project.sh deleted file mode 100755 index 5070846..0000000 --- a/scripts/sdk_signer_sdk_client/local/run_agents_for_project.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Script pour lancer les agents de 4NK_template sur un projet externe -# Usage: ./run_agents_for_project.sh [project_path] [output_dir] - -PROJECT_PATH="${1:-.}" -OUTPUT_DIR="${2:-tests/reports/agents}" -TEMPLATE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" -MODULE_LAST_IMAGE_FILE="$(cd "$TEMPLATE_DIR/.." && pwd)/modules/4NK_template/.last_image" - -if [[ ! -d "$PROJECT_PATH" ]]; then - echo "Erreur: Le projet '$PROJECT_PATH' n'existe pas" >&2 - exit 1 -fi - -mkdir -p "$PROJECT_PATH/$OUTPUT_DIR" - -echo "=== Lancement des agents 4NK_template sur: $PROJECT_PATH ===" - -if ! command -v docker >/dev/null 2>&1; then - echo "Docker requis pour exécuter les agents via conteneur." >&2 - exit 2 -fi - -# Si une image du module existe, l'utiliser en priorité -if [[ -f "$MODULE_LAST_IMAGE_FILE" ]]; then - IMAGE_NAME="$(cat "$MODULE_LAST_IMAGE_FILE" | tr -d '\r\n')" - echo "Utilisation de l'image du module: $IMAGE_NAME" - # Préparer montage du fichier d'env si présent - ENV_MOUNT="" - if [[ -f "$HOME/.4nk_template/.env" ]]; then - ENV_MOUNT="-v $HOME/.4nk_template/.env:/root/.4nk_template/.env:ro" - fi - # Lancer le conteneur en utilisant l'ENTRYPOINT qui configure safe.directory - docker run --rm \ - -e RUNNER_MODE=agents \ - -e TARGET_DIR=/work \ - -e OUTPUT_DIR=/work/$OUTPUT_DIR \ - -v "$(realpath "$PROJECT_PATH"):/work" \ - $ENV_MOUNT \ - "$IMAGE_NAME" || true -else - echo "Aucune image de module détectée, fallback docker compose dans 4NK_template" - cd "$TEMPLATE_DIR" - docker compose -f docker-compose.ci.yml build - RUNNER_MODE="agents" TARGET_DIR="/work" OUTPUT_DIR="/work/$OUTPUT_DIR" \ - docker compose -f docker-compose.ci.yml run --rm project-ci || true -fi - -echo "=== Agents terminés → $PROJECT_PATH/$OUTPUT_DIR ===" diff --git a/scripts/sdk_signer_sdk_client/release/guard.sh b/scripts/sdk_signer_sdk_client/release/guard.sh deleted file mode 100755 index cb5410b..0000000 --- a/scripts/sdk_signer_sdk_client/release/guard.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Release guard script -# Checks: tests, docs updated, compile, version ↔ changelog ↔ tag consistency, release type - -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd)" -cd "$ROOT_DIR" - -mode="${RELEASE_TYPE:-ci-verify}" # values: latest | wip | ci-verify - -echo "[release-guard] mode=$mode" - -# 1) Basic presence checks -[[ -f CHANGELOG.md ]] || { echo "CHANGELOG.md manquant"; exit 1; } -version_file="VERSION" -[[ -f TEMPLATE_VERSION ]] && version_file="TEMPLATE_VERSION" -[[ -f "$version_file" ]] || { echo "$version_file manquant"; exit 1; } - -# 2) Extract version -project_version=$(tr -d '\r' < "$version_file" | head -n1 | sed 's/^v//') -[[ -n "$project_version" ]] || { echo "Version vide dans $version_file"; exit 1; } -echo "[release-guard] version=$project_version" - -# 3) Changelog checks -if ! grep -Eq "^## \\[$project_version\\]" CHANGELOG.md; then - if [[ "$mode" == "wip" ]]; then - grep -Eq "^## \\[Unreleased\\]" CHANGELOG.md || { echo "Section [Unreleased] absente du CHANGELOG"; exit 1; } - else - echo "Entrée CHANGELOG pour version $project_version manquante"; exit 1; - fi -fi - -# 4) Tests (optional best-effort) -if [[ -x tests/run_all_tests.sh ]]; then - echo "[release-guard] exécution tests/run_all_tests.sh" - ./tests/run_all_tests.sh || { echo "Tests en échec"; exit 1; } -else - echo "[release-guard] tests absents (ok)" -fi - -# 5) Build/compile (optional based on project) -if [[ -d sdk_relay ]] && command -v cargo >/dev/null 2>&1; then - echo "[release-guard] cargo build (sdk_relay)" - (cd sdk_relay && cargo build --quiet) || { echo "Compilation échouée"; exit 1; } -else - echo "[release-guard] build spécifique non applicable (ok)" -fi - -# 6) Release type handling -case "$mode" in - latest) - ;; - wip) - # En wip, autoriser versions suffixées; pas d’exigence d’entrée datée - ;; - ci-verify) - # En CI, on valide juste la présence de CHANGELOG et version - ;; - *) - echo "RELEASE_TYPE invalide: $mode (latest|wip|ci-verify)"; exit 1; - ;; -esac - -echo "[release-guard] OK" - diff --git a/scripts/sdk_signer_sdk_client/run-wasm-tests.ps1 b/scripts/sdk_signer_sdk_client/run-wasm-tests.ps1 deleted file mode 100644 index 9c001df..0000000 --- a/scripts/sdk_signer_sdk_client/run-wasm-tests.ps1 +++ /dev/null @@ -1,128 +0,0 @@ -$ErrorActionPreference = "Stop" - -function Set-WasmToolchainEnv { - param() - $clang = $env:CC - if (-not $clang -or -not (Test-Path $clang)) { - $defaultClang = "C:\\Program Files\\LLVM\\bin\\clang.exe" - if (Test-Path $defaultClang) { - $clang = $defaultClang - } else { - $cmd = Get-Command clang.exe -ErrorAction SilentlyContinue - if ($cmd) { $clang = $cmd.Path } - } - } - if (-not $clang) { throw "Clang introuvable. Installez LLVM/Clang et relancez." } - - $env:CC = $clang - $llvmBin = Split-Path $clang -Parent - $env:AR = Join-Path $llvmBin "llvm-ar.exe" - $env:NM = Join-Path $llvmBin "llvm-nm.exe" - - $env:TARGET_CC = $env:CC - $env:CC_wasm32_unknown_unknown = $env:CC - $env:AR_wasm32_unknown_unknown = $env:AR - $env:NM_wasm32_unknown_unknown = $env:NM - [System.Environment]::SetEnvironmentVariable('CC_wasm32-unknown-unknown', $env:CC, 'Process') - [System.Environment]::SetEnvironmentVariable('AR_wasm32-unknown-unknown', $env:AR, 'Process') - [System.Environment]::SetEnvironmentVariable('NM_wasm32-unknown-unknown', $env:NM, 'Process') -} - -function Invoke-WasmPackTests { - param( - [switch]$Chrome, - [switch]$Firefox, - [switch]$Node - ) - if ($Chrome) { Ensure-WasmBindgenRunner; wasm-pack test --headless --chrome } - if ($Firefox) { Ensure-WasmBindgenRunner; wasm-pack test --headless --firefox } - if ($Node) { - # Forcer Node comme runner pour wasm-bindgen-test - $node = (Get-Command node.exe -ErrorAction SilentlyContinue).Path - if ($node) { $env:WASM_BINDGEN_TEST_RUNNER = $node } else { $env:WASM_BINDGEN_TEST_RUNNER = "node" } - $env:CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER = "node" - wasm-pack test --node - } -} - -$runnerSet = $false -function Ensure-WasmBindgenRunner { - param() - # Cherche un runner dans le cache wasm-pack - $localWp = Join-Path $env:LOCALAPPDATA ".wasm-pack" - $cachedRunner = $null - if (Test-Path $localWp) { - $candidates = Get-ChildItem -Path $localWp -Recurse -Filter "wasm-bindgen-test-runner.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 - if ($candidates) { $cachedRunner = $candidates.FullName } - } - - if (-not $cachedRunner) { - Write-Host "Aucun runner trouvé. Téléchargement de l’archive officielle (tar.gz) pour Windows..." -ForegroundColor Yellow - $wbgVersion = "0.2.100" - $arch = "x86_64-pc-windows-msvc" - $tarName = "wasm-bindgen-$wbgVersion-$arch.tar.gz" - $downloadUrl = "https://github.com/rustwasm/wasm-bindgen/releases/download/$wbgVersion/$tarName" - $destParent = $localWp - $tarPath = Join-Path $env:TEMP $tarName - try { - if (-not (Test-Path $destParent)) { New-Item -ItemType Directory -Force -Path $destParent | Out-Null } - Invoke-WebRequest -Uri $downloadUrl -OutFile $tarPath -UseBasicParsing -ErrorAction Stop - Push-Location $destParent - tar -xzf $tarPath - Pop-Location - } catch { - Write-Warning "Échec du téléchargement/extraction du runner: $($_.Exception.Message)" - } finally { - if (Test-Path $tarPath) { Remove-Item -Force $tarPath } - } - # Recherche récursive du binaire extrait - $found = Get-ChildItem -Path (Join-Path $destParent "wasm-bindgen-$wbgVersion-$arch") -Recurse -Filter "wasm-bindgen-test-runner.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 - if ($found) { $cachedRunner = $found.FullName } - } - - if ($cachedRunner -and (Test-Path $cachedRunner)) { - $script:runnerSet = $true - $env:WASM_BINDGEN_TEST_RUNNER = $cachedRunner - $runnerDir = Split-Path $cachedRunner -Parent - if ($env:PATH -notlike "*$runnerDir*") { $env:PATH = "$runnerDir;$env:PATH" } - # Force cargo/wasm-pack à utiliser ce runner pour wasm32-unknown-unknown - [System.Environment]::SetEnvironmentVariable('CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER', $cachedRunner, 'Process') - # Copie de secours dans les dossiers cache wasm-pack attendus (hashés) - try { - $wpDirs = Get-ChildItem -Path $localWp -Directory -Filter "wasm-bindgen-*" -ErrorAction SilentlyContinue - foreach ($d in $wpDirs) { - $destRunner = Join-Path $d.FullName "wasm-bindgen-test-runner.exe" - if (-not (Test-Path $destRunner)) { - Copy-Item -Force $cachedRunner $destRunner -ErrorAction SilentlyContinue - } - $wbExeSrc = Join-Path $runnerDir "wasm-bindgen.exe" - $wbExeDst = Join-Path $d.FullName "wasm-bindgen.exe" - if ((Test-Path $wbExeSrc) -and -not (Test-Path $wbExeDst)) { - Copy-Item -Force $wbExeSrc $wbExeDst -ErrorAction SilentlyContinue - } - } - } catch {} - Write-Host "WASM_BINDGEN_TEST_RUNNER défini vers: $cachedRunner" -ForegroundColor Green - return - } - - Write-Warning "wasm-bindgen-test-runner introuvable. wasm-pack tentera de le télécharger lors de l'exécution des tests." -} - -$scriptsDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$repoRoot = Split-Path -Parent $scriptsDir -Push-Location $repoRoot -try { - Set-WasmToolchainEnv - # Ne préparer le runner binaire que si navigateurs utilisés (Node n'en a pas besoin) - try { - # D'abord Node (plus robuste sur Windows) - Invoke-WasmPackTests -Node - } catch { - Write-Warning "Tests Node échoués, tentative avec navigateurs headless." - Invoke-WasmPackTests -Chrome -Firefox - } -} finally { - Pop-Location -} - diff --git a/scripts/sdk_signer_sdk_client/scripts/auto-ssh-push.sh b/scripts/sdk_signer_sdk_client/scripts/auto-ssh-push.sh deleted file mode 100755 index 0064500..0000000 --- a/scripts/sdk_signer_sdk_client/scripts/auto-ssh-push.sh +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Script d'automatisation des push SSH (template Linux) -# Utilise automatiquement la clé SSH pour pousser sur le remote courant via SSH. - -GITEA_HOST="${GITEA_HOST:-git.4nkweb.com}" - -echo "🔑 Configuration SSH pour push (template)..." - -# Configuration SSH automatique -echo "⚙️ Configuration Git pour utiliser SSH..." -git config --global url."git@${GITEA_HOST}:".insteadOf "https://${GITEA_HOST}/" - -# Vérifier la configuration SSH -echo "🔍 Vérification de la configuration SSH..." -if ! ssh -T git@"${GITEA_HOST}" 2>&1 | grep -qi "authenticated\|welcome"; then - echo "❌ Échec de l'authentification SSH" - echo "💡 Vérifiez que votre clé SSH est configurée :" - echo " 1. ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_4nk" - echo " 2. Ajouter la clé publique à votre compte Gitea" - echo " 3. ssh-add ~/.ssh/id_ed25519_4nk" - exit 1 -fi - -echo "✅ Authentification SSH réussie" - -# Fonction pour push automatique -get_current_branch() { - # Détecte la branche courante, compatible anciennes versions de git - local br - br="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)" - if [ -z "$br" ] || [ "$br" = "HEAD" ]; then - br="$(git symbolic-ref --short -q HEAD 2>/dev/null || true)" - fi - if [ -z "$br" ]; then - # dernier recours: parser la sortie de "git branch" - br="$(git branch 2>/dev/null | sed -n 's/^* //p' | head -n1)" - fi - echo "$br" -} - -auto_push() { - local branch - branch=${1:-$(get_current_branch)} - local commit_message=${2:-"Auto-commit $(date '+%Y-%m-%d %H:%M:%S')"} - - echo "🚀 Push automatique sur la branche: $branch" - - # Ajouter tous les changements - git add . - - # Ne pas commiter si rien à commite - if [[ -z "$(git diff --cached --name-only)" ]]; then - echo "ℹ️ Aucun changement indexé. Skip commit/push." - return 0 - fi - - # Commiter avec le message fourni - git commit -m "$commit_message" || true - - # Push avec SSH automatique - echo "📤 Push vers origin/$branch..." - git push origin "$branch" - - echo "✅ Push réussi !" -} - -# Fonction pour push avec message personnalisé -push_with_message() { - local message="$1" - local branch=${2:-$(get_current_branch)} - - echo "💬 Push avec message: $message" - auto_push "$branch" "$message" -} - -# Fonction pour push rapide (sans message) -quick_push() { - local branch=${1:-$(get_current_branch)} - auto_push "$branch" -} - -# Fonction pour push sur une branche spécifique -push_branch() { - local branch="$1" - local message=${2:-"Update $branch $(date '+%Y-%m-%d %H:%M:%S')"} - - echo "🌿 Push sur la branche: $branch" - auto_push "$branch" "$message" -} - -# Fonction pour push et merge vers main -push_and_merge() { - local source_branch=${1:-$(get_current_branch)} - local target_branch=${2:-main} - - echo "🔄 Push et merge $source_branch -> $target_branch" - - # Push de la branche source - auto_push "$source_branch" - - # Indication pour PR manuelle - echo "🔗 Ouvrez une Pull Request sur votre forge pour $source_branch -> $target_branch" -} - -# Fonction pour status et push conditionnel -status_and_push() { - echo "📊 Statut du repository:" - git status --short || true - - if [[ -n $(git status --porcelain) ]]; then - echo "📝 Changements détectés, push automatique..." - auto_push - else - echo "✅ Aucun changement à pousser" - fi -} - -# Menu interactif si aucun argument fourni -if [[ $# -eq 0 ]]; then - echo "🤖 Script de push SSH automatique (template)" - echo "" - echo "Options disponibles:" - echo " auto-ssh-push.sh quick - Push rapide" - echo " auto-ssh-push.sh message \"Mon message\" - Push avec message" - echo " auto-ssh-push.sh branch nom-branche - Push sur branche spécifique" - echo " auto-ssh-push.sh merge [source] [target] - Push et préparation merge" - echo " auto-ssh-push.sh status - Status et push conditionnel" - echo "" - exit 0 -fi - -# Traitement des arguments -case "$1" in - "quick") - quick_push - ;; - "message") - if [[ -z "${2:-}" ]]; then - echo "❌ Message requis pour l'option 'message'" - exit 1 - fi - push_with_message "$2" "${3:-}" - ;; - "branch") - if [[ -z "${2:-}" ]]; then - echo "❌ Nom de branche requis pour l'option 'branch'" - exit 1 - fi - push_branch "$2" "${3:-}" - ;; - "merge") - push_and_merge "${2:-}" "${3:-}" - ;; - "status") - status_and_push - ;; - *) - echo "❌ Option inconnue: $1" - echo "💡 Utilisez './scripts/auto-ssh-push.sh' pour voir les options" - exit 1 - ;; -esac - -echo "🎯 Push SSH automatique terminé !" diff --git a/scripts/sdk_signer_sdk_client/scripts/init-ssh-env.sh b/scripts/sdk_signer_sdk_client/scripts/init-ssh-env.sh deleted file mode 100755 index a125ab1..0000000 --- a/scripts/sdk_signer_sdk_client/scripts/init-ssh-env.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Script d'initialisation de l'environnement SSH (template Linux) -# Configure automatiquement SSH pour les push via Gitea - -GITEA_HOST="${GITEA_HOST:-git.4nkweb.com}" - -echo "🚀 Initialisation de l'environnement SSH (template)..." - -# Couleurs -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -print_status() { echo -e "${BLUE}[INFO]${NC} $1"; } -print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } -print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; } -print_error() { echo -e "${RED}[ERROR]${NC} $1"; } - -print_status "Configuration SSH..." - -# 1. Configuration Git pour SSH -print_status "Configuration Git pour utiliser SSH (${GITEA_HOST})..." -git config --global url."git@${GITEA_HOST}:".insteadOf "https://${GITEA_HOST}/" - -# 2. Vérification des clés SSH -print_status "Vérification des clés SSH existantes..." -if [[ -f ~/.ssh/id_rsa || -f ~/.ssh/id_ed25519 ]]; then - print_success "Clé SSH trouvée" -else - print_warning "Aucune clé SSH trouvée" -fi - -# 3. Test de la connexion SSH -print_status "Test de la connexion SSH vers ${GITEA_HOST}..." -if ssh -T git@"${GITEA_HOST}" 2>&1 | grep -qi "authenticated\|welcome"; then - print_success "Authentification SSH réussie" -else - print_error "Échec de l'authentification SSH" -fi - -# 4. Alias Git -print_status "Configuration des alias Git..." -git config --global alias.ssh-push '!f() { git add . && git commit -m "${1:-Auto-commit $(date)}" && git push origin $(git branch --show-current); }; f' -git config --global alias.quick-push '!f() { git add . && git commit -m "Update $(date)" && git push origin $(git branch --show-current); }; f' -print_success "Alias Git configurés" - -# 5. Rendu exécutable des scripts si chemin standard -print_status "Configuration des permissions des scripts (si présents)..." -chmod +x scripts/auto-ssh-push.sh 2>/dev/null || true -chmod +x scripts/setup-ssh-ci.sh 2>/dev/null || true -print_success "Scripts rendus exécutables (si présents)" - -# 6. Résumé -echo "" -print_success "=== Configuration SSH terminée ===" - diff --git a/scripts/sdk_signer_sdk_client/scripts/setup-ssh-ci.sh b/scripts/sdk_signer_sdk_client/scripts/setup-ssh-ci.sh deleted file mode 100755 index 041c18c..0000000 --- a/scripts/sdk_signer_sdk_client/scripts/setup-ssh-ci.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Script de configuration SSH pour CI/CD (template Linux) -# Utilise automatiquement la clé SSH pour les opérations Git - -GITEA_HOST="${GITEA_HOST:-git.4nkweb.com}" - -echo "🔑 Configuration automatique de la clé SSH pour CI/CD..." - -if [ -n "${CI:-}" ]; then - echo "✅ Environnement CI détecté" - - if [ -n "${SSH_PRIVATE_KEY:-}" ]; then - echo "🔐 Configuration de la clé SSH privée..." - mkdir -p ~/.ssh && chmod 700 ~/.ssh - printf "%s" "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - - if [ -n "${SSH_PUBLIC_KEY:-}" ]; then - printf "%s" "$SSH_PUBLIC_KEY" > ~/.ssh/id_rsa.pub - chmod 644 ~/.ssh/id_rsa.pub - fi - - cat > ~/.ssh/config << EOF -Host ${GITEA_HOST} - HostName ${GITEA_HOST} - User git - IdentityFile ~/.ssh/id_rsa - StrictHostKeyChecking no - UserKnownHostsFile=/dev/null -EOF - chmod 600 ~/.ssh/config - - echo "🧪 Test SSH vers ${GITEA_HOST}..." - ssh -T git@"${GITEA_HOST}" 2>&1 || true - - git config --global url."git@${GITEA_HOST}:".insteadOf "https://${GITEA_HOST}/" - echo "✅ Configuration SSH terminée" - else - echo "⚠️ SSH_PRIVATE_KEY non défini, bascule HTTPS" - fi -else - echo "ℹ️ Environnement local détecté" - if [ -f ~/.ssh/id_rsa ] || [ -f ~/.ssh/id_ed25519 ]; then - echo "🔑 Clé SSH locale trouvée" - git config --global url."git@${GITEA_HOST}:".insteadOf "https://${GITEA_HOST}/" - echo "✅ Configuration SSH locale terminée" - else - echo "⚠️ Aucune clé SSH trouvée; configuration manuelle requise" - fi -fi - -echo "🎯 Configuration SSH CI/CD terminée" - diff --git a/scripts/sdk_signer_sdk_client/security/audit.sh b/scripts/sdk_signer_sdk_client/security/audit.sh deleted file mode 100755 index c705469..0000000 --- a/scripts/sdk_signer_sdk_client/security/audit.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -echo "[security-audit] démarrage" -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd)" -cd "$ROOT_DIR" - -rc=0 - -# 1) Audit Rust (si Cargo.toml présent et cargo disponible) -if command -v cargo >/dev/null 2>&1 && [ -f Cargo.toml ] || find . -maxdepth 2 -name Cargo.toml | grep -q . ; then - echo "[security-audit] cargo audit" - if ! cargo audit --deny warnings; then rc=1; fi || true -else - echo "[security-audit] pas de projet Rust (ok)" -fi - -# 2) Audit npm (si package.json présent) -if [ -f package.json ]; then - echo "[security-audit] npm audit --audit-level=moderate" - if ! npm audit --audit-level=moderate; then rc=1; fi || true -else - echo "[security-audit] pas de package.json (ok)" -fi - -# 3) Recherche de secrets grossiers -echo "[security-audit] scan secrets" -if grep -RIE "(?i)(api[_-]?key|secret|password|private[_-]?key)" --exclude-dir .git --exclude-dir node_modules --exclude-dir target --exclude "*.md" . >/dev/null 2>&1; then - echo "[security-audit] secrets potentiels détectés"; rc=1 -else - echo "[security-audit] aucun secret évident" -fi - -echo "[security-audit] terminé rc=$rc" -exit $rc - - diff --git a/scripts/sdk_signer_sdk_client/setup-ssh-ci.sh b/scripts/sdk_signer_sdk_client/setup-ssh-ci.sh deleted file mode 100755 index 7b9b63a..0000000 --- a/scripts/sdk_signer_sdk_client/setup-ssh-ci.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -# Script de configuration SSH pour CI/CD ihm_client -# Utilise automatiquement la clé SSH pour les opérations Git - -set -e - -echo "🔑 Configuration automatique de la clé SSH pour ihm_client CI/CD..." - -# Vérifier si on est dans un environnement CI -if [ -n "$CI" ]; then - echo "✅ Environnement CI détecté" - - # Configuration SSH pour Gitea Actions - if [ -n "$SSH_PRIVATE_KEY" ]; then - echo "🔐 Configuration de la clé SSH privée..." - - # Créer le répertoire SSH - mkdir -p ~/.ssh - chmod 700 ~/.ssh - - # Écrire la clé privée - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - - # Ajouter la clé publique correspondante (si disponible) - if [ -n "$SSH_PUBLIC_KEY" ]; then - echo "$SSH_PUBLIC_KEY" > ~/.ssh/id_rsa.pub - chmod 644 ~/.ssh/id_rsa.pub - fi - - # Configuration SSH pour git.4nkweb.com - cat > ~/.ssh/config << EOF -Host git.4nkweb.com - HostName git.4nkweb.com - User git - IdentityFile ~/.ssh/id_rsa - StrictHostKeyChecking no - UserKnownHostsFile=/dev/null -EOF - - chmod 600 ~/.ssh/config - - # Tester la connexion SSH - echo "🧪 Test de connexion SSH vers git.4nkweb.com..." - if ssh -T git@git.4nkweb.com 2>&1 | grep -q "Welcome"; then - echo "✅ Connexion SSH réussie" - else - echo "⚠️ Connexion SSH établie (message de bienvenue non détecté)" - fi - - # Configurer Git pour utiliser SSH - git config --global url."git@git.4nkweb.com:".insteadOf "https://git.4nkweb.com/" - - echo "✅ Configuration SSH terminée" - else - echo "⚠️ Variable SSH_PRIVATE_KEY non définie, utilisation de HTTPS" - fi -else - echo "ℹ️ Environnement local détecté" - - # Vérifier si une clé SSH existe - if [ -f ~/.ssh/id_rsa ]; then - echo "🔑 Clé SSH locale trouvée" - - # Configurer Git pour utiliser SSH localement - git config --global url."git@git.4nkweb.com:".insteadOf "https://git.4nkweb.com/" - - echo "✅ Configuration SSH locale terminée" - else - echo "⚠️ Aucune clé SSH trouvée, configuration manuelle requise" - echo "💡 Pour configurer SSH manuellement :" - echo " 1. Générer une clé SSH : ssh-keygen -t rsa -b 4096" - echo " 2. Ajouter la clé publique à votre compte Gitea" - echo " 3. Tester : ssh -T git@git.4nkweb.com" - fi -fi - -echo "🎯 Configuration SSH terminée pour ihm_client" - diff --git a/scripts/sdk_signer_sdk_client/utils/check_md024.ps1 b/scripts/sdk_signer_sdk_client/utils/check_md024.ps1 deleted file mode 100644 index 000c6d1..0000000 --- a/scripts/sdk_signer_sdk_client/utils/check_md024.ps1 +++ /dev/null @@ -1,47 +0,0 @@ -Param( - [string]$Root = "." -) - -$ErrorActionPreference = "Stop" - -$files = Get-ChildItem -Path $Root -Recurse -Filter *.md | Where-Object { $_.FullName -notmatch '\\archive\\' } -$had = $false -foreach ($f in $files) { - try { - $lines = Get-Content -LiteralPath $f.FullName -Encoding UTF8 -ErrorAction Stop - } catch { - Write-Warning ("Impossible de lire: {0} — {1}" -f $f.FullName, $_.Exception.Message) - continue - } - $map = @{} - $firstMap = @{} - $dups = @{} - for ($i = 0; $i -lt $lines.Count; $i++) { - $line = $lines[$i] - if ($line -match '^\s{0,3}#{1,6}\s+(.*)$') { - $t = $Matches[1].Trim() - $norm = ([regex]::Replace($t, '\s+', ' ')).ToLowerInvariant() - if ($map.ContainsKey($norm)) { - if (-not $dups.ContainsKey($norm)) { - $dups[$norm] = New-Object System.Collections.ArrayList - $firstMap[$norm] = $map[$norm] - } - [void]$dups[$norm].Add($i + 1) - } else { - $map[$norm] = $i + 1 - } - } - } - if ($dups.Keys.Count -gt 0) { - $had = $true - Write-Output "=== $($f.FullName) ===" - foreach ($k in $dups.Keys) { - $first = $firstMap[$k] - $others = ($dups[$k] -join ', ') - Write-Output ("Heading: '{0}' first@{1} duplicates@[{2}]" -f $k, $first, $others) - } - } -} -if (-not $had) { - Write-Output "No duplicate headings detected." -}