Metadata-Version: 2.4
Name: collective.lockdown
Version: 1.1.0
Summary: Protect plone sites against site admins
Home-page: https://github.com/collective/collective.lockdown
Author: Guido A.J. Stevens
Author-email: guido.stevens@cosent.net
License: GPL version 2
Project-URL: PyPI, https://pypi.org/project/collective.lockdown/
Project-URL: Source, https://github.com/collective/collective.lockdown
Project-URL: Tracker, https://github.com/collective/collective.lockdown/issues
Keywords: Python Plone CMS
Classifier: Environment :: Web Environment
Classifier: Framework :: Plone
Classifier: Framework :: Plone :: Addon
Classifier: Framework :: Plone :: 6.2
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
Requires-Python: >=3.11
License-File: LICENSE.GPL
License-File: LICENSE.rst
Requires-Dist: setuptools
Requires-Dist: Products.CMFPlone
Provides-Extra: test
Requires-Dist: plone.app.testing; extra == "test"
Requires-Dist: plone.testing; extra == "test"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: project-url
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

.. This README is meant for consumption by humans and PyPI. PyPI can render rst files so please do not use Sphinx features.
   If you want to learn more about writing documentation, please check out: http://docs.plone.org/about/documentation_styleguide.html
   This text does not appear on PyPI or github. It is a comment.

.. image:: https://github.com/collective/collective.lockdown/actions/workflows/plone-package.yml/badge.svg
    :target: https://github.com/collective/collective.lockdown/actions/workflows/plone-package.yml

.. image:: https://img.shields.io/pypi/v/collective.lockdown.svg
    :target: https://pypi.python.org/pypi/collective.lockdown/
    :alt: Latest Version

.. image:: https://img.shields.io/pypi/pyversions/collective.lockdown.svg?style=plastic   :alt: Supported - Python Versions

.. image:: https://img.shields.io/pypi/l/collective.lockdown.svg
    :target: https://pypi.python.org/pypi/collective.lockdown/
    :alt: License


===================
collective.lockdown
===================

Lock Plone against the ``Site Administrator`` role.

This restricts ``Site Administrator`` to: manage content, and manage users.
It prevents ``Site Administrator`` from reconfiguring the site or making layout changes.

This package should be suitable for both Plone classicui and Plone headless.

What it does
------------

Site owners at the client side need permissions to properly manage content
and users. However, if your setup is such that as an integrator you're
responsible for views and site configuration, the default Plone permission
set for ``Site Administrator`` is too wide.

We've seen users switch the default layout to something not properly
supported, or otherwise muck up the configuration of their site. Then
they open a support ticket "the site is broken" — without disclosing
what they just did.

On install, this add-on strips ``Site Administrator`` from a curated set
of permissions on the Plone site root:

- every ``Plone Site Setup: *`` permission *except* ``Overview`` (so the
  Site Setup link in the toolbar still works) and ``Users and Groups``
  (so user administration remains possible);
- ``Portlets: Manage portlets``;
- ``Modify view template``.

The control-panel index view self-filters its rendered configlets by
per-configlet permission, so stripping the underlying permissions is
sufficient to hide everything except the user management card.

The install handler writes role lists surgically via
``manage_permission`` (with acquisition disabled, so role grants cannot
leak back in through Zope-root acquisition). Permissions outside the
lockdown set are not touched.


Hidden control panel configlets
-------------------------------

The upstream ``Users and Groups`` permission guards four configlets:
``Users``, ``Groups``, ``User and Group Settings``, and ``Member Fields``.
Keeping that permission grants ``Site Administrator`` access to all four,
which is wider than needed — site owners should only manage user
accounts, not the global group/role mapping or member schema.

On install, the three other configlets (``UsersGroups2``,
``UsersGroupsSettings``, ``MemberFields``) get a TALES ``condition_expr``
on their ``portal_controlpanel`` entries that only evaluates true for
users holding the ``Manager`` role::

    python: member is not None and 'Manager' in member.getRolesInContext(portal)

The ``UsersGroups`` (Users) configlet is left untouched, so site owners
still reach the user listing from the control panel. ``Manager`` users
continue to see the full set. On uninstall, the conditions are cleared
back to the upstream empty default.


Uninstall
---------

Uninstalling via Site Setup → Add-ons restores every lockdown permission
to its upstream Plone baseline — both the role list and the acquisition
flag — using a snapshot of a vanilla Plone fixture captured at package
build time. The configlet conditions are also cleared back to empty.
The result is indistinguishable from a Plone site on which the add-on
was never installed.


Installation
------------

Install ``collective.lockdown`` by adding it to your buildout::

    [buildout]

    ...

    eggs =
        collective.lockdown


and then running ``bin/buildout``.


Development
-----------

Routine tests run at the default level::

    bin/test -s collective.lockdown

The upstream permission baseline lives in
``collective/lockdown/default_permissions.py`` and is checked
against a vanilla Plone fixture by a level-2 drift detector. It is
skipped from default runs, because running tests with side effects is unclean,
and the data only changes on Plone upgrades. To audit and, if
necessary, regenerate the snapshot::

    bin/test -s collective.lockdown --at-level 2

On drift, the test rewrites ``default_permissions.py`` in place and
fails with a diff summary — review and commit the result.

Note that when the default_permissions change, you'll have to re-run
the tests in order for them to pick up the newly generated default permissions
correctly.

Contribute
----------

- Issue Tracker: https://github.com/collective/collective.lockdown/issues
- Source Code: https://github.com/collective/collective.lockdown

License
-------

The project is licensed under the GPLv2.


Contributors
============

- Guido A.J. Stevens, guido.stevens@cosent.net


Changelog
=========


1.1.0 (2026-05-29)
------------------

- Switch fully to PEP-420 native namespace.


1.0.0 (2026-05-29)
------------------

- Initial release.
  [gyst]
- Rename from collective.lockdownclassicui -> collective.lockdown
  [gyst]
