mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-04-28 10:26:54 +02:00
Compare commits
8 Commits
2667f3c259
...
f21120e9f7
Author | SHA1 | Date | |
---|---|---|---|
f21120e9f7 | |||
8055c7b994 | |||
efad73415d | |||
c3988ce812 | |||
75a110fde9 | |||
8b0308589d | |||
9232db4ef7 | |||
c157e93011 |
@ -93,7 +93,7 @@ ansible-playbook -i /path/to/your/inventory/servers.tmp "$(pkgmgr path cymais)pl
|
||||
|
||||
---
|
||||
|
||||
## Using a Vault Password File
|
||||
## Using a Password File
|
||||
|
||||
To avoid entering your vault password interactively every time, use the `--vault-password-file` option:
|
||||
```bash
|
||||
|
54
07_SECURITY.md
Normal file
54
07_SECURITY.md
Normal file
@ -0,0 +1,54 @@
|
||||
# Security
|
||||
|
||||
CyMaIS is designed with security in mind. However, while following our guidelines can greatly improve your system’s security, no IT system can be 100% secure. Please report any vulnerabilities as soon as possible.
|
||||
|
||||
---
|
||||
|
||||
## For End Users
|
||||
|
||||
For optimal personal security, we **strongly recommend** the following:
|
||||
|
||||
- **Use a Password Manager**
|
||||
Use a reliable password manager such as [KeePass](https://keepass.info/) 🔐. (Learn more about [password managers](https://en.wikipedia.org/wiki/Password_manager) on Wikipedia.) KeePass is available for both smartphones and PCs, and it can automatically generate strong, random passwords.
|
||||
|
||||
- **Enable Two-Factor Authentication (2FA)**
|
||||
Always enable 2FA whenever possible. Many password managers (like KeePass) can generate [TOTP](https://en.wikipedia.org/wiki/Time-based_One-Time_Password) tokens, adding an extra layer of security even if your password is compromised.
|
||||
Synchronize your password database across devices using the [Nextcloud Client](https://nextcloud.com/) 📱💻.
|
||||
|
||||
- **Use Encrypted Systems**
|
||||
We recommend running CyMaIS only on systems with full disk encryption. For example, Linux distributions such as [Manjaro](https://manjaro.org/) (based on ArchLinux) with desktop environments like [GNOME](https://en.wikipedia.org/wiki/GNOME) provide excellent security. (Learn more about [disk encryption](https://en.wikipedia.org/wiki/Disk_encryption) on Wikipedia.)
|
||||
|
||||
- **Beware of Phishing and Social Engineering**
|
||||
Always verify email senders, avoid clicking on unknown links, and never share your passwords or 2FA codes with anyone. (Learn more about [Phishing](https://en.wikipedia.org/wiki/Phishing) and [Social Engineering](https://en.wikipedia.org/wiki/Social_engineering_(security)) on Wikipedia.)
|
||||
|
||||
Following these guidelines will significantly enhance your personal security—but remember, no system is completely immune to risk.
|
||||
|
||||
---
|
||||
|
||||
## For Administrators
|
||||
|
||||
Administrators have additional responsibilities to secure the entire system:
|
||||
|
||||
- **Deploy on an Encrypted Server**
|
||||
It is recommended to install CyMaIS on an encrypted server to prevent hosting providers from accessing end-user data. For a practical guide on setting up an encrypted server, refer to the [Hetzner Arch LUKS repository](https://github.com/kevinveenbirkenbach/hetzner-arch-luks) 🔐. (Learn more about [disk encryption](https://en.wikipedia.org/wiki/Disk_encryption) on Wikipedia.)
|
||||
|
||||
- **Centralized User Management & SSO**
|
||||
For robust authentication and central user management, set up CyMaIS using Keycloak and LDAP.
|
||||
This configuration enables centralized [Single Sign-On (SSO)](https://en.wikipedia.org/wiki/Single_sign-on) (SSO), simplifying user management and boosting security.
|
||||
|
||||
- **Enforce 2FA and Use a Password Manager**
|
||||
Administrators should also enforce [2FA](https://en.wikipedia.org/wiki/Multi-factor_authentication) and use a password manager with auto-generated passwords. We again recommend [KeePass](https://keepass.info/). The KeePass database can be stored securely in your Nextcloud instance and synchronized between devices.
|
||||
|
||||
- **Avoid Root Logins & Plaintext Passwords**
|
||||
CyMaIS forbids logging in via the root user or using simple passwords. Instead, an SSH key must be generated and transferred during system initialization. When executing commands as root, always use `sudo` (or, if necessary, `sudo su`—but only if you understand the risks). (More information on [SSH](https://en.wikipedia.org/wiki/Secure_Shell) and [sudo](https://en.wikipedia.org/wiki/Sudo) is available on Wikipedia.)
|
||||
|
||||
- **Manage Inventories Securely**
|
||||
Your inventories for running CyMaIS should be managed in a separate repository and secured with tools such as [Ansible Vault](https://en.wikipedia.org/wiki/Encryption) 🔒. Sensitive credentials must never be stored in plaintext; use a password file to secure these details.
|
||||
|
||||
- **Reporting Vulnerabilities**
|
||||
If you discover a security vulnerability in CyMaIS, please report it immediately. We encourage proactive vulnerability reporting so that issues can be addressed as quickly as possible. Contact our security team at [security@cymais.cloud](mailto:security@cymais.cloud)
|
||||
**DO NOT OPEN AN ISSUE.**
|
||||
|
||||
---
|
||||
|
||||
By following these guidelines, both end users and administrators can achieve a high degree of security. Stay vigilant, keep your systems updated, and report any suspicious activity. Remember: while we strive for maximum security, no system is completely infallible.
|
12
Makefile
Normal file
12
Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
.PHONY: install deinstall refresh
|
||||
|
||||
install:
|
||||
$(MAKE) -C sphinx html
|
||||
$(MAKE) -C sphinx install
|
||||
|
||||
deinstall:
|
||||
$(MAKE) -C sphinx clean
|
||||
|
||||
refresh:
|
||||
$(MAKE) -C sphinx clean
|
||||
$(MAKE) -C sphinx html
|
@ -20,7 +20,7 @@ Backup Remote to Local is a robust solution for retrieving backup data from remo
|
||||
- **Integration with Other Roles:** Works alongside roles like backup-directory-validator, cleanup-failed-docker-backups, systemd-timer, backups-provider, and system-maintenance-lock.
|
||||
- **Administrative Debugging:** Detailed debug instructions and administrative tasks are provided in a separate file.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
|
||||
- **Backup Scheme:**
|
||||

|
||||
|
@ -20,7 +20,7 @@ The purpose of this role is to enhance the security of your backup system by pro
|
||||
- **Sudo Configuration:** Grants passwordless sudo rights for rsync, enabling secure and automated backup transfers.
|
||||
- **Integration:** Supports seamless integration with your backup infrastructure by limiting the backup user's permissions to only the required commands.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
|
||||
For more details on how the role works and advanced configuration options, please see the related references below:
|
||||
- [Ansible Playbooks Lookups](https://docs.ansible.com/ansible/latest/user_guide/playbooks_lookups.html#id3)
|
||||
|
@ -23,5 +23,5 @@ The primary purpose of this role is to maintain optimal backup storage by automa
|
||||
- **Systemd Integration:** Configures a systemd service to run cleanup tasks.
|
||||
- **Dependency Integration:** Works in conjunction with related roles for comprehensive backup management.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://stackoverflow.com/questions/48929553/get-hard-disk-size-in-python
|
@ -21,6 +21,6 @@ The primary purpose of this role is to enable proper routing and connectivity fo
|
||||
- **NAT Support:** Configures the external interface for proper masquerading.
|
||||
- **Role Integration:** Depends on the [client-wireguard](../client-wireguard/README.md) role to ensure that WireGuard is properly configured before applying firewall rules.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://gist.github.com/insdavm/b1034635ab23b8839bf957aa406b5e39
|
||||
- https://wiki.debian.org/iptables
|
||||
|
@ -22,7 +22,7 @@ The primary purpose of this role is to configure WireGuard on a client by settin
|
||||
- **Administration Support:** For client key creation and further setup, please refer to the [Administration](./Administration.md) file.
|
||||
- **Modular Design:** Easily integrates with other WireGuard roles or network configuration roles.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
|
||||
- [WireGuard Documentation](https://www.wireguard.com/)
|
||||
- [ArchWiki: WireGuard](https://wiki.archlinux.org/index.php/WireGuard)
|
||||
|
@ -31,7 +31,7 @@ Variables are crucial in configuring your Akaunting setup. Ensure you set the fo
|
||||
- **Nginx Configuration**: Necessary steps to configure Nginx as a reverse proxy for Akaunting.
|
||||
- **Database and Runtime Environment**: Instructions on how to set up the `db.env` and `run.env` files for database and runtime configurations.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
For more details, visit the [Akaunting Docker Repository](https://github.com/akaunting/docker) and the [Akaunting Forums](https://akaunting.com/forum).
|
||||
|
||||
## Contribution and Feedback
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
This role allows the setup of [baserole](https://baserow.io/).
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
|
||||
It was created with the help of [Chat GPT-4](https://chat.openai.com/share/556c2d7f-6b6f-4256-a646-a50529554efc).
|
||||
|
||||
|
@ -6,7 +6,7 @@ Role to deploy [BigBlueButton](https://bigbluebutton.org/).
|
||||
## SSO
|
||||
- https://docs.bigbluebutton.org/greenlight/v3/external-authentication/
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://github.com/bigbluebutton/docker
|
||||
- https://docs.bigbluebutton.org/greenlight/gl-install.html#setting-bigbluebutton-credentials
|
||||
- https://goneuland.de/big-blue-button-mit-docker-und-traefik-installieren/
|
||||
|
@ -1,7 +1,7 @@
|
||||
# DRAFT role docker-bluesky
|
||||
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://therobbiedavis.com/selfhosting-bluesky-with-docker-and-swag/
|
||||
- Relevant for proxy configuration: https://cprimozic.net/notes/posts/notes-on-self-hosting-bluesky-pds-alongside-other-services/
|
||||
- https://github.com/bluesky-social/pds
|
||||
|
@ -13,7 +13,7 @@ Ensure you have the following:
|
||||
- A central MariaDB instance running
|
||||
- Necessary permissions to manage Docker and database configurations
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
|
||||
- [Friendica Docker Hub](https://hub.docker.com/_/friendica)
|
||||
- [Friendica Installation Docs](https://wiki.friendi.ca/docs/install)
|
||||
|
@ -2,5 +2,5 @@
|
||||
|
||||
This role doesn't work and needs to be implemented
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://docs.funkwhale.audio/installation/docker.html
|
@ -1,5 +1,5 @@
|
||||
# role docker-gitea
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- [Gitea LDAP integration](https://docs.gitea.com/usage/authentication)
|
||||
- [Gitea Alternatives](https://chatgpt.com/share/67a5f599-c9b0-800f-87fe-49a3b61263e6)
|
@ -33,7 +33,7 @@ Include this role in your Ansible playbooks and specify the necessary variables.
|
||||
|
||||
For a detailed walkthrough and explanation of this role, refer to the conversation at [ChatGPT Session Transcript](https://chat.openai.com/share/1b0147bf-d4de-4790-b8ed-c332aa4e3ce3).
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://ralph.blog.imixs.com/2019/06/09/running-gitlab-on-docker/
|
||||
|
||||
## Performance Optimation
|
||||
|
@ -13,7 +13,7 @@ The role integrates Keycloak with PostgreSQL as a database and supports operatio
|
||||
- Support for running behind a reverse proxy (e.g., NGINX).
|
||||
- Automatic creation and management of Docker Compose files.
|
||||
|
||||
## 📚 Other Resources 📚
|
||||
## Other Resources 📚
|
||||
|
||||
For more details about Keycloak, check out:
|
||||
- [Official Keycloak Documentation](https://www.keycloak.org/)
|
||||
|
@ -11,7 +11,7 @@ This role deploys the Listmonk application using Docker. Listmonk is a high perf
|
||||
- **docker-compose.yml**: Defines the Docker setup for Listmonk and its database.
|
||||
- **config.toml**: Contains the application settings including the database connection, admin credentials, and server settings.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- For detailed installation instructions and configuration options, visit the [Listmonk Installation Documentation](https://listmonk.app/docs/installation/).
|
||||
- You can also find more information on the [Listmonk GitHub Repository](https://github.com/knadh/listmonk/).
|
||||
|
||||
|
@ -7,7 +7,7 @@ This project provides a **Docker-based setup for Mastodon**, including full **OI
|
||||
|
||||
This README and some parts of the code were created with the assistance of ChatGPT. You can follow the discussion and evolution of this project in [this conversation](https://chatgpt.com/c/67a4e19b-3884-800f-9d45-621dda2a6572).
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- [Mastodon with Docker & Traefik](https://goneuland.de/mastodon-mit-docker-und-traefik-installieren/)
|
||||
- [Mastodon Configuration Guide](https://gist.github.com/TrillCyborg/84939cd4013ace9960031b803a0590c4)
|
||||
- [Check Website Availability](https://www.2daygeek.com/linux-command-check-website-is-up-down-alive/)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# role docker-mediawiki
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
This role was adapted to solve some deprecation message. Please test it before using productive. [See this conversation](https://chatgpt.com/share/6781487e-45fc-800f-a35e-e93f49448176).
|
||||
|
@ -1,4 +1,4 @@
|
||||
# role docker-moodle
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://github.com/bitnami/containers/tree/main/bitnami/moodle
|
@ -3,5 +3,5 @@
|
||||
## Credits 📝
|
||||
This README was created with the assistance of ChatGPT, based on a conversation held at this [link](https://chat.openai.com/share/83828f9a-b817-48d8-86ed-599f64850b4d). ChatGPT provided guidance on structuring this document and outlining the key components of the Docker MyBB role.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://github.com/mybb/docker
|
@ -157,7 +157,8 @@ SELECT * FROM `oc_appconfig` WHERE appid LIKE "%cospend%";
|
||||
SELECT * FROM `oc_migrations` WHERE app LIKE "%cospend%";
|
||||
```
|
||||
|
||||
# Identity and Access Management (IAM)
|
||||
# IAM
|
||||
IAM(Identity and Access Management) is setup via Keycloak and LDAP.
|
||||
|
||||
## OpenID Connect (OIDC) Support 🔐
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
# Docker Nextcloud Role 🚀
|
||||
# Nextcloud Server
|
||||
|
||||
This repository contains an Ansible role for deploying and managing [Nextcloud](https://nextcloud.com/) using [Docker](https://www.docker.com/). It covers configuration modifications, updates, backups, database management, and more. Additionally, OIDC (OpenID Connect) is supported (for example, via **Keycloak**).
|
||||
---
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
|
||||
- [Nextcloud Docker Example with Nginx Proxy, MariaDB, and FPM](https://github.com/nextcloud/docker/blob/master/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/docker-compose.yml)
|
||||
- [Nextcloud Upgrade via Docker by Goneuland](https://goneuland.de/nextcloud-upgrade-auf-neue-versionen-mittels-docker/)
|
||||
|
@ -1,7 +1,7 @@
|
||||
# docker peertube
|
||||
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://docs.joinpeertube.org/install-docker
|
||||
- https://github.com/Chocobozzz/PeerTube/issues/3091
|
||||
- [OIDC Plugin installation](https://chatgpt.com/c/67a4f448-4be8-800f-8639-4c15cb2fb44e)
|
@ -1,6 +1,6 @@
|
||||
# docker roulette-wheel
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://github.com/p-wojt/roulette-wheel
|
||||
- https://dev.to/ms314006/how-to-package-front-end-projects-into-docker-images-and-use-it-with-webpack-go3
|
||||
- https://stackoverflow.com/questions/53178820/dockerfile-to-run-nodejs-static-content-in-docker-container
|
||||
|
@ -1,5 +1,5 @@
|
||||
# role driver-epson-multiprinter
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://bernhardsteindl.at/epson-ecotank-et-3600-unter-arch-linux-einrichten/
|
||||
- http://download.ebz.epson.net/dsc/search/01/search/searchModule
|
||||
- https://aur.archlinux.org/packages/epson-inkjet-printer-escpr
|
||||
|
@ -12,7 +12,7 @@ The `main.yml` file in this role consists of tasks that automate the installatio
|
||||
|
||||
There are commented-out tasks for installing additional AUR packages, such as `aacskeys` and `libbdplus`, which can be enabled as per the user's requirements.
|
||||
|
||||
## 📚 Other Resources and Resources
|
||||
## Other Resources and Resources
|
||||
For more in-depth information and guidance on Blu-ray playback and software configuration, the following resources can be consulted:
|
||||
- [Arch Linux Wiki on Blu-ray](https://wiki.archlinux.org/title/Blu-ray#Using_aacskeys)
|
||||
- [Guide to Play Blu-ray with VLC](https://videobyte.de/play-blu-ray-with-vlc)
|
||||
|
@ -1,6 +1,6 @@
|
||||
# collection-blu-ray-player
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://wiki.archlinux.org/title/Blu-ray#Using_aacskeys
|
||||
- https://videobyte.de/play-blu-ray-with-vlc
|
||||
- https://archived.forum.manjaro.org/t/wie-kann-ich-bluray-uhd-abspielen/127396/12
|
||||
|
@ -24,7 +24,7 @@ The `pc-gnome` role includes several tasks for installing GNOME software, managi
|
||||
6. **Execute CLI GNOME Extension Manager Script**:
|
||||
- Runs the CLI GNOME Extension Manager script to manage GNOME extensions based on the `{{gnome_extensions}}` variable.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
For additional details on managing GNOME extensions via command line, visit [Ask Ubuntu](https://askubuntu.com/questions/1029376/how-do-i-enable-and-disable-gnome-extensions-from-the-command-line).
|
||||
|
||||
## Dependencies
|
||||
|
@ -28,6 +28,6 @@ For more detailed information on Jrnl and its functionalities, visit [Jrnl's off
|
||||
## Contributing
|
||||
Contributions to this role are welcome. Please adhere to standard coding conventions and best practices.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
|
||||
This role was created as part of a larger playbook. For more context on this role, you can refer to the related ChatGPT conversation [here](https://chat.openai.com/share/ae168ca0-5191-4bec-96a0-ffcfabca0024).
|
@ -9,7 +9,7 @@ The `main.yml` file in the `pc-video-conference` role includes tasks for setting
|
||||
1. **Install Video Conference Software**:
|
||||
- Utilizes the `kewlfft.aur.aur` module with `yay` as the helper to install `zoom`, a popular video conferencing application.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- As noted, the Microsoft Teams client is no longer natively supported on Linux. For more information and potential workarounds, you can visit the [AUR package page for Teams](https://aur.archlinux.org/packages/teams).
|
||||
|
||||
## Dependencies
|
||||
|
@ -21,6 +21,6 @@ The primary purpose of this role is to establish a secure SSH environment by dep
|
||||
- **Systemd Integration:** Automatically restarts the SSH service upon configuration changes.
|
||||
- **Security Enhancements:** Enforces secure defaults such as disabled root login and public key authentication.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://www.google.com/search?client=firefox-b-d&q=sshd+why+to+deactivate+pam
|
||||
- https://man7.org/linux/man-pages/man5/sshd_config.5.html
|
||||
|
@ -20,5 +20,5 @@ The primary purpose of this role is to streamline AUR package management on Arch
|
||||
- **User Creation:** Creates a dedicated `aur_builder` user.
|
||||
- **Sudo Configuration:** Grants passwordless sudo rights to `aur_builder` for pacman.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://github.com/kewlfft/ansible-aur
|
@ -19,6 +19,6 @@ The primary purpose of this role is to provide a comprehensive solution for auto
|
||||
- **Secure Notifications:** Integrates with systemd to trigger email alerts when services fail.
|
||||
- **Suite Integration:** Part of the `systemd-notifier` suite, offering a unified approach to service failure notifications.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
|
||||
This role was created as part of a conversation with OpenAI's ChatGPT and can be found [here](https://chat.openai.com/share/96e4ca12-0888-41c0-9cfc-29c0180f0dba).
|
||||
|
@ -19,6 +19,6 @@ The primary purpose of this role is to provide a robust solution for automated T
|
||||
- **Secure Notifications:** Leverages systemd to trigger alerts automatically when services fail.
|
||||
- **Suite Integration:** Part of the [`systemd-notifier` suite](../) which includes related roles such as [systemd-notifier-email](../systemd-notifier-email/README.md) and others.
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
|
||||
This role was developed as part of a conversation with OpenAI's ChatGPT and can be found [here](https://chat.openai.com/share/96e4ca12-0888-41c0-9cfc-29c0180f0dba).
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Update Debian-based Systems
|
||||
# Update apt
|
||||
|
||||
## Description
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Update-Pacman Role
|
||||
# Update Pacman
|
||||
|
||||
## Description
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Update-Yay Role
|
||||
# Update yay
|
||||
|
||||
## Description
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
systemctl status wg-quick@wg0.cymais.service
|
||||
```
|
||||
|
||||
## 📚 Other Resources
|
||||
## Other Resources
|
||||
- https://golb.hplar.ch/2019/01/expose-server-vpn.html
|
||||
- https://wiki.archlinux.org/index.php/WireGuard
|
||||
- https://wireguard.how/server/raspbian/
|
||||
|
25
sphinx/README.md
Normal file
25
sphinx/README.md
Normal file
@ -0,0 +1,25 @@
|
||||
# Documentation
|
||||
|
||||
CyMaIS uses [Sphinx](https://www.sphinx-doc.org/) to automatically generate its documentation and leverages the [Awesome Sphinx Theme](https://sphinxawesome.xyz/) for a sleek and responsive design. Enjoy a seamless, visually engaging experience 🚀✨.
|
||||
|
||||
## For Users
|
||||
|
||||
You can access the documentation [here](https://docs.cymais.cloud/) 🔗. Browse the latest updates and guides to get started.
|
||||
|
||||
## For Administrators
|
||||
|
||||
### Setup
|
||||
|
||||
#### On Localhost
|
||||
|
||||
To generate the documentation locally, run the following command:
|
||||
|
||||
```bash
|
||||
pkgmgr shell cymais -c "make refresh"
|
||||
```
|
||||
|
||||
This command cleans the previous build and generates the updated documentation. Once complete, you can view it at the output location (e.g., [templates/html/index.html](templates/html/index.html)) 👀💻.
|
||||
|
||||
#### On Server
|
||||
|
||||
In your inventory file, enable the **Sphinx** role. When activated, the documentation will be automatically generated and deployed under the **docs** subdomain of your CyMaIS instance. This ensures your documentation is always current and easily accessible 🔄🌐.
|
@ -1,72 +1,127 @@
|
||||
import os
|
||||
import re
|
||||
from sphinx.util import logging
|
||||
from .nav_utils import natural_sort_key, extract_headings_from_file, group_headings, sort_tree, MAX_HEADING_LEVEL, DEFAULT_MAX_NAV_DEPTH
|
||||
from .nav_utils import extract_headings_from_file, MAX_HEADING_LEVEL
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def collect_subfolder_tree(dir_path, base_url, current_depth, max_depth):
|
||||
def collect_folder_tree(dir_path, base_url):
|
||||
"""
|
||||
Recursively collects navigation items from subdirectories.
|
||||
For each subfolder, it looks for a candidate file (prefer "index.rst" then "README.md").
|
||||
Only subfolders with such a file will be included.
|
||||
If a candidate is found, the first level‑1 heading from that file is used as the title;
|
||||
if no heading is found, the folder name is used.
|
||||
The link is built pointing directly to the candidate file (by its base name) rather than the folder.
|
||||
Returns a list representing the subfolder tree.
|
||||
Recursively collects the folder tree starting from the given directory.
|
||||
|
||||
For each folder:
|
||||
- Hidden folders (names starting with a dot) are skipped.
|
||||
- A folder is processed only if it contains one of the representative files:
|
||||
index.rst, index.md, readme.md, or readme.rst.
|
||||
- The first heading of the representative file is used as the folder title.
|
||||
- The representative file is not listed as a file in the folder.
|
||||
- All other Markdown and reStructuredText files are listed without sub-headings,
|
||||
using their first heading as the file title.
|
||||
"""
|
||||
items = []
|
||||
# Skip hidden directories
|
||||
if os.path.basename(dir_path).startswith('.'):
|
||||
return None
|
||||
|
||||
# List all files in the current directory with .md or .rst extension
|
||||
files = [f for f in os.listdir(dir_path)
|
||||
if os.path.isfile(os.path.join(dir_path, f))
|
||||
and (f.endswith('.md') or f.endswith('.rst'))]
|
||||
|
||||
# Find representative file for folder title using index or readme
|
||||
rep_file = None
|
||||
for candidate in ['index.rst', 'index.md', 'readme.md', 'readme.rst']:
|
||||
for f in files:
|
||||
if f.lower() == candidate:
|
||||
rep_file = f
|
||||
break
|
||||
if rep_file:
|
||||
break
|
||||
|
||||
# Skip this folder if no representative file exists
|
||||
if not rep_file:
|
||||
return None
|
||||
|
||||
rep_path = os.path.join(dir_path, rep_file)
|
||||
headings = extract_headings_from_file(rep_path, max_level=MAX_HEADING_LEVEL)
|
||||
folder_title = headings[0]['text'] if headings else os.path.basename(dir_path)
|
||||
folder_link = os.path.join(base_url, os.path.splitext(rep_file)[0])
|
||||
|
||||
# Remove the representative file from the list to avoid duplication,
|
||||
# and filter out any additional "readme.md" or "index.rst" files.
|
||||
files.remove(rep_file)
|
||||
files = [f for f in files if f.lower() not in ['readme.md', 'index.rst']]
|
||||
|
||||
# Process the remaining files in the current directory
|
||||
file_items = []
|
||||
for file in sorted(files, key=lambda s: s.lower()):
|
||||
file_path = os.path.join(dir_path, file)
|
||||
file_headings = extract_headings_from_file(file_path, max_level=MAX_HEADING_LEVEL)
|
||||
file_title = file_headings[0]['text'] if file_headings else file
|
||||
file_base = os.path.splitext(file)[0]
|
||||
file_link = os.path.join(base_url, file_base)
|
||||
file_items.append({
|
||||
'level': 1,
|
||||
'text': file_title,
|
||||
'link': file_link,
|
||||
'anchor': '',
|
||||
'priority': 1,
|
||||
'filename': file
|
||||
})
|
||||
|
||||
# Process subdirectories (ignoring hidden ones)
|
||||
dir_items = []
|
||||
for item in sorted(os.listdir(dir_path), key=lambda s: s.lower()):
|
||||
full_path = os.path.join(dir_path, item)
|
||||
if os.path.isdir(full_path):
|
||||
candidate = None
|
||||
for cand in ['index.rst', 'README.md']:
|
||||
candidate_path = os.path.join(full_path, cand)
|
||||
if os.path.isfile(candidate_path):
|
||||
candidate = candidate_path
|
||||
break
|
||||
# Only include the folder if a candidate file was found.
|
||||
if candidate:
|
||||
headings = extract_headings_from_file(candidate, max_level=MAX_HEADING_LEVEL)
|
||||
title = headings[0]['text'] if headings else item
|
||||
# Use the candidate file's base name as link target.
|
||||
candidate_base = os.path.splitext(os.path.basename(candidate))[0]
|
||||
link = os.path.join(base_url, item, candidate_base)
|
||||
entry = {
|
||||
'level': 1,
|
||||
'text': title,
|
||||
'link': link,
|
||||
'anchor': '',
|
||||
'priority': 0,
|
||||
'filename': item
|
||||
if os.path.isdir(full_path) and not item.startswith('.'):
|
||||
subtree = collect_folder_tree(full_path, os.path.join(base_url, item))
|
||||
if subtree:
|
||||
dir_items.append(subtree)
|
||||
|
||||
# Combine files and subdirectories as children of the current folder
|
||||
children = file_items + dir_items
|
||||
|
||||
return {
|
||||
'text': folder_title,
|
||||
'link': folder_link,
|
||||
'children': children,
|
||||
'filename': os.path.basename(dir_path)
|
||||
}
|
||||
if current_depth < max_depth:
|
||||
children = collect_subfolder_tree(full_path, os.path.join(base_url, item), current_depth + 1, max_depth)
|
||||
if children:
|
||||
entry['children'] = children
|
||||
items.append(entry)
|
||||
return items
|
||||
|
||||
def mark_current(node, active):
|
||||
"""
|
||||
Recursively mark nodes as current if the active page (pagename)
|
||||
matches the node's link or is a descendant of it.
|
||||
|
||||
The function sets node['current'] = True if:
|
||||
- The node's link matches the active page exactly, or
|
||||
- The active page begins with the node's link plus a separator (indicating a child).
|
||||
Additionally, if any child node is current, the parent is marked as current.
|
||||
"""
|
||||
is_current = False
|
||||
node_link = node.get('link', '').rstrip('/')
|
||||
active = active.rstrip('/')
|
||||
if node_link and (active == node_link or active.startswith(node_link + '/')):
|
||||
is_current = True
|
||||
|
||||
# Recurse into children if they exist
|
||||
children = node.get('children', [])
|
||||
for child in children:
|
||||
if mark_current(child, active):
|
||||
is_current = True
|
||||
|
||||
node['current'] = is_current
|
||||
return is_current
|
||||
|
||||
def add_local_subfolders(app, pagename, templatename, context, doctree):
|
||||
"""
|
||||
Collects a tree of subfolder navigation items from the current directory.
|
||||
For each subfolder, the title is determined by scanning for a candidate file
|
||||
(prefer "index.rst" then "README.md") and extracting its first level‑1 heading,
|
||||
or using the folder name if none is found.
|
||||
The resulting tree is stored in context['local_subfolders'].
|
||||
Sets the 'local_subfolders' context variable with the entire folder tree
|
||||
starting from app.srcdir, and marks the tree with the 'current' flag up
|
||||
to the active page.
|
||||
"""
|
||||
srcdir = app.srcdir
|
||||
directory = os.path.dirname(pagename)
|
||||
abs_dir = os.path.join(srcdir, directory)
|
||||
if not os.path.isdir(abs_dir):
|
||||
logger.warning(f"Directory {abs_dir} not found for page {pagename}.")
|
||||
context['local_subfolders'] = []
|
||||
return
|
||||
|
||||
max_nav_depth = getattr(app.config, 'local_nav_max_depth', DEFAULT_MAX_NAV_DEPTH)
|
||||
subfolder_tree = collect_subfolder_tree(abs_dir, directory, current_depth=0, max_depth=max_nav_depth)
|
||||
sort_tree(subfolder_tree)
|
||||
context['local_subfolders'] = subfolder_tree
|
||||
root_dir = app.srcdir
|
||||
folder_tree = collect_folder_tree(root_dir, '')
|
||||
if folder_tree:
|
||||
mark_current(folder_tree, pagename)
|
||||
context['local_subfolders'] = [folder_tree] if folder_tree else []
|
||||
|
||||
def setup(app):
|
||||
app.connect('html-page-context', add_local_subfolders)
|
||||
|
@ -3,25 +3,16 @@ import re
|
||||
import yaml
|
||||
|
||||
DEFAULT_MAX_NAV_DEPTH = 4
|
||||
MAX_HEADING_LEVEL = 2
|
||||
MAX_HEADING_LEVEL = 0 # This can be overridden in your configuration
|
||||
|
||||
def natural_sort_key(text):
|
||||
"""
|
||||
Generate a key for natural (human-friendly) sorting,
|
||||
taking numeric parts into account.
|
||||
"""
|
||||
return [int(c) if c.isdigit() else c.lower() for c in re.split(r'(\d+)', text)]
|
||||
|
||||
def extract_headings_from_file(filepath, max_level=MAX_HEADING_LEVEL):
|
||||
"""
|
||||
Extract headings from a file.
|
||||
For Markdown (.md) files, looks for lines starting with '#' (up to max_level).
|
||||
For reStructuredText (.rst) files, looks for a line immediately followed by an underline.
|
||||
If no headings are found and the file is an index file while a README.md exists in the same folder,
|
||||
it will try to extract headings from the README.md instead.
|
||||
Returns a list of dictionaries with keys: 'level', 'text', and 'anchor' (if applicable).
|
||||
"""
|
||||
import os, re
|
||||
# If max_level is 0, set it to a very high value to effectively iterate infinitely
|
||||
if max_level == 0:
|
||||
max_level = 9999
|
||||
|
||||
headings = []
|
||||
ext = os.path.splitext(filepath)[1].lower()
|
||||
try:
|
||||
@ -34,7 +25,8 @@ def extract_headings_from_file(filepath, max_level=MAX_HEADING_LEVEL):
|
||||
continue
|
||||
if in_code_block:
|
||||
continue
|
||||
match = re.match(r'^(#{1,})\s+(.*)$', line)
|
||||
# Assuming markdown headings are defined with '#' characters
|
||||
match = re.match(r'^(#{1,})(.*?)$', line)
|
||||
if match:
|
||||
level = len(match.group(1))
|
||||
if level <= max_level:
|
||||
@ -53,9 +45,6 @@ def extract_headings_from_file(filepath, max_level=MAX_HEADING_LEVEL):
|
||||
headings.append({'level': level, 'text': heading_text, 'anchor': ''})
|
||||
except Exception as e:
|
||||
print(f"Warning: Error reading {filepath}: {e}")
|
||||
|
||||
# If no headings were found and the file is an index file,
|
||||
# then try to load headings from a README.md in the same folder.
|
||||
if not headings:
|
||||
base = os.path.basename(filepath).lower()
|
||||
if base == 'index.rst':
|
||||
@ -69,10 +58,6 @@ def extract_headings_from_file(filepath, max_level=MAX_HEADING_LEVEL):
|
||||
return headings
|
||||
|
||||
def group_headings(headings):
|
||||
"""
|
||||
Convert a flat list of headings into a tree structure based on their level.
|
||||
Each heading gets a 'children' list.
|
||||
"""
|
||||
tree = []
|
||||
stack = []
|
||||
for heading in headings:
|
||||
@ -87,13 +72,7 @@ def group_headings(headings):
|
||||
return tree
|
||||
|
||||
def sort_tree(tree):
|
||||
"""
|
||||
Sort a tree of navigation items, first by a 'priority' value (lower comes first)
|
||||
and then by a natural sort key based on the 'filename' field (or the 'text' field if no filename is provided).
|
||||
This ensures that 'index' and 'readme' (priority 0) always appear at the top.
|
||||
"""
|
||||
tree.sort(key=lambda x: (x.get('priority', 1), natural_sort_key(x.get('filename', x['text']))))
|
||||
for item in tree:
|
||||
if item.get('children'):
|
||||
sort_tree(item['children'])
|
||||
|
||||
|
@ -1,19 +1,21 @@
|
||||
{% macro render_headings(headings, level=1) %}
|
||||
<ul class="toctree-l{{ level }}" style="list-style: none; padding-left: 0;">
|
||||
<ul class="toctree-l{{ level }}" style="list-style: none; padding-left: 0; overflow-x: auto; white-space: nowrap;">
|
||||
{% for item in headings %}
|
||||
<li class="toctree-l{{ level }}{% if item.current %} current{% endif %}"
|
||||
{% if item.children %} x-data="{ expanded: false }" {% endif %}
|
||||
{% if item.children %}
|
||||
x-data="{ expanded: {{ 'true' if item.current else 'false' }} }"
|
||||
{% endif %}
|
||||
style="white-space: nowrap;">
|
||||
<div class="menu-item" style="display: inline-flex; align-items: center; justify-content: space-between; width: 100%; white-space: nowrap;">
|
||||
<!-- Link- und "Datei öffnen"-Bereich -->
|
||||
<!-- Link and file open section -->
|
||||
<div style="display: inline-flex; align-items: center; white-space: nowrap;">
|
||||
<a class="reference internal{% if item.children %} expandable{% endif %}"
|
||||
<a class="reference internal{% if item.children %} expandable{% endif %}{% if item.current %} current{% endif %}"
|
||||
href="{{ pathto(item.link).replace('#', '') }}{% if item.anchor %}#{{ item.anchor }}{% endif %}"
|
||||
style="text-decoration: none; white-space: nowrap;">
|
||||
{{ item.text }}
|
||||
</a>
|
||||
</div>
|
||||
<!-- Expand-Toggle-Button -->
|
||||
<!-- Expand-Toggle Button -->
|
||||
{% if item.children %}
|
||||
<button @click.prevent.stop="expanded = !expanded" type="button" class="toggle-button"
|
||||
style="background: none; border: none; padding: 0; margin-left: auto;">
|
||||
@ -37,13 +39,15 @@
|
||||
</ul>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% if local_md_headings or local_subfolders %}
|
||||
<div class="local-md-headings">
|
||||
<h3 class="toctree-l1">Index</h3>
|
||||
<h3>Overview</h3>
|
||||
<hr />
|
||||
<h4 class="toctree-l1">Current Index</h4>
|
||||
{% if local_md_headings %}
|
||||
{{ render_headings(local_md_headings) }}
|
||||
{% endif %}
|
||||
<h4 class="toctree-l1">File Explorer</h4>
|
||||
{% if local_subfolders %}
|
||||
{{ render_headings(local_subfolders) }}
|
||||
{% endif %}
|
||||
|
Loading…
x
Reference in New Issue
Block a user