Skip to content

build: bump openapi-generation to license token validation and wire the license election - #2124

Open
ThomasRooney wants to merge 1 commit into
mainfrom
build/bump-generator-license-election
Open

build: bump openapi-generation to license token validation and wire the license election#2124
ThomasRooney wants to merge 1 commit into
mainfrom
build/bump-generator-license-election

Conversation

@ThomasRooney

@ThomasRooney ThomasRooney commented Aug 27, 2026

Copy link
Copy Markdown
Member

Summary

Wires the CLI to the platform's target-scoped license tokens (speakeasy-registry#4708, live) and the generator's offline validation (openapi-generation#55).

Pins:

  • openapi-generation/v2 v2.934.0 (openapi-generation#55: offline license validation with target-scoped tokens)
  • speakeasy-core v0.24.0 (access.CheckGenerationAccess exposing AccessDetails.license_jwt)
  • speakeasy-client-sdk-go/v3 v3.28.1
  • generation-context v1.1.0 (WithDirect no longer implies AGPL; explicit ElectAGPL())

Behaviour

  • internal/sdkgen: the access check now returns the platform-issued license token (["*"] for paid tiers on every non-blocked check — allowed and warning — one named target for free workspaces). The CLI elects commercial whenever a token is present and attaches it for the generator to validate; the /v1/auth/validate token is a fallback. No token ⇒ AGPL election plus a warning ("No license token was issued for this generation; generated output is licensed under AGPL-3.0-only."). Blocked access still aborts before generation, as before.
  • Consequence: the "not in the approved SDK target list" warn path for paid tiers now produces commercial output again (on main it has been AGPL-stamped since the generation-context change). Free workspaces get commercial output for their one language; a second language is blocked by the access check.
  • internal/run: workflow runs without workspace context elect AGPL explicitly. cmd/lint: the dry-run diagnostic generation elects AGPL explicitly (nothing is written). internal/validation unchanged.
  • generate usage / pkg/codesamples untouched; they pass the caller's context through.

Offline licenses

  • Every successful online authentication stores the validate token in ~/.speakeasy/config.yaml as offline_license_token (only non-free tokens for the authenticated workspace; cleared on logout or when a re-authentication issues none). Overrides for CI/air-gapped use: SPEAKEASY_LICENSE_TOKEN (raw JWT), then SPEAKEASY_LICENSE_FILE (path).
  • Every command that requires authentication uses the stored license first (internal/auth.CommandContext): if it validates (licensetoken.Inspect) and belongs to the configured workspace, /v1/auth/validate is skipped and the authenticated context is built from the token's claims — with an SDK client when an API key is configured, so registry uploads, telemetry and the access check behave exactly as online. Without an API key the run is fully offline (telemetry and registry disabled at context construction, no access check).
  • Fallback everywhere: an unusable license (unreadable file, invalid/expired token, other workspace) is skipped with a warning naming the source, never the token; a license that does not cover a selected target (internal/auth.EnsureTargets, checked once in RunInner before uploads and in generate sdk) or an access check that fails with 401/403 (internal/auth.WithPlatformFallback) triggers the normal online authentication, which refreshes the stored token, and the operation is retried once. Nothing falls back to AGPL where the online path would have been commercial.

Verified in a sandboxed $HOME against prod: API key only / garbage token / stale token / other-workspace token / broken SPEAKEASY_LICENSE_TOKEN → online path, commercial output, fresh token stored; no API key + valid token → offline commercial; API key + valid token → validate skipped (~3 s saved per command), access check kept.

Verification

  • go build ./..., unit suite (excluding integration) green, golangci-lint clean on touched packages.
  • Smoke against prod with the built binary: speakeasy-self run → commercial output, no warning. Free workspace run -t go → commercial output; run -t typescript → "Upgrade Required … exceeded the limit of one free generated SDK", blocked.

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 27, 2026

Copy link
Copy Markdown

Running ultrareview automatically — High-risk licensing change: wiring the CLI to the new license-token validation changes AGPL vs commercial election across all generation paths; a missed bug could mislicense outputs or break authenticated runs.. I'll post findings when complete.

@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.

Ultrareview completed in 7m 55s

All reported issues were addressed across 6 files

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread internal/sdkgen/generation_context_test.go Outdated
Comment thread go.mod Outdated

@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.

All reported issues were addressed across 4 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread internal/sdkgen/sdkgen.go
ThomasRooney added a commit that referenced this pull request Aug 28, 2026
…2126)

Dependency bump only, split out of #2124 so the SDK/core change ships
and is verified on its own before the generator change.

- `speakeasy-client-sdk-go/v3` v3.28.0 → **v3.28.1** (regenerated from
the registry spec after speakeasy-registry#4708: `AccessDetails` gains
`license_jwt` and `status_code`; no signature changes).
- `speakeasy-core` v0.23.0 → **v0.24.0** (`access.CheckGenerationAccess`
returns the full access decision including the platform-issued license
token; `HasGenerationAccess` unchanged).

No CLI behaviour change: nothing reads the token yet. #2124 (generator
pin + commercial-on-token wiring) rebases on top once
openapi-generation#55 is released.

Guards from #2121 still apply: `internal/sdk/sdk_test.go` asserts
`x-api-key` on `Artifacts.PostTags`/`GetRevisions`; `TestRegistryFlow`
ends with `tag promote`.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Bumps `speakeasy-core` to v0.24.0 and `speakeasy-client-sdk-go/v3` to
v3.28.1. These upgrades expose a platform-issued license token and new
`AccessDetails` fields (`license_jwt`, `status_code`), but nothing reads
them yet, so CLI behavior is unchanged.

<sup>Written for commit 943cae8.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/speakeasy-api/speakeasy/pull/2126?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
@ThomasRooney
ThomasRooney force-pushed the build/bump-generator-license-election branch from 5dbba26 to 07519df Compare August 28, 2026 11:56

@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.

All reported issues were addressed across 6 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread internal/sdkgen/sdkgen.go Outdated

@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.

All reported issues were addressed across 13 files (changes from recent commits).

Tip: instead of fixing issues one by one fix them all with cubic
Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread internal/model/command.go Outdated
Comment thread internal/run/run.go Outdated
Comment thread internal/config/config.go Outdated
Comment thread internal/config/config.go Outdated
Comment thread cmd/generate/sdk.go Outdated

@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.

All reported issues were addressed across 17 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread cmd/run.go
Comment thread internal/model/command.go Outdated
Comment thread internal/config/config.go Outdated
Comment thread internal/config/offline_license_test.go Outdated

@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.

All reported issues were addressed across 15 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread internal/run/target.go Outdated
Comment thread cmd/configure.go Outdated
Comment thread internal/sdkgen/sdkgen.go Outdated
Comment thread internal/run/run.go Outdated
@ThomasRooney
ThomasRooney force-pushed the build/bump-generator-license-election branch from 588a056 to 532bfa2 Compare August 28, 2026 23:18

@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.

2 issues found across 15 files (changes from recent commits).

Confidence score: 2/5

  • internal/model/command.go conflates --force for run and generate sdk with an authentication refresh, causing valid offline licenses to be bypassed; keep generation forcing separate from authentication refresh handling.
  • internal/auth/auth.go returns an SDK-less context for valid offline-token users on every RequiresAuth command, so status, billing activate, and configure can fail despite valid credentials; ensure offline authentication supplies the required SDK context or narrowly scopes the restriction.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/auth/auth.go">

<violation number="1" location="internal/auth/auth.go:74">
P2: When a valid offline token is used without an API key, `CommandContext` returns an SDK-less context for every `RequiresAuth` command. Commands such as `status`, `billing activate`, and configure then fail with a missing-API-key error instead of authenticating online; restrict this path to offline-capable commands or ensure platform authentication before online commands.

(Based on your team's feedback about SDK-less offline command contexts.)</violation>
</file>

<file name="internal/model/command.go">

<violation number="1" location="internal/model/command.go:140">
P1: When `--force` is used on `run` or `generate sdk`, this treats the generation-control flag as an authentication refresh request and bypasses valid offline licenses. Keep generation force separate from authentication refresh, using a dedicated auth-refresh signal instead.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread internal/model/command.go Outdated
Comment thread internal/auth/auth.go

@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.

1 issue found across 3 files (changes from recent commits).

Confidence score: 4/5

  • In cmd/lint/lint.go, unauthenticated interactive lint runs can swallow the WithGenerationContext error and show an empty generation-warnings tab as though the dry run succeeded; return the error so callers can report the failure.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="cmd/lint/lint.go">

<violation number="1" location="cmd/lint/lint.go:603">
P2: When lint runs interactively without authentication, `WithGenerationContext` fails and this returns a nil error, so the caller displays an empty generation-warnings tab as if the dry run succeeded. Return the error here; the callers already skip targets whose dry run returns an error.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread cmd/lint/lint.go
licenseToken, _ := coreauth.GetLicenseTokenFromContext(ctx)
commercialCtx, err := coreauth.WithGenerationContext(ctx, generationaccess.GeneratedLicenseCommercial)
if err != nil {
return nil, nil

@cubic-dev-ai cubic-dev-ai Bot Aug 28, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: When lint runs interactively without authentication, WithGenerationContext fails and this returns a nil error, so the caller displays an empty generation-warnings tab as if the dry run succeeded. Return the error here; the callers already skip targets whose dry run returns an error.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At cmd/lint/lint.go, line 603:

<comment>When lint runs interactively without authentication, `WithGenerationContext` fails and this returns a nil error, so the caller displays an empty generation-warnings tab as if the dry run succeeded. Return the error here; the callers already skip targets whose dry run returns an error.</comment>

<file context>
@@ -589,10 +591,18 @@ func warningsToTabContents(warnings []error) []interactivity.InspectableContent
+		licenseToken, _ := coreauth.GetLicenseTokenFromContext(ctx)
+		commercialCtx, err := coreauth.WithGenerationContext(ctx, generationaccess.GeneratedLicenseCommercial)
+		if err != nil {
+			return nil, nil
+		}
+		ctx = licensetoken.WithToken(commercialCtx, licenseToken)
</file context>
Suggested change
return nil, nil
return nil, err
Fix with cubic

@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.

1 issue found across 5 files (changes from recent commits).

Confidence score: 2/5

  • internal/sdkgen/sdkgen.go can preserve an old token after tokenless online re-authentication and skip the platform access check when a workspace is downgraded or blocked, potentially allowing access that should be denied; clear the old token during tokenless re-authentication.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/sdkgen/sdkgen.go">

<violation number="1" location="internal/sdkgen/sdkgen.go:374">
P1: When a workspace is downgraded or blocked after tokenless online re-authentication, this branch still treats the preserved old token as sufficient and skips the platform access check. Clear the old token on tokenless re-authentication or retain the access check whenever an SDK is present, so blocked generation cannot proceed.

(Based on your team's feedback about stale offline licenses after downgrade.)</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread internal/sdkgen/sdkgen.go
// An offline-license context still carries an SDK client when an API key is
// persisted; the license decides generation access there, so the platform
// access check (and therefore the network) must not be required.
if hasOfflineLicense(ctx) && len(licenseToken) > 0 {

@cubic-dev-ai cubic-dev-ai Bot Aug 28, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: When a workspace is downgraded or blocked after tokenless online re-authentication, this branch still treats the preserved old token as sufficient and skips the platform access check. Clear the old token on tokenless re-authentication or retain the access check whenever an SDK is present, so blocked generation cannot proceed.

(Based on your team's feedback about stale offline licenses after downgrade.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At internal/sdkgen/sdkgen.go, line 374:

<comment>When a workspace is downgraded or blocked after tokenless online re-authentication, this branch still treats the preserved old token as sufficient and skips the platform access check. Clear the old token on tokenless re-authentication or retain the access check whenever an SDK is present, so blocked generation cannot proceed.

(Based on your team's feedback about stale offline licenses after downgrade.) </comment>

<file context>
@@ -367,6 +368,12 @@ func evaluateGenerationAccess(ctx context.Context, args *access.GenerationAccess
+	// An offline-license context still carries an SDK client when an API key is
+	// persisted; the license decides generation access there, so the platform
+	// access check (and therefore the network) must not be required.
+	if hasOfflineLicense(ctx) && len(licenseToken) > 0 {
+		return ctx, &access.GenerationAccess{Allowed: true}, licenseToken, nil
+	}
</file context>
Fix with cubic

…commercial license election and offline licenses

Bumps openapi-generation to a version that validates commercial license
tokens and requires an explicit license election for generated output.

The CLI always elects the customer's commercial license: the AGPL
election exists only as a source-build fallback in the upstream
generator and is never used here. A missing license token no longer
downgrades the election; generation proceeds as commercial and the
generator rejects it as unproven, with a CLI warning pointing at the
platform. Lint's diagnostic dry-run reuses the workspace license token
under a commercial election and skips diagnostics when unauthenticated.

Adds offline licenses (internal/license): a validated license token from
SPEAKEASY_LICENSE_TOKEN, SPEAKEASY_LICENSE_FILE, or the persisted
offline_license_token authenticates 'run' and 'generate sdk' without the
platform, gated per command by the new OfflineCapable field. Offline
contexts re-authenticate on demand via EnsureTargets, EnsurePlatform,
and WithPlatformFallback, so GitHub runs and uncovered targets still go
online. Generation access honors the offline license even when a
persisted API key put an SDK client in the context, keeping offline
generation offline for logged-in users.

Auth persistence captures the license token issued at validation, scoped
to the authenticated workspace and never for free tiers. Token-less
authentication preserves a manually configured offline license, a
workspace change clears it, and logout wipes it. --force on run and
generate sdk stays a generation-control flag; refreshing the persisted
license online is done explicitly via 'speakeasy auth login', which can
again replace a revoked key or switch accounts.
@ThomasRooney
ThomasRooney force-pushed the build/bump-generator-license-election branch from 8c57c76 to ba6ef5c Compare August 28, 2026 23:56

@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.

4 issues found across 17 files (changes from recent commits).

Confidence score: 2/5

  • internal/run/run.go in Workflow.Run skips the explicit AGPL election without workspace context, allowing tokenless workflow runs to enter generation incorrectly — restore the no-workspace AGPL election before target checks.
  • internal/sdkgen/sdkgen.go in withGenerationContext elects the commercial license when no token is issued, causing the validator to reject required AGPL fallback generation — select AGPL for tokenless generation.
  • cmd/lint/lint.go lets unauthenticated lint openapi --dry-run attempt commercial generation with an empty token, while discarded errors can make the dry run fail silently — use the appropriate AGPL fallback and propagate or surface generation errors.
  • internal/auth/auth.go forces browser opening after offline-license checks return 401/403 instead of retrying with the configured API key, breaking automatic retries in CI and other non-interactive environments — refresh through the API key first.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/run/run.go">

<violation number="1" location="internal/run/run.go:183">
P1: When `Workflow.Run` has no workspace context, this preparation performs no explicit AGPL/direct election. Restore the no-workspace AGPL election before target checks so tokenless workflow runs do not enter generation with the wrong licensing context.</violation>
</file>

<file name="cmd/lint/lint.go">

<violation number="1" location="cmd/lint/lint.go:601">
P2: When `lint openapi --dry-run` runs without authentication, this branch elects commercial with an empty token. The generator rejects tokenless commercial generation, while `runDryRunGeneration` discards its errors, so unauthenticated lint silently loses target-specific warnings; elect AGPL explicitly when no token is available.</violation>
</file>

<file name="internal/auth/auth.go">

<violation number="1" location="internal/auth/auth.go:106">
P2: When an offline-license access check returns 401/403, this fallback passes `force=true`, which opens the browser instead of refreshing through the configured API key. Automatic retries therefore fail in CI and other non-interactive environments; use a non-interactive online refresh path here.</violation>
</file>

<file name="internal/sdkgen/sdkgen.go">

<violation number="1" location="internal/sdkgen/sdkgen.go:407">
P1: When no license token is issued, `withGenerationContext` still elects the commercial license, so the CLI does not produce the required AGPL fallback and the validator can reject generation. Elect AGPL when `licenseToken` is empty, commercial only when a token is present, and emit the AGPL-3.0-only warning for that branch.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread internal/run/run.go

if _, err := core.GetWorkspaceIDFromContext(ctx); err != nil {
return generationaccess.WithDirect(ctx), nil //nolint:nilerr // Direct runs do not carry workspace context.
ctx, err = ensureTargets(ctx, targetTypes)

@cubic-dev-ai cubic-dev-ai Bot Aug 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: When Workflow.Run has no workspace context, this preparation performs no explicit AGPL/direct election. Restore the no-workspace AGPL election before target checks so tokenless workflow runs do not enter generation with the wrong licensing context.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At internal/run/run.go, line 183:

<comment>When `Workflow.Run` has no workspace context, this preparation performs no explicit AGPL/direct election. Restore the no-workspace AGPL election before target checks so tokenless workflow runs do not enter generation with the wrong licensing context.</comment>

<file context>
@@ -173,25 +175,48 @@ func (w *Workflow) Run(ctx context.Context) error {
-
-	if _, err := core.GetWorkspaceIDFromContext(ctx); err != nil {
-		return generationaccess.WithDirect(ctx), nil //nolint:nilerr // Direct runs do not carry workspace context.
+	ctx, err = ensureTargets(ctx, targetTypes)
+	if err != nil {
+		return ctx, err
</file context>
Fix with cubic

Comment thread internal/sdkgen/sdkgen.go
// commercial; the generator then rejects the generation as unproven rather
// than silently downgrading the license.
func withGenerationContext(ctx context.Context, licenseToken []byte) (context.Context, error) {
ctx, err := coreauth.WithGenerationContext(ctx, generationaccess.GeneratedLicenseCommercial)

@cubic-dev-ai cubic-dev-ai Bot Aug 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: When no license token is issued, withGenerationContext still elects the commercial license, so the CLI does not produce the required AGPL fallback and the validator can reject generation. Elect AGPL when licenseToken is empty, commercial only when a token is present, and emit the AGPL-3.0-only warning for that branch.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At internal/sdkgen/sdkgen.go, line 407:

<comment>When no license token is issued, `withGenerationContext` still elects the commercial license, so the CLI does not produce the required AGPL fallback and the validator can reject generation. Elect AGPL when `licenseToken` is empty, commercial only when a token is present, and emit the AGPL-3.0-only warning for that branch.</comment>

<file context>
@@ -348,12 +361,54 @@ func Generate(ctx context.Context, opts GenerateOptions) (*GenerationAccess, err
+// commercial; the generator then rejects the generation as unproven rather
+// than silently downgrading the license.
+func withGenerationContext(ctx context.Context, licenseToken []byte) (context.Context, error) {
+	ctx, err := coreauth.WithGenerationContext(ctx, generationaccess.GeneratedLicenseCommercial)
+	if err != nil {
+		return ctx, err
</file context>
Fix with cubic

Comment thread cmd/lint/lint.go
if _, ok := generationaccess.StateFromContext(ctx); !ok {
ctx = generationaccess.WithDirect(ctx)
licenseToken, _ := coreauth.GetLicenseTokenFromContext(ctx)
commercialCtx, err := coreauth.WithGenerationContext(ctx, generationaccess.GeneratedLicenseCommercial)

@cubic-dev-ai cubic-dev-ai Bot Aug 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: When lint openapi --dry-run runs without authentication, this branch elects commercial with an empty token. The generator rejects tokenless commercial generation, while runDryRunGeneration discards its errors, so unauthenticated lint silently loses target-specific warnings; elect AGPL explicitly when no token is available.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At cmd/lint/lint.go, line 601:

<comment>When `lint openapi --dry-run` runs without authentication, this branch elects commercial with an empty token. The generator rejects tokenless commercial generation, while `runDryRunGeneration` discards its errors, so unauthenticated lint silently loses target-specific warnings; elect AGPL explicitly when no token is available.</comment>

<file context>
@@ -589,10 +591,18 @@ func warningsToTabContents(warnings []error) []interactivity.InspectableContent
 	if _, ok := generationaccess.StateFromContext(ctx); !ok {
-		ctx = generationaccess.WithDirect(ctx)
+		licenseToken, _ := coreauth.GetLicenseTokenFromContext(ctx)
+		commercialCtx, err := coreauth.WithGenerationContext(ctx, generationaccess.GeneratedLicenseCommercial)
+		if err != nil {
+			return nil, nil
</file context>
Fix with cubic

Comment thread internal/auth/auth.go
if err == nil || licenseFromContext(ctx) == nil || !isAuthenticationFailure(err) {
return ctx, err
}
authCtx, err := authenticateWithHint(ctx, true)

@cubic-dev-ai cubic-dev-ai Bot Aug 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: When an offline-license access check returns 401/403, this fallback passes force=true, which opens the browser instead of refreshing through the configured API key. Automatic retries therefore fail in CI and other non-interactive environments; use a non-interactive online refresh path here.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At internal/auth/auth.go, line 106:

<comment>When an offline-license access check returns 401/403, this fallback passes `force=true`, which opens the browser instead of refreshing through the configured API key. Automatic retries therefore fail in CI and other non-interactive environments; use a non-interactive online refresh path here.</comment>

<file context>
@@ -2,31 +2,157 @@ package auth
+	if err == nil || licenseFromContext(ctx) == nil || !isAuthenticationFailure(err) {
+		return ctx, err
+	}
+	authCtx, err := authenticateWithHint(ctx, true)
+	if err != nil {
+		return authCtx, err
</file context>
Suggested change
authCtx, err := authenticateWithHint(ctx, true)
authCtx, err := authenticateWithHint(ctx, false)
Fix with cubic

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.

1 participant