v1.6.12
Declare which plugin columns are credentials, and which only look like it (#22).
Four bundled plugins carry a friendly key matching core's Redaction::CREDENTIAL_PATTERN and none of them said what it was.
Two were real credentials the API was emitting. pushbullet and slack both put their class in $validClasses, so every list the API returned carried the token in clear to any caller holding pushbullet.view / slack.view. Holding either token is being able to post as that account. Both now sit in the always tier — nothing reads them back, the same reasoning as ldap.bindPwd.
One is a product key. windowskey.key is the same kind of value as core's host.productKey and now sits in the same tier core puts that one in: stripped from API list payloads, kept on a direct single-entity GET. The plugin's own pages are unaffected — they read the model, and the list grid is served by the web tier at ?node=windowskey&sub=list, not by the API emitter that strips.
Two only look like credentials, and now say so through the new exempt bucket:
| field | what it actually is |
|---|---|
capone.key |
the DMI string capone matches an image on — the form calls it "Key to match", and the unauthenticated capone endpoint posts it in the clear on every lookup |
windowskeyassociation.windowskeyID |
an integer foreign key, matching only because "key" is in the plugin's name |
Core cannot answer either question on a plugin's behalf: the bundled plugins are a fetched artifact (ADR 0009), so a core entry naming a plugin class fails on any tree that has not fetched them — a fresh clone, or CI. That is what the exempt bucket is for.
Needs core carrying the exempt bucket on API_SENSITIVE_FIELDS (FOGProject/fogproject working-1.6). Without it the bucket never reaches the event and the two exemptions are ignored, which leaves those fields redacted — the safe direction. The three credential declarations work against any 1.6 core.