Skip to content

Commit 07519df

Browse files
committed
build: bump openapi-generation to license token validation and elect commercial on the access-check token
Pins openapi-generation/v2 at 3f9d8b8234 (openapi-generation#55, target- scoped license tokens) and generation-context v1.1.0. The platform returns a license token on every non-blocked access check (wildcard for paid tiers, one target for free workspaces), so the CLI elects commercial output whenever a token is present and attaches it for the generator to validate; the auth-context token is a fallback and a warning is printed when no token was issued. Direct workflow runs and the lint dry-run elect AGPL explicitly now that WithDirect no longer implies it.
1 parent b42ff17 commit 07519df

6 files changed

Lines changed: 50 additions & 25 deletions

File tree

cmd/lint/lint.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ func runDryRunGeneration(ctx context.Context, schemaPath, targetLanguage, workin
592592
// Lint is available without authentication, so its optional diagnostic
593593
// generation must explicitly use the direct AGPL mode when no caller state exists.
594594
if _, ok := generationaccess.StateFromContext(ctx); !ok {
595-
ctx = generationaccess.WithDirect(ctx)
595+
ctx = generationaccess.WithDirect(ctx, generationaccess.ElectAGPL())
596596
}
597597

598598
// Load the OpenAPI schema

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ require (
4141
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
4242
github.com/samber/lo v1.52.0
4343
github.com/sethvargo/go-githubactions v1.3.2
44-
github.com/speakeasy-api/generation-context v1.0.0
44+
github.com/speakeasy-api/generation-context v1.1.0
4545
github.com/speakeasy-api/git-diff-parser v0.2.0
4646
github.com/speakeasy-api/gram v0.0.0-20260121234743-5a36906a8929
4747
github.com/speakeasy-api/huh v1.1.2
4848
github.com/speakeasy-api/jq v0.1.1-0.20251107233444-84d7e49e84a4
4949
github.com/speakeasy-api/openapi v1.25.0
50-
github.com/speakeasy-api/openapi-generation/v2 v2.933.1
50+
github.com/speakeasy-api/openapi-generation/v2 v2.933.1-0.20260827162058-3f9d8b8234af
5151
github.com/speakeasy-api/sdk-gen-config v1.58.0
5252
github.com/speakeasy-api/speakeasy-agent-mode-content v0.2.12
5353
github.com/speakeasy-api/speakeasy-client-sdk-go/v3 v3.28.1

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -530,8 +530,8 @@ github.com/sourcegraph/jsonrpc2 v0.2.2 h1:fCyU80iidEwcF9kWaj4ylOO1h8pT8P8sFGv8EK
530530
github.com/sourcegraph/jsonrpc2 v0.2.2/go.mod h1:ZafdZgk/axhT1cvZAPOhw+95nz2I/Ra5qMlU4gTRwIo=
531531
github.com/speakeasy-api/easytemplate v0.12.4 h1:0xEm93tqPfdIWKUwgxvFgDLBmSDXlCImp+mQF3XZcOg=
532532
github.com/speakeasy-api/easytemplate v0.12.4/go.mod h1:UF8bFhTpyr1sHiEWacT7ULN67Bve6UIrTH7uvzdbTEY=
533-
github.com/speakeasy-api/generation-context v1.0.0 h1:LMHn7k1GCT1lIuwWSCn2ogaUgaIq8eGsGGPUXmvpW0s=
534-
github.com/speakeasy-api/generation-context v1.0.0/go.mod h1:AxqOSyH55Kp70pQynKl0nSlpke6P3/FlnFL//7sPM50=
533+
github.com/speakeasy-api/generation-context v1.1.0 h1:VndzBP6wdkk1yp7DGA/lgAMH+qudMLYf2I5wuXscs+8=
534+
github.com/speakeasy-api/generation-context v1.1.0/go.mod h1:AxqOSyH55Kp70pQynKl0nSlpke6P3/FlnFL//7sPM50=
535535
github.com/speakeasy-api/git-diff-parser v0.2.0 h1:fvPsWhTqTt+8j9Kx4eXF6kRRqDUC60gy0VII4PnjIHA=
536536
github.com/speakeasy-api/git-diff-parser v0.2.0/go.mod h1:P46HmmVVmwA9P8h2wa0fDpmRM8/grbVQ+uKhWDtpkIY=
537537
github.com/speakeasy-api/goja v0.0.0-20260223084236-ed0328a0a462 h1:wFAq/dFgXzPkOpI36BkHdUl4rKi7qh6iMsvlRkh2fCs=
@@ -550,8 +550,8 @@ github.com/speakeasy-api/libopenapi v0.21.10-fixhiddencomps-fixed h1:ZtuakKtG6x7
550550
github.com/speakeasy-api/libopenapi v0.21.10-fixhiddencomps-fixed/go.mod h1:Gc8oQkjr2InxwumK0zOBtKN9gIlv9L2VmSVIUk2YxcU=
551551
github.com/speakeasy-api/openapi v1.25.0 h1:xyJ5ZzW4YwStT2ICo0o7v9M890J7VpsR7AqhQSZnwl4=
552552
github.com/speakeasy-api/openapi v1.25.0/go.mod h1:9gGkzi9jNspEbcB08zta+IjzAi5Zy4QgSEQfF/LSrbQ=
553-
github.com/speakeasy-api/openapi-generation/v2 v2.933.1 h1:g0lZi8XsS2NjArwP1hyC08bJRKeOHjgD9gx9ie7KONQ=
554-
github.com/speakeasy-api/openapi-generation/v2 v2.933.1/go.mod h1:1Yypyh8Dl2dg/aYMY8ySCJ6kfuI9xTpUxuSs30XpZPE=
553+
github.com/speakeasy-api/openapi-generation/v2 v2.933.1-0.20260827162058-3f9d8b8234af h1:KuV5UGjAwP1pjJglPMzM02SBnJUsR9kkymf1y0v5jbg=
554+
github.com/speakeasy-api/openapi-generation/v2 v2.933.1-0.20260827162058-3f9d8b8234af/go.mod h1:OOjYkuR25Q5RvpwR5z1EeA9tIKdp3TK4jnXQsNbpmHg=
555555
github.com/speakeasy-api/openapi/openapi/linter/customrules v0.0.0-20260206023826-2483fb8e98b4 h1:gV+lYeVNNJG9X3Sl9Su3cRh1iF/oNqzvb5Ijq2QR8jY=
556556
github.com/speakeasy-api/openapi/openapi/linter/customrules v0.0.0-20260206023826-2483fb8e98b4/go.mod h1:1zQpVio7X6QJDtyNdUguCgZ+IC7CzKhhjvNgJdvGVF0=
557557
github.com/speakeasy-api/sdk-gen-config v1.58.0 h1:JrDgDU3XBIidv+TXFqYBvIomfeGEQ0zN+OnHyUc+kNw=

internal/run/run.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ func withWorkflowGenerationContext(ctx context.Context) (context.Context, error)
179179
}
180180

181181
if _, err := core.GetWorkspaceIDFromContext(ctx); err != nil {
182-
return generationaccess.WithDirect(ctx), nil //nolint:nilerr // Direct runs do not carry workspace context.
182+
return generationaccess.WithDirect(ctx, generationaccess.ElectAGPL()), nil //nolint:nilerr // Direct runs do not carry workspace context.
183183
}
184184

185185
// Target-level access checks decide whether authenticated output is commercial.

internal/sdkgen/generation_context_test.go

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,29 @@ package sdkgen
22

33
import (
44
"context"
5+
"errors"
56
"testing"
67
"time"
78

89
generationaccess "github.com/speakeasy-api/generation-context/access"
10+
"github.com/speakeasy-api/openapi-generation/v2/pkg/licensetoken"
911
"github.com/speakeasy-api/speakeasy-client-sdk-go/v3/pkg/models/shared"
1012
"github.com/speakeasy-api/speakeasy-core/auth"
1113
)
1214

13-
func TestWithGenerationContextSelectsCallerDecidedLicense(t *testing.T) {
15+
func TestWithGenerationContextElectsOnLicenseToken(t *testing.T) {
1416
t.Parallel()
1517

1618
createdAt := time.Date(2024, time.January, 2, 3, 4, 5, 0, time.UTC)
1719
testCases := []struct {
18-
name string
19-
generationAllowed bool
20-
wantLicense generationaccess.GeneratedLicense
20+
name string
21+
licenseToken []byte
22+
wantLicense generationaccess.GeneratedLicense
23+
wantToken bool
2124
}{
22-
{name: "allowed generation is commercial", generationAllowed: true, wantLicense: generationaccess.GeneratedLicenseCommercial},
23-
{name: "unentitled generation is AGPL", generationAllowed: false, wantLicense: generationaccess.GeneratedLicenseAGPL},
25+
{name: "license token elects commercial", licenseToken: []byte("license-token"), wantLicense: generationaccess.GeneratedLicenseCommercial, wantToken: true},
26+
{name: "no license token elects AGPL", wantLicense: generationaccess.GeneratedLicenseAGPL},
27+
{name: "empty license token elects AGPL", licenseToken: []byte{}, wantLicense: generationaccess.GeneratedLicenseAGPL},
2428
}
2529

2630
for _, tt := range testCases {
@@ -37,7 +41,7 @@ func TestWithGenerationContextSelectsCallerDecidedLicense(t *testing.T) {
3741
[]shared.BillingAddOn{shared.BillingAddOnSnippetAi},
3842
)
3943

40-
ctx, err := withGenerationContext(legacy, tt.generationAllowed)
44+
ctx, err := withGenerationContext(legacy, tt.licenseToken)
4145
if err != nil {
4246
t.Fatalf("with generation context: %v", err)
4347
}
@@ -54,6 +58,14 @@ func TestWithGenerationContextSelectsCallerDecidedLicense(t *testing.T) {
5458
if !state.HasBillingAddOn(shared.BillingAddOnSnippetAi) {
5559
t.Fatal("caller bridge lost authenticated billing add-ons")
5660
}
61+
_, verification, err := licensetoken.ResolveGenerationAccess(ctx)
62+
if tt.wantToken {
63+
if !errors.Is(err, licensetoken.ErrInvalidLicenseToken) {
64+
t.Fatalf("expected the attached fixture token to reach the validator and be rejected, got verification=%v err=%v", verification, err)
65+
}
66+
} else if err != nil || verification != nil {
67+
t.Fatalf("expected no license token attached, got verification=%v err=%v", verification, err)
68+
}
5769
})
5870
}
5971
}
@@ -68,7 +80,7 @@ func TestWithGenerationContextPreservesCancellableContext(t *testing.T) {
6880
cancellable, cancel := context.WithCancel(legacy)
6981
defer cancel()
7082

71-
ctx, err := withGenerationContext(cancellable, true)
83+
ctx, err := withGenerationContext(cancellable, []byte("license-token"))
7284
if err != nil {
7385
t.Fatalf("with generation context: %v", err)
7486
}
@@ -86,7 +98,7 @@ func TestWithGenerationContextRejectsIncompleteAuthentication(t *testing.T) {
8698
t.Parallel()
8799

88100
original := auth.SetAccountTypeInContext(context.Background(), string(shared.AccountTypeBusiness))
89-
ctx, err := withGenerationContext(original, true)
101+
ctx, err := withGenerationContext(original, []byte("license-token"))
90102
if err == nil {
91103
t.Fatal("expected incomplete authentication error")
92104
}

internal/sdkgen/sdkgen.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727

2828
changelog "github.com/speakeasy-api/openapi-generation/v2"
2929
"github.com/speakeasy-api/openapi-generation/v2/pkg/generate"
30+
"github.com/speakeasy-api/openapi-generation/v2/pkg/licensetoken"
3031
"github.com/speakeasy-api/openapi-generation/v2/pkg/merge"
3132
"github.com/speakeasy-api/speakeasy/internal/log"
3233
"github.com/speakeasy-api/speakeasy/internal/utils"
@@ -102,13 +103,14 @@ func Generate(ctx context.Context, opts GenerateOptions) (*GenerationAccess, err
102103

103104
logger := log.From(ctx).WithAssociatedFile(opts.SchemaPath)
104105

105-
generationAccess, level, message, accessErr := access.HasGenerationAccess(ctx, &access.GenerationAccessArgs{
106+
accessResult, accessErr := access.CheckGenerationAccess(ctx, &access.GenerationAccessArgs{
106107
GenLockID: GetGenLockID(opts.OutDir),
107108
TargetType: &opts.Language,
108109
})
109110
if accessErr != nil {
110111
return &GenerationAccess{}, fmt.Errorf("failed to evaluate generation access: %w", accessErr)
111112
}
113+
generationAccess, level, message := accessResult.Allowed, accessResult.Level, accessResult.Message
112114

113115
if !generationAccess && level != nil && *level == shared.LevelBlocked {
114116
msg := styles.RenderErrorMessage(
@@ -124,14 +126,21 @@ func Generate(ctx context.Context, opts GenerateOptions) (*GenerationAccess, err
124126
}, stderrors.New("generation access blocked")
125127
}
126128

127-
ctx, err := withGenerationContext(ctx, generationAccess)
129+
licenseToken := accessResult.LicenseToken
130+
if licenseToken == nil {
131+
licenseToken, _ = auth.GetLicenseTokenFromContext(ctx)
132+
}
133+
ctx, err := withGenerationContext(ctx, licenseToken)
128134
if err != nil {
129135
return &GenerationAccess{
130136
AccessAllowed: generationAccess,
131137
Message: message,
132138
Level: level,
133139
}, fmt.Errorf("failed to prepare generation context: %w", err)
134140
}
141+
if licenseToken == nil {
142+
logger.Warnf("No license token was issued for this generation; generated output is licensed under AGPL-3.0-only.")
143+
}
135144

136145
logger.Infof("Generating SDK for %s...\n", opts.Language)
137146

@@ -276,7 +285,7 @@ func Generate(ctx context.Context, opts GenerateOptions) (*GenerationAccess, err
276285

277286
var errs []error
278287
if opts.CancellableGeneration != nil && opts.CancellableGeneration.CancellableContext != nil {
279-
cancelCtx, err := withGenerationContext(opts.CancellableGeneration.CancellableContext, generationAccess)
288+
cancelCtx, err := withGenerationContext(opts.CancellableGeneration.CancellableContext, licenseToken)
280289
if err != nil {
281290
return fmt.Errorf("failed to prepare cancellable generation context: %w", err)
282291
}
@@ -348,12 +357,16 @@ func Generate(ctx context.Context, opts GenerateOptions) (*GenerationAccess, err
348357
}, nil
349358
}
350359

351-
func withGenerationContext(ctx context.Context, generationAllowed bool) (context.Context, error) {
352-
generatedLicense := generationaccess.GeneratedLicenseAGPL
353-
if generationAllowed {
354-
generatedLicense = generationaccess.GeneratedLicenseCommercial
360+
func withGenerationContext(ctx context.Context, licenseToken []byte) (context.Context, error) {
361+
if len(licenseToken) == 0 {
362+
return auth.WithGenerationContext(ctx, generationaccess.GeneratedLicenseAGPL)
363+
}
364+
365+
ctx, err := auth.WithGenerationContext(ctx, generationaccess.GeneratedLicenseCommercial)
366+
if err != nil {
367+
return ctx, err
355368
}
356-
return auth.WithGenerationContext(ctx, generatedLicense)
369+
return licensetoken.WithToken(ctx, licenseToken), nil
357370
}
358371

359372
func ValidateConfig(ctx context.Context, outDir string) error {

0 commit comments

Comments
 (0)