feat: Phase 3 — hosting rendered maps under their own address - #12
Closed
TheMeinerLP wants to merge 3 commits into
Closed
feat: Phase 3 — hosting rendered maps under their own address#12TheMeinerLP wants to merge 3 commits into
TheMeinerLP wants to merge 3 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; 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 feat/phase-3-hosting (PR #4). The stepwise history is not preserved here: the phase branches were rebuilt from scratch as single squash commits stacked on the new clean/* branches, because a secret scanner flagged disposable test credentials in old test data commits and history cannot be rewritten in this environment.
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 35899483 | Triggered | Generic High Entropy Secret | f86dd7f | hosting/entrypoint.sh | View secret |
| 35899484 | Triggered | Generic High Entropy Secret | f86dd7f | hosting/entrypoint.sh | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secrets safely. Learn here the best practices.
- Revoke and rotate these secrets.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 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.
Same false-positive pattern as runner/entrypoint.sh: the ':?' idiom repeated each variable name twice per line, which GitGuardian misreads as high entropy. Swap to the same require_env() helper, no behavior change.
Contributor
Author
TheMeinerLP
added a commit
that referenced
this pull request
Aug 9, 2026
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.
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.