From e305b9093486a0bbbf4a37a3c7b8bbf2327111c5 Mon Sep 17 00:00:00 2001 From: Fabian Date: Tue, 4 Aug 2026 13:57:33 +0100 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f62ef952556ebcda3ad568d3864177be628f0af0 Merge: 6c008119 15c3457e Author: Fabian Date: Tue Aug 4 13:56:35 2026 +0100 Merge pull request #305 from launchdarkly/ffeldberg/REL-15193/merge-public-history Merge public ld-openapi history, so mirroring stops conflicting commit 15c3457ec09e701131df6b6e13ada49bfd923b55 Author: Fabian Date: Tue Aug 4 13:23:41 2026 +0100 Drop the Confluence links ahead of mirroring Two comments carried the internal runbook URL - the release.yml header and preflight.sh's - and this repo is mirrored to the public launchdarkly/ld-openapi, where a link nobody outside the company can open is noise at best. Both now refer to "the release runbook" without the URL; the surrounding explanations, which are the part that actually helps a reader, are untouched. Nothing else was changed. The remaining references to internal repositories, paths, the trust-policy identity and the Slack channel are reasonable to have in public: they are names of things, not credentials, and several are already public - .github/runs-on.yml with its `_extends: .github-private` exists verbatim in the public repo today. The only other match in the tree is the generator jar, which is a local download and gitignored; no .jar is committed. Co-Authored-By: Claude Opus 5 (1M context) commit 951b78585e748f788d6bc7ef342e899b7f8e5f3c Merge: 6c008119 dd8e70fe Author: Fabian Date: Tue Aug 4 13:12:59 2026 +0100 Merge public ld-openapi history, keeping this repo's work The two repos last shared an ancestor in October 2024 (94cdd5e5, "prepare 17.0.0 release"): 224 commits here, 10 there. That is why mirroring private onto public conflicts add/add on the workflow files - both sides created them independently after the split - and why the mirror job has never completed. Merging public in first establishes shared history, so the mirror in the other direction is an ordinary fast-forwardable merge rather than a conflict to re-resolve by hand on every release. Content-wise this changes almost nothing, which is the useful finding: public had nothing this repo lacks. All four conflicts resolved to our side. README.md, Makefile public's are strict subsets. Ours keeps the axios 1.18.1 pin and the push_dry_run prerequisite. ci.yml, release.yml ours; public's predate the automation entirely. samples/javascript, left deleted. Neither existed at the merge base; templates/javascript public acquired them through earlier mirror merges and a01aa45c removed the php and javascript targets here deliberately. Re-adding them would undo that. The 10 public-only commits are duplicates of work already here, applied separately - the SEC-7924 action pinning and the CODEOWNERS renames - so nothing unique is lost. CODEOWNERS and dependency-scan-gha.yml were already identical. Also pins runs-on/action, the one third-party action still on a floating tag, to match what SEC-7924 established on the public side. launchdarkly/octosts-action stays on @v1 deliberately: it is first-party and its maintainer pushes security updates to that tag. Verified: no conflict markers, all three workflows parse, selfcheck 10/10, and the staged tree differs from this repo's main by exactly the one pin. Co-Authored-By: Claude Opus 5 (1M context) commit 6c008119702631d051f93c9556f794d935c7b49f Merge: b59f010b 6a22265b Author: Fabian Date: Tue Aug 4 12:47:23 2026 +0100 Merge pull request #304 from launchdarkly/ffeldberg/REL-15193/downstream-and-verify-fixes Fix the three defects the 24.0.0 release exposed commit 6a22265ba3c63f55c068ec22b5419511c67b049f Author: Fabian Date: Tue Aug 4 12:24:52 2026 +0100 Skip the trust-policy checks on a response that is not a policy The selfcheck job failed in CI on this branch, reporting that the policy grants no permissions and lists no repositories: repos/${GONFALON}/commits/main needs 'contents' but the policy grants: [] FAIL pr-downstream targets absent from the policy's repositories: ... Caused by the change in the previous commit that gave the CI step a GITHUB_TOKEN. The policy lives in a private repo that token cannot read, so `gh api` now returns a 404 error body on stdout instead of nothing. The fetch used `|| true`, which discarded the exit status but kept the body, and a GitHub API error body is valid YAML - so it parsed into a dict with none of the keys the checks read, and they failed against something that was never a policy. Before the token was added, gh produced no output and the checks skipped correctly. Two fixes, because either alone leaves a hole. The fetch now respects gh's exit status rather than swallowing it, and the result is shape-checked for the four keys the checks actually read before any of them run. Anything else means SKIP, with a message naming which situation applies - not readable at all, or fetched but not a policy - so a skip is diagnosable instead of ambient. This is the same defect class as the previous commit, one layer along: there the check passed having verified nothing, here it failed having verified something that was not the subject. Validate the input before trusting a verdict about it. Verified against the exact CI condition - a stub returning the 404 body with a non-zero exit - which now yields three SKIPs and exit 0; against a 200 whose body is not a policy, which SKIPs and names the missing keys; and with the real policy present, which still runs everything, 10/10. Co-Authored-By: Claude Opus 5 (1M context) commit da4734df42b62cf9370523770fab230b4d15a2e8 Author: Fabian Date: Tue Aug 4 12:09:24 2026 +0100 Bring CLAUDE.md and README.md up to date, and keep internals out of both This repo is mirrored to the public launchdarkly/ld-openapi, so both files are effectively public. Neither now names the internal service repo that owns the spec, the federated-token infrastructure or its trust-policy identity, the internal policy or IaC repositories, internal service accounts, team names, Slack channels, or internal documentation URLs. The public repo has no references to any of those today, so this keeps that boundary rather than widening it. Where an internal system matters to understanding the flow it is described by what it does, with the concrete names left to the workflow files. CLAUDE.md is also brought current: the three gates and their overrides, the credential audit, both downstream PR jobs and why they are skipped on a rehearsal, verify-published's hard and soft checks and the reason the Go proxy is soft, the selfcheck harness and the two rules it enforces about itself, the id-token requirement including the reusable-workflow double grant, and the fact that a rehearsal's log is nearly indistinguishable from a real release. Also records the immutability of published registry versions and the re-run failed jobs rule, which are the two things most likely to turn a partial failure into a worse one. README.md previously described releases in one sentence. It now walks the actual sequence, lists the inputs worth knowing, and states the immutable-version constraint. It also documents single-language generation, the template override convention and its coupling to GENERATOR_VERSION, and how generated clients are verified - all things a reader of the public repo would otherwise have to infer from the Makefile. Co-Authored-By: Claude Opus 5 (1M context) commit e179fc8f656fa8ffd48fb6a8b074a33d33dde01f Author: Fabian Date: Tue Aug 4 12:01:49 2026 +0100 Stop selfcheck passing when it verified nothing Review finding, and correct. The ACTION-INPUTS check swallowed every lookup failure and only counted successes, so if no action could be resolved it printed "CHECKED 0" and then PASSed. In CI that was guaranteed: the selfcheck step had no GH_TOKEN, so `gh api` failed for every action and the check reported success having verified nothing - false assurance about exactly the mistake it was added to catch. Now reports SKIP when it resolved nothing, and SKIP naming the specific actions when it resolved only some, rather than passing on a partial sample. The CI step also now passes GITHUB_TOKEN, which is sufficient to read the pinned action repos - all public - so the check actually runs there instead of skipping forever. A permanently-skipped check is barely better than a falsely-passing one. The same shape existed in two other checks, so fixed the class rather than the instance: a count derived by extracting from the workflows means "the extractor broke" far more often than it means "the repo is clean". The OIDC check now cross-references the raw YAML text and fails if the workflows mention octosts-action while it detected no token-minting job; POLICY-REPOS fails if it finds no pr-downstream targets at all. Verified: unauthenticated gh now yields SKIP rather than PASS; breaking the OIDC extractor while leaving the real usage in place is caught as "the check is broken"; a normal local run still passes 10/10. Co-Authored-By: Claude Opus 5 (1M context) commit ee1baff0785af5a54a2d6bdc84ac5bcca1fd8fc1 Author: Fabian Date: Tue Aug 4 11:53:23 2026 +0100 Fix the three defects the 24.0.0 release exposed All three surfaced only during a real release, and all three are now covered by selfcheck so they cannot recur silently. Team reviewers cannot be requested with a federated token. The provider job failed with "Unable to request reviewers. If requesting team reviewers a 'repo' scoped PAT is required" - after it had already created PR #528 - so the work succeeded and the job went red on a trailing step. This is a consequence of moving from a PAT to OctoSTS; foundation's workflow gets away with team-reviewers because it still uses a PAT. Both downstream jobs now request the dispatcher instead. CODEOWNERS in each downstream repo still pulls in the owning team, so nothing is lost. The pinned pr-downstream has no `dryrun` input. Passing one produced only a warning, and the value was ignored, so both downstream jobs were attempting real PR creation during a rehearsal. They only failed to open PRs because the version they bump to did not exist yet - luck, not design, and the dry run's safety was documented on the strength of that input existing. Both jobs are now skipped outright when dryRun is set, which is honest about what a rehearsal can cover: these jobs cannot be exercised without a published version to bump to. The Go module proxy check is now soft rather than hard. Go has no publish step - the tag is the release, and the tag is already checked directly - and proxy.golang.org caches negative lookups, so the earlier dry run's `go get` for v24.0.0 made it serve "unknown revision" for a while afterwards. That failed verify-published on a release where every registry had in fact published, which then skipped the GitHub releases and both downstream PRs. Adds an ACTION-INPUTS check to selfcheck: for every third-party action pinned to a ref, it fetches that ref's action.yml and asserts each input the workflow passes is actually declared. Verified by reintroducing `dryrun` and confirming it is caught as "not an input of launchdarkly-labs/pr-downstream@08b3feb5df32". Covers 24 pinned action/input pairs. Co-Authored-By: Claude Opus 5 (1M context) commit b59f010b9267ea7f634428f33024616633b8a5d4 Merge: 2a1a906e 9ce6910e Author: Fabian Date: Mon Aug 3 16:48:01 2026 +0100 Merge pull request #303 from launchdarkly/ffeldberg/REL-15193/parity-gate-diagnostics Say what the spec-parity gate is waiting for commit 9ce6910e63988797cc531b7ce78db8821616b88a Author: Fabian Date: Mon Aug 3 16:24:25 2026 +0100 Close a blind spot in selfcheck's endpoint extraction Review finding, and correct on both counts. The drift-explanation block added a gonfalon call listing commits that touch the spec path. Its URL sits on a backslash continuation line, and the extractor matched only `gh_gonfalon api "..."` on a single line - so the call was invisible. It was therefore neither validated against the granted permissions nor reported as unrecognised, which is exactly the silent gap the endpoint table exists to close. Six calls existed; selfcheck was checking five. That is worse than a missing table entry, because it defeats the guarantee documented in CLAUDE.md: an unknown endpoint is supposed to fail rather than be assumed fine. A missing entry is loud; an undetected call is not. Fixes both halves: - joins backslash continuations before extracting, so no future call can slip past regardless of formatting, and errors out if extraction finds nothing at all rather than silently passing an empty set - adds /commits?path= -> contents to the table Now checks 6 of 6 calls. The endpoint needs `contents`, which the policy already grants, so no trust-policy change is needed. Verified by planting an unrecognised endpoint on a continuation line - now caught as "not in selfcheck's endpoint->permission table" - and by pointing a same-line call at /status, still caught as needing an ungranted permission. Co-Authored-By: Claude Opus 5 (1M context) commit 0333f8a8b43fcdb165f81ef375bdafd0769c0eca Author: Fabian Date: Mon Aug 3 16:16:19 2026 +0100 Add skipSpecParity, so a pending deploy cannot block a release Gate 1 refuses to release while gonfalon main's spec is ahead of production. That is the right default - it keeps the published release notes matched to the spec that actually ships - but it has no override, so an undeployed spec commit blocks the release entirely, for as long as the deploy takes. Right now that is holding up 24.0.0 over six schema properties: VR-65 adds _site/_links.site to AITool, PromptSnippet, AgentGraph, AIConfigs, PromptSnippets and AITools, and production has not picked it up in over two hours. Paths and schema counts are otherwise identical between the two specs. skipSpecParity releases what production is serving. It does not change what ships, since the build downloads the spec from production either way - it changes whether the run refuses to proceed. The cost is that version and changelog still come from main, so release notes may describe merged-but-undeployed changes and the downstream gonfalon PR would record them against this version. Those entries need trimming in that PR, which requires review anyway. The gate logs exactly that when the flag is used. Default is unchanged: without the flag it still waits and then fails with the commit it was waiting on. Co-Authored-By: Claude Opus 5 (1M context) commit 98f8799c0330c7981c76541b0eda352ef34675f3 Author: Fabian Date: Mon Aug 3 16:08:47 2026 +0100 Say what the spec-parity gate is waiting for The gate reported only two blob hashes - "prod=c0314584 main=1a42c60b" - then polled silently for up to 30 minutes. That says nothing about what is in flight or how stale production is, which is the only question an operator has when a release stalls here. On the first mismatch it now resolves prod's blob back to the gonfalon commit that produced it, and names both sides: prod is serving apidocs/openapi-public-final.json from 70f24a20b 2026-07-31T17:20:52Z feat(releases): expose active phase status on release progression API (#68403) main's latest spec commit is f5999286e 2026-08-03T14:59:00Z Add canonical relative _site links to public API resources (VR-65) (#67542) Resolved once rather than per poll, so a long wait costs a handful of extra API calls rather than hundreds. If prod's spec matches no recent commit on main it now says so explicitly instead of waiting silently. That would mean production is serving something never merged, or the file moved, and either is worth stopping for. The timeout message names the commit being waited on and why the wait matters: releasing early would publish release notes describing endpoints the shipped spec does not contain. Co-Authored-By: Claude Opus 5 (1M context) commit 2a1a906eedf123002e92ce6669b7d171c7ae23dc Merge: e5599709 69d3a58c Author: Fabian Date: Mon Aug 3 15:58:07 2026 +0100 Merge pull request #302 from launchdarkly/ffeldberg/REL-15193/gonfalon-checks-permission Fix the gonfalon CI gate and the OctoSTS scope check commit 69d3a58c0e972cc8a3a2c6a63765af7b1d6f31a8 Author: Fabian Date: Mon Aug 3 15:48:58 2026 +0100 Add a local selfcheck for the release automation Every failure in this automation so far was discoverable without running a release, but nothing was checking for it, so each one cost a merge, a dispatch, and a wait. This closes that loop: static checks that run in seconds locally and gate CI. One check per defect that actually shipped: OIDC a job used octosts-action without id-token: write POLICY-PERM the CI gate called an endpoint the trust policy did not permit POLICY-MATCH an unanchored job_workflow_ref that could never match POLICY-REPOS a downstream target missing from the policy's allowlist SECRETS a workflow referenced a secret that did not exist DRYRUN a make dry-run target that was a silent no-op PORTABILITY mapfile and bare sed -i, which break on macOS bash 3.2 Verified by reintroducing all six defects one at a time and confirming each is caught with a specific message, not just a generic failure. The endpoint-to-permission table is the interesting part: it maps each API call preflight makes through the federated token to the GitHub App permission that call requires, and fails if the trust policy does not grant it. An unrecognised endpoint is a failure rather than an assumed pass, so adding a call without considering permissions cannot silently reintroduce a 403. Trust-policy checks need the policy, which lives in the private launchdarkly/.github-private. Locally it is read from a checkout or via gh; in CI neither is available, so those three checks skip and the run still passes on the remaining five. Confirmed by running with gh shadowed by a failing stub. Also quotes the bump assignments in preflight.sh to clear SC2209, so shellcheck is clean at -S warning across every script this automation owns and the gate is meaningful. Co-Authored-By: Claude Opus 5 (1M context) commit 139d1c6362dcf03ee5585e8a4ca0e11e056b639d Author: Fabian Date: Mon Aug 3 15:32:14 2026 +0100 Fix the gonfalon CI gate and the OctoSTS scope check Two separate defects, found by the second dry run on main. The id-token fix worked - the token minted and the trust policy matched - so these are what was behind it. Preflight's Gate 2 died with "Resource not accessible by integration (HTTP 403)". It called /commits/{sha}/status, which needs the `statuses` permission. No policy in launchdarkly/.github-private grants that and it may not be available on the OctoSTS app at all, so the gate now uses check-runs only, which needs `checks: read` - granted, and with precedent in service-template-go-sync. The tradeoff is that legacy commit statuses from external systems are no longer considered; the GitHub Actions checks are what "is gonfalon green" means here. Also paginates, which the previous version did not: gonfalon main currently has 84 check runs, well past the first page of 30. The audit reported "missing push on launchdarkly/gonfalon (granted: none)" for a token that had just been minted with contents: write. The check inspected `.permissions` on the repo endpoint, which reports a *user's* role - push, pull, admin - and an App installation token has no role, only granular permissions, so that field is always empty for it. My local tests passed only because I stood a PAT in for the minted token, which does have a role. It now enumerates scope with /installation/repositories, which is what actually catches the failure worth catching: a repo missing from the policy's allowlist. An installation token's permission set cannot be read back over the API, so write access is reported UNVERIFIED and is proven only when a downstream PR opens. Requires adding `checks: read` to the trust policy; that is a separate change in launchdarkly/.github-private. Co-Authored-By: Claude Opus 5 (1M context) commit e559970938c3ec7286b926cdbb10e810ebf93ce0 Merge: d0bb8ac4 3c690bcd Author: Fabian Date: Mon Aug 3 15:21:19 2026 +0100 Merge pull request #301 from launchdarkly/ffeldberg/REL-15193/octosts-id-token-permission Grant id-token: write to every job that mints an OctoSTS token commit 3c690bcd5412f4daca956ca350ab24b9952ad185 Author: Fabian Date: Mon Aug 3 15:04:29 2026 +0100 Grant id-token: write to every job that mints an OctoSTS token The first dry run on main failed in both Preflight and Token audit with: Missing required environment variables - have you set 'id-token: write' in your workflow? octosts-action exchanges a GitHub Actions OIDC token, which requires id-token: write on the job. Only the release job had it, granted long ago for the AWS OIDC role that fetches the Java signing key; the four jobs added by the release automation did not, so every exchange failed before it could reach the trust policy. Adds it to preflight, downstream-gonfalon, downstream-terraform-provider, and the token-audit caller. For token-audit it has to be granted twice - on the calling job here and at the workflow level in token-audit.yml - because a reusable workflow is capped by the permissions its caller holds, and token-audit.yml's own block previously restricted it to contents: read. Nothing was wrong with the trust policy: the exchange never got far enough to consult it. The audit's continue-on-error on the mint step did its job, reporting "no federated token was minted" and still checking everything else, which is what isolated this to the OIDC step rather than the policy. Co-Authored-By: Claude Opus 5 (1M context) commit d0bb8ac407088e8c3edca93cc164015dddc144b7 Merge: f71c64cd a6e006e1 Author: Fabian Date: Mon Aug 3 15:00:02 2026 +0100 Merge pull request #300 from launchdarkly/ffeldberg/REL-15193/automate-openapi-client-releases Prepare for fully automating openapi client releases commit a6e006e1998378eec05ee8f2af337d5859b2dead Author: Fabian Date: Mon Aug 3 14:48:09 2026 +0100 Correct the pre-merge testing note for the main-only trust policy The OctoSTS grant is pinned to refs/heads/main, so the earlier claim that branch dispatches federate no longer holds. Everything else in release.yml is still testable from a branch; the federated-token steps are not. Co-Authored-By: Claude Opus 5 (1M context) commit d8fbfa52554dd599bf5000b9d72c3dd75bf5157a Author: Fabian Date: Mon Aug 3 14:27:58 2026 +0100 Document that OctoSTS claim patterns are anchored octo-sts compiles each claim pattern as regexp.Compile("^" + v + "$"), and job_workflow_ref always carries an @refs/heads/... suffix, so a pattern ending at .yml silently matches nothing and every token exchange is denied. Cost us a round of review on the trust policy; worth recording next to the other two traps. Co-Authored-By: Claude Opus 5 (1M context) commit d38a46d222851aabdfed1fce996b90d0f14a88cf Author: Fabian Date: Mon Aug 3 14:22:55 2026 +0100 Request review from team-enterprise on the provider PR terraform-provider-launchdarkly's CODEOWNERS assigns everything outside /docs/ to @launchdarkly/team-enterprise. team-integrations was a guess and wrong. Co-Authored-By: Claude Opus 5 (1M context) commit b86a2edfd9b073d4519fca4ffa1142c66364f7fe Author: Fabian Date: Mon Aug 3 14:18:06 2026 +0100 Federate downstream access with OctoSTS, and add the terraform provider Replaces the PR_CREATOR_GH_TOKEN approach entirely, per review feedback on the terraform PR: OctoSTS mints credentials at runtime, so no long-lived token has to be provisioned, stored, or rotated for this. The terraform change that would have added one is dropped. Both downstream jobs and the preflight gonfalon reads now take their token from launchdarkly/octosts-action@v1, governed by a ld-openapi-downstream trust policy in launchdarkly/.github-private. BOT_TOKEN keeps only what it already had: the client repos and the public mirror. Two things about the policy that are easy to get wrong. LaunchDarkly's instance reads policies from .github/launchdarkly/, not the .github/chainguard/ path that both the upstream octo-sts README and the action's own docs document - the documented path exists nowhere in the org. And org-scoped policies carry a `repositories` allowlist, so a new downstream target has to be added there or the minted token cannot see it. Adds downstream-terraform-provider, so a release also opens a bump PR against terraform-provider-launchdarkly. That repo gets its own `make update-api-client-go`, mirroring gonfalon's, keeping each codemod beside the imports it rewrites - ~220 files there, and plain Go rather than bazel. Its commit message uses a chore(deps) prefix because the repo runs release-please and a feat prefix would cut a provider release on its own. The token audit now mints a token and checks it rather than inspecting a stored secret. What fails with federation is the federation: a missing policy, a job_workflow_ref that does not match, or a repo left out of the allowlist. It checks both downstream repos, and reports clearly when no token was minted at all. Note the policy has to name token-audit.yml as well as release.yml, because a reusable workflow reports its own path in job_workflow_ref, not the caller's. Co-Authored-By: Claude Opus 5 (1M context) commit d6efcf2561ffb741600416620b9d07339a5a0ab8 Author: Fabian Date: Mon Aug 3 13:51:45 2026 +0100 Detect the terraform placeholder in the token audit The SSM parameters backing these secrets are created by terraform holding the literal string SET_IN_PARAMETER_STORE, and the real value is written by hand afterwards. Between those two points the GitHub secret exists but is the placeholder, and GitHub answers an API call with it as "Bad credentials" - true but unhelpful. Name the actual situation instead. Co-Authored-By: Claude Opus 5 (1M context) commit ffff51c05bb2e1a2e4a3f9f13654ee3174718038 Author: Fabian Date: Mon Aug 3 13:44:21 2026 +0100 Set GOPRIVATE for the gonfalon downstream job pr-downstream rewrites all github.com URLs to authenticate with the supplied token, and gonfalon's `make tidy` then resolves Go modules from private launchdarkly repos. Without GOPRIVATE, go consults proxy.golang.org for those paths and gets a 404. The equivalent gonfalon job in launchdarkly/foundation's pr-downstream workflow sets this at the workflow level; ours had not. Co-Authored-By: Claude Opus 5 (1M context) commit 5fdbee71b0a334e425e1df887e7336933fcdd1d6 Author: Fabian Date: Mon Aug 3 13:41:53 2026 +0100 Read gonfalon with PR_CREATOR_GH_TOKEN, and stop failing valid RubyGems keys Findings from the first dispatched token audit. BOT_TOKEN cannot see launchdarkly/gonfalon at all, so preflight died on its very first gate. It should never have been asked to: BOT_TOKEN is the releaser credential for the client repos, and granting the release bot read access to the main application repo just to fetch a spec blob and a changelog is the wrong trade. Preflight now reads gonfalon through GONFALON_TOKEN, defaulting to PR_CREATOR_GH_TOKEN, whose service account already has push on gonfalon. Client repo calls still use BOT_TOKEN. Consequence: PR_CREATOR_GH_TOKEN is needed on every run, not only when the downstream PR job is enabled, so the audit now demands read unconditionally and push only when that job will run. The RUBYGEM_API_KEY failure was my check, not the credential. RubyGems API keys are scoped, and a key scoped to push_rubygem - which is all releasing needs, and the correct level of privilege - is rejected by /api/v1/profile/me.json. The last release published fine, so the key is valid. There is no read-only endpoint a push-only key can pass, so this is now reported UNVERIFIED alongside PYPI_TOKEN rather than as a failure. Also softened the Central Portal probe: a non-401/403 response reflects the probe's request shape, not the credentials. Verified the probe still detects genuinely bad credentials, which return 401. Confirmed by the same audit run: BOT_TOKEN does have push on the public ld-openapi, so dropping PUBLIC_MIRROR_GH_TOKEN was correct. Co-Authored-By: Claude Opus 5 (1M context) commit ac9c822b0530ffb69754f0df0a3c1b4cd6f7f531 Author: Fabian Date: Mon Aug 3 12:28:43 2026 +0100 Use BOT_TOKEN for the public mirror instead of a new secret Checking how the terraform repo provisions these credentials showed that one of the two secrets this branch introduced does not need to exist. Public ld-openapi grants "sa-release-bots" = "Releaser" in accounts/github/launchdarkly/common/repo_ld-openapi.tf, the identical grant the api-client-* repos carry, and BOT_TOKEN is the releaser token (/global/services/github/releaser-github-token) that already pushes to those repos on every release. So the mirror can use BOT_TOKEN for both sides, and PUBLIC_MIRROR_GH_TOKEN is dropped: one fewer secret to provision, and no terraform change needed for mirroring. The audit now checks BOT_TOKEN's push access on launchdarkly/ld-openapi rather than the existence of a separate secret, still gated on mirrorPublic. PR_CREATOR_GH_TOKEN is left as is. It resolves as an organization-level secret: foundation's pr-downstream workflow has been succeeding with no repo-level secret of that name and none declared for it in terraform. Whether it reaches this repo depends on the org secret's visibility, which needs org admin to read, so the token audit is the way to find out. CLAUDE.md records the fallback - declare it per-repo as integration-framework-private, accelerate, and gonfalon do. No access grant is needed on gonfalon either way: pd-sa-pr-creator already has push there. Co-Authored-By: Claude Opus 5 (1M context) commit f4e5ff14c34c97ff632d1453a18f3063c205d0c7 Author: Fabian Date: Mon Aug 3 12:21:11 2026 +0100 Pin axios to 1.18.1 to unbreak the TypeScript client build The generated TypeScript client has stopped compiling, which blocks CI on every PR and would fail a real release at build_clients: common.ts(108,14): error TS2527: The inferred type of 'createRequestFunction' references an inaccessible 'unique symbol' type. A type annotation is necessary. Nothing in this repo caused it. axios 1.19.0, released 2026-07-29, added `declare const axiosResponseDefault: unique symbol` to index.d.ts and refers to it from the public return type of request(). The symbol is never exported, so tsc cannot name it while inferring the type of createRequestFunction. Because axiosVersion was a floating ^1.13.1, every build since picked up 1.19.0. Bisected locally: 1.13.1 through 1.18.1 all build, 1.19.0 alone fails. The last green CI run was 22 June, when 1.18.1 was current. Not fixed upstream: openapi-generator master still emits the unannotated function, and 1.19.0 is still axios latest with no patch release. Pinning is deliberately the stopgap rather than the fix. The real fix is a common.mustache override annotating the returned closure, `): Promise =>` with `as Promise` on the axios.request call, which I verified compiles clean against 1.19.0 and against older axios. It is deferred because it adds a fifth template override to keep in sync on generator upgrades. The Makefile comment records both the reasoning and when to revert. Verified by regenerating the client from scratch and running what CI runs: npm install, tsc and the esm build both emit, and the sample compiles against the result. The sample's npm start was not run locally as it needs LD_API_KEY and creates a real flag. Co-Authored-By: Claude Opus 5 (1M context) commit fc72f93bd6eb57f2d5cb86c616ee0954d99e22c4 Author: Fabian Date: Mon Aug 3 12:10:16 2026 +0100 Fix release-graph and dry-run defects found in review Three defects, all real: verify-published demanded a v tag on all five client repos, but `make push` tags only Go that way; the other four get a bare , and their v tag is created later by create-release, which runs *after* verification. Every healthy release would have reported four failures, failed the job, and skipped create-release, the gonfalon PR, and the mirror - telling the operator to delete tags and retry. My own validation missed it because I tested against 23.0.0, an already-completed release where create-release had long since added the v tags. Now checks what exists at that point in the graph. `make push_dry_run` was a no-op: the target carried GIT_PUSH_COMMAND and GIT_PUSH_DESC assignments but, unlike push_test, no prerequisite on `push`, so it printed "Nothing to be done" and exited 0. A rehearsal therefore never cloned a client repo, never committed, and never checked push access, while CLAUDE.md claimed it did all three. Latent in the repo before this branch, and the pre-existing publish-dry-run.sh was affected too. Version derivation took the first entry of the tags endpoint, which GitHub does not document as semver-sorted and which is not lexicographically safe either (v9.0.0 vs v17.0.0). Now filters to release tags and sorts with sort -V. Also adds openDownstreamPr, mirroring mirrorPublic, and makes the token audit demand only the credentials the current run will use. Without this a missing PR_CREATOR_GH_TOKEN or PUBLIC_MIRROR_GH_TOKEN blocks the audit gate and so blocks any rehearsal - neither secret exists in this repo yet, so the flow could not be exercised at all before creating them. Co-Authored-By: Claude Opus 5 (1M context) commit 5a233dfe54d13e1d98569032b809eb1befae0913 Author: Fabian Date: Mon Aug 3 11:40:49 2026 +0100 Audit release credentials read-only, and gate releases on it Answers "do these tokens have the permissions they need?" without a release. A dry run cannot: create-release is skipped entirely, pr-downstream skips PR creation, and the publish dry-run scripts never authenticate to any registry, so a rehearsal proves almost nothing about credentials. token-audit.sh asks each provider directly, using only GETs and whoami-style calls. For GitHub it reads `.permissions` on the repo endpoint, which reflects what that specific token can do. It reports UNVERIFIED rather than passing silently where no read-only check exists: PyPI has no token introspection endpoint, and confirming LD_API_KEY can write would mean writing. This runs as a gate on every release rather than only on rehearsals. A bad registry credential would otherwise surface after `make push` had already tagged five client repos, which is the case that forces the delete-the-tags-and-retry dance the runbook warns about. Mirroring is checked conditionally so a missing PUBLIC_MIRROR_GH_TOKEN cannot block a release that runs with mirrorPublic off. Also fixes a bug in the dry-run path added in the previous commit: the scripts/release-dry-run/*.sh scripts all copy their would-be-published artifacts into LD_RELEASE_ARTIFACTS_DIR and fail on mkdir when it is unset, which it was. The workflow now sets it and uploads the result, so a rehearsal also shows exactly what would have been published. ci.yml gains workflow_dispatch, both so it can run against any branch and because its sample programs create and delete a real flag - which is the only way to confirm LD_API_KEY has write access, the one thing the audit cannot check. Co-Authored-By: Claude Opus 5 (1M context) commit 16dfecf27e7121ab045d0329a16f10f4f2ca1c5f Author: Fabian Date: Mon Aug 3 11:33:54 2026 +0100 Add CLAUDE.md Documents what is not discoverable from a quick read of the repo: that this is a generator rather than a library, that the spec is downloaded from production at build time so build output depends on what is deployed, that the mustache overrides are verbatim upstream copies which must be re-copied when GENERATOR_VERSION moves, and how the release automation and its gates work. Also records two things that mislead on inspection: `make push` clones api-client-typescript-axios, which is a GitHub redirect to the renamed api-client-typescript rather than a mismatch to fix; and non-Go client repos carry two tags per release, a bare X.Y.Z from `make push` plus vX.Y.Z created by the create-release job, both of which must be deleted before retrying a failed release. Co-Authored-By: Claude Opus 5 (1M context) commit 1f58676806a67e76eefcd4cc8fd32ff0dff7b52e Author: Fabian Date: Mon Aug 3 11:33:43 2026 +0100 Automate the client library release runbook Releasing client libraries required a human to work through a Confluence runbook: check that gonfalon is healthy, ask in Slack whether any spec changes are mid-flight, decide patch/minor/major from the changelog, wait for the spec commit to reach production, paste the version and changelog markdown into a workflow_dispatch form, spot-check the registries, then open two gonfalon changes and mirror this repo to its public counterpart by hand. release.yml now derives its own inputs and enforces each precondition as a gate, so a normal release is a dispatch with no inputs at all. Every input that remains is an override: releaseVersion, bumpType, dryRun, force, mirrorPublic, skipCiGate. The key gate is spec parity. gonfalon commits the published spec at apidocs/openapi-public-final.json and production serves that file byte for byte, so `git hash-object` of the production download equals gonfalon's git blob SHA for that path. Equality means production is caught up AND nothing is mid-flight, which is what the Slack check and the wait-for-deploy step were approximating. It is polled until it holds, and compared by blob SHA through the tree API because the file is ~2.8MB, past the contents API's 1MB raw limit. Every subsequent read from gonfalon is pinned to the commit parity resolved to: main moves often, and reading the spec and the changelog at separate moments can otherwise pair a changelog with a spec it does not describe. Bump type is inferred from the '### ' headings of gonfalon's [Unreleased] section. '### Changed' is genuinely ambiguous, covering breaking and additive changes alike, so the rule errs toward major and an unrecognised heading aborts rather than guesses. Post-publish, the workflow polls the registries and client repo tags instead of trusting a spot-check, opens a single gonfalon PR carrying both the changelog rename and the api-client-go bump, and squash-mirrors onto the public repo. Two deliberate stopping points: the gonfalon PR does not auto-merge, because a major bump rewrites import paths across ~18 Go files and the Bazel graph; and the mirror aborts on conflict rather than resolving, because that push is not practically reversible and the runbook's guidance there is "use your discretion". The gonfalon dependency codemod lives in gonfalon as `make update-api-client-go`, beside the imports it rewrites, rather than in a workflow YAML here. publish.sh gains a DRY_RUN path routing to push_dry_run and publish_dry_run, so a dispatch with dryRun rehearses the whole flow while pushing and publishing nothing. Co-Authored-By: Claude Opus 5 (1M context) commit f71c64cd69981c5ecfe38e526b5f7794a9419930 Merge: 33d54cc2 8adf2b2a Author: ari-launchdarkly Date: Wed Jun 17 11:29:43 2026 -0700 Merge pull request #298 from launchdarkly/devin/1781712015-replace-fm-foundations-with-team-foundation Replace team-fm-foundations with team-foundation in CODEOWNERS commit 8adf2b2afd72079e32a5620d4538afb91c884e6b Author: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed Jun 17 16:00:16 2026 +0000 Replace team-fm-foundations with team-foundation in CODEOWNERS commit 33d54cc2308bd5ae9da5c43d6a1e0de495406b51 Merge: 3f87e7c1 34580ece Author: Owen McCarthy Date: Tue Mar 24 09:43:17 2026 -0400 Merge pull request #296 from launchdarkly/security/SEC-7924/pin-github-actions chore: [SEC-7924] pin third-party GitHub Actions to commit SHAs commit 34580ece17b33599919cc9ffd434c52308159843 Author: Patrick Kaeding Date: Mon Mar 23 23:22:07 2026 -0400 [SEC-7924] chore: pin third-party GitHub Actions to commit SHAs Pin all third-party GitHub Actions to full-length commit SHAs to prevent supply chain attacks. Addresses findings from the third-party-action-not-pinned-to-commit-sha Semgrep rule. commit 3f87e7c1043a786bee5a105dc796a30d99976ba1 Merge: a01aa45c dbef4100 Author: Kane Parkinson <93555788+kparkinson-ld@users.noreply.github.com> Date: Wed Mar 18 11:32:34 2026 -0700 Merge pull request #295 from launchdarkly/devin/1773853464-update-codeowners-team-name Update CODEOWNERS: rename team-fm-next to team-fm-foundations commit dbef410061f7191faae111a62e48aa69b3f2f224 Author: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed Mar 18 18:04:11 2026 +0000 Update CODEOWNERS: rename team-fm-next to team-fm-foundations Co-Authored-By: Kane Parkinson commit a01aa45cd0f3c1157acd9bed71468638cda4a5e2 Author: Ben Woskow <48036130+bwoskow-ld@users.noreply.github.com> Date: Fri Jan 23 16:46:14 2026 -0800 [REL-11803] removing the php and javascript targets (#294) removing the php and javascript targets commit 7eab99a5ad75ec763b0ea5716c6cf5078b331ee8 Author: Ben Woskow <48036130+bwoskow-ld@users.noreply.github.com> Date: Wed Jan 7 13:07:28 2026 -0800 [REL-11491] Extracting out the api version value to a variable (#293) commit 52ac35599899195b42297042ce468143a4ac8afc Author: Ben Woskow <48036130+bwoskow-ld@users.noreply.github.com> Date: Wed Jan 7 10:26:07 2026 -0800 [REL-11491] Setting the default API version to v4 + fixing several CI breakages (#291) commit e27ba4fb0546ba8887d43f40a1ae9a4da32fa74d Merge: 6284ec26 3781843c Author: Tony Knopp Date: Wed Jan 7 12:06:24 2026 -0500 Merge pull request #292 from launchdarkly/tknopp/chore/update-codeowners Update CODEOWNERS for Next ownership commit 3781843ce80d2baee83854f7d02494cd441486b9 Author: Tony Knopp Date: Wed Jan 7 11:55:34 2026 -0500 Update CODEOWNERS Adding fm-next commit 6284ec261eee157295f52b24d99a52d7e2a45a3d Author: Drew Inglis Date: Wed Dec 3 15:11:44 2025 -0800 Fix whitespace in GH workflow files (#289) Remove EOL whitespace add newlines at ends of files for POSIX compliance commit 2135ae0b698caab33c1747c2988f4edf099418f9 Author: Cody Spath Date: Wed Oct 29 11:17:33 2025 -0400 [REL-10444] add additionalProperty to set axios version to latest (#287) feat: add additionalProperty to set axios version > 1.12.0 commit 53f454df53736c40b8476fdeba938babfca3b65d Author: Isabelle Miller Date: Tue Oct 21 15:25:32 2025 +0200 [REL-10233] add dependency-scan GHA to OpenAPI generation (#286) * [REL-10233] i think this should do it * [REL-10233] mkdir if not exists commit 1d577448d7a114665bdcda06bb043bab00fc22ed Author: Henry Barrow Date: Fri Oct 17 15:42:30 2025 +0100 [REL-10138] Fix Gradle task name to closeAndReleaseSonatypeStagingRepository (#285) The correct task name from gradle-nexus-publish-plugin includes 'Staging': - Incorrect: closeAndReleaseSonatypeRepository - Correct: closeAndReleaseSonatypeStagingRepository This fixes the error 'Task closeAndReleaseSonatypeRepository not found in root project'. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude commit de4f88351e7c483d99b4d3f9496a9ab432d3c0a8 Author: Henry Barrow Date: Thu Oct 16 16:29:48 2025 +0100 [REL-10138] Migrate from nexus-staging plugin to gradle-nexus-publish-plugin (#283) * [REL-10138] Fix nexusStaging serverUrl for Sonatype Central Add missing serverUrl configuration to the nexusStaging block to point to the new Sonatype Central staging API. Without this property, the plugin defaults to the old OSSRH URL that was shut down on June 30, 2025, causing 401 Unauthorized errors when attempting to close and release repositories. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude * [REL-10138] Migrate from nexus-staging plugin to gradle-nexus-publish-plugin Migrate from the old io.codearte.nexus-staging plugin to the newer io.github.gradle-nexus.publish-plugin to properly support Sonatype Central. The old plugin was causing 403 Forbidden errors because it wasn't fully compatible with the Sonatype Central staging API. The new plugin is the recommended solution and provides better support for the new API. Changes: - Replace io.codearte.nexus-staging plugin with io.github.gradle-nexus.publish-plugin v2.0.0 - Remove nexusStaging configuration block and publishing.repositories.maven block - Add nexusPublishing configuration with proper Sonatype Central URLs - Update publish script to use new task names: publishToSonatype and closeAndReleaseSonatypeRepository 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --------- Co-authored-by: Claude commit 155120dfc589ee4d23c132f2fbbd6c3338d465bf Author: Tilde Thurium Date: Thu Oct 16 07:11:31 2025 -0700 remove developer relations from CODEOWNERS (#284) commit 87063ce51413ef9a930a92f3f7c9456a567ebd5c Author: Lucy Date: Wed Oct 15 14:38:58 2025 -0700 (bug-fix) Update form-data dependency (#275) There's a critical security vulnerability in `form-data` 3.4.0, which was a transitive dependency of superagent 5.3.0. The superagent version is set in [this mustache file](https://github.com/OpenAPITools/openapi-generator/blob/ddb15d4b9d6fa0f04090b5db3d64ea1b8a6d0ee6/modules/openapi-generator/src/main/resources/Javascript/libraries/javascript/package.mustache) in the openapi generator, but we can override that with our own local `package.mustache`. This bumps the superagent version for the generated `api-client-javascript` to `^7.0.0`, which imports form-data 4.0.4. commit cc162dae45a08699914652721da4fadd5727e827 Author: Henry Barrow Date: Wed Oct 15 17:33:25 2025 +0100 [REL-10138] Fix nexusStaging serverUrl for Sonatype Central (#282) Add missing serverUrl configuration to the nexusStaging block to point to the new Sonatype Central staging API. Without this property, the plugin defaults to the old OSSRH URL that was shut down on June 30, 2025, causing 401 Unauthorized errors when attempting to close and release repositories. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude commit c2c2badabdaab248a3a0e3a523b77b707df8877c Author: Henry Barrow Date: Wed Oct 15 16:49:09 2025 +0100 [REL-10138] Migrate Maven publish from OSSRH to Sonatype Central (#281) * [REL-10138] Migrate Maven publish from OSHH to Sonatype Central * [REL-10138] Revert signing password change * [REL-10138] Update publish URL following https://central.sonatype.org/publish/publish-portal-ossrh-staging-api/ commit 99219f91673b153cbecc890046939d11b0290479 Author: Henry Barrow Date: Fri Oct 10 14:11:10 2025 +0100 [REL-10048] Fix Java build (#280) * [REL-10048] Add build step to test java build * [REL-10048] Remove unnecessary template * [REL-10048] Just focus on java * [REL-10048] build everything * [REL-10048] try fixing build * [REL-10048] update template * [REL-10048] update template * [REL-10048] update template * [REL-10048] rename artifact reference * [REL-10048] delete build action commit ddcca6afcd7ce8969b732d28beda9b4e7c373573 Author: Henry Barrow Date: Thu Oct 9 21:33:09 2025 +0100 [REL-10048] Update generator to v7.16.0 (#279) * [REL-10048] Try updating to latest version of generator * [REL-10048] Bump php version commit 00a02e1fb16ffa745643b533f50a357c33545b4b Author: Brodie Vivio <10712242+bvivio@users.noreply.github.com> Date: Thu Oct 9 09:36:34 2025 -0700 [EXPT-3347] Attempt to Fix Java Compilation Errors (#276) * fix java testImplementation import to account for openapi generator version bump to 7.5.0 commit e9f4b2728c632a7c30a68a351854331433ceb22b Author: Henry Barrow Date: Thu Oct 9 16:24:19 2025 +0100 Bump generator to v 7.5.0 (#250) * Bump generator to v 7.5.0 * Fix go client * Fix python client * Fix go template * Bump go in CI and update Makefile * Try removing python partial header * Fix typescript client * Use Api instead of API in go client * Update python model package name * Remove python template reference * Revert models change * Remove typescript template files * [sc-242972] Fix GHA multiline issue * [sc-242972] Ignore scripts * [sc-242972] try bumping js version * [sc-242972] Try fixing js * [sc-242972] Swtch to using npm run build * [sc-242972] Switch to ES6 * [sc-242972] Downgrade to node 20 * [sc-242972] switch back to require * [sc-242972] Don't use link command * [sc-242972] commit package.json * [sc-242972] Try cleaning node module * [sc-242972] modernize * [sc-242972] Try checking in package-lock * [sc-242972] Use babel preset * [sc-242972] Comment out JS test * [sc-242972] Add Check Success job commit 7286ff63eb1c7e6e612ea33ee39857db145e223f Merge: 6fe39caa 8d5a479d Author: Abhishek Acharya Date: Thu Oct 9 00:52:35 2025 +0530 Merge pull request #277 from launchdarkly/aacharya/migration-gha Gha migration commit 8d5a479db74e49d06c51228c107ca986d0c68659 Author: Abhishek Acharya Date: Thu Oct 9 00:32:35 2025 +0530 revert java code as its working fine commit fb1c75dfa6a00b44de688b04a684c5afb78259af Author: Abhishek Acharya Date: Thu Oct 9 00:25:58 2025 +0530 testing java fix commit 4db0165eaf5face1ba8edbb4a4ae6e1a67686fa7 Author: Abhishek Acharya Date: Thu Oct 9 00:18:12 2025 +0530 fixing js version commit 9b1f5031164da183cea1b3ac1886de75f78f8b7b Author: Abhishek Acharya Date: Thu Oct 9 00:13:08 2025 +0530 js fix commit 91178912eb2032f745ab085a719bbb319e5e3341 Author: Abhishek Acharya Date: Wed Oct 8 21:17:21 2025 +0530 fixing flag npx commit ad6767a7fa3c101fcb9dfe777155ebb5d8bffded Author: Abhishek Acharya Date: Wed Oct 8 21:09:58 2025 +0530 fixing javascript commit 4a44e85f1fd0d699666a530bdec14dfd177d6b70 Author: Abhishek Acharya Date: Wed Oct 8 20:49:57 2025 +0530 fixing go commit f33e7c11267537b8903a68daf53052352a8b0719 Author: Abhishek Acharya Date: Wed Oct 8 20:40:54 2025 +0530 fixing ruby commit 9d613f7ab663e97d579ae3f6a960876a83c8c2de Author: Abhishek Acharya Date: Wed Oct 8 20:27:27 2025 +0530 fixing uid commit 33cd388402521c4a8bce5b141deaf626829e0427 Author: Abhishek Acharya Date: Wed Oct 8 20:21:12 2025 +0530 added api key commit 4cdc1e9adfbcec53861504344e056ae6f22b0185 Author: Abhishek Acharya Date: Wed Oct 8 20:00:51 2025 +0530 adding php as well commit 1547f0363943e768d5bb9a072a217f751ed95b9f Author: Abhishek Acharya Date: Tue Oct 7 22:14:54 2025 +0530 back to gha commit d3939bf77339350aef8b7c9c8363e268cf853a67 Author: Abhishek Acharya Date: Tue Oct 7 22:11:30 2025 +0530 removed cache in build step commit 57633b59a43c144c01e04fb13d3413fc22acb5e9 Author: Abhishek Acharya Date: Tue Oct 7 22:09:10 2025 +0530 removed sudo commit db240d49ed21f434c379cf4f6f3cc21e6417359b Author: Abhishek Acharya Date: Tue Oct 7 22:04:35 2025 +0530 fixing uid commit bf762491fd7ce0573035800f41719ddcf510b4f5 Author: Abhishek Acharya Date: Tue Oct 7 22:01:04 2025 +0530 added user commit a7fbecd63af149dd583ce85baa1860d2e95a5e31 Author: Abhishek Acharya Date: Tue Oct 7 21:59:16 2025 +0530 updating runson commit a8a2e46177ed299437453e80bf97f20ed367009d Author: Abhishek Acharya Date: Tue Oct 7 21:56:34 2025 +0530 removed id commit cd75526f730c56534d1aa8d8ecda144ad2317e42 Author: Abhishek Acharya Date: Tue Oct 7 21:54:31 2025 +0530 adding rusnon commit 48580d2d9496fc3496ffb2179e85e0a3251a8217 Author: Abhishek Acharya Date: Tue Oct 7 21:49:50 2025 +0530 fixing version commit 429aa3743b84135ad0c05bd358945214046198da Author: Abhishek Acharya Date: Tue Oct 7 21:42:34 2025 +0530 testing gha commit 62e57c733235f4ba91fc7622a55280de985e6c7b Author: Abhishek Acharya Date: Tue Oct 7 20:53:45 2025 +0530 user id fix commit 030b16a9e865d47cd434c52a058baff112b47951 Author: Abhishek Acharya Date: Tue Oct 7 20:47:49 2025 +0530 testing gha migration commit 6fe39caa2c3b291a3feb292089749bb726b72573 Merge: c55c9591 b70ba044 Author: Chris Blackburn Date: Fri Apr 4 17:27:27 2025 -0400 Merge pull request #274 from launchdarkly/cblackburn/fix-pypi-upload-error update packaging to be compatible with latest twine commit b70ba04442bb40862d368b397719f78c1c220788 Author: Chris Blackburn Date: Fri Apr 4 15:52:45 2025 -0400 update packaging to be compatible with latest twine commit c55c9591a2a3e63fc4ab8f3cdcba7e33b721c8d7 Author: Henry Barrow Date: Tue Feb 25 10:13:45 2025 +0000 Update CODEOWNERS file (#273) Update CODEOWNERS: replace @launchdarkly/team-release-backend with @launchdarkly/team-enterprise commit cc3ded54daed148e711cc17535e162366207eee9 Author: Lucy Date: Wed Jan 29 09:48:13 2025 -0800 [DOCS-1155] Update README-PREFIX to not hardcode latest version (#272) The README prefix that gets prepended to all generated API client library READMEs had the latest API version hard coded. Now that that version is being deprecated it causes confusion. This updates it to not hard code the exact latest version value. Co-authored-by: Lucy Voigt commit 40c5eb48d5ec6cfb2de776f2e4bf115e15a9622f Author: Lucy Date: Fri Dec 13 14:22:54 2024 -0800 Typo in Makefile (#271) Co-authored-by: Lucy Voigt commit c93ababb686d1a7fc673f6fd77d1cade45793931 Author: Lucy Date: Fri Dec 13 13:38:33 2024 -0800 Download gpg key to correct path (#270) Co-authored-by: Lucy Voigt commit 341fb72cee867a0ea2d607f922dd3f7291328b03 Author: Lucy Date: Fri Dec 13 13:06:39 2024 -0800 Correct path for java code signing keyring (#269) Co-authored-by: Lucy Voigt commit f30ab00f0801ff22b83d5ad2a6ac76ffe283a67c Author: Lucy Date: Fri Dec 13 12:45:41 2024 -0800 Add publishing secrets as env vars to get written to files (#268) Co-authored-by: Lucy Voigt commit b287e4349714f977604c00861228321d5a6a34b2 Author: Lucy Date: Fri Dec 13 12:31:33 2024 -0800 Run prepare script to set up secrets for publishing (#267) Co-authored-by: Lucy Voigt commit 1a98ecee139c2ea85a6bf9cc5eea6957b8497026 Author: Lucy Date: Fri Dec 13 12:15:45 2024 -0800 Try setting stack size in gradle.properties (#266) Co-authored-by: Lucy Voigt commit d8ad9d964800721e9918eb356d8f97a8ae4a166b Author: Lucy Date: Fri Dec 13 11:58:33 2024 -0800 Bump java thread stack size (#265) Co-authored-by: Lucy Voigt commit 8ba48f4f5ad25774084a184ebfa3fa162e3f8b49 Author: Paddy Date: Fri Dec 13 11:39:21 2024 -0800 Log the stack size for Java. (#264) commit 9ad100c439975f53ef017b54400aa029f503b2e6 Author: Lucy Date: Fri Dec 13 10:45:31 2024 -0800 Remove java env attempt (#263) Co-authored-by: Lucy Voigt commit 2aaf6895c71471cf7e94f4f9f145f548873dd640 Author: Lucy Date: Fri Dec 13 10:40:10 2024 -0800 Use java 11 instead of 17 (#262) Co-authored-by: Lucy Voigt commit e96e03c092284e7680dc442cfec37e44b8ab7e96 Author: Lucy Date: Fri Dec 13 10:20:19 2024 -0800 Give GH action permission (#261) Co-authored-by: Lucy Voigt commit 69623c06abe4d13d03c8f9002e1e1866dc589d6c Author: Lucy Date: Fri Dec 13 10:12:56 2024 -0800 Sudo python update for file permissions (#260) Co-authored-by: Lucy Voigt commit fcd541d13137330b6482e4656c4978ae160c6899 Author: Lucy Date: Fri Dec 13 10:06:50 2024 -0800 Sudo install golang (#259) Co-authored-by: Lucy Voigt commit 46dfb4d496a082acd5448c4b71d4f22f09abb03b Author: Lucy Date: Fri Dec 13 09:50:40 2024 -0800 [RO-771] Add manual setup steps (#258) Add manual setup steps Co-authored-by: Lucy Voigt commit 8252b34383534bea27c7608ac5a783ffebaf52a9 Author: Lucy Date: Thu Dec 12 15:59:29 2024 -0800 Try default ubuntu image and hope it magically has everything we need (#257) Co-authored-by: Lucy Voigt commit e568639a77930556368fecf970436bf9ef11ebeb Author: Lucy Date: Thu Dec 12 15:52:33 2024 -0800 Try pinning checkout version to work with Docker images (#256) Co-authored-by: Lucy Voigt commit c90a0da7d69cb026f1a1655b717946edbe115d39 Author: Lucy Date: Thu Dec 12 15:34:06 2024 -0800 [RO-771] Migrate repo from Releaser to manual GH Action (#255) * [RO-771] Migrate repo from Releaser to manual GH Action This moves the release process for LD API client libraries from Releaser to Github Actions. I looked at improving the release process itself (to not write out secrets to files, or use more standard release tools) and ultimately it seemed easiest to move everything wholesale and make any improvements to the actual process separately. * Add back releaser files --------- Co-authored-by: Lucy Voigt commit 4511d082be56e24a295e04561b8894f54218257d Merge: fc9eae4c 94cdd5e5 Author: LaunchDarklyReleaseBot Date: Mon Oct 14 10:23:53 2024 +0000 merge from public after release commit fc9eae4cb017ebefb65a6ffb43c1a794a749a82f Author: Henry Barrow Date: Fri Aug 16 15:51:55 2024 +0100 Transfer code ownership (#254) * Transfer code ownership * Add developer relations commit 3b039a2a8c3c84e29baf902c6ab679e3f7269a1f Merge: 3b7867c3 8f621bbb Author: LaunchDarklyReleaseBot Date: Thu May 16 11:32:19 2024 +0000 merge from public after release commit 3b7867c31ab233038013b8ffe1bc19aec19d15c3 Author: Henry Barrow Date: Thu May 16 12:21:27 2024 +0100 Fix typo in package.json template extension (#253) * Fix typo in package.json template name * Remove ESM clause commit e7cc9a6fdd41553ec874c48746831a79ab7ba59f Merge: 9a23b8a0 0d065e9a Author: LaunchDarklyReleaseBot Date: Thu May 16 10:14:05 2024 +0000 merge from public after release commit 9a23b8a01b1a1744516ecee373509cd2a68aacf7 Author: Henry Barrow Date: Wed May 15 15:40:59 2024 +0100 Generate go interface (#252) commit ec516afb7c24a31f1e648814df527c3b37cd1f3b Author: Henry Barrow Date: Wed May 15 15:20:03 2024 +0100 Update Axios dependency in Typescript client (#251) * Update .gitignore * Try updating axios * Update package.json * Update sample commit fa0f8b84746ccd07c2a75306d7594b918aae9e8c Author: Lucy Voigt Date: Mon Apr 10 14:16:48 2023 -0700 Only include 'View code' link if sample code is available (#248) * Only include 'View code' link if sample code is available * Add description to Typescript README --------- Co-authored-by: Lucy Voigt commit a73a23a22eda0c78823342769de2acc0104e75cc Merge: 3fdd0fb1 8375579c Author: LaunchDarklyReleaseBot Date: Tue Feb 28 02:11:32 2023 +0000 merge from public after release commit 3fdd0fb1af9106e726667226f381b4584791529f Author: Lucy Voigt Date: Mon Feb 27 17:53:34 2023 -0800 Update SSM parameter paths (#247) Co-authored-by: Lucy Voigt commit 537c9c0512218633e0a39894f080aa595b8c8be0 Merge: 5e71bf11 b31a8372 Author: LaunchDarklyReleaseBot Date: Mon Nov 21 23:16:43 2022 +0000 merge from public after release commit 5e71bf113bdd67cdd0c2298e99e923834c65068a Author: carmenquan Date: Tue Aug 23 09:50:02 2022 -0700 Update codeowners (#245) * Update codeowners * fix squad name commit 5bcce16404f4f2665b9dc88eb2a774280abca590 Author: carmenquan Date: Thu Aug 11 13:27:11 2022 -0700 adding back other clients (#243) commit 1b9a2822004d61427a6eef898ce8950a5c43f966 Author: carmenquan Date: Wed Jul 20 16:47:03 2022 -0700 fix: [sc-160524] Need to remove all old files before copying new targets to git repo (#244) * adding back other clients * remove contents of the newly cloned git folder * revert change from old PR * add comment commit d614ecac3f6498908f44aee9d8d3a1e802daa647 Merge: 2a688ff7 8d727b2f Author: LaunchDarklyReleaseBot Date: Tue Jul 12 19:05:18 2022 +0000 merge from public after release commit 2a688ff7aa1be1daaf516a96c6f520ce75077443 Merge: a28bf48d 0d421a7f Author: LaunchDarklyReleaseBot Date: Tue Jul 12 00:39:33 2022 +0000 merge from public after release commit a28bf48d0fb9938623753d6be68dff4e51c92e55 Author: carmenquan Date: Mon Jul 11 17:31:43 2022 -0700 add wildcards (#242) commit 8798ef0886274f6904309a5d106b4111fe7fa0b2 Merge: c430adf3 a733b6ed Author: LaunchDarklyReleaseBot Date: Tue Jul 12 00:22:22 2022 +0000 merge from public after release commit c430adf3ce9d1214bbf7c1c8b93b7b63a8d29e8a Author: carmenquan Date: Mon Jul 11 17:17:21 2022 -0700 only updating java (#241) commit 3ed1f7357d0c9b23bdb0adfe10137f3526116280 Author: carmenquan Date: Mon Jul 11 17:04:15 2022 -0700 Rename gitignore mustache file (#240) * adding .gitignore file * rename file commit deba82d01dfffddf36cf0b5b15a3ba048cb70833 Merge: b2ac1307 f6b34b66 Author: LaunchDarklyReleaseBot Date: Mon Jul 11 23:44:22 2022 +0000 merge from public after release commit b2ac130729dccdd0c105fff25ab53e3ea5691414 Author: carmenquan Date: Mon Jul 11 16:27:08 2022 -0700 adding .gitignore file (#239) commit d52442ef88d7b6734b35e156eff9b9d89079c3b5 Merge: 75469cc5 57dd374b Author: LaunchDarklyReleaseBot Date: Mon Jul 11 22:48:31 2022 +0000 merge from public after release commit 75469cc5d249cf5f06df5e6c5387fcd686ed8386 Author: carmenquan Date: Mon Jul 11 15:36:31 2022 -0700 Adding template for fixing restructuredtext issue (#238) * adding template for fixing restructuredtext issue * missing second line commit 68f2e81ad679023f72359130204bbe6f6da5346b Merge: 3a58257f 6c3f0dfb Author: LaunchDarklyReleaseBot Date: Mon Jul 11 22:00:55 2022 +0000 merge from public after release commit 3a58257f952917f947f1ebd74fd2445003229b71 Author: carmenquan Date: Mon Jul 11 12:59:48 2022 -0700 Update to OpenAPI Generator 6.0.0 (#233) * updating to use 6.0.0-beta * update version to 6.0.0 * remove ld-openapi-generator-cli.jar * update gradle file * update gradle file * update gradle file * update gradle file * update gradle file * updating axios * remove files * remove extra gradle * add typescript tsconfig.mustache * adding a projects sample * adding println * adding println for projects * remove delete action * testing new config * testing new api key * removing load prior targets * revert java sample change * updating java config * cleanup in case of bad run for java * Revert "cleanup in case of bad run for java" This reverts commit 205bed7a6d9035f8483e2c23662ed6a7b0bfdb3d. * updating go sample * removing projects * Update tsconfig.mustache (#236) * add blurb about versioning * fixing link * Update samples/java/src/main/java/com/launchdarkly/sample/Main.java * Update README-PREFIX.md Co-authored-by: Molly * Update README-PREFIX.md Co-authored-by: Yusinto Ngadiman Co-authored-by: Molly commit 7e84493e123689e754ea015d7ae12d476c9ddcf9 Author: Jaz White Date: Thu Jun 9 10:33:51 2022 -0400 [sc-156083] Add php sample app (#234) commit 90b118bc6d817aea6722d7dd1e9c8bda0665bd00 Author: Jaz White Date: Wed Jun 8 15:39:36 2022 -0400 update codeowners (#235) commit af193d1749da652b602eda12ef556c2ee13a2dd7 Merge: 428e83ef 1dc13c9d Author: LaunchDarklyReleaseBot Date: Fri Apr 29 20:22:59 2022 +0000 merge from public after release commit 428e83efe061d1899031b3101f938edcca55d0ea Merge: 37ed5ef5 677d8307 Author: LaunchDarklyReleaseBot Date: Tue Apr 12 21:39:57 2022 +0000 merge from public after release commit 37ed5ef5e952eba69d1f759c74babf091d3a50e7 Merge: 2af1865e e8e121da Author: LaunchDarklyReleaseBot Date: Fri Mar 11 16:38:24 2022 +0000 merge from public after release commit 2af1865ec2eb7d08c058366e2b1f4a3b61c9e835 Author: carmenquan Date: Thu Mar 10 17:36:50 2022 -0800 Update branch from master to main (#229) * update branch from master to main * adding fetch all * test if main exists * test if main exists * test clone * Removed git submodule -b to checkout the default branch automatically. * Update Makefile * Update Makefile * Update Makefile * Removed c# * Update Makefile * Replaced make foreach with bash for loop. * Apply suggestions from code review * Update Makefile * Update Makefile * Rollback to working version. * Update Makefile * add git fetch * remove variable * adding back version * using prev branch variable * remove version Co-authored-by: Yusinto Ngadiman commit 5c129cef028336df5673765f7c05b2a04366c380 Author: carmenquan Date: Thu Mar 3 13:57:52 2022 -0800 remove csharp dotnet references (#230) commit 53703711d7bd1e1ee24abeda7dfca98e57a52909 Author: carmenquan Date: Thu Mar 3 09:14:07 2022 -0800 Remove publish to java gh pages (#228) * remove publish to java gh pages * adding whitespace commit bef9393ddcddb622e4f694f2632fe1186b71494a Merge: cb953dbc a08d2549 Author: LaunchDarklyReleaseBot Date: Sat Jan 15 00:51:02 2022 +0000 merge from public after release commit cb953dbc781197861e33551b961d1a622917d20c Merge: c508a8dc d5a1320b Author: LaunchDarklyReleaseBot Date: Thu Jan 6 23:49:32 2022 +0000 merge from public after release commit c508a8dc4167604a2bfc118a196b191712dc0f53 Author: carmenquan Date: Thu Jan 6 08:30:59 2022 -0800 allow execution of gradle wrapper (#226) commit b446ce2a091d7373867b528494a5e076c76c1180 Author: carmenquan Date: Wed Jan 5 10:09:28 2022 -0800 switch to gradlew, update from deprecated ghpages library (#225) commit 20099f525775f14ed0334eb783f0db28fe30e151 Author: Dan O'Brien Date: Mon Dec 6 11:54:42 2021 -0500 update version template (#224) commit d5614ba64bf1a236fe6829e11b4469ee2e402368 Merge: c24f99ee f1631c5c Author: LaunchDarklyReleaseBot Date: Fri Dec 3 21:00:34 2021 +0000 merge from public after release commit c24f99ee21512d98bdd2e548056306522069c0ab Author: carmenquan Date: Fri Dec 3 12:53:10 2021 -0800 update .jar (#223) commit 6a3c938a2ffe8b0cd4b38e61e49082f0acf6eb8e Merge: 6d9b668c fdf5a2ca Author: LaunchDarklyReleaseBot Date: Fri Dec 3 20:10:04 2021 +0000 merge from public after release commit 6d9b668c332a87146c9d22d6e478d509e6f1b09b Author: carmenquan Date: Fri Dec 3 08:17:56 2021 -0800 update generator (#221) commit f485f71b57fdfd59d7aac2e05197842817e37829 Author: carmenquan Date: Thu Dec 2 15:29:08 2021 -0800 renaming variate to variation (#222) commit 9415d887ea731b3ff088f093094c89a1eb265500 Author: Dan O'Brien Date: Wed Dec 1 14:29:50 2021 -0500 update Makefile (#220) add temporary template, plan to upstream change commit e7444a12830c80dfb0b49be300e602622d1027f9 Merge: 13922c06 83378976 Author: LaunchDarklyReleaseBot Date: Fri Oct 1 17:57:23 2021 +0000 merge from public after release commit 13922c065514aa64dbc22a9cec91b53711ebcb52 Merge: 591b28f3 7c4696da Author: Eli Bishop Date: Thu Sep 30 17:25:47 2021 -0700 Merge pull request #219 from launchdarkly/eb/ch124841/skip-duplicate-publish allow release to proceed if a per-target publish step failed only because it was already published commit 7c4696daec4a36a48bd265d5da907960063e490a Author: Eli Bishop Date: Thu Sep 30 14:44:29 2021 -0700 allow release to proceed if a per-target publish step failed only because it was already published commit 591b28f3e1e7d85b831f6be9eb77c6902317af46 Author: carmenquan Date: Wed Sep 29 16:18:43 2021 -0700 using token username (#218) commit c5d62a3e74fc602e0b57d4d7c17c697273b53308 Merge: 23e16c4a 3fc80089 Author: LaunchDarklyReleaseBot Date: Wed Sep 29 21:05:32 2021 +0000 merge from public after release commit 23e16c4a7f7f2b7319cd275f476db523fd18315c Author: carmenquan Date: Wed Sep 29 13:05:04 2021 -0700 [sc124605] Removing custom template for ruby client (#217) * removing custom template for ruby client * remove whitespace commit 74f88df7e1f38d439fc53240699b12dc5cefdc4d Author: Dan O'Brien Date: Tue Sep 28 13:04:53 2021 -0400 fix python build (#216) commit 694e6d0edaa3e3ed1e1681b9cc7138552a52c758 Author: carmenquan Date: Tue Sep 28 10:04:36 2021 -0700 api-client-javascript 6.0.0 doesn't work due to incorrect package generation (#215) * update to copy hidden files * remove python * Revert "remove python" This reverts commit b5bc51b589406d4af33826be5a3da1ed7836583c. commit aec6e982e82330c221d765df05f684ea3aa905d7 Author: Ben Woskow <48036130+bwoskow-ld@users.noreply.github.com> Date: Wed Sep 22 09:58:46 2021 -0700 Replace deprecated docker image usage with newer CircleCI docker images (#214) commit cef27e5148766f282dfaaa494ab0dc8fdd5fdfff Author: Dan O'Brien Date: Wed Sep 8 15:44:15 2021 -0400 Java Client Changes (#213) * move Java to end of publish add gradle.properties file to set longer timeout to Sonatype * move Java to end of publish * Update .ldrelease/publish-dry-run.sh Co-authored-by: carmenquan Co-authored-by: carmenquan commit 9be13e8ff4dfdde8226270b8e8aeb2f8b108ba10 Merge: 848210e8 165978d7 Author: Ben Woskow Date: Thu Sep 2 10:36:15 2021 -0700 Merge branch 'master' of github.com:launchdarkly/ld-openapi commit 848210e8c6e960bc35577b841c7790b8d11c78c3 Author: Dan O'Brien Date: Thu Sep 2 13:09:45 2021 -0400 back out previous ssh changes and correctly use https (#212) commit 02f0c09986aceb6d8806a7cdce931422b84add03 Merge: 08002aea fd8c724f Author: Ben Woskow Date: Wed Sep 1 13:38:08 2021 -0700 Merge branch 'master' of github.com:launchdarkly/ld-openapi commit 08002aead42768a6e743807e19554ffbbdafde42 Merge: 19587622 0f166eca Author: Christie Williams Date: Wed Sep 1 16:36:09 2021 -0400 Merge pull request #211 from launchdarkly/dob/ssh add ssh dir commit 0f166eca142dba99f6b8d8836f7b3780bffad7da Author: Dan O'Brien Date: Wed Sep 1 16:33:45 2021 -0400 add ssh dir commit 195876228e0a81ef58f705f60d2ef7cb98814302 Merge: e70aa89b bfe89952 Author: Ben Woskow Date: Wed Sep 1 13:29:01 2021 -0700 Merge branch 'master' of github.com:launchdarkly/ld-openapi commit e70aa89b4d078fb00b3e83431a7b5072d61302bb Author: Dan O'Brien Date: Wed Sep 1 14:45:05 2021 -0400 adding github host key (#210) commit f99020d945a10f5be7dc81a6d706128008470f8e Merge: df0e1bbf 55d23be2 Author: LaunchDarklyReleaseBot Date: Wed Sep 1 18:08:56 2021 +0000 merge from public after release commit df0e1bbf9d1a155ca2b6731dfe6053a0198de018 Merge: 0c02abc4 44903061 Author: Christie Williams Date: Wed Sep 1 13:30:55 2021 -0400 Merge pull request #209 from launchdarkly/christie/fix-bad-merge Fix bad merge commit 4490306186bb5e2171949feb6b22a482e60bbefa Author: Christie Williams Date: Wed Sep 1 13:28:21 2021 -0400 Fix bad merge commit 0c02abc4857f277f2dee311317f678026597907e Merge: 6a2222e7 f5bc3c3d Author: Christie Williams Date: Wed Sep 1 09:38:08 2021 -0400 Merge pull request #203 from launchdarkly/goas [ch118869] Use generated openapi spec commit f5bc3c3dd464ac66468c2c9615b6b4928dfe0067 Merge: 0c5c3b45 6a2222e7 Author: Christie Williams Date: Tue Aug 31 16:11:05 2021 -0400 Merge branch 'master' into goas commit 0c5c3b45580f6dffbba69e14b10c201e265eaabb Author: Dan O'Brien Date: Tue Aug 31 13:26:53 2021 -0400 Fix typescript sample code (#208) * updates for typescript * add node t types remove finally * remove commented out code * fixes based on feedback commit 78fb16ce43882c5676f9069340e1a8bfc1357475 Author: Eli Bishop Date: Mon Aug 30 12:29:44 2021 -0700 fix problems with Java and JavaScript client builds (#207) commit 9adf26f9bfdf6b2d8c63459440d2d4c4ba79ae73 Author: Eli Bishop Date: Mon Aug 30 10:17:18 2021 -0700 update goas branch for new release process (#206) commit 6a2222e7e7c194c63696d70f520012b335913468 Author: Eli Bishop Date: Fri Aug 27 15:15:44 2021 -0700 verify that client code builds, fix (most) Java build issues, make dry run more useful (#205) commit 4983e578898a671e57e8cc3f759b21f3fe031b0b Author: Christie Williams Date: Thu Aug 26 18:02:21 2021 -0400 Fix ruby sample commit 4b32c1e98909965d494eafa5bbaa5b13ab89efde Author: Christie Williams Date: Thu Aug 26 17:58:35 2021 -0400 Fix python sample commit 7261fc151b9cf09fe5687f65d5b7a472ad8ca76f Author: Christie Williams Date: Thu Aug 26 17:56:25 2021 -0400 Update examples commit b0985794218b819b97a661d83c3973060c496c9d Merge: 411a1649 dad92169 Author: Christie Williams Date: Thu Aug 26 16:34:51 2021 -0400 Merge branch 'master' into goas commit dad92169be6ab0b4cee9816c3cfdd2137872570f Author: Eli Bishop Date: Thu Aug 26 12:07:36 2021 -0700 further implementation of Dockerized Releaser (#204) commit 411a1649a8b8322bde8fab3aba0f837ae6f5a1a5 Merge: 7bb8d5fd c9c01f42 Author: Christie Williams Date: Wed Aug 18 15:30:37 2021 -0400 Merge branch 'master' into goas commit 7bb8d5fd50c921eb2866767d00c01e34fc8ca27e Merge: ef3446f5 cef847c2 Author: Christie Williams Date: Wed Aug 18 15:26:46 2021 -0400 Merge pull request #199 from launchdarkly/christie/ch114006/clean-up-stale-content-and-files Clean up stale content and files commit cef847c2d4f6b74e096b51a39c72b09b1fc59dc0 Author: Christie Williams Date: Wed Aug 18 15:14:54 2021 -0400 Update ld-openapi-generator-cli.jar commit 87d9353a37540721a6b6547976ae1455b65681d8 Author: Christie Williams Date: Wed Aug 18 14:10:52 2021 -0400 Use patched version of openapi-generator-cli temporarily commit e322e77760ee0c869edcc811f60450fe2c0aff29 Author: Christie Williams Date: Fri Aug 6 12:45:29 2021 -0400 Update go example commit c9c01f420acf046c4a695ebd7b2b93958674f37a Merge: 7689bb4e 752ed1bb Author: LaunchDarklyReleaseBot Date: Fri Aug 6 16:32:37 2021 +0000 merge from public after release commit 7689bb4e2b63707001ca770a31001305fa101c39 Author: Raymond Ho Date: Mon Aug 2 13:33:45 2021 -0700 update docs for approvals copy flag (#201) commit ef3446f55b74c3d4d255bdee8e562e2ebe4e9937 Author: Dan O'Brien Date: Thu Jul 29 15:50:42 2021 -0400 pass in git info to every clinet (#200) commit fba0f7245873bf6d2ba0f64836d0241101510b46 Author: Christie Williams Date: Wed Jul 28 10:20:23 2021 -0400 s/VariateRep/FlagPostVariations commit 5fdb36614dc9c90f62bbea9a1fd9689fe0b830dd Author: Christie Williams Date: Wed Jul 28 10:14:20 2021 -0400 s/GlobalFlagRep/FlagPost commit 0f1c1bb530e40f1c08d1610ffea0b73f036427ee Author: Christie Williams Date: Wed Jul 28 10:00:53 2021 -0400 Samples sans reps2 commit 6092bee13b10f876bdcd249420365a43292f3a6d Author: Christie Williams Date: Tue Jul 20 08:55:33 2021 -0400 Remove validation skipping commit 7a7f9640154471b8cfc0abe89ef0aad95f2fdcde Author: Christie Williams Date: Fri Jul 16 12:28:23 2021 -0400 Revert removal of java sdk gh page commit 1cd46d9a4b178f189803b744db39d94ea509366d Author: Christie Williams Date: Fri Jul 16 10:01:41 2021 -0400 86 github pages commit 0b0188c4436f936eecc921ebf598e385034ec919 Author: Christie Williams Date: Thu Jul 15 10:11:58 2021 -0400 Skip spec validation commit 3248e40d53b58b7417dc124c932c33e38fa37cba Author: Christie Williams Date: Thu Jul 15 10:05:22 2021 -0400 Revert "Clean description refs from openapi spec before generating" This reverts commit 21e2da16350dcf83b72740454bdb563aa25799ee. commit 21e2da16350dcf83b72740454bdb563aa25799ee Author: Christie Williams Date: Thu Jul 15 09:43:13 2021 -0400 Clean description refs from openapi spec before generating commit 274aa7cf7e6bd44e6e68d4ec5e9622f0175fe369 Author: Christie Williams Date: Thu Jul 15 09:29:30 2021 -0400 Update readme commit d83e675e307768750e17557c4174e40af87f8103 Author: Christie Williams Date: Wed Jul 14 17:20:01 2021 -0400 Update README.md Co-authored-by: Ben Woskow <48036130+bwoskow-ld@users.noreply.github.com> commit 669c8daea6571efd9b63b0a9de5d30ab135b3495 Author: Christie Williams Date: Wed Jul 14 16:16:35 2021 -0400 Skip spec validation to avoid breaking it commit ccc5f67a544d55da1a7c2ce16488b05c4c551e84 Author: Christie Williams Date: Wed Jul 14 16:11:16 2021 -0400 Rev to open api generator 5.2 commit 201457979118dcae2efe8205c233c85401586b86 Author: Christie Williams Date: Wed Jul 14 16:11:04 2021 -0400 Update readme commit f24ae04c128580f05d11c91be01fc4d1141bb248 Author: Christie Williams Date: Wed Jul 14 16:10:43 2021 -0400 Remove vestigial files commit 1e0b8e36e9c1fdd299e07a4382ad3f2572b9541c Author: Ben Woskow <48036130+bwoskow-ld@users.noreply.github.com> Date: Wed Jul 14 10:35:03 2021 -0400 temporarily remove csharp from publication process (#197) commit f0f54c9d8519fc4d4b2718b8c7813743f2390973 Author: Ben Woskow <48036130+bwoskow-ld@users.noreply.github.com> Date: Wed Jul 14 10:34:55 2021 -0400 add sample code link (#198) commit 73d0938404d594f0d6560ebf024be28549b43a50 Author: vatasha <21329981+vatasha@users.noreply.github.com> Date: Fri Jul 9 14:59:05 2021 -0700 Update docs for environment approval settings (#196) * Update docs for environment approval settings Co-authored-by: Sarah Day commit 4a5b1c39a9afaae9b12e5a5f0f23329aec0e756f Author: Ben Woskow <48036130+bwoskow-ld@users.noreply.github.com> Date: Fri Jul 9 06:50:45 2021 -0700 Adding the DX squad as codeowners commit 267a8144f7ef61780f62ba6ad0ba7d189736fa98 Author: Ben Woskow <48036130+bwoskow-ld@users.noreply.github.com> Date: Fri Jul 2 11:25:15 2021 -0700 update readme links (#195) commit edcb80bafa4cdebe9f40f997df44fa6a55d06b31 Author: Ben Woskow <48036130+bwoskow-ld@users.noreply.github.com> Date: Fri Jul 2 09:22:16 2021 -0700 Updating sample codes to work with latest spec (#194) commit 72f4a7e0327bb5b2c3807010c178fa9a0fe5e357 Author: Dan O'Brien Date: Mon Jun 7 08:39:31 2021 -0400 update releaser (#193) * first stab at migrating generators. ran out of time to fix errors. * Go client generating remove old README template for Go ignoring openapi-generator binary from git * download generator if not there * update Go example add back go folder temporarily to build * working go example * template cleanup * updates for python and go * add ruby support * temporary reorder of build * wget json file again build all clients fix up docs there is no more yaml generation * updates for java * small cleanup * basic README cleanup to kick off CI * update releaser * updates for javascript * wrong directory * fix java * update typescript build * minor js updates * clean up flag in conflict * updates for PHP * remove commented out dependency java Co-authored-by: Ben Woskow commit 9873a4059c50f73b32520290837b2a2e3f7e205c Author: Dan O'Brien Date: Mon Jun 7 08:23:59 2021 -0400 Bw/ch109131/generator migration start (#192) * first stab at migrating generators. ran out of time to fix errors. * Go client generating remove old README template for Go ignoring openapi-generator binary from git * download generator if not there * update Go example add back go folder temporarily to build * working go example * template cleanup * updates for python and go * add ruby support * temporary reorder of build * wget json file again build all clients fix up docs there is no more yaml generation * updates for java * small cleanup * basic README cleanup to kick off CI Co-authored-by: Ben Woskow commit b3d3268cfb1ed6ef8f16520c6fe6ad9e7081bf01 Merge: 9d6f732f bde782f9 Author: Dan O'Brien Date: Fri Jun 4 09:11:47 2021 -0400 Merge branch 'kbrack/ch98924/gonfalon-openapi' into goas commit bde782f95f028c0a8bed1fbbcd9fc88e291187bf Merge: e3be908b 9d6f732f Author: Dan O'Brien Date: Fri Jun 4 09:11:31 2021 -0400 resolve merge commit 9d6f732f71f8cceed90b9de950011b33a5508f2d Merge: 6c2261b7 0e595d6b Author: LaunchDarklyCI Date: Wed Apr 21 16:22:22 2021 +0000 merge from public after release commit 6c2261b7ae81a09648430be34b0d50794a14392f Author: Henry Jacobs Date: Wed Apr 21 08:46:11 2021 -0700 [ch105622] add flag dependencies endpoints to openapi (#190) * add flag dependencies endpoints * fix list dep flags resp description commit 3976a91a24aea549bcb8de6d3d3e26a56b64e2db Merge: 0adc7211 b63d4d56 Author: Matthew Wagner Date: Thu Apr 8 14:39:57 2021 -0700 Merge pull request #189 from launchdarkly/mattwagner/ch103716/fix-typo [ch103716] Correct typo in big segment update operation name commit b63d4d56aeea58bc7bb290ecd9e3a40df5b1ef5c Author: Matt Wagner Date: Wed Apr 7 18:42:04 2021 -0700 [ch103716] Correct typo in big segment update operation name commit e3be908b00b9f64efe16d66795b58c90ebb85a77 Author: Lexi Ross Date: Sun Apr 4 10:09:06 2021 -0700 update java sample commit f2c0f9070474c60887c795279d4488395a78bb71 Author: Lexi Ross Date: Thu Apr 1 10:39:11 2021 -0700 update ruby client for testing commit cae275c24c7aef01fdcecb01658e264d6e3e2ef5 Author: Lexi Ross Date: Wed Mar 31 17:13:42 2021 -0700 update ruby sample code to use new ruby client commit 594f5ef7e3c84e12b5e37cc93bdc535e48219a5c Author: Lexi Ross Date: Wed Mar 31 16:24:31 2021 -0700 update javascript sample code to use new javascript client commit 5d0542817467557a5a31202e4eee54426bf727bd Author: Lexi Ross Date: Wed Mar 31 14:57:42 2021 -0700 update java sample code to use new java client commit 0aff03e59d3ef474846b217c10d1584d69488b70 Author: Raymond Ho Date: Mon Mar 29 17:44:34 2021 -0700 update typescript target to axios commit 791307975b9b1cf943aead78f1c7163af7e7ad7d Author: Raymond Ho Date: Mon Mar 29 17:29:42 2021 -0700 fix swagger-client import name commit 7dc15ad06f2c25aabd076c6b5b0f24dbbcdaf9cf Author: Raymond Ho Date: Mon Mar 29 17:02:22 2021 -0700 fix Python sample commit 0d993db0d4a8b6b4e95e776b2a749919411d17ca Author: Raymond Ho Date: Mon Mar 29 12:49:17 2021 -0700 revert back to production openapi spec commit a20dde5f394ebe96942c0c35aff81860a88add6c Author: Raymond Ho Date: Fri Mar 26 15:24:00 2021 -0700 update go sample to use updated go client commit 1205ac51de83754fec454d8a7e422431a92abb9c Author: Raymond Ho Date: Thu Mar 25 17:03:20 2021 -0700 use staging url commit f1d3cb8d5a4299bf0a7059402d143f4fe5a3460b Author: Kevin Brackbill Date: Mon Mar 8 14:59:18 2021 -0800 get openapi spec from prod gonfalon commit 02c95997d97e925e037ce19b34fd83e875c5b16d Author: Kevin Brackbill Date: Wed Feb 24 12:23:24 2021 -0800 clean up circle config commit 9c582176f8d524b6ea9201e6e4108217118edabc Author: Kevin Brackbill Date: Wed Feb 24 11:32:12 2021 -0800 use gonfalon generated openapi 3 spec --- .github/workflows/ci.yml | 25 +- .github/workflows/release.yml | 252 +- .github/workflows/token-audit.yml | 67 + CLAUDE.md | 164 + Makefile | 24 +- README.md | 38 +- samples/javascript/package-lock.json | 3875 ----------------- samples/javascript/package.json | 13 - scripts/release/gonfalon-update.sh | 67 + scripts/release/mirror-public.sh | 85 + scripts/release/preflight.sh | 325 ++ scripts/release/publish.sh | 10 + scripts/release/selfcheck.sh | 354 ++ scripts/release/token-audit.sh | 247 ++ scripts/release/verify-published.sh | 109 + .../javascript/package.mustache | 52 - 16 files changed, 1752 insertions(+), 3955 deletions(-) create mode 100644 .github/workflows/token-audit.yml create mode 100644 CLAUDE.md delete mode 100644 samples/javascript/package-lock.json delete mode 100644 samples/javascript/package.json create mode 100755 scripts/release/gonfalon-update.sh create mode 100755 scripts/release/mirror-public.sh create mode 100755 scripts/release/preflight.sh create mode 100755 scripts/release/selfcheck.sh create mode 100755 scripts/release/token-audit.sh create mode 100755 scripts/release/verify-published.sh delete mode 100644 swagger-codegen-templates/javascript/package.mustache diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 046eaa9..85bafd5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,10 @@ name: CI (build + client samples) pull_request: branches: - main + # Run on demand against any branch. The sample jobs exercise LD_API_KEY against + # the real 'openapi' project, so this doubles as a check that that credential + # still works — the token audit can only confirm it reads, not that it writes. + workflow_dispatch: env: LD_API_KEY: ${{ secrets.LD_API_KEY }} @@ -66,6 +70,24 @@ jobs: with: name: api-clients path: /tmp/api-clients + selfcheck: + name: Release automation selfcheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Ensure PyYAML + run: python3 -c "import yaml" 2>/dev/null || pip install --quiet pyyaml + # Trust-policy checks self-skip here: the policy lives in the private + # launchdarkly/.github-private, which GITHUB_TOKEN cannot read. Run this + # locally for the full set. + - name: Selfcheck + # GITHUB_TOKEN is enough to read the pinned action repos (all public), which + # is what the ACTION-INPUTS check needs. Without it that check resolves + # nothing and reports SKIP. + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: ./scripts/release/selfcheck.sh + test-go: runs-on: ubuntu-latest needs: build @@ -114,7 +136,7 @@ jobs: with: name: targets path: targets - - uses: ruby/setup-ruby@3ff19f5e2baf30647122352b96108b1fbe250c64 # v1 + - uses: ruby/setup-ruby@319994f95fa847cf3fb3cd3dbe89f6dcde9f178f # v1 with: ruby-version: '2.7' - name: Prepare RubyGems / ffi @@ -191,6 +213,7 @@ jobs: name: Check Success needs: - build + - selfcheck - test-go - test-python - test-ruby diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3dfd06f..eda1479 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,20 +1,129 @@ +name: Release client libraries + +# Implements the full release runbook. +# +# Dispatch with no inputs for a normal release. Everything the runbook asks a +# human to look up — whether gonfalon is healthy, whether prod is caught up, the +# bump type, the version, the changelog body — is derived in the preflight job, +# which aborts with a specific reason rather than releasing on a guess. on: workflow_dispatch: inputs: releaseVersion: - description: Next release version - required: true - type: string - changeLog: - description: Pending changelog - required: true + description: 'Override the derived version (bare semver, e.g. 24.0.0). Blank = derive.' + required: false type: string + bumpType: + description: 'Override the bump inferred from the changelog headings.' + required: false + type: choice + default: '' + options: ['', 'major', 'minor', 'patch'] + dryRun: + description: 'Rehearse: clone and commit, but push nothing and publish nothing.' + required: false + type: boolean + default: false + force: + description: 'Delete tags left behind by a previous failed attempt instead of aborting.' + required: false + type: boolean + default: false + openDownstreamPr: + description: 'Open the downstream PRs (gonfalon and terraform-provider-launchdarkly).' + required: false + type: boolean + default: true + mirrorPublic: + description: 'Squash-mirror this repo onto the public launchdarkly/ld-openapi.' + required: false + type: boolean + default: true + skipCiGate: + description: "Release even if gonfalon's main branch is red." + required: false + type: boolean + default: false + skipSpecParity: + description: "Release the spec production is serving even if gonfalon main is ahead. Check the gonfalon PR's changelog entries before merging it." + required: false + type: boolean + default: false + +# Two concurrent releases would race on client-repo tags. +concurrency: + group: release-client-libraries + cancel-in-progress: false jobs: + # Runs on every release, not just rehearsals. A bad registry credential would + # otherwise surface only after `make push` had already tagged five client repos, + # which is the case that forces the delete-the-tags-and-retry dance. A dry run + # cannot cover this on its own: create-release is skipped, pr-downstream skips + # PR creation, and the publish dry-run scripts never authenticate to a registry. + token-audit: + name: Token audit + # A reusable workflow is capped by what its caller grants, so id-token has to + # be granted here as well as inside token-audit.yml. + permissions: + id-token: write + contents: read + uses: ./.github/workflows/token-audit.yml + with: + # Only demand the credentials this run will actually use, so a switched-off + # job cannot block the release — and so the flow can be rehearsed before + # those tokens have been created. + requireMirrorToken: ${{ inputs.mirrorPublic }} + requireDownstreamToken: ${{ inputs.openDownstreamPr }} + secrets: inherit + + preflight: + name: Preflight + runs-on: ubuntu-latest + # Required for the OIDC token the octosts-action step exchanges. + permissions: + id-token: write + contents: read + outputs: + version: ${{ steps.derive.outputs.version }} + major: ${{ steps.derive.outputs.major }} + bump: ${{ steps.derive.outputs.bump }} + changelog: ${{ steps.derive.outputs.changelog }} + previous_version: ${{ steps.derive.outputs.previous_version }} + steps: + - uses: actions/checkout@v4 + # Reading gonfalon needs a credential the releaser token does not have. + # Minted at runtime rather than stored: no long-lived secret, and the trust + # policy in launchdarkly/.github-private is what grants it. + - uses: launchdarkly/octosts-action@v1 + id: sts + with: + identity: ld-openapi-downstream + scope: launchdarkly + - name: Derive release inputs and check gates + id: derive + # Two tokens: the releaser token for the client repos (tag checks, and tag + # deletes when force=true), and the federated token for reading gonfalon. + env: + GH_TOKEN: ${{ secrets.BOT_TOKEN }} + GONFALON_TOKEN: ${{ steps.sts.outputs.token }} + VERSION_OVERRIDE: ${{ inputs.releaseVersion }} + BUMP_OVERRIDE: ${{ inputs.bumpType }} + FORCE: ${{ inputs.force }} + SKIP_CI_GATE: ${{ inputs.skipCiGate }} + SKIP_SPEC_PARITY: ${{ inputs.skipSpecParity }} + run: ./scripts/release/preflight.sh + release: + name: Build and publish clients + needs: [preflight, token-audit] runs-on: ubuntu-latest env: - LD_RELEASE_VERSION: ${{ inputs.releaseVersion }} + LD_RELEASE_VERSION: ${{ needs.preflight.outputs.version }} + DRY_RUN: ${{ inputs.dryRun }} + # The scripts/release-dry-run/*.sh scripts copy the artifacts they would + # have published into this directory, and fail without it. + LD_RELEASE_ARTIFACTS_DIR: ${{ github.workspace }}/dry-run-artifacts GH_TOKEN: ${{ secrets.BOT_TOKEN }} PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} RUBYGEM_API_KEY: ${{ secrets.RUBYGEM_API_KEY }} @@ -64,24 +173,145 @@ jobs: # * Push built clients to their respective Github repos # * Tag those commits with the release version # * Publish each client to it's respective platform (e.g. Rubygems) + # With DRY_RUN=true it clones and commits but pushes/publishes nothing. - name: Publish clients run: | export PATH=/opt/gradle/bin:/usr/local/go/bin:$HOME/.rubygems/bin:$PATH export GEM_HOME=$HOME/.rubygems + mkdir -p "$LD_RELEASE_ARTIFACTS_DIR" ./scripts/release/publish.sh - # This step creates a release with changelog from the tag + # Lets a rehearsal be inspected: these are the exact artifacts a real run + # would have pushed to the registries. + - name: Upload dry-run artifacts + if: ${{ inputs.dryRun }} + uses: actions/upload-artifact@v4 + with: + name: dry-run-artifacts + path: ${{ github.workspace }}/dry-run-artifacts + if-no-files-found: error + + verify-published: + name: Verify published + needs: [preflight, release] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Poll registries and client repo tags + if: ${{ !inputs.dryRun }} + env: + GH_TOKEN: ${{ secrets.BOT_TOKEN }} + run: ./scripts/release/verify-published.sh "${{ needs.preflight.outputs.version }}" + - name: Skipped + if: ${{ inputs.dryRun }} + run: echo "Dry run — nothing was published, so there is nothing to verify." + create-release: + name: Create GitHub release + needs: [preflight, verify-published] runs-on: ubuntu-latest permissions: contents: write - needs: release strategy: matrix: repo: ['api-client-go', 'api-client-java', 'api-client-python', 'api-client-ruby', 'api-client-typescript'] steps: - uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # v1.14.0 + if: ${{ !inputs.dryRun }} with: repo: ${{ matrix.repo }} token: ${{ secrets.BOT_TOKEN }} - tag: v${{ inputs.releaseVersion }} - body: ${{ inputs.changeLog }} + tag: v${{ needs.preflight.outputs.version }} + body: ${{ needs.preflight.outputs.changelog }} + + downstream-gonfalon: + name: Gonfalon PR (changelog + api-client-go bump) + needs: [preflight, verify-published] + # Skipped on a rehearsal. The pinned pr-downstream has no `dryrun` input, so + # passing one was silently ignored and a dry run would open a real PR; it only + # avoided doing so because the version it bumps to did not exist yet. + if: ${{ inputs.openDownstreamPr && !inputs.dryRun }} + permissions: + id-token: write + contents: read + # gonfalon's `make tidy` resolves Go modules from private launchdarkly repos. + # Without this, go consults proxy.golang.org for them and gets a 404. The + # equivalent workflow in launchdarkly/foundation sets the same variable. + env: + GOPRIVATE: github.com/launchdarkly/* + # gonfalon's `make tidy` and gazelle need bazel and a beefy runner, matching + # the gonfalon job in launchdarkly/foundation's pr-downstream workflow. + runs-on: runs-on=${{ github.run_id }}/runner=ub24-large-amd + steps: + - uses: runs-on/action@15385172809cc0346c6821b00c3c3dd2598785b4 # v2.1.0 + # Checked out at the workspace root; pr-downstream clones gonfalon into a + # subdirectory, so the update script stays reachable by absolute path. + - uses: actions/checkout@v4 + - uses: bazel-contrib/setup-bazel@083175551ceeceebc757ebee2127fde78840ca77 # 0.18.0 + with: + bazelisk-version: '1.x' + bazelisk-cache: true + - uses: launchdarkly/octosts-action@v1 + id: sts + with: + identity: ld-openapi-downstream + scope: launchdarkly + - uses: launchdarkly-labs/pr-downstream@08b3feb5df321ebfed2d0855493e81edbb06a2cf # v1.4.0 + with: + repository: launchdarkly/gonfalon + token: ${{ steps.sts.outputs.token }} + author: launchdarkly-octoauth[bot]<226478175+launchdarkly-octoauth[bot]@users.noreply.github.com> + # A user, not a team: an OctoSTS App installation token cannot request team + # reviewers ("If requesting team reviewers a 'repo' scoped PAT is required"), + # which failed the job even though the PR was created. CODEOWNERS in the + # downstream repo still pulls in the owning team. + reviewers: ${{ github.actor }} + title: '[bot] API ${{ needs.preflight.outputs.version }}: release changelog and bump api-client-go' + branch: bump-api-client-go/${{ needs.preflight.outputs.version }} + commit-message: '[bot] Release API ${{ needs.preflight.outputs.version }}: changelog + api-client-go bump' + # A major bump rewrites import paths across ~18 Go files and the Bazel + # graph, so this wants human eyes before it merges. + auto-merge: false + update-command: $GITHUB_WORKSPACE/scripts/release/gonfalon-update.sh ${{ needs.preflight.outputs.version }} + + downstream-terraform-provider: + name: Terraform provider PR (api-client-go bump) + needs: [preflight, verify-published] + if: ${{ inputs.openDownstreamPr && !inputs.dryRun }} + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + steps: + - uses: launchdarkly/octosts-action@v1 + id: sts + with: + identity: ld-openapi-downstream + scope: launchdarkly + - uses: launchdarkly-labs/pr-downstream@08b3feb5df321ebfed2d0855493e81edbb06a2cf # v1.4.0 + with: + repository: launchdarkly/terraform-provider-launchdarkly + token: ${{ steps.sts.outputs.token }} + author: launchdarkly-octoauth[bot]<226478175+launchdarkly-octoauth[bot]@users.noreply.github.com> + reviewers: ${{ github.actor }} + title: 'chore(deps): bump api-client-go to v${{ needs.preflight.outputs.version }}' + branch: bump-api-client-go/${{ needs.preflight.outputs.version }} + # The provider uses release-please, which reads this prefix. `chore` keeps + # the bump from cutting a provider release on its own; change to `feat` + # if a client bump should ship one. + commit-message: 'chore(deps): bump api-client-go to v${{ needs.preflight.outputs.version }}' + # A major bump rewrites the import path across ~220 files here. + auto-merge: false + update-command: make update-api-client-go API_CLIENT_GO_VERSION=${{ needs.preflight.outputs.version }} + + mirror-public: + name: Mirror to public ld-openapi + needs: [preflight, verify-published] + if: ${{ inputs.mirrorPublic }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Squash-mirror private main onto the public repo + env: + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + DRY_RUN: ${{ inputs.dryRun }} + run: ./scripts/release/mirror-public.sh "${{ needs.preflight.outputs.version }}" diff --git a/.github/workflows/token-audit.yml b/.github/workflows/token-audit.yml new file mode 100644 index 0000000..433234a --- /dev/null +++ b/.github/workflows/token-audit.yml @@ -0,0 +1,67 @@ +name: Token audit + +# Read-only check that every credential the release needs still has the +# permissions it needs. Makes no changes, so it is safe to run at any time. +# +# Exists because a dry run cannot answer this on its own: create-release is +# skipped, pr-downstream skips PR creation, and the publish dry-run scripts never +# authenticate to a registry. `release.yml` runs this as a gate before it builds, +# so a bad credential fails the run before any tag has been pushed rather than +# halfway through publishing. +on: + workflow_dispatch: + inputs: + requireMirrorToken: + description: "Treat BOT_TOKEN lacking push on the public ld-openapi as a failure." + required: false + type: boolean + default: true + requireDownstreamToken: + description: 'Require push on the downstream PR targets.' + required: false + type: boolean + default: true + workflow_call: + inputs: + requireMirrorToken: + required: false + type: boolean + default: true + requireDownstreamToken: + required: false + type: boolean + default: true + +permissions: + # id-token is what lets the audit mint the same federated token the release + # jobs use; without it the exchange fails before it reaches the trust policy. + id-token: write + contents: read + +jobs: + audit: + name: Audit release credentials + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + # Mint the same federated token the release jobs use, so the audit proves + # the trust policy works rather than inspecting a stored secret. + - uses: launchdarkly/octosts-action@v1 + id: sts + continue-on-error: true + with: + identity: ld-openapi-downstream + scope: launchdarkly + - name: Audit + env: + REQUIRE_MIRROR_TOKEN: ${{ inputs.requireMirrorToken }} + REQUIRE_DOWNSTREAM_TOKEN: ${{ inputs.requireDownstreamToken }} + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + STS_TOKEN: ${{ steps.sts.outputs.token }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} + RUBYGEM_API_KEY: ${{ secrets.RUBYGEM_API_KEY }} + CENTRAL_PORTAL_USERNAME: ${{ secrets.CENTRAL_PORTAL_USERNAME }} + CENTRAL_PORTAL_PASSWORD: ${{ secrets.CENTRAL_PORTAL_PASSWORD }} + LD_API_KEY: ${{ secrets.LD_API_KEY }} + run: ./scripts/release/token-audit.sh diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..e2ef89f --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,164 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this repo is + +A code *generator*, not a library. It turns LaunchDarkly's OpenAPI spec into REST API client libraries for Go, Java, Python, Ruby, and TypeScript, then pushes each generated client into its own public `launchdarkly/api-client-` repo and publishes to the language package registry. + +Two consequences that shape everything: + +1. **The spec is not in the repo.** `make` downloads it from `https://app.launchdarkly.com/api/v2/openapi.json` at build time, so build output depends on what is currently deployed to production. +2. **Almost all client code is generated.** The only hand-written, committed artifacts are the Makefile, the mustache template overrides, the samples, and the release scripts. Client source appears under `targets/` (gitignored) after a build. + +## Build + +Requires `java`, `curl`, `jq`. The generator jar is downloaded to the repo root on first build. + +```bash +make # all clients + both HTML doc targets +make go # single target: go | java | python | ruby | typescript-axios +make html html2 # doc targets only +make targets_docker # run `make all` in the release container image (matches CI) +make clean # rm -rf targets/ client-clones/ +``` + +Output layout (all gitignored): + +- `targets/openapi.json` — downloaded spec, the input to every generator run +- `targets/api-client-/` — generated client +- `targets/html/`, `targets/html2/` — generated API docs +- `targets/build/api-client-/` — throwaway copy used by `build_clients`/`publish`, so build artifacts never land in a source tree + +Version comes from `LD_RELEASE_VERSION` (default `0.0.1-SNAPSHOT`); `TAG` defaults to it. + +## Verifying a change + +No unit test suite. Validation is three layers. + +**1. Static checks over the release automation** — seconds, no side effects: + +```bash +./scripts/release/selfcheck.sh +``` + +Every check corresponds to a defect that shipped and cost a dispatch-and-wait cycle: a job minting a federated token without `id-token: write`; an API call the trust policy doesn't permit; a token-scope pattern that can never match; a downstream target missing from its allowlist; a referenced secret that doesn't exist; an input passed to a pinned action that the action doesn't declare; a `make` dry-run target that is a silent no-op; `mapfile`/bare `sed -i`, which break on macOS bash 3.2. + +Two rules it enforces about itself, both learned the hard way: + +- **A check that verified nothing reports SKIP or FAIL, never PASS.** Several checks derive a count by extracting from the workflows, and a zero there means the extractor broke far more often than it means the repo is clean — so they cross-check against the raw file text and fail on a mismatch. +- **An unrecognised API endpoint is a failure, not an assumed pass.** When adding a call made with the federated token, add its endpoint to the endpoint→permission table. That table is what turns a would-be 403 into a local error. + +Checks needing credentials self-skip, so it is useful in CI with less coverage. + +**2. Does the generated code compile and package?** + +```bash +LD_RELEASE_VERSION=0.0.1 make +make BUILD_TARGETS="go java python ruby typescript-axios" build_clients +``` + +`build_clients` runs `scripts/build/.sh` per target. Narrow it while iterating: `make BUILD_TARGETS=go build_clients`. + +**3. Does the client work against the API?** Each `samples//` program creates a multivariate flag `test-`, prints it, and deletes it — live integration tests needing `LD_API_KEY`. Run one after `make `: + +```bash +cd samples/go && make +cd samples/python && pip install -e ../../targets/api-client-python && python main.py +cd targets/api-client-ruby && gem build launchdarkly_api.gemspec && gem install ./launchdarkly_api*.gem && cd ../../samples/ruby && ruby main.rb +cd targets/api-client-java && mvn clean install && cd ../../samples/java && mvn clean install exec:java # pom.xml has an API_CLIENT_VERSION placeholder CI seds +cd targets/api-client-typescript-axios && npm install && npm run build && npm link && cd ../../samples/typescript-axios && npm link launchdarkly-api-typescript && npm install && npm run build && npm start +``` + +Sample code is spliced into each client's README, so sample edits change published docs. + +## Architecture notes + +### Template overrides (`swagger-codegen-templates/`) + +Only the HTTP-layer file per language is overridden; everything else uses stock generator templates. Each override is a **verbatim copy of the upstream generator template** with additions fenced by `// CUSTOM-START` / `// CUSTOM-END`, injecting the default `LD-API-Version` header (and, for TypeScript, `X-LaunchDarkly-User-Agent`). + +**When bumping `GENERATOR_VERSION` you must re-copy the upstream templates and re-apply the CUSTOM blocks** — otherwise the override silently pins old generator behaviour. The Makefile header lists the upstream URL for each file. + +### Two versions that move independently + +- `GENERATOR_VERSION` — openapi-generator release used +- `LATEST_API_VERSION` (e.g. `20240415`) — the API version the spec corresponds to, baked into every client as the default `LD-API-Version` header. Update it when the spec's API version changes, or clients keep sending a stale header. + +Per-language flags live in `CODEGEN_PARAMS_` — package names, registry metadata, and each language's version convention (Go uses only the major from `TAG`; others the full `TAG`). + +**Client dependency versions float, so a third-party release can break the build with no change here.** That has happened: `axios` is pinned to an exact `1.18.1` because 1.19.0 broke the TypeScript client's build. See the comment above `CODEGEN_PARAMS_typescript-axios` for the cause and the revert condition. Nothing builds on a schedule, so the next PR is what discovers such breakage. + +### Release plumbing (`Makefile` + `scripts/release/`) + +- `make push` — clones each public `api-client-` repo into `client-clones/`, wipes it, copies the generated client in, commits, tags, pushes. Go is tagged `v$(TAG)`; every other target `$(TAG)` bare. Rehearse with `make push_dry_run` (real clone + commit, `git push --dry-run`) or `make push_test` (echoes git commands). +- The TypeScript target is named `typescript-axios`, so `push` clones `launchdarkly/api-client-typescript-axios` — that repo was renamed to `api-client-typescript` and GitHub redirects the old name. Both work; don't "fix" the apparent mismatch with `release.yml`'s `create-release` matrix. +- Non-Go client repos end up with **two tags per release**: bare `X.Y.Z` from `make push`, and `vX.Y.Z` created by `create-release`. Go gets only `vX.Y.Z`. +- `make publish` — pushes artifacts to PyPI, RubyGems, npm, and Maven Central. Go has no registry step; its **tag is the release**. +- `scripts/release/prepare.sh` writes registry credentials. Deliberately set up *after* build/test so build scripts cannot push. +- `push_dry_run` needs its `push` prerequisite; without it the target is only variable assignments, so `make` reports "Nothing to be done" and exits 0 — a rehearsal that silently does nothing. The `release-dry-run/*.sh` scripts also need `LD_RELEASE_ARTIFACTS_DIR` set or they fail on `mkdir`. + +## Releasing client libraries + +`release.yml` automates the release runbook end to end (the process and its rationale are documented internally). Dispatch it with **no inputs** — version, bump type, and release notes are derived, and each precondition is an enforced gate that aborts with a specific reason. + +All inputs are optional escape hatches: `releaseVersion` (bare semver), `bumpType`, `dryRun`, `force` (delete tags left by a failed attempt), `openDownstreamPr`, `mirrorPublic`, `skipCiGate`, `skipSpecParity`. + +### Job graph + +(`preflight`, `token-audit`) → `release` → `verify-published` → (`create-release`, downstream PR jobs, `mirror-public`) + +`scripts/release/preflight.sh` does the derivation and gating, and runs locally given a token with read access to the spec's source repo. + +- **Gate 1 — spec parity** (bypass with `skipSpecParity`). The spec's source repo commits the published spec, and production serves that file byte for byte, so comparing git blob SHAs settles whether production is caught up and nothing is mid-flight. Compared by blob SHA rather than downloading both copies, because the file is ~2.8 MB — over the contents API's 1 MB raw limit — while the tree API always returns a blob SHA. On a mismatch it names the commit production is serving and the one it is waiting for. The build ships production's bytes either way, so `skipSpecParity` changes only whether the run refuses to proceed — but version and notes still come from the source repo's tip, so the notes may then describe merged-but-undeployed changes. +- **Gate 2 — source repo CI green**, pinned to the commit parity resolved to. Uses check-runs only; the combined-status endpoint needs a permission the token isn't granted. +- **Gate 3 — no tag collisions** from a partial release, in any client repo, for either tag form. + +Everything read from the source repo is pinned to the one commit Gate 1 settled on. Its default branch moves often enough that reading the spec and the notes at separate moments can pair notes with a spec they don't describe. + +**Bump inference** comes from the `### ` headings of the source repo's unreleased changelog section: `Removed`/`Changed` → major, `Added`/`Deprecated` → minor, `Bug Fixes`/`Fixed`/`Security` → patch. `### Changed` is genuinely ambiguous, so the rule errs toward major; override with `bumpType`. An unrecognised heading aborts rather than guesses. + +### Post-release jobs + +- `verify-published` polls PyPI, RubyGems and npm as **hard** failures, plus the Go module proxy and Maven Central as **soft** warnings, then checks client repo tags. The Go proxy is soft on purpose: Go has no publish step, the tag is checked directly, and the proxy caches *negative* lookups — so a `go get` for a version before it exists (a rehearsal, say) makes it serve "unknown revision" for a while afterwards. That failed this job once on an otherwise complete release. It checks `v` on Go and a **bare ``** elsewhere, since that is all `make push` has created by then. +- Two downstream PR jobs bump the published client in the repos that consume it, each calling that repo's own `make update-api-client-go`. Keeping each codemod in the repo it edits means the logic lives beside the imports it rewrites. Neither auto-merges: a major bump moves the Go module path (`api-client-go/vN`), so it rewrites imports across dozens to hundreds of files, and most API releases are major. +- **Both downstream jobs are skipped on a rehearsal.** The pinned `pr-downstream` version has no `dryrun` input, so passing one was silently ignored and a rehearsal was attempting real PR creation. They also can't be meaningfully rehearsed: they bump *to* the version being released, which does not exist until it is published. +- **Reviewers are requested as a user, not a team.** A federated App installation token cannot request team reviewers. CODEOWNERS in each downstream repo still pulls in the owning team. +- `mirror-public` squash-mirrors onto the public `launchdarkly/ld-openapi`. **Aborts on conflict rather than resolving** — that push is not practically reversible, and the public repo has diverged. Failure here does not invalidate the release. + +### Credentials + +`BOT_TOKEN` needs push on all five `api-client-*` repos and on the public `ld-openapi`; the registry credentials need publish rights; `LD_API_KEY` needs write on the project the samples use. Anything touching the spec's source repo or the downstream repos uses a token **minted at runtime**, not a stored secret. + +Stored secrets are managed in internal infrastructure, not here. Where a parameter is created holding a placeholder and the real value written separately, there is a window where the secret exists but is the placeholder — the audit detects that and names it, rather than reporting an opaque authentication failure. + +`token-audit.yml` audits every credential read-only and is dispatchable on its own. `release.yml` runs it as a gate on **every** release: a bad registry credential would otherwise surface only after `make push` had tagged five client repos, which is what forces the delete-the-tags-and-retry dance. + +Two registry credentials cannot be positively verified and report `UNVERIFIED`, which is not a failure: PyPI has no token introspection, and a correctly-scoped RubyGems key (push-only) is rejected by the profile endpoint by design. + +**Every job that mints a federated token needs `permissions: id-token: write`.** Without it the exchange fails before it reaches the trust policy. For a reusable workflow it must be granted **twice** — on the calling job and at the called workflow's own level — because a reusable workflow is capped by what its caller holds. + +### Rehearsing + +`dryRun: true` runs the audit, preflight, and the full build, uses `push_dry_run`/`publish_dry_run`, and skips the downstream PR jobs. The artifacts a real run would have published are uploaded as `dry-run-artifacts`. + +**A rehearsal's log looks almost identical to a real release.** `push_dry_run` does real clones, commits and local tags, and `git push --dry-run` prints the same `* [new tag]` lines a real push does; `npm publish --dry-run` prints its usual notices. The distinguishing markers are `(dry-run)` in the npm output and "Simulating the updates we would do" from `make`. When in doubt, verify against the world — repo tags and registry HTTP status — rather than trusting the log's appearance. + +`push_dry_run` does authenticate and check write access, so it genuinely exercises `BOT_TOKEN`'s push rights. + +### Testing changes to these workflows + +`workflow_dispatch` only registers if the workflow file carrying that trigger exists on **`main`**. A new workflow, or a newly added trigger on an existing one, is therefore not dispatchable until merged. `release.yml` itself is dispatchable from any branch and GitHub runs the definition from the branch you select — **except** the federated-token steps, whose trust policy is restricted to `main`. Anything needing a minted token only works there. `ci.yml` runs on every PR regardless. + +### Troubleshooting + +- `Access Denied` fetching `openapi.json` — that endpoint fails intermittently; re-run. +- Publish failure to one registry — **published registry versions are immutable.** A partial publish cannot be re-run; it needs a new patch version. Before re-running anything, establish what actually landed: repo tags and each registry's HTTP status. `force: true` deletes tags from a prior attempt but cannot un-publish. +- Re-running a run: use **re-run failed jobs**, never re-run all, or the publish job repeats against registries that already hold the version. +- Gate 1 timing out — either the spec commit has not deployed, or spec changes keep landing. Waiting is the correct default; `skipSpecParity` is the override. +- A healthy run takes ~6 min through publish. Much longer means something is hanging. + +## Conventions + +- Never edit generated output under `targets/` to fix a problem; change the spec, the template override, or the `CODEGEN_PARAMS_` flags. +- This repo is kept in sync with the public `launchdarkly/ld-openapi`, so treat everything committed here as publishable. diff --git a/Makefile b/Makefile index aa7b417..316d738 100644 --- a/Makefile +++ b/Makefile @@ -80,15 +80,33 @@ CODEGEN_PARAMS_java = \ --additional-properties=gradleProperties=systemProp.org.gradle.internal.http.connectionTimeout=300000$$'\n'systemProp.org.gradle.internal.http.socketTimeout=300000$$'\n'org.gradle.jvmargs=-Xss2m \ --additional-properties=launchDarklyApiVersion=${LATEST_API_VERSION} CODEGEN_PARAMS_python = \ + -t $(TEMPLATES_PATH)/python \ --additional-properties=packageName=launchdarkly_api \ --additional-properties=packageVersion=$(TAG) \ --additional-properties=launchDarklyApiVersion=${LATEST_API_VERSION} +# TEMPORARY: axios is pinned to 1.18.1 rather than a floating ^1.13.1 range. +# axios 1.19.0 (2026-07-29) added `declare const axiosResponseDefault: unique symbol` +# to its index.d.ts and refers to it from the public return type of `request()`. +# The symbol is never exported, so tsc cannot name it when it infers the type of +# the generated common.ts `createRequestFunction`, and the client fails to build: +# common.ts(108,14): error TS2527: The inferred type of 'createRequestFunction' +# references an inaccessible 'unique symbol' type. A type annotation is necessary. +# Everything up to and including 1.18.1 builds. This is not fixed upstream: +# openapi-generator master still emits the unannotated function, and 1.19.0 is +# still axios latest. +# +# The real fix is a swagger-codegen-templates/typescript/common.mustache override +# annotating the returned closure — `): Promise =>` plus +# `as Promise` on the axios.request call — which compiles clean against 1.19.0 +# and against older axios. Deferred: it adds a fifth template to keep in sync with +# generator upgrades. Revert this pin when that override lands, or when axios +# exports the symbol. CODEGEN_PARAMS_typescript-axios = \ -t $(TEMPLATES_PATH)/typescript \ --additional-properties=npmName=launchdarkly-api-typescript \ --additional-properties=npmVersion=$(TAG) \ --additional-properties=supportsES6=true \ - --additional-properties=axiosVersion=^1.13.1 \ + --additional-properties=axiosVersion=1.18.1 \ --additional-properties=launchDarklyApiVersion=${LATEST_API_VERSION} CODEGEN_PARAMS_ruby = \ -t $(TEMPLATES_PATH)/ruby \ @@ -170,6 +188,10 @@ push_test: push push_dry_run: GIT_PUSH_COMMAND=git push --dry-run push_dry_run: GIT_PUSH_DESC=Simulating the updates we would do +# Without this prerequisite the target is only a set of variable assignments, so +# `make push_dry_run` prints "Nothing to be done" and exits 0 — a rehearsal that +# silently does nothing. push_test has always had it; this one was missing it. +push_dry_run: push # for each client library, clone the repository and replace the contents with the newly generated client push: mkdir $(CLIENT_CLONES_PATH); \ diff --git a/README.md b/README.md index 640ea19..3163a4a 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,46 @@ The LaunchDarkly REST API is for custom integrations, data export, or automating Server/client code for the API can be automatically generated. To generate the code: - 1. Ensure that you have `curl` and `jq` installed. + 1. Ensure that you have `java`, `curl`, and `jq` installed. 1. The default make command will generate all target libraries: ``` > make ``` +Generated output lands under `targets/`, which is not committed. To generate a single language, name it as the target — for example `make go`. Valid targets are `go`, `java`, `python`, `ruby`, and `typescript-axios`. + +Only the HTTP-layer template is overridden per language, in `swagger-codegen-templates/`. Each override is a verbatim copy of the corresponding upstream generator template with LaunchDarkly additions fenced by `CUSTOM-START` / `CUSTOM-END` markers, so it must be re-copied and re-applied whenever `GENERATOR_VERSION` in the Makefile changes. + +## Verifying generated clients + +There is no unit test suite. Two checks stand in for one, both run by CI on every pull request: + + 1. `make BUILD_TARGETS="go java python ruby typescript-axios" build_clients` — confirms each generated client compiles and packages. + 1. The programs under `samples/` — each creates a feature flag against the live API, prints it, and deletes it, exercising the generated client end to end. They need an API key. + +`./scripts/release/selfcheck.sh` runs static checks over the release automation itself, in a couple of seconds and with no side effects. + ## How releases work -This project is set up to use [Github Actions](https://github.com/launchdarkly/ld-openapi-private/actions/workflows/release.yml) to release new versions. \ No newline at end of file +Releases run from the [`release.yml`](.github/workflows/release.yml) GitHub Actions workflow. Dispatch it with no inputs for a normal release: the version, the semver bump, and the release notes are all derived, and each precondition is an enforced gate that fails with a specific reason rather than releasing on a guess. + +A release, in order: + + 1. Audits every credential it will need, read-only, before doing any work. + 1. Checks that production is serving the spec the release will be built from, and that the spec's source is in a good state. + 1. Derives the next version from the most recent client tag and the bump implied by the pending changelog entries. + 1. Generates and builds all five clients. + 1. Pushes each client to its own public `launchdarkly/api-client-` repository, tags it, and publishes to PyPI, RubyGems, npm, and Maven Central. Go has no registry step — its git tag is the release. + 1. Confirms each package is actually retrievable from its registry before continuing. + 1. Creates a GitHub release on each client repository, and opens pull requests bumping the new client version in the repositories that consume it. + +All workflow inputs are optional overrides. The useful ones: + +| Input | Effect | +| --- | --- | +| `dryRun` | Rehearses everything without pushing or publishing anything | +| `releaseVersion` | Releases a specific version instead of the derived one | +| `bumpType` | Forces `major`, `minor`, or `patch` | +| `force` | Deletes tags left behind by a previous failed attempt | + +Published registry versions are immutable, so a release that fails partway through cannot simply be re-run — it needs a new patch version. If a run fails, establish what actually reached each registry before retrying, and re-run only the failed jobs so the publish step is not repeated. diff --git a/samples/javascript/package-lock.json b/samples/javascript/package-lock.json deleted file mode 100644 index f950ba0..0000000 --- a/samples/javascript/package-lock.json +++ /dev/null @@ -1,3875 +0,0 @@ -{ - "name": "launchdarkly-api-javascript-sample", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "launchdarkly-api-javascript-sample", - "version": "1.0.0", - "license": "Apache 2.0", - "dependencies": { - "launchdarkly-api": "file:../../targets/api-client-javascript" - } - }, - "../../targets/api-client-javascript": { - "name": "launchdarkly-api", - "version": "0.0.1-SNAPSHOT", - "license": "Apache 2.0", - "dependencies": { - "@babel/cli": "^7.0.0", - "superagent": "^5.3.0" - }, - "devDependencies": { - "@babel/core": "^7.0.0", - "@babel/plugin-proposal-class-properties": "^7.0.0", - "@babel/plugin-proposal-decorators": "^7.0.0", - "@babel/plugin-proposal-do-expressions": "^7.0.0", - "@babel/plugin-proposal-export-default-from": "^7.0.0", - "@babel/plugin-proposal-export-namespace-from": "^7.0.0", - "@babel/plugin-proposal-function-bind": "^7.0.0", - "@babel/plugin-proposal-function-sent": "^7.0.0", - "@babel/plugin-proposal-json-strings": "^7.0.0", - "@babel/plugin-proposal-logical-assignment-operators": "^7.0.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", - "@babel/plugin-proposal-numeric-separator": "^7.0.0", - "@babel/plugin-proposal-optional-chaining": "^7.0.0", - "@babel/plugin-proposal-pipeline-operator": "^7.0.0", - "@babel/plugin-proposal-throw-expressions": "^7.0.0", - "@babel/plugin-syntax-dynamic-import": "^7.0.0", - "@babel/plugin-syntax-import-meta": "^7.0.0", - "@babel/preset-env": "^7.0.0", - "@babel/register": "^7.0.0", - "expect.js": "^0.3.1", - "mocha": "^8.0.1", - "sinon": "^7.2.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/cli": { - "version": "7.28.3", - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.28", - "commander": "^6.2.0", - "convert-source-map": "^2.0.0", - "fs-readdir-recursive": "^1.1.0", - "glob": "^7.2.0", - "make-dir": "^2.1.0", - "slash": "^2.0.0" - }, - "bin": { - "babel": "bin/babel.js", - "babel-external-helpers": "bin/babel-external-helpers.js" - }, - "engines": { - "node": ">=6.9.0" - }, - "optionalDependencies": { - "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", - "chokidar": "^3.6.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/code-frame": { - "version": "7.27.1", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/compat-data": { - "version": "7.28.4", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/core": { - "version": "7.28.4", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/generator": { - "version": "7.28.3", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.3" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "regexpu-core": "^6.2.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "debug": "^4.4.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.22.10" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-globals": { - "version": "7.28.0", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helper-wrap-function": { - "version": "7.28.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/helpers": { - "version": "7.28.4", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/parser": { - "version": "7.28.4", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.4" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-decorators": { - "version": "7.28.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-syntax-decorators": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-do-expressions": { - "version": "7.28.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-export-default-from": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-function-bind": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-function-sent": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-pipeline-operator": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-syntax-pipeline-operator": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-proposal-throw-expressions": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-syntax-decorators": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-syntax-pipeline-operator": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.28.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.28.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-class-properties": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.28.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-classes": { - "version": "7.28.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-for-of": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-function-name": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-json-strings": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-literals": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-new-target": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.7", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-private-methods": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-spread": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/preset-env": { - "version": "7.28.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.0", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.27.1", - "@babel/plugin-syntax-import-attributes": "^7.27.1", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.0", - "@babel/plugin-transform-async-to-generator": "^7.27.1", - "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.0", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.3", - "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", - "@babel/plugin-transform-dotall-regex": "^7.27.1", - "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.27.1", - "@babel/plugin-transform-export-namespace-from": "^7.27.1", - "@babel/plugin-transform-for-of": "^7.27.1", - "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.27.1", - "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", - "@babel/plugin-transform-member-expression-literals": "^7.27.1", - "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.27.1", - "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.0", - "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.27.1", - "@babel/plugin-transform-private-property-in-object": "^7.27.1", - "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.3", - "@babel/plugin-transform-regexp-modifiers": "^7.27.1", - "@babel/plugin-transform-reserved-words": "^7.27.1", - "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.27.1", - "@babel/plugin-transform-sticky-regex": "^7.27.1", - "@babel/plugin-transform-template-literals": "^7.27.1", - "@babel/plugin-transform-typeof-symbol": "^7.27.1", - "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.27.1", - "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "core-js-compat": "^3.43.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/register": { - "version": "7.28.3", - "dev": true, - "license": "MIT", - "dependencies": { - "clone-deep": "^4.0.1", - "find-cache-dir": "^2.0.0", - "make-dir": "^2.1.0", - "pirates": "^4.0.6", - "source-map-support": "^0.5.16" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/template": { - "version": "7.27.2", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/traverse": { - "version": "7.28.4", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@babel/types": { - "version": "7.28.4", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "../../targets/api-client-javascript/node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "../../targets/api-client-javascript/node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "../../targets/api-client-javascript/node_modules/@nicolo-ribaudo/chokidar-2": { - "version": "2.1.8-no-fsevents.3", - "license": "MIT", - "optional": true - }, - "../../targets/api-client-javascript/node_modules/@sinonjs/commons": { - "version": "1.8.6", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "../../targets/api-client-javascript/node_modules/@sinonjs/formatio": { - "version": "3.2.2", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^3.1.0" - } - }, - "../../targets/api-client-javascript/node_modules/@sinonjs/samsam": { - "version": "3.3.3", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^1.3.0", - "array-from": "^2.1.1", - "lodash": "^4.17.15" - } - }, - "../../targets/api-client-javascript/node_modules/@sinonjs/text-encoding": { - "version": "0.7.3", - "dev": true, - "license": "(Unlicense OR Apache-2.0)" - }, - "../../targets/api-client-javascript/node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "dev": true, - "license": "ISC" - }, - "../../targets/api-client-javascript/node_modules/ansi-colors": { - "version": "4.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/ansi-regex": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "../../targets/api-client-javascript/node_modules/anymatch": { - "version": "3.1.3", - "devOptional": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "../../targets/api-client-javascript/node_modules/argparse": { - "version": "2.0.1", - "dev": true, - "license": "Python-2.0" - }, - "../../targets/api-client-javascript/node_modules/array-from": { - "version": "2.1.1", - "dev": true, - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/asynckit": { - "version": "0.4.0", - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.14", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.7", - "@babel/helper-define-polyfill-provider": "^0.6.5", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.13.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/balanced-match": { - "version": "1.0.2", - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/baseline-browser-mapping": { - "version": "2.8.14", - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "../../targets/api-client-javascript/node_modules/binary-extensions": { - "version": "2.3.0", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../targets/api-client-javascript/node_modules/brace-expansion": { - "version": "1.1.12", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "../../targets/api-client-javascript/node_modules/braces": { - "version": "3.0.3", - "devOptional": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/browser-stdout": { - "version": "1.3.1", - "dev": true, - "license": "ISC" - }, - "../../targets/api-client-javascript/node_modules/browserslist": { - "version": "4.26.3", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.8.9", - "caniuse-lite": "^1.0.30001746", - "electron-to-chromium": "^1.5.227", - "node-releases": "^2.0.21", - "update-browserslist-db": "^1.1.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "../../targets/api-client-javascript/node_modules/buffer-from": { - "version": "1.1.2", - "dev": true, - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "../../targets/api-client-javascript/node_modules/call-bound": { - "version": "1.0.4", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/camelcase": { - "version": "6.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../targets/api-client-javascript/node_modules/caniuse-lite": { - "version": "1.0.30001749", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "../../targets/api-client-javascript/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "../../targets/api-client-javascript/node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/chokidar": { - "version": "3.6.0", - "license": "MIT", - "optional": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "../../targets/api-client-javascript/node_modules/cliui": { - "version": "7.0.4", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/clone-deep": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/combined-stream": { - "version": "1.0.8", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "../../targets/api-client-javascript/node_modules/commander": { - "version": "6.2.1", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "../../targets/api-client-javascript/node_modules/commondir": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/component-emitter": { - "version": "1.3.1", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../targets/api-client-javascript/node_modules/concat-map": { - "version": "0.0.1", - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/convert-source-map": { - "version": "2.0.0", - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/cookiejar": { - "version": "2.1.4", - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/core-js-compat": { - "version": "3.45.1", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.25.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "../../targets/api-client-javascript/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "../../targets/api-client-javascript/node_modules/decamelize": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../targets/api-client-javascript/node_modules/delayed-stream": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "../../targets/api-client-javascript/node_modules/diff": { - "version": "5.0.0", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "../../targets/api-client-javascript/node_modules/dunder-proto": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "../../targets/api-client-javascript/node_modules/electron-to-chromium": { - "version": "1.5.233", - "license": "ISC" - }, - "../../targets/api-client-javascript/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/es-define-property": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "../../targets/api-client-javascript/node_modules/es-errors": { - "version": "1.3.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "../../targets/api-client-javascript/node_modules/es-object-atoms": { - "version": "1.1.1", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "../../targets/api-client-javascript/node_modules/es-set-tostringtag": { - "version": "2.1.0", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "../../targets/api-client-javascript/node_modules/escalade": { - "version": "3.2.0", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/escape-string-regexp": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../targets/api-client-javascript/node_modules/esutils": { - "version": "2.0.3", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "../../targets/api-client-javascript/node_modules/expect.js": { - "version": "0.3.1", - "dev": true - }, - "../../targets/api-client-javascript/node_modules/fast-safe-stringify": { - "version": "2.1.1", - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/fill-range": { - "version": "7.1.1", - "devOptional": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/find-cache-dir": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/find-up": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../targets/api-client-javascript/node_modules/flat": { - "version": "5.0.2", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "../../targets/api-client-javascript/node_modules/form-data": { - "version": "3.0.4", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.35" - }, - "engines": { - "node": ">= 6" - } - }, - "../../targets/api-client-javascript/node_modules/formidable": { - "version": "1.2.6", - "license": "MIT", - "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" - } - }, - "../../targets/api-client-javascript/node_modules/fs-readdir-recursive": { - "version": "1.1.0", - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/fs.realpath": { - "version": "1.0.0", - "license": "ISC" - }, - "../../targets/api-client-javascript/node_modules/function-bind": { - "version": "1.1.2", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/gensync": { - "version": "1.0.0-beta.2", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../../targets/api-client-javascript/node_modules/get-caller-file": { - "version": "2.0.5", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "../../targets/api-client-javascript/node_modules/get-intrinsic": { - "version": "1.3.0", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/get-proto": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "../../targets/api-client-javascript/node_modules/glob": { - "version": "7.2.3", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "../../targets/api-client-javascript/node_modules/glob-parent": { - "version": "5.1.2", - "devOptional": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "../../targets/api-client-javascript/node_modules/gopd": { - "version": "1.2.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/growl": { - "version": "1.10.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.x" - } - }, - "../../targets/api-client-javascript/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/has-symbols": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/has-tostringtag": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/hasown": { - "version": "2.0.2", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "../../targets/api-client-javascript/node_modules/he": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" - } - }, - "../../targets/api-client-javascript/node_modules/inflight": { - "version": "1.0.6", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "../../targets/api-client-javascript/node_modules/inherits": { - "version": "2.0.4", - "license": "ISC" - }, - "../../targets/api-client-javascript/node_modules/is-binary-path": { - "version": "2.1.0", - "devOptional": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/is-core-module": { - "version": "2.16.1", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/is-extglob": { - "version": "2.1.1", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../../targets/api-client-javascript/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/is-glob": { - "version": "4.0.3", - "devOptional": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "../../targets/api-client-javascript/node_modules/is-number": { - "version": "7.0.0", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "../../targets/api-client-javascript/node_modules/is-plain-obj": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/is-plain-object": { - "version": "2.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "../../targets/api-client-javascript/node_modules/isarray": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "../../targets/api-client-javascript/node_modules/isobject": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../../targets/api-client-javascript/node_modules/js-tokens": { - "version": "4.0.0", - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/js-yaml": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "../../targets/api-client-javascript/node_modules/jsesc": { - "version": "3.1.0", - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/json5": { - "version": "2.2.3", - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/just-extend": { - "version": "4.2.1", - "dev": true, - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/kind-of": { - "version": "6.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../../targets/api-client-javascript/node_modules/locate-path": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../targets/api-client-javascript/node_modules/lodash": { - "version": "4.17.21", - "dev": true, - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/lodash.debounce": { - "version": "4.0.8", - "dev": true, - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/log-symbols": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "../../targets/api-client-javascript/node_modules/lolex": { - "version": "4.2.0", - "dev": true, - "license": "BSD-3-Clause" - }, - "../../targets/api-client-javascript/node_modules/lru-cache": { - "version": "5.1.1", - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "../../targets/api-client-javascript/node_modules/make-dir": { - "version": "2.1.0", - "license": "MIT", - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/make-dir/node_modules/semver": { - "version": "5.7.2", - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "../../targets/api-client-javascript/node_modules/math-intrinsics": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "../../targets/api-client-javascript/node_modules/methods": { - "version": "1.1.2", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "../../targets/api-client-javascript/node_modules/mime": { - "version": "2.6.0", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/mime-db": { - "version": "1.52.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "../../targets/api-client-javascript/node_modules/mime-types": { - "version": "2.1.35", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "../../targets/api-client-javascript/node_modules/minimatch": { - "version": "3.1.2", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "../../targets/api-client-javascript/node_modules/mocha": { - "version": "8.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.1", - "debug": "4.3.1", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.0.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.20", - "serialize-javascript": "5.0.1", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.1.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 10.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "../../targets/api-client-javascript/node_modules/mocha/node_modules/chokidar": { - "version": "3.5.1", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.1" - } - }, - "../../targets/api-client-javascript/node_modules/mocha/node_modules/debug": { - "version": "4.3.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "../../targets/api-client-javascript/node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "dev": true, - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/mocha/node_modules/glob": { - "version": "7.1.6", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "../../targets/api-client-javascript/node_modules/mocha/node_modules/minimatch": { - "version": "3.0.4", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "../../targets/api-client-javascript/node_modules/mocha/node_modules/readdirp": { - "version": "3.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "../../targets/api-client-javascript/node_modules/ms": { - "version": "2.1.3", - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/nanoid": { - "version": "3.1.20", - "dev": true, - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "../../targets/api-client-javascript/node_modules/nise": { - "version": "1.5.3", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/formatio": "^3.2.1", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "lolex": "^5.0.1", - "path-to-regexp": "^1.7.0" - } - }, - "../../targets/api-client-javascript/node_modules/nise/node_modules/lolex": { - "version": "5.1.2", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "../../targets/api-client-javascript/node_modules/node-releases": { - "version": "2.0.23", - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/normalize-path": { - "version": "3.0.0", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../../targets/api-client-javascript/node_modules/object-inspect": { - "version": "1.13.4", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/once": { - "version": "1.4.0", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "../../targets/api-client-javascript/node_modules/p-limit": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../targets/api-client-javascript/node_modules/p-locate": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../targets/api-client-javascript/node_modules/p-try": { - "version": "2.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/path-exists": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/path-is-absolute": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../../targets/api-client-javascript/node_modules/path-parse": { - "version": "1.0.7", - "dev": true, - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/path-to-regexp": { - "version": "1.9.0", - "dev": true, - "license": "MIT", - "dependencies": { - "isarray": "0.0.1" - } - }, - "../../targets/api-client-javascript/node_modules/picocolors": { - "version": "1.1.1", - "license": "ISC" - }, - "../../targets/api-client-javascript/node_modules/picomatch": { - "version": "2.3.1", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "../../targets/api-client-javascript/node_modules/pify": { - "version": "4.0.1", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/pirates": { - "version": "4.0.7", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "../../targets/api-client-javascript/node_modules/pkg-dir": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/pkg-dir/node_modules/find-up": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/pkg-dir/node_modules/locate-path": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../targets/api-client-javascript/node_modules/pkg-dir/node_modules/p-locate": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/pkg-dir/node_modules/path-exists": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/qs": { - "version": "6.14.0", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/randombytes": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "../../targets/api-client-javascript/node_modules/readable-stream": { - "version": "3.6.2", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "../../targets/api-client-javascript/node_modules/readdirp": { - "version": "3.6.0", - "license": "MIT", - "optional": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "../../targets/api-client-javascript/node_modules/regenerate": { - "version": "1.4.2", - "dev": true, - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/regenerate-unicode-properties": { - "version": "10.2.2", - "dev": true, - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/regexpu-core": { - "version": "6.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.2", - "regjsgen": "^0.8.0", - "regjsparser": "^0.13.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.2.1" - }, - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/regjsgen": { - "version": "0.8.0", - "dev": true, - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/regjsparser": { - "version": "0.13.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "jsesc": "~3.1.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "../../targets/api-client-javascript/node_modules/require-directory": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../../targets/api-client-javascript/node_modules/resolve": { - "version": "1.22.10", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/semver": { - "version": "6.3.1", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "../../targets/api-client-javascript/node_modules/serialize-javascript": { - "version": "5.0.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "../../targets/api-client-javascript/node_modules/shallow-clone": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/side-channel": { - "version": "1.1.0", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/side-channel-list": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/side-channel-map": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/side-channel-weakmap": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/sinon": { - "version": "7.5.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^1.4.0", - "@sinonjs/formatio": "^3.2.1", - "@sinonjs/samsam": "^3.3.3", - "diff": "^3.5.0", - "lolex": "^4.2.0", - "nise": "^1.5.2", - "supports-color": "^5.5.0" - } - }, - "../../targets/api-client-javascript/node_modules/sinon/node_modules/diff": { - "version": "3.5.0", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "../../targets/api-client-javascript/node_modules/sinon/node_modules/has-flag": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/sinon/node_modules/supports-color": { - "version": "5.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/slash": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../../targets/api-client-javascript/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "../../targets/api-client-javascript/node_modules/source-map-support": { - "version": "0.5.21", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "../../targets/api-client-javascript/node_modules/string_decoder": { - "version": "1.3.0", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "../../targets/api-client-javascript/node_modules/string-width": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/strip-ansi": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/strip-json-comments": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../../targets/api-client-javascript/node_modules/superagent": { - "version": "5.3.1", - "license": "MIT", - "dependencies": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.2", - "debug": "^4.1.1", - "fast-safe-stringify": "^2.0.7", - "form-data": "^3.0.0", - "formidable": "^1.2.2", - "methods": "^1.1.2", - "mime": "^2.4.6", - "qs": "^6.9.4", - "readable-stream": "^3.6.0", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 7.0.0" - } - }, - "../../targets/api-client-javascript/node_modules/superagent/node_modules/semver": { - "version": "7.7.3", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "../../targets/api-client-javascript/node_modules/supports-color": { - "version": "8.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "../../targets/api-client-javascript/node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../../targets/api-client-javascript/node_modules/to-regex-range": { - "version": "5.0.1", - "devOptional": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "../../targets/api-client-javascript/node_modules/type-detect": { - "version": "4.0.8", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/unicode-property-aliases-ecmascript": { - "version": "2.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "../../targets/api-client-javascript/node_modules/update-browserslist-db": { - "version": "1.1.3", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "../../targets/api-client-javascript/node_modules/util-deprecate": { - "version": "1.0.2", - "license": "MIT" - }, - "../../targets/api-client-javascript/node_modules/which": { - "version": "2.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "../../targets/api-client-javascript/node_modules/wide-align": { - "version": "1.1.3", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "../../targets/api-client-javascript/node_modules/workerpool": { - "version": "6.1.0", - "dev": true, - "license": "Apache-2.0" - }, - "../../targets/api-client-javascript/node_modules/wrap-ansi": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "../../targets/api-client-javascript/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/wrappy": { - "version": "1.0.2", - "license": "ISC" - }, - "../../targets/api-client-javascript/node_modules/y18n": { - "version": "5.0.8", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "../../targets/api-client-javascript/node_modules/yallist": { - "version": "3.1.1", - "license": "ISC" - }, - "../../targets/api-client-javascript/node_modules/yargs": { - "version": "16.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "../../targets/api-client-javascript/node_modules/yargs-parser": { - "version": "20.2.4", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "../../targets/api-client-javascript/node_modules/yargs-unparser": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "../../targets/api-client-javascript/node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "../../targets/api-client-javascript/node_modules/yocto-queue": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/launchdarkly-api": { - "resolved": "../../targets/api-client-javascript", - "link": true - } - } -} diff --git a/samples/javascript/package.json b/samples/javascript/package.json deleted file mode 100644 index 949d9de..0000000 --- a/samples/javascript/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "launchdarkly-api-javascript-sample", - "version": "1.0.0", - "description": "Sample app for launchdarkly-api", - "main": "index.js", - "scripts": { - "start": "node index.js" - }, - "license": "Apache 2.0", - "dependencies": { - "launchdarkly-api": "file:../../targets/api-client-javascript" - } -} diff --git a/scripts/release/gonfalon-update.sh b/scripts/release/gonfalon-update.sh new file mode 100755 index 0000000..c80ddc9 --- /dev/null +++ b/scripts/release/gonfalon-update.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# +# Runbook steps 10 and 12, as a single downstream change: +# 10. rename gonfalon's [Unreleased] changelog heading to the released version +# and open a fresh empty [Unreleased] above it +# 12. bump the api-client-go version gonfalon depends on +# +# Runs from the root of a gonfalon checkout — pr-downstream clones the downstream +# repo into a subdirectory and runs update-command there, so this script is +# invoked by absolute path out of the ld-openapi-private workspace. +# +# Usage: gonfalon-update.sh VERSION [RELEASE_DATE] +# +# The dependency bump itself lives in gonfalon as `make update-api-client-go`, +# beside the imports it rewrites — a major bump moves the module path +# (api-client-go/vN) and has to move Go sources, BUILD.bazel labels, and +# MODULE.bazel together. This script only drives it and handles the changelog. + +set -euo pipefail + +version=${1:?usage: gonfalon-update.sh VERSION [RELEASE_DATE]} +release_date=${2:-$(date -u +%Y-%m-%d)} + +CHANGELOG=apidocs/CHANGELOG.md + +fail() { echo "gonfalon-update FAILED: $*" >&2; exit 1; } +note() { echo "==> $*"; } + +[ -f go.mod ] || fail "no go.mod here — expected to run from the gonfalon repo root (pwd=$(pwd))" +[ -f "${CHANGELOG}" ] || fail "${CHANGELOG} not found" +grep -q '^update-api-client-go:' Makefile || \ + fail "gonfalon has no 'update-api-client-go' make target — it may have been renamed" + +# --- Step 10: changelog ------------------------------------------------------ +note "Renaming [Unreleased] to [${version}] - ${release_date} in ${CHANGELOG}" +grep -qx '## \[Unreleased\]' "${CHANGELOG}" || \ + fail "no '## [Unreleased]' heading in ${CHANGELOG}; it may have been renamed already" + +# Without this, a retried release re-renames the freshly created [Unreleased] +# heading and leaves two [VERSION] sections behind. +grep -qE "^## \[${version}\]" "${CHANGELOG}" && \ + fail "${CHANGELOG} already has a '## [${version}]' section — this release was already recorded in gonfalon" + +awk -v version="${version}" -v date="${release_date}" ' + !done && /^## \[Unreleased\]$/ { + print "## [Unreleased]" + print "" + print "## [" version "] - " date + done = 1 + next + } + { print } +' "${CHANGELOG}" > "${CHANGELOG}.tmp" +mv "${CHANGELOG}.tmp" "${CHANGELOG}" + +# --- Step 12: api-client-go --------------------------------------------------- +note "make update-api-client-go API_CLIENT_GO_VERSION=${version}" +make update-api-client-go "API_CLIENT_GO_VERSION=${version}" + +# Guard against a silent no-op: if nothing changed, the PR would be empty and the +# release would look complete while gonfalon still points at the old client. +if git diff --quiet; then + fail "no changes produced — the changelog rewrite and dependency bump both no-opped" +fi + +note "Done. Changed files:" +git diff --name-only | sed 's/^/ /' diff --git a/scripts/release/mirror-public.sh b/scripts/release/mirror-public.sh new file mode 100755 index 0000000..5ae5d53 --- /dev/null +++ b/scripts/release/mirror-public.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +# +# Runbook step 11: squash-mirror this private repo onto the public launchdarkly/ld-openapi. +# +# Usage: mirror-public.sh VERSION +# +# Env: +# BOT_TOKEN the releaser token, used for both repos (required) +# DRY_RUN true = `git push --dry-run` +# +# One token covers both sides: public ld-openapi and this repo both grant +# "sa-release-bots" = "Releaser" in terraform, the same grant the api-client-* +# repos use for the pushes `make push` already does every release. +# +# This makes private-repo content public and is not practically reversible, so it +# deliberately does NOT resolve conflicts: the runbook's guidance is "generally +# I'd choose the private repo one, but use your discretion", which is a human +# decision. On conflict this aborts and leaves the release otherwise complete. + +set -euo pipefail + +version=${1:?usage: mirror-public.sh VERSION} +: "${BOT_TOKEN:?BOT_TOKEN is required}" + +PUBLIC_REPO=launchdarkly/ld-openapi +PRIVATE_REPO=launchdarkly/ld-openapi-private + +workdir=$(mktemp -d) +trap 'rm -rf "${workdir}"' EXIT + +note() { echo "==> $*"; } +fail() { echo "MIRROR FAILED: $*" >&2; exit 1; } + +note "Cloning ${PUBLIC_REPO}" +git clone --quiet "https://x-access-token:${BOT_TOKEN}@github.com/${PUBLIC_REPO}.git" "${workdir}/public" +cd "${workdir}/public" + +git config user.name LaunchDarklyReleaseBot +git config user.email launchdarklyreleasebot@launchdarkly.com + +git remote add private "https://x-access-token:${BOT_TOKEN}@github.com/${PRIVATE_REPO}.git" +git fetch --quiet private main + +if git diff --quiet HEAD private/main; then + note "Public repo already matches private main — nothing to mirror." + exit 0 +fi + +note "Files that will change on ${PUBLIC_REPO}" +git diff --name-status HEAD private/main | sed 's/^/ /' + +if ! git merge --squash private/main; then + conflicts=$(git diff --name-only --diff-filter=U || true) + fail "merge conflicts while squashing private/main: +$(sed 's/^/ /' <<<"${conflicts}") + Resolve by hand per the runbook and push to ${PUBLIC_REPO} yourself. + The release itself already completed; only the public mirror is pending." +fi + +if git diff --cached --quiet; then + note "Squash produced no staged changes — nothing to commit." + exit 0 +fi + +git commit --quiet -m "Sync from ${PRIVATE_REPO} for release ${version}" + +if [ "${DRY_RUN:-false}" = "true" ]; then + note "DRY_RUN: would push to ${PUBLIC_REPO} main" + git push --dry-run origin main +else + note "Pushing to ${PUBLIC_REPO} main" + git push origin main +fi + +if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then + { + echo "### Public mirror" + echo + echo "Squashed \`${PRIVATE_REPO}@main\` onto [\`${PUBLIC_REPO}\`](https://github.com/${PUBLIC_REPO}) for release ${version}." + if [ "${DRY_RUN:-false}" = "true" ]; then + echo + echo "_Dry run — nothing was pushed._" + fi + } >> "${GITHUB_STEP_SUMMARY}" +fi diff --git a/scripts/release/preflight.sh b/scripts/release/preflight.sh new file mode 100755 index 0000000..8f94a90 --- /dev/null +++ b/scripts/release/preflight.sh @@ -0,0 +1,325 @@ +#!/usr/bin/env bash +# +# Derives every input the release needs and enforces the preflight gates from the +# release runbook. +# +# Requires: gh, curl, git. +# +# Two GitHub tokens, because they answer to different repos: +# GH_TOKEN the releaser token (BOT_TOKEN) — client repos only, used for +# the tag-collision check and, with FORCE, tag deletes. +# GONFALON_TOKEN read on launchdarkly/gonfalon, for the spec-parity gate, the +# CI gate, and the changelog. In CI this is an OctoSTS token +# minted at runtime from the ld-openapi-downstream trust policy. +# The releaser token deliberately has no gonfalon access and +# should not be granted any just to read a file. +# +# Env: +# VERSION_OVERRIDE skip version derivation and use this bare semver +# BUMP_OVERRIDE major|minor|patch — skip changelog inference +# FORCE true = delete colliding tags instead of aborting +# PARITY_TIMEOUT seconds to wait for prod to catch up to gonfalon main (default 1800) +# PARITY_INTERVAL seconds between parity polls (default 60) +# SKIP_CI_GATE true = don't require gonfalon main to be green +# SKIP_SPEC_PARITY true = release what prod serves even if main is ahead +# +# Writes version/bump/changelog to $GITHUB_OUTPUT when running under Actions, +# and always prints a human-readable summary. + +set -euo pipefail + +GONFALON=launchdarkly/gonfalon +SPEC_PATH=apidocs/openapi-public-final.json +CHANGELOG_PATH=apidocs/CHANGELOG.md +SPEC_URL=https://app.launchdarkly.com/api/v2/openapi.json +GO_CLIENT_REPO=launchdarkly/api-client-go + +# Canonical repo names. `make push` clones api-client-typescript-axios, which is a +# GitHub redirect to api-client-typescript; use the canonical name for API calls. +CLIENT_REPOS=( + launchdarkly/api-client-go + launchdarkly/api-client-java + launchdarkly/api-client-python + launchdarkly/api-client-ruby + launchdarkly/api-client-typescript +) + +PARITY_TIMEOUT=${PARITY_TIMEOUT:-1800} +PARITY_INTERVAL=${PARITY_INTERVAL:-60} +workdir=$(mktemp -d) +trap 'rm -rf "${workdir}"' EXIT + +fail() { echo "PREFLIGHT FAILED: $*" >&2; exit 1; } +note() { echo "==> $*"; } + +# Every gonfalon read goes through this, so the releaser token is never used +# against a repo it has no business reading. +GONFALON_TOKEN=${GONFALON_TOKEN:-} +[ -n "${GONFALON_TOKEN}" ] || \ + fail "GONFALON_TOKEN must be set — it is what reads ${GONFALON}. In CI it comes from the octosts-action step; locally, pass a token with read access. BOT_TOKEN has no access there." +gh_gonfalon() { GH_TOKEN="${GONFALON_TOKEN}" gh "$@"; } + +# --- Gate 1: prod serves exactly what gonfalon main has committed ------------- +# This replaces both the Slack "nothing mid-flight" check and the "wait for the +# commit to be deployed to production" wait. gonfalon commits the published spec, +# and prod serves that file byte for byte, so a git blob SHA comparison settles it: +# equal -> prod is caught up AND nothing is mid-flight; safe to release. +# unequal -> either a merged spec change isn't deployed yet, or one just landed. +# +# Compared via `git hash-object` rather than downloading gonfalon's copy: the file +# is ~2.8MB, over the contents API's 1MB raw limit, but the tree API always +# returns its blob SHA. +# +# main is re-resolved on every poll so we converge on wherever main currently is, +# then frozen: every later read (CI status, changelog) uses that one commit. Doing +# otherwise lets a merge land mid-preflight and pair a changelog with a spec it +# does not describe — gonfalon's main moves often enough for that to be real. +note "Gate 1: comparing prod spec against ${GONFALON} main:${SPEC_PATH}" +spec_dir=$(dirname "${SPEC_PATH}") +spec_file=$(basename "${SPEC_PATH}") +deadline=$(( $(date +%s) + PARITY_TIMEOUT )) +while :; do + gonfalon_sha=$(gh_gonfalon api "repos/${GONFALON}/commits/main" --jq '.sha') + [ -n "${gonfalon_sha}" ] || fail "could not resolve ${GONFALON} main" + + curl -s -L --fail "${SPEC_URL}" -o "${workdir}/prod-openapi.json" || \ + fail "could not download ${SPEC_URL} (this endpoint fails intermittently — retry the run)" + + prod_blob=$(git hash-object "${workdir}/prod-openapi.json") + main_blob=$(gh_gonfalon api "repos/${GONFALON}/git/trees/${gonfalon_sha}:${spec_dir}" \ + --jq ".tree[] | select(.path == \"${spec_file}\") | .sha") + + [ -n "${main_blob}" ] || fail "could not read blob SHA for ${SPEC_PATH} at ${GONFALON}@${gonfalon_sha}" + + if [ "${prod_blob}" = "${main_blob}" ]; then + echo " in sync at ${gonfalon_sha:0:9} (blob ${prod_blob})" + break + fi + + # SKIP_SPEC_PARITY releases what production is serving even though main is ahead. + # The build downloads the spec from prod either way, so this does not change what + # ships — it changes whether we refuse to ship. What it costs: the changelog and + # version still come from main, so the release notes may describe spec changes + # that are merged but not yet deployed, and the downstream gonfalon PR would + # record them against this version. Trim those entries from that PR before + # merging it; it requires review anyway. + if [ "${SKIP_SPEC_PARITY:-false}" = "true" ]; then + echo " NOT IN SYNC, but SKIP_SPEC_PARITY=true — proceeding." + echo " prod blob ${prod_blob}" + echo " main blob ${main_blob} at ${gonfalon_sha:0:9}" + echo " Releasing the spec production currently serves. Check the changelog" + echo " entries in the gonfalon PR against what actually shipped before merging it." + break + fi + + # Two blob hashes say nothing about what is being waited on. Resolve prod's blob + # back to the gonfalon commit that produced it, once, on the first mismatch. + if [ -z "${drift_explained:-}" ]; then + drift_explained=1 + echo " not in sync. Resolving which commit prod is serving..." + spec_history=$(gh_gonfalon api \ + "repos/${GONFALON}/commits?path=${SPEC_PATH}&per_page=20" \ + --jq '.[] | "\(.sha) \(.commit.committer.date) \(.commit.message | split("\n")[0])"' 2>/dev/null || true) + + prod_commit="" + while IFS= read -r line; do + [ -n "${line}" ] || continue + c=${line%% *} + b=$(gh_gonfalon api "repos/${GONFALON}/git/trees/${c}:${spec_dir}" \ + --jq ".tree[] | select(.path == \"${spec_file}\") | .sha" 2>/dev/null || true) + if [ "${b}" = "${prod_blob}" ]; then prod_commit=${line}; break; fi + done <<<"${spec_history}" + + main_line=$(head -1 <<<"${spec_history}") + if [ -n "${prod_commit}" ]; then + echo " prod is serving ${SPEC_PATH} from ${prod_commit}" + else + echo " WARNING: prod's spec matches no recent commit on main. It may be serving" + echo " something unreleased, or the file moved. Investigate before releasing." + fi + echo " main's latest spec commit is ${main_line}" + echo " Waiting for that to reach production." + fi + + now=$(date +%s) + if [ "${now}" -ge "${deadline}" ]; then + fail "prod spec (${prod_blob}) still differs from ${GONFALON} main (${main_blob}) after ${PARITY_TIMEOUT}s. + Waiting on: ${main_line:-the latest spec commit on main} to deploy to production. + Releasing before it does would publish release notes describing a spec that + production is not yet serving. Either wait for the deploy and re-dispatch, or + raise PARITY_TIMEOUT. Check the gonfalon deploy pipeline and #proj-openapi." + fi + echo " still waiting, retrying in ${PARITY_INTERVAL}s ($(( deadline - now ))s left)" + sleep "${PARITY_INTERVAL}" +done + +# --- Gate 2: that gonfalon commit is green ------------------------------------ +# The runbook's "make sure CI is passing (basically: Gonfalon is currently in a +# good state)", pinned to the commit whose spec we are about to ship. +# Uses check-runs only. The combined-status endpoint +# (/commits/{sha}/status) needs the `statuses` permission, which no policy in +# launchdarkly/.github-private grants and which may not be available on the +# OctoSTS app at all; `checks: read` is granted and has precedent +# (service-template-go-sync). check-runs covers the GitHub Actions checks, which +# is what "is gonfalon green" means here. The tradeoff is that legacy commit +# statuses from external systems are not considered. +if [ "${SKIP_CI_GATE:-false}" != "true" ]; then + note "Gate 2: checking CI for ${GONFALON}@${gonfalon_sha:0:9}" + check_runs=$(gh_gonfalon api "repos/${GONFALON}/commits/${gonfalon_sha}/check-runs" --paginate) || \ + fail "could not read check runs for ${GONFALON}@${gonfalon_sha:0:9}. + If this is HTTP 403, the federated token is missing 'checks: read' — add it to + .github/launchdarkly/ld-openapi-downstream.sts.yaml in launchdarkly/.github-private." + + total=$(jq '[.check_runs[]] | length' <<<"${check_runs}") + failed_checks=$(jq '[.check_runs[] | select(.conclusion == "failure" or .conclusion == "timed_out")] | length' <<<"${check_runs}") + + if [ "${failed_checks}" -gt 0 ]; then + jq -r '.check_runs[] | select(.conclusion == "failure" or .conclusion == "timed_out") | " failed: \(.name)"' <<<"${check_runs}" >&2 || true + fail "${GONFALON}@${gonfalon_sha:0:9} is not green (${failed_checks} of ${total} checks failed). Set SKIP_CI_GATE=true to override." + fi + echo " green (${total} check runs, none failed)" +else + echo " Gate 2 skipped (SKIP_CI_GATE=true)" +fi + +# --- Changelog: extract the [Unreleased] body -------------------------------- +note "Reading ${CHANGELOG_PATH} at ${GONFALON}@${gonfalon_sha:0:9}" +gh_gonfalon api "repos/${GONFALON}/contents/${CHANGELOG_PATH}?ref=${gonfalon_sha}" \ + -H "Accept: application/vnd.github.raw" > "${workdir}/CHANGELOG.md" || \ + fail "could not read ${CHANGELOG_PATH} from ${GONFALON}@${gonfalon_sha}" + +awk ' + /^## \[Unreleased\]/ { capture = 1; next } + /^## \[/ { capture = 0 } + capture { print } +' "${workdir}/CHANGELOG.md" > "${workdir}/unreleased.md" + +# Trim leading/trailing blank lines. +sed -i'' -e '/./,$!d' "${workdir}/unreleased.md" +printf '%s\n' "$(cat "${workdir}/unreleased.md")" > "${workdir}/unreleased.md" + +if ! grep -q '[^[:space:]]' "${workdir}/unreleased.md"; then + fail "the [Unreleased] section of ${CHANGELOG_PATH} is empty — there is nothing to release" +fi + +# --- Bump type: inferred from the [Unreleased] section headings --------------- +# Removed/Changed -> major (both have historically carried breaking changes) +# Added/Deprecated -> minor +# Bug Fixes/Fixed -> patch +# +# NOTE: `### Changed` is genuinely ambiguous — it covers breaking and additive +# changes alike — so this rule deliberately errs toward major. Override with +# BUMP_OVERRIDE when you know better. +headings=$(grep -E '^### ' "${workdir}/unreleased.md" | sed 's/^### //' | sort -u || true) +[ -n "${headings}" ] || fail "no '### ' headings found under [Unreleased]; cannot infer a bump type" + +if [ -n "${BUMP_OVERRIDE:-}" ]; then + bump=${BUMP_OVERRIDE} + case "${bump}" in + major|minor|patch) ;; + *) fail "BUMP_OVERRIDE must be major, minor, or patch (got '${bump}')" ;; + esac + note "Bump type: ${bump} (overridden)" +elif grep -qxE 'Removed|Changed' <<<"${headings}"; then + bump="major" +elif grep -qxE 'Added|Deprecated' <<<"${headings}"; then + bump="minor" +elif grep -qxE 'Bug Fixes|Fixed|Security' <<<"${headings}"; then + bump="patch" +else + fail "unrecognised [Unreleased] headings, cannot infer a bump type: +$(sed 's/^/ /' <<<"${headings}") + Add the heading to preflight.sh's rule or pass BUMP_OVERRIDE." +fi +[ -n "${BUMP_OVERRIDE:-}" ] || note "Bump type: ${bump} (from headings: $(paste -sd, - <<<"${headings}"))" + +# --- Version: previous api-client-go tag + bump ------------------------------ +# Sort explicitly rather than trusting the tags endpoint's order, which GitHub +# does not document as semver-descending — and lexicographic order would put +# v9.0.0 above v17.0.0 anyway. +prev_tag=$(gh api --paginate "repos/${GO_CLIENT_REPO}/tags" --jq '.[].name' \ + | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -1) +[ -n "${prev_tag}" ] || fail "could not read the latest tag from ${GO_CLIENT_REPO}" +prev_version=${prev_tag#v} + +IFS=. read -r prev_major prev_minor prev_patch <<<"${prev_version}" +case "${bump}" in + major) version="$(( prev_major + 1 )).0.0" ;; + minor) version="${prev_major}.$(( prev_minor + 1 )).0" ;; + patch) version="${prev_major}.${prev_minor}.$(( prev_patch + 1 ))" ;; +esac + +if [ -n "${VERSION_OVERRIDE:-}" ]; then + grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$' <<<"${VERSION_OVERRIDE}" || \ + fail "VERSION_OVERRIDE must be bare semver MAJOR.MINOR.PATCH with no leading 'v' (got '${VERSION_OVERRIDE}')" + note "Version: ${VERSION_OVERRIDE} (overridden; derivation said ${version})" + version=${VERSION_OVERRIDE} +else + note "Version: ${version} (previous ${prev_version}, ${bump} bump)" +fi +major=${version%%.*} + +# --- Gate 3: no colliding tags ---------------------------------------------- +# A re-run after a partial failure trips over tags the previous attempt created. +# Non-Go repos get two tags per release: bare X.Y.Z from `make push`, and vX.Y.Z +# from the create-release job. Both have to go. +note "Gate 3: checking for existing ${version} / v${version} tags" +collisions=() +for repo in "${CLIENT_REPOS[@]}"; do + for ref in "${version}" "v${version}"; do + if gh api "repos/${repo}/git/ref/tags/${ref}" >/dev/null 2>&1; then + collisions+=("${repo}#${ref}") + fi + done +done + +if [ ${#collisions[@]} -gt 0 ]; then + if [ "${FORCE:-false}" = "true" ]; then + for collision in "${collisions[@]}"; do + repo=${collision%%#*} + ref=${collision##*#} + echo " deleting ${repo} tag ${ref}" + gh api -X DELETE "repos/${repo}/git/refs/tags/${ref}" + done + else + fail "tags for ${version} already exist: +$(printf ' %s\n' "${collisions[@]}") + A previous release attempt got partway through. Delete these tags, or re-run with force=true." + fi +fi + +# --- Emit -------------------------------------------------------------------- +if [ -n "${GITHUB_OUTPUT:-}" ]; then + delimiter="changelog-$(openssl rand -hex 8)" + { + echo "version=${version}" + echo "major=${major}" + echo "previous_version=${prev_version}" + echo "bump=${bump}" + echo "gonfalon_sha=${gonfalon_sha}" + echo "changelog<<${delimiter}" + cat "${workdir}/unreleased.md" + echo "${delimiter}" + } >> "${GITHUB_OUTPUT}" +fi + +if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then + { + echo "### Release ${version}" + echo + echo "| | |" + echo "|---|---|" + echo "| Previous | \`${prev_version}\` |" + echo "| Bump | ${bump} |" + echo "| gonfalon commit | [\`${gonfalon_sha:0:9}\`](https://github.com/${GONFALON}/commit/${gonfalon_sha}) |" + echo "| Spec blob | \`${prod_blob}\` |" + echo + echo "
Changelog" + echo + cat "${workdir}/unreleased.md" + echo + echo "
" + } >> "${GITHUB_STEP_SUMMARY}" +fi + +note "Preflight passed. Releasing ${version}." diff --git a/scripts/release/publish.sh b/scripts/release/publish.sh index 7adb8cd..7e3aea5 100755 --- a/scripts/release/publish.sh +++ b/scripts/release/publish.sh @@ -9,6 +9,16 @@ echo >>~/.netrc "machine github.com login LaunchDarklyReleaseBot password ${GH_T git config --global user.name LaunchDarklyReleaseBot git config --global user.email launchdarklyreleasebot@launchdarkly.com +if [ "${DRY_RUN:-false}" = "true" ]; then + # Rehearsal: clones and commits for real, but pushes nothing and publishes nothing. + echo Simulating updates to client repositories... + make RELEASE_TARGETS="go java python ruby typescript-axios" TAG=${LD_RELEASE_VERSION} push_dry_run + + echo Simulating publishing of client artifacts... + make PUBLISH_TARGETS="python ruby typescript-axios java" publish_dry_run + exit 0 +fi + # Publish updates to client repositories echo Publishing updates to client repositories... make RELEASE_TARGETS="go java python ruby typescript-axios" TAG=${LD_RELEASE_VERSION} push diff --git a/scripts/release/selfcheck.sh b/scripts/release/selfcheck.sh new file mode 100755 index 0000000..2a4375f --- /dev/null +++ b/scripts/release/selfcheck.sh @@ -0,0 +1,354 @@ +#!/usr/bin/env bash +# +# Static checks over the release automation, runnable locally in seconds. +# +# ./scripts/release/selfcheck.sh +# +# Exists because every failure in this automation so far was discoverable without +# running a release, but nothing was checking for it. Each check below corresponds +# to a defect that actually shipped and cost a dispatch-and-wait cycle: +# +# OIDC a job used octosts-action without id-token: write +# POLICY-PERM the CI gate called an endpoint the trust policy did not permit +# POLICY-MATCH a job_workflow_ref pattern that could never match (unanchored) +# POLICY-REPOS a downstream target missing from the policy's allowlist +# SECRETS a workflow referenced a secret that did not exist +# DRYRUN a make dry-run target that was a silent no-op +# PORTABILITY mapfile / bare sed -i, which break on macOS bash 3.2 +# +# Checks needing the trust policy are SKIPped when it is unreachable (it lives in +# the private launchdarkly/.github-private), so this is useful in CI too, just +# with less coverage. Point POLICY_FILE at a local checkout to get the full set. + +set -uo pipefail + +cd "$(dirname "${BASH_SOURCE[0]}")/../.." || exit 1 + +REPO=launchdarkly/ld-openapi-private +POLICY_REPO=launchdarkly/.github-private +POLICY_PATH=.github/launchdarkly/ld-openapi-downstream.sts.yaml +POLICY_FILE=${POLICY_FILE:-$HOME/code/launchdarkly/.github-private/${POLICY_PATH}} + +# Scripts this automation owns. The per-target publish scripts predate it and +# carry unused-positional-arg warnings that are part of their interface. +OWNED_SCRIPTS=( + scripts/release/preflight.sh + scripts/release/token-audit.sh + scripts/release/verify-published.sh + scripts/release/mirror-public.sh + scripts/release/gonfalon-update.sh + scripts/release/publish.sh + scripts/release/selfcheck.sh +) + +pass=0; fail=0; skip=0 +ok() { echo " PASS $1"; pass=$((pass+1)); } +bad() { echo " FAIL $1"; fail=$((fail+1)); } +nope() { echo " SKIP $1"; skip=$((skip+1)); } + +# Resolve the trust policy: local checkout, else the API, else skip. +# +# Two traps here, both of which have bitten: +# - `|| true` on the fetch keeps a failed request's response body. A GitHub API +# error body is valid YAML, so it parses into a dict with none of the keys the +# checks read, and they then "fail" against something that is not a policy. +# With a token that cannot see the policy repo - CI, for one - that is the +# normal case, not an edge case. +# - so the fetch must respect gh's exit status AND the result must be shape-checked +# before use. Anything that is not recognisably a trust policy means SKIP. +policy="" +policy_problem="" +if [ -f "${POLICY_FILE}" ]; then + policy=$(cat "${POLICY_FILE}") +elif command -v gh >/dev/null 2>&1; then + if fetched=$(gh api "repos/${POLICY_REPO}/contents/${POLICY_PATH}" \ + -H "Accept: application/vnd.github.raw" 2>/dev/null); then + policy="${fetched}" + fi +fi +if [ -n "${policy}" ]; then + for key in subject_pattern claim_pattern permissions repositories; do + grep -qE "^${key}:" <<<"${policy}" || policy_problem="${policy_problem} ${key}" + done + if [ -n "${policy_problem}" ]; then + policy="" + policy_problem="fetched a response that is not a trust policy (missing:${policy_problem})" + fi +fi + +echo "== shellcheck ==" +if command -v shellcheck >/dev/null 2>&1; then + if out=$(shellcheck -S warning "${OWNED_SCRIPTS[@]}" 2>&1); then + ok "no warnings in ${#OWNED_SCRIPTS[@]} owned scripts" + else + bad "shellcheck warnings:" + sed 's/^/ /' <<<"${out}" | head -20 + fi +else + nope "shellcheck not installed" +fi + +echo +echo "== PORTABILITY: constructs that break on macOS bash 3.2 / BSD sed ==" +# This file necessarily contains the patterns it searches for, so exclude it. +port_targets=() +for f in "${OWNED_SCRIPTS[@]}"; do [ "${f}" = "scripts/release/selfcheck.sh" ] || port_targets+=("${f}"); done +port_hits=$(grep -nE '(^|[^-])\bmapfile\b|sed -i +[^.'"'"'"]' "${port_targets[@]}" 2>/dev/null || true) +if [ -z "${port_hits}" ]; then + ok "no mapfile, no bare 'sed -i'" +else + bad "non-portable constructs:" + sed 's/^/ /' <<<"${port_hits}" +fi + +echo +echo "== OIDC: every octosts-action step has id-token: write ==" +oidc=$(python3 - <<'PY' +import yaml, glob, os, sys +problems, checked = [], 0 +wf = {os.path.basename(p): yaml.safe_load(open(p)) for p in glob.glob('.github/workflows/*.yml')} + +def grants(doc, job): + for src in (job.get('permissions'), doc.get('permissions')): + if isinstance(src, dict) and src.get('id-token') == 'write': + return True + return False + +for fname, doc in wf.items(): + for jname, job in (doc.get('jobs') or {}).items(): + uses_sts = any('octosts-action' in str(s.get('uses', '')) for s in (job.get('steps') or [])) + if uses_sts: + checked += 1 + if not grants(doc, job): + problems.append(f"{fname}/{jname} runs octosts-action without id-token: write") + # A reusable-workflow call is capped by the caller's permissions. + called = str(job.get('uses', '')) + if called.startswith('./'): + target = wf.get(os.path.basename(called)) + if target and any( + 'octosts-action' in str(s.get('uses', '')) + for tj in (target.get('jobs') or {}).values() + for s in (tj.get('steps') or []) + ): + checked += 1 + if not grants(doc, job): + problems.append(f"{fname}/{jname} calls {os.path.basename(called)} (which mints a token) without granting id-token: write") +print(f"CHECKED {checked}") +for p in problems: + print(f"PROBLEM {p}") +PY +) +n=$(grep -oE 'CHECKED [0-9]+' <<<"${oidc}" | awk '{print $2}') +# If the raw YAML mentions octosts-action but the parser found no minting job, the +# extractor is broken and a pass would be meaningless. +raw_sts=$(grep -rlc 'octosts-action' .github/workflows/*.yml 2>/dev/null | wc -l | tr -d ' ') +if [ "${n:-0}" = "0" ] && [ "${raw_sts}" != "0" ]; then + bad "workflows reference octosts-action but no token-minting job was detected — the check is broken" +elif grep -q PROBLEM <<<"${oidc}"; then + bad "id-token gaps:" + grep PROBLEM <<<"${oidc}" | sed 's/PROBLEM / /' +else + ok "${n:-0} token-minting job(s), all grant id-token: write" +fi + +echo +echo "== POLICY-MATCH: the trust policy matches this repo's workflows on main ==" +if [ -z "${policy}" ]; then + nope "trust policy unavailable: ${policy_problem:-not found locally and not readable via gh} (set POLICY_FILE, or authenticate gh against ${POLICY_REPO})" +else + match=$(POLICY="${policy}" REPO="${REPO}" python3 - <<'PY' +import os, re, yaml, glob +pol = yaml.safe_load(os.environ['POLICY']); repo = os.environ['REPO'] +# octo-sts compiles claim patterns anchored: regexp.Compile("^" + v + "$") +jr = re.compile("^" + pol['claim_pattern']['job_workflow_ref'] + "$") +sr = re.compile("^" + pol['subject_pattern'] + "$") +problems = [] +if not sr.match(f"repo:{repo}:ref:refs/heads/main"): + problems.append(f"subject_pattern does not match a dispatch on main") +minting = [] +for p in glob.glob('.github/workflows/*.yml'): + doc = yaml.safe_load(open(p)) + if any('octosts-action' in str(s.get('uses','')) + for j in (doc.get('jobs') or {}).values() for s in (j.get('steps') or [])): + minting.append(os.path.basename(p)) +for f in sorted(minting): + claim = f"{repo}/.github/workflows/{f}@refs/heads/main" + if not jr.match(claim): + problems.append(f"job_workflow_ref does not match {claim}") +print(f"CHECKED {len(minting)}") +for p in problems: print("PROBLEM " + p) +PY +) + if grep -q PROBLEM <<<"${match}"; then + bad "policy would deny these:" + grep PROBLEM <<<"${match}" | sed 's/PROBLEM / /' + else + ok "$(grep -oE 'CHECKED [0-9]+' <<<"${match}" | awk '{print $2}') minting workflow(s) match on refs/heads/main" + fi +fi + +echo +echo "== POLICY-PERM: the policy permits every gonfalon endpoint preflight calls ==" +if [ -z "${policy}" ]; then + nope "trust policy unavailable${policy_problem:+: ${policy_problem}}" +else + # Endpoint -> required GitHub App permission. Hand-maintained; extend it when a + # new endpoint is called. This is the check that catches a 403 before CI does. + perm=$(POLICY="${policy}" python3 - <<'PY' +import os, re, yaml +pol = yaml.safe_load(os.environ['POLICY']) +granted = pol.get('permissions') or {} +RULES = [ + (r'/commits/[^/"]+/status', 'statuses'), + (r'/commits/[^/"]+/check-runs', 'checks'), + (r'/git/trees/', 'contents'), + (r'/contents/', 'contents'), + (r'/commits\?path=', 'contents'), # list commits touching a path + (r'/commits/main', 'contents'), +] +src = open('scripts/release/preflight.sh').read() +# Join backslash line-continuations first. Without this, a call whose URL sits on +# the next line is invisible to the extractor — so it is neither validated nor +# reported as unrecognised, which is precisely the silent gap this table exists to +# close. One such call shipped before this was fixed. +src = re.sub(r'\\\n\s*', ' ', src) +# Only calls routed through the gonfalon token are governed by this policy. +calls = re.findall(r'gh_gonfalon api\s+"([^"]+)"', src) +if not calls: + print("PROBLEM found no gh_gonfalon calls at all — the extractor is broken") +problems, seen = [], set() +for c in calls: + for pattern, need in RULES: + if re.search(pattern, c): + seen.add(need) + if need not in granted: + problems.append(f"{c} needs '{need}' but the policy grants: {sorted(granted)}") + break + else: + problems.append(f"{c} is not in selfcheck's endpoint->permission table; add it") +print(f"CHECKED {len(calls)} call(s), permissions needed: {sorted(seen)}") +for p in sorted(set(problems)): print("PROBLEM " + p) +PY +) + echo " $(grep -oE 'CHECKED.*' <<<"${perm}")" + if grep -q PROBLEM <<<"${perm}"; then + bad "permission gaps:" + grep PROBLEM <<<"${perm}" | sed 's/PROBLEM / /' + else + ok "every gonfalon endpoint is covered by the policy's permissions" + fi +fi + +echo +echo "== POLICY-REPOS: every downstream target is in the policy allowlist ==" +if [ -z "${policy}" ]; then + nope "trust policy unavailable${policy_problem:+: ${policy_problem}}" +else + targets=$(grep -oE 'repository: launchdarkly/[a-z0-9._-]+' .github/workflows/release.yml | awk '{print $2}' | sort -u) + allowed=$(POLICY="${policy}" python3 -c " +import os, yaml +print('\n'.join('launchdarkly/' + r for r in (yaml.safe_load(os.environ['POLICY']).get('repositories') or [])))") + missing="" + for t in ${targets}; do grep -qxF "${t}" <<<"${allowed}" || missing="${missing} ${t}"; done + if [ -z "${targets}" ]; then + bad "found no pr-downstream targets in release.yml — the extraction is broken" + elif [ -n "${missing}" ]; then + bad "pr-downstream targets absent from the policy's repositories:${missing}" + else + ok "all pr-downstream targets allowed ($(tr '\n' ' ' <<<"${targets}"))" + fi +fi + +echo +echo "== SECRETS: every secret the workflows reference exists on the repo ==" +if command -v gh >/dev/null 2>&1 && actual=$(gh api "repos/${REPO}/actions/secrets" --jq '.secrets[].name' 2>/dev/null) && [ -n "${actual}" ]; then + referenced=$(grep -rhoE 'secrets\.[A-Z0-9_]+' .github/workflows/ | cut -d. -f2 | sort -u) + missing="" + for s in ${referenced}; do + [ "${s}" = "GITHUB_TOKEN" ] && continue + grep -qxF "${s}" <<<"${actual}" || missing="${missing} ${s}" + done + if [ -n "${missing}" ]; then + bad "referenced but not present as repo secrets (may be org-level — verify):${missing}" + else + ok "all referenced secrets exist ($(tr '\n' ' ' <<<"${referenced}"))" + fi +else + nope "cannot list repo secrets (needs gh auth with admin on ${REPO})" +fi + +echo +echo "== ACTION-INPUTS: every input passed to a pinned action actually exists ==" +# A workflow passing an input the action does not declare gets only a warning, which +# nobody reads, and the value is silently ignored. `dryrun: ${{ inputs.dryRun }}` was +# passed to a pinned pr-downstream that has no such input, so rehearsals were +# attempting real PR creation. +if command -v gh >/dev/null 2>&1; then + ai=$(python3 - <<'PYEOF' +import yaml, glob, os, re, subprocess, sys +problems, checked, unresolved = [], 0, [] +for path in glob.glob('.github/workflows/*.yml'): + doc = yaml.safe_load(open(path)) + for jname, job in (doc.get('jobs') or {}).items(): + for step in (job.get('steps') or []): + uses, with_ = str(step.get('uses','')), (step.get('with') or {}) + # Only third-party actions pinned to a ref we can resolve. + if not with_ or '@' not in uses or uses.startswith('./'): + continue + repo, ref = uses.rsplit('@', 1) + if repo.count('/') != 1: + continue + try: + raw = subprocess.run( + ['gh','api',f'repos/{repo}/contents/action.yml?ref={ref}', + '-H','Accept: application/vnd.github.raw'], + capture_output=True, text=True, timeout=25) + if raw.returncode != 0 or not raw.stdout.strip(): + unresolved.append(f"{repo}@{ref[:12]}") + continue + declared = set((yaml.safe_load(raw.stdout).get('inputs') or {}).keys()) + except Exception: + unresolved.append(f"{repo}@{ref[:12]}") + continue + checked += 1 + for k in with_: + if k not in declared: + problems.append(f"{os.path.basename(path)}/{jname}: '{k}' is not an input of {repo}@{ref[:12]}") +print(f"CHECKED {checked}") +print(f"UNRESOLVED {len(set(unresolved))} {' '.join(sorted(set(unresolved)))}".rstrip()) +for p in sorted(set(problems)): print("PROBLEM " + p) +PYEOF +) + echo " $(grep -oE 'CHECKED [0-9]+' <<<"${ai}") pinned action(s) with inputs" + unresolved=$(grep -oE 'UNRESOLVED [0-9]+.*' <<<"${ai}" | cut -d' ' -f2-) + if grep -q PROBLEM <<<"${ai}"; then + bad "inputs that will be silently ignored:" + grep PROBLEM <<<"${ai}" | sed 's/PROBLEM / /' + elif grep -q 'CHECKED 0' <<<"${ai}"; then + # Passing here would be false assurance: it verified nothing. Needs a token + # with read access to the action repos (GITHUB_TOKEN suffices; they are public). + nope "resolved no pinned actions at all, so nothing was verified${unresolved:+ (unresolved: ${unresolved#* })}" + elif [ "${unresolved%% *}" != "0" ]; then + nope "some pinned actions could not be resolved and were not verified: ${unresolved#* }" + else + ok "all inputs passed to pinned actions are declared by them" + fi +else + nope "cannot resolve pinned actions (gh not available)" +fi + +echo +echo "== DRYRUN: rehearsal make targets are not silent no-ops ==" +for target in push_dry_run publish_dry_run; do + out=$(make -n "${target}" 2>&1 || true) + if grep -qi "nothing to be done" <<<"${out}" || [ -z "${out}" ]; then + bad "make ${target} does nothing — it needs a recipe or a prerequisite" + else + ok "make ${target} expands to $(wc -l <<<"${out}" | tr -d ' ') line(s) of recipe" + fi +done + +echo +echo "-----" +echo "PASS ${pass} FAIL ${fail} SKIP ${skip}" +[ "${fail}" -eq 0 ] || exit 1 diff --git a/scripts/release/token-audit.sh b/scripts/release/token-audit.sh new file mode 100755 index 0000000..b152db3 --- /dev/null +++ b/scripts/release/token-audit.sh @@ -0,0 +1,247 @@ +#!/usr/bin/env bash +# +# Read-only audit of every credential the release needs. Makes no changes: only +# GETs and whoami-style calls, so it is safe to run any time. +# +# A dry run cannot answer "do the tokens have the right permissions?" on its own. +# It skips create-release entirely, pr-downstream skips PR creation, and the +# publish dry-run scripts never authenticate to any registry. This closes that +# gap by asking each provider directly. +# +# Exits non-zero if a required GitHub permission is missing or a verifiable +# registry credential is rejected. Credentials with no read-only verification +# path are reported as UNVERIFIED rather than silently passed. +# +# Secrets are read from the environment and never printed. + +set -uo pipefail + +# Set to false when the corresponding job is switched off for this run, so a +# missing credential cannot block a release that was never going to use it. This +# also lets the flow be rehearsed before those tokens exist. +REQUIRE_MIRROR_TOKEN=${REQUIRE_MIRROR_TOKEN:-true} +REQUIRE_DOWNSTREAM_TOKEN=${REQUIRE_DOWNSTREAM_TOKEN:-true} + +pass=(); fail=(); unverified=(); skipped=() + +ok() { echo " PASS $1"; pass+=("$1"); } +bad() { echo " FAIL $1"; fail+=("$1"); } +unver() { echo " UNVERIFIED $1"; unverified+=("$1"); } +skip() { echo " SKIP $1"; skipped+=("$1"); } + +# --- GitHub tokens ----------------------------------------------------------- +# `.permissions` on the repo endpoint reflects what THIS token can do, so it +# answers the push/read question without writing anything. +check_repo_perm() { + local label=$1 token=$2 repo=$3 needed=$4 + + if [ -z "${token}" ]; then + bad "${label}: secret is not set (needs ${needed} on ${repo})" + return + fi + + # Terraform creates these SSM parameters holding a placeholder, so between the + # first apply and someone writing the real value there is a window where the + # secret exists but is the literal placeholder. Say so, rather than reporting + # an opaque "Bad credentials". + if [ "${token}" = "SET_IN_PARAMETER_STORE" ]; then + bad "${label}: still holds the terraform placeholder. Write the real value to its SSM parameter, then re-apply terraform so the secret picks it up." + return + fi + + local body + if ! body=$(GH_TOKEN="${token}" gh api "repos/${repo}" 2>&1); then + if grep -qi "404\|not found" <<<"${body}"; then + bad "${label}: cannot see ${repo} at all — token lacks access or repo is wrong (needs ${needed})" + else + bad "${label}: error reading ${repo} — $(head -1 <<<"${body}")" + fi + return + fi + + local granted + granted=$(jq -r '.permissions // {} | to_entries | map(select(.value)) | map(.key) | join(",")' <<<"${body}") + + if [ "${needed}" = "pull" ]; then + # Any successful read satisfies a read requirement. + ok "${label}: can read ${repo} (granted: ${granted:-read})" + elif jq -e --arg p "${needed}" '.permissions[$p] == true' <<<"${body}" >/dev/null 2>&1; then + ok "${label}: has ${needed} on ${repo} (granted: ${granted})" + else + bad "${label}: missing ${needed} on ${repo} (granted: ${granted:-none})" + fi +} + +echo "== GitHub: BOT_TOKEN ==" +echo " used by: preflight tag checks, publish.sh push, create-release, mirror-public" +for repo in api-client-go api-client-java api-client-python api-client-ruby api-client-typescript; do + # push also covers creating tags and GitHub releases, which create-release needs. + check_repo_perm "BOT_TOKEN" "${BOT_TOKEN:-}" "launchdarkly/${repo}" "push" +done + +echo +echo "== OctoSTS federated token ==" +echo " minted from the ld-openapi-downstream trust policy in launchdarkly/.github-private" +echo " used by: preflight (reads gonfalon's spec blob, CI status, changelog)" +echo " downstream-gonfalon and downstream-terraform-provider (branch + PR)" +# There is no stored secret to inspect here. What can go wrong is the federation +# itself: a policy that does not match, or a repo missing from its `repositories` +# allowlist. Checked via /installation/repositories, which enumerates exactly what +# the minted token is scoped to. +# +# NOT via `.permissions` on the repo endpoint: that field reports a *user's* role +# (push/pull/admin), and an App installation token has no role, only granular +# permissions — so it always reads as empty and every check would fail. +if [ -z "${STS_TOKEN:-}" ]; then + bad "OctoSTS: no federated token was minted. Check the octosts-action step and that .github/launchdarkly/ld-openapi-downstream.sts.yaml in launchdarkly/.github-private matches this workflow." +else + required=(launchdarkly/gonfalon) + if [ "${REQUIRE_DOWNSTREAM_TOKEN}" = "true" ]; then + required+=(launchdarkly/terraform-provider-launchdarkly) + else + skip "OctoSTS token on terraform-provider-launchdarkly: downstream PRs are disabled for this run" + fi + + if scoped=$(GH_TOKEN="${STS_TOKEN}" gh api /installation/repositories --paginate --jq '.repositories[].full_name' 2>/dev/null) && [ -n "${scoped}" ]; then + for repo in "${required[@]}"; do + if grep -qxF "${repo}" <<<"${scoped}"; then + ok "OctoSTS token is scoped to ${repo}" + else + bad "OctoSTS token cannot reach ${repo} — add it to the policy's 'repositories' list. In scope: $(paste -sd, - <<<"${scoped}")" + fi + done + # An installation token's permission set cannot be introspected over the API, + # so contents/pull_requests write is only proven when a PR is actually opened. + unver "OctoSTS token: permission level (contents and pull_requests write) cannot be read back; it is proven only when a downstream PR is opened" + else + # Fall back to reachability if that endpoint is unavailable — still catches a + # repo missing from the allowlist, which is the common failure. + for repo in "${required[@]}"; do + if GH_TOKEN="${STS_TOKEN}" gh api "repos/${repo}" >/dev/null 2>&1; then + ok "OctoSTS token can reach ${repo}" + else + bad "OctoSTS token cannot reach ${repo} — check the policy's 'repositories' list" + fi + done + unver "OctoSTS token: could not enumerate scope via /installation/repositories; fell back to per-repo reachability" + fi +fi + +echo +echo "== GitHub: BOT_TOKEN on the public mirror target ==" +echo " used by: mirror-public (squash push to launchdarkly/ld-openapi)" +if [ "${REQUIRE_MIRROR_TOKEN}" = "true" ]; then + check_repo_perm "BOT_TOKEN" "${BOT_TOKEN:-}" "launchdarkly/ld-openapi" "push" +else + skip "BOT_TOKEN on launchdarkly/ld-openapi: mirroring is disabled for this run" +fi + +# --- Registries --------------------------------------------------------------- +echo +echo "== Registries ==" + +if [ -z "${NPM_TOKEN:-}" ]; then + bad "NPM_TOKEN: secret is not set" +elif user=$(curl -s -f -H "Authorization: Bearer ${NPM_TOKEN}" https://registry.npmjs.org/-/whoami | jq -r '.username' 2>/dev/null) && [ -n "${user}" ]; then + ok "NPM_TOKEN: authenticates as ${user}" +else + bad "NPM_TOKEN: rejected by registry.npmjs.org/-/whoami" +fi + +# RubyGems API keys are scoped. A key scoped to push_rubygem — all that releasing +# needs, and the right level of privilege — is rejected by the profile endpoint, +# so a read check there says nothing useful about whether the key can publish. +# There is no read-only endpoint a push-only key can pass, so don't pretend. +if [ -n "${RUBYGEM_API_KEY:-}" ]; then + code=$(curl -s -o /dev/null -w '%{http_code}' -H "Authorization: ${RUBYGEM_API_KEY}" \ + https://rubygems.org/api/v1/profile/me.json || echo 000) + if [ "${code}" = "200" ]; then + ok "RUBYGEM_API_KEY: authenticates (profile readable, so the key is broadly scoped)" + else + unver "RUBYGEM_API_KEY: set; profile endpoint returned HTTP ${code}, which is expected for a push-only scoped key and does not indicate a problem" + fi +else + bad "RUBYGEM_API_KEY: secret is not set" +fi + +# PyPI has no read-only token introspection endpoint; the only way to exercise an +# upload token is to upload. Presence is all we can assert. +if [ -n "${PYPI_TOKEN:-}" ]; then + unver "PYPI_TOKEN: set, but PyPI offers no read-only way to validate an upload token" +else + bad "PYPI_TOKEN: secret is not set" +fi + +if [ -n "${CENTRAL_PORTAL_USERNAME:-}" ] && [ -n "${CENTRAL_PORTAL_PASSWORD:-}" ]; then + bearer=$(printf '%s:%s' "${CENTRAL_PORTAL_USERNAME}" "${CENTRAL_PORTAL_PASSWORD}" | base64 | tr -d '\n') + code=$(curl -s -o /dev/null -w '%{http_code}' -X POST \ + -H "Authorization: Bearer ${bearer}" \ + 'https://central.sonatype.com/api/v1/publisher/deployments?size=1' || echo 000) + case "${code}" in + 200) ok "CENTRAL_PORTAL_*: authenticates to central.sonatype.com" ;; + 401|403) bad "CENTRAL_PORTAL_*: rejected by central.sonatype.com (HTTP ${code})" ;; + # Anything else means the request shape was wrong, not the credentials. The + # portal has no documented whoami, so this is best-effort only. + *) unver "CENTRAL_PORTAL_*: set; portal returned HTTP ${code} to a best-effort probe, which reflects the probe rather than the credentials" ;; + esac +else + bad "CENTRAL_PORTAL_USERNAME/PASSWORD: not set" +fi + +# --- LD API key used by the CI sample programs -------------------------------- +echo +echo "== LaunchDarkly API ==" +echo " used by: ci.yml sample programs (create + delete a flag in the 'openapi' project)" +if [ -z "${LD_API_KEY:-}" ]; then + bad "LD_API_KEY: secret is not set" +else + code=$(curl -s -o /dev/null -w '%{http_code}' \ + -H "Authorization: ${LD_API_KEY}" \ + https://app.launchdarkly.com/api/v2/projects/openapi || echo 000) + case "${code}" in + 200) ok "LD_API_KEY: can read the 'openapi' project" ;; + 401) bad "LD_API_KEY: unauthorized" ;; + 403) bad "LD_API_KEY: forbidden on the 'openapi' project" ;; + 404) bad "LD_API_KEY: the 'openapi' project is not visible to this token" ;; + *) unver "LD_API_KEY: HTTP ${code} from the projects endpoint" ;; + esac + # The samples create and delete flags; a read-only token passes the check above + # but fails in CI, so flag that this audit cannot prove write access. + unver "LD_API_KEY: write access (samples create/delete flags) cannot be checked without writing" +fi + +# --- Report ------------------------------------------------------------------- +summary() { + echo "### Token audit" + echo + echo "| Result | Count |" + echo "|---|---|" + echo "| PASS | ${#pass[@]} |" + echo "| FAIL | ${#fail[@]} |" + echo "| UNVERIFIED | ${#unverified[@]} |" + echo "| SKIP | ${#skipped[@]} |" + if [ ${#fail[@]} -gt 0 ]; then + echo + echo "**Failures**" + printf -- '- %s\n' "${fail[@]}" + fi + if [ ${#unverified[@]} -gt 0 ]; then + echo + echo "**Unverified** (no read-only check exists; these can only fail at publish time)" + printf -- '- %s\n' "${unverified[@]}" + fi +} + +echo +echo "-----" +echo "PASS ${#pass[@]} FAIL ${#fail[@]} UNVERIFIED ${#unverified[@]} SKIP ${#skipped[@]}" +[ -n "${GITHUB_STEP_SUMMARY:-}" ] && summary >> "${GITHUB_STEP_SUMMARY}" + +if [ ${#fail[@]} -gt 0 ]; then + echo + echo "Credentials needing attention:" >&2 + printf ' %s\n' "${fail[@]}" >&2 + exit 1 +fi + +echo "All checkable credentials are good." diff --git a/scripts/release/verify-published.sh b/scripts/release/verify-published.sh new file mode 100755 index 0000000..e832f99 --- /dev/null +++ b/scripts/release/verify-published.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +# +# Runbook step 9: verify the release actually landed everywhere, instead of +# trusting that someone remembered to spot-check a repo. +# +# Usage: verify-published.sh VERSION +# +# Hard checks fail the job. Soft checks only warn: Maven Central's sync from the +# publishing portal to repo1 can lag well past a sensible CI timeout, so a miss +# there means "check later", not "the release is broken". + +set -euo pipefail + +version=${1:?usage: verify-published.sh VERSION} +major=${version%%.*} + +POLL_TIMEOUT=${POLL_TIMEOUT:-600} +POLL_INTERVAL=${POLL_INTERVAL:-20} + +failures=() +warnings=() + +# poll NAME MODE URL +# MODE is "hard" or "soft". +poll() { + local name=$1 mode=$2 url=$3 + local deadline=$(( $(date +%s) + POLL_TIMEOUT )) + + echo "==> ${name}" + while :; do + local code + code=$(curl -s -o /dev/null -L -w '%{http_code}' "${url}" || echo 000) + if [ "${code}" = "200" ]; then + echo " published (${url})" + return 0 + fi + + if [ "$(date +%s)" -ge "${deadline}" ]; then + if [ "${mode}" = "hard" ]; then + failures+=("${name} — last HTTP ${code} from ${url}") + echo " NOT FOUND after ${POLL_TIMEOUT}s (HTTP ${code})" + else + warnings+=("${name} — not visible yet (HTTP ${code}); registry sync may still be in flight") + echo " not visible yet (HTTP ${code}) — soft check, continuing" + fi + return 0 + fi + sleep "${POLL_INTERVAL}" + done +} + +poll "PyPI launchdarkly-api" hard "https://pypi.org/pypi/launchdarkly-api/${version}/json" +poll "RubyGems launchdarkly_api" hard "https://rubygems.org/api/v2/rubygems/launchdarkly_api/versions/${version}.json" +poll "npm launchdarkly-api-typescript" hard "https://registry.npmjs.org/launchdarkly-api-typescript/${version}" +# Soft, deliberately. Go has no publish step — the git tag IS the release, and the +# tag is checked below. proxy.golang.org is a demand-populated cache that also +# caches negative lookups, so a `go get` for the version before it existed (a dry +# run, say) makes it serve "unknown revision" for a while afterwards. That happened +# on 24.0.0 and failed this job on an otherwise complete release. +poll "Go module proxy api-client-go/v${major}" soft "https://proxy.golang.org/github.com/launchdarkly/api-client-go/v${major}/@v/v${version}.info" +poll "Maven Central com.launchdarkly:api-client" soft "https://repo1.maven.org/maven2/com/launchdarkly/api-client/${version}/api-client-${version}.pom" + +# Tags on the client repos, checking only what exists at THIS point in the graph. +# `make push` tags Go as v but the other four as a bare ; their +# v tag is created later, by the create-release job, which runs after +# this one. Checking v everywhere would fail four repos on every healthy +# release and stop the run before create-release ever got the chance. +echo "==> client repo tags" +for repo in api-client-go api-client-java api-client-python api-client-ruby api-client-typescript; do + if [ "${repo}" = "api-client-go" ]; then ref="v${version}"; else ref="${version}"; fi + if gh api "repos/launchdarkly/${repo}/git/ref/tags/${ref}" >/dev/null 2>&1; then + echo " launchdarkly/${repo} ${ref}" + else + failures+=("launchdarkly/${repo} has no ${ref} tag") + echo " launchdarkly/${repo} MISSING ${ref}" + fi +done + +if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then + { + echo "### Publish verification for ${version}" + if [ ${#failures[@]} -eq 0 ]; then + echo + echo "All hard checks passed." + else + echo + echo "**Failures**" + printf -- '- %s\n' "${failures[@]}" + fi + if [ ${#warnings[@]} -gt 0 ]; then + echo + echo "**Warnings**" + printf -- '- %s\n' "${warnings[@]}" + fi + } >> "${GITHUB_STEP_SUMMARY}" +fi + +if [ ${#warnings[@]} -gt 0 ]; then + printf 'WARNING: %s\n' "${warnings[@]}" >&2 +fi + +if [ ${#failures[@]} -gt 0 ]; then + printf 'FAILED: %s\n' "${failures[@]}" >&2 + echo >&2 + echo "Re-running the release requires deleting the tags it already created (both X.Y.Z and vX.Y.Z on non-Go repos) or dispatching with force=true." >&2 + exit 1 +fi + +echo "All hard checks passed for ${version}." diff --git a/swagger-codegen-templates/javascript/package.mustache b/swagger-codegen-templates/javascript/package.mustache deleted file mode 100644 index 1e3e1f6..0000000 --- a/swagger-codegen-templates/javascript/package.mustache +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "{{{projectName}}}", - "version": "{{{projectVersion}}}", - "description": "{{{projectDescription}}}", - "license": "{{licenseName}}", - "main": "dist{{#invokerPackage}}/{{.}}{{/invokerPackage}}/index.js", - "scripts": { - "build": "babel src -d dist", - "prepare": "npm run build", - "test": "mocha --require @babel/register --recursive" - }, - "browser": { - "fs": false - }, -{{#npmRepository}} - "publishConfig":{ - "registry":"{{npmRepository}}" - }, -{{/npmRepository}} - "dependencies": { - "@babel/cli": "^7.0.0", - "superagent": "^10.0.0" - }, - "devDependencies": { - "@babel/core": "^7.0.0", - "@babel/plugin-proposal-class-properties": "^7.0.0", - "@babel/plugin-proposal-decorators": "^7.0.0", - "@babel/plugin-proposal-do-expressions": "^7.0.0", - "@babel/plugin-proposal-export-default-from": "^7.0.0", - "@babel/plugin-proposal-export-namespace-from": "^7.0.0", - "@babel/plugin-proposal-function-bind": "^7.0.0", - "@babel/plugin-proposal-function-sent": "^7.0.0", - "@babel/plugin-proposal-json-strings": "^7.0.0", - "@babel/plugin-proposal-logical-assignment-operators": "^7.0.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", - "@babel/plugin-proposal-numeric-separator": "^7.0.0", - "@babel/plugin-proposal-optional-chaining": "^7.0.0", - "@babel/plugin-proposal-pipeline-operator": "^7.0.0", - "@babel/plugin-proposal-throw-expressions": "^7.0.0", - "@babel/plugin-syntax-dynamic-import": "^7.0.0", - "@babel/plugin-syntax-import-meta": "^7.0.0", - "@babel/preset-env": "^7.0.0", - "@babel/register": "^7.0.0", - "expect.js": "^0.3.1", - "mocha": "^8.0.1", - "sinon": "^7.2.0" - }, - "files": [ - "dist" - ] -} -