check-opencloud-security 1.22.2__tar.gz → 1.22.4__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 (113) hide show
  1. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/CHANGELOG.md +29 -0
  2. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/PKG-INFO +1 -1
  3. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/adr/README.md +3 -2
  4. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/pyproject.toml +1 -1
  5. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_check_pull_request.py +16 -27
  6. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_docker_wizard.py +78 -1
  7. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/.gitignore +0 -0
  8. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/LICENSE +0 -0
  9. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/README.md +0 -0
  10. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/ansible/README.md +0 -0
  11. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/authentik/README.md +0 -0
  12. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/check_opencloud_security.py +0 -0
  13. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/config/README.md +0 -0
  14. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/contrib/README.md +0 -0
  15. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/docker/README.md +0 -0
  16. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/docs/README.md +0 -0
  17. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/img/README.md +0 -0
  18. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/README.md +0 -0
  19. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/__init__.py +0 -0
  20. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/advisory_source.py +0 -0
  21. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/baseline.py +0 -0
  22. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/caa.py +0 -0
  23. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/cli.py +0 -0
  24. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/completion.py +0 -0
  25. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/config.py +0 -0
  26. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/data/release_schedule.json +0 -0
  27. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/data/vulnerabilities.json +0 -0
  28. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/data_signing.py +0 -0
  29. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/dns.py +0 -0
  30. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/dnssec.py +0 -0
  31. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/factory.py +0 -0
  32. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/fetch.py +0 -0
  33. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/hardening.py +0 -0
  34. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/prometheus.py +0 -0
  35. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/refresh_data.py +0 -0
  36. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/releases.py +0 -0
  37. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/remediation.py +0 -0
  38. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/scanner.py +0 -0
  39. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/schedule_source.py +0 -0
  40. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/secrets.py +0 -0
  41. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/selfupdate.py +0 -0
  42. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/service.py +0 -0
  43. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/snippets.py +0 -0
  44. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/tls.py +0 -0
  45. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/versions.py +0 -0
  46. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/vulndb.py +0 -0
  47. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/opencloud_local_scan/wizard.py +0 -0
  48. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/packaging/README.md +0 -0
  49. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/packaging/tests/install-smoke.sh +0 -0
  50. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/scripts/README.md +0 -0
  51. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/secrets/README.md +0 -0
  52. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/security/advisories/README.md +0 -0
  53. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/__init__.py +0 -0
  54. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/conftest.py +0 -0
  55. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/fake_opencloud.py +0 -0
  56. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/integration/test_real_opencloud.py +0 -0
  57. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_address_parity.py +0 -0
  58. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_advisory_checks.py +0 -0
  59. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_advisory_headers.py +0 -0
  60. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_baseline.py +0 -0
  61. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_caa.py +0 -0
  62. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_cli_explain.py +0 -0
  63. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_companions.py +0 -0
  64. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_completion.py +0 -0
  65. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_concurrency.py +0 -0
  66. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_config.py +0 -0
  67. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_contract_documents.py +0 -0
  68. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_contrib_assets.py +0 -0
  69. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_cross_origin.py +0 -0
  70. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_data_signing.py +0 -0
  71. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_diff_command.py +0 -0
  72. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_distro_packaging.py +0 -0
  73. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_dns.py +0 -0
  74. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_dnssec.py +0 -0
  75. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_documentation_indexes.py +0 -0
  76. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_documentation_links.py +0 -0
  77. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_e2e_cli.py +0 -0
  78. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_env_config.py +0 -0
  79. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_explain.py +0 -0
  80. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_forwarded_host.py +0 -0
  81. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_frontend_documentation.py +0 -0
  82. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_github_action.py +0 -0
  83. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_hardening.py +0 -0
  84. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_homebrew_formula.py +0 -0
  85. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_local_scanner.py +0 -0
  86. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_multi_host.py +0 -0
  87. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_output_formats.py +0 -0
  88. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_perfdata.py +0 -0
  89. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_prometheus.py +0 -0
  90. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_rating_thresholds.py +0 -0
  91. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_redis_contract.py +0 -0
  92. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_reference_data_limits.py +0 -0
  93. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_refresh_data.py +0 -0
  94. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_release_dry_run.py +0 -0
  95. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_release_notes.py +0 -0
  96. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_release_schedule.py +0 -0
  97. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_releases.py +0 -0
  98. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_remediation.py +0 -0
  99. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_render_architecture_diagrams.py +0 -0
  100. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_security_advisories.py +0 -0
  101. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_selfupdate.py +0 -0
  102. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_service.py +0 -0
  103. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_settings_completeness.py +0 -0
  104. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_snippets.py +0 -0
  105. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_ssrf_pinning.py +0 -0
  106. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_tls.py +0 -0
  107. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_update_script.py +0 -0
  108. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_version.py +0 -0
  109. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_vulndb.py +0 -0
  110. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_waivers.py +0 -0
  111. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_webhook.py +0 -0
  112. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_wizard.py +0 -0
  113. {check_opencloud_security-1.22.2 → check_opencloud_security-1.22.4}/tests/test_workflow_hardening.py +0 -0
@@ -12,6 +12,35 @@ entry to `RELEASE.md` and uses it as the body of the GitHub release.
12
12
 
13
13
  ## [Unreleased]
14
14
 
15
+ ## [1.22.4] - 2026-09-13
16
+
17
+ ### Changed
18
+
19
+ - **A pull request documents itself in `CHANGELOG.md` alone.**
20
+ `scripts/check_pull_request.py` no longer requires `RELEASE.md` to change or
21
+ its heading to name the version in `pyproject.toml`, and the test that
22
+ compared the two in the repository is gone. The release workflow writes
23
+ `RELEASE.md` from `## [Unreleased]` and overwrites it, so an entry copied
24
+ there by hand was discarded, and between a bump and its release the file
25
+ rightly still names the last release - which failed the suite on a branch
26
+ with nothing wrong in it. `AGENTS.md`, `CLAUDE.md`, `CONTRIBUTING.md` and the
27
+ pull request template now say to leave it to the release. See ADR 0048.
28
+
29
+ ### Fixed
30
+
31
+ - **A Docker setup wizard downloaded on its own writes the Authentik
32
+ blueprints.** `docker/README.md` says to `curl` just `setup-wizard.py`, but
33
+ the wizard copied the blueprints from a checkout beside it and skipped any
34
+ it could not find without a word. The generated stack mounted
35
+ `./authentik/blueprints` anyway, Docker created it empty, and Authentik
36
+ started with no provider: `/mcp` refused every token, and the forward auth
37
+ in front of `/admin` answered 404, which nginx turns into a 500. The wizard
38
+ now carries the four blueprints itself, generated into it from
39
+ `authentik/blueprints/` by `scripts/embed_wizard_blueprints.py`, and a test
40
+ fails when the embedded copies differ from those files. A deployment set up
41
+ with an earlier download gets them by re-running the wizard.
42
+ - Fixed version bump.
43
+
15
44
  ## [1.22.2] - 2026-09-13
16
45
 
17
46
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: check-opencloud-security
3
- Version: 1.22.2
3
+ Version: 1.22.4
4
4
  Summary: Check the security level of your OpenCloud instance with a built-in scanner - no API access required
5
5
  Project-URL: Homepage, https://github.com/sowoi/check-opencloud-security
6
6
  Project-URL: Live demo, https://scan.okxo.de
@@ -51,9 +51,10 @@ project. Read the accepted records that affect an area before changing it.
51
51
  | [0042](0042-every-resolved-address-is-compared-only-when-the-operator-asks.md) | Every resolved address is compared only when the operator asks | Accepted |
52
52
  | [0043](0043-an-operators-exclusion-outranks-every-allowance.md) | An operator's exclusion outranks every allowance | Accepted |
53
53
  | [0044](0044-the-operator-area-may-write-the-exclusions.md) | The operator's area may write the exclusions, and nothing else | Accepted |
54
- | [0045](0045-a-release-is-rehearsed-on-the-pull-request-and-publishes-last.md) | A release is rehearsed on the pull request and publishes last | Accepted; its pull request policy superseded by ADR 0046 |
55
- | [0046](0046-a-release-needs-no-label-and-the-pull-request-policy-is-local.md) | A release needs no label, and the pull request policy is local | Accepted |
54
+ | [0045](0045-a-release-is-rehearsed-on-the-pull-request-and-publishes-last.md) | A release is rehearsed on the pull request and publishes last | Accepted; its pull request policy superseded by ADR 0046, its `RELEASE.md` requirement by ADR 0048 |
55
+ | [0046](0046-a-release-needs-no-label-and-the-pull-request-policy-is-local.md) | A release needs no label, and the pull request policy is local | Accepted; its `RELEASE.md` requirement superseded by ADR 0048 |
56
56
  | [0047](0047-the-bundled-provider-requires-a-second-factor-and-provisions-its-accounts.md) | The bundled provider requires a second factor and provisions its accounts | Accepted |
57
+ | [0048](0048-release-md-is-written-by-the-release-not-by-a-pull-request.md) | RELEASE.md is written by the release, not by a pull request | Accepted |
57
58
 
58
59
  ## Writing a new record
59
60
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "check-opencloud-security"
3
- version = "1.22.2"
3
+ version = "1.22.4"
4
4
  description = "Check the security level of your OpenCloud instance with a built-in scanner - no API access required"
5
5
  authors = [{ name = "Massoud Ahmed" }]
6
6
  requires-python = ">=3.10"
@@ -1,7 +1,7 @@
1
1
  """Tests for scripts/check_pull_request.py.
2
2
 
3
3
  Two rules used to live only as checkboxes in the pull request template: that
4
- every change is written up in CHANGELOG.md and RELEASE.md, and that a version
4
+ every change is written up in CHANGELOG.md, and that a version
5
5
  bump - which publishes to PyPI the moment it lands - moves forward and says
6
6
  what it is. These tests hold the script that checks them to failing when it
7
7
  should, and to staying quiet when it should.
@@ -52,13 +52,12 @@ RELEASE = "## check-opencloud-security {version}\n\n{body}\n"
52
52
  def documented(**overrides: object) -> dict:
53
53
  """A pull request that documents itself, so a test can break one thing."""
54
54
  arguments: dict = {
55
- "changed_files": ["webapp/app.py", "CHANGELOG.md", "RELEASE.md"],
55
+ "changed_files": ["webapp/app.py", "CHANGELOG.md"],
56
56
  "labels": set(),
57
57
  "author": "a-contributor",
58
58
  "version": "1.1.0",
59
59
  "base_changelog": CHANGELOG.format(unreleased=""),
60
60
  "head_changelog": CHANGELOG.format(unreleased="### Fixed\n\n- A thing."),
61
- "head_release": RELEASE.format(version="1.1.0", body="- A thing."),
62
61
  }
63
62
  arguments.update(overrides)
64
63
  return arguments
@@ -108,21 +107,18 @@ def test_an_entry_under_the_declared_version_counts():
108
107
  assert script.check_changelog(**documented(base_changelog=base, head_changelog=head)) == []
109
108
 
110
109
 
111
- def test_a_change_missing_from_release_md_is_refused():
112
- """AGENTS.md asks for both files; the release body comes from the second."""
113
- problems = script.check_changelog(**documented(changed_files=["webapp/app.py", "CHANGELOG.md"]))
114
-
115
- assert any("RELEASE.md is unchanged" in p for p in problems)
116
- assert not any("CHANGELOG.md" in p and "no new entry" in p for p in problems)
117
-
118
-
119
- def test_release_md_written_for_another_version_is_refused():
120
- """Entries under a stale heading are notes for a release that already went out."""
110
+ def test_release_md_is_not_asked_of_a_pull_request():
111
+ """The release workflow writes RELEASE.md from the changelog and overwrites it."""
112
+ assert script.check_changelog(**documented()) == []
113
+ # Touching it is not a substitute for the changelog entry it is written from.
121
114
  problems = script.check_changelog(
122
- **documented(head_release=RELEASE.format(version="1.0.0", body="- A thing."))
115
+ **documented(
116
+ changed_files=["webapp/app.py", "RELEASE.md"],
117
+ head_changelog=CHANGELOG.format(unreleased=""),
118
+ )
123
119
  )
124
-
125
- assert any("RELEASE.md is written for 1.0.0" in p for p in problems)
120
+ assert any("CHANGELOG.md has no new entry" in p for p in problems)
121
+ assert not any("RELEASE.md" in p for p in problems)
126
122
 
127
123
 
128
124
  @pytest.mark.parametrize(
@@ -196,14 +192,6 @@ def test_the_project_version_ignores_other_tables():
196
192
  assert script.project_version(PYPROJECT.format(version="1.2.3")) == "1.2.3"
197
193
 
198
194
 
199
- def test_the_repository_documents_releases_under_the_heading_the_check_reads():
200
- """Checked against the real files, so a renamed heading fails here, not on every pull request."""
201
- pyproject = (REPO_ROOT / "pyproject.toml").read_text(encoding="utf-8")
202
- release = (REPO_ROOT / "RELEASE.md").read_text(encoding="utf-8")
203
-
204
- assert script.release_heading_version(release) == script.project_version(pyproject)
205
-
206
-
207
195
  # --- the whole script, against a real repository -----------------------------
208
196
 
209
197
 
@@ -236,11 +224,13 @@ def test_the_script_passes_a_documented_bump_end_to_end(repo, capsys):
236
224
  """Everything wired together: diff, versions, tags and commit subjects."""
237
225
  (repo / "app.py").write_text("x = 2\n", encoding="utf-8")
238
226
  (repo / "CHANGELOG.md").write_text(CHANGELOG.format(unreleased="### Fixed\n\n- x."), encoding="utf-8")
239
- (repo / "RELEASE.md").write_text(RELEASE.format(version="1.0.0", body="- First.\n- x."), encoding="utf-8")
240
227
  _git(repo, "commit", "-qam", "fix: x")
241
228
  (repo / "pyproject.toml").write_text(PYPROJECT.format(version="1.1.0"), encoding="utf-8")
242
- (repo / "RELEASE.md").write_text(RELEASE.format(version="1.1.0", body="- x."), encoding="utf-8")
243
229
  _git(repo, "commit", "-qam", "chore(release): bump to version 1.1.0")
230
+ # RELEASE.md still describes 1.0.0, as it does until the release rewrites it.
231
+ assert (repo / "RELEASE.md").read_text(encoding="utf-8").startswith(
232
+ "## check-opencloud-security 1.0.0"
233
+ )
244
234
 
245
235
  assert script.main(["--base", "main"]) == 0
246
236
  assert "version 1.1.0 is in order" in capsys.readouterr().out
@@ -250,7 +240,6 @@ def test_the_script_refuses_a_mislabelled_bump_commit_end_to_end(repo, capsys):
250
240
  """The subject check reads the version each commit actually set, from git."""
251
241
  (repo / "CHANGELOG.md").write_text(CHANGELOG.format(unreleased="### Fixed\n\n- x."), encoding="utf-8")
252
242
  (repo / "pyproject.toml").write_text(PYPROJECT.format(version="1.1.0"), encoding="utf-8")
253
- (repo / "RELEASE.md").write_text(RELEASE.format(version="1.1.0", body="- x."), encoding="utf-8")
254
243
  _git(repo, "commit", "-qam", "Bump to version 1.3.3")
255
244
 
256
245
  assert script.main(["--base", "main"]) == 1
@@ -437,7 +437,9 @@ def test_the_wizard_names_no_real_host(tmp_path: Path) -> None:
437
437
  """Placeholders only, in the questions as well as in the generated files."""
438
438
  import re
439
439
 
440
- source = WIZARD_PATH.read_text(encoding="utf-8")
440
+ # Without escapes: the embedded blueprints carry redirect URIs as regular
441
+ # expressions, and `127\.0\.0\.1` is still the loopback address.
442
+ source = WIZARD_PATH.read_text(encoding="utf-8").replace("\\", "")
441
443
  allowed = {
442
444
  "127.0.0.1",
443
445
  "0.0.0.0",
@@ -581,6 +583,81 @@ def test_the_blueprint_travels_beside_the_compose_file_that_mounts_it(
581
583
  assert not (tmp_path / "plain" / "authentik").exists()
582
584
 
583
585
 
586
+ def test_a_wizard_downloaded_on_its_own_still_writes_every_blueprint(
587
+ tmp_path: Path,
588
+ ) -> None:
589
+ """The README says to curl the one file; the blueprints must not need a checkout."""
590
+ download = tmp_path / "download"
591
+ download.mkdir()
592
+ lone_wizard = download / "setup-wizard.py"
593
+ lone_wizard.write_bytes(WIZARD_PATH.read_bytes())
594
+ assert not (tmp_path / "authentik").exists()
595
+
596
+ spec = importlib.util.spec_from_file_location("lone_setup_wizard", lone_wizard)
597
+ assert spec and spec.loader
598
+ lone = importlib.util.module_from_spec(spec)
599
+ sys.modules[spec.name] = lone
600
+ try:
601
+ spec.loader.exec_module(lone)
602
+ setup = lone.Setup(
603
+ enable_mcp=True,
604
+ mcp_auth_enabled=True,
605
+ admin_enabled=True,
606
+ admin_users="okko",
607
+ deploy_authentik=True,
608
+ public_base_url="https://scan.example.com",
609
+ )
610
+ lone._generate_unattended(setup)
611
+ lone._finalise(setup)
612
+ output = tmp_path / "deployment"
613
+ written = lone.write_files(
614
+ setup, output / "docker-compose.yml", output / ".env"
615
+ )
616
+ finally:
617
+ del sys.modules[spec.name]
618
+
619
+ repository_blueprints = WIZARD_PATH.parent.parent / "authentik" / "blueprints"
620
+ blueprints = output / "authentik" / "blueprints"
621
+ names = sorted(path.name for path in blueprints.iterdir())
622
+ assert names == [
623
+ "opencloud-admin.yaml",
624
+ "opencloud-enrollment.yaml",
625
+ "opencloud-mfa.yaml",
626
+ "opencloud-scanner.yaml",
627
+ ]
628
+ for name in names:
629
+ assert (blueprints / name).read_text(encoding="utf-8") == (
630
+ repository_blueprints / name
631
+ ).read_text(encoding="utf-8")
632
+ assert any(item.endswith(name) for item in written)
633
+ # Nothing was read from, or written to, where a checkout would have been.
634
+ assert not (tmp_path / "authentik").exists()
635
+
636
+
637
+ def test_the_embedded_blueprints_are_the_ones_in_the_repository() -> None:
638
+ """A blueprint edited without re-embedding would ship the old one to every download."""
639
+ spec = importlib.util.spec_from_file_location(
640
+ "embed_wizard_blueprints",
641
+ WIZARD_PATH.parent.parent / "scripts" / "embed_wizard_blueprints.py",
642
+ )
643
+ assert spec and spec.loader
644
+ embed = importlib.util.module_from_spec(spec)
645
+ spec.loader.exec_module(embed)
646
+
647
+ assert embed.is_current(), "run python scripts/embed_wizard_blueprints.py"
648
+
649
+ # And the check does notice a block that has fallen behind: an edit inside
650
+ # it is what regenerating puts right, and nothing outside it is touched.
651
+ source = WIZARD_PATH.read_text(encoding="utf-8")
652
+ block_start = source.index(embed.START_MARKER)
653
+ stale = source[:block_start] + source[block_start:].replace(
654
+ "authentik_", "stale_", 1
655
+ )
656
+ assert stale != source
657
+ assert embed.render_wizard(stale) == source
658
+ assert set(wizard_module.EMBEDDED_BLUEPRINTS) == set(embed.BLUEPRINT_NAMES)
659
+
660
+
584
661
  def test_a_mail_server_is_configured_without_its_password_reaching_the_compose_file(
585
662
  tmp_path: Path, monkeypatch: pytest.MonkeyPatch
586
663
  ) -> None: