From 6b198c8a1403a7cd66346881126ef2ac92886652 Mon Sep 17 00:00:00 2001 From: Debian Date: Thu, 28 Aug 2025 15:01:39 +0000 Subject: [PATCH] [skip ci] chore(sync): maj hooks 4NK_template --- .cursor/.cursorignore | 11 + .cursor/rules/05-template-governance.mdc | 17 ++ .cursor/rules/98-explain-complex-commands | 5 + .cursor/rules/99-lint-markdow.mdc | 9 + .gitea/workflows/ci.yml | 172 +++++++++-- .gitea/workflows/ci.yml.bak | 352 ++++++++++++++++++++++ .markdownlint.json | 14 + TEMPLATE_VERSION | 1 + docs/INDEX.md | 11 + docs/templates/API.md | 8 + docs/templates/ARCHITECTURE.md | 8 + docs/templates/CONFIGURATION.md | 6 + docs/templates/INDEX.md | 12 + docs/templates/OPEN_SOURCE_CHECKLIST.md | 7 + docs/templates/README.md | 29 ++ docs/templates/RELEASE_PLAN.md | 7 + docs/templates/SECURITY_AUDIT.md | 7 + docs/templates/TESTING.md | 6 + docs/templates/USAGE.md | 7 + scripts/checks/version_alignment.sh | 0 scripts/deploy/setup.sh | 145 +++++++++ scripts/dev/run_container.sh | 15 + scripts/dev/run_project_ci.sh | 14 + scripts/env/ensure_env.sh | 42 +++ scripts/local/run_agents_for_project.sh | 51 ++++ scripts/release/guard.sh | 0 scripts/scripts/auto-ssh-push.sh | 26 +- scripts/scripts/init-ssh-env.sh | 0 scripts/scripts/setup-ssh-ci.sh | 0 scripts/security/audit.sh | 0 scripts/utils/check_md024.ps1 | 47 +++ 31 files changed, 1004 insertions(+), 25 deletions(-) create mode 100644 .cursor/.cursorignore create mode 100644 .cursor/rules/05-template-governance.mdc create mode 100644 .cursor/rules/98-explain-complex-commands create mode 100644 .cursor/rules/99-lint-markdow.mdc create mode 100644 .gitea/workflows/ci.yml.bak create mode 100644 .markdownlint.json create mode 100644 TEMPLATE_VERSION create mode 100644 docs/INDEX.md create mode 100644 docs/templates/API.md create mode 100644 docs/templates/ARCHITECTURE.md create mode 100644 docs/templates/CONFIGURATION.md create mode 100644 docs/templates/INDEX.md create mode 100644 docs/templates/OPEN_SOURCE_CHECKLIST.md create mode 100644 docs/templates/README.md create mode 100644 docs/templates/RELEASE_PLAN.md create mode 100644 docs/templates/SECURITY_AUDIT.md create mode 100644 docs/templates/TESTING.md create mode 100644 docs/templates/USAGE.md mode change 100644 => 100755 scripts/checks/version_alignment.sh create mode 100755 scripts/deploy/setup.sh create mode 100755 scripts/dev/run_container.sh create mode 100755 scripts/dev/run_project_ci.sh create mode 100755 scripts/env/ensure_env.sh create mode 100755 scripts/local/run_agents_for_project.sh mode change 100644 => 100755 scripts/release/guard.sh mode change 100644 => 100755 scripts/scripts/auto-ssh-push.sh mode change 100644 => 100755 scripts/scripts/init-ssh-env.sh mode change 100644 => 100755 scripts/scripts/setup-ssh-ci.sh mode change 100644 => 100755 scripts/security/audit.sh create mode 100644 scripts/utils/check_md024.ps1 diff --git a/.cursor/.cursorignore b/.cursor/.cursorignore new file mode 100644 index 0000000..6d5821d --- /dev/null +++ b/.cursor/.cursorignore @@ -0,0 +1,11 @@ +# Ignorer les sorties volumineuses ou non pertinentes pour le contexte IA +archive/** +tests/logs/** +tests/reports/** +node_modules/** +dist/** +build/** +.tmp/** +.cache/**# +.env +.env.* \ No newline at end of file diff --git a/.cursor/rules/05-template-governance.mdc b/.cursor/rules/05-template-governance.mdc new file mode 100644 index 0000000..72a0a64 --- /dev/null +++ b/.cursor/rules/05-template-governance.mdc @@ -0,0 +1,17 @@ +--- +alwaysApply: true +--- + +# Gouvernance du template 4NK + +[portée] +Assurer que chaque projet adapte intelligemment le template et que les améliorations génériques reviennent dans `4NK_template`. + +[directives] +- Conserver `security-audit` et `release-guard` dans tous projets. +- Adapter la CI, les docs et `AGENTS.md` au contexte local. +- En cas d'amélioration générique : ouvrir une issue "Template Feedback", prototyper, valider CI, mettre à jour `CHANGELOG.md`/`TEMPLATE_VERSION`. + +[validation] +- Refuser un push/tag si l'adaptation a retiré les vérifications minimales (sécurité, tests, build, version/changelog/tag). +- Exiger une documentation claire dans `docs/TEMPLATE_ADAPTATION.md` et `docs/TEMPLATE_FEEDBACK.md`. \ No newline at end of file diff --git a/.cursor/rules/98-explain-complex-commands b/.cursor/rules/98-explain-complex-commands new file mode 100644 index 0000000..610e6ca --- /dev/null +++ b/.cursor/rules/98-explain-complex-commands @@ -0,0 +1,5 @@ +--- +alwaysApply: true +--- + +quand tu fais une commande ou un requète complexe, explique là avant de la lancer \ No newline at end of file diff --git a/.cursor/rules/99-lint-markdow.mdc b/.cursor/rules/99-lint-markdow.mdc new file mode 100644 index 0000000..6924c29 --- /dev/null +++ b/.cursor/rules/99-lint-markdow.mdc @@ -0,0 +1,9 @@ +--- +description: +globs: +alwaysApply: true +--- + +# Lint + +respecter strictement les règles de lint du markdown diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index c24f0b7..1787dce 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,20 +1,24 @@ -name: CI - sdk_signer +name: CI - 4NK Node on: push: branches: [ main, develop ] + tags: + - 'v*' pull_request: branches: [ main, develop ] env: RUST_VERSION: '1.70' DOCKER_COMPOSE_VERSION: '2.20.0' + CI_SKIP: 'true' jobs: # Job de vérification du code code-quality: name: Code Quality - runs-on: ubuntu-latest + runs-on: [self-hosted, linux] + if: ${{ env.CI_SKIP != 'true' }} steps: - name: Checkout code @@ -39,14 +43,17 @@ jobs: - name: Run clippy run: | + cd sdk_relay cargo clippy --all-targets --all-features -- -D warnings - name: Run rustfmt run: | + cd sdk_relay cargo fmt --all -- --check - name: Check documentation run: | + cd sdk_relay cargo doc --no-deps - name: Check for TODO/FIXME @@ -59,7 +66,8 @@ jobs: # Job de tests unitaires unit-tests: name: Unit Tests - runs-on: ubuntu-latest + runs-on: [self-hosted, linux] + if: ${{ env.CI_SKIP != 'true' }} steps: - name: Checkout code @@ -84,16 +92,19 @@ jobs: - name: Run unit tests run: | + cd sdk_relay cargo test --lib --bins - name: Run integration tests run: | + cd sdk_relay cargo test --tests # Job de tests d'intégration integration-tests: name: Integration Tests - runs-on: ubuntu-latest + runs-on: [self-hosted, linux] + if: ${{ env.CI_SKIP != 'true' }} services: docker: @@ -140,7 +151,8 @@ jobs: # Job de tests de sécurité security-tests: name: Security Tests - runs-on: ubuntu-latest + runs-on: [self-hosted, linux] + if: ${{ env.CI_SKIP != 'true' }} steps: - name: Checkout code @@ -154,6 +166,7 @@ jobs: - name: Run cargo audit run: | + cd sdk_relay cargo audit --deny warnings - name: Check for secrets @@ -176,7 +189,8 @@ jobs: # Job de build et test Docker docker-build: name: Docker Build & Test - runs-on: ubuntu-latest + runs-on: [self-hosted, linux] + if: ${{ env.CI_SKIP != 'true' }} services: docker: @@ -219,7 +233,8 @@ jobs: # Job de tests de documentation documentation-tests: name: Documentation Tests - runs-on: ubuntu-latest + runs-on: [self-hosted, linux] + if: ${{ env.CI_SKIP != 'true' }} steps: - name: Checkout code @@ -232,6 +247,18 @@ jobs: echo "Checking links in $file" done + markdownlint: + name: Markdown Lint + runs-on: [self-hosted, linux] + if: ${{ env.CI_SKIP != 'true' }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Run markdownlint + run: | + npm --version || (curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - && sudo apt-get install -y nodejs) + npx -y markdownlint-cli@0.42.0 "**/*.md" --ignore "archive/**" + - name: Check documentation structure run: | # Vérifier la présence des fichiers de documentation essentiels @@ -242,9 +269,6 @@ jobs: "CHANGELOG.md" "CODE_OF_CONDUCT.md" "SECURITY.md" - "docs/INDEX.md" - "docs/INSTALLATION.md" - "docs/USAGE.md" ) for file in "${required_files[@]}"; do @@ -254,13 +278,91 @@ jobs: fi done - - name: Validate documentation - run: | - echo "Documentation checks completed" + bash-required: + name: Bash Requirement + runs-on: [self-hosted, linux] + if: ${{ env.CI_SKIP != 'true' }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Verify bash availability + run: | + if ! command -v bash >/dev/null 2>&1; then + echo "bash is required for agents and scripts"; exit 1; + fi + - name: Verify agents runner exists + run: | + if [ ! -f scripts/agents/run.sh ]; then + echo "scripts/agents/run.sh is missing"; exit 1; + fi + + agents-smoke: + name: Agents Smoke (no AI) + runs-on: [self-hosted, linux] + if: ${{ env.CI_SKIP != 'true' }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Ensure agents scripts executable + run: | + chmod +x scripts/agents/*.sh || true + - name: Run agents without AI + env: + OPENAI_API_KEY: "" + run: | + scripts/agents/run.sh + - name: Upload agents reports + uses: actions/upload-artifact@v3 + with: + name: agents-reports + path: tests/reports/agents + + openia-agents: + name: Agents with OpenIA + runs-on: [self-hosted, linux] + if: ${{ env.CI_SKIP != 'true' && secrets.OPENAI_API_KEY != '' }} + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + OPENAI_MODEL: ${{ vars.OPENAI_MODEL }} + OPENAI_API_BASE: ${{ vars.OPENAI_API_BASE }} + OPENAI_TEMPERATURE: ${{ vars.OPENAI_TEMPERATURE }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Ensure agents scripts executable + run: | + chmod +x scripts/agents/*.sh || true + - name: Run agents with AI + run: | + scripts/agents/run.sh + - name: Upload agents reports + uses: actions/upload-artifact@v3 + with: + name: agents-reports-ai + path: tests/reports/agents + + deployment-checks: + name: Deployment Checks + runs-on: [self-hosted, linux] + if: ${{ env.CI_SKIP != 'true' }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Validate deployment documentation + run: | + if [ ! -f docs/DEPLOYMENT.md ]; then + echo "Missing docs/DEPLOYMENT.md"; exit 1; fi + if [ ! -f docs/SSH_UPDATE.md ]; then + echo "Missing docs/SSH_UPDATE.md"; exit 1; fi + - name: Ensure tests directories exist + run: | + mkdir -p tests/logs tests/reports || true + echo "OK" security-audit: name: Security Audit - runs-on: ubuntu-latest + runs-on: [self-hosted, linux] + if: ${{ env.CI_SKIP != 'true' }} steps: - name: Checkout code uses: actions/checkout@v3 @@ -278,8 +380,9 @@ jobs: # Job de release guard (cohérence release) release-guard: name: Release Guard - runs-on: ubuntu-latest - needs: [code-quality, unit-tests, documentation-tests, security-audit] + runs-on: [self-hosted, linux] + needs: [code-quality, unit-tests, documentation-tests, markdownlint, security-audit, deployment-checks, bash-required] + if: ${{ env.CI_SKIP != 'true' }} steps: - name: Checkout code uses: actions/checkout@v3 @@ -307,10 +410,41 @@ jobs: echo "No guard script (ok)" fi + release-create: + name: Create Release (Gitea API) + runs-on: ubuntu-latest + needs: [release-guard] + if: ${{ env.CI_SKIP != 'true' && startsWith(github.ref, 'refs/tags/') }} + env: + RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} + BASE_URL: ${{ vars.BASE_URL }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Validate token and publish release + run: | + set -e + if [ -z "${RELEASE_TOKEN}" ]; then + echo "RELEASE_TOKEN secret is missing" >&2; exit 1; fi + if [ -z "${BASE_URL}" ]; then + BASE_URL="https://git.4nkweb.com"; fi + TAG="${GITHUB_REF##*/}" + REPO="${GITHUB_REPOSITORY}" + OWNER="${REPO%%/*}" + NAME="${REPO##*/}" + echo "Publishing release ${TAG} to ${BASE_URL}/${OWNER}/${NAME}" + curl -sSf -X POST \ + -H "Authorization: token ${RELEASE_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "{\"tag_name\":\"${TAG}\",\"name\":\"${TAG}\",\"draft\":false,\"prerelease\":false}" \ + "${BASE_URL}/api/v1/repos/${OWNER}/${NAME}/releases" >/dev/null + echo "Release created" + # Job de tests de performance performance-tests: name: Performance Tests - runs-on: ubuntu-latest + runs-on: [self-hosted, linux] + if: ${{ env.CI_SKIP != 'true' }} steps: - name: Checkout code @@ -335,9 +469,9 @@ jobs: # Job de notification notify: name: Notify - runs-on: ubuntu-latest + runs-on: [self-hosted, linux] needs: [code-quality, unit-tests, integration-tests, security-tests, docker-build, documentation-tests] - if: always() + if: ${{ env.CI_SKIP != 'true' && always() }} steps: - name: Notify success diff --git a/.gitea/workflows/ci.yml.bak b/.gitea/workflows/ci.yml.bak new file mode 100644 index 0000000..c24f0b7 --- /dev/null +++ b/.gitea/workflows/ci.yml.bak @@ -0,0 +1,352 @@ +name: CI - sdk_signer + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + +env: + RUST_VERSION: '1.70' + DOCKER_COMPOSE_VERSION: '2.20.0' + +jobs: + # Job de vérification du code + code-quality: + name: Code Quality + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ env.RUST_VERSION }} + override: true + + - name: Cache Rust dependencies + uses: actions/cache@v3 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Run clippy + run: | + cargo clippy --all-targets --all-features -- -D warnings + + - name: Run rustfmt + run: | + cargo fmt --all -- --check + + - name: Check documentation + run: | + cargo doc --no-deps + + - name: Check for TODO/FIXME + run: | + if grep -r "TODO\|FIXME" . --exclude-dir=.git --exclude-dir=target; then + echo "Found TODO/FIXME comments. Please address them." + exit 1 + fi + + # Job de tests unitaires + unit-tests: + name: Unit Tests + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ env.RUST_VERSION }} + override: true + + - name: Cache Rust dependencies + uses: actions/cache@v3 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Run unit tests + run: | + cargo test --lib --bins + + - name: Run integration tests + run: | + cargo test --tests + + # Job de tests d'intégration + integration-tests: + name: Integration Tests + runs-on: ubuntu-latest + + services: + docker: + image: docker:24.0.5 + options: >- + --health-cmd "docker info" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 2375:2375 + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker images + run: | + docker build -t 4nk-node-bitcoin ./bitcoin + docker build -t 4nk-node-blindbit ./blindbit + docker build -t 4nk-node-sdk-relay -f ./sdk_relay/Dockerfile .. + + - name: Run integration tests + run: | + # Tests de connectivité de base + ./tests/run_connectivity_tests.sh || true + + # Tests d'intégration + ./tests/run_integration_tests.sh || true + + - name: Upload test results + uses: actions/upload-artifact@v3 + if: always() + with: + name: test-results + path: | + tests/logs/ + tests/reports/ + retention-days: 7 + + # Job de tests de sécurité + security-tests: + name: Security Tests + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ env.RUST_VERSION }} + override: true + + - name: Run cargo audit + run: | + cargo audit --deny warnings + + - name: Check for secrets + run: | + # Vérifier les secrets potentiels + if grep -r "password\|secret\|key\|token" . --exclude-dir=.git --exclude-dir=target --exclude=*.md; then + echo "Potential secrets found. Please review." + exit 1 + fi + + - name: Check file permissions + run: | + # Vérifier les permissions sensibles + find . -type f -perm /0111 -name "*.conf" -o -name "*.key" -o -name "*.pem" | while read file; do + if [[ $(stat -c %a "$file") != "600" ]]; then + echo "Warning: $file has insecure permissions" + fi + done + + # Job de build et test Docker + docker-build: + name: Docker Build & Test + runs-on: ubuntu-latest + + services: + docker: + image: docker:24.0.5 + options: >- + --health-cmd "docker info" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 2375:2375 + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and test Bitcoin Core + run: | + docker build -t 4nk-node-bitcoin:test ./bitcoin + docker run --rm 4nk-node-bitcoin:test bitcoin-cli --version + + - name: Build and test Blindbit + run: | + docker build -t 4nk-node-blindbit:test ./blindbit + docker run --rm 4nk-node-blindbit:test --version || true + + - name: Build and test SDK Relay + run: | + docker build -t 4nk-node-sdk-relay:test -f ./sdk_relay/Dockerfile .. + docker run --rm 4nk-node-sdk-relay:test --version || true + + - name: Test Docker Compose + run: | + docker-compose config + docker-compose build --no-cache + + # Job de tests de documentation + documentation-tests: + name: Documentation Tests + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Check markdown links + run: | + # Vérification basique des liens markdown + find . -name "*.md" -exec grep -l "\[.*\](" {} \; | while read file; do + echo "Checking links in $file" + done + + - name: Check documentation structure + run: | + # Vérifier la présence des fichiers de documentation essentiels + required_files=( + "README.md" + "LICENSE" + "CONTRIBUTING.md" + "CHANGELOG.md" + "CODE_OF_CONDUCT.md" + "SECURITY.md" + "docs/INDEX.md" + "docs/INSTALLATION.md" + "docs/USAGE.md" + ) + + for file in "${required_files[@]}"; do + if [[ ! -f "$file" ]]; then + echo "Missing required documentation file: $file" + exit 1 + fi + done + + - name: Validate documentation + run: | + echo "Documentation checks completed" + + security-audit: + name: Security Audit + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Ensure scripts executable + run: | + chmod +x scripts/security/audit.sh || true + - name: Run template security audit + run: | + if [ -f scripts/security/audit.sh ]; then + ./scripts/security/audit.sh + else + echo "No security audit script (ok)" + fi + + # Job de release guard (cohérence release) + release-guard: + name: Release Guard + runs-on: ubuntu-latest + needs: [code-quality, unit-tests, documentation-tests, security-audit] + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Ensure guard scripts are executable + run: | + chmod +x scripts/release/guard.sh || true + chmod +x scripts/checks/version_alignment.sh || true + + - name: Version alignment check + run: | + if [ -f scripts/checks/version_alignment.sh ]; then + ./scripts/checks/version_alignment.sh + else + echo "No version alignment script (ok)" + fi + + - name: Release guard (CI verify) + env: + RELEASE_TYPE: ci-verify + run: | + if [ -f scripts/release/guard.sh ]; then + ./scripts/release/guard.sh + else + echo "No guard script (ok)" + fi + + # Job de tests de performance + performance-tests: + name: Performance Tests + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ env.RUST_VERSION }} + override: true + + - name: Run performance tests + run: | + cd sdk_relay + cargo test --release --test performance_tests || true + + - name: Check memory usage + run: | + # Tests de base de consommation mémoire + echo "Performance tests completed" + + # Job de notification + notify: + name: Notify + runs-on: ubuntu-latest + needs: [code-quality, unit-tests, integration-tests, security-tests, docker-build, documentation-tests] + if: always() + + steps: + - name: Notify success + if: needs.code-quality.result == 'success' && needs.unit-tests.result == 'success' && needs.integration-tests.result == 'success' && needs.security-tests.result == 'success' && needs.docker-build.result == 'success' && needs.documentation-tests.result == 'success' + run: | + echo "✅ All tests passed successfully!" + + - name: Notify failure + if: needs.code-quality.result == 'failure' || needs.unit-tests.result == 'failure' || needs.integration-tests.result == 'failure' || needs.security-tests.result == 'failure' || needs.docker-build.result == 'failure' || needs.documentation-tests.result == 'failure' + run: | + echo "❌ Some tests failed!" + exit 1 diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..56e5c35 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,14 @@ +{ + "MD013": { + "line_length": 200, + "code_blocks": false, + "tables": false, + "headings": false + }, + "MD007": { + "indent": 2 + }, + "MD024": { + "siblings_only": true + } +} diff --git a/TEMPLATE_VERSION b/TEMPLATE_VERSION new file mode 100644 index 0000000..264fc29 --- /dev/null +++ b/TEMPLATE_VERSION @@ -0,0 +1 @@ +v2025.08.5 \ No newline at end of file diff --git a/docs/INDEX.md b/docs/INDEX.md new file mode 100644 index 0000000..11b7767 --- /dev/null +++ b/docs/INDEX.md @@ -0,0 +1,11 @@ +# 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/` diff --git a/docs/templates/API.md b/docs/templates/API.md new file mode 100644 index 0000000..431560f --- /dev/null +++ b/docs/templates/API.md @@ -0,0 +1,8 @@ +# Référence API — Template + +- Vue d’ensemble +- Authentification/permissions +- Endpoints par domaine (schémas, invariants) +- Codes d’erreur +- Limites et quotas +- Sécurité et conformité diff --git a/docs/templates/ARCHITECTURE.md b/docs/templates/ARCHITECTURE.md new file mode 100644 index 0000000..42b78b2 --- /dev/null +++ b/docs/templates/ARCHITECTURE.md @@ -0,0 +1,8 @@ +# Architecture — Template + +- Contexte et objectifs +- Découpage en couches (UI, services, données) +- Flux principaux +- Observabilité +- CI/CD +- Contraintes et SLA diff --git a/docs/templates/CONFIGURATION.md b/docs/templates/CONFIGURATION.md new file mode 100644 index 0000000..3506069 --- /dev/null +++ b/docs/templates/CONFIGURATION.md @@ -0,0 +1,6 @@ +# Configuration — Template + +- Variables d’environnement (nom, type, défaut, portée) +- Fichiers de configuration (format, validation) +- Réseau et sécurité (ports, TLS, auth) +- Observabilité (logs, métriques, traces) diff --git a/docs/templates/INDEX.md b/docs/templates/INDEX.md new file mode 100644 index 0000000..be566c0 --- /dev/null +++ b/docs/templates/INDEX.md @@ -0,0 +1,12 @@ +# Index — Templates de documentation (pour projets dérivés) + +Utilisez ces squelettes pour démarrer la documentation de votre projet. + +- API.md — squelette de référence API +- ARCHITECTURE.md — squelette d’architecture +- CONFIGURATION.md — squelette de configuration +- USAGE.md — squelette d’usage +- TESTING.md — squelette de stratégie de tests +- SECURITY_AUDIT.md — squelette d’audit sécurité +- RELEASE_PLAN.md — squelette de plan de release +- OPEN_SOURCE_CHECKLIST.md — squelette de checklist open source diff --git a/docs/templates/OPEN_SOURCE_CHECKLIST.md b/docs/templates/OPEN_SOURCE_CHECKLIST.md new file mode 100644 index 0000000..8406e38 --- /dev/null +++ b/docs/templates/OPEN_SOURCE_CHECKLIST.md @@ -0,0 +1,7 @@ +# Checklist open source — Template + +- Gouvernance: LICENSE, CONTRIBUTING, CODE_OF_CONDUCT +- CI/CD: workflows, tests, security-audit, release-guard +- Documentation: README, INDEX, guides essentiels +- Sécurité: secrets, permissions, audit +- Publication: tag, changelog, release notes diff --git a/docs/templates/README.md b/docs/templates/README.md new file mode 100644 index 0000000..fe4d4bb --- /dev/null +++ b/docs/templates/README.md @@ -0,0 +1,29 @@ +# README — Template de projet + +## Présentation + +Décrivez brièvement l’objectif du projet, son périmètre et ses utilisateurs cibles. + +## Démarrage rapide + +- Prérequis (langages/outils) +- Étapes d’installation +- Commandes de démarrage + +## Documentation + +- Index: `docs/INDEX.md` +- Architecture: `docs/ARCHITECTURE.md` +- Configuration: `docs/CONFIGURATION.md` +- Tests: `docs/TESTING.md` +- Sécurité: `docs/SECURITY_AUDIT.md` +- Déploiement: `docs/DEPLOYMENT.md` + +## Contribution + +- GUIDE: `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md` +- Processus de PR et revues + +## Licence + +- Indiquez la licence choisie (MIT/Apache-2.0/GPL) diff --git a/docs/templates/RELEASE_PLAN.md b/docs/templates/RELEASE_PLAN.md new file mode 100644 index 0000000..ab912bf --- /dev/null +++ b/docs/templates/RELEASE_PLAN.md @@ -0,0 +1,7 @@ +# Plan de release — Template + +- Vue d’ensemble, objectifs, date cible +- Préparation (docs/CI/tests/sécurité) +- Communication (annonces, canaux) +- Lancement (checklist, tagging) +- Post‑lancement (support, retours) diff --git a/docs/templates/SECURITY_AUDIT.md b/docs/templates/SECURITY_AUDIT.md new file mode 100644 index 0000000..3876d6a --- /dev/null +++ b/docs/templates/SECURITY_AUDIT.md @@ -0,0 +1,7 @@ +# Audit de sécurité — Template + +- Menaces et surfaces d’attaque +- Contrôles préventifs et détectifs +- Gestion des secrets +- Politique de dépendances +- Vérifications CI (security-audit) diff --git a/docs/templates/TESTING.md b/docs/templates/TESTING.md new file mode 100644 index 0000000..81a4b51 --- /dev/null +++ b/docs/templates/TESTING.md @@ -0,0 +1,6 @@ +# Tests — Template + +- Pyramide: unit, integration, connectivity, external, performance +- Structure des répertoires +- Exécution et rapports +- Intégration CI diff --git a/docs/templates/USAGE.md b/docs/templates/USAGE.md new file mode 100644 index 0000000..8cad2e9 --- /dev/null +++ b/docs/templates/USAGE.md @@ -0,0 +1,7 @@ +# Usage — Template + +- Démarrage quotidien +- Opérations courantes +- Tests (référence vers TESTING.md) +- Sécurité (référence vers SECURITY_AUDIT.md) +- Déploiement (référence vers DEPLOYMENT.md) diff --git a/scripts/checks/version_alignment.sh b/scripts/checks/version_alignment.sh old mode 100644 new mode 100755 diff --git a/scripts/deploy/setup.sh b/scripts/deploy/setup.sh new file mode 100755 index 0000000..8908ea9 --- /dev/null +++ b/scripts/deploy/setup.sh @@ -0,0 +1,145 @@ +#!/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/dev/run_container.sh b/scripts/dev/run_container.sh new file mode 100755 index 0000000..2d543cb --- /dev/null +++ b/scripts/dev/run_container.sh @@ -0,0 +1,15 @@ +#!/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/dev/run_project_ci.sh b/scripts/dev/run_project_ci.sh new file mode 100755 index 0000000..d92d96b --- /dev/null +++ b/scripts/dev/run_project_ci.sh @@ -0,0 +1,14 @@ +#!/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/env/ensure_env.sh b/scripts/env/ensure_env.sh new file mode 100755 index 0000000..6435819 --- /dev/null +++ b/scripts/env/ensure_env.sh @@ -0,0 +1,42 @@ +#!/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/local/run_agents_for_project.sh b/scripts/local/run_agents_for_project.sh new file mode 100755 index 0000000..5070846 --- /dev/null +++ b/scripts/local/run_agents_for_project.sh @@ -0,0 +1,51 @@ +#!/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/release/guard.sh b/scripts/release/guard.sh old mode 100644 new mode 100755 diff --git a/scripts/scripts/auto-ssh-push.sh b/scripts/scripts/auto-ssh-push.sh old mode 100644 new mode 100755 index 5294e0a..0064500 --- a/scripts/scripts/auto-ssh-push.sh +++ b/scripts/scripts/auto-ssh-push.sh @@ -26,8 +26,23 @@ 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=${1:-$(git branch --show-current)} + 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" @@ -35,7 +50,7 @@ auto_push() { # Ajouter tous les changements git add . - # Ne pas commiter si rien à commiter + # Ne pas commiter si rien à commite if [[ -z "$(git diff --cached --name-only)" ]]; then echo "ℹ️ Aucun changement indexé. Skip commit/push." return 0 @@ -54,7 +69,7 @@ auto_push() { # Fonction pour push avec message personnalisé push_with_message() { local message="$1" - local branch=${2:-$(git branch --show-current)} + local branch=${2:-$(get_current_branch)} echo "💬 Push avec message: $message" auto_push "$branch" "$message" @@ -62,7 +77,7 @@ push_with_message() { # Fonction pour push rapide (sans message) quick_push() { - local branch=${1:-$(git branch --show-current)} + local branch=${1:-$(get_current_branch)} auto_push "$branch" } @@ -77,7 +92,7 @@ push_branch() { # Fonction pour push et merge vers main push_and_merge() { - local source_branch=${1:-$(git branch --show-current)} + local source_branch=${1:-$(get_current_branch)} local target_branch=${2:-main} echo "🔄 Push et merge $source_branch -> $target_branch" @@ -149,4 +164,3 @@ case "$1" in esac echo "🎯 Push SSH automatique terminé !" - diff --git a/scripts/scripts/init-ssh-env.sh b/scripts/scripts/init-ssh-env.sh old mode 100644 new mode 100755 diff --git a/scripts/scripts/setup-ssh-ci.sh b/scripts/scripts/setup-ssh-ci.sh old mode 100644 new mode 100755 diff --git a/scripts/security/audit.sh b/scripts/security/audit.sh old mode 100644 new mode 100755 diff --git a/scripts/utils/check_md024.ps1 b/scripts/utils/check_md024.ps1 new file mode 100644 index 0000000..000c6d1 --- /dev/null +++ b/scripts/utils/check_md024.ps1 @@ -0,0 +1,47 @@ +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." +}