源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,287 @@
|
||||
package workspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
managedcredentialsbiz "github.com/tutti-os/tutti/services/tuttid/biz/managedcredentials"
|
||||
)
|
||||
|
||||
func (s *SQLiteStore) ListManagedModelProviderConfigs(ctx context.Context, workspaceID string) ([]managedcredentialsbiz.ProviderConfig, error) {
|
||||
if s == nil || s.writeDB == nil {
|
||||
return nil, errors.New("workspace database is not initialized")
|
||||
}
|
||||
rows, err := s.readDB.QueryContext(ctx, `
|
||||
SELECT workspace_id, provider_id, enabled, api_key_ciphertext, base_url, models_json, updated_at_unix_ms
|
||||
FROM managed_model_provider_credentials
|
||||
WHERE workspace_id = ?
|
||||
ORDER BY provider_id
|
||||
`, workspaceID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list managed model provider configs: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var configs []managedcredentialsbiz.ProviderConfig
|
||||
for rows.Next() {
|
||||
config, err := scanManagedModelProviderConfig(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configs = append(configs, config)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("list managed model provider config rows: %w", err)
|
||||
}
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
func (s *SQLiteStore) GetManagedModelProviderConfig(ctx context.Context, workspaceID string, providerID managedcredentialsbiz.ProviderID) (managedcredentialsbiz.ProviderConfig, error) {
|
||||
if s == nil || s.writeDB == nil {
|
||||
return managedcredentialsbiz.ProviderConfig{}, errors.New("workspace database is not initialized")
|
||||
}
|
||||
row := s.readDB.QueryRowContext(ctx, `
|
||||
SELECT workspace_id, provider_id, enabled, api_key_ciphertext, base_url, models_json, updated_at_unix_ms
|
||||
FROM managed_model_provider_credentials
|
||||
WHERE workspace_id = ? AND provider_id = ?
|
||||
`, workspaceID, providerID)
|
||||
config, err := scanManagedModelProviderConfig(row)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return managedcredentialsbiz.ProviderConfig{}, ErrWorkspaceAppNotFound
|
||||
}
|
||||
return managedcredentialsbiz.ProviderConfig{}, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (s *SQLiteStore) PutManagedModelProviderConfig(ctx context.Context, config managedcredentialsbiz.ProviderConfig) error {
|
||||
if s == nil || s.writeDB == nil {
|
||||
return errors.New("workspace database is not initialized")
|
||||
}
|
||||
modelsJSON, err := json.Marshal(config.Models)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal managed provider models: %w", err)
|
||||
}
|
||||
ciphertext, err := encryptManagedCredential(config.APIKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
now := unixMs(time.Now().UTC())
|
||||
_, err = s.writeDB.ExecContext(ctx, `
|
||||
INSERT INTO managed_model_provider_credentials (
|
||||
workspace_id, provider_id, enabled, api_key_ciphertext, base_url, models_json, updated_at_unix_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(workspace_id, provider_id) DO UPDATE SET
|
||||
enabled = excluded.enabled,
|
||||
api_key_ciphertext = excluded.api_key_ciphertext,
|
||||
base_url = excluded.base_url,
|
||||
models_json = excluded.models_json,
|
||||
updated_at_unix_ms = excluded.updated_at_unix_ms
|
||||
`, config.WorkspaceID, string(config.Provider), boolInt(config.Enabled), ciphertext, config.BaseURL, string(modelsJSON), now)
|
||||
if err != nil {
|
||||
return fmt.Errorf("put managed model provider config: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SQLiteStore) DeleteManagedModelProviderConfig(ctx context.Context, workspaceID string, providerID managedcredentialsbiz.ProviderID) error {
|
||||
if s == nil || s.writeDB == nil {
|
||||
return errors.New("workspace database is not initialized")
|
||||
}
|
||||
_, err := s.writeDB.ExecContext(ctx, `
|
||||
DELETE FROM managed_model_provider_credentials
|
||||
WHERE workspace_id = ? AND provider_id = ?
|
||||
`, workspaceID, providerID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("delete managed model provider config: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SQLiteStore) PutManagedModelGrant(ctx context.Context, grant managedcredentialsbiz.Grant) error {
|
||||
if s == nil || s.writeDB == nil {
|
||||
return errors.New("workspace database is not initialized")
|
||||
}
|
||||
providersJSON, err := json.Marshal(grant.ProviderIDs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal managed grant providers: %w", err)
|
||||
}
|
||||
scopesJSON, err := json.Marshal(grant.Scopes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal managed grant scopes: %w", err)
|
||||
}
|
||||
_, err = s.writeDB.ExecContext(ctx, `
|
||||
INSERT INTO managed_model_app_grants (
|
||||
workspace_id, app_id, grant_ref, provider_ids_json, scopes_json, created_at_unix_ms, expires_at_unix_ms, revoked_at_unix_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, NULL)
|
||||
ON CONFLICT(workspace_id, app_id, grant_ref) DO UPDATE SET
|
||||
provider_ids_json = excluded.provider_ids_json,
|
||||
scopes_json = excluded.scopes_json,
|
||||
expires_at_unix_ms = excluded.expires_at_unix_ms,
|
||||
revoked_at_unix_ms = NULL
|
||||
`, grant.WorkspaceID, grant.AppID, grant.GrantRef, string(providersJSON), string(scopesJSON), unixMs(grant.CreatedAt), unixMs(grant.ExpiresAt))
|
||||
if err != nil {
|
||||
return fmt.Errorf("put managed model grant: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SQLiteStore) GetManagedModelGrant(ctx context.Context, workspaceID string, appID string, grantRef string) (managedcredentialsbiz.Grant, error) {
|
||||
if s == nil || s.writeDB == nil {
|
||||
return managedcredentialsbiz.Grant{}, errors.New("workspace database is not initialized")
|
||||
}
|
||||
row := s.readDB.QueryRowContext(ctx, `
|
||||
SELECT workspace_id, app_id, grant_ref, provider_ids_json, scopes_json, created_at_unix_ms, expires_at_unix_ms, revoked_at_unix_ms
|
||||
FROM managed_model_app_grants
|
||||
WHERE workspace_id = ? AND app_id = ? AND grant_ref = ?
|
||||
`, workspaceID, appID, grantRef)
|
||||
var grant managedcredentialsbiz.Grant
|
||||
var providersJSON string
|
||||
var scopesJSON string
|
||||
var createdAtUnixMS int64
|
||||
var expiresAtUnixMS int64
|
||||
var revokedAt sql.NullInt64
|
||||
if err := row.Scan(&grant.WorkspaceID, &grant.AppID, &grant.GrantRef, &providersJSON, &scopesJSON, &createdAtUnixMS, &expiresAtUnixMS, &revokedAt); err != nil {
|
||||
return managedcredentialsbiz.Grant{}, err
|
||||
}
|
||||
_ = json.Unmarshal([]byte(providersJSON), &grant.ProviderIDs)
|
||||
_ = json.Unmarshal([]byte(scopesJSON), &grant.Scopes)
|
||||
grant.CreatedAt = time.UnixMilli(createdAtUnixMS).UTC()
|
||||
grant.ExpiresAt = time.UnixMilli(expiresAtUnixMS).UTC()
|
||||
grant.RevokedAt = nullableUnixMs(revokedAt)
|
||||
return grant, nil
|
||||
}
|
||||
|
||||
func (s *SQLiteStore) RevokeManagedModelGrant(ctx context.Context, workspaceID string, appID string, grantRef string) error {
|
||||
if s == nil || s.writeDB == nil {
|
||||
return errors.New("workspace database is not initialized")
|
||||
}
|
||||
_, err := s.writeDB.ExecContext(ctx, `
|
||||
UPDATE managed_model_app_grants
|
||||
SET revoked_at_unix_ms = ?
|
||||
WHERE workspace_id = ? AND app_id = ? AND grant_ref = ?
|
||||
`, unixMs(time.Now().UTC()), workspaceID, appID, grantRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("revoke managed model grant: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SQLiteStore) DeleteManagedModelGrant(ctx context.Context, workspaceID string, appID string, grantRef string) error {
|
||||
if s == nil || s.writeDB == nil {
|
||||
return errors.New("workspace database is not initialized")
|
||||
}
|
||||
_, err := s.writeDB.ExecContext(ctx, `
|
||||
DELETE FROM managed_model_app_grants
|
||||
WHERE workspace_id = ? AND app_id = ? AND grant_ref = ?
|
||||
`, workspaceID, appID, grantRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("delete managed model grant: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type managedProviderScanner interface {
|
||||
Scan(dest ...any) error
|
||||
}
|
||||
|
||||
func scanManagedModelProviderConfig(row managedProviderScanner) (managedcredentialsbiz.ProviderConfig, error) {
|
||||
var config managedcredentialsbiz.ProviderConfig
|
||||
var providerID string
|
||||
var enabled int
|
||||
var ciphertext string
|
||||
var modelsJSON string
|
||||
var updatedAtUnixMS int64
|
||||
if err := row.Scan(&config.WorkspaceID, &providerID, &enabled, &ciphertext, &config.BaseURL, &modelsJSON, &updatedAtUnixMS); err != nil {
|
||||
return managedcredentialsbiz.ProviderConfig{}, err
|
||||
}
|
||||
apiKey, err := decryptManagedCredential(ciphertext)
|
||||
if err != nil {
|
||||
return managedcredentialsbiz.ProviderConfig{}, err
|
||||
}
|
||||
config.Provider = managedcredentialsbiz.ProviderID(providerID)
|
||||
config.Enabled = enabled != 0
|
||||
config.APIKey = apiKey
|
||||
_ = json.Unmarshal([]byte(modelsJSON), &config.Models)
|
||||
config.UpdatedAt = time.UnixMilli(updatedAtUnixMS).UTC()
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func boolInt(value bool) int {
|
||||
if value {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func managedCredentialKey() []byte {
|
||||
seed := strings.TrimSpace(os.Getenv("TUTTI_MANAGED_CREDENTIAL_SECRET"))
|
||||
if seed == "" {
|
||||
hostname, _ := os.Hostname()
|
||||
userConfigDir, _ := os.UserConfigDir()
|
||||
seed = "tutti-managed-credentials:" + hostname + ":" + userConfigDir
|
||||
}
|
||||
sum := sha256.Sum256([]byte(seed))
|
||||
return sum[:]
|
||||
}
|
||||
|
||||
func encryptManagedCredential(value string) (string, error) {
|
||||
if value == "" {
|
||||
return "", nil
|
||||
}
|
||||
block, err := aes.NewCipher(managedCredentialKey())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create managed credential cipher: %w", err)
|
||||
}
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create managed credential gcm: %w", err)
|
||||
}
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return "", fmt.Errorf("create managed credential nonce: %w", err)
|
||||
}
|
||||
ciphertext := gcm.Seal(nonce, nonce, []byte(value), nil)
|
||||
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||||
}
|
||||
|
||||
func decryptManagedCredential(value string) (string, error) {
|
||||
if value == "" {
|
||||
return "", nil
|
||||
}
|
||||
raw, err := base64.StdEncoding.DecodeString(value)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("decode managed credential: %w", err)
|
||||
}
|
||||
block, err := aes.NewCipher(managedCredentialKey())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create managed credential cipher: %w", err)
|
||||
}
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create managed credential gcm: %w", err)
|
||||
}
|
||||
if len(raw) < gcm.NonceSize() {
|
||||
return "", errors.New("managed credential ciphertext is malformed")
|
||||
}
|
||||
nonce := raw[:gcm.NonceSize()]
|
||||
ciphertext := raw[gcm.NonceSize():]
|
||||
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("decrypt managed credential: %w", err)
|
||||
}
|
||||
return string(plaintext), nil
|
||||
}
|
||||
Reference in New Issue
Block a user