pwshpy 1.0.0__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 (256) hide show
  1. pwshpy-1.0.0/.claude-plugin/marketplace.json +14 -0
  2. pwshpy-1.0.0/.claude-plugin/plugin.json +9 -0
  3. pwshpy-1.0.0/.devcontainer/devcontainer.json +22 -0
  4. pwshpy-1.0.0/.devcontainer/settings.json +6 -0
  5. pwshpy-1.0.0/.env.example +312 -0
  6. pwshpy-1.0.0/.gitattributes +15 -0
  7. pwshpy-1.0.0/.github/actions/extract-metadata/action.yml +92 -0
  8. pwshpy-1.0.0/.github/dependabot.yml +22 -0
  9. pwshpy-1.0.0/.github/workflows/codeql.yml +39 -0
  10. pwshpy-1.0.0/.github/workflows/default_cicd_public.yml +386 -0
  11. pwshpy-1.0.0/.github/workflows/default_release_public.yml +85 -0
  12. pwshpy-1.0.0/.gitignore +196 -0
  13. pwshpy-1.0.0/.qlty/qlty.toml +2 -0
  14. pwshpy-1.0.0/.snyk +5 -0
  15. pwshpy-1.0.0/CHANGELOG.md +10 -0
  16. pwshpy-1.0.0/COMMANDS.md +316 -0
  17. pwshpy-1.0.0/CONFIG.md +508 -0
  18. pwshpy-1.0.0/CONTRIBUTING.md +48 -0
  19. pwshpy-1.0.0/DEVELOPMENT.md +178 -0
  20. pwshpy-1.0.0/INSTALL.md +142 -0
  21. pwshpy-1.0.0/LICENSE +22 -0
  22. pwshpy-1.0.0/Makefile +270 -0
  23. pwshpy-1.0.0/PKG-INFO +317 -0
  24. pwshpy-1.0.0/README.md +251 -0
  25. pwshpy-1.0.0/SECURITY.md +37 -0
  26. pwshpy-1.0.0/ai-stance.md +90 -0
  27. pwshpy-1.0.0/ai-transparency.md +96 -0
  28. pwshpy-1.0.0/codecov.yml +27 -0
  29. pwshpy-1.0.0/docs/adr/0001-memory-adapters-in-src.md +29 -0
  30. pwshpy-1.0.0/docs/backends-and-platforms.md +53 -0
  31. pwshpy-1.0.0/docs/cli-reference.md +109 -0
  32. pwshpy-1.0.0/docs/library-usage.md +82 -0
  33. pwshpy-1.0.0/docs/locale-and-identity.md +68 -0
  34. pwshpy-1.0.0/docs/portability-roadmap.md +205 -0
  35. pwshpy-1.0.0/docs/power-tools.md +108 -0
  36. pwshpy-1.0.0/docs/powershell-switch-mapping.md +78 -0
  37. pwshpy-1.0.0/docs/quickstart.md +72 -0
  38. pwshpy-1.0.0/notebooks/Quickstart.ipynb +136 -0
  39. pwshpy-1.0.0/pyproject.toml +306 -0
  40. pwshpy-1.0.0/skills/using-pwsh/SKILL.md +154 -0
  41. pwshpy-1.0.0/src/pwshpy/__init__.py +144 -0
  42. pwshpy-1.0.0/src/pwshpy/__init__conf__.py +90 -0
  43. pwshpy-1.0.0/src/pwshpy/__main__.py +9 -0
  44. pwshpy-1.0.0/src/pwshpy/adapters/__init__.py +14 -0
  45. pwshpy-1.0.0/src/pwshpy/adapters/cli/__init__.py +60 -0
  46. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/__init__.py +75 -0
  47. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/_common.py +66 -0
  48. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/acl.py +51 -0
  49. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/cim.py +56 -0
  50. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/config.py +335 -0
  51. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/connections.py +54 -0
  52. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/credentials.py +67 -0
  53. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/disks.py +50 -0
  54. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/dns.py +48 -0
  55. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/dotnet.py +158 -0
  56. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/elevation.py +40 -0
  57. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/environment.py +50 -0
  58. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/event_log.py +52 -0
  59. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/fileio.py +49 -0
  60. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/filesystem.py +134 -0
  61. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/info.py +76 -0
  62. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/local_accounts.py +72 -0
  63. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/logging.py +33 -0
  64. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/mutating.py +364 -0
  65. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/netcheck.py +56 -0
  66. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/networking.py +64 -0
  67. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/proc.py +49 -0
  68. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/processes.py +54 -0
  69. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/registry.py +71 -0
  70. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/scheduled_tasks.py +51 -0
  71. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/services.py +51 -0
  72. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/system.py +102 -0
  73. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/uptime.py +46 -0
  74. pwshpy-1.0.0/src/pwshpy/adapters/cli/commands/web.py +100 -0
  75. pwshpy-1.0.0/src/pwshpy/adapters/cli/constants.py +28 -0
  76. pwshpy-1.0.0/src/pwshpy/adapters/cli/context.py +155 -0
  77. pwshpy-1.0.0/src/pwshpy/adapters/cli/exit_codes.py +52 -0
  78. pwshpy-1.0.0/src/pwshpy/adapters/cli/main.py +120 -0
  79. pwshpy-1.0.0/src/pwshpy/adapters/cli/output.py +199 -0
  80. pwshpy-1.0.0/src/pwshpy/adapters/cli/py.typed +0 -0
  81. pwshpy-1.0.0/src/pwshpy/adapters/cli/root.py +219 -0
  82. pwshpy-1.0.0/src/pwshpy/adapters/cli/typed_click.py +42 -0
  83. pwshpy-1.0.0/src/pwshpy/adapters/config/__init__.py +25 -0
  84. pwshpy-1.0.0/src/pwshpy/adapters/config/defaultconfig.d/40-layered-config.toml +71 -0
  85. pwshpy-1.0.0/src/pwshpy/adapters/config/defaultconfig.d/90-logging.toml +432 -0
  86. pwshpy-1.0.0/src/pwshpy/adapters/config/defaultconfig.toml +44 -0
  87. pwshpy-1.0.0/src/pwshpy/adapters/config/deploy.py +118 -0
  88. pwshpy-1.0.0/src/pwshpy/adapters/config/display.py +56 -0
  89. pwshpy-1.0.0/src/pwshpy/adapters/config/loader.py +188 -0
  90. pwshpy-1.0.0/src/pwshpy/adapters/config/overrides.py +189 -0
  91. pwshpy-1.0.0/src/pwshpy/adapters/config/permissions.py +185 -0
  92. pwshpy-1.0.0/src/pwshpy/adapters/config/py.typed +0 -0
  93. pwshpy-1.0.0/src/pwshpy/adapters/logging/__init__.py +13 -0
  94. pwshpy-1.0.0/src/pwshpy/adapters/logging/py.typed +0 -0
  95. pwshpy-1.0.0/src/pwshpy/adapters/logging/setup.py +132 -0
  96. pwshpy-1.0.0/src/pwshpy/adapters/memory/__init__.py +41 -0
  97. pwshpy-1.0.0/src/pwshpy/adapters/memory/config.py +62 -0
  98. pwshpy-1.0.0/src/pwshpy/adapters/memory/logging.py +15 -0
  99. pwshpy-1.0.0/src/pwshpy/adapters/native/__init__.py +115 -0
  100. pwshpy-1.0.0/src/pwshpy/adapters/native/acl.py +94 -0
  101. pwshpy-1.0.0/src/pwshpy/adapters/native/acl_control.py +104 -0
  102. pwshpy-1.0.0/src/pwshpy/adapters/native/cim.py +96 -0
  103. pwshpy-1.0.0/src/pwshpy/adapters/native/credentials.py +122 -0
  104. pwshpy-1.0.0/src/pwshpy/adapters/native/dns.py +89 -0
  105. pwshpy-1.0.0/src/pwshpy/adapters/native/elevation.py +186 -0
  106. pwshpy-1.0.0/src/pwshpy/adapters/native/environment.py +30 -0
  107. pwshpy-1.0.0/src/pwshpy/adapters/native/event_log.py +116 -0
  108. pwshpy-1.0.0/src/pwshpy/adapters/native/event_log_control.py +49 -0
  109. pwshpy-1.0.0/src/pwshpy/adapters/native/fileio.py +179 -0
  110. pwshpy-1.0.0/src/pwshpy/adapters/native/filesystem.py +151 -0
  111. pwshpy-1.0.0/src/pwshpy/adapters/native/inventory.py +85 -0
  112. pwshpy-1.0.0/src/pwshpy/adapters/native/journald.py +148 -0
  113. pwshpy-1.0.0/src/pwshpy/adapters/native/local_account_control.py +159 -0
  114. pwshpy-1.0.0/src/pwshpy/adapters/native/local_accounts.py +104 -0
  115. pwshpy-1.0.0/src/pwshpy/adapters/native/marshal.py +431 -0
  116. pwshpy-1.0.0/src/pwshpy/adapters/native/netcheck.py +48 -0
  117. pwshpy-1.0.0/src/pwshpy/adapters/native/networking.py +107 -0
  118. pwshpy-1.0.0/src/pwshpy/adapters/native/posix_account_control.py +160 -0
  119. pwshpy-1.0.0/src/pwshpy/adapters/native/posix_accounts.py +86 -0
  120. pwshpy-1.0.0/src/pwshpy/adapters/native/posix_acl.py +269 -0
  121. pwshpy-1.0.0/src/pwshpy/adapters/native/process_control.py +91 -0
  122. pwshpy-1.0.0/src/pwshpy/adapters/native/process_exec.py +90 -0
  123. pwshpy-1.0.0/src/pwshpy/adapters/native/psutil_disk.py +56 -0
  124. pwshpy-1.0.0/src/pwshpy/adapters/native/psutil_net.py +72 -0
  125. pwshpy-1.0.0/src/pwshpy/adapters/native/psutil_process.py +73 -0
  126. pwshpy-1.0.0/src/pwshpy/adapters/native/psutil_system.py +41 -0
  127. pwshpy-1.0.0/src/pwshpy/adapters/native/registry.py +113 -0
  128. pwshpy-1.0.0/src/pwshpy/adapters/native/registry_control.py +79 -0
  129. pwshpy-1.0.0/src/pwshpy/adapters/native/scheduled_task_control.py +145 -0
  130. pwshpy-1.0.0/src/pwshpy/adapters/native/scheduled_tasks.py +124 -0
  131. pwshpy-1.0.0/src/pwshpy/adapters/native/secret_service.py +179 -0
  132. pwshpy-1.0.0/src/pwshpy/adapters/native/service_control.py +184 -0
  133. pwshpy-1.0.0/src/pwshpy/adapters/native/services.py +106 -0
  134. pwshpy-1.0.0/src/pwshpy/adapters/native/systemd_dbus.py +113 -0
  135. pwshpy-1.0.0/src/pwshpy/adapters/native/systemd_services.py +176 -0
  136. pwshpy-1.0.0/src/pwshpy/adapters/native/systemd_timers.py +249 -0
  137. pwshpy-1.0.0/src/pwshpy/adapters/native/web.py +140 -0
  138. pwshpy-1.0.0/src/pwshpy/adapters/powershell/__init__.py +17 -0
  139. pwshpy-1.0.0/src/pwshpy/adapters/powershell/hosted.py +453 -0
  140. pwshpy-1.0.0/src/pwshpy/adapters/py.typed +0 -0
  141. pwshpy-1.0.0/src/pwshpy/application/__init__.py +26 -0
  142. pwshpy-1.0.0/src/pwshpy/application/ports.py +486 -0
  143. pwshpy-1.0.0/src/pwshpy/application/py.typed +0 -0
  144. pwshpy-1.0.0/src/pwshpy/composition/__init__.py +104 -0
  145. pwshpy-1.0.0/src/pwshpy/composition/facade.py +1276 -0
  146. pwshpy-1.0.0/src/pwshpy/composition/py.typed +0 -0
  147. pwshpy-1.0.0/src/pwshpy/domain/__init__.py +53 -0
  148. pwshpy-1.0.0/src/pwshpy/domain/behaviors.py +5 -0
  149. pwshpy-1.0.0/src/pwshpy/domain/enums.py +367 -0
  150. pwshpy-1.0.0/src/pwshpy/domain/errors.py +114 -0
  151. pwshpy-1.0.0/src/pwshpy/domain/pipeline.py +147 -0
  152. pwshpy-1.0.0/src/pwshpy/domain/py.typed +0 -0
  153. pwshpy-1.0.0/src/pwshpy/domain/records.py +692 -0
  154. pwshpy-1.0.0/src/pwshpy/entry.py +26 -0
  155. pwshpy-1.0.0/src/pwshpy/py.typed +0 -0
  156. pwshpy-1.0.0/tests/conftest.py +523 -0
  157. pwshpy-1.0.0/tests/test_acl_control.py +208 -0
  158. pwshpy-1.0.0/tests/test_acl_pwsh_oracle.py +67 -0
  159. pwshpy-1.0.0/tests/test_cache_effectiveness.py +155 -0
  160. pwshpy-1.0.0/tests/test_cim_pwsh_oracle.py +66 -0
  161. pwshpy-1.0.0/tests/test_cli_config.py +802 -0
  162. pwshpy-1.0.0/tests/test_cli_connections.py +61 -0
  163. pwshpy-1.0.0/tests/test_cli_core.py +210 -0
  164. pwshpy-1.0.0/tests/test_cli_disks.py +62 -0
  165. pwshpy-1.0.0/tests/test_cli_elevation.py +90 -0
  166. pwshpy-1.0.0/tests/test_cli_env.py +48 -0
  167. pwshpy-1.0.0/tests/test_cli_env_file.py +174 -0
  168. pwshpy-1.0.0/tests/test_cli_exit_codes.py +78 -0
  169. pwshpy-1.0.0/tests/test_cli_filesystem.py +55 -0
  170. pwshpy-1.0.0/tests/test_cli_mutating.py +195 -0
  171. pwshpy-1.0.0/tests/test_cli_networking.py +34 -0
  172. pwshpy-1.0.0/tests/test_cli_overrides.py +164 -0
  173. pwshpy-1.0.0/tests/test_cli_power.py +63 -0
  174. pwshpy-1.0.0/tests/test_cli_processes.py +87 -0
  175. pwshpy-1.0.0/tests/test_cli_registry.py +72 -0
  176. pwshpy-1.0.0/tests/test_cli_resolve.py +56 -0
  177. pwshpy-1.0.0/tests/test_cli_system_credentials.py +187 -0
  178. pwshpy-1.0.0/tests/test_cli_test_connection.py +50 -0
  179. pwshpy-1.0.0/tests/test_cli_uptime.py +49 -0
  180. pwshpy-1.0.0/tests/test_cli_validation.py +132 -0
  181. pwshpy-1.0.0/tests/test_cli_web_commands.py +85 -0
  182. pwshpy-1.0.0/tests/test_config_overrides.py +327 -0
  183. pwshpy-1.0.0/tests/test_credentials.py +135 -0
  184. pwshpy-1.0.0/tests/test_deploy_permissions.py +517 -0
  185. pwshpy-1.0.0/tests/test_display.py +121 -0
  186. pwshpy-1.0.0/tests/test_dotnet.py +139 -0
  187. pwshpy-1.0.0/tests/test_dotnet_cmdlet.py +253 -0
  188. pwshpy-1.0.0/tests/test_dotnet_guard.py +34 -0
  189. pwshpy-1.0.0/tests/test_dotnet_module_wrappers.py +64 -0
  190. pwshpy-1.0.0/tests/test_dotnet_pool.py +72 -0
  191. pwshpy-1.0.0/tests/test_elevation.py +150 -0
  192. pwshpy-1.0.0/tests/test_enums.py +78 -0
  193. pwshpy-1.0.0/tests/test_error_hierarchy.py +44 -0
  194. pwshpy-1.0.0/tests/test_errors.py +14 -0
  195. pwshpy-1.0.0/tests/test_event_log_control.py +78 -0
  196. pwshpy-1.0.0/tests/test_event_log_pwsh_oracle.py +64 -0
  197. pwshpy-1.0.0/tests/test_facade.py +719 -0
  198. pwshpy-1.0.0/tests/test_fileio.py +140 -0
  199. pwshpy-1.0.0/tests/test_filesystem.py +124 -0
  200. pwshpy-1.0.0/tests/test_inventory.py +30 -0
  201. pwshpy-1.0.0/tests/test_journald.py +79 -0
  202. pwshpy-1.0.0/tests/test_local_account_control.py +196 -0
  203. pwshpy-1.0.0/tests/test_local_accounts_pwsh_oracle.py +72 -0
  204. pwshpy-1.0.0/tests/test_locale_invariance.py +56 -0
  205. pwshpy-1.0.0/tests/test_logging.py +31 -0
  206. pwshpy-1.0.0/tests/test_marshal.py +45 -0
  207. pwshpy-1.0.0/tests/test_marshal_ace.py +27 -0
  208. pwshpy-1.0.0/tests/test_marshal_event.py +59 -0
  209. pwshpy-1.0.0/tests/test_marshal_process.py +25 -0
  210. pwshpy-1.0.0/tests/test_marshal_registry.py +94 -0
  211. pwshpy-1.0.0/tests/test_marshal_services.py +65 -0
  212. pwshpy-1.0.0/tests/test_marshal_task.py +25 -0
  213. pwshpy-1.0.0/tests/test_metadata.py +84 -0
  214. pwshpy-1.0.0/tests/test_metadata_sync.py +80 -0
  215. pwshpy-1.0.0/tests/test_module_entry.py +176 -0
  216. pwshpy-1.0.0/tests/test_native_acl.py +151 -0
  217. pwshpy-1.0.0/tests/test_native_cim.py +199 -0
  218. pwshpy-1.0.0/tests/test_native_connections.py +65 -0
  219. pwshpy-1.0.0/tests/test_native_disks.py +29 -0
  220. pwshpy-1.0.0/tests/test_native_dns.py +65 -0
  221. pwshpy-1.0.0/tests/test_native_environment.py +24 -0
  222. pwshpy-1.0.0/tests/test_native_event_log.py +185 -0
  223. pwshpy-1.0.0/tests/test_native_local_accounts.py +152 -0
  224. pwshpy-1.0.0/tests/test_native_netcheck.py +37 -0
  225. pwshpy-1.0.0/tests/test_native_process.py +26 -0
  226. pwshpy-1.0.0/tests/test_native_registry.py +77 -0
  227. pwshpy-1.0.0/tests/test_native_scheduled_tasks.py +183 -0
  228. pwshpy-1.0.0/tests/test_native_services.py +166 -0
  229. pwshpy-1.0.0/tests/test_native_uptime.py +26 -0
  230. pwshpy-1.0.0/tests/test_networking.py +43 -0
  231. pwshpy-1.0.0/tests/test_output.py +80 -0
  232. pwshpy-1.0.0/tests/test_output_broken_pipe.py +48 -0
  233. pwshpy-1.0.0/tests/test_pipeline.py +93 -0
  234. pwshpy-1.0.0/tests/test_portable_pwsh_oracle.py +164 -0
  235. pwshpy-1.0.0/tests/test_ports.py +127 -0
  236. pwshpy-1.0.0/tests/test_posix_account_control.py +112 -0
  237. pwshpy-1.0.0/tests/test_posix_account_controller.py +74 -0
  238. pwshpy-1.0.0/tests/test_posix_accounts.py +50 -0
  239. pwshpy-1.0.0/tests/test_posix_acl.py +83 -0
  240. pwshpy-1.0.0/tests/test_process_control.py +85 -0
  241. pwshpy-1.0.0/tests/test_process_exec.py +102 -0
  242. pwshpy-1.0.0/tests/test_property_overrides.py +165 -0
  243. pwshpy-1.0.0/tests/test_records.py +61 -0
  244. pwshpy-1.0.0/tests/test_registry_control.py +135 -0
  245. pwshpy-1.0.0/tests/test_registry_pwsh_oracle.py +96 -0
  246. pwshpy-1.0.0/tests/test_scheduled_task_control.py +212 -0
  247. pwshpy-1.0.0/tests/test_scheduled_tasks_pwsh_oracle.py +57 -0
  248. pwshpy-1.0.0/tests/test_secret_service.py +59 -0
  249. pwshpy-1.0.0/tests/test_service_control.py +236 -0
  250. pwshpy-1.0.0/tests/test_services_pwsh_oracle.py +91 -0
  251. pwshpy-1.0.0/tests/test_structural_guarantees.py +79 -0
  252. pwshpy-1.0.0/tests/test_systemd_controller.py +67 -0
  253. pwshpy-1.0.0/tests/test_systemd_services.py +71 -0
  254. pwshpy-1.0.0/tests/test_systemd_task_controller.py +101 -0
  255. pwshpy-1.0.0/tests/test_systemd_timers.py +109 -0
  256. pwshpy-1.0.0/tests/test_web.py +123 -0
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "pwshpy",
3
+ "owner": { "name": "bitranox" },
4
+ "metadata": {
5
+ "description": "pwshpy delivered as a single Claude Code plugin: the using-pwsh skill for using pwshpy (a Pythonic PowerShell) instead of writing or debugging PowerShell / .ps1."
6
+ },
7
+ "plugins": [
8
+ {
9
+ "name": "pwshpy",
10
+ "source": ".",
11
+ "description": "Use pwshpy - a genuinely Pythonic PowerShell (typed records + a lazy pipeline, as a library and a CLI) - instead of writing, modifying, or debugging pwsh / .ps1; and translate cmdlets and .ps1 scripts to it."
12
+ }
13
+ ]
14
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "pwshpy",
3
+ "description": "A genuinely Pythonic PowerShell: typed records and a lazy pipeline over native OS bindings, never a pwsh.exe subprocess and never text parsing. Ships the using-pwsh skill: use pwshpy (the `from pwshpy import ps` library and the `pwshpy` CLI) instead of writing or debugging PowerShell / .ps1, and translate cmdlets and .ps1 scripts to it.",
4
+ "version": "1.0.0",
5
+ "author": { "name": "bitranox" },
6
+ "homepage": "https://github.com/bitranox/pwshpy",
7
+ "repository": "https://github.com/bitranox/pwshpy",
8
+ "license": "MIT"
9
+ }
@@ -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,312 @@
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
+ # Logging Configuration (lib_log_rich)
16
+ # ==============================================================================
17
+ #
18
+ # Naming Convention
19
+ # -----------------
20
+ # Format: <SECTION>__<KEY>=value (double underscore separates section from key)
21
+ # Strings need no quotes. Booleans: true/false. Floats: 1.0. Lists: comma-separated.
22
+ #
23
+ # Full environment variable (outside .env):
24
+ # PWSHPY___LIB_LOG_RICH__<KEY>=value
25
+ #
26
+ # For nested subsections (e.g. payload_limits):
27
+ # PWSHPY___LIB_LOG_RICH__PAYLOAD_LIMITS__<KEY>=value
28
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__<KEY>=value
29
+
30
+ # --- Core Identity ---
31
+
32
+ # Purpose: Logical service name recorded in each log event
33
+ # Type: string (non-empty)
34
+ # Default: "pwshpy"
35
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__SERVICE=my-application
36
+ # .env: LIB_LOG_RICH__SERVICE=my-application
37
+ # LIB_LOG_RICH__SERVICE=my-application
38
+
39
+ # Purpose: Deployment environment label
40
+ # Type: string (non-empty)
41
+ # Default: "prod"
42
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__ENVIRONMENT=dev
43
+ # .env: LIB_LOG_RICH__ENVIRONMENT=dev
44
+ # LIB_LOG_RICH__ENVIRONMENT=dev
45
+
46
+ # --- Console Output ---
47
+
48
+ # Purpose: Minimum severity level emitted to Rich console
49
+ # Type: string (case-insensitive): "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
50
+ # Default: "INFO"
51
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__CONSOLE_LEVEL=DEBUG
52
+ # .env: LIB_LOG_RICH__CONSOLE_LEVEL=DEBUG
53
+ # LIB_LOG_RICH__CONSOLE_LEVEL=DEBUG
54
+
55
+ # Purpose: Where to send console output
56
+ # Type: string: "stdout", "stderr", "both", "custom", "none"
57
+ # Default: "stderr"
58
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__CONSOLE_STREAM=stderr
59
+ # .env: LIB_LOG_RICH__CONSOLE_STREAM=stderr
60
+ # LIB_LOG_RICH__CONSOLE_STREAM=stderr
61
+
62
+ # Purpose: Console line layout preset
63
+ # Type: string (case-insensitive): "full", "short", "full_loc", "short_loc"
64
+ # Default: "short_loc"
65
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__CONSOLE_FORMAT_PRESET=short_loc
66
+ # .env: LIB_LOG_RICH__CONSOLE_FORMAT_PRESET=short_loc
67
+ # LIB_LOG_RICH__CONSOLE_FORMAT_PRESET=short_loc
68
+
69
+ # Purpose: Custom console output template (overrides preset)
70
+ # Type: string (Python str.format template); empty = uses preset
71
+ # Default: (empty, uses preset)
72
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__CONSOLE_FORMAT_TEMPLATE={timestamp_trimmed_naive_loc} {level_code} {message}
73
+ # .env: LIB_LOG_RICH__CONSOLE_FORMAT_TEMPLATE={timestamp_trimmed_naive_loc} {level_code} {message}
74
+ # LIB_LOG_RICH__CONSOLE_FORMAT_TEMPLATE={timestamp_trimmed_naive_loc} {level_code} {message}
75
+
76
+ # Purpose: Rich color palette for console output
77
+ # Type: string: "classic", "dark", "neon", "pastel"
78
+ # Default: "dark"
79
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__CONSOLE_THEME=dark
80
+ # .env: LIB_LOG_RICH__CONSOLE_THEME=dark
81
+ # LIB_LOG_RICH__CONSOLE_THEME=dark
82
+
83
+ # Purpose: Override Rich styles per severity level (comma-separated LEVEL=style pairs)
84
+ # Type: comma-separated LEVEL=style pairs
85
+ # Default: (empty, uses theme defaults)
86
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__CONSOLE_STYLES=DEBUG=dim,ERROR=bold red
87
+ # .env: LIB_LOG_RICH__CONSOLE_STYLES=DEBUG=dim,ERROR=bold red
88
+ # LIB_LOG_RICH__CONSOLE_STYLES=DEBUG=dim,ERROR=bold red
89
+
90
+ # Purpose: Force ANSI color output even when stderr is not a TTY
91
+ # Type: boolean (true/false)
92
+ # Default: false
93
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__FORCE_COLOR=true
94
+ # .env: LIB_LOG_RICH__FORCE_COLOR=true
95
+ # LIB_LOG_RICH__FORCE_COLOR=true
96
+
97
+ # Purpose: Disable color output entirely (overrides force_color)
98
+ # Type: boolean (true/false)
99
+ # Default: false
100
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__NO_COLOR=false
101
+ # .env: LIB_LOG_RICH__NO_COLOR=false
102
+ # LIB_LOG_RICH__NO_COLOR=false
103
+
104
+ # --- Backend Adapters ---
105
+
106
+ # Purpose: Minimum severity threshold for journald and Windows Event Log
107
+ # Type: string (case-insensitive): "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
108
+ # Default: "WARNING"
109
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__BACKEND_LEVEL=WARNING
110
+ # .env: LIB_LOG_RICH__BACKEND_LEVEL=WARNING
111
+ # LIB_LOG_RICH__BACKEND_LEVEL=WARNING
112
+
113
+ # Purpose: Enable systemd journald adapter (Linux only; requires python3-systemd)
114
+ # Type: boolean (true/false)
115
+ # Default: false
116
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__ENABLE_JOURNALD=true
117
+ # .env: LIB_LOG_RICH__ENABLE_JOURNALD=true
118
+ # LIB_LOG_RICH__ENABLE_JOURNALD=true
119
+
120
+ # Purpose: Enable Windows Event Log adapter (Windows only)
121
+ # Type: boolean (true/false)
122
+ # Default: false
123
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__ENABLE_EVENTLOG=false
124
+ # .env: LIB_LOG_RICH__ENABLE_EVENTLOG=false
125
+ # LIB_LOG_RICH__ENABLE_EVENTLOG=false
126
+
127
+ # --- Graylog / GELF ---
128
+
129
+ # Purpose: Enable Graylog adapter for centralized logging
130
+ # Type: boolean (true/false)
131
+ # Default: false
132
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__ENABLE_GRAYLOG=true
133
+ # .env: LIB_LOG_RICH__ENABLE_GRAYLOG=true
134
+ # LIB_LOG_RICH__ENABLE_GRAYLOG=true
135
+
136
+ # Purpose: Graylog server address (host:port)
137
+ # Type: string "host:port"
138
+ # Default: (none, must be configured to enable Graylog)
139
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__GRAYLOG_ENDPOINT=graylog.example.com:12201
140
+ # .env: LIB_LOG_RICH__GRAYLOG_ENDPOINT=graylog.example.com:12201
141
+ # LIB_LOG_RICH__GRAYLOG_ENDPOINT=graylog.example.com:12201
142
+
143
+ # Purpose: Transport protocol for Graylog (tcp, udp); TLS only supported with tcp
144
+ # Type: string: "tcp", "udp"
145
+ # Default: "tcp"
146
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__GRAYLOG_PROTOCOL=tcp
147
+ # .env: LIB_LOG_RICH__GRAYLOG_PROTOCOL=tcp
148
+ # LIB_LOG_RICH__GRAYLOG_PROTOCOL=tcp
149
+
150
+ # Purpose: Wrap Graylog TCP connection in TLS
151
+ # Type: boolean (true/false)
152
+ # Default: false
153
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__GRAYLOG_TLS=true
154
+ # .env: LIB_LOG_RICH__GRAYLOG_TLS=true
155
+ # LIB_LOG_RICH__GRAYLOG_TLS=true
156
+
157
+ # Purpose: Minimum severity level sent to Graylog
158
+ # Type: string (case-insensitive): "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
159
+ # Default: "WARNING"
160
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__GRAYLOG_LEVEL=WARNING
161
+ # .env: LIB_LOG_RICH__GRAYLOG_LEVEL=WARNING
162
+ # LIB_LOG_RICH__GRAYLOG_LEVEL=WARNING
163
+
164
+ # --- Queue Settings ---
165
+
166
+ # Purpose: Route log events through background queue worker (false = synchronous, blocks on I/O)
167
+ # Type: boolean (true/false)
168
+ # Default: true
169
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__QUEUE_ENABLED=true
170
+ # .env: LIB_LOG_RICH__QUEUE_ENABLED=true
171
+ # LIB_LOG_RICH__QUEUE_ENABLED=true
172
+
173
+ # Purpose: Maximum pending events before queue full policy applies
174
+ # Type: integer (> 0)
175
+ # Default: 2048
176
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__QUEUE_MAXSIZE=2048
177
+ # .env: LIB_LOG_RICH__QUEUE_MAXSIZE=2048
178
+ # LIB_LOG_RICH__QUEUE_MAXSIZE=2048
179
+
180
+ # Purpose: Behavior when queue is full
181
+ # Type: string: "block" (wait for space), "drop" (discard events)
182
+ # Default: "block"
183
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__QUEUE_FULL_POLICY=block
184
+ # .env: LIB_LOG_RICH__QUEUE_FULL_POLICY=block
185
+ # LIB_LOG_RICH__QUEUE_FULL_POLICY=block
186
+
187
+ # Purpose: Timeout in seconds for blocking queue puts (0 = infinite wait)
188
+ # Type: float (>= 0)
189
+ # Default: 1.0
190
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__QUEUE_PUT_TIMEOUT=1.0
191
+ # .env: LIB_LOG_RICH__QUEUE_PUT_TIMEOUT=1.0
192
+ # LIB_LOG_RICH__QUEUE_PUT_TIMEOUT=1.0
193
+
194
+ # Purpose: Maximum wait in seconds for queue drain during shutdown
195
+ # Type: float (> 0)
196
+ # Default: 5.0
197
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__QUEUE_STOP_TIMEOUT=5.0
198
+ # .env: LIB_LOG_RICH__QUEUE_STOP_TIMEOUT=5.0
199
+ # LIB_LOG_RICH__QUEUE_STOP_TIMEOUT=5.0
200
+
201
+ # --- Ring Buffer ---
202
+
203
+ # Purpose: Enable in-memory circular buffer for log history (enables log.dump())
204
+ # Type: boolean (true/false)
205
+ # Default: true
206
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__ENABLE_RING_BUFFER=true
207
+ # .env: LIB_LOG_RICH__ENABLE_RING_BUFFER=true
208
+ # LIB_LOG_RICH__ENABLE_RING_BUFFER=true
209
+
210
+ # Purpose: Maximum events retained in ring buffer
211
+ # Type: integer (> 0)
212
+ # Default: 25000
213
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__RING_BUFFER_SIZE=25000
214
+ # .env: LIB_LOG_RICH__RING_BUFFER_SIZE=25000
215
+ # LIB_LOG_RICH__RING_BUFFER_SIZE=25000
216
+
217
+ # --- Dump Format ---
218
+
219
+ # Purpose: Default layout for text dumps
220
+ # Type: string (case-insensitive): "full", "short", "full_loc", "short_loc"
221
+ # Default: "full"
222
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__DUMP_FORMAT_PRESET=full
223
+ # .env: LIB_LOG_RICH__DUMP_FORMAT_PRESET=full
224
+ # LIB_LOG_RICH__DUMP_FORMAT_PRESET=full
225
+
226
+ # Purpose: Custom template for text dumps (overrides preset)
227
+ # Type: string (Python str.format template); empty = uses preset
228
+ # Default: (empty, uses preset)
229
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__DUMP_FORMAT_TEMPLATE={timestamp_trimmed_naive_loc} {level_code} {message}
230
+ # .env: LIB_LOG_RICH__DUMP_FORMAT_TEMPLATE={timestamp_trimmed_naive_loc} {level_code} {message}
231
+ # LIB_LOG_RICH__DUMP_FORMAT_TEMPLATE={timestamp_trimmed_naive_loc} {level_code} {message}
232
+
233
+ # --- Security & Payload ---
234
+
235
+ # Purpose: Regex patterns to redact sensitive data (comma-separated field=regex pairs)
236
+ # Type: comma-separated field=regex pairs
237
+ # Default: password=.+,secret=.+,token=.+
238
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__SCRUB_PATTERNS=password=.+,secret=.+,token=.+,api_key=.+
239
+ # .env: LIB_LOG_RICH__SCRUB_PATTERNS=password=.+,secret=.+,token=.+,api_key=.+
240
+ # LIB_LOG_RICH__SCRUB_PATTERNS=password=.+,secret=.+,token=.+,api_key=.+
241
+
242
+ # Purpose: Throttle log emissions (MAX_EVENTS:WINDOW_SECONDS)
243
+ # Type: string "max_events:window_seconds"
244
+ # Default: (none, no rate limiting)
245
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__RATE_LIMIT=100:60
246
+ # .env: LIB_LOG_RICH__RATE_LIMIT=100:60
247
+ # LIB_LOG_RICH__RATE_LIMIT=100:60
248
+
249
+ # --- Payload Limits ---
250
+
251
+ # Purpose: Truncate vs reject oversized messages
252
+ # Type: boolean (true/false)
253
+ # Default: true
254
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__PAYLOAD_LIMITS__TRUNCATE_MESSAGE=true
255
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__TRUNCATE_MESSAGE=true
256
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__TRUNCATE_MESSAGE=true
257
+
258
+ # Purpose: Maximum characters in primary log message
259
+ # Type: integer
260
+ # Default: 4096
261
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__PAYLOAD_LIMITS__MESSAGE_MAX_CHARS=4096
262
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__MESSAGE_MAX_CHARS=4096
263
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__MESSAGE_MAX_CHARS=4096
264
+
265
+ # Purpose: Maximum keys in extra metadata dict
266
+ # Type: integer
267
+ # Default: 25
268
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_KEYS=25
269
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_KEYS=25
270
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_KEYS=25
271
+
272
+ # Purpose: Maximum characters per extra value (after stringify)
273
+ # Type: integer
274
+ # Default: 512
275
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_VALUE_CHARS=512
276
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_VALUE_CHARS=512
277
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_VALUE_CHARS=512
278
+
279
+ # Purpose: Maximum nesting depth for extra structures
280
+ # Type: integer
281
+ # Default: 3
282
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_DEPTH=3
283
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_DEPTH=3
284
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_DEPTH=3
285
+
286
+ # Purpose: Total UTF-8 byte limit for sanitized extra payload
287
+ # Type: integer
288
+ # Default: 8192
289
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_TOTAL_BYTES=8192
290
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_TOTAL_BYTES=8192
291
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__EXTRA_MAX_TOTAL_BYTES=8192
292
+
293
+ # Purpose: Maximum keys in LogContext.extra
294
+ # Type: integer
295
+ # Default: 20
296
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__PAYLOAD_LIMITS__CONTEXT_MAX_KEYS=20
297
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__CONTEXT_MAX_KEYS=20
298
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__CONTEXT_MAX_KEYS=20
299
+
300
+ # Purpose: Maximum characters per context value
301
+ # Type: integer
302
+ # Default: 256
303
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__PAYLOAD_LIMITS__CONTEXT_MAX_VALUE_CHARS=256
304
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__CONTEXT_MAX_VALUE_CHARS=256
305
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__CONTEXT_MAX_VALUE_CHARS=256
306
+
307
+ # Purpose: Number of frames preserved in exception tracebacks
308
+ # Type: integer
309
+ # Default: 10
310
+ # Environment Variable: PWSHPY___LIB_LOG_RICH__PAYLOAD_LIMITS__STACKTRACE_MAX_FRAMES=10
311
+ # .env: LIB_LOG_RICH__PAYLOAD_LIMITS__STACKTRACE_MAX_FRAMES=10
312
+ # LIB_LOG_RICH__PAYLOAD_LIMITS__STACKTRACE_MAX_FRAMES=10
@@ -0,0 +1,15 @@
1
+ # Normalize every text file to LF in the repo AND the working tree, on every OS.
2
+ # `text=auto` auto-detects binary and leaves it untouched; `eol=lf` forces LF checkout
3
+ # so a Windows edit/save cannot reintroduce CRLF churn.
4
+ * text=auto eol=lf
5
+
6
+ # Runtime-critical: CRLF here breaks execution on Linux (^M in shebang / make recipes).
7
+ Makefile text eol=lf
8
+ *.sh text eol=lf
9
+ *.py text eol=lf
10
+ *.ps1 text eol=lf
11
+ *.toml text eol=lf
12
+ *.md text eol=lf
13
+ *.json text eol=lf
14
+ *.yml text eol=lf
15
+ *.yaml text eol=lf
@@ -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@v7
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 }}"