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 %}
{# Which installation this is (ADR-0074). First, because every other card
on this page describes something *about* an instance and until this one
the page never said which. Outside the polled fragment on the rule that
block states for itself: it is settled at import and cannot change while
the process runs.
Two fields and not four. The mark already contains the pid and the start,
and the engine block below shows the start again in local time — a card
repeating either would be the same fact three times. What is worth its own
row is the *name*, which is the only part a deployment chooses, and the
**mark**, because that is the string that ends up in somebody else's
bucket and on a status line, and the reason to come to this page at all is
to find out whether it is this instance's. #}
This instance
| Name |
{{ instance.name }}
{%- if not instance_named %} (the hostname — no instance: in the settings){% endif %} |
| Mark |
{#- The whole string, unbroken and selectable: it is
compared for equality elsewhere, so a copy of it has
to be exact. #}
{{ instance.mark }}
what a package writes down when it has to say which instance did something — unique to this process, and unchanged while it runs |
{% 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) %}
| Type | Module | Version | From |
{% 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. -#}
{{ 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 %} |
{#- 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. -#}
{{ 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 %} |
{% endfor %}
{%- 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. -#}
| Package | Registers |
{% 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. -#}
{{ 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 %} |
{#- 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. -#}
{%- for item in row.registers %}
{{ item }}{% if not loop.last %} {% endif %}
{%- endfor %} |
{% 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 %}
| Slot | Package | Template | Context | From |
{% for filler in slot_fillers %}
{{ filler.slot }} |
{{ filler.package }} |
{{ filler.template }} |
{% if filler.context %}provider{% else %}—{% endif %} |
{#- 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". -#}
{% if filler.builtin %}built-in{% else %}extension{% endif %} |
{% endfor %}
{% 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. #}
| Scheme | Package | Replaces | From |
{% for row in resolvers %}
{{ row.scheme }}:// |
{{ row.owner }} |
{% if row.replaced %}{{ row.replaced }}{% else %}—{% endif %} |
{% if row.builtin %}built-in{% else %}extension{% endif %} |
{% endfor %}
{% 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
| Door | Route | Provider | Package | Default |
{% 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*. -#}
{{ door.name }}{% if door.label != door.name %} ({{ door.label }}){% endif %} |
{{ door.route }} |
{{ door.provider_name }} |
{{ door.owner }} |
{% if door.default %}default{% else %}—{% endif %} |
{% endfor %}
{#- 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 }}
| Directive | Sources |
{% for directive, sources in csp_directives %}
{{ directive }} |
{%- for source in sources %}
{{ source.value }}
({{ source.by }})
{%- if not loop.last %} {% endif %}
{%- endfor %}
|
{% endfor %}
{% include '_page_end.html' %}