{% set page_title = 'System' %} {% include '_header.html' %}

System · little-sister {{ version }}

{# Server-seeded, same contract as the dashboard's stamp (ADR-0005): this page doesn't navigate on its own, so it always says from when the information below actually is. Under the kiosk layout the slim line already carries it — there must be exactly one #status-updated on the page, because that is what the poller looks for. #} {% if layout != 'kiosk' %}
updated {{ rendered_at }}
{% endif %}
{% include '_system_info.html' %}
{# The registered check types and who answers for each. A type may come from a separately released package (ADR-0051), so this is the only place an operator can read which code — and which version — is behind a `type:` name in their YAML. Always shown: there are always the built-ins, and the point is the comparison between them and everything else. Split, though. The types this configuration runs come first; the rest fold into a disclosure, because on a small deployment they are most of the card and none of the question being asked. They stay reachable because a registered-but-unused type is the proof a freshly installed plugin took — see `_type_roster`, which owns the reasoning. #} {#- Top-aligned, alone among this page's tables, because alone among them a row here can grow: opening "used by 9 checks" stretches the Type cell down a list of node paths, and centering put Module, Version and From halfway down that list, beside nothing they describe. They answer for the type named at the top of the row, so that is where they sit. -#} {%- macro type_table(rows) %} {% for row in rows %} {%- set origin = row.origin %} {#- "used by", because a bare count under a type name reads as something the *package* brought — two checks shipped — when it is the opposite: how many checks in this deployment's configuration name this type. A package contributing one type to two checks is the ordinary case, so the ambiguous phrasing was wrong most of the time. And the count opens. It is the right summary at a glance, but it was the one number on this page that the page could not substantiate — *two of what?* — while every other card here names its subjects. A disclosure rather than a tooltip: the list is as long as the deployment is large, and it has to survive a keyboard and a screenshot. The unused types below have no list, and say so by not offering one. -#} {#- The loaded path under the module name, because the version beside it is the installed metadata's claim: a source copy earlier on the path shadows an installed distribution of the same name, and then the version is answering for code that is not running. Exactly the case somebody reads this table to diagnose, so the table shows both. Against a root the reader has, not absolutely: the diagnostic is *which root*, and nine tenths of an absolute path is the same prefix on every row — starting with somebody's home directory. The whole string stays one hover away. -#} {% endfor %}
TypeModuleVersionFrom
{{ origin.type_name }} {%- if row.count %}
used by {{ row.count }} check{{ 's' if row.count != 1 else '' }} {#- The node path, not the check's name: the path is the thing the reader can go and look at, so each is a link to that node. -#}
    {%- for path in row.paths %}
  • {{ path }}
  • {%- endfor %}
{%- endif %}
{{ origin.module }} {% if origin.path %}
{{ origin.path | loaded_from }}{% endif %}
{% if origin.version %}{{ origin.version }}{% else %}—{% endif %} {% if origin.builtin %}built-in{% elif origin.distribution %}{{ origin.distribution }}{% else %}source{% endif %}
{%- endmacro %}

Check types

{% if types_in_use %} {{ type_table(types_in_use) }} {% if types_folded %} {#- The count belongs in the summary: a closed disclosure has to say what it is hiding, or an operator looking for a type they cannot find has no reason to open it. #}
{{ types_folded | length }} more registered type{{ 's' if types_folded | length != 1 else '' }}, unused by this configuration
{{ type_table(types_folded) }}
{% endif %} {% else %} {#- Nothing to split against (no engine, or no checks) — and that is the moment the roster matters most, so it is shown whole. #} {{ type_table(types_folded) }} {% endif %}
{# What is installed beside the library. A package reaches this instance through four seams and the tables below are each about one of them, so until this card the *version* of a package that registers no check type was unreadable from the running instance — see `_registering_packages`. One row per installation, not per contribution: the loaded path and the release belong to the package, and printing them on every slot row would say the same thing twice for a package that fills two. Absent when nothing but the library registered anything. #} {% if packages %}

Packages

{#- Two columns, not three. A column of its own left the loaded path a narrow ribbon breaking at the hyphen in "site-packages" while squeezing everything either side of it; under the name it has the table's whole width and needs none of it, now that the path is drawn against a root (`loaded_from`) instead of absolutely. The column stays a column because what it holds is one thing — this package's identity: what it is called, what was installed, and where that turned out to be. -#} {% for row in packages %} {#- The import name is what every other table on this page prints, so it leads; the distribution and version sit beside it because that pair is what an operator compares against what they installed. A package with no installed metadata is a copy on the path — the shadowing case, worth saying out loud. -#} {#- Each registration is one fact and must not break across lines: "slot reason.actions" split after "slot" reads as two entries, and the column is narrow enough for that to happen. The list still wraps *between* items — that is what the breaks are for. -#} {% endfor %}
PackageRegisters
{{ row.origin.package }} {% if row.origin.distribution %}· {{ row.origin.distribution }} {{ row.origin.version }}{% else %}· source{% endif %} {%- if row.origin.path %}
{{ row.origin.path | loaded_from }}{% endif %}
{%- for item in row.registers %} {{ item }}{% if not loop.last %}
{% endif %} {%- endfor %}
{% endif %} {# The extension seams (ADR-0034 / ADR-0035 / ADR-0064), outside #system-info because they are decided at import time and never move while the process runs — re-fetching them on the ~10s poll would say nothing new. Registration is import-order sensitive and each of its failures is a log warning, so the running instance has to be able to answer "did my extension take?" without anyone opening a log file. `slot_fillers` is `all_fillers()` and the library registers its own two unconditionally, so in practice this card is always drawn and the guard is what makes that a *fact about the fillers* rather than an assumption here. The resolver list below is deliberately not part of it: it would make the guard unreachable, and an unreachable condition is one no test can hold. #} {% if slot_fillers or extra_aspects %}

Extensions

{% if slot_fillers %} {% for filler in slot_fillers %} {#- Which kind: a dependent package's registration, or the library's own declarative action list, which fills the same slots through the same seam (ADR-0038). Worth naming, because an operator looking here after adding a config action needs to see the difference between "mine" and "theirs". -#} {% endfor %}
SlotPackageTemplateContextFrom
{{ filler.slot }} {{ filler.package }} {{ filler.template }} {% if filler.context %}provider{% else %}—{% endif %}{% if filler.builtin %}built-in{% else %}extension{% endif %}
{% endif %} {% if resolvers %} {#- Every claimed secret scheme with the package that answers for it (ADR-0064), drawn as the slot table above is and not as a prose line: a deployment with a few named identities has seven or more of these, and a comma list of `scheme (package)` pairs wrapped into a paragraph where the eye has to re-find the boundary on every item. Two seams, one shape — the columns even mean the same things, `From` telling the library's own claim from a package's exactly as it does for a filler. The built-in `env` is listed too, unlike the aspects line below: the schemes are additive and a reference names exactly one, so this table is what a config field may say — and leaving the library's own claim out would make an *override* of it look like an ordinary registration. `Replaces` is empty in every ordinary deployment and stays a column anyway, because a replacement is the one fact on this seam that the outcome cannot show. #} {% for row in resolvers %} {% endfor %}
SchemePackageReplacesFrom
{{ row.scheme }}:// {{ row.owner }} {% if row.replaced %}{{ row.replaced }}{% else %}—{% endif %} {% if row.builtin %}built-in{% else %}extension{% endif %}
{% endif %} {% if extra_aspects %} {#- Each name with the package that registered it: the name alone says the file is *declared*, which is not the question when the file is misbehaving. An owner is absent only where the caller could not be inferred, and then nothing is claimed. Still a line rather than a table: an aspect has one fact beyond its owner and a deployment has one or two of them, which is a sentence. #}

Registered configuration aspects: {% for name, owner in extra_aspects %}config/{{ name }}{% if owner %} ({{ owner }}){% endif %}{% if not loop.last %}, {% endif %}{% endfor %}

{% endif %}
{% endif %} {# The ways in (ADR-0069 §6). Always shown, like the policy below and unlike the extensions card above: **a way into an application must not be knowable only by reading the source**, which is the whole reason this card exists — every door an install has is registered in its own `wsgi.py`, and that file is not on the screen when somebody is asking *who can log in here, and how*. No empty state, and the reason is worth writing down rather than rediscovering: an installation that registered **no** door can be started and warns about itself at startup, but nobody can be signed in on it, so nobody reaches this page. Reading this table at all means one of its rows answered for you. One row per door, and the columns are the question the other seam tables answer: what is claimed, and by whom. `Default` rather than a `From` column, because which door `/login` and an unidentified request go to is the fact an operator comes here for, and the package already says whose code answers. #}

Identity

{% for door in doors %} {#- The label beside the name only where they differ: it defaults to the name, and printing `keycloak (keycloak)` on every row would be a column of noise to carry one deployment's *Company SSO*. -#} {% endfor %}
DoorRouteProviderPackageDefault
{{ door.name }}{% if door.label != door.name %} ({{ door.label }}){% endif %} {{ door.route }} {{ door.provider_name }} {{ door.owner }} {% if door.default %}default{% else %}—{% endif %}
{#- What `/login` itself does, which the table cannot say: under `choose_at_login()` it is a page offering these doors rather than the default one's login step, and an unidentified request still goes wherever that provider sends it. A way into an application must not be knowable only by reading the source, and *which address does what* is part of the way in. -#}

{% if choosing_at_login %} /login offers a choice of the doors above; an unidentified request still goes to the default door. {% else %} /login is the default door's own login step. {% endif %}

{#- The system-admin account's own three facts (ADR-0069 §5): that it is configured at all, whether its credential resolved, and **which keyword** configured it — so a deployment that took the discouraged shortcut can be seen to have taken it by somebody who is not reading `wsgi.py`. A line rather than three more columns of `—`: one door with a few facts is a sentence, which is the same call the aspects line makes beside the slot table above. *Configured but unavailable* is the state this line exists for: an admin who did get in can see why the other door is shut. The reference is printed and the password never is — a config field names a secret, it never carries one (ADR-0023). -#} {% if system_admin %}

System admin: configured by {{ system_admin.keyword }}= {%- if system_admin.reference %} ({{ system_admin.reference }}){% endif %}, {% if system_admin.available %}credential resolved. {%- else %}credential unavailable — that door is shut ({{ system_admin.problem }}).{% endif %}

{% else %}

No system-admin account is configured: this instance is reachable only through the doors above.

{% endif %}
{# The effective Content-Security-Policy (ADR-0048 §7). Always shown, unlike the extensions card above: there is always a policy, and the reason to print it is that a source may come from a *package* — a request blocked inside somebody else's code is undebuggable from here unless the page says who asked for each origin. The header name is part of the answer: a Report-Only policy reports and blocks nothing. #}

Content-Security-Policy

{{ csp_header }}

{% for directive, sources in csp_directives %} {% endfor %}
DirectiveSources
{{ directive }} {%- for source in sources %} {{ source.value }} ({{ source.by }}) {%- if not loop.last %}
{% endif %} {%- endfor %}
{% include '_page_end.html' %}