feat: Add consolidated snippets.#396
Draft
kinyoklion wants to merge 3 commits intomainfrom
Draft
Conversation
…ing-started
Introduces sdk-meta/snippets/, a self-contained Go module that owns the
canonical source for LaunchDarkly SDK code samples and renders them
into downstream consumers. Slice scope: python-server-sdk "Getting
Started" flow, end-to-end.
What's here
-----------
- cmd/snippets — CLI with three subcommands:
render — rewrite the body of every JSX element marked with an
SDK_SNIPPET:RENDER comment in a consumer checkout
verify — recompute hashes and fail if any managed region drifted
validate — run each snippet inside a per-language Docker validator
- internal/model — snippet file format (YAML frontmatter + one fenced
code block) loaded from sdks/<id>/snippets/.
- internal/render — minimal {{ var }} / {{ if var }}...{{ end }}
templating engine with a runtime mode for validation and a JS
template-literal mode for the ld-application adapter.
- internal/markers — host-syntax-aware scanner for SDK_SNIPPET:RENDER
comments (`// …`, `{/* … */}`, `/* … */`); hashes the rendered region
to catch hand-edits.
- internal/adapters/ldapplication — first adapter target. Discovers
consumer files via each sdk.yaml's ld-application.get-started-file
field and rewrites only the JSX children of marked <Snippet>
elements, preserving surrounding whitespace.
- internal/validate — orchestrator that builds a Docker image per
language and runs the snippet verbatim against a real LaunchDarkly
environment. The SDK key and flag key come from the caller's
LAUNCHDARKLY_SDK_KEY / LAUNCHDARKLY_FLAG_KEY env vars (the same
convention the hello-* sample apps use), are forwarded into the
container, and never end up in committed files.
- sdks/python-server-sdk — sdk descriptor plus four snippets sourced
verbatim from the existing get-started flow:
getting-started/mkdir
getting-started/install
getting-started/main-py
getting-started/run
- validators/languages/python — Docker image plus run.sh that pip-
installs the snippet's own requirements, runs the entrypoint, and
matches the expected flag-evaluation line within a timeout.
- docs/AUTHORING.md — snippet authoring guide.
Naming and module path
----------------------
- Go module: github.com/launchdarkly/sdk-meta/snippets
- Adapter target: --target=ld-application (renders into the LD
application UI). A future --target=ld-docs adapter is planned for
the docs site; not implemented yet.
Out of scope (kept in design doc, not in this commit): all SDKs other
than python-server-sdk, the ld-docs MDX adapter, GitHub Actions,
signed-binary release pipeline, sdk-meta capability integration,
region/version conditional rendering.
Verified locally
----------------
- go build ./... : clean
- go test ./... : render + markers tests pass
- snippets render --target=ld-application --out=<app-checkout>: idempotent
- snippets verify --target=ld-application --out=<app-checkout>: ok
- snippets validate (with LAUNCHDARKLY_SDK_KEY + LAUNCHDARKLY_FLAG_KEY):
matches "*** The <flag> feature flag evaluates to ..." against a
real LD environment.
1e7c5d1 to
ac28710
Compare
Findings 1-19 from the multi-agent review (artifacts/multi-review-sdk-meta-396.md). All worth-fixing items are addressed in this commit; the four "could not prove" hardening items are deferred (they remain open documentation in the review file). Security and correctness ------------------------ - #1, #5: Marker hash now covers the full <Tag …>…</Tag> element, not just the children, so attribute-only edits (e.g. lang="python" → lang="go") are detected by `verify`. The `hash=` field is required at verify time; a missing hash is an error rather than a skip. - #2: validation.entrypoint must be a plain filename (filepath.Base equal, no path separators or ..). Blocks the "snippet writes to ~/.ssh" class of attack via author-controlled YAML. - #3: ld-application.get-started-file is rejected if it's absolute or if filepath.Rel(appDir, full) starts with "..". Blocks the same class via the consumer-side path. - #4: Template tokenizer was treating any token starting with "end" (`endTime`, `endIndex`, …) as `{{ end }}`. Switched HasPrefix → equality. - #6: Marker scanner now tracks <Tag depth so a nested same-tag pair (`<Snippet><Snippet>…</Snippet></Snippet>`) doesn't silently truncate to the inner close. Same-prefix tags (`<SnippetGroup>`) don't count as opens of `<Snippet>`. - #7: runtimeInputs has a `sdk-key` arm wired to LAUNCHDARKLY_SDK_KEY, with a defensive check that flag-key/sdk-key inputs cannot declare a runtime-default (those values must always come from the environment). - #8: validation.requirements rejects newlines and lines starting with `-` so a snippet can't smuggle `--extra-index-url` through to pip. - #9: Backtick-string scanner now tracks `${ … }` expression depth, so a nested template literal inside an interpolation expression doesn't prematurely end the outer string. - #10: Render path split into RenderForLDApplicationTemplate (escaping for backtick literals) and RenderForJSXText (no escaping; for bare text). The bare-text path no longer corrupts backslashes / backticks in user-visible output. - #11: Atomic write — temp file in the same directory, fsync, rename; source file mode is preserved. - #12: Validator Docker tag is a content hash of the validator dir, so concurrent runs against the same validator share the cached image and runs against different validators cannot interleave. - #13: run.sh redacts LAUNCHDARKLY_SDK_KEY from the log dump on failure. - #14: Bare-vs-backticks decision is driven by the snippet's intent (interpolation / multiline / JSX-special chars), not by what's already in the file. Re-renders no longer stay sticky on the wrapped form. - #17: snippet frontmatter and sdk.yaml are decoded with KnownFields(true) so a typo like `Entrpoint:` is a hard error. Cosmetic / docs --------------- - #15: AUTHORING.md notes the uppercase-first JSX-component-tag constraint. - #16: hashLen const + comment documenting the 12-hex-char (~48 bit) budget is for accidental-drift detection only, not integrity. - #19: go.mod uses `go 1.24` (drops the patch version). Tests ----- - New tests for: endFoo regression, unmatched/unclosed `{{ if/end }}`, unknown variable, empty template, RenderForJSXText backslash round-trip, HasInterpolation, ContainsJSXSpecial, scanner edge cases (no markers, block-style, unterminated comment, gap, self-closing, missing close, nested same-tag, similar-prefix tag, nested-backtick), full-element hash detects attribute edits, descriptor-traversal rejects, runtimeInputs rejects runtime-default on key types, requirements rejects pip flags, entrypoint rejects path components. Verified end-to-end ------------------- - go build ./... / go vet ./... / go test ./... all clean - snippets render --target=ld-application --out=<app>: rewrites the file with full-element hashes; second run reports "no changes". - snippets verify ok on the freshly rendered file. - snippets verify rejects: a one-byte attribute edit (lang="python" → lang="go") AND a marker with the hash= field stripped. - snippets validate (with real LAUNCHDARKLY_SDK_KEY / LAUNCHDARKLY_FLAG_KEY) matches the expected flag-evaluation line.
Walk back the part of the prior review-feedback commit that hashed the full <Tag …>…</Tag> region. The scope=content contract says the consumer owns the element's attributes; locking them down forces a re-render every time someone tweaks `withCopyButton` / `label="…"` / `className` and offers nothing the design promised. `verify` now: - requires a hash= field on every marker (#5, unchanged) - compares it against the SHA-256 of src[RegionStart:RegionEnd] (just the children, as originally documented) - accepts attribute-only edits, rejects child edits Tests updated: TestVerify_AcceptsAttributeEdit and TestVerify_RejectsChildEdit pin the new contract; the dead TestFullElementHash_DetectsAttributeEdit is removed; the now-unused Match.FullElementHash method is dropped. End-to-end re-checked: render is idempotent, verify ok, an attribute edit passes verify, a child edit fails verify with a children-hash error, and `snippets validate` against a real LD environment still prints `*** The sample-feature feature flag evaluates to True`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First slice of
snippets/: a self-contained Go module that owns the canonical source for LaunchDarkly SDK code samples and renders them into downstream consumers. Scope:python-server-sdk"Getting Started" flow, end-to-end.In scope
render,verify,validate).ld-applicationadapter — rewrites the body of marked<Snippet>elements in TSX.Out of scope (later slices)
python-server-sdk.ld-docsadapter, GitHub Actions, signed-binary release, sdk-meta capability integration, region/version conditionals.Snippet file
verifyrecomputes the hash and fails on hand-edits inside marked regions.CLI
Test plan
cd snippets && go build ./... && go test ./...clean.snippets render --target=ld-application --out=<app>is idempotent on a checkout that already contains the markers.snippets verifyrejects a hand-edit inside a marked region.snippets validate --sdk=python-server-sdkagainst a real LD test env prints*** The <flag> feature flag evaluates to <value>and exits 0.