Skip to content

Proposal/12/privacy data types#11818

Open
chfsx wants to merge 11 commits into
ILIAS-eLearning:trunkfrom
srsolutionsag:proposal/12/privacy-data-types
Open

Proposal/12/privacy data types#11818
chfsx wants to merge 11 commits into
ILIAS-eLearning:trunkfrom
srsolutionsag:proposal/12/privacy-data-types

Conversation

@chfsx

@chfsx chfsx commented Jul 23, 2026

Copy link
Copy Markdown
Member

This PR proposes the general infrastructure für Data: Privacy Data Types and a first implementation for "Postal Adress".

Please have a look at the general information in https://github.com/srsolutionsag/ILIAS/blob/0cd06a7f741cf8f007dc3b5552868354b0029d7d/components/ILIAS/Data/src/Privacy/README.md

chfsx added 10 commits July 23, 2026 11:32
Personal data values are wrapped in privacy data types that carry their
origin (Source) and release the raw value only through resolve() with an
explicitly stated Purpose. Every resolve is reported to a PrivacyLogger,
forming the GDPR audit trail.

- PrivacyDataType<T> interface + abstract base, first concrete type
  PostalAddress (compound over usr_data street/city/zipcode/country)
- Sources: DbTableColumn(s), UserInput, ExternalApi, SessionData,
  LegacySource; KnownSources catalogue with named usr_data getters
- Purposes: StoreInTable, DisplayToUser, PassToComponent,
  TechnicalProcessing, LegacyAccess (marks unmigrated call sites)
- PrivacyLogger as contribute/seek collection with CompositeLogger;
  no persistent backend yet (storage/retention decision pending)
- Services defined/implemented in the Data component bootstrap; types
  are created via an injectable Factory that binds the audit logger
  (no static named constructors)
Legacy code can access the privacy data type services via
$DIC[\ILIAS\Data\Privacy\Services::class] until all consumers are
migrated to the component bootstrap.
- Rules: NoRawValueAccessRule (no PrivacyDataType into var_dump/
  json_encode/serialize etc.), StoreInTableTargetRule (StoreInTable
  requires a DbTarget), PreferKnownSourcesRule (no DbTableColumn(s)
  literals outside the KnownSources catalogue; escape hatch
  @privacy-undocumented)
- Return type extension: PrivacyDataType<T>::resolve() is typed as T
- PrivacyResolveCollector + report rule: every resolve() call site is
  collected with purpose and component and emitted into PHPStan's JSON
  output; KnownSources getters are evaluated so reports show the actual
  table/columns
- Generator renders per-component privacy documentation (stored /
  displayed / passed / technical / unmigrated legacy access + GDPR
  summary) to PRIVACY_DATA.md; --overwrite-privacy-md switches to
  PRIVACY.md once the community decides to replace the handwritten files
- CLI: scripts/Privacy/generate-privacy-docs.php [--run-phpstan]
  [--component=X] [--dry-run]
Profile\Data now holds the residential address as a single
PostalAddress privacy value instead of four bare strings. The
repository wraps the value on read (source usr_data street/city/
zipcode/country) and resolves it on store with a StoreInTable purpose,
so every persistence of the address lands in the audit trail.

Migrated consumers state their real purpose:
- profile form fields (Street/City/ZipCode/Country/Location) resolve
  with DisplayToUser and write back with a UserInput source
- PublicProfileGUI resolves with DisplayToUser for the profile page
  and the vCard export
- the profile mail body resolves with PassToComponent(Mail)
- the XML import parser writes with an ExternalApi(xml_import) source

The string-based accessors on ilObjUser and Profile\Data remain as
deprecated delegates that resolve with a LegacyAccess purpose (reads)
or a LegacySource (writes) — nothing breaks, and every unmigrated
access shows up in the audit trail and the generated report.

Raw SQL reads of the address columns (user lists, search) bypass the
wrapper and are left for later migration steps.
The user info overlays of the map GUIs resolve the postal address
privacy type with an explicit DisplayToUser purpose instead of the
deprecated string accessors.
The USER_STREET/CITY/ZIPCODE/COUNTRY placeholder values resolve the
postal address privacy type with a PassToComponent(Certificate)
purpose instead of the deprecated string accessors.
ilMStListUser holds the address as a PostalAddress privacy value; the
list fetcher wraps the raw usr_data columns with the proper source.
Table rendering and Excel/CSV export resolve with DisplayToUser
purposes; the string accessors remain as deprecated legacy delegates.
The user country criterion resolves the postal address privacy type
with a TechnicalProcessing purpose instead of the deprecated string
accessor.
shibUser writes street/zipcode/country received from the identity
provider into the postal address privacy type with an
ExternalApi(shibboleth) source instead of the deprecated setters.
Output of scripts/Privacy/generate-privacy-docs.php for the components
migrated to the postal address privacy type (User, Maps, Certificate,
MyStaff, LegalDocuments).
DefaultMappings::conditionDefinitions() now pulls Purposes from the
container in addition to ilObjDataCache. The TermsOfService and
DataProtection consumer tests still expected a single offsetGet call.
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.

1 participant