A password-gated static documentation build that an entire module drives
A gated documentation site, and a variable no tooling knew about
What makes it hard
Every scenario in the module failed on staging, with a message the step itself had written:
Error: this docs build is password-gated and DOCS_GATE_PASSWORD is not set — export itThe failure screenshot showed the gate: "This documentation is private. Enter the password to continue."
The variable was read directly by a project step. It was absent from .env.example, which the repository states is the contract for what an operator must supply. It was absent from the env: blocks of both CI workflows. And sdods doctor passed clean.
That last one is the finding. Doctor's variables check resolves every ${VAR} reference declared under envs/<env>.yaml vars: against the .env files and the shell. A variable that only a step reads is not in that set, so doctor reported a fully configured workspace for an environment where a whole module could not run. An operator who followed the setup instructions exactly ended up red.
It is a small bug with a general shape: configuration that bypasses the configuration system is invisible to the tools that check configuration.
How to cover it
The fix is one line of YAML and it generalises.
Declare the variable in the environment file, so it enters the set doctor knows about:
vars:
docsGatePassword: ${DOCS_GATE_PASSWORD}Then read it in the step through the template renderer rather than from process.env. Every {string} argument and every doc string is rendered, and variables resolve in order: values captured with I save the response JSON path ... as ..., then the current dataset row, then vars: from the environment file. ${VAR} references are resolved earlier, by configuration. Secrets stay references; they are never literals in a feature file or a YAML.
Now sdods doctor -p <slug> reports it missing instead of passing, and the same variable name goes into the workflow env: blocks as a repository secret.
The second half is a testing question rather than a configuration one. There was no scenario proving the gate works. A gate that nothing asserts is a gate nobody knows is closed. Two scenarios, and the more valuable one needs no secret at all:
- the gate refuses without a password — runnable by anyone, on any machine, with nothing configured
- the gate opens with the right password — the one that needs the secret, and the one that should skip cleanly when it is absent rather than failing the module
sdods doctor can see it. If a step reaches around the environment file for something, the first symptom will be a green doctor over a red module, and that combination costs more to diagnose than either failure alone.Scenario sketch
@ui @sanity
Scenario: The documentation gate refuses an empty password
Given I navigate to the "docs" page
Then I should see the text "This documentation is private"
And the "Unlock" button should be visible
@ui @smoke
Scenario: The documentation gate opens for the deploy password
Given I navigate to the "docs" page
When I fill the "Password" field with "{{docsGatePassword}}"
And I click the "Unlock" button
Then I should not see the text "This documentation is private"
And the element with test id "docs-sidebar" should be visiblesdods doctor -p <slug> --jsonOnce the variable is declared under vars:, that command is the thing that tells a new operator what to export — which is what .env.example was trying to be, and what doctor can actually enforce.
Other use cases
- Testing an eight-screen auth funnel that has no test idsLogin, signup, email verification, 2FA, the device flow, OAuth consent, invitation acceptance and password reset
- A 403 that a shared cache is free to replayAuthorisation refusals on an API served through a CDN
- Plan caps, spending limits, and a gate that never firedBilling, usage and spending-limit routes behind plan entitlements
- A workflow canvas SDODS cannot dragA node-graph editor: 193 block types, edges, handles, sub-block inputs and subflow containers