mkdocs2confluence 0.17.4__tar.gz → 0.18.1__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 (110) hide show
  1. {mkdocs2confluence-0.17.4/src/mkdocs2confluence.egg-info → mkdocs2confluence-0.18.1}/PKG-INFO +5 -2
  2. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/README.md +3 -0
  3. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/pyproject.toml +19 -4
  4. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1/src/mkdocs2confluence.egg-info}/PKG-INFO +5 -2
  5. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs2confluence.egg-info/requires.txt +1 -1
  6. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/cli.py +1 -1
  7. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/compiler/page.py +1 -1
  8. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/loader/config.py +17 -2
  9. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/parser/markdown.py +3 -1
  10. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/preprocess/includes.py +1 -1
  11. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/publisher/client.py +4 -1
  12. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/skill_installer.py +2 -2
  13. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/transforms/_kroki.py +4 -1
  14. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/transforms/mermaid.py +1 -1
  15. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_children_macro.py +80 -0
  16. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_skill_installer.py +2 -0
  17. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/LICENSE +0 -0
  18. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/setup.cfg +0 -0
  19. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs2confluence.egg-info/SOURCES.txt +0 -0
  20. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs2confluence.egg-info/dependency_links.txt +0 -0
  21. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs2confluence.egg-info/entry_points.txt +0 -0
  22. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs2confluence.egg-info/top_level.txt +0 -0
  23. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/__init__.py +0 -0
  24. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/compiler/__init__.py +0 -0
  25. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/compiler/models.py +0 -0
  26. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/emitter/__init__.py +0 -0
  27. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/emitter/xhtml.py +0 -0
  28. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/ir/__init__.py +0 -0
  29. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/ir/nodes.py +0 -0
  30. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/ir/treeutil.py +0 -0
  31. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/loader/__init__.py +0 -0
  32. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/loader/extra_css.py +0 -0
  33. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/loader/nav.py +0 -0
  34. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/loader/page.py +0 -0
  35. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/parser/__init__.py +0 -0
  36. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/pdf/__init__.py +0 -0
  37. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/pdf/generator.py +0 -0
  38. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/pdf/render.py +0 -0
  39. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/preprocess/__init__.py +0 -0
  40. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/preprocess/abbrevs.py +0 -0
  41. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/preprocess/captions.py +0 -0
  42. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/preprocess/fence.py +0 -0
  43. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/preprocess/frontmatter.py +0 -0
  44. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/preprocess/icons.py +0 -0
  45. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/preprocess/linkdefs.py +0 -0
  46. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/preview/__init__.py +0 -0
  47. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/preview/render.py +0 -0
  48. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/preview/server.py +0 -0
  49. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/publisher/__init__.py +0 -0
  50. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/publisher/changelog.py +0 -0
  51. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/publisher/executor.py +0 -0
  52. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/publisher/http_retry.py +0 -0
  53. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/publisher/models.py +0 -0
  54. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/publisher/planner.py +0 -0
  55. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/skills/mkdocs-changelog/SKILL.md +0 -0
  56. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/skills/mkdocs-changelog/scripts/changelog_data.py +0 -0
  57. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/sync/__init__.py +0 -0
  58. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/sync/anchoring.py +0 -0
  59. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/sync/command.py +0 -0
  60. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/sync/comments.py +0 -0
  61. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/sync/github.py +0 -0
  62. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/sync/platform.py +0 -0
  63. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/sync/state.py +0 -0
  64. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/transforms/__init__.py +0 -0
  65. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/transforms/abbrevs.py +0 -0
  66. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/transforms/admonition_titles.py +0 -0
  67. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/transforms/assets.py +0 -0
  68. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/transforms/attachment_previews.py +0 -0
  69. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/transforms/captions.py +0 -0
  70. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/transforms/editlink.py +0 -0
  71. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/transforms/footer.py +0 -0
  72. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/transforms/images.py +0 -0
  73. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/transforms/internallinks.py +0 -0
  74. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/src/mkdocs_to_confluence/transforms/plantuml.py +0 -0
  75. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_abbrevs.py +0 -0
  76. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_admonition_titles.py +0 -0
  77. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_attachment_previews.py +0 -0
  78. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_captions.py +0 -0
  79. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_changelog_config.py +0 -0
  80. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_changelog_publish.py +0 -0
  81. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_cli.py +0 -0
  82. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_editlink.py +0 -0
  83. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_emitter.py +0 -0
  84. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_exclude_properties_config.py +0 -0
  85. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_extra_css.py +0 -0
  86. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_footer.py +0 -0
  87. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_frontmatter.py +0 -0
  88. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_icons.py +0 -0
  89. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_images.py +0 -0
  90. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_internallinks.py +0 -0
  91. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_ir.py +0 -0
  92. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_linkdefs.py +0 -0
  93. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_loader.py +0 -0
  94. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_mermaid.py +0 -0
  95. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_page_loader.py +0 -0
  96. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_parser.py +0 -0
  97. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_pdf.py +0 -0
  98. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_plantuml.py +0 -0
  99. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_preprocess.py +0 -0
  100. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_preview.py +0 -0
  101. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_publish_client.py +0 -0
  102. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_publish_config.py +0 -0
  103. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_publish_pipeline.py +0 -0
  104. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_server.py +0 -0
  105. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_sync_anchoring.py +0 -0
  106. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_sync_command.py +0 -0
  107. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_sync_comments.py +0 -0
  108. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_sync_github.py +0 -0
  109. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_sync_state.py +0 -0
  110. {mkdocs2confluence-0.17.4 → mkdocs2confluence-0.18.1}/tests/test_treeutil.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs2confluence
3
- Version: 0.17.4
3
+ Version: 0.18.1
4
4
  Summary: Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more
5
5
  Author: Anders Hybertz
6
6
  License: GPL-3.0-or-later
@@ -35,7 +35,7 @@ Requires-Dist: pytest-cov; extra == "dev"
35
35
  Requires-Dist: ruff; extra == "dev"
36
36
  Requires-Dist: mypy; extra == "dev"
37
37
  Requires-Dist: types-PyYAML; extra == "dev"
38
- Requires-Dist: bandit; extra == "dev"
38
+ Requires-Dist: bandit[sarif]; extra == "dev"
39
39
  Requires-Dist: build; extra == "dev"
40
40
  Requires-Dist: pre-commit; extra == "dev"
41
41
  Dynamic: license-file
@@ -161,6 +161,7 @@ confluence:
161
161
  mermaid_render: kroki # "kroki" (default) | "kroki:https://your-kroki" | "none" — also controls PlantUML rendering
162
162
  full_width: true # default: true
163
163
  attachment_preview: false # default: false — inline PDF/Office previews
164
+ children_macro: true # default: true — child page list on section index pages
164
165
  changelog: CHANGELOG.md # optional: publish as a top-level "What's New" page
165
166
  exclude_properties: # optional: front matter keys to hide from Page Properties
166
167
  - source_documents
@@ -171,6 +172,8 @@ confluence:
171
172
 
172
173
  `attachment_preview` (bool, default `false`) renders links to local PDF/Office files (`.pdf`, `.doc(x)`, `.xls(x)`, `.ppt(x)`) as inline `view-file` previews instead of download links. Other file types always remain download links.
173
174
 
175
+ `children_macro` (bool, default `true`) controls the native Children Display macro appended to section index pages (a nav section with an `index.md`). Set it to `false` to publish those pages without the auto-generated child page list; the change takes effect on the next publish.
176
+
174
177
  The `confluence:` block is also accepted under `extra:` for MkDocs strict-mode compatibility. The API token is read from `token:` in `mkdocs.yml`, then `CONFLUENCE_API_TOKEN`, then `MK2CONF_TOKEN`.
175
178
 
176
179
  ### Changelog / What's New page
@@ -119,6 +119,7 @@ confluence:
119
119
  mermaid_render: kroki # "kroki" (default) | "kroki:https://your-kroki" | "none" — also controls PlantUML rendering
120
120
  full_width: true # default: true
121
121
  attachment_preview: false # default: false — inline PDF/Office previews
122
+ children_macro: true # default: true — child page list on section index pages
122
123
  changelog: CHANGELOG.md # optional: publish as a top-level "What's New" page
123
124
  exclude_properties: # optional: front matter keys to hide from Page Properties
124
125
  - source_documents
@@ -129,6 +130,8 @@ confluence:
129
130
 
130
131
  `attachment_preview` (bool, default `false`) renders links to local PDF/Office files (`.pdf`, `.doc(x)`, `.xls(x)`, `.ppt(x)`) as inline `view-file` previews instead of download links. Other file types always remain download links.
131
132
 
133
+ `children_macro` (bool, default `true`) controls the native Children Display macro appended to section index pages (a nav section with an `index.md`). Set it to `false` to publish those pages without the auto-generated child page list; the change takes effect on the next publish.
134
+
132
135
  The `confluence:` block is also accepted under `extra:` for MkDocs strict-mode compatibility. The API token is read from `token:` in `mkdocs.yml`, then `CONFLUENCE_API_TOKEN`, then `MK2CONF_TOKEN`.
133
136
 
134
137
  ### Changelog / What's New page
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mkdocs2confluence"
3
- version = "0.17.4"
3
+ version = "0.18.1"
4
4
  description = "Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more"
5
5
  readme = "README.md"
6
6
  license = { text = "GPL-3.0-or-later" }
@@ -52,7 +52,7 @@ dev = [
52
52
  "ruff",
53
53
  "mypy",
54
54
  "types-PyYAML",
55
- "bandit",
55
+ "bandit[sarif]",
56
56
  "build",
57
57
  "pre-commit",
58
58
  ]
@@ -74,7 +74,22 @@ where = ["src"]
74
74
  line-length = 120
75
75
 
76
76
  [tool.ruff.lint]
77
- select = ["E", "F", "I"]
77
+ # S = flake8-bandit (security), B = flake8-bugbear (likely bugs).
78
+ select = ["E", "F", "I", "S", "B"]
79
+ ignore = [
80
+ # Deliberate throughout: best-effort side effects (content hashes, managed-page
81
+ # stamps) whose failure is self-healing on the next run. Each site says so.
82
+ "S110", # try-except-pass
83
+ # Fixed argument lists only — `git log` in the footer transform and the macOS
84
+ # DYLD self-re-exec in cli.py. No user input reaches a subprocess.
85
+ "S603", "S606", "S607",
86
+ # Retry jitter in http_retry.py, not a security context.
87
+ "S311",
88
+ ]
89
+
90
+ [tool.ruff.lint.per-file-ignores]
91
+ # Tests assert freely and use throwaway credentials in fixtures.
92
+ "tests/**" = ["S101", "S105", "S106", "S107"]
78
93
 
79
94
  [tool.mypy]
80
95
  strict = true
@@ -104,7 +119,7 @@ exclude_lines = [
104
119
  ]
105
120
 
106
121
  # Architecture boundaries — enforces the compile pipeline stage separation
107
- # documented in .github/copilot-instructions.md. Higher layers may import lower
122
+ # documented in AGENTS.md. Higher layers may import lower
108
123
  # ones; siblings joined by "|" must stay independent of each other.
109
124
  [tool.importlinter]
110
125
  root_package = "mkdocs_to_confluence"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs2confluence
3
- Version: 0.17.4
3
+ Version: 0.18.1
4
4
  Summary: Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more
5
5
  Author: Anders Hybertz
6
6
  License: GPL-3.0-or-later
@@ -35,7 +35,7 @@ Requires-Dist: pytest-cov; extra == "dev"
35
35
  Requires-Dist: ruff; extra == "dev"
36
36
  Requires-Dist: mypy; extra == "dev"
37
37
  Requires-Dist: types-PyYAML; extra == "dev"
38
- Requires-Dist: bandit; extra == "dev"
38
+ Requires-Dist: bandit[sarif]; extra == "dev"
39
39
  Requires-Dist: build; extra == "dev"
40
40
  Requires-Dist: pre-commit; extra == "dev"
41
41
  Dynamic: license-file
@@ -161,6 +161,7 @@ confluence:
161
161
  mermaid_render: kroki # "kroki" (default) | "kroki:https://your-kroki" | "none" — also controls PlantUML rendering
162
162
  full_width: true # default: true
163
163
  attachment_preview: false # default: false — inline PDF/Office previews
164
+ children_macro: true # default: true — child page list on section index pages
164
165
  changelog: CHANGELOG.md # optional: publish as a top-level "What's New" page
165
166
  exclude_properties: # optional: front matter keys to hide from Page Properties
166
167
  - source_documents
@@ -171,6 +172,8 @@ confluence:
171
172
 
172
173
  `attachment_preview` (bool, default `false`) renders links to local PDF/Office files (`.pdf`, `.doc(x)`, `.xls(x)`, `.ppt(x)`) as inline `view-file` previews instead of download links. Other file types always remain download links.
173
174
 
175
+ `children_macro` (bool, default `true`) controls the native Children Display macro appended to section index pages (a nav section with an `index.md`). Set it to `false` to publish those pages without the auto-generated child page list; the change takes effect on the next publish.
176
+
174
177
  The `confluence:` block is also accepted under `extra:` for MkDocs strict-mode compatibility. The API token is read from `token:` in `mkdocs.yml`, then `CONFLUENCE_API_TOKEN`, then `MK2CONF_TOKEN`.
175
178
 
176
179
  ### Changelog / What's New page
@@ -9,7 +9,7 @@ pytest-cov
9
9
  ruff
10
10
  mypy
11
11
  types-PyYAML
12
- bandit
12
+ bandit[sarif]
13
13
  build
14
14
  pre-commit
15
15
 
@@ -274,7 +274,7 @@ def _build_parser() -> argparse.ArgumentParser:
274
274
  "Detected targets (all installed when no --tool given):\n"
275
275
  " hermes ~/.hermes/skills/tooling/mkdocs-changelog/SKILL.md\n"
276
276
  " github-skills .github/skills/tooling/mkdocs-changelog/SKILL.md\n"
277
- " claude .claude/commands/changelog.md (frontmatter stripped)\n"
277
+ " claude .claude/commands/mk2conf-changelog.md (frontmatter stripped)\n"
278
278
  " copilot .github/instructions/mk2conf-changelog.instructions.md\n"
279
279
  " cursor .cursor/rules/mk2conf-changelog.mdc\n"
280
280
  "\n"
@@ -79,7 +79,7 @@ def compile_page(
79
79
  preprocessed = strip_link_defs(preprocessed)
80
80
  ir_nodes = parse(preprocessed)
81
81
  ir_nodes = strip_links_in_admonition_titles(ir_nodes, node.docs_path or "")
82
- if is_section_index:
82
+ if is_section_index and (config.confluence is None or config.confluence.children_macro):
83
83
  ir_nodes = ir_nodes + (ChildrenMacro(),)
84
84
  # Parse definitions as inline markdown so links etc. survive into the glossary.
85
85
  parsed_abbrevs = {abbr: parse_inline(defn) for abbr, defn in abbrevs.items()}
@@ -37,6 +37,7 @@ class ConfluenceConfig:
37
37
  changelog_file: str | None = None # path relative to docs_dir; None means disabled
38
38
  exclude_properties: tuple[str, ...] = () # front matter keys to omit from Page Properties table
39
39
  attachment_preview: bool = False # render PDF/Office attachment links as view-file macros
40
+ children_macro: bool = True # append Children Display macro to section index pages
40
41
 
41
42
 
42
43
  @dataclass(frozen=True)
@@ -153,7 +154,11 @@ def load_config(mkdocs_yml: Path) -> MkDocsConfig:
153
154
  raise FileNotFoundError(f"mkdocs.yml not found: {mkdocs_yml}")
154
155
 
155
156
  with mkdocs_yml.open(encoding="utf-8") as fh:
156
- raw: object = yaml.load(fh, Loader=_make_env_loader()) # nosec B506
157
+ # B506 is suppressed below because _make_env_loader() returns a
158
+ # yaml.SafeLoader subclass — this is a safe load. Bandit cannot resolve the
159
+ # loader through the function call, so it assumes the worst. Removing the
160
+ # suppression reintroduces a medium-severity finding that fails CI.
161
+ raw: object = yaml.load(fh, Loader=_make_env_loader()) # noqa: S506 # nosec B506
157
162
 
158
163
  if not isinstance(raw, dict):
159
164
  raise ConfigError("mkdocs.yml must be a YAML mapping at the top level.")
@@ -275,7 +280,7 @@ def load_config(mkdocs_yml: Path) -> MkDocsConfig:
275
280
  raise ConfigError(
276
281
  f"mkdocs.yml: 'confluence.changelog' path {cl_str!r} "
277
282
  "escapes docs_dir. The path must be relative to the docs directory."
278
- )
283
+ ) from None
279
284
  changelog_file = cl_str
280
285
 
281
286
  # exclude_properties (optional) — raw front matter keys to omit from
@@ -300,6 +305,15 @@ def load_config(mkdocs_yml: Path) -> MkDocsConfig:
300
305
  )
301
306
  attachment_preview = raw_preview
302
307
 
308
+ # children_macro (optional) — child page list on section index pages
309
+ raw_children = raw_conf.get("children_macro", True)
310
+ if not isinstance(raw_children, bool):
311
+ raise ConfigError(
312
+ "mkdocs.yml: 'confluence.children_macro' must be a boolean, "
313
+ f"got {type(raw_children).__name__}."
314
+ )
315
+ children_macro = raw_children
316
+
303
317
  confluence = ConfluenceConfig(
304
318
  base_url=base_url.rstrip("/"),
305
319
  space_key=space_key,
@@ -317,6 +331,7 @@ def load_config(mkdocs_yml: Path) -> MkDocsConfig:
317
331
  changelog_file=changelog_file,
318
332
  exclude_properties=exclude_properties,
319
333
  attachment_preview=attachment_preview,
334
+ children_macro=children_macro,
320
335
  )
321
336
 
322
337
  # --- extra_css (optional) ---
@@ -1207,7 +1207,9 @@ def _build_tree(
1207
1207
  def _make_cell(
1208
1208
  text: str, col: int, is_header: bool = False
1209
1209
  ) -> TableCell:
1210
- align = aligns[col] if col < len(aligns) else None
1210
+ # B023 is suppressed below: _make_cell is defined and fully consumed
1211
+ # inside a single loop iteration, so aligns cannot be rebound under it.
1212
+ align = aligns[col] if col < len(aligns) else None # noqa: B023
1211
1213
  return TableCell(
1212
1214
  children=_parse_inline(text, fn_map=_fn),
1213
1215
  align=align,
@@ -294,7 +294,7 @@ def _parse_spec(
294
294
  raise IncludeError(
295
295
  f"{source_path}:{lineno}: named-section includes are not yet "
296
296
  f"supported: {raw_spec!r}"
297
- )
297
+ ) from None
298
298
  if start < 1 or end < start:
299
299
  raise IncludeError(
300
300
  f"{source_path}:{lineno}: invalid line range {start}:{end} "
@@ -7,6 +7,7 @@ Authentication is HTTP Basic with email + API token.
7
7
  from __future__ import annotations
8
8
 
9
9
  import base64
10
+ from functools import partial
10
11
  from pathlib import Path
11
12
  from typing import Any, cast
12
13
  from urllib.parse import parse_qs, urlparse
@@ -378,7 +379,9 @@ class ConfluenceClient:
378
379
  name = lbl.get("name", "")
379
380
  if name:
380
381
  http_request_with_retry(
381
- lambda: self._http.delete(label_url, params={"name": name}),
382
+ # partial binds name now; a closure would late-bind and could
383
+ # delete the wrong label if the helper ever defers the call.
384
+ partial(self._http.delete, label_url, params={"name": name}),
382
385
  f"set_page_labels({page_id!r})",
383
386
  )
384
387
 
@@ -90,13 +90,13 @@ def install_skill(
90
90
  dest.write_text(content_body, encoding="utf-8")
91
91
  installed.append(("claude", dest))
92
92
 
93
- # GitHub Copilot — project-level, body only as .instructions.md
93
+ # GitHub Copilot — .instructions.md needs applyTo frontmatter or Copilot ignores it
94
94
  if _want("copilot"):
95
95
  copilot_marker = project_dir / ".github" / "copilot-instructions.md"
96
96
  if explicit or copilot_marker.exists():
97
97
  dest = project_dir / ".github" / "instructions" / "mk2conf-changelog.instructions.md"
98
98
  dest.parent.mkdir(parents=True, exist_ok=True)
99
- dest.write_text(content_body, encoding="utf-8")
99
+ dest.write_text(f'---\napplyTo: "**"\n---\n\n{content_body}', encoding="utf-8")
100
100
  installed.append(("copilot", dest))
101
101
 
102
102
  # Cursor — project-level, body as .mdc
@@ -53,7 +53,10 @@ def kroki_post(source: str, diagram_type: str, kroki_url: str, fmt: str = "png")
53
53
  """POST *source* to Kroki for *diagram_type* and return rendered bytes."""
54
54
  url = f"{kroki_url.rstrip('/')}/{diagram_type}/{fmt}"
55
55
  body = source.encode("utf-8")
56
- req = urllib.request.Request(
56
+ # kroki_url comes from config, so the scheme is not attacker-controlled, but it is
57
+ # also not validated. Switching this to httpx (already a dependency) would restrict
58
+ # it to http/https and remove the urllib import entirely.
59
+ req = urllib.request.Request( # noqa: S310
57
60
  url,
58
61
  data=body,
59
62
  headers={
@@ -62,7 +62,7 @@ def _mermaid_ink_png(source: str) -> bytes:
62
62
  compressed = zlib.compress(payload.encode("utf-8"))
63
63
  encoded = base64.urlsafe_b64encode(compressed).decode().rstrip("=")
64
64
  url = f"{_MERMAID_INK_URL}/img/pako:{encoded}?type=png"
65
- req = urllib.request.Request(url, headers={"User-Agent": "mk2conf/1.0"})
65
+ req = urllib.request.Request(url, headers={"User-Agent": "mk2conf/1.0"}) # noqa: S310
66
66
  with urllib.request.urlopen(req, timeout=_TIMEOUT) as resp: # noqa: S310 # nosec B310
67
67
  return cast(bytes, resp.read())
68
68
 
@@ -92,9 +92,89 @@ def test_compile_page_children_macro_before_footer(tmp_path: Path) -> None:
92
92
  assert children_pos < panel_pos
93
93
 
94
94
 
95
+ # ── children_macro config flag ────────────────────────────────────────────────
96
+
97
+
98
+ def test_children_macro_disabled_omits_macro(tmp_path: Path) -> None:
99
+ """confluence.children_macro=false must suppress the macro on section indexes."""
100
+ xhtml = _compile_index(tmp_path, children_macro=False)
101
+
102
+ assert 'ac:name="children"' not in xhtml
103
+
104
+
105
+ def test_children_macro_enabled_by_default(tmp_path: Path) -> None:
106
+ """A confluence block without children_macro must keep the macro."""
107
+ xhtml = _compile_index(tmp_path, children_macro=True)
108
+
109
+ assert 'ac:name="children"' in xhtml
110
+
111
+
112
+ def test_children_macro_config_default_true(tmp_path: Path) -> None:
113
+ from mkdocs_to_confluence.loader.config import load_config
114
+
115
+ cfg = load_config(_write_mkdocs(tmp_path, _CONF))
116
+ assert cfg.confluence.children_macro is True
117
+
118
+
119
+ def test_children_macro_config_false(tmp_path: Path) -> None:
120
+ from mkdocs_to_confluence.loader.config import load_config
121
+
122
+ cfg = load_config(_write_mkdocs(tmp_path, _CONF + " children_macro: false\n"))
123
+ assert cfg.confluence.children_macro is False
124
+
125
+
126
+ def test_children_macro_config_non_bool_raises(tmp_path: Path) -> None:
127
+ import pytest
128
+
129
+ from mkdocs_to_confluence.loader.config import ConfigError, load_config
130
+
131
+ with pytest.raises(ConfigError, match="children_macro"):
132
+ load_config(_write_mkdocs(tmp_path, _CONF + " children_macro: maybe\n"))
133
+
134
+
95
135
  # ── Helpers ───────────────────────────────────────────────────────────────────
96
136
 
97
137
 
138
+ _CONF = (
139
+ "confluence:\n"
140
+ " base_url: https://x.atlassian.net/wiki\n"
141
+ " email: a@b.test\n"
142
+ " space_key: TECH\n"
143
+ )
144
+
145
+
146
+ def _write_mkdocs(tmp_path: Path, extra: str = "") -> Path:
147
+ (tmp_path / "docs").mkdir()
148
+ (tmp_path / "mkdocs.yml").write_text(f"site_name: Test Site\n{extra}", encoding="utf-8")
149
+ return tmp_path / "mkdocs.yml"
150
+
151
+
152
+ def _compile_index(tmp_path: Path, *, children_macro: bool) -> str:
153
+ """Compile a section index page with a confluence block set to *children_macro*."""
154
+ from mkdocs_to_confluence.loader.config import ConfluenceConfig, MkDocsConfig
155
+
156
+ docs = tmp_path / "docs"
157
+ docs.mkdir()
158
+ md = docs / "index.md"
159
+ md.write_text("# Section\n\nIntro.\n", encoding="utf-8")
160
+
161
+ config = MkDocsConfig(
162
+ site_name="Test",
163
+ docs_dir=docs,
164
+ repo_url=None,
165
+ edit_uri=None,
166
+ nav=None,
167
+ confluence=ConfluenceConfig(
168
+ base_url="https://x.atlassian.net/wiki",
169
+ email="a@b.test",
170
+ token="",
171
+ space_key="TECH",
172
+ children_macro=children_macro,
173
+ ),
174
+ )
175
+ return compile_page(_page_node("Section", md), config, is_section_index=True).xhtml
176
+
177
+
98
178
  def _page_node(title: str, path: Path) -> object:
99
179
  from mkdocs_to_confluence.loader.nav import NavNode
100
180
 
@@ -64,6 +64,8 @@ def test_install_skill_copilot(tmp_path: Path) -> None:
64
64
  assert dest.name == "mk2conf-changelog.instructions.md"
65
65
  content = dest.read_text(encoding="utf-8")
66
66
  assert "name: mkdocs-changelog" not in content
67
+ # Copilot ignores .instructions.md files without applyTo frontmatter
68
+ assert content.startswith('---\napplyTo: "**"\n---\n\n# MkDocs Changelog Entry')
67
69
 
68
70
 
69
71
  def test_install_skill_cursor(tmp_path: Path) -> None: