yao/cmd/ci-token/main.go
Max 7373b0b6f7 feat(tai): enhance gRPC tunnel functionality and internal host handling
- Introduced ExpandHosts function to parse and expand comma-separated host entries, including special values like "internal" and "localhost".
- Updated gRPC server to utilize the new ExpandHosts function for improved host management.
- Added HostHasInternal function to check for "internal" in host strings, enhancing configuration flexibility.
- Implemented new gRPC endpoints for TaiTunnel registration and forwarding, improving tunnel communication capabilities.
- Refactored authentication logic to include new TaiTunnel endpoints, ensuring proper access control.

Made-with: Cursor
2026-03-12 20:35:17 +08:00

87 lines
2.3 KiB
Go

//go:build ci
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"time"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/engine"
"github.com/yaoapp/yao/openapi/oauth"
)
func main() {
appPath := flag.String("app", envOr("YAO_CI_APP_PATH", "."), "Yao application directory")
clientID := flag.String("client-id", envOr("YAO_CI_OAUTH_CLIENT_ID", "ci-tai"), "OAuth client ID embedded in token")
subject := flag.String("subject", envOr("YAO_CI_OAUTH_SUBJECT", "ci-tai"), "JWT subject claim")
scope := flag.String("scope", envOr("YAO_CI_OAUTH_SCOPE", "tai:tunnel"), "Token scope (space-separated)")
ttl := flag.String("ttl", envOr("YAO_CI_OAUTH_TTL", "24h"), "Token TTL (e.g. 1h, 24h, 168h)")
userID := flag.String("user-id", envOr("YAO_CI_OAUTH_USER_ID", ""), "User ID claim")
teamID := flag.String("team-id", envOr("YAO_CI_OAUTH_TEAM_ID", ""), "Team ID claim")
flag.Parse()
root, err := filepath.Abs(*appPath)
if err != nil {
fmt.Fprintf(os.Stderr, "ci-token: invalid app path: %v\n", err)
os.Exit(1)
}
if err := os.Chdir(root); err != nil {
fmt.Fprintf(os.Stderr, "ci-token: chdir %s: %v\n", root, err)
os.Exit(1)
}
config.Conf = config.LoadFrom(filepath.Join(root, ".env"))
config.Conf.Root = root
cfg := config.Conf
cfg.Session.IsCLI = true
warnings, err := engine.Load(cfg, engine.LoadOption{Action: "run"})
if err != nil {
fmt.Fprintf(os.Stderr, "ci-token: engine.Load failed: %v\n", err)
os.Exit(1)
}
for _, w := range warnings {
fmt.Fprintf(os.Stderr, "ci-token: warning [%s]: %v\n", w.Widget, w.Error)
}
if oauth.OAuth == nil {
fmt.Fprintln(os.Stderr, "ci-token: oauth service not initialized (openapi.Load may have failed)")
os.Exit(1)
}
dur, err := time.ParseDuration(*ttl)
if err != nil {
fmt.Fprintf(os.Stderr, "ci-token: invalid --ttl %q: %v\n", *ttl, err)
os.Exit(1)
}
expiresIn := int(dur.Seconds())
extraClaims := map[string]interface{}{}
if *userID != "" {
extraClaims["user_id"] = *userID
}
if *teamID != "" {
extraClaims["team_id"] = *teamID
}
token, err := oauth.OAuth.MakeAccessToken(*clientID, *scope, *subject, expiresIn, extraClaims)
if err != nil {
fmt.Fprintf(os.Stderr, "ci-token: MakeAccessToken failed: %v\n", err)
os.Exit(1)
}
fmt.Print(token)
}
func envOr(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}