feat(snippets): entrypoint-based render + sdk.yaml reduced to id#405
Merged
kinyoklion merged 3 commits intomainfrom Apr 30, 2026
Merged
feat(snippets): entrypoint-based render + sdk.yaml reduced to id#405kinyoklion merged 3 commits intomainfrom
kinyoklion merged 3 commits intomainfrom
Conversation
kinyoklion
added a commit
to launchdarkly/gh-actions
that referenced
this pull request
Apr 29, 2026
The CLI no longer asks each sdk.yaml which file in the consumer to rewrite (see launchdarkly/sdk-meta#405); instead the consumer declares its own list of search roots. Plumb that through: - New required input `entrypoints` (newline-separated list of directories, relative to $GITHUB_WORKSPACE). - Render step parses the input into individual `--entrypoint=` flags and passes them to `snippets render`. - Empty / whitespace-only lines are tolerated and skipped; an empty list fails loudly. - README + the in-action usage block updated to show the new shape. Consumer wiring becomes: - uses: launchdarkly/gh-actions/actions/sync-snippets@main with: entrypoints: | static/ld/components/getStarted github-token: ${{ secrets.GITHUB_TOKEN }}
ff91662 to
6a5ff66
Compare
keelerm84
approved these changes
Apr 30, 2026
6a5ff66 to
b5d7f1e
Compare
Two related schema changes that simplify the contract between this
repo and its consumers:
1. Drop the `ld-application.get-started-file(s)` field entirely.
The renderer no longer asks each sdk.yaml which file to rewrite.
Instead the consumer (gonfalon, ld-docs-private) declares its own
list of entrypoint directories, and the renderer walks them
recursively for files containing the SDK_SNIPPET:RENDER sentinel.
- `Render(sdksFS, entrypoints []string)` and the matching `Verify`
replace the old `(sdksFS, appDir)` signatures.
- The walk skips `node_modules`, `.git`, `.next`, `dist`, `build`,
`.cache`, `coverage`, `out`, `.turbo`. Files are filtered by
extension (.tsx/.jsx/.ts/.js/.mdx) and by a fast bytes.Contains
pre-check for the marker sentinel before invoking the regex
scanner.
- Symlinks are skipped, so a malicious symlink farm in a vendored
directory can't pull the renderer outside the entrypoint.
- Overlapping entrypoints dedupe.
- Empty entrypoint list, missing entrypoint, or entrypoint that
points at a file all fail loudly.
2. Reduce sdk.yaml to a single field: `id:`. The id matches the
SDK's identifier in launchdarkly/sdk-meta's API packages, where the
authoritative metadata lives (display name, type, languages,
regions, hello-world repo, docs URL). Every previously-modeled
field on the descriptor was unread by this codebase; downstream
consumers that need that metadata read sdk-meta directly.
- The `descriptor` struct + `loadDescriptor` function are deleted.
Nothing in the engine reads sdk.yaml today.
- Each of the 23 sdk.yaml files reduces to a header comment plus
`id: <sdk>`.
CLI:
Old: snippets render --target=ld-application --out=<consumer>
New: snippets render --target=ld-application --entrypoint=<dir> ...
--entrypoint is a custom flag.Value that accumulates across repeats
(mirrors the standard Go-stdlib stringSliceFlag idiom).
End-to-end against gonfalon's static/ld/components/getStarted:
- Reset every marker hash to 0 (122 markers in 24 files).
- `snippets render --entrypoint=...getStarted` rewrites all 24
files via the embedded sdks/ tree.
- Diff against pre-reset stash: byte-identical.
- `snippets verify --entrypoint=...getStarted`: ok.
Companion changes follow:
- launchdarkly/gh-actions PR #82 needs to add an `entrypoints` input
that the consumer-side workflow declares.
- This PR stacks on #404 (the embedding +
release pipeline PR).
b5d7f1e to
90fd12a
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 90fd12a. Configure here.
90fd12a to
560f8c0
Compare
Per the schema audit, slot was a write-only field — declared on the LDApplicationHints struct, decoded from frontmatter, never read by any production code. The marker comment carries the snippet id directly, so the per-page lookup slot was meant to power doesn't happen. - Remove the LDApplicationHints struct and the LDApplication field on Frontmatter. - Strip the `ld-application:\n slot: <name>\n` block from all 122 snippet files (KnownFields(true) would otherwise fail to parse them after the struct change). - Render output unaffected: end-to-end against gonfalon shows `no changes` + `ok` from verify.
skipDirNames prunes well-known noise (node_modules, dist, build, …) under each entrypoint, but filepath.WalkDir invokes the callback for the root itself first. If a consumer pointed `--entrypoint=./build` at a project that emits TSX there, the root's basename matched the skip-list and the walk silently produced zero files. Guard the skip check so it only fires beneath the root, and add a regression test.
560f8c0 to
704448f
Compare
kinyoklion
added a commit
to launchdarkly/gh-actions
that referenced
this pull request
May 1, 2026
* feat(sync-snippets): composite action that pulls SDK snippets New action at actions/sync-snippets/. Resolves the latest launchdarkly/sdk-meta `snippets/*` GitHub Release, downloads the platform's signed binary, cosign-verifies it (keyless / OIDC, identity pinned to sdk-meta's release-please workflow), runs `snippets render` against the consumer checkout, and opens or updates a sync PR via peter-evans/create-pull-request when the render produced any diff. Designed for gonfalon (and future ld-docs-private use); both call this with `@main`. Daily cron + workflow_dispatch on the consumer side keeps the consumer current without a coordinated rollout. Implementation notes: - The `snippets` CLI binary embeds the canonical sdks/ tree at build time (sdk-meta side, separate PR). One artifact, one signature check, atomic content + engine pinning. - `--certificate-identity-regexp` matches sdk-meta's release-please workflow path on main, so a token leaked from any other workflow cannot produce a matching OIDC claim. - Per-platform archive name resolution mirrors goreleaser's default template (snippets_<version>_<os>_<arch>.tar.gz). * feat(sync-snippets): switch to consumer-declared entrypoints The CLI no longer asks each sdk.yaml which file in the consumer to rewrite (see launchdarkly/sdk-meta#405); instead the consumer declares its own list of search roots. Plumb that through: - New required input `entrypoints` (newline-separated list of directories, relative to $GITHUB_WORKSPACE). - Render step parses the input into individual `--entrypoint=` flags and passes them to `snippets render`. - Empty / whitespace-only lines are tolerated and skipped; an empty list fails loudly. - README + the in-action usage block updated to show the new shape. Consumer wiring becomes: - uses: launchdarkly/gh-actions/actions/sync-snippets@main with: entrypoints: | static/ld/components/getStarted github-token: ${{ secrets.GITHUB_TOKEN }} * feat(sync-snippets): switch to github attestation verification The upstream sdk-meta release pipeline is moving from cosign keyless sidecars to GitHub's first-party SLSA build-provenance attestation (launchdarkly/sdk-meta#409). Match it on the verifier side: - Replace `cosign verify-blob` with `gh attestation verify --signer- workflow launchdarkly/sdk-meta/.github/workflows/release-please.yml`. Same identity pinning, but the attestation is fetched from sdk-meta's repo-level attestation store rather than as `.sig`/`.pem` release assets. - Drop the `sigstore/cosign-installer` step. `gh` ships preinstalled on every GitHub-hosted runner. - Drop the `id-token: write` permission from the consumer wiring example — verification is read-only against sdk-meta's attestation store and doesn't need an OIDC token. - Update README copy to match. * fix(sync-snippets): drop literal ${{ from action description The action manifest's description: field is template-evaluated at action-load time. Embedding a copy-paste-able workflow snippet that contained ${{ secrets.GITHUB_TOKEN }} caused 'Unrecognized named-value: secrets' parse failures whenever a consumer used the action — secrets aren't in scope when the manifest itself is being loaded. Replace the inline workflow example with a prose pointer to README.md, which carries the full consumer wiring snippet. * fix(sync-snippets): exclude drafts and pre-releases from latest resolution A 'latest' lookup that catches sdk-meta's release-pipeline mid-publish window would point at a draft release whose archives and attestations haven't uploaded yet — and the subsequent 'gh release download' / 'gh attestation verify' would fail noisily but pointlessly. Pre-releases are excluded under the same logic: consumers asking for 'latest' want the latest stable, not a release-candidate the pipeline cut for testing. Per @keelerm84 review on PR #82.
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.

Stacked on #404. Two coordinated schema changes that simplify the contract between this repo and its consumers.
1. Drop `ld-application.get-started-file(s)`; render walks entrypoints
The CLI no longer asks each sdk.yaml which file in the consumer to touch. The consumer (gonfalon, ld-docs-private) declares its own list of entrypoint directories, and the renderer walks them recursively, picking up any file that has the right extension (`.tsx` / `.jsx` / `.ts` / `.js` / `.mdx`) AND contains the `SDK_SNIPPET:RENDER:` sentinel.
`--entrypoint` is repeatable. Walks skip `node_modules`, `.git`, `.next`, `dist`, `build`, `.cache`, `coverage`, `out`, `.turbo` wholesale. Symlinks aren't followed. Overlapping entrypoints dedupe.
This decouples the consumer's directory layout from the snippet sources: gonfalon is free to reorganize `static/ld/components/getStarted/sdk/` however it wants without us shipping a release.
2. `sdk.yaml` reduces to `id:`
The id matches the SDK's identifier in `launchdarkly/sdk-meta`'s API packages. Every other piece of per-SDK metadata (display name, language flavors, supported regions, hello-world repo URL, docs path) lives there as the authoritative source — this repo doesn't need to duplicate it. The `descriptor` struct and `loadDescriptor` function are deleted; nothing in the engine reads sdk.yaml anymore.
End-to-end check against gonfalon
Companion changes
Out of scope
Note
Medium Risk
Medium risk because it changes the
render/verifyCLI contract and the ld-application adapter’s file discovery logic (now walking directories and filtering by sentinel/extension), which could miss or newly include files in consumer repos if entrypoints are misconfigured.Overview
Reworks ld-application rendering to be entrypoint-driven. The
snippets render/verifycommands now require one or more repeatable--entrypointdirectories (replacing--out) and pass these through to the adapter.Changes file discovery from sdk-declared targets to consumer-tree scanning. The ld-application adapter now walks each entrypoint recursively, skips common junk dirs (for example
node_modules,.git,dist,build), ignores symlinks, filters to known extensions (.tsx/.jsx/.ts/.js/.mdx), and only processes files containing theSDK_SNIPPET:RENDER:sentinel; overlapping entrypoints are deduped.Simplifies SDK metadata inputs.
sdk.yamlis reduced to justid:across SDKs, the ld-applicationsdk.yamldescriptor loader is removed, and snippet frontmatter drops theld-applicationhints struct (ld-application.slot). Tests and authoring docs are updated to reflect the new entrypoint workflow and discovery behavior.Reviewed by Cursor Bugbot for commit 704448f. Bugbot is set up for automated code reviews on this repo. Configure here.