fix(cli): linear app-template prints the consent page as Linear's Redirect URI — print the AgentCore callback instead (#914) - #918
Open
isadeks wants to merge 1 commit into
Conversation
`bgagent linear app-template` printed the hosted consent page as the Linear Redirect URI. Linear never redirects there — it is AgentCore's `resourceOauth2ReturnUrl`, where AgentCore sends the browser AFTER Linear redirects, to show the session id. So an operator who registered exactly what the template printed still failed consent with "Invalid redirect_uri parameter for the application", and the template's own traps list blamed a trailing slash. Linear redirects to the AgentCore provider callback on the `setup` path and to the CLI's loopback listener on `add-workspace`. The field now holds only that, one line per state: - provider exists -> the AgentCore callback, alone - vault, first run -> "Leave empty — `setup <slug>` prints the URI to add" - no vault -> the loopback listener The consent page is still printed, after the form and labelled "nothing to paste", because it is how an operator confirms the vault is deployed. `setup` now prints the callback on EVERY consent, not only the run that created the provider. `provider.created` was standing in for "this URI is registered on the Linear app": true once per provider lifetime, while the real condition stays false until a human pastes it in. Anyone who interrupted the first run, or lost the scrollback, got no remedy on any later run — just an authorize URL that dies in the browser. Four existing tests asserted the old model, one named "the hosted URI REPLACES the loopback rather than joining it". They are corrected rather than deleted, since they record which mistake was being prevented. A new test pins the deferred state at exactly two lines so the explanation cannot grow back. Verified against a live vault stack and a real Linear workspace: the field now renders the same two-URI list that had to be assembled by hand to get consent through. 995 CLI tests, 64 suites. Refs #914
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #914.
The bug
bgagent linear app-templateprinted the hosted consent page as the Linear Redirect URI. Linear never redirects there — it is AgentCore'sresourceOauth2ReturnUrl(cli/src/linear-vault.ts:399), where AgentCore sends the browser after Linear redirects, to show the session idsetupasks for.So an operator who registered exactly what the template printed still failed consent:
and the template's own traps list sent them looking for a trailing-slash typo. Hit live on a three-workspace dev stack; the field had to be assembled by hand from the authorize URL to get consent through.
Linear redirects to the AgentCore provider callback on the
setuppath, and to the CLI's loopback listener on the olderadd-workspacepath. Previously the code swapped one for the other (opts.hostedConsentUrl ? [hostedConsentUrl] : [callbackUrl]), so with the vault deployed the field held only a URI Linear ignores — and the URI it needs appeared solely if--slughappened to resolve an already-created provider.What the field holds now
One line, and only what the operator's own path uses:
Leave empty — bgagent linear setup <slug> prints the URI to add, then stops.A first run genuinely cannot show the callback: AgentCore mints the id during
CreateOauth2CredentialProvider, which needs the Client ID/Secret from an app that does not exist yet. So the template says so in one line and hands off tosetup, rather than filling the field with another flow's URI.The consent page is still printed — it is how an operator confirms the vault is deployed — but after the form and labelled
nothing to paste, so it cannot be mistaken for a field value.setupnow prints the callback on every consentprovider.createdwas standing in for "this URI is registered on the Linear app". It is true exactly once per provider lifetime, while the real condition stays false until a human pastes the URI in. Anyone who interrupted the first run, lost the scrollback, or never finished the paste got no remedy on any later run — just an authorize URL guaranteed to die in the browser. The code comment said as much: "the redirect URIs were dealt with on the first run above."Tests
995 passing, 64 suites. Four existing tests asserted the old model — one named "the hosted URI REPLACES the loopback rather than joining it" — and are corrected rather than deleted, since each records which mistake was being prevented. New coverage:
Verified live
Against a real vault stack (
ComputeSubstrate=agentcore,LinearVaultConsentUrlpresent) and a real Linear workspace:--slug <workspace>renders that workspace's own callback, and a bare run defers tosetup.Scope notes
--slugwould be unnecessary; fix(linear): bind webhook routing values to the workspace that signed the delivery #917 lands that capability properly (listOnboardedWorkspaceSlugs, which also falls back to paginated Secrets Manager listing), so the duplicate was removed rather than shipped in two places. Makingapp-templateinfer the slug is a natural follow-up once fix(linear): bind webhook routing values to the workspace that signed the delivery #917 merges.mise run buildpasses locally: 1,800 agent / 4,779 CDK (222 suites) / 995 CLI (64 suites), pluscdk:synth:quietand eslint clean. (An earlier revision of this description said the gate could not be run locally — that was a stale local mise, since resolved.)LINEAR_SETUP_GUIDE.mdnever told operators to register the consent page, and its instruction to "paste exactly what the template prints" (:73) becomes true again with this fix.