Skip to content

Add requesty <harness> commands that launch a harness through Requesty, with browser sign-in, profiles and model selection - #32

Open
lavicosa wants to merge 13 commits into
mainfrom
feat/eng-1709-oauth-client
Open

lavicosa wants to merge 13 commits into
mainfrom
feat/eng-1709-oauth-client

Conversation

@lavicosa

@lavicosa lavicosa commented Sep 21, 2026 •

Copy link
Copy Markdown
Collaborator
  • Adds requesty <harness> commands that launch a harness through Requesty
  • Adds oauth package for authenticating
  • Adds onboarding package which onboards a user using OAuth and provisions an API key
  • Adds support for profiles, along with harness/model preferences

@github-actions

github-actions Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

AI Cost

No spend detected for branch feat/eng-1709-oauth-client in the last 30 days.

Updated 2026-09-25T17:08Z · last 30 days · data from Requesty

@github-actions github-actions Bot added the cost:$0.00 AI cost for this branch label Sep 21, 2026
Comment thread internal/oauth/browser.go
Comment thread internal/oauth/browser.go
Comment thread internal/oauth/browser.go
Comment thread internal/harnesses/exec_windows.go
Comment thread internal/harnesses/hermes.go
Comment thread internal/harnesses/opencode.go
Comment thread internal/harnesses/pi.go
@lavicosa lavicosa changed the title Implement OAuth flow for provisioning API key Add requesty <harness> commands that launch a harness through Requesty, with browser sign-in, profiles and model selection Sep 24, 2026
@lavicosa
lavicosa force-pushed the feat/eng-1709-oauth-client branch from 7546a3a to cdf61a9 Compare September 24, 2026 13:48
Comment thread internal/oauth/flow.go

// Options configures Login. Only APIBaseURL is required; the rest exist so
// tests can stand in for the browser, the terminal, and the network.
type Options struct {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there a reason we have so many options right now?
As a first step, maybe we can simplify this a bit by keeping the options, but failing if they are not specified, limiting the number of different permutations that we need to test and care about?

As in, bottom line, remove all the default values from inside Login, and just have the caller always specify those.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It was to facilitate headless vs tui mode as well as testing but agree it could be nicer. I've simpified this to a validate function to fail if not specified. All of the fields are required except OnAuthorizeURL.

// The redirect URI must use the 127.0.0.1 literal, not localhost, so that is
// what we bind to.
func listenCallback(state string) (*callbackServer, error) {
listener, err := net.Listen("tcp", "127.0.0.1:0")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we add a comment here saying that port 0 generates a random port number, and we create the redirectUri after we already know it

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done.

Comment thread internal/oauth/callback.go Outdated
// check comes first so that a response meant for another attempt, or forged
// by a page that guessed the port, is never acted on.
func (s *callbackServer) resolve(query url.Values) callbackResult {
if subtle.ConstantTimeCompare([]byte(query.Get("state")), []byte(s.state)) != 1 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why ConstantTimeCompare is important here?

@lavicosa lavicosa Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch, dropped to be a !=.

Comment thread internal/oauth/callback.go Outdated
return callbackResult{err: errors.New("state mismatch: the response did not belong to this sign-in attempt")}
}

if code := query.Get("error"); code != "" {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

err := query.Get("error") ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done.

Comment thread internal/oauth/callback.go Outdated
}

if code := query.Get("error"); code != "" {
return callbackResult{err: &Error{Code: code, Description: query.Get("error_description")}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How do we decide when to return an Error and when to return an errors.New ?

@lavicosa lavicosa Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

We return an Error for failures from the authorization server and errors.New when it's a problem the CLI detects.

It's like that to capture the auth server error code given in a typed struct and facilitate tests.

Comment thread cmd/harness.go Outdated

// newHarnessCommands returns the `requesty <harness>` commands, each of which
// starts a harness with Requesty injected for that run.
func newHarnessCommands(env environment) []*cobra.Command {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can't we build something that automatically generates a command per Harness in our internal harnesses package?

Probably just a bit of massaging of the DefaultConfigDirClaudeCode to be a method that accepts the harness name and a factory that does the same to create the actual client.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I would push back and say that the harness launch commands belong in cmd. However, I have simplified it so that the definitions used here now come from LaunchDefinition and harnesses.LaunchDefinitions().

I also removed DefaultConfigDirClaudeCode and the other harness specific functions and moved it to be inside the harness constructor, the right place for it.

@lavicosa
lavicosa force-pushed the feat/eng-1709-oauth-client branch from 3c3c4fe to a6adee1 Compare September 25, 2026 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cost:$0.00 AI cost for this branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants