{"id":31743186,"url":"https://github.com/jmousqueton/murail","last_synced_at":"2026-02-17T15:03:02.124Z","repository":{"id":315614016,"uuid":"1060141312","full_name":"JMousqueton/Murail","owner":"JMousqueton","description":"Plateforme de simulation de crise inspirée de l’exercice massifié REMPAR25 de l’ANSSI","archived":false,"fork":false,"pushed_at":"2025-12-16T18:54:46.000Z","size":10942,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-20T06:23:30.494Z","etag":null,"topics":["anssi","anssi-fr","crise","cybersecurite","exercise","murail","rempar","rempar25","simulation"],"latest_commit_sha":null,"homepage":"https://murail-demo.mousqueton.io","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JMousqueton.png","metadata":{"files":{"readme":"README-en.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-19T12:53:36.000Z","updated_at":"2025-12-19T18:52:44.000Z","dependencies_parsed_at":"2025-09-19T17:36:06.514Z","dependency_job_id":"fcc21656-b7c7-44bf-ac91-6caf0c657b59","html_url":"https://github.com/JMousqueton/Murail","commit_stats":null,"previous_names":["jmousqueton/rempar","jmousqueton/murail"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/JMousqueton/Murail","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JMousqueton%2FMurail","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JMousqueton%2FMurail/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JMousqueton%2FMurail/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JMousqueton%2FMurail/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JMousqueton","download_url":"https://codeload.github.com/JMousqueton/Murail/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JMousqueton%2FMurail/sbom","scorecard":{"id":1239770,"data":{"date":"2025-11-15T19:10:30Z","repo":{"name":"github.com/JMousqueton/Murail","commit":"5f84a6071b59832a5099b40ddb8a43abdc4a3849"},"scorecard":{"version":"v5.1.1","commit":"cd152cb6742c5b8f2f3d2b5193b41d9c50905198"},"score":4,"checks":[{"name":"CI-Tests","score":-1,"reason":"no pull request found","details":null,"documentation":{"short":"Determines if the project runs tests before pull requests are merged.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#ci-tests"}},{"name":"Maintained","score":0,"reason":"project was created in last 90 days. please review its contents carefully","details":["Warn: Repository was created in last 90 days."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#sast"}},{"name":"Token-Permissions","score":10,"reason":"GitHub workflow tokens follow principle of least privilege","details":["Info: topLevel permissions set to 'read-all': .github/workflows/scorecard.yml:18","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":8,"reason":"dependency not pinned by hash detected -- score normalized to 8","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scorecard.yml:76: update your workflow using https://app.stepsecurity.io/secureworkflow/JMousqueton/Murail/scorecard.yml/main?enable=pin","Info:   2 out of   3 GitHub-owned GitHubAction dependencies pinned","Info:   1 out of   1 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":5,"reason":"5 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2018-66 / GHSA-562c-5r94-xh97","Warn: Project is vulnerable to: PYSEC-2019-179 / GHSA-5wv5-4vpf-pj6m","Warn: Project is vulnerable to: PYSEC-2023-62 / GHSA-m2qf-hxjv-5gpq","Warn: Project is vulnerable to: PYSEC-2017-48 / GHSA-chqf-hx79-gxc6","Warn: Project is vulnerable to: PYSEC-2020-73"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#vulnerabilities"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#branch-protection"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#security-policy"}},{"name":"Dependency-Update-Tool","score":0,"reason":"no update tool detected","details":["Warn: no dependency update tool configurations found"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#dependency-update-tool"}},{"name":"Contributors","score":3,"reason":"project has 1 contributing companies or organizations -- score normalized to 3","details":["Info: found contributions from: computacenter"],"documentation":{"short":"Determines if the project has a set of contributors from multiple organizations (e.g., companies).","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#contributors"}}]},"last_synced_at":"2025-11-15T21:09:53.071Z","repository_id":315614016,"created_at":"2025-11-15T21:09:53.072Z","updated_at":"2025-11-15T21:09:53.072Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29548201,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-17T14:33:00.708Z","status":"ssl_error","status_checked_at":"2026-02-17T14:32:58.657Z","response_time":100,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anssi","anssi-fr","crise","cybersecurite","exercise","murail","rempar","rempar25","simulation"],"created_at":"2025-10-09T11:51:24.530Z","updated_at":"2026-02-17T15:03:02.118Z","avatar_url":"https://github.com/JMousqueton.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"➡️ [Lire cette documentation en français](README.md)\n\n# Mur@il\nCrisis simulation platform inspired by the **REMPAR25** exercise by **ANSSI**\n\n# Crisis Simulation – Exercise Inspired by REMPAR25\n\n## 📌 Context\n\nThis project was born from the **REMPAR25** cybersecurity exercise, a large-scale simulation organized by **ANSSI** in France in 2025.  \nIts purpose is to put teams in realistic conditions to test their responsiveness and coordination in case of a cyberattack or major incident.\n\nThe platform allows you to **simulate realistic communication channels** (social media feeds, internal messaging stimuli) driven by a scenario defined in an Excel file.  \nIt can be used for trainings, role-playing sessions, or crisis management exercises.\n\n---\n\n## 🎯 Project Objectives\n\n- Reproduce an immersive environment simulating:\n  - A **social network** similar to Twitter.\n  - An **internal messaging system** (webmail-like) with user roles (HR, Communication, Decision, etc.).\n- Provide participants with an easy-to-access environment usable directly in a web browser.\n- Allow trainers/facilitators to monitor the progress of the exercise:\n  - An **admin console** to load and monitor the scenario.\n  - An **animator view** to analyze the exercise in real time.\n\n---\n\n## ⚙️ Main Features\n\n### 🔑 Authentication\n- **Admin** access protected by password.\n- **Animator** access protected by a distinct password.\n- Role-based access for messaging (Communication, Decision, IT, HR, Legal/Finance, etc.).\n\n### 📊 Administration\n- Upload scenario Excel file (`chronogramme.xlsx`).\n- Upload social media Excel file (`PMS.xlsx`).\n- View past events and upcoming messages/tweets.\n- Monitor the total number of tweets and messages.\n\n### 🐦 Social Media\n- Feed simulating **Twitter**.\n- Displays tweets scheduled in the scenario.\n- Dynamic engagement (likes, retweets) evolves automatically.\n- Detection and display of trending **hashtags**.\n- Option to filter the timeline by hashtag.\n\n### ✉️ Internal Messaging\n- **Webmail** view with user role selection.\n- Messages appear over time depending on the selected role.\n- Includes an **\"All\" mode** for messages addressed to all roles.\n- Each user can mark a message as **\"Processed\"** (stored locally in browser, no impact on other users).\n\n### 🪄 Animator\n- Password-protected access.\n- Timeline displaying **messages only** (no tweets).\n- For each message:\n  - Stimulus ID highlighted (yellow badge).\n  - Delivery time.\n  - **Expected reaction** (🔎) and **Comment** (📝).\n- View to monitor the exercise in real time and evaluate team reactions.\n\n### 👁️ Observer\n- Password-protected access.\n- Timeline displaying **messages only** (no tweets).\n- For each message, the observer can note the crisis team's reaction with thumbs up 👍 or down 👎 and add a comment.\n- Information is stored locally in the browser.\n- Export in JSON or CSV format.\n\n---\n\n## 📂 Scenario File Structure (Excel)\n\nThe platform uses **two separate Excel files**:\n\n### 1. **Chronogramme** (messages and events)\nThe Excel file `chronogramme.xlsx` must contain at least the following columns:\n\n- `id` : unique stimulus identifier (for messages).\n- `horaire` : delivery time (format `HH:MM` or `HH:MM:SS`).\n- `type` : `message` or `decompte`.\n- `emetteur` : message author.\n- `destinataire` : recipient role(s) (or `tous` for broadcast). *Support for multi-recipient messages with line breaks.*\n- `stimuli` : message content.\n- `reaction attendue` *(optional)* : expected team response.\n- `commentaire` *(optional)* : note for the animator.\n- `livrable` *(optional)* : expected deliverable (press release, report, etc.).\n\n**Supported types:**\n- `message` : internal message sent to designated roles.\n- `decompte` : countdown window (real-time counter for the exercise).\n\n### 2. **PMS** (tweets) — *Optional, requires `ENABLE_PMS=true`*\nThe Excel file `pms.xlsx` must contain at least the following columns:\n\n- `horaire` : delivery time (format `HH:MM` or `HH:MM:SS`).\n- `emetteur` : tweet author (simulated Twitter account).\n- `stimuli` : tweet content.\n\n---\n\n## �� What's New (Latest Update)\n\n### Improved Architecture\n- **Separation of sources**: tweets and messages loadable from separate Excel files.\n- **Dynamic role extraction**: roles are automatically extracted from message recipients.\n- **Multi-recipient support**: a message can be addressed to multiple roles (with line breaks in CSV).\n\n### Administration Interface\n- Simplified interface with separate uploads for:\n  - **Chronogramme** (messages + countdowns)\n  - **PMS** (tweets) — optional, requires activation\n- Load status display for each module.\n\n### Timestamp Management\n- Better handling of Excel formats and timezones.\n- Automatic support for variable time formats (`HH:MM`, `HH:MM:SS`, etc.).\n\n### Technical Improvements\n- Pinned dependency versions (`requirements.txt`)\n- Improved locking mechanism (threading) for shared structures.\n- Complete i18n support with translations for new keys.\n- No-cache headers to prevent SSE caching issues.\n\n---\n\nComplete documentation explaining how the platform works and how to prepare Excel files is available here:  \n➡️ [Documentation/Documentation-en.md](Documentation/Documentation-en.md)\n\n---\n\n## 🚀 Installation\n\n### 1. Prerequisites\n- Python **3.9+**\n- Pip and virtualenv\n\n### 2. Local Installation\n```bash\ngit clone https://github.com/jmousqueton/murail.git\ncd murail\npython3 -m venv venv\nsource venv/bin/activate\npip install -r requirements.txt\n```\n\n**Dependencies** (recommended versions):\n- Flask==3.1.2\n- pandas==2.3.3\n- openpyxl==3.1.5\n- python-dateutil==2.9.0.post0\n- python-dotenv==1.2.1\n- Unidecode==1.4.0\n\n### 3. Configuration\n\nCopy the example configuration file and adapt it:\n```bash\ncp env.example .env\n```\n\nEdit the `.env` file and fill in the required variables. See [env.example](env.example) for a detailed description of each variable.\n\n**Main variables:**\n\n```env\n# Authentication (recommended: use different passwords)\nADMIN_PASSWORD=MyAdminPassword\nANIMATOR_PASSWORD=MyAnimatorPassword\nOBSERVER_PASSWORD=MyObserverPassword\n\n# Configuration\nAPP_ID=SIM-MURAIL\nFLASK_SECRET=my-long-secret-key                # Generate: python3 -c \"import secrets; print(secrets.token_hex(32))\"\nTZ=Europe/Paris                                # Timezone (e.g: Europe/Paris, UTC)\nLANG=en                                        # Default language (fr or en)\n\n# Scenario files\nCHRONOGRAMME_FILE=Sample/chronogramme.xlsx     # Messages and countdowns\nENABLE_PMS=true                                # Enable PMS module (tweets)\nPMS_FILE=Sample/pms.xlsx                       # Tweets (requires ENABLE_PMS=true)\n\n# Optional\nDEBUG=false                                    # Flask debug mode (do not enable in production)\nDEMO=false                                     # Demo mode (bypass auth for demonstration)\nTRACKING=                                      # Analytics code (e.g. Google Analytics)\nPORT=5000                                      # Listen port (default: 5000)\n```\n\n**For more details**, see [env.example](env.example) which contains explanations for each variable.\n\n### 4. Launch the Application\n```bash\npython app.py\n```\n\nThe application is then available at [http://localhost:5000](http://localhost:5000).\n\n---\n\n## 🐳 Docker Deployment\n\n### Option 1: Docker Compose (recommended)\n\nThe easiest way to deploy Murail:\n\n```bash\n# 1. Create a .env file with your configuration\ncp env.example .env\n# Edit .env and configure your passwords and settings\n\n# 2. Launch the application\ndocker-compose up -d\n\n# 3. View logs\ndocker-compose logs -f\n\n# 4. Stop the application\ndocker-compose down\n```\n\nThe application will be accessible at [http://localhost:5000](http://localhost:5000).\n\n### Option 2: Docker Only\n\n```bash\n# 1. Build the image\ndocker build -t murail:latest .\n\n# 2. Run the container\ndocker run -d \\\n  --name murail-app \\\n  -p 5000:5000 \\\n  -e ADMIN_PASSWORD=yourpassword \\\n  -e ANIMATOR_PASSWORD=yourpassword2 \\\n  -e OBSERVER_PASSWORD=yourpassword3 \\\n  -e FLASK_SECRET=$(python3 -c \"import secrets; print(secrets.token_hex(32))\") \\\n  -v $(pwd)/Sample:/app/Sample:ro \\\n  murail:latest\n```\n\n### Custom Scenarios with Docker\n\nTo use your own Excel files:\n\n```bash\n# Place your files in ./custom-scenarios/\ndocker-compose up -d\n\n# Or with docker run:\ndocker run -d \\\n  -p 5000:5000 \\\n  -v $(pwd)/custom-scenarios:/app/custom-scenarios:ro \\\n  -e CHRONOGRAMME_FILE=/app/custom-scenarios/my-scenario.xlsx \\\n  murail:latest\n```\n\n### Health Check\n\nCheck container health:\n\n```bash\n# Via Docker\ndocker inspect --format='{{.State.Health.Status}}' murail-app\n\n# Via HTTP\ncurl http://localhost:5000/health\n```\n\n### Production\n\nFor production deployment, consider:\n\n- Use a reverse proxy (nginx, Traefik)\n- Enable HTTPS with Let's Encrypt\n- Configure strong passwords\n- Disable `DEBUG=false` and `DEMO=false`\n- Limit network access with firewall rules\n\n---\n\n## 👥 Target Audience\n\n- **Crisis exercise organizers** (CISOs, IT Directors, trainers).\n- **Communication, Legal, HR, Finance, and Technical teams** during training.\n- **Animators** responsible for evaluating team reaction and coordination.\n\n---\n\n## Online Demo\n\nA demonstration instance is available at:  \n👉 [https://murail-demo.mousqueton.io](https://murail-demo.mousqueton.io)\n\nIn demo mode:\n\n- **Animator** access does not require a password.\n- **Observer** access does not require a password.\n- **Admin** access is not available.\n- Other features (Messaging, Social Media) remain accessible to test the scenario.\n- This mode is designed for discovery purposes only.\n\n---\n\n## 🚀 Todo\n\n- [ ] Add a **light/dark mode** (preference saved in browser)\n- [ ] Ability to publish custom tweets (limited to communications role)\n- [ ] Generate a PDF from **observer** notes\n\n---\n\n## 📜 License\n\nProject distributed under GNU license.  \n⚠️ This project is intended for **training and simulation purposes only**.\n\n---\n\n## 🙏 Acknowledgments\n\n- **ANSSI** for organizing **REMPAR25**, which inspired this platform.\n- All contributors who enrich large-scale cybersecurity exercises.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmousqueton%2Fmurail","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjmousqueton%2Fmurail","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmousqueton%2Fmurail/lists"}