feat: Phase 3 — hosting rendered maps under their own address - #20
Open
TheMeinerLP wants to merge 2 commits into
Open
feat: Phase 3 — hosting rendered maps under their own address#20TheMeinerLP wants to merge 2 commits into
TheMeinerLP wants to merge 2 commits into
Conversation
Hosting layer on top of Phase 2b. A rendered map now becomes reachable under its own address. A BlueMapHosting resource produces a BlueMap webserver Deployment that reads the finished maps straight from S3, plus Service, Ingress and — where cert-manager is present — a Certificate, and reports the URL back in status. - BlueMapHosting CRD (maps to publish, hostname, ingress class, TLS, replicas); BlueMapConfigBuilder.buildForHosting for the multi-map config plus webserver.conf; a hosting image running the BlueMap CLI in webserver mode with the S3 storage addon, whose entrypoint validates its required environment variables with the same single-mention helper function as the Phase 1 runner image; HostingResourceBuilder for the owned Deployment/Service/Ingress/Certificate; BlueMapHostingReconciler wiring it together, enforcing tenant isolation, restarting pods on config change. - Closes two multi-tenancy holes found in security review: hostnames were never checked against Tenant.spec.hosting.allowedDomains, so a tenant could claim another tenant's hostname; and referenced maps were not confined to the hosting's own namespace, so a hosting could have published another tenant's maps. Both are now enforced with a condition instead of silently proceeding. - Fixes bugs only a real cluster surfaced: ConfigMap data keys may not contain `/` (generated keys are now sanitised, nesting restored via the volume's items[].path); Certificate.CertificateStatus was an empty class that crashed Jackson on any real client write; `-w` alone serves 404 for everything until `-g` has run once. - 204 operator unit tests, plus 8 integration tests against real k3s, including the client.supports(Certificate.class) branch that the mock server could never exercise. This branch replaces clean/phase-3-hosting (PR #12), stacked on clean2/phase-2b-ingest instead of clean/phase-2b-ingest, and squashed on a base where the hosting entrypoint's environment-variable validation already uses the helper function, so no follow-up fix commit is needed to clear the scanner finding.
️✅ There are no secrets present in this pull request anymore.If these secrets were true positive and are still valid, we highly recommend you to revoke them. 🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request. |
TheMeinerLP
force-pushed
the
clean2/phase-2b-ingest
branch
from
August 9, 2026 10:30
98276bd to
e31fa4a
Compare
TheMeinerLP
force-pushed
the
clean2/phase-3-hosting
branch
from
August 9, 2026 10:30
cb571e5 to
0a64b11
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 3 of Apus: hosting. Stacked on PR #3 (phase 2b), which must land first.
A rendered map now becomes reachable under its own address. A
BlueMapHostingresourceproduces a BlueMap webserver Deployment that reads the finished maps straight from S3,
plus Service, Ingress and — where cert-manager is present — a Certificate, and reports
the URL back in status.
What this delivers
BlueMapHostingCRDBlueMapConfigBuilder.buildForHostingwebserver.conf— the case the env-var contract cannot coverhostingimageHostingResourceBuilderBlueMapHostingReconcilerBlueMapConfigBuilderwas built in phase 2a, found to be pointless for the render path,and deliberately kept unwired with a javadoc note saying phase 3 would need it. That is
exactly what happened.
Two multi-tenancy holes, closed here
Both were reported by a security review of the merged builder code.
Hostnames were never checked against the tenant's allowed domains.
Tenant.spec.hosting.allowedDomainswas documented in the spec but modelled nowhere and enforced by nobody — so a tenant could
have claimed another tenant's hostname and taken over its traffic. The reconciler now
resolves the owning tenant via the namespace label, matches the hostname (literal or
single-level wildcard, mirroring wildcard-TLS semantics) and refuses with a condition
instead of creating an Ingress. An empty domain list means "not configured", not
"unrestricted".
Referenced maps were not confined to the hosting's own namespace. A hosting could have
published another tenant's maps. Maps are now resolved only within the hosting's namespace;
a missing one is an error, not a hint to look elsewhere.
Bugs the real cluster found that mocks could not
/. The generated config used logical keys likemaps/survival-overworld.conf; the mock server accepted them, a real API server rejectsthem outright. Keys are now sanitised, with the nested path restored through the volume's
items[].path, where slashes are legal. Without the cluster test this would have brokenevery hosting in production.
Certificate.CertificateStatuswas a genuinely empty class, which crashes Jackson onany real client write. Invisible while only the pure builder was under test.
-walone serves 404 for everything until-ghas run once — found by actuallyrunning the image, not by reading flags.
Testing
204 operator unit tests, plus 8 integration tests against real k3s. The
client.supports(Certificate.class)branch is now genuinely exercised: on a cert-manager-lesscluster it returns false and the reconciler blocks the whole hosting rather than silently
skipping TLS. That branch was previously untestable — the mock server always answers true.
Explicitly not covered
hosting pod serves real tiles over HTTP via a direct call.
BlueMapMap.status.bucket, as in the existing operator integration test.the background security review.