Replace 8 bash env modules with a single Python generator
(cli.meta.env) that materialises env/static.env + runtime context
into a gitignored .env. Each variable lives in its own handler
under utils/env/handlers/; defaults carry inline one-line `# ...`
comments.
Rename to the INFINITO_* schema:
- workflow inputs: APPS, SERVICES_DISABLED, CMD, DEBUG, WHITELIST,
BUNDLES, FULL_CYCLE, VARIANT, RUN_FLAGS, LIMIT_HOST, PARALLEL
- inventory: INVENTORY_DIR / INVENTORY_FILE / HOST_VARS_FILE,
PW_FILE -> INVENTORY_PASSWORD_FILE
- venv: VENV_BASE / VENV_FALLBACK / VENV_NAME
- new SPOT defaults: COMPILE_SILENCE, CONTAINER_NO_CA,
WAIT_HEALTH_TIMEOUT_S, PACKAGE_CACHE_FRONTEND_INIT_IMAGE,
promoted IMAGE_TAG from GHA-only to general passthrough
compose.yml hardening:
- inline \${VAR:-default} removed; strict \${VAR:?...} everywhere
- new integration lint blocks regressions
Tooling:
- scripts/install/all.sh owns the stamp-file install logic
(Makefile target delegates)
- scripts/meta/env/load.sh is the single shell entry point;
8 bash modules deleted
- new shell lint: no INFINITO_* defaults outside env/static.env
Tests:
- 93 new unit tests for utils/env/{builder,parser,runtime,writer}
- restructure tests/lint into repository/ (file-content rules) vs
filesystem/{shell,python,env}/ (filesystem-shape rules)
- drift + smoke integration tests against the generator
Docs:
- variables.md is now a pointer; per-variable docs live next to
the key in env/static.env / env/ci.env
- compose.yml.md drops the Default column
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.8 KiB
LDAP 📒
This page describes how application roles consume the platform's LDAP provider, OpenLDAP.
The variable tree lives in 12_ldap.yml under LDAP.
For the cross-cutting IAM principles, including the paired identifier rule shared with OIDC, see common.md.
For OIDC-side details see oidc.md.
Variable Tree 🌳
The high-level structure:
| Key | Meaning |
|---|---|
LDAP.DN.ROOT |
Base DN derived from DOMAIN_PRIMARY |
LDAP.DN.ADMINISTRATOR.DATA |
Bind DN for CRUD on entries below ROOT |
LDAP.DN.ADMINISTRATOR.CONFIGURATION |
Bind DN for cn=config schema work |
LDAP.DN.OU.USERS |
Container for user objects |
LDAP.DN.OU.GROUPS |
Container for organizational groups |
LDAP.DN.OU.ROLES |
Container for application RBAC roles |
LDAP.BIND_CREDENTIAL |
Password for the data administrator DN |
LDAP.SERVER.DOMAIN |
Hostname or container name to dial |
LDAP.SERVER.PORT |
Port resolved through the ports registry |
LDAP.SERVER.URI |
Full ldap[s]://host:port URI |
LDAP.SERVER.SECURITY |
Transport security mode, empty when unused |
LDAP.NETWORK.LOCAL |
True when the consumer shares the OpenLDAP Docker network |
Rules:
- Roles MUST connect via
LDAP.SERVER.URI. Building the URI from the individualINFINITO_DOMAIN,PORT, and protocol parts is forbidden because the helper variables in 12_ldap.yml already pick the correct scheme based on Docker-network availability. - The data administrator DN MUST be used for adding, modifying, and removing
users, groups, and roles. The configuration administrator DN MUST be used
only for schema and overlay changes pushed via
ldapi:///. - New OUs SHOULD NOT be invented. Place users under
OU.USERS, RBAC roles underOU.ROLES, and organizational groups underOU.GROUPS.
Object Classes 🧱
LDAP.USER.OBJECTS lists the structural and auxiliary object classes attached to user entries:
| Group | Key | Default | Purpose |
|---|---|---|---|
| Structural | (list) | person, inetOrgPerson, posixAccount |
Core identity, internet attributes, UNIX account fields |
| Auxiliary | NEXTCLOUD_USER |
nextcloudUser |
Adds nextcloudQuota and nextcloudEnabled |
| Auxiliary | SSH_PUBLIC_KEY |
ldapPublicKey |
Stores SSH public keys for services like Gitea |
Each entry has exactly one structural class chain.
New auxiliary classes SHOULD be added under LDAP.USER.OBJECTS.AUXILIARY so consumers can probe them by symbolic name instead of literal string.
User Attributes 🪧
LDAP.USER.ATTRIBUTES lists the LDAP attribute names that applications query:
| Key | Default value | Meaning |
|---|---|---|
LDAP.USER.ATTRIBUTES.ID |
uid |
Login identifier, paired with the OIDC preferred_username |
LDAP.USER.ATTRIBUTES.MAIL |
mail |
Primary email |
LDAP.USER.ATTRIBUTES.FULLNAME |
cn |
Display name |
LDAP.USER.ATTRIBUTES.FIRSTNAME |
givenName |
First name |
LDAP.USER.ATTRIBUTES.SURNAME |
sn |
Last name |
LDAP.USER.ATTRIBUTES.SSH_PUBLIC_KEY |
sshPublicKey |
SSH key attribute |
LDAP.USER.ATTRIBUTES.NEXTCLOUD_QUOTA |
nextcloudQuota |
Per-user Nextcloud quota |
Rules:
- Templates MUST reference
LDAP.USER.ATTRIBUTES.*. Hardcodeduid,cn, orsnvalues are forbidden because the underlying schema may switch flavor in the future. - The login attribute is paired with the OIDC username claim by design. Changing one without the other breaks LDAP-OIDC correlation. See oidc.md for the OIDC-side rule.
Filters 🔎
LDAP.FILTERS.USERS provides reusable LDAP search filters:
| Key | Purpose |
|---|---|
LDAP.FILTERS.USERS.LOGIN |
Resolve a single user by login attribute, parameterized via %uid |
LDAP.FILTERS.USERS.ALL |
Match every user entry, used for sync jobs and listings |
Roles SHOULD prefer these filters over composing new ones inline so a future schema change updates every consumer at once.
RBAC 👥
LDAP.RBAC controls how application roles are represented:
| Key | Meaning |
|---|---|
LDAP.RBAC.FLAVORS |
Allowed group flavors, currently groupOfNames |
LDAP.RBAC.EMPTY_MEMBER_DN |
Placeholder DN for empty groupOfNames groups |
groupOfNames requires at least one member attribute.
The placeholder DN exists so newly created empty groups remain schema-valid until the first real member is added.
Related Files 📚
| File | Purpose |
|---|---|
| 12_ldap.yml | LDAP SPOT, defines LDAP.* |
| svc-db-openldap | LDAP provider role |
| oidc.md | OIDC-side counterpart, paired user identifier |
| common.md | Cross-cutting IAM principles and integration checklist |