Compare commits

...

5 Commits

37 changed files with 295 additions and 91 deletions

1
.gitignore vendored
View File

@@ -1,5 +1,4 @@
site.retry
*__pycache__
docs/*
venv
*.log

View File

@@ -1 +0,0 @@
# Developer Guide

4
08_DEVELOPER_GUIDE.rst Normal file
View File

@@ -0,0 +1,4 @@
Developer Guide
===============
To get an overview over all yaml files check out :doc:`docs/generated/yaml_index`.

View File

@@ -0,0 +1 @@
# Investor Informations

View File

@@ -5,10 +5,10 @@ Thank you for your interest in contributing to CyMaIS! We welcome contributions
## How to Contribute
There are several ways you can help:
- **Reporting Issues:** Found a bug or have a feature request? Please open an issue on our [GitHub Issues page](https://github.com/your-repo-link/issues) with a clear description and steps to reproduce the problem.
- **Reporting Issues:** Found a bug or have a feature request? Please open an issue on our [GitHub Issues page](https://github.com/kevinveenbirkenbach/cymais/issues) with a clear description and steps to reproduce the problem.
- **Code Contributions:** If you'd like to contribute code, fork the repository, create a new branch for your feature or bug fix, and submit a pull request. Ensure your code adheres to our coding style and includes tests where applicable.
- **Documentation:** Improving the documentation is a great way to contribute. Whether it's clarifying an existing section or adding new guides, your contributions help others understand and use CyMaIS effectively.
- **Financial Contributions:** If you appreciate CyMaIS and want to support its ongoing development, consider making a financial contribution. For more details, please see our [06_DONATE.md](06_DONATE.md) file.
- **Financial Contributions:** If you appreciate CyMaIS and want to support its ongoing development, consider making a financial contribution. For more details, please see our [donate options](11_DONATE.md).
## Code of Conduct

View File

@@ -1,12 +1,12 @@
.PHONY: install deinstall refresh
install:
$(MAKE) -C sphinx html $(MAKEFLAGS)
$(MAKE) -C sphinx install $(MAKEFLAGS)
$(MAKE) -C docs html $(MAKEFLAGS)
$(MAKE) -C docs install $(MAKEFLAGS)
deinstall:
$(MAKE) -C sphinx clean $(MAKEFLAGS)
$(MAKE) -C docs clean $(MAKEFLAGS)
refresh:
$(MAKE) -C sphinx clean $(MAKEFLAGS)
$(MAKE) -C sphinx html $(MAKEFLAGS)
$(MAKE) -C docs clean $(MAKEFLAGS)
$(MAKE) -C docs html $(MAKEFLAGS)

4
docs/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
assets/img/*
build/*
generated/*
!generated/.gitkeep

52
docs/Makefile Normal file
View File

@@ -0,0 +1,52 @@
# Minimal Makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment
SPHINXOPTS ?= -c .
SPHINXBUILD ?= sphinx-build
SPHINX_SOURCE_DIR ?= ../
SPHINX_BUILD_DIR ?= ./build
SPHINX_GENERATED_DIR = ./generated
.PHONY: help install copy-images apidoc remove-generated html Makefile
# Copy images before running any Sphinx command (except for help)
copy-images:
@echo "Copying images from ../assets/img/ to ./assets/img/..."
cp -vr ../assets/img/* ./assets/img/
# Generate reStructuredText files from Python modules using sphinx-apidoc
generate-apidoc:
@echo "Running sphinx-apidoc..."
sphinx-apidoc -f -o $(SPHINX_GENERATED_DIR)/modules $(SPHINX_SOURCE_DIR)
generate-yaml-index:
@echo "Generating YAML index..."
python generators/yaml_index.py --source-dir $(SPHINX_SOURCE_DIR) --output-file $(SPHINX_GENERATED_DIR)/yaml_index.rst
generate-ansible-roles:
@echo "Generating Ansible roles documentation..."
python generators/ansible_roles.py --roles-dir $(SPHINX_SOURCE_DIR)/roles --output-dir $(SPHINX_GENERATED_DIR)/roles
remove-generated:
@echo "Removing generated files..."
- find $(SPHINX_GENERATED_DIR)/ -type f ! -name '.gitkeep' -delete
# "help" target does not copy images
help:
@$(SPHINXBUILD) -M help "$(SPHINX_SOURCE_DIR)" "$(SPHINX_BUILD_DIR)" $(SPHINXOPTS) $(O)
html: copy-images generate-apidoc generate-ansible-roles generate-yaml-index
@$(SPHINXBUILD) -M html "$(SPHINX_SOURCE_DIR)" "$(SPHINX_BUILD_DIR)" $(SPHINXOPTS)
just-html:
@$(SPHINXBUILD) -M html "$(SPHINX_SOURCE_DIR)" "$(SPHINX_BUILD_DIR)" $(SPHINXOPTS)
clean: remove-generated
@$(SPHINXBUILD) -M clean "$(SPHINX_SOURCE_DIR)" "$(SPHINX_BUILD_DIR)" $(SPHINXOPTS) $(O)
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SPHINX_SOURCE_DIR)" "$(SPHINX_BUILD_DIR)" $(SPHINXOPTS) $(O)

56
docs/README.md Normal file
View File

@@ -0,0 +1,56 @@
# 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 performs the following steps:
- **Copy Images:** Before building, it copies the necessary image assets from `../assets/img/` to `./assets/img/` using the `copy-images` target.
- **Generate API Documentation:** It executes `sphinx-apidoc` (via the `apidoc` target) to automatically generate reStructuredText files for all Python modules. These files are stored under a designated directory (e.g., `modules`), ensuring that every Python file is included in the documentation.
- **Build HTML Documentation:** Finally, it builds the HTML documentation using `sphinx-build` (triggered by the `html` target).
Once complete, you can view the documentation at the output location (e.g., [templates/html/index.html](templates/html/index.html)) 👀💻.
#### On Server
The same commands can be used on the server to ensure that documentation is always up to date. Make sure the server environment is properly configured with the necessary Python packages and assets.
### Additional Commands
- **`make copy-images`:**
Copies image files from the assets directory into the local documentation directory. This ensures that all required images are available for the generated documentation.
- **`make apidoc`:**
Runs `sphinx-apidoc` to scan all Python files in the source directory and generate corresponding reStructuredText files. This automates the inclusion of all Python modules into the Sphinx documentation.
- **`make html`:**
This target depends on the `apidoc` target. It first generates the API documentation and then builds the HTML documentation using `sphinx-build`. This is the standard target to produce the final, viewable documentation.
- **`make refresh`:**
A custom target (typically defined as a combination of cleaning the previous build and then running `make html`) that ensures the documentation is regenerated from scratch with the latest changes.
### Debug
To debug and produce a log file, execute:
```bash
pkgmgr shell cymais -c "make refresh SPHINXOPTS='-v -c .' 2>&1 | tee debug.log"
```
This command increases the verbosity of the Sphinx build process and redirects all output to `debug.log`, which is useful for troubleshooting any issues during the documentation build.
```

View File

@@ -16,9 +16,20 @@ project = 'CyMaIS - Cyber Master Infrastructure Solution'
copyright = '2025, Kevin Veen-Birkenbach'
author = 'Kevin Veen-Birkenbach'
# Highlighting for Jinja
from sphinx.highlighting import lexers
from pygments.lexers.templates import DjangoLexer
lexers['jinja'] = DjangoLexer()
lexers['j2'] = DjangoLexer()
# -- General configuration ---------------------------------------------------
templates_path = ['templates']
exclude_patterns = ['docs', 'venv', 'venv/**']
exclude_patterns = [
'docs/build',
'venv',
'venv/**'
]
# -- Options for HTML output -------------------------------------------------
html_theme = 'sphinxawesome_theme'
@@ -41,19 +52,23 @@ html_theme_options = {
}
source_suffix = {
'.rst': 'restructuredtext',
'.md': 'markdown',
'.rst': 'restructuredtext',
'.yml': 'restructuredtext',
'.yaml': 'restructuredtext',
}
sys.path.insert(0, os.path.abspath('./extensions'))
extensions = [
'sphinx.ext.autosummary',
'sphinx.ext.autodoc',
#'sphinx.ext.autosummary',
'myst_parser',
'extensions.local_file_headings',
'extensions.local_subfolders',
'extensions.roles_overview',
'extensions.markdown_include',
'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
]
autosummary_generate = True
@@ -62,7 +77,29 @@ myst_enable_extensions = [
"colon_fence",
]
import logging
from docutils import nodes
logger = logging.getLogger(__name__)
def replace_assets_in_doctree(app, doctree, docname):
# Replace asset references in image nodes
for node in doctree.traverse(nodes.image):
if "assets/" in node['uri']:
new_uri = node['uri'].replace("assets/", "_static/")
node['uri'] = new_uri
logger.info("Replaced image URI in {}: {}".format(docname, new_uri))
# Replace asset references in raw HTML nodes
for node in doctree.traverse(nodes.raw):
if node.get('format') == 'html' and "assets/" in node.astext():
new_text = node.astext().replace("assets/", "_static/")
node.children = [nodes.raw('', new_text, format='html')]
logger.info("Replaced raw HTML assets in {}.".format(docname))
def setup(app):
app.connect("doctree-resolved", replace_assets_in_doctree)
python_domain = app.registry.domains.get('py')
if python_domain is not None:
directive = python_domain.directives.get('currentmodule')

View File

@@ -29,8 +29,8 @@ def add_local_file_headings(app, pagename, templatename, context, doctree):
files = [f for f in os.listdir(abs_dir) if f.endswith('.md') or f.endswith('.rst')]
# If an index file is present, remove any readme files (case-insensitive).
files_lower = [f.lower() for f in files]
if 'index.md' in files_lower or 'index.rst' in files_lower:
files = [f for f in files if f.lower() not in ['readme.md', 'readme.rst']]
if 'index.rst' in files_lower:
files = [f for f in files if f.lower() not in ['readme.md']]
file_items = []
for file in files:

View File

@@ -4,6 +4,8 @@ from .nav_utils import extract_headings_from_file, MAX_HEADING_LEVEL
logger = logging.getLogger(__name__)
CANDIDATES = ['index.rst', 'readme.md', 'main.rst']
def collect_folder_tree(dir_path, base_url):
"""
Recursively collects the folder tree starting from the given directory.
@@ -28,7 +30,7 @@ def collect_folder_tree(dir_path, base_url):
# 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 candidate in CANDIDATES:
for f in files:
if f.lower() == candidate:
rep_file = f
@@ -48,7 +50,7 @@ def collect_folder_tree(dir_path, base_url):
# 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']]
files = [f for f in files if f.lower() not in CANDIDATES]
# Process the remaining files in the current directory
file_items = []

0
docs/generated/.gitkeep Normal file
View File

View File

@@ -0,0 +1,42 @@
import os
import yaml
import argparse
def generate_ansible_roles_doc(roles_dir, output_dir):
"""Generates reStructuredText documentation for Ansible roles."""
if not os.path.exists(output_dir):
os.makedirs(output_dir)
for role in os.listdir(roles_dir):
role_path = os.path.join(roles_dir, role)
meta_file = os.path.join(role_path, "meta/main.yml")
readme_file = os.path.join(role_path, "README.md")
if os.path.exists(meta_file):
with open(meta_file, "r", encoding="utf-8") as f:
meta_data = yaml.safe_load(f)
role_doc = os.path.join(output_dir, f"{role}.rst")
with open(role_doc, "w", encoding="utf-8") as f:
f.write(f"{role.capitalize()} Role\n")
f.write("=" * (len(role) + 7) + "\n\n")
f.write(f"**Description:** {meta_data.get('description', 'No description available')}\n\n")
f.write("### Variables\n")
for key, value in meta_data.get('galaxy_info', {}).items():
f.write(f"- **{key}**: {value}\n")
if os.path.exists(readme_file):
f.write("\n### README\n")
with open(readme_file, "r", encoding="utf-8") as readme:
f.write("\n" + readme.read())
print(f"Ansible roles documentation has been generated in {output_dir}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate documentation for Ansible roles.")
parser.add_argument("--roles-dir", required=True, help="Directory containing Ansible roles.")
parser.add_argument("--output-dir", required=True, help="Directory where documentation will be saved.")
args = parser.parse_args()
generate_ansible_roles_doc(args.roles_dir, args.output_dir)

View File

@@ -0,0 +1,51 @@
import os
import argparse
import pathspec
def load_gitignore_patterns(source_dir):
"""Loads .gitignore patterns from the given source directory and returns a PathSpec object."""
gitignore_path = os.path.join(source_dir, ".gitignore")
if not os.path.exists(gitignore_path):
return pathspec.PathSpec.from_lines("gitwildmatch", [])
with open(gitignore_path, "r", encoding="utf-8") as f:
patterns = f.readlines()
return pathspec.PathSpec.from_lines("gitwildmatch", patterns)
def generate_yaml_index(source_dir, output_file):
"""Generates an index file listing all YAML files in the specified directory while respecting .gitignore rules."""
yaml_files = []
spec = load_gitignore_patterns(source_dir) # Load .gitignore rules
# Walk through the source directory and collect YAML files
for root, _, files in os.walk(source_dir):
for file in files:
file_path = os.path.relpath(os.path.join(root, file), start=source_dir)
if file.endswith(('.yml', '.yaml')) and not spec.match_file(file_path):
yaml_files.append(os.path.join(root, file))
# Create the output directory if it doesn't exist
os.makedirs(os.path.dirname(output_file), exist_ok=True)
# Write the YAML index to the output file
with open(output_file, "w", encoding="utf-8") as f:
f.write("YAML Files\n===========\n\n")
f.write("This document lists all `.yaml` and `.yml` files found in the specified directory, excluding ignored files.\n\n")
for file in sorted(yaml_files):
relative_file_path = os.path.relpath(file, start=os.path.dirname(output_file))
f.write(f".. literalinclude:: {relative_file_path}\n :language: yaml\n :linenos:\n\n")
print(f"YAML index has been generated at {output_file}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate an index for YAML files while respecting .gitignore.")
parser.add_argument("--source-dir", required=True, help="Directory containing YAML files.")
parser.add_argument("--output-file", required=True, help="Path to the output .rst file.")
args = parser.parse_args()
generate_yaml_index(args.source_dir, args.output_file)

7
docs/requirements.txt Normal file
View File

@@ -0,0 +1,7 @@
myst-parser
sphinx
sphinxawesome-theme
docutils
sphinx-jinja
sphinxcontrib-yaml
pathspec

5
docs/templates/logo.html vendored Normal file
View File

@@ -0,0 +1,5 @@
<div class="sidebar-logo" style="text-align: center; margin-bottom: 1em;">
<img src="{{ pathto("_static/img/logo.png", 1) }}" alt="Logo" style="max-width: 100%;">
</div>

View File

@@ -61,5 +61,5 @@
{% endif %}
</div>
{% endif %}
<script src="{{ pathto('assets/js/current-nav.js', 1) }}"></script>
<script src="{{ pathto('_static/js/current-nav.js', 1) }}"></script>

View File

@@ -350,7 +350,7 @@ defaults_applications:
flavor: "oidc_login" # Keeping on sociallogin because the other option is not implemented yet
matomo_tracking_enabled: "{{matomo_tracking_enabled_default}}" # Enables\Disables Matomo Tracking
css_enabled: "{{css_enabled_default}}" # Enables\Disables Global CSS Style
landingpage_iframe_enabled: "true" # Enables\Disables the possibility to embed this on landing page via iframe
landingpage_iframe_enabled: "{{landingpage_iframe_enabled_default}}" # Enables\Disables the possibility to embed this on landing page via iframe
database:
central_storage: True # Activate Central Database Storage
credentials:
@@ -632,7 +632,7 @@ defaults_applications:
portfolio:
database:
central_storage: False # Portfolio doesn't use any database
central_storage: False # Portfolio doesn't use any database
matomo_tracking_enabled: "{{matomo_tracking_enabled_default}}" # Enables\Disables Matomo Tracking
css_enabled: "{{css_enabled_default}}" # Enables\Disables Global CSS Style
landingpage_iframe_enabled: false # Doesn't make sense to load landingpage in landingpage
@@ -648,12 +648,12 @@ defaults_applications:
## Sphinx
sphinx:
version: "3.9-slim" # Use latest docker image
repository_sphinx_source: "https://github.com/kevinveenbirkenbach/cymais.git" # Repository address to pull the source repository from
sphinx_exec_dir_relative: "sphinx/" # The relative path to the sphinx Makefile folder from the source dir
matomo_tracking_enabled: "{{matomo_tracking_enabled_default}}" # Enables\Disables Matomo Tracking
css_enabled: "{{css_enabled_default}}" # Enables\Disables Global CSS Style
landingpage_iframe_enabled: true # Makes sense to make the documentary allways in iframe available
version: "3.9-slim" # Use latest docker image
repository_sphinx_source: "https://github.com/kevinveenbirkenbach/cymais.git" # Repository address to pull the source repository from
sphinx_exec_dir_relative: "docs/" # The relative path to the sphinx Makefile folder from the source dir
matomo_tracking_enabled: "{{matomo_tracking_enabled_default}}" # Enables\Disables Matomo Tracking
css_enabled: "{{css_enabled_default}}" # Enables\Disables Global CSS Style
landingpage_iframe_enabled: true # Makes sense to make the documentary allways in iframe available
## Taiga

View File

@@ -1,4 +1,4 @@
About
===============================
.. markdown-include:: README.md
.. markdown-include:: ./README.md

View File

@@ -1 +1,2 @@
# Jenkins
This role is deprecated. Needs to be reimplemented.

View File

@@ -1,3 +1,5 @@
# XMPP
This role needs to be implemented
- https://hub.docker.com/r/ejabberd/ecs/
- https://docs.ejabberd.im/CONTAINER/
- https://github.com/processone/docker-ejabberd

View File

@@ -1 +1,2 @@
# Nginx Https Server
This role loads the components to create an nginx server with https

1
sphinx/.gitignore vendored
View File

@@ -1 +0,0 @@
assets/img/*

View File

@@ -1,24 +0,0 @@
# Minimal Makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment
SPHINXOPTS ?= -c .
SPHINXBUILD ?= sphinx-build
SPHINX_SOURCE_DIR ?= ../
SPHINX_BUILD_DIR ?= ../docs
.PHONY: help install copy-images Makefile
# Copy images before running any Sphinx command (except for help)
copy-images:
@echo "Copying images from ../images/ to ./assets/img/..."
cp -r ../assets/img/* ./assets/img/
# "help" target does not copy images
help:
@$(SPHINXBUILD) -M help "$(SPHINX_SOURCE_DIR)" "$(SPHINX_BUILD_DIR)" $(SPHINXOPTS) $(O)
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SPHINX_SOURCE_DIR)" "$(SPHINX_BUILD_DIR)" $(SPHINXOPTS) $(O)

View File

@@ -1,30 +0,0 @@
# 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
### Debug
To debug and produce an .log execute:
```bash
pkgmgr shell cymais -c "make refresh SPHINXOPTS='-v -c .' 2>&1 | tee debug.log"
```

View File

@@ -1,4 +0,0 @@
myst-parser
sphinx
sphinxawesome-theme
docutils

View File

@@ -1,5 +0,0 @@
<div class="sidebar-logo" style="text-align: center; margin-bottom: 1em;">
<img src="{{ pathto("assets/img/logo_cymais.png", 1) }}" alt="Logo" style="max-width: 100%;">
</div>

1
tasks/README.md Normal file
View File

@@ -0,0 +1 @@
This folder contains the cross role tasks

View File

@@ -59,6 +59,10 @@
users: "{{users}}"
when: enable_debug | bool
- name: init root user
include_role:
name: user-root
- name: update device
include_role:
name: update