Problem/Motivation

The settings form at /admin/config/content/content-credentials explains that the service API key is deliberately not a form field, because Drupal configuration is exported to code and usually committed, and tells the site builder to set it in settings.php instead. It then reports:

Currently: no key is set.

— while the key is set, in that very file, and is the one the reader actually uses.

Steps to reproduce

  1. Add to settings.php: $config['content_credentials.settings']['reader']['api_key'] = 'something';
  2. Rebuild caches.
  3. Open /admin/config/content/content-credentials.

The page says no key is set. \Drupal::config('content_credentials.settings')->get('reader.api_key') returns the value.

Measured on Drupal 11.4.6 with ai_disclosure 1.0.0-alpha2, on the site built to exercise the HTTP signing-service route.

Cause

SettingsForm::apiKeyNote() reads $this->config(...). That is ConfigFormBase's editable configuration object, and overrides from settings.php are not applied to it. The form never writes reader.api_key — on purpose — so the stored value is empty on every site, and the line therefore reads "no key is set" whatever the site has done.

The form already knows this distinction. withOverrideState() compares configFactory()->getEditable() against configFactory()->get() for exactly this reason, and carries a comment saying that editable configuration "has no overrides applied — comparing it against itself could never detect one". The API-key note did not get the same treatment, and its own docblock says it reports "whether one is in effect".

Proposed resolution

Read the effective value — configFactory()->get(...) — for that one line.

Two things the fix must not do, and both are worth a test rather than care:

  • It must never render the key itself, or any part of it. The line says whether a key is in effect and nothing more. A fix that helpfully shows the first few characters would turn a wrong sentence into a credential leak on a page that a site builder may screenshot.
  • It must not turn the key into a form field, or write it to configuration. Keeping it out of exported config is the whole reason the paragraph exists.

Remaining tasks

  1. A failing test with the value present only as an override, watched failing.
  2. The fix.
  3. A test that the key itself never reaches the rendered page.

User interface changes

One sentence on the settings form starts telling the truth.

API changes

None.

Data model changes

None.

Note on how this was found

By running the module on a real site with the key where the form says it belongs. It is not reachable from a configuration fixture, because settings.php is not configuration — which is why the existing tests cover the override machinery and still miss this line.

Comments

maurice1969 created an issue. See original summary.

  • maurice1969 committed 1aeae2c9 on main
    Issue #3622762 by maurice1969: SPEC 009 — report the API key that is in...

  • maurice1969 committed 1aeae2c9 on 1.0.x
    Issue #3622762 by maurice1969: SPEC 009 — report the API key that is in...
maurice1969’s picture

Status: Active » Fixed

Fixed in 1aeae2c, on main and 1.0.x.

apiKeyNote() reads the effective configuration instead of ConfigFormBase's editable object. One call. The form already knew the distinction — withOverrideState() compares editable against effective for exactly this reason and says so in a comment — and this line had simply not been given the same treatment, while its own docblock claimed it reported whether a key is "in effect".

What was measured

  • The criterion for the defect was watched failing first, with the key present only as a global override and stored configuration asserted empty. That asymmetry is the test: a fixture that saves the key into stored configuration cannot fail for this reason, which is how the defect survived.
  • The other two criteria described behaviour that was already correct, so neither was trusted on a pass. Each was killed by a mutation: "always claim a key is set" — the cheapest fix, which satisfies the first criterion on its own — and a note that appends the key in parentheses, which is the helpful wrong fix and would turn a false sentence into a credential on a screen someone may screenshot.
  • On the site the report came from: the form now reads "Currently: a key is set." with the key in settings.php, and the key appears nowhere in the page source.
  • 96 tests here, 139 on a Drupal 11.4.6 site with ai_disclosure 1.0.0-alpha2. CI green on both branches, read job by job.

One note worth passing on, because it nearly cost a wrong conclusion: the first attempt at the third mutation reported a pass, and the test was not at fault — the substitution had silently failed to match, so the code under test never changed. A mutation that does not apply looks exactly like a test that does not bind. Confirm the source actually changed before believing a survivor.

Marking fixed.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.