Skip to content

build: bump speakeasy-core to capture the registry license token - #2117

Merged
ThomasRooney merged 4 commits into
mainfrom
feat/license-token-context
Aug 24, 2026
Merged

build: bump speakeasy-core to capture the registry license token#2117
ThomasRooney merged 4 commits into
mainfrom
feat/license-token-context

Conversation

@ThomasRooney

@ThomasRooney ThomasRooney commented Aug 18, 2026

Copy link
Copy Markdown
Member

Why

The registry now returns license_jwt on /v1/auth/validate — a registry-signed Ed25519 JWT proving commercial generation entitlement (speakeasy-api/speakeasy-registry#4702, live in prod). The open-source generator validates it offline (speakeasy-api/openapi-generation#55). Step 1 for the CLI is simply to stop dropping the token on the floor.

What

  • Bump speakeasy-core to v0.23.0 (speakeasy-api/speakeasy-core#157, released) and speakeasy-client-sdk-go to v3.27.0. Core tees license_jwt out of the validate response into the auth context (auth.GetLicenseTokenFromContext), because the pinned client SDK predates the field and its decoder drops unknown JSON.
  • No behaviour change in this PR. Commercial-vs-AGPL is still decided by sdkgen.withGenerationContext from the access check, exactly as today.

Follow-up (the meaningful change)

Once #55 tags: in sdkgen.withGenerationContext, when generation is allowed and a token is present, attach it with licensetoken.WithToken(ctx, tok) instead of pre-synthesising commercial AuthenticatedInfo — so the generator's validator establishes commercial output and the CLI stops being a path around the check. Also cache the token as the offline license file (30-day TTL). That PR also has to absorb the pre-existing internal/schemas breakage against generator ≥ v2.932.1 (unrelated to licensing, blocks any generator bump today).

Sequencing

speakeasy-core#157 → this → openapi-generation#55 → CLI follow-up.

Testing

go build ./...; go test ./internal/sdkgen/ ./internal/run/ green.


Summary by cubic

Captures the registry license_jwt from /v1/auth/validate in the auth context. Previously the CLI dropped this token; now it’s stored for later use. Behavior is unchanged and generation gating still follows the existing access check.

  • Pin speakeasy-core v0.23.0 (tees the token into context via auth.GetLicenseTokenFromContext) and speakeasy-client-sdk-go/v3 v3.27.0 (adds typed LicenseJwt); merged main and re-resolved deps while keeping these pins.
  • Bump github.com/stretchr/testify to v1.12.1; add indirect go.yaml.in/yaml/v3 v3.0.5 and github.com/spyzhov/ajson v0.8.0; remove indirect github.com/davecgh/go-spew.
  • No behavior or config changes; no migration required.
  • Follow-up: pass the token to the generator via licensetoken.WithToken so the generator validates commercial output and cache it for offline use.

Written for commit 81ecf8d. Summary will update on new commits.

Review in cubic

/v1/auth/validate now returns license_jwt (speakeasy-registry#4702). Core
tees it into the auth context (speakeasy-core#157); the CLI does not yet
act on it. Follow-up wires it through to the generator via
licensetoken.WithToken once openapi-generation#55 is released — that is
the change that makes the generator, not the CLI, decide commercial
output.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 2 files

Re-trigger cubic

…k-go

Pseudo-versions pending tags: speakeasy-core#157, speakeasy-client-sdk-go#50.
Replaces the pseudo-version pins now that speakeasy-core#157 is released.
testify moves to 1.12.1 as the SDK's transitive minimum.

Claude-Session: https://claude.ai/code/session_01DkiJPLbxuA3XKkK4bb7KcA
@ThomasRooney
ThomasRooney marked this pull request as ready for review August 24, 2026 12:34
…k-go v3.27.0 pins

go.mod/go.sum resolved on main's dependency set (openapi-generation v2.932.10,
openapi v1.25.0, sdk-gen-config v1.58.0) with the two license-token pins
re-applied; testify resolves to 1.12.1 as the SDK's transitive minimum.

Claude-Session: https://claude.ai/code/session_01DkiJPLbxuA3XKkK4bb7KcA
@ThomasRooney
ThomasRooney merged commit 5c2f293 into main Aug 24, 2026
12 of 14 checks passed
@ThomasRooney
ThomasRooney deleted the feat/license-token-context branch August 24, 2026 13:20
ThomasRooney pushed a commit that referenced this pull request Aug 24, 2026
… auth (#2120)

## Why

CLI **v1.795.2** breaks `speakeasy tag promote` for customers using
registry tagging in CI (reported by Unkey):

```
Error: {"message":"err_unauthorized: unauthorized -- bearer token missing","status_code":403}
Error: failed to tag registry images: error running speakeasy tag: ... speakeasy tag promote
```

**This is not a security exposure** — the server still enforces auth
(`MustHaveConsistentWorkspaceIDClaimHTTP`). It's a spec/codegen defect:
the client stopped *sending* credentials.

`v1.795.1..v1.795.2` changes only `go.mod`/`go.sum`, and the operative
line is `speakeasy-client-sdk-go/v3 v3.26.7 -> v3.27.0`.

## What broke

v3.27.0 was the first regeneration of that SDK since 2025-05-06. It
picked up a registry spec defect live since March:
`openapi_artifacts.yaml` and `openapi_subscriptions.yaml` declare no
top-level `security`, so once `speakeasy merge` began pushing global
security down onto individual operations (#1952, registry#4559), their
13 operations composed as `security: []`.

The generated SDK therefore dropped `utils.PopulateSecurity` from **all
11 Artifacts and both Subscriptions operations**.

Verified against a local test server, identical calling code:

| Operation | v3.26.7 | v3.27.0 |
|---|---|---|
| `Artifacts.PostTags` | `X-Api-Key` sent | **no auth header** |
| `Artifacts.GetRevisions` | `X-Api-Key` sent | **no auth header** |
| `Workspaces.Get` (control) | `X-Api-Key` sent | `X-Api-Key` sent |

Affected CLI paths: `registry/tagging.go` -> `Artifacts.PostTags`
(powers `tag promote`, `tag apply`, `ci tag`) and
`internal/remote/sources.go:153` -> `Artifacts.GetRevisions`.

This went unnoticed for five months because the other consumers (webapp,
admin SDK) authenticate via `credentials: 'include'` cookies, so a
missing security parameter is invisible to them. The
header-authenticated public Go SDK was frozen by a broken regen since
May 2025 — so it kept shipping correct pre-March code until now.

## Why revert rather than fix forward

- Customers tracking `speakeasyVersion: latest` pick this up
automatically; the breakage is spreading.
- The real fix spans three repos (registry spec -> SDK regen -> CLI
bump) and can't land quickly.
- #2117 was explicit groundwork — "No behaviour change in this PR" — and
what it enables (openapi-generation#55) is **still open**, so this gives
up no live functionality.

## Verification

- `go build ./...` — clean
- `go test ./registry/... ./pkg/merge/...` — pass
- Resolved deps back to `client-sdk-go v3.26.7` / `speakeasy-core
v0.22.2`; all 11 `PopulateSecurity` calls restored

## Follow-up

1. Cut **v1.795.3** — the revert only helps once released.
2. Add top-level `security` to `openapi_artifacts.yaml` +
`openapi_subscriptions.yaml` in speakeasy-registry. `openapi_admin.yaml`
has the same defect (36 ops, no impact today).
3. Re-land #2117 on a fixed v3.27.1.
4. Consider a warning in `pkg/merge` when `setExplicitNoSecurity` marks
operations unsecured — it silently performs a security-downgrading
transform, which is what let this ship.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
ThomasRooney added a commit that referenced this pull request Aug 25, 2026
…and regression coverage

Re-does #2117 (reverted in #2120): speakeasy-core v0.23.0 to capture the
registry license token, and speakeasy-client-sdk-go v3.27.1 which
restores auth on the artifacts/subscriptions operations that v3.27.0
silently dropped (generated from a composed spec that marked them
'security: []'; fixed at the source in speakeasy-registry#4707 and
regenerated in speakeasy-client-sdk-go#51). Pinned to a v3.27.1
pseudo-version until the tag exists.

Why nothing caught it last time: the SDK regression left every method
signature unchanged — utils.PopulateSecurity simply vanished from those
operations, so builds stayed green and the requests went out with no
x-api-key. Registry e2e tests push/pull via oras/ocicommon credentials
and never touch the generated SDK, and the only SDK callsites
(registry/tagging.go PostTags, internal/remote/sources.go GetRevisions —
which swallows errors) had no coverage.

Two new guards:
- internal/sdk/sdk_test.go: hermetic contract test asserting the
  x-api-key header is sent on Artifacts.PostTags and
  Artifacts.GetRevisions (verified to fail against v3.27.0).
- integration/workflow_registry_test.go: TestRegistryFlow now finishes
  with 'speakeasy tag promote', exercising the platform-API auth path
  end-to-end (passes in 30s against prod).
ThomasRooney added a commit that referenced this pull request Aug 26, 2026
…+ regression coverage (#2121)

## Summary

Re-does #2117 (reverted in #2120 after it broke registry auth for
customers as v1.795.2):

- `speakeasy-core` v0.22.2 → **v0.23.0** — captures the registry license
token (the original point of #2117).
- `speakeasy-client-sdk-go/v3` v3.26.7 → **v3.28.0** — v3.27.0 was
generated from a composed spec that marked all 13
artifacts/subscriptions operations `security: []`, so
`utils.PopulateSecurity` vanished from them and every `tag promote`/`tag
apply`/`ci tag` went out without `x-api-key` → 403s. Fixed at the source
(speakeasy-registry#4707: fragments now all declare the same top-level
security, so merge keeps the global block; #4705 typed the
`target_resource` enum) and regenerated from the registry-published spec
(speakeasy-client-sdk-go#52, tagged v3.28.0). `PopulateSecurity` is back
on all 11 Artifacts + 2 Subscriptions operations; the only operations
without auth are the three that are public by design (`getAccessToken`,
`handleCheckoutCallback`, `handleStripeWebhook`). No SDK signature
changes vs v3.26.7.

## Why no test caught it last time

The regression changed no method signatures — auth just silently
disappeared from the requests, so builds and CI stayed green. Registry
e2e tests (`TestRegistryFlow` etc.) push/pull via **oras/ocicommon**
credentials and never touch the generated SDK; the only SDK-auth
callsites are `registry/tagging.go` (`Artifacts.PostTags`) and
`internal/remote/sources.go` (`Artifacts.GetRevisions`, which swallows
errors entirely) — neither had coverage, and there wasn't a single
`httptest` server in the repo to assert outbound headers. `release.yml`
runs no tests at all.

## New regression guards

1. **`internal/sdk/sdk_test.go`** — hermetic contract test: `httptest`
server + `InitSDKWithKey`, asserts the `x-api-key` header is present on
`Artifacts.PostTags` and `Artifacts.GetRevisions` requests. **Verified
to fail against v3.27.0** (header absent) and pass against v3.26.7 /
v3.28.0. Catches any future SDK bump that drops auth, at unit-test speed
with no credentials needed.
2. **`integration/workflow_registry_test.go`** — `TestRegistryFlow` now
ends with `speakeasy tag promote -s test-source -t e2e-test`, exercising
the platform-API (SDK) auth path end-to-end alongside the existing oras
push/pull. Runs on every PR via `validate.yml` (`SPEAKEASY_API_KEY`).
With v3.27.0 this step 403s.

Possible follow-up (out of scope here): a `pkg/merge` warning when
`setExplicitNoSecurity` stamps `security: []` onto operations, so
composed-spec consumers notice before an SDK regen does.

## Verification (at v3.28.0)

- `go build ./...`, `go test ./internal/sdk/` pass.
- `go test ./integration/ -run 'TestRegistryFlow$'` passes (49s, real
platform).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants