Skip to content

Resolve env-dependent storybook.registry via allow-listed interpolation#3486

Merged
clintandrewhall merged 2 commits into
mainfrom
storybook-registry-env-interpolation
Jun 30, 2026
Merged

Resolve env-dependent storybook.registry via allow-listed interpolation#3486
clintandrewhall merged 2 commits into
mainfrom
storybook-registry-env-interpolation

Conversation

@clintandrewhall

Copy link
Copy Markdown
Contributor

Closes #3485

Why

docset.yml is a committed, static artifact, but storybook.registry is inherently environment-dependent: local serve, per-PR preview, and main/production each need a different URL that varies only in one ref segment. Today contributors hand-edit docset.yml per environment and revert before merge, which is error-prone. The actor that knows the ref at render time is the build/preview layer, not the author at commit time.

What

storybook.registry now supports shell-style environment interpolation with a committed default, so one committed value works everywhere:

storybook:
  registry: ${KIBANA_STORYBOOK_REGISTRY:-https://ci-artifacts.kibana.dev/storybooks/main/storybook-docs/docs_registry.json}
  • ${VAR} / ${VAR:-default} resolve with familiar shell semantics. With no env var set (e.g. a main build) the committed default is used byte-for-byte.
  • Because docs-builder renders untrusted PR branches, interpolation is restricted to an explicit allow-list (currently KIBANA_STORYBOOK_REGISTRY). Any other name is never read from the process environment — it is left literal and a warning is emitted — so a malicious docset.yml cannot exfiltrate CI secrets such as ${AWS_SECRET_ACCESS_KEY}.
  • Graceful degradation: when an environment-supplied registry (e.g. an ephemeral per-PR URL not yet published) is unreachable, the directive falls back to the committed default. A committed/static registry that fails to read remains a hard error so typos and broken paths don't silently drop every embed.

The substitution primitive lives in Elastic.Documentation.Configuration and is repo-agnostic: docs-builder does not know how to construct a Kibana pr-<N> URL; the consumer supplies the variable.

IEnvironmentVariables is threaded through IDocumentationSetContext so configuration resolution is injectable and the set/unset/fallback cases are deterministic in tests.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@clintandrewhall, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 32 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b95d4258-5dac-429e-b41f-9a86cf69aa15

📥 Commits

Reviewing files that changed from the base of the PR and between 3018204 and 06afc80.

📒 Files selected for processing (16)
  • docs/syntax/storybook.md
  • src/Elastic.Documentation.Configuration/BuildContext.cs
  • src/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cs
  • src/Elastic.Documentation.Configuration/EnvironmentInterpolation.cs
  • src/Elastic.Documentation/IDocumentationContext.cs
  • src/Elastic.Markdown/Myst/Directives/Storybook/StorybookBlock.cs
  • tests/Elastic.Documentation.Configuration.Tests/ApiConfigurationTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileExcludeTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileReleaseNotesTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileStorybookRegistryTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/CrossLinkRegistryTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/EnvironmentInterpolationTests.cs
  • tests/Elastic.Markdown.Tests/Directives/DirectiveBaseTests.cs
  • tests/Elastic.Markdown.Tests/Directives/StorybookTests.cs
  • tests/Navigation.Tests/TestDocumentationSetContext.cs
  • tests/authoring/Framework/CrossLinkResolverAssertions.fs
📝 Walkthrough

Walkthrough

This PR adds allow-listed shell-style interpolation for storybook.registry, threads environment access through build and test contexts, stores a committed fallback value, and updates Storybook registry loading to use that fallback when the primary registry read fails. It also adds documentation for the new configuration syntax and tests for interpolation, fallback, and disallowed variables.

Possibly related PRs

  • elastic/docs-builder#2910: Earlier Storybook registry work in the same loading path; this PR extends that flow with environment interpolation and fallback handling.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: allow-listed interpolation for env-dependent storybook.registry.
Description check ✅ Passed The description is directly about the same interpolation, allow-listing, and fallback behavior implemented in the PR.
Linked Issues check ✅ Passed The changes match the linked issue goals: allow-listed env interpolation, default fallback, injected environment access, and registry fallback handling.
Out of Scope Changes check ✅ Passed The code changes and tests are all directly tied to env-dependent storybook.registry interpolation and fallback behavior.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch storybook-registry-env-interpolation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileStorybookRegistryTests.cs`:
- Around line 43-50: The test DisallowedVariable_IsLeftLiteral_AndWarns
currently asserts only that config.StorybookRegistry remains the literal and
does not contain the secret; update the test to also assert that the
DiagnosticsCollector (collector) recorded a warning. After creating config via
CreateConfiguration(...) and before completing the test, add an assertion that
collector contains at least one warning entry (or a specific warning message) to
verify the warning path is exercised.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 433b691f-3bf0-4666-a3da-e958b6a42ba5

📥 Commits

Reviewing files that changed from the base of the PR and between 182938f and 11c3303.

📒 Files selected for processing (15)
  • docs/syntax/storybook.md
  • src/Elastic.Documentation.Configuration/BuildContext.cs
  • src/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cs
  • src/Elastic.Documentation.Configuration/EnvironmentInterpolation.cs
  • src/Elastic.Documentation/IDocumentationContext.cs
  • src/Elastic.Markdown/Myst/Directives/Storybook/StorybookBlock.cs
  • tests/Elastic.Documentation.Configuration.Tests/ApiConfigurationTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileExcludeTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileStorybookRegistryTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/CrossLinkRegistryTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/EnvironmentInterpolationTests.cs
  • tests/Elastic.Markdown.Tests/Directives/DirectiveBaseTests.cs
  • tests/Elastic.Markdown.Tests/Directives/StorybookTests.cs
  • tests/Navigation.Tests/TestDocumentationSetContext.cs
  • tests/authoring/Framework/CrossLinkResolverAssertions.fs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileReleaseNotesTests.cs (1)

151-167: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

MockDocumentationSetContext.Environment wires up the real system environment, not a deterministic stub.

Line 166 returns SystemEnvironmentVariables.Instance, the live process-environment implementation, rather than a deterministic/mock IEnvironmentVariables. This file's test data never sets storybook.registry, so it's harmless today, but it contradicts the contract this layer introduces — IEnvironmentVariables exists precisely so config-resolution tests are deterministic and don't leak host/CI environment state. The hook in DirectiveBaseTests is "Override to inject a deterministic environment for env-dependent config (e.g. storybook.registry)." Any future addition of storybook.registry (or similar env-dependent fields) to tests in this file would silently pick up real CI/host env vars.

♻️ Suggested fix
-		public IEnvironmentVariables Environment => SystemEnvironmentVariables.Instance;
+		public IEnvironmentVariables Environment { get; init; } = NullEnvironmentVariables.Instance;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileReleaseNotesTests.cs`
around lines 151 - 167, MockDocumentationSetContext.Environment is using the
live SystemEnvironmentVariables.Instance instead of a deterministic test stub.
Update the MockDocumentationSetContext in ConfigurationFileReleaseNotesTests to
inject a controlled IEnvironmentVariables implementation (as intended by
DirectiveBaseTests) so env-dependent config like storybook.registry cannot leak
host/CI state into these tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileReleaseNotesTests.cs`:
- Around line 151-167: MockDocumentationSetContext.Environment is using the live
SystemEnvironmentVariables.Instance instead of a deterministic test stub. Update
the MockDocumentationSetContext in ConfigurationFileReleaseNotesTests to inject
a controlled IEnvironmentVariables implementation (as intended by
DirectiveBaseTests) so env-dependent config like storybook.registry cannot leak
host/CI state into these tests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6352e1a3-ac55-4028-8b4c-7fe494db31db

📥 Commits

Reviewing files that changed from the base of the PR and between 11c3303 and 3018204.

📒 Files selected for processing (16)
  • docs/syntax/storybook.md
  • src/Elastic.Documentation.Configuration/BuildContext.cs
  • src/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cs
  • src/Elastic.Documentation.Configuration/EnvironmentInterpolation.cs
  • src/Elastic.Documentation/IDocumentationContext.cs
  • src/Elastic.Markdown/Myst/Directives/Storybook/StorybookBlock.cs
  • tests/Elastic.Documentation.Configuration.Tests/ApiConfigurationTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileExcludeTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileReleaseNotesTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileStorybookRegistryTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/CrossLinkRegistryTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/EnvironmentInterpolationTests.cs
  • tests/Elastic.Markdown.Tests/Directives/DirectiveBaseTests.cs
  • tests/Elastic.Markdown.Tests/Directives/StorybookTests.cs
  • tests/Navigation.Tests/TestDocumentationSetContext.cs
  • tests/authoring/Framework/CrossLinkResolverAssertions.fs
💤 Files with no reviewable changes (2)
  • tests/authoring/Framework/CrossLinkResolverAssertions.fs
  • tests/Navigation.Tests/TestDocumentationSetContext.cs
✅ Files skipped from review due to trivial changes (1)
  • tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileExcludeTests.cs
🚧 Files skipped from review as they are similar to previous changes (12)
  • src/Elastic.Documentation/IDocumentationContext.cs
  • tests/Elastic.Documentation.Configuration.Tests/CrossLinkRegistryTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/ApiConfigurationTests.cs
  • tests/Elastic.Markdown.Tests/Directives/DirectiveBaseTests.cs
  • src/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cs
  • tests/Elastic.Documentation.Configuration.Tests/EnvironmentInterpolationTests.cs
  • docs/syntax/storybook.md
  • src/Elastic.Documentation.Configuration/BuildContext.cs
  • tests/Elastic.Documentation.Configuration.Tests/ConfigurationFileStorybookRegistryTests.cs
  • tests/Elastic.Markdown.Tests/Directives/StorybookTests.cs
  • src/Elastic.Markdown/Myst/Directives/Storybook/StorybookBlock.cs
  • src/Elastic.Documentation.Configuration/EnvironmentInterpolation.cs

@reakaleek reakaleek requested a review from Mpdreamz June 30, 2026 20:48
clintandrewhall and others added 2 commits June 30, 2026 17:06
docset.yml is committed and static, but storybook.registry is environment-dependent (local, per-PR preview, main). Resolving it from an allow-listed environment variable lets one committed value serve every environment without per-env edits. The allow-list is required because docs-builder renders untrusted PR branches, so unrestricted env access would be a secret-exfiltration vector.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The DisallowedVariable_IsLeftLiteral_AndWarns test named the warning path but never verified it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@clintandrewhall clintandrewhall force-pushed the storybook-registry-env-interpolation branch from 3018204 to 06afc80 Compare June 30, 2026 21:06
@clintandrewhall clintandrewhall merged commit 5059e85 into main Jun 30, 2026
25 checks passed
@clintandrewhall clintandrewhall deleted the storybook-registry-env-interpolation branch June 30, 2026 21:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] Resolve env-dependent config values (starting with storybook.registry)

2 participants