Skip to content

Add the Plone 3.0 legacy image - #203

Merged
ericof merged 1 commit into
mainfrom
issue-187
Aug 28, 2026
Merged

ericof merged 1 commit into
mainfrom
issue-187

Conversation

@ericof

@ericof ericof commented Aug 28, 2026

Copy link
Copy Markdown
Member

Adds the Plone 3.0 image — the seventh series of the legacy matrix, the first tarball-era image, and the last port that needs new shared scripts.

These images are for content extraction, migration rehearsal and archaeology only. The stacks have known, unpatched security issues and must never be exposed.

Closes #187

This is the seam

build-elementtree.sh and docker-entrypoint.sh both arrive here. That completes the shared set — legacy/shared/ now matches the source repository's file list exactly:

Series Closure
3.0 needed 2 new scripts ← this PR
2.5, 2.1, 2.0, 1.0 already fully satisfied

So the remaining four ports are copy-and-wire, with no new shared code. build-plone-buildout.sh correspondingly drops out of 3.0's closure — there is no buildout in the tarball era.

Three structural differences from everything ported so far

1. Zope is fetched and built here, not by buildout

The tarball comes from old.zope.dev — a host no other series uses — and goes through ./configure && make && make install into /opt/zope:

CFLAGS="-fcommon -fno-strict-aliasing" make

-fcommon is required because gcc ≥ 10 rejects the tentative definitions in Zope 2.10's C extensions.

2. The bundle layout is unique to this release

3.0 ships Products/ plus lib/python/, rather than one directory per product as the 2.x bundles do. Per its own INSTALL.txt, both trees install into their counterparts inside the Zope instance — and <instance>/lib/python is on sys.path because Zope 2.10's Zope2/Startup/handlers.py always inserts it.

The Dockerfile asserts both copies afterwards (test -f .../CMFPlone/version.txt, test -d .../lib/python/plone), so a layout change in a future bundle fails the build rather than yielding an instance that starts with half of Plone missing. Verified on the built image — lib/python holds archetypes, five, kss, plone, wicked.

3. ElementTree is load-bearing, not defensive

Products/Marshall/handlers/atxml.py, at module scope:

try:
    from celementtree import ElementTree
except ImportError:
    from elementtree import ElementTree   # <- unguarded

The except catches only the C variant; the pure-Python fallback is unguarded. With no elementtree installed the module raises and Marshall fails to load — which is what the smoke gate's product-load check covers.

Version pin

3.0.5, not 3.0.6. The 3.0.6 roll shipped only as PloneBase-3.0.6.tar.gz — the stripped core, without dependency products — so 3.0.5 is the last full Plone-*.tar.gz for the series.

Note also the source host: https://dist.plone.org/Plone-3.0.5.tar.gz directly, not dist.plone.org/archive/ as 1.0 – 2.5 use.

Verification

Check Result
make lint — hadolint ×8, shellcheck ×11, yq pass
Base smoke test (SMOKE_CREATE_SITE=1) pass, 6/6 gates
-demo build + make test-demo-3.0 pass, 6/6 gates
make -n on all four targets, GNU Make 3.81 correct, incl. the stem trap

The -demo run is the first exercise of docker-entrypoint.sh in this repository. seed-demo-site.sh invokes /docker-entrypoint.sh start, which now resolves to the zopectl-based tarball entrypoint rather than the buildout one, and drives it through site creation, clean shutdown, and the ADMIN_PASSWORD reset on the seeded database. "Build-time password admin:admin no longer authenticates" is what proves the reset landed.

Version claims were read out of the built image rather than assumed:

Products/CMFPlone/version.txt     -> 3.0.5
getZopeVersion()  (from /opt/zope) -> (2, 10, 13, '', -1)
lib/python/                        -> archetypes five kss plone wicked
elementtree                        -> site-packages
simplejson                         -> 2.0.9, site-packages

Cold-build status: the local build was cache hits off the source repository, so the cold build happens for the first time in CI — and for this series that cold build includes compiling Zope 2.10.13 from source, so expect this leg to be the slowest in the matrix so far.

Also in this PR

legacy/README.md's shared-scripts table gains both new scripts, and the sentence promising "further scripts arrive with the earlier series they serve" is replaced — there are none left to arrive.

Follow-ups

Seventh series of the legacy matrix, the first tarball-era image, and the last
port that needs new shared scripts. Refs #187.

build-elementtree.sh and docker-entrypoint.sh both arrive here, which completes
the shared set: legacy/shared/ now matches the source repository's file list
exactly, and the closures for 2.5, 2.1, 2.0 and 1.0 are all already satisfied.
The remaining four ports are copy-and-wire.

Three things make 3.0 structurally different from every series ported so far.

Zope is fetched and built here rather than by buildout. The tarball comes from
old.zope.dev -- a host no other series uses -- and goes through ./configure &&
make && make install into /opt/zope, with CFLAGS="-fcommon" because gcc >= 10
rejects the tentative definitions in Zope 2.10's C extensions. build-plone-
buildout.sh drops out of the closure entirely.

The bundle layout is unique to this release. 3.0 ships Products/ plus
lib/python/ rather than one directory per product as the 2.x bundles do, and
per its INSTALL.txt both trees install into their counterparts inside the Zope
instance. The Dockerfile asserts both copies afterwards, so a layout change in a
future bundle fails the build rather than producing an instance that starts with
half of Plone missing. Verified on the built image: lib/python holds
archetypes, five, kss, plone and wicked.

ElementTree is load-bearing rather than defensive.
Products/Marshall/handlers/atxml.py does, at module scope:

    try:
        from celementtree import ElementTree
    except ImportError:
        from elementtree import ElementTree

The except catches only the C variant; the pure-Python fallback is unguarded, so
with no elementtree installed the module raises and Marshall fails to load. The
smoke gate's product-load check is what covers this.

3.0.5, not 3.0.6: the 3.0.6 roll shipped only as PloneBase-3.0.6.tar.gz, the
stripped core without dependency products, so 3.0.5 is the last full
Plone-*.tar.gz for the series. The source URL is dist.plone.org/ directly rather
than dist.plone.org/archive/ as 1.0 - 2.5 use.

legacy/README.md's shared-scripts table gains both new scripts, and the sentence
promising further scripts with later series is replaced -- there are none left.

Verified locally: make lint passes with 8 Dockerfiles and 11 shell scripts; the
base image passes the smoke gate with SMOKE_CREATE_SITE=1 (6/6), and the -demo
variant builds and passes make test-demo-3.0 (6/6). The -demo run is the first
exercise of docker-entrypoint.sh in this repository: seed-demo-site.sh drives it
through site creation, clean shutdown and the ADMIN_PASSWORD reset on the seeded
database, and the build-time password no longer authenticates afterwards.

The versions were read out of the built image rather than assumed:
Products/CMFPlone/version.txt reads 3.0.5, getZopeVersion() returns
(2, 10, 13, '', -1) from /opt/zope, and elementtree and simplejson 2.0.9 both
resolve to site-packages.

The local docker build reused cached layers from the source repository, so a
cold build is exercised for the first time in CI -- and for this series that
cold build includes compiling Zope 2.10.13 from source.
@ericof ericof self-assigned this Aug 28, 2026
@ericof
ericof merged commit 70749ee into main Aug 28, 2026
12 checks passed
@ericof
ericof deleted the issue-187 branch August 28, 2026 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plone 3.0 image

1 participant