proxmox-srvbackup 1.6.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. proxmox_srvbackup-1.6.2/.devcontainer/devcontainer.json +22 -0
  2. proxmox_srvbackup-1.6.2/.devcontainer/settings.json +6 -0
  3. proxmox_srvbackup-1.6.2/.env.example +500 -0
  4. proxmox_srvbackup-1.6.2/.github/actions/extract-metadata/action.yml +92 -0
  5. proxmox_srvbackup-1.6.2/.github/dependabot.yml +22 -0
  6. proxmox_srvbackup-1.6.2/.github/workflows/codeql.yml +39 -0
  7. proxmox_srvbackup-1.6.2/.github/workflows/default_cicd_public.yml +318 -0
  8. proxmox_srvbackup-1.6.2/.github/workflows/default_release_public.yml +69 -0
  9. proxmox_srvbackup-1.6.2/.gitignore +189 -0
  10. proxmox_srvbackup-1.6.2/.qlty/qlty.toml +2 -0
  11. proxmox_srvbackup-1.6.2/.snyk +5 -0
  12. proxmox_srvbackup-1.6.2/CHANGELOG.md +324 -0
  13. proxmox_srvbackup-1.6.2/CONFIG.md +627 -0
  14. proxmox_srvbackup-1.6.2/CONTRIBUTING.md +49 -0
  15. proxmox_srvbackup-1.6.2/DEVELOPMENT.md +147 -0
  16. proxmox_srvbackup-1.6.2/INSTALL.md +193 -0
  17. proxmox_srvbackup-1.6.2/LICENSE +22 -0
  18. proxmox_srvbackup-1.6.2/Makefile +260 -0
  19. proxmox_srvbackup-1.6.2/PKG-INFO +692 -0
  20. proxmox_srvbackup-1.6.2/README.md +639 -0
  21. proxmox_srvbackup-1.6.2/SECURITY.md +37 -0
  22. proxmox_srvbackup-1.6.2/codecov.yml +27 -0
  23. proxmox_srvbackup-1.6.2/docs/adr/0001-memory-adapters-in-src.md +29 -0
  24. proxmox_srvbackup-1.6.2/docs/systemdesign/module_reference.md +351 -0
  25. proxmox_srvbackup-1.6.2/notebooks/Quickstart.ipynb +136 -0
  26. proxmox_srvbackup-1.6.2/pyproject.toml +265 -0
  27. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/__init__.py +29 -0
  28. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/__init__conf__.py +90 -0
  29. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/__main__.py +9 -0
  30. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/__init__.py +15 -0
  31. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/backup/__init__.py +22 -0
  32. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/backup/config_backup.py +99 -0
  33. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/backup/orchestrator.py +237 -0
  34. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/backup/retention.py +62 -0
  35. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/backup/setup_keys.py +160 -0
  36. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/backup/zfs_backup.py +178 -0
  37. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/__init__.py +66 -0
  38. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/commands/__init__.py +34 -0
  39. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/commands/backup.py +229 -0
  40. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/commands/config.py +334 -0
  41. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/commands/email/__init__.py +16 -0
  42. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/commands/email/_common.py +284 -0
  43. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/commands/email/send_email.py +140 -0
  44. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/commands/email/send_notification.py +99 -0
  45. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/commands/info.py +74 -0
  46. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/commands/logging.py +32 -0
  47. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/constants.py +28 -0
  48. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/context.py +155 -0
  49. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/exit_codes.py +52 -0
  50. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/main.py +120 -0
  51. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/py.typed +0 -0
  52. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/cli/root.py +166 -0
  53. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/__init__.py +25 -0
  54. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/defaultconfig.d/40-layered-config.toml +71 -0
  55. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/defaultconfig.d/50-mail.toml +222 -0
  56. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/defaultconfig.d/60-backup.toml +120 -0
  57. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/defaultconfig.d/90-logging.toml +432 -0
  58. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/defaultconfig.toml +46 -0
  59. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/deploy.py +118 -0
  60. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/display.py +56 -0
  61. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/loader.py +188 -0
  62. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/overrides.py +189 -0
  63. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/permissions.py +185 -0
  64. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/py.typed +0 -0
  65. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/systemd/proxmox-srvbackup-backup.service +10 -0
  66. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/config/systemd/proxmox-srvbackup-backup.timer +10 -0
  67. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/email/__init__.py +28 -0
  68. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/email/config.py +311 -0
  69. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/email/py.typed +0 -0
  70. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/email/sender.py +26 -0
  71. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/email/transport.py +274 -0
  72. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/email/validation.py +62 -0
  73. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/logging/__init__.py +13 -0
  74. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/logging/py.typed +0 -0
  75. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/logging/setup.py +132 -0
  76. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/memory/__init__.py +65 -0
  77. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/memory/backup.py +112 -0
  78. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/memory/config.py +62 -0
  79. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/memory/email.py +179 -0
  80. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/memory/logging.py +15 -0
  81. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/py.typed +0 -0
  82. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/ssh/__init__.py +16 -0
  83. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/adapters/ssh/commands.py +217 -0
  84. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/application/__init__.py +32 -0
  85. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/application/ports.py +233 -0
  86. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/application/py.typed +0 -0
  87. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/composition/__init__.py +160 -0
  88. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/composition/py.typed +0 -0
  89. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/domain/__init__.py +63 -0
  90. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/domain/behaviors.py +128 -0
  91. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/domain/enums.py +76 -0
  92. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/domain/errors.py +104 -0
  93. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/domain/models.py +122 -0
  94. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/domain/py.typed +0 -0
  95. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/entry.py +26 -0
  96. proxmox_srvbackup-1.6.2/src/proxmox_srvbackup/py.typed +0 -0
  97. proxmox_srvbackup-1.6.2/tests/conftest.py +668 -0
  98. proxmox_srvbackup-1.6.2/tests/test_backup_adapters.py +267 -0
  99. proxmox_srvbackup-1.6.2/tests/test_backup_per_server.py +353 -0
  100. proxmox_srvbackup-1.6.2/tests/test_behaviors.py +13 -0
  101. proxmox_srvbackup-1.6.2/tests/test_cache_effectiveness.py +155 -0
  102. proxmox_srvbackup-1.6.2/tests/test_cli_config.py +802 -0
  103. proxmox_srvbackup-1.6.2/tests/test_cli_core.py +222 -0
  104. proxmox_srvbackup-1.6.2/tests/test_cli_email.py +781 -0
  105. proxmox_srvbackup-1.6.2/tests/test_cli_env_file.py +181 -0
  106. proxmox_srvbackup-1.6.2/tests/test_cli_exit_codes.py +158 -0
  107. proxmox_srvbackup-1.6.2/tests/test_cli_overrides.py +164 -0
  108. proxmox_srvbackup-1.6.2/tests/test_cli_validation.py +132 -0
  109. proxmox_srvbackup-1.6.2/tests/test_config_overrides.py +327 -0
  110. proxmox_srvbackup-1.6.2/tests/test_deploy_permissions.py +524 -0
  111. proxmox_srvbackup-1.6.2/tests/test_display.py +121 -0
  112. proxmox_srvbackup-1.6.2/tests/test_enums.py +78 -0
  113. proxmox_srvbackup-1.6.2/tests/test_errors.py +39 -0
  114. proxmox_srvbackup-1.6.2/tests/test_logging.py +31 -0
  115. proxmox_srvbackup-1.6.2/tests/test_mail.py +1228 -0
  116. proxmox_srvbackup-1.6.2/tests/test_metadata.py +84 -0
  117. proxmox_srvbackup-1.6.2/tests/test_metadata_sync.py +80 -0
  118. proxmox_srvbackup-1.6.2/tests/test_module_entry.py +179 -0
  119. proxmox_srvbackup-1.6.2/tests/test_ports.py +188 -0
  120. proxmox_srvbackup-1.6.2/tests/test_property_email.py +284 -0
  121. proxmox_srvbackup-1.6.2/tests/test_property_overrides.py +165 -0
@@ -0,0 +1,22 @@
1
+ {
2
+ "image": "mcr.microsoft.com/devcontainers/python:3.13",
3
+
4
+ "postCreateCommand": "bash -lc '\nPY=/usr/local/bin/python;\n$PY -m pip install -U pip && \\\n$PY -m pip install ipykernel && \\\n$PY -m pip install -e . && \\\n# register kernel using this exact interpreter\n$PY -m ipykernel install --name=python3 --display-name=\"Python 3 (3.13)\" --user && \\\n# patch the notebook to point to the python3 kernelspec (VS Code will bind to /usr/local/bin/python)\n$PY - <<\"PY\"\nimport json, pathlib\np = pathlib.Path(\"notebooks/Quickstart.ipynb\")\nif p.exists():\n nb = json.loads(p.read_text(encoding=\"utf-8\"))\n md = nb.setdefault(\"metadata\", {})\n md[\"kernelspec\"] = {\n \"name\": \"python3\",\n \"display_name\": \"Python 3 (3.13)\",\n \"language\": \"python\"\n }\n md[\"language_info\"] = {\"name\": \"python\"}\n p.write_text(json.dumps(nb, ensure_ascii=False, indent=1), encoding=\"utf-8\")\n print(\"Pinned kernelspec to python3 in\", p)\nelse:\n print(\"Notebook not found:\", p)\nPY'\n",
5
+
6
+ "customizations": {
7
+ "vscode": {
8
+ "extensions": ["ms-toolsai.jupyter", "ms-python.python"],
9
+ "settings": {
10
+ "workbench.startupEditor": "none",
11
+ "jupyter.alwaysTrustNotebooks": true,
12
+ "jupyter.kernelPickerType": "OnlyRecommended",
13
+ "python.defaultInterpreterPath": "/usr/local/bin/python"
14
+ }
15
+ },
16
+ "codespaces": {
17
+ "openFiles": ["README.md"]
18
+ }
19
+ },
20
+
21
+ "postAttachCommand": "bash -lc 'if [ -f notebooks/Quickstart.ipynb ]; then code -r notebooks/Quickstart.ipynb; fi'"
22
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "python.defaultInterpreterPath": "/usr/local/bin/python3.13",
3
+ "jupyter.alwaysTrustNotebooks": true,
4
+ "jupyter.kernelPickerType": "OnlyRecommended",
5
+ "jupyter.askForKernelRestart": false
6
+ }
@@ -0,0 +1,500 @@
1
+ # Copy to .env and fill values as needed.
2
+
3
+ # Codecov upload token (required for private repos; optional for public repos)
4
+ CODECOV_TOKEN=
5
+
6
+ # PyPI API token for release workflow (.github/workflows/release.yml)
7
+ # Format: pypi-AgENdGVzdC5weXBpLm9yZwIk...
8
+ PYPI_API_TOKEN=
9
+
10
+ # Optional: GitHub token for API-limited tasks
11
+ GITHUB_TOKEN=
12
+
13
+
14
+ # ==============================================================================
15
+ # Backup Configuration
16
+ # ==============================================================================
17
+ #
18
+ # Naming Convention
19
+ # -----------------
20
+ # Format: <SECTION>__<KEY>=value (double underscore separates section from key)
21
+ #
22
+ # Full environment variable (outside .env):
23
+ # PROXMOX_SRVBACKUP___BACKUP__<KEY>=value
24
+ # (triple underscore separates the application slug from the section)
25
+
26
+ # Purpose: Base directory for storing all backup files
27
+ # Type: string (absolute path)
28
+ # Default: /mnt/zpool-ssd/px-node-backups
29
+ # Environment Variable: PROXMOX_SRVBACKUP___BACKUP__BACKUP_BASE_DIR=/mnt/zpool-ssd/px-node-backups
30
+ # .env: BACKUP__BACKUP_BASE_DIR=/mnt/zpool-ssd/px-node-backups
31
+ # BACKUP__BACKUP_BASE_DIR=/mnt/zpool-ssd/px-node-backups
32
+
33
+ # Purpose: Maximum number of concurrent backup threads
34
+ # Type: integer (> 0)
35
+ # Default: 4
36
+ # Environment Variable: PROXMOX_SRVBACKUP___BACKUP__MAX_PARALLEL=4
37
+ # .env: BACKUP__MAX_PARALLEL=4
38
+ # BACKUP__MAX_PARALLEL=4
39
+
40
+ # Purpose: Number of backup files to keep per server (oldest pruned)
41
+ # Type: integer (> 0)
42
+ # Default: 3
43
+ # Environment Variable: PROXMOX_SRVBACKUP___BACKUP__RETENTION_COUNT=3
44
+ # .env: BACKUP__RETENTION_COUNT=3
45
+ # BACKUP__RETENTION_COUNT=3
46
+
47
+ # Purpose: SSH user for remote server connections
48
+ # Type: string
49
+ # Default: root
50
+ # Environment Variable: PROXMOX_SRVBACKUP___BACKUP__SSH_USER=root
51
+ # .env: BACKUP__SSH_USER=root
52
+ # BACKUP__SSH_USER=root
53
+
54
+ # Purpose: SSH connection timeout in seconds
55
+ # Type: integer (> 0)
56
+ # Default: 15
57
+ # Environment Variable: PROXMOX_SRVBACKUP___BACKUP__SSH_CONNECT_TIMEOUT=15
58
+ # .env: BACKUP__SSH_CONNECT_TIMEOUT=15
59
+ # BACKUP__SSH_CONNECT_TIMEOUT=15
60
+
61
+ # Purpose: Directory for storing per-server SSH keypairs
62
+ # Type: string (absolute path)
63
+ # Default: /root/.ssh
64
+ # Environment Variable: PROXMOX_SRVBACKUP___BACKUP__SSH_KEY_DIR=/root/.ssh
65
+ # .env: BACKUP__SSH_KEY_DIR=/root/.ssh
66
+ # BACKUP__SSH_KEY_DIR=/root/.ssh
67
+
68
+ # Purpose: Filename prefix for per-server SSH keys
69
+ # Type: string
70
+ # Default: backup_pull
71
+ # Environment Variable: PROXMOX_SRVBACKUP___BACKUP__SSH_KEY_PREFIX=backup_pull
72
+ # .env: BACKUP__SSH_KEY_PREFIX=backup_pull
73
+ # BACKUP__SSH_KEY_PREFIX=backup_pull
74
+
75
+ # Purpose: Path to shared SSH key for initial key deployment (setup-keys command)
76
+ # Type: string (absolute path)
77
+ # Default: (empty, must be configured to use setup-keys)
78
+ # Environment Variable: PROXMOX_SRVBACKUP___BACKUP__BOOTSTRAP_KEY=/path/to/bootstrap.key
79
+ # .env: BACKUP__BOOTSTRAP_KEY=/path/to/bootstrap.key
80
+ # BACKUP__BOOTSTRAP_KEY=/path/to/bootstrap.key
81
+
82
+ # ==============================================================================
83
+ # Per-Server Backup Overrides
84
+ # ==============================================================================
85
+ #
86
+ # Per-server settings can be overridden via .env using the nested key format:
87
+ # BACKUP__SERVERS__<SERVER_NAME>__<KEY>=value
88
+ #
89
+ # Use UPPERCASE for the server name, and replace hyphens with underscores:
90
+ # Server "proxmox-fw" → BACKUP__SERVERS__PROXMOX_FW__...
91
+ #
92
+ # Full environment variable (outside .env):
93
+ # PROXMOX_SRVBACKUP___BACKUP__SERVERS__<SERVER_NAME>__<KEY>=value
94
+
95
+ # Purpose: FQDN or IP address for SSH connections to this server
96
+ # Type: string
97
+ # Default: (must be set in TOML or .env)
98
+ # .env: BACKUP__SERVERS__PROXMOX01__HOSTNAME=proxmox01.example.com
99
+ # BACKUP__SERVERS__PROXMOX01__HOSTNAME=proxmox01.example.com
100
+
101
+ # Purpose: ZFS pool name to snapshot on this server
102
+ # Type: string
103
+ # Default: rpool
104
+ # .env: BACKUP__SERVERS__PROXMOX01__ZFS_POOL=rpool
105
+ # BACKUP__SERVERS__PROXMOX01__ZFS_POOL=rpool
106
+
107
+ # Purpose: Whether this is the local backup server (skip SSH, run commands locally)
108
+ # Type: boolean (true/false)
109
+ # Default: false
110
+ # .env: BACKUP__SERVERS__PROXMOX_PBS__IS_LOCAL=true
111
+ # BACKUP__SERVERS__PROXMOX_PBS__IS_LOCAL=true
112
+
113
+ # Purpose: Whether to back up configuration files for this server
114
+ # Type: boolean (true/false)
115
+ # Default: true
116
+ # .env: BACKUP__SERVERS__PROXMOX01__BACKUP_CONFIGFILES=true
117
+ # BACKUP__SERVERS__PROXMOX01__BACKUP_CONFIGFILES=true
118
+
119
+ # Purpose: Whether to back up ZFS rpool snapshot for this server
120
+ # Type: boolean (true/false)
121
+ # Default: true
122
+ # Set to false for servers without a ZFS rpool (e.g. firewall appliances)
123
+ # .env: BACKUP__SERVERS__PROXMOX_FW__BACKUP_SNAPSHOT=false
124
+ # BACKUP__SERVERS__PROXMOX_FW__BACKUP_SNAPSHOT=false
125
+
126
+ # ==============================================================================
127
+ # Email Configuration (SMTP)
128
+ # ==============================================================================
129
+ #
130
+ # Naming Convention
131
+ # -----------------
132
+ # Format: <SECTION>__<KEY>=value (double underscore separates section from key)
133
+ # Lists use comma-separated values, booleans use true/false, floats use decimal notation.
134
+ #
135
+ # Full environment variable (outside .env):
136
+ # PROXMOX_SRVBACKUP___EMAIL__<KEY>=value
137
+ # (triple underscore separates the application slug from the section)
138
+
139
+ # Purpose: SMTP servers for email delivery, tried in order (host:port, comma-separated)
140
+ # Type: comma-separated strings in "host[:port]" format
141
+ # Default: (empty, must be configured to send email)
142
+ # Environment Variable: PROXMOX_SRVBACKUP___EMAIL__SMTP_HOSTS=smtp.example.com:587
143
+ # .env: EMAIL__SMTP_HOSTS=smtp.example.com:587
144
+ # EMAIL__SMTP_HOSTS=smtp.example.com:587
145
+
146
+ # Purpose: Default sender address for outgoing emails
147
+ # Type: string (valid email address)
148
+ # Default: (empty, must be configured or passed via --from)
149
+ # Environment Variable: PROXMOX_SRVBACKUP___EMAIL__FROM_ADDRESS=noreply@example.com
150
+ # .env: EMAIL__FROM_ADDRESS=noreply@example.com
151
+ # EMAIL__FROM_ADDRESS=noreply@example.com
152
+
153
+ # Purpose: Default recipient addresses (comma-separated)
154
+ # Type: comma-separated strings (valid email addresses)
155
+ # Default: (empty, must be configured or passed via --to)
156
+ # Environment Variable: PROXMOX_SRVBACKUP___EMAIL__RECIPIENTS=admin@example.com,ops@example.com
157
+ # .env: EMAIL__RECIPIENTS=admin@example.com,ops@example.com
158
+ # EMAIL__RECIPIENTS=admin@example.com,ops@example.com
159
+
160
+ # Purpose: SMTP authentication username
161
+ # Type: string
162
+ # Default: (empty, no authentication)
163
+ # Environment Variable: PROXMOX_SRVBACKUP___EMAIL__SMTP_USERNAME=noreply@example.com
164
+ # .env: EMAIL__SMTP_USERNAME=noreply@example.com
165
+ # EMAIL__SMTP_USERNAME=noreply@example.com
166
+
167
+ # Purpose: SMTP authentication password
168
+ # Type: string
169
+ # Default: (empty, no authentication)
170
+ # Environment Variable: PROXMOX_SRVBACKUP___EMAIL__SMTP_PASSWORD=your-app-password
171
+ # .env: EMAIL__SMTP_PASSWORD=your-app-password
172
+ # EMAIL__SMTP_PASSWORD=your-app-password
173
+
174
+ # Purpose: Enable STARTTLS negotiation before authentication
175
+ # Type: boolean (true/false)
176
+ # Default: true
177
+ # Environment Variable: PROXMOX_SRVBACKUP___EMAIL__USE_STARTTLS=true
178
+ # .env: EMAIL__USE_STARTTLS=true
179
+ # EMAIL__USE_STARTTLS=true
180
+
181
+ # Purpose: Socket timeout in seconds for SMTP operations
182
+ # Type: float
183
+ # Default: 30.0
184
+ # Environment Variable: PROXMOX_SRVBACKUP___EMAIL__TIMEOUT=30.0
185
+ # .env: EMAIL__TIMEOUT=30.0
186
+ # EMAIL__TIMEOUT=30.0
187
+
188
+ # Purpose: Raise FileNotFoundError when attachment files are missing
189
+ # Type: boolean (true/false)
190
+ # Default: true
191
+ # Environment Variable: PROXMOX_SRVBACKUP___EMAIL__RAISE_ON_MISSING_ATTACHMENTS=true
192
+ # .env: EMAIL__RAISE_ON_MISSING_ATTACHMENTS=true
193
+ # EMAIL__RAISE_ON_MISSING_ATTACHMENTS=true
194
+
195
+ # Purpose: Raise ValueError when recipient addresses are invalid
196
+ # Type: boolean (true/false)
197
+ # Default: true
198
+ # Environment Variable: PROXMOX_SRVBACKUP___EMAIL__RAISE_ON_INVALID_RECIPIENT=true
199
+ # .env: EMAIL__RAISE_ON_INVALID_RECIPIENT=true
200
+ # EMAIL__RAISE_ON_INVALID_RECIPIENT=true
201
+
202
+ # ==============================================================================
203
+ # Logging Configuration (lib_log_rich)
204
+ # ==============================================================================
205
+ #
206
+ # Naming Convention
207
+ # -----------------
208
+ # Format: <SECTION>__<KEY>=value (double underscore separates section from key)
209
+ # Strings need no quotes. Booleans: true/false. Floats: 1.0. Lists: comma-separated.
210
+ #
211
+ # Full environment variable (outside .env):
212
+ # PROXMOX_SRVBACKUP___LIB_LOG_RICH__<KEY>=value
213
+ #
214
+ # For nested subsections (e.g. payload_limits):
215
+ # PROXMOX_SRVBACKUP___LIB_LOG_RICH__PAYLOAD_LIMITS__<KEY>=value
216
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__<KEY>=value
217
+
218
+ # --- Core Identity ---
219
+
220
+ # Purpose: Logical service name recorded in each log event
221
+ # Type: string (non-empty)
222
+ # Default: "proxmox_srvbackup"
223
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__SERVICE=my-application
224
+ # .env: LIB_LOG_RICH__SERVICE=my-application
225
+ # LIB_LOG_RICH__SERVICE=my-application
226
+
227
+ # Purpose: Deployment environment label
228
+ # Type: string (non-empty)
229
+ # Default: "prod"
230
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__ENVIRONMENT=dev
231
+ # .env: LIB_LOG_RICH__ENVIRONMENT=dev
232
+ # LIB_LOG_RICH__ENVIRONMENT=dev
233
+
234
+ # --- Console Output ---
235
+
236
+ # Purpose: Minimum severity level emitted to Rich console
237
+ # Type: string (case-insensitive): "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
238
+ # Default: "INFO"
239
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__CONSOLE_LEVEL=DEBUG
240
+ # .env: LIB_LOG_RICH__CONSOLE_LEVEL=DEBUG
241
+ # LIB_LOG_RICH__CONSOLE_LEVEL=DEBUG
242
+
243
+ # Purpose: Where to send console output
244
+ # Type: string: "stdout", "stderr", "both", "custom", "none"
245
+ # Default: "stderr"
246
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__CONSOLE_STREAM=stderr
247
+ # .env: LIB_LOG_RICH__CONSOLE_STREAM=stderr
248
+ # LIB_LOG_RICH__CONSOLE_STREAM=stderr
249
+
250
+ # Purpose: Console line layout preset
251
+ # Type: string (case-insensitive): "full", "short", "full_loc", "short_loc"
252
+ # Default: "short_loc"
253
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__CONSOLE_FORMAT_PRESET=short_loc
254
+ # .env: LIB_LOG_RICH__CONSOLE_FORMAT_PRESET=short_loc
255
+ # LIB_LOG_RICH__CONSOLE_FORMAT_PRESET=short_loc
256
+
257
+ # Purpose: Custom console output template (overrides preset)
258
+ # Type: string (Python str.format template); empty = uses preset
259
+ # Default: (empty, uses preset)
260
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__CONSOLE_FORMAT_TEMPLATE={timestamp_trimmed_naive_loc} {level_code} {message}
261
+ # .env: LIB_LOG_RICH__CONSOLE_FORMAT_TEMPLATE={timestamp_trimmed_naive_loc} {level_code} {message}
262
+ # LIB_LOG_RICH__CONSOLE_FORMAT_TEMPLATE={timestamp_trimmed_naive_loc} {level_code} {message}
263
+
264
+ # Purpose: Rich color palette for console output
265
+ # Type: string: "classic", "dark", "neon", "pastel"
266
+ # Default: "dark"
267
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__CONSOLE_THEME=dark
268
+ # .env: LIB_LOG_RICH__CONSOLE_THEME=dark
269
+ # LIB_LOG_RICH__CONSOLE_THEME=dark
270
+
271
+ # Purpose: Override Rich styles per severity level (comma-separated LEVEL=style pairs)
272
+ # Type: comma-separated LEVEL=style pairs
273
+ # Default: (empty, uses theme defaults)
274
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__CONSOLE_STYLES=DEBUG=dim,ERROR=bold red
275
+ # .env: LIB_LOG_RICH__CONSOLE_STYLES=DEBUG=dim,ERROR=bold red
276
+ # LIB_LOG_RICH__CONSOLE_STYLES=DEBUG=dim,ERROR=bold red
277
+
278
+ # Purpose: Force ANSI color output even when stderr is not a TTY
279
+ # Type: boolean (true/false)
280
+ # Default: false
281
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__FORCE_COLOR=true
282
+ # .env: LIB_LOG_RICH__FORCE_COLOR=true
283
+ # LIB_LOG_RICH__FORCE_COLOR=true
284
+
285
+ # Purpose: Disable color output entirely (overrides force_color)
286
+ # Type: boolean (true/false)
287
+ # Default: false
288
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__NO_COLOR=false
289
+ # .env: LIB_LOG_RICH__NO_COLOR=false
290
+ # LIB_LOG_RICH__NO_COLOR=false
291
+
292
+ # --- Backend Adapters ---
293
+
294
+ # Purpose: Minimum severity threshold for journald and Windows Event Log
295
+ # Type: string (case-insensitive): "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
296
+ # Default: "WARNING"
297
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__BACKEND_LEVEL=WARNING
298
+ # .env: LIB_LOG_RICH__BACKEND_LEVEL=WARNING
299
+ # LIB_LOG_RICH__BACKEND_LEVEL=WARNING
300
+
301
+ # Purpose: Enable systemd journald adapter (Linux only; requires python3-systemd)
302
+ # Type: boolean (true/false)
303
+ # Default: false
304
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__ENABLE_JOURNALD=true
305
+ # .env: LIB_LOG_RICH__ENABLE_JOURNALD=true
306
+ # LIB_LOG_RICH__ENABLE_JOURNALD=true
307
+
308
+ # Purpose: Enable Windows Event Log adapter (Windows only)
309
+ # Type: boolean (true/false)
310
+ # Default: false
311
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__ENABLE_EVENTLOG=false
312
+ # .env: LIB_LOG_RICH__ENABLE_EVENTLOG=false
313
+ # LIB_LOG_RICH__ENABLE_EVENTLOG=false
314
+
315
+ # --- Graylog / GELF ---
316
+
317
+ # Purpose: Enable Graylog adapter for centralized logging
318
+ # Type: boolean (true/false)
319
+ # Default: false
320
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__ENABLE_GRAYLOG=true
321
+ # .env: LIB_LOG_RICH__ENABLE_GRAYLOG=true
322
+ # LIB_LOG_RICH__ENABLE_GRAYLOG=true
323
+
324
+ # Purpose: Graylog server address (host:port)
325
+ # Type: string "host:port"
326
+ # Default: (none, must be configured to enable Graylog)
327
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__GRAYLOG_ENDPOINT=graylog.example.com:12201
328
+ # .env: LIB_LOG_RICH__GRAYLOG_ENDPOINT=graylog.example.com:12201
329
+ # LIB_LOG_RICH__GRAYLOG_ENDPOINT=graylog.example.com:12201
330
+
331
+ # Purpose: Transport protocol for Graylog (tcp, udp); TLS only supported with tcp
332
+ # Type: string: "tcp", "udp"
333
+ # Default: "tcp"
334
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__GRAYLOG_PROTOCOL=tcp
335
+ # .env: LIB_LOG_RICH__GRAYLOG_PROTOCOL=tcp
336
+ # LIB_LOG_RICH__GRAYLOG_PROTOCOL=tcp
337
+
338
+ # Purpose: Wrap Graylog TCP connection in TLS
339
+ # Type: boolean (true/false)
340
+ # Default: false
341
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__GRAYLOG_TLS=true
342
+ # .env: LIB_LOG_RICH__GRAYLOG_TLS=true
343
+ # LIB_LOG_RICH__GRAYLOG_TLS=true
344
+
345
+ # Purpose: Minimum severity level sent to Graylog
346
+ # Type: string (case-insensitive): "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
347
+ # Default: "WARNING"
348
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__GRAYLOG_LEVEL=WARNING
349
+ # .env: LIB_LOG_RICH__GRAYLOG_LEVEL=WARNING
350
+ # LIB_LOG_RICH__GRAYLOG_LEVEL=WARNING
351
+
352
+ # --- Queue Settings ---
353
+
354
+ # Purpose: Route log events through background queue worker (false = synchronous, blocks on I/O)
355
+ # Type: boolean (true/false)
356
+ # Default: true
357
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__QUEUE_ENABLED=true
358
+ # .env: LIB_LOG_RICH__QUEUE_ENABLED=true
359
+ # LIB_LOG_RICH__QUEUE_ENABLED=true
360
+
361
+ # Purpose: Maximum pending events before queue full policy applies
362
+ # Type: integer (> 0)
363
+ # Default: 2048
364
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__QUEUE_MAXSIZE=2048
365
+ # .env: LIB_LOG_RICH__QUEUE_MAXSIZE=2048
366
+ # LIB_LOG_RICH__QUEUE_MAXSIZE=2048
367
+
368
+ # Purpose: Behavior when queue is full
369
+ # Type: string: "block" (wait for space), "drop" (discard events)
370
+ # Default: "block"
371
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__QUEUE_FULL_POLICY=block
372
+ # .env: LIB_LOG_RICH__QUEUE_FULL_POLICY=block
373
+ # LIB_LOG_RICH__QUEUE_FULL_POLICY=block
374
+
375
+ # Purpose: Timeout in seconds for blocking queue puts (0 = infinite wait)
376
+ # Type: float (>= 0)
377
+ # Default: 1.0
378
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__QUEUE_PUT_TIMEOUT=1.0
379
+ # .env: LIB_LOG_RICH__QUEUE_PUT_TIMEOUT=1.0
380
+ # LIB_LOG_RICH__QUEUE_PUT_TIMEOUT=1.0
381
+
382
+ # Purpose: Maximum wait in seconds for queue drain during shutdown
383
+ # Type: float (> 0)
384
+ # Default: 5.0
385
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__QUEUE_STOP_TIMEOUT=5.0
386
+ # .env: LIB_LOG_RICH__QUEUE_STOP_TIMEOUT=5.0
387
+ # LIB_LOG_RICH__QUEUE_STOP_TIMEOUT=5.0
388
+
389
+ # --- Ring Buffer ---
390
+
391
+ # Purpose: Enable in-memory circular buffer for log history (enables log.dump())
392
+ # Type: boolean (true/false)
393
+ # Default: true
394
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__ENABLE_RING_BUFFER=true
395
+ # .env: LIB_LOG_RICH__ENABLE_RING_BUFFER=true
396
+ # LIB_LOG_RICH__ENABLE_RING_BUFFER=true
397
+
398
+ # Purpose: Maximum events retained in ring buffer
399
+ # Type: integer (> 0)
400
+ # Default: 25000
401
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__RING_BUFFER_SIZE=25000
402
+ # .env: LIB_LOG_RICH__RING_BUFFER_SIZE=25000
403
+ # LIB_LOG_RICH__RING_BUFFER_SIZE=25000
404
+
405
+ # --- Dump Format ---
406
+
407
+ # Purpose: Default layout for text dumps
408
+ # Type: string (case-insensitive): "full", "short", "full_loc", "short_loc"
409
+ # Default: "full"
410
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__DUMP_FORMAT_PRESET=full
411
+ # .env: LIB_LOG_RICH__DUMP_FORMAT_PRESET=full
412
+ # LIB_LOG_RICH__DUMP_FORMAT_PRESET=full
413
+
414
+ # Purpose: Custom template for text dumps (overrides preset)
415
+ # Type: string (Python str.format template); empty = uses preset
416
+ # Default: (empty, uses preset)
417
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__DUMP_FORMAT_TEMPLATE={timestamp_trimmed_naive_loc} {level_code} {message}
418
+ # .env: LIB_LOG_RICH__DUMP_FORMAT_TEMPLATE={timestamp_trimmed_naive_loc} {level_code} {message}
419
+ # LIB_LOG_RICH__DUMP_FORMAT_TEMPLATE={timestamp_trimmed_naive_loc} {level_code} {message}
420
+
421
+ # --- Security & Payload ---
422
+
423
+ # Purpose: Regex patterns to redact sensitive data (comma-separated field=regex pairs)
424
+ # Type: comma-separated field=regex pairs
425
+ # Default: password=.+,secret=.+,token=.+
426
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__SCRUB_PATTERNS=password=.+,secret=.+,token=.+,api_key=.+
427
+ # .env: LIB_LOG_RICH__SCRUB_PATTERNS=password=.+,secret=.+,token=.+,api_key=.+
428
+ # LIB_LOG_RICH__SCRUB_PATTERNS=password=.+,secret=.+,token=.+,api_key=.+
429
+
430
+ # Purpose: Throttle log emissions (MAX_EVENTS:WINDOW_SECONDS)
431
+ # Type: string "max_events:window_seconds"
432
+ # Default: (none, no rate limiting)
433
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__RATE_LIMIT=100:60
434
+ # .env: LIB_LOG_RICH__RATE_LIMIT=100:60
435
+ # LIB_LOG_RICH__RATE_LIMIT=100:60
436
+
437
+ # --- Payload Limits ---
438
+
439
+ # Purpose: Truncate vs reject oversized messages
440
+ # Type: boolean (true/false)
441
+ # Default: true
442
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__PAYLOAD_LIMITS__TRUNCATE_MESSAGE=true
443
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__TRUNCATE_MESSAGE=true
444
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__TRUNCATE_MESSAGE=true
445
+
446
+ # Purpose: Maximum characters in primary log message
447
+ # Type: integer
448
+ # Default: 4096
449
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__PAYLOAD_LIMITS__MESSAGE_MAX_CHARS=4096
450
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__MESSAGE_MAX_CHARS=4096
451
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__MESSAGE_MAX_CHARS=4096
452
+
453
+ # Purpose: Maximum keys in extra metadata dict
454
+ # Type: integer
455
+ # Default: 25
456
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_KEYS=25
457
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_KEYS=25
458
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_KEYS=25
459
+
460
+ # Purpose: Maximum characters per extra value (after stringify)
461
+ # Type: integer
462
+ # Default: 512
463
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_VALUE_CHARS=512
464
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_VALUE_CHARS=512
465
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_VALUE_CHARS=512
466
+
467
+ # Purpose: Maximum nesting depth for extra structures
468
+ # Type: integer
469
+ # Default: 3
470
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_DEPTH=3
471
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_DEPTH=3
472
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_DEPTH=3
473
+
474
+ # Purpose: Total UTF-8 byte limit for sanitized extra payload
475
+ # Type: integer
476
+ # Default: 8192
477
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_TOTAL_BYTES=8192
478
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_TOTAL_BYTES=8192
479
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_TOTAL_BYTES=8192
480
+
481
+ # Purpose: Maximum keys in LogContext.extra
482
+ # Type: integer
483
+ # Default: 20
484
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__PAYLOAD_LIMITS__CONTEXT_MAX_KEYS=20
485
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__CONTEXT_MAX_KEYS=20
486
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__CONTEXT_MAX_KEYS=20
487
+
488
+ # Purpose: Maximum characters per context value
489
+ # Type: integer
490
+ # Default: 256
491
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__PAYLOAD_LIMITS__CONTEXT_MAX_VALUE_CHARS=256
492
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__CONTEXT_MAX_VALUE_CHARS=256
493
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__CONTEXT_MAX_VALUE_CHARS=256
494
+
495
+ # Purpose: Number of frames preserved in exception tracebacks
496
+ # Type: integer
497
+ # Default: 10
498
+ # Environment Variable: PROXMOX_SRVBACKUP___LIB_LOG_RICH__PAYLOAD_LIMITS__STACKTRACE_MAX_FRAMES=10
499
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__STACKTRACE_MAX_FRAMES=10
500
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__STACKTRACE_MAX_FRAMES=10
@@ -0,0 +1,92 @@
1
+ name: Extract project metadata
2
+ description: >-
3
+ Parse pyproject.toml and expose project metadata as step outputs.
4
+ Requires Python to be available in the runner environment.
5
+ Auto-installs rtoml if not already present.
6
+
7
+ outputs:
8
+ PACKAGE_MODULE:
9
+ description: Python-importable module name (underscored)
10
+ value: ${{ steps.meta.outputs.PACKAGE_MODULE }}
11
+ PROJECT_NAME:
12
+ description: Project name from pyproject.toml
13
+ value: ${{ steps.meta.outputs.PROJECT_NAME }}
14
+ CLI_BIN:
15
+ description: CLI entry-point binary name
16
+ value: ${{ steps.meta.outputs.CLI_BIN }}
17
+ SRC_PATH:
18
+ description: Source directory path (e.g. "src")
19
+ value: ${{ steps.meta.outputs.SRC_PATH }}
20
+ COV_FAIL_UNDER:
21
+ description: Minimum coverage percentage from tool.coverage.report.fail_under
22
+ value: ${{ steps.meta.outputs.COV_FAIL_UNDER }}
23
+ COV_REPORT_FILE:
24
+ description: Coverage report filename (e.g. "coverage.xml")
25
+ value: ${{ steps.meta.outputs.COV_REPORT_FILE }}
26
+ PYTEST_VERBOSITY:
27
+ description: Pytest verbosity flag (e.g. "-vv")
28
+ value: ${{ steps.meta.outputs.PYTEST_VERBOSITY }}
29
+ BANDIT_SKIP_FLAG:
30
+ description: Bandit skip flag string (e.g. "-s B101,B601") or empty
31
+ value: ${{ steps.meta.outputs.BANDIT_SKIP_FLAG }}
32
+
33
+ runs:
34
+ using: composite
35
+ steps:
36
+ - name: Extract project metadata from pyproject.toml
37
+ id: meta
38
+ shell: python
39
+ run: |
40
+ import os, subprocess, sys
41
+ try:
42
+ import rtoml
43
+ except ModuleNotFoundError:
44
+ subprocess.check_call([sys.executable, "-m", "pip", "install", "rtoml", "-q"])
45
+ import rtoml
46
+
47
+ from pathlib import Path
48
+ data = rtoml.load(Path('pyproject.toml'))
49
+
50
+ # --- [project] section ---
51
+ project = data['project']['name']
52
+ module = project.replace('-', '_')
53
+ dash = project.replace('_', '-')
54
+ scripts = list(data['project'].get('scripts', {}).keys())
55
+ cli_bin = scripts[0] if scripts else dash
56
+
57
+ # --- [tool.scripts.test] section ---
58
+ scripts_test = data.get('tool', {}).get('scripts', {}).get('test', {})
59
+ src_path = scripts_test.get('src-path', 'src')
60
+ pytest_verbosity = scripts_test.get('pytest-verbosity', '-vv')
61
+ cov_report_file = scripts_test.get('coverage-report-file', 'coverage.xml')
62
+
63
+ # --- [tool.coverage.report] section ---
64
+ cov_fail_under = (
65
+ data.get('tool', {}).get('coverage', {}).get('report', {}).get('fail_under', 90)
66
+ )
67
+
68
+ # --- [tool.bandit] section ---
69
+ bandit_skips = data.get('tool', {}).get('bandit', {}).get('skips', [])
70
+ bandit_skip_flag = f"-s {','.join(bandit_skips)}" if bandit_skips else ""
71
+
72
+ # Write to GITHUB_OUTPUT for composite action outputs
73
+ with open(os.environ['GITHUB_OUTPUT'], 'a', encoding='utf-8') as out:
74
+ out.write(f"PROJECT_NAME={project}\n")
75
+ out.write(f"PACKAGE_MODULE={module}\n")
76
+ out.write(f"CLI_BIN={cli_bin}\n")
77
+ out.write(f"SRC_PATH={src_path}\n")
78
+ out.write(f"PYTEST_VERBOSITY={pytest_verbosity}\n")
79
+ out.write(f"COV_REPORT_FILE={cov_report_file}\n")
80
+ out.write(f"COV_FAIL_UNDER={cov_fail_under}\n")
81
+ out.write(f"BANDIT_SKIP_FLAG={bandit_skip_flag}\n")
82
+
83
+ # Also write to GITHUB_ENV so subsequent steps can use ${{ env.VAR }}
84
+ with open(os.environ['GITHUB_ENV'], 'a', encoding='utf-8') as env:
85
+ env.write(f"PROJECT_NAME={project}\n")
86
+ env.write(f"PACKAGE_MODULE={module}\n")
87
+ env.write(f"CLI_BIN={cli_bin}\n")
88
+ env.write(f"SRC_PATH={src_path}\n")
89
+ env.write(f"PYTEST_VERBOSITY={pytest_verbosity}\n")
90
+ env.write(f"COV_REPORT_FILE={cov_report_file}\n")
91
+ env.write(f"COV_FAIL_UNDER={cov_fail_under}\n")
92
+ env.write(f"BANDIT_SKIP_FLAG={bandit_skip_flag}\n")
@@ -0,0 +1,22 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ allow:
8
+ - dependency-type: "direct"
9
+ labels:
10
+ - "dependencies"
11
+ commit-message:
12
+ prefix: "deps"
13
+ include: "scope"
14
+ - package-ecosystem: "github-actions"
15
+ directory: "/"
16
+ schedule:
17
+ interval: "weekly"
18
+ labels:
19
+ - "dependencies"
20
+ commit-message:
21
+ prefix: "deps"
22
+ include: "scope"
@@ -0,0 +1,39 @@
1
+ name: CodeQL
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, master ]
6
+ pull_request:
7
+ branches: [ main, master ]
8
+ schedule:
9
+ - cron: '0 8 * * 1'
10
+
11
+ jobs:
12
+ analyze:
13
+ name: CodeQL Analyze
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ actions: read
17
+ contents: read
18
+ security-events: write
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ language: [ 'python' ]
23
+
24
+ steps:
25
+ - name: Checkout repository
26
+ uses: actions/checkout@v6
27
+
28
+ - name: Initialize CodeQL
29
+ uses: github/codeql-action/init@v4
30
+ with:
31
+ languages: ${{ matrix.language }}
32
+
33
+ - name: Autobuild
34
+ uses: github/codeql-action/autobuild@v4
35
+
36
+ - name: Perform CodeQL Analysis
37
+ uses: github/codeql-action/analyze@v4
38
+ with:
39
+ category: "/language:${{ matrix.language }}"