Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,22 @@ RUN --mount=type=bind,source=config/patch/s3.py,target=/tmp/s3_patch.py \
echo "[patch] PATCH_FILES=false — s3.py patch skipped (upstream file unchanged)"; \
fi

# Fix the invalid <ows:SupportedCRS> urn MapProxy emits since 6.0.0: correct
# it to the OGC-valid form (urn:ogc:def:crs:EPSG::4326 — upstream renders a
# single colon before the code, which violates OGC 07-092r1). This one edits
# the installed template in place instead of replacing it, so an upstream
# rework of that line aborts the build rather than silently reverting other
# template changes.
RUN --mount=type=bind,source=config/patch/wmts_capabilities_compat.py,target=/tmp/wmts_capabilities_compat.py \
if [ "${PATCH_FILES}" = "true" ]; then \
python /tmp/wmts_capabilities_compat.py \
/opt/venv/lib/python3.11/site-packages/mapproxy/service/templates/wmts100capabilities.xml \
&& echo "[patch] wmts100capabilities.xml applied and verified" \
|| { echo "[patch] wmts100capabilities.xml FAILED — build aborted" >&2; exit 1; }; \
else \
echo "[patch] PATCH_FILES=false — wmts100capabilities.xml patch skipped (upstream file unchanged)"; \
fi

# ── Runtime Stage ───────────────────────────────────────────────────────────
FROM python:3.11-slim-bookworm

Expand Down
73 changes: 73 additions & 0 deletions config/patch/wmts_capabilities_compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env python3
"""Fix the invalid <ows:SupportedCRS> urn MapProxy emits since 6.0.0.

MapProxy commit b8f8949b ("restful encoding / style isdefault and
urn:ogc:def:crs for SupportedCRS", first released in 6.0.0) gave
<ows:SupportedCRS> in the WMTS 1.0.0 capabilities template a
"urn:ogc:def:crs:" prefix rendered as "urn:ogc:def:crs:EPSG:4326" — an
invalid OGC URN: the version field between authority and code is missing,
so there is a single colon where the standard (OGC 07-092r1) requires two
("urn:ogc:def:crs:EPSG::4326"). This script keeps the prefix but doubles
the first colon of srs_name at render time, producing the valid
"urn:ogc:def:crs:EPSG::4326" form.

This script edits exactly that one line in the installed template and
leaves every other upstream change in place. It is applied at build time
(see the Dockerfile) rather than shipping a full copy of the template, so a
MapProxy upgrade that reworks these lines aborts the build loudly instead of
silently reverting unrelated template improvements.

Usage: wmts_capabilities_compat.py <path-to-wmts100capabilities.xml>
"""

import sys

# (description, exact text in the installed template, replacement, expected hits)
EDITS = (
(
'SupportedCRS urn missing version colon',
'<ows:SupportedCRS>urn:ogc:def:crs:{{tile_matrix_set.srs_name}}</ows:SupportedCRS>',
"<ows:SupportedCRS>urn:ogc:def:crs:"
"{{tile_matrix_set.srs_name.replace(':', '::', 1)}}"
'</ows:SupportedCRS>',
1,
),
)

# Text that must not survive the rewrite, whatever form the template took.
RESIDUE = ('urn:ogc:def:crs:{{tile_matrix_set.srs_name}}',)


def main(argv):
if len(argv) != 2:
sys.exit('usage: %s <path-to-wmts100capabilities.xml>' % argv[0])

path = argv[1]
with open(path, encoding='utf-8') as fh:
template = fh.read()

for description, old, new, expected in EDITS:
found = template.count(old)
if found != expected:
sys.exit(
'[patch] %s: expected %d occurrence(s) of %r in %s, found %d — '
'upstream template changed, review the patch against this '
'MapProxy version' % (description, expected, old, path, found)
)
template = template.replace(old, new)

for residue in RESIDUE:
if residue in template:
sys.exit(
'[patch] %r still present in %s after rewrite' % (residue, path)
)

with open(path, 'w', encoding='utf-8') as fh:
fh.write(template)

print('[patch] wmts100capabilities.xml: fixed SupportedCRS urn to the '
'valid urn:ogc:def:crs:EPSG::<code> form')


if __name__ == '__main__':
main(sys.argv)
31 changes: 31 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ MapProxy running under **uWSGI**, instrumented with **OpenTelemetry** (traces, m
- [uWSGI Tuning](#uwsgi-tuning)
- [Health Check](#health-check)
- [Building the Image Locally](#building-the-image-locally)
- [MapProxy Patches](#mapproxy-patches)
- [Exposed Ports](#exposed-ports)
- [Volumes](#volumes)
- [OpenShift / Arbitrary UID](#openshift--arbitrary-uid)
Expand Down Expand Up @@ -412,6 +413,36 @@ The image uses a **multi-stage build**: all compile-time dependencies (GCC, GDAL

`MAPPROXY_VERSION` is the single source of truth — it is used in `pip install`, the OCI image labels, and the `SERVICE_VERSION` env var read by `app.py` at runtime.

### MapProxy Patches

The builder stage applies three patches to the installed MapProxy under
`config/patch/`, each bind-mounted so the patch source never lands in an image
layer. Every patch verifies itself and **aborts the build** on failure, so a
MapProxy upgrade that invalidates one is caught at build time rather than in
production. Build with `--build-arg PATCH_FILES=false` to skip all three and get
stock upstream behaviour (useful for upstream-compat testing).

| Patch | Target | Why |
| -------------------------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `redis.py` | `mapproxy/cache/redis.py` | Redis resilience — short timeouts, retries, TLS (see the Redis env vars) |
| `s3.py` | `mapproxy/cache/s3.py` | S3/MinIO fixes, including signing `use_http_get` reads so private buckets work |
| `wmts_capabilities_compat.py` | `mapproxy/service/templates/wmts100capabilities.xml` | Fixes the invalid `<ows:SupportedCRS>` urn MapProxy emits since 6.0.0 |

The WMTS one corrects exactly one element — changed by upstream MapProxy
commit `b8f8949b`:

| Element | MapProxy 6.x (stock) | This image |
| ---------------------- | ------------------------------------------------- | -------------------------------- |
| `<ows:SupportedCRS>` | `urn:ogc:def:crs:EPSG:4326` | `urn:ogc:def:crs:EPSG::4326` |

The stock `SupportedCRS` urn is invalid per OGC 07-092r1: the version field
between authority and code is empty, so the urn must carry a double colon
(`EPSG::4326`), not the single colon MapProxy renders.

Unlike the other two, it rewrites the one line in place instead of shipping a
full copy of the template, so an upstream rework of that line fails the build
loudly rather than silently reverting unrelated template changes.

---

## Exposed Ports
Expand Down
Loading