WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
package cmdutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/Tencent/WeKnora/cli/internal/secrets"
|
||||
sdk "github.com/Tencent/WeKnora/client"
|
||||
)
|
||||
|
||||
// Refresher is the narrow SDK surface RefreshAndPersist depends on.
|
||||
// *sdk.Client satisfies it implicitly; tests inject fakes.
|
||||
type Refresher interface {
|
||||
RefreshToken(ctx context.Context, refreshToken string) (*sdk.RefreshTokenResponse, error)
|
||||
}
|
||||
|
||||
// RefreshAndPersist reads the stored refresh token for profileName, exchanges it
|
||||
// for a new access + refresh pair via refresher, and writes both back to the
|
||||
// secrets store. Returns the new access token (the refresh is already
|
||||
// persisted as a side-effect, so callers only need the access value to
|
||||
// retry the original request).
|
||||
//
|
||||
// Single canonical implementation shared by `weknora auth refresh` and the
|
||||
// AuthRetryTransport's refresh closure - both used to inline the same
|
||||
// six-step sequence with subtly diverging error wording.
|
||||
func RefreshAndPersist(ctx context.Context, store secrets.Store, refresher Refresher, profileName string) (string, error) {
|
||||
refresh, err := store.Get(profileName, "refresh")
|
||||
if errors.Is(err, secrets.ErrNotFound) || refresh == "" {
|
||||
return "", &Error{
|
||||
Code: CodeAuthTokenExpired,
|
||||
Message: "refresh token missing for profile " + profileName,
|
||||
Hint: "run `weknora auth login` to re-authenticate",
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return "", Wrapf(CodeLocalKeychainDenied, err, "load refresh token")
|
||||
}
|
||||
|
||||
resp, err := refresher.RefreshToken(ctx, refresh)
|
||||
if err != nil {
|
||||
// WrapHTTP rather than fixed CodeNetworkError so a refresh
|
||||
// rejected by the server (401/403) surfaces as auth.token_expired /
|
||||
// auth.forbidden instead of collapsing to network.error.
|
||||
return "", WrapHTTP(err, "refresh access token")
|
||||
}
|
||||
if resp == nil || !resp.Success || resp.AccessToken == "" || resp.RefreshToken == "" {
|
||||
msg := "refresh token rejected"
|
||||
if resp != nil && resp.Message != "" {
|
||||
msg = "refresh token rejected: " + resp.Message
|
||||
}
|
||||
return "", &Error{
|
||||
Code: CodeAuthTokenExpired,
|
||||
Message: msg,
|
||||
Hint: "run `weknora auth login` to re-authenticate",
|
||||
}
|
||||
}
|
||||
|
||||
if err := store.Set(profileName, "access", resp.AccessToken); err != nil {
|
||||
return "", Wrapf(CodeLocalKeychainDenied, err, "save access token")
|
||||
}
|
||||
if err := store.Set(profileName, "refresh", resp.RefreshToken); err != nil {
|
||||
return "", Wrapf(CodeLocalKeychainDenied, err, "save refresh token")
|
||||
}
|
||||
return resp.AccessToken, nil
|
||||
}
|
||||
Reference in New Issue
Block a user