# Arquitetura do Sistema O Yby implementa uma arquitetura **GitOps Híbrida**, projetada para oferecer a mesma experiência de desenvolvimento (DX) tanto localmente quanto em produção. --- ## 🏗️ Diagrama de Alto Nível (Local Dev) O mecanismo do `yby up` (contexto local) reside na criação de um "loop fechado" de GitOps dentro do seu computador. ```mermaid flowchart TD subgraph Host ["💻 Seu Computador (Host)"] Dev[Desenvolvedor] Code["Código (IDE)"] CLI["Yby CLI (Watcher)"] end subgraph Cluster ["☸️ Cluster Local (k3d)"] style Cluster fill:#e1f5fe,stroke:#01579b subgraph Infra ["Namespace: yby-system"] GitMirror["📦 Git Mirror (Gitea)"] Argo["🐙 Argo CD"] Sealed["🔐 Sealed Secrets"] end subgraph App ["Namespace: seu-projeto"] Pod["🚀 Pod da Aplicação"] end end Dev -->|Edita| Code Code -.->|File Watch| CLI CLI == Sync ==> GitMirror Argo -- Pull --> GitMirror Argo -- Apply --> Pod Sealed -.->|Decrypt| Pod ``` ### O Componente "Git Mirror" Em vez de esperar você fazer `git push` para o GitHub, o Yby sincroniza as mudanças locais **instantaneamente** para o container `Git Mirror` interno. **Resultado**: Feedback loop de < 5 segundos. --- ## Arquitetura de Criptografia de Segredos O Yby oferece três estratégias para resolver o problema de "Segredos no Git", selecionáveis via `--secrets-strategy` (no `yby init`) ou `--strategy` (no `yby seal`). ### Estratégia 1: Sealed Secrets (criptografia assimétrica) ```mermaid sequenceDiagram participant Dev as Desenvolvedor participant CLI as Yby CLI participant Git as Git Repo participant Controller as SealedSecrets (Cluster) Note over Dev,CLI: Fase de Encriptação (Pública) Dev->>CLI: yby seal CLI->>Controller: Busca Chave Pública (PubKey) CLI->>CLI: Encripta dados com PubKey CLI->>Git: Push sealed-secret.yaml (Seguro) Note over Git,Controller: Fase de Decriptação (Privada) Git->>Controller: ArgoCD aplica SealedSecret Controller->>Controller: Decripta usando Chave Privada (PrivKey) Controller->>Cluster: Cria Secret Nativo (Ouvido pelo Pod) ``` 1. **Chave Pública**: Livre para todos. Desenvolvedores usam para criptografar. 2. **Chave Privada**: Vive APENAS dentro do controlador no cluster. Nunca sai (exceto via Backup de DR). ### Estratégia 2: SOPS + age (criptografia local) ```mermaid sequenceDiagram participant Dev as Desenvolvedor participant CLI as Yby CLI participant Git as Git Repo participant CD as ArgoCD + KSOPS Dev->>CLI: yby seal --strategy sops CLI->>CLI: Encripta com age (chave local) CLI->>Git: Push sops-secret.yaml (Encriptado) Git->>CD: Sync e decripta via KSOPS plugin CD->>Cluster: Cria Secret Nativo ``` Não requer controlador no cluster. A chave age fica no ambiente do desenvolvedor. ### Estratégia 3: External Secrets Operator (provedor externo) ```mermaid sequenceDiagram participant Dev as Desenvolvedor participant CLI as Yby CLI participant Git as Git Repo participant ESO as ESO (Cluster) participant Provider as Vault / AWS / GCP / Azure Dev->>CLI: yby init --secrets-strategy external-secrets CLI->>Git: Push ExternalSecret + ClusterSecretStore manifests Git->>ESO: ArgoCD aplica ExternalSecret ESO->>Provider: Busca secret real ESO->>Cluster: Cria Secret Nativo ``` Os segredos ficam no provedor externo. O ESO sincroniza automaticamente. --- ## ⚡ Arquitetura Event-Driven (Argo Events) Para automações complexas (ex: disparar um training job de ML quando um arquivo chega no S3), o Yby inclui **Argo Events** e **Argo Workflows**. * **Event Bus**: Escuta webhooks (GitHub, Registry, S3). * **Sensor**: Filtra eventos e dispara gatilhos. * **Trigger**: Inicia um Workflow ou Deployment. Isso permite criar pipelines de CI/CD que rodam **dentro** do cluster Kubernetes, economizando custos de Runners externos (GitHub Actions). --- ## 🏢 Arquitetura de Enterprise Overrides (pkg/scaffold/overrides.go) O sistema de overrides parametriza a stack sem alterar templates: ``` yby init --config overrides.yaml | v LoadOverrides(paths...) → EnterpriseOverrides struct | v BlueprintContext.Overrides = &ov | v contextFuncMap(ctx) → template.FuncMap com Resolve* | ├─ .tmpl (Go templates): {{ resolveImage "ubuntu:22.04" }} │ {{ resolveNS "argocd" }} │ {{ resolveIngress "traefik" }} │ └─ values.yaml.tmpl → values.yaml (Helm values) └─ .yaml (Helm templates): {{ .Values.images.kubectl }} {{ .Values.namespaces.argocd }} ``` ### Camadas de Resolução | Função | Lógica | | :--- | :--- | | `ResolveImage(img)` | Override explícito > Registry prefix > Original | | `ResolveNamespace(ns)` | Se prefix: `prefix-ns`, senão: `ns` | | `ResolveStorageClass(fb)` | Se cloud.storageClass: usa, senão: fallback | | `ResolveHelmRepo(url)` | Se helm.repoBaseURL: substitui, senão: original | | `ResolveChartVersion(c,v)` | Se helm.versions[c]: usa, senão: fallback | | `ResolveTLSIssuer(fb)` | Se tls.issuer: usa, senão: fallback | | `ResourceProfile()` | small/medium/large → CPU/Memory values | Todas as funções fazem nil-check — sem overrides, retornam o valor original (backward-compat total). --- ## ☁️ Arquitetura Multi-Cloud (pkg/cloud/) O Yby suporta clusters gerenciados (EKS, AKS, GKE) através de uma camada de abstração multi-cloud com duas estratégias complementares: ### Camadas ``` pkg/cloud/ ├── provider.go → Interface CloudProvider (Name, IsAvailable, CLIVersion, ListClusters, ConfigureKubeconfig, ValidateCredentials, RefreshToken) ├── detect.go → Detecção automática do provider via kubeconfig context ├── aws.go / azure.go / gcp.go → Implementações CLI-first (via shared.Runner, zero deps externas) ├── aws_token.go / azure_token.go / gcp_token.go → Token generators SDK (build tags aws/azure/gcp) ├── *_token_stub.go → Stubs CLI fallback quando build tag ausente ├── token_cache.go → Cache in-memory thread-safe com TTL e margem 60s └── token_refresh.go → AutoRefreshTransport (http.RoundTripper) ``` 1. **Camada CLI-first**: Cada provider (aws.go, azure.go, gcp.go) usa `shared.Runner` para invocar os CLIs nativos (`aws`, `az`, `gcloud`). Zero dependências externas — funciona em qualquer máquina com o CLI instalado. 2. **Camada SDK (build tags)**: Arquivos como `aws_token.go` (build tag `aws`) usam SDKs nativos para gerar tokens com melhor performance. Quando a build tag não está presente, stubs (`*_token_stub.go`) fazem fallback para a camada CLI. 3. **Auth avançada (build tags)**: `aws_auth.go` (tag `aws`), `azure_auth.go` (tag `azure`), `gcp_auth.go` (tag `gcp`) implementam métodos enterprise de autenticação — SSO/MFA/IRSA (AWS), device code/interactive/cert/MSI (Azure), WIF/SA impersonation/Connect Gateway (GCP). Stubs correspondentes para fallback CLI. ### AutoRefreshTransport O `AutoRefreshTransport` é um `http.RoundTripper` que intercepta respostas 401 e renova credenciais automaticamente: ``` Requisição HTTP → Cluster responde 401 → mutex.Lock() (serializa refreshes concorrentes) → Invalida cache do token → Gera novo token via CloudProvider → Retry da requisição original com novo BearerToken → mutex.Unlock() ``` ### TokenCache Cache in-memory thread-safe para tokens cloud. Usa uma **margem de 60 segundos** antes da expiração real para evitar race conditions — o token é considerado expirado 60s antes do TTL oficial. ### Integração com KubeClient Em `GetKubeClient()`, quando o ambiente tem `Cloud != nil`: - Injeta `BearerToken` na rest.Config - Injeta `WrapTransport` com `AutoRefreshTransport` para refresh automático ### Credential Store (`credential_store.go`) Armazenamento seguro de tokens cloud de longa duração (ex: SSO sessions): - **Keychain nativo**: via `go-keyring` (macOS Keychain, Linux secret-service/kwallet, Windows Credential Manager) - **Fallback encriptado**: arquivo `~/.yby/credentials.enc` com AES-256-GCM e chave derivada de passphrase - Thread-safe, operações `Store`, `Retrieve`, `Delete` ### Audit Log (`audit.go`) Log JSONL de operações de autenticação cloud em `~/.yby/audit.log`: - Registra: provider, método de auth, cluster, identidade, timestamp, resultado - Rotação automática em 10MB - Consulta via `yby cloud audit [--since DURATION] [--export json|csv] [--provider P]` ### AuthConfig Struct `AuthConfig` em `CloudConfig` configura método de autenticação avançada: - `method` — sso, assume-role, web-identity, mfa - `sso_start_url`, `sso_region`, `sso_account`, `sso_role_name` — campos SSO AWS - `mfa_serial` — ARN do dispositivo MFA Campos adicionais em `CloudConfig` para GCP: `service_account`, `credentials_file`, `fleet_membership`. --- ## 🧩 Arquitetura de Plugins (pkg/plugin/) Plugins são binários separados (`yby-plugin-`) que conversam com o core por JSON. O core os descobre a cada execução e registra cada um como subcomando (`yby sentinel`, `yby viz`...). ``` yby [-c ambiente] [args do plugin] | v Discover: ~/.yby/plugins, depois ./.yby/plugins (mesmo nome: vale o primeiro achado) | roda o hook manifest só dos confiáveis; o não confiável entra pelo nome do arquivo v Contexto do command (barato e/ou caro, abaixo) | ambiente pedido que não existe → ERR_CONFIG_INVALID v RunInteractive: 1. Confiança: SHA-256 do binário confere com ~/.yby/plugins/trusted.json? não → ERR_PLUGIN (confie com yby plugin trust ) 2. pedido em YBY_PLUGIN_REQUEST, caminho do core em YBY_BIN, TTY ligado ``` ### Hooks | Hook | Uso | | :--- | :--- | | `manifest` | Nome, versão, descrição, hooks e `consome_contexto`, dentro de `data`. Lido na descoberta, a cada `yby`, só dos plugins confiáveis. | | `context` | O plugin **fornece** dados (o Atlas dá o blueprint, o Synapstor o estado do índice lido de `.synapstor/.index/manifest.json`). O `yby init` junta as respostas. | | `command` | Execução interativa, quando o usuário chama `yby `. | | `assets` | Pasta de templates que o `yby init` põe por cima dos do core no scaffold. | O `Run()` manda o pedido pelo STDIN e lê a resposta JSON no STDOUT. O `RunInteractive()` passa o pedido na variável `YBY_PLUGIN_REQUEST` (ou, grande demais para uma variável, num arquivo apontado por `YBY_PLUGIN_REQUEST_FILE`) e liga o terminal ao plugin. ### Contexto do `command` Declarar o hook `context` é fornecer contexto, não consumir. O que chega ao `command` depende de duas coisas: | Contexto | O que leva | Quando vai | | :--- | :--- | :--- | | **Barato** | `project_name` (nome da pasta), `environment`, `infra` (`kube_config` resolvido, `kube_context`, `namespace`) e `values` do ambiente pedido no `.yby/environments.yaml`, sem rodar nada | A todo plugin, só quando o ambiente foi pedido: `-c`/`--context` antes do nome do plugin ou `YBY_ENV` | | **Caro** | Overview (ou o `README.md`) e backlog do `.synapstor` e os hooks `context` dos outros plugins | Só a quem declara `"consome_contexto": true` no manifesto | * Sem ambiente pedido e sem `consome_contexto`, o plugin abre direto, sem contexto. O `current` do `environments.yaml` não conta. * Ambiente pedido que não existe é `ERR_CONFIG_INVALID`; flag antes do nome do plugin que não é do core é `ERR_VALIDATION`. Depois do nome, toda flag é do plugin. * Args com `-h`/`--help` abrem a ajuda sem contexto nenhum. * Nenhum plugin nativo declara `consome_contexto`: o Bard pega o blueprint pela ferramenta `atlas_blueprint`, não pelo contexto. ```json { "data": { "name": "meu-plugin", "version": "1.0.0", "hooks": ["command"], "consome_contexto": true } } ``` ### Confiança * **Binários**: o `yby plugin install` registra o SHA-256 do binário em `~/.yby/plugins/trusted.json`; um plugin copiado à mão (inclusive em `./.yby/plugins`, que um repositório clonado pode trazer) só abre pelo `yby ` depois de `yby plugin trust `, e os hooks `context` que o `yby ` junta para quem consome contexto passam pela mesma verificação. Se o binário mudar, o checksum não bate e o core recusa. A descoberta também confere: o `manifest` só roda nos confiáveis (pelo carimbo de caminho, tamanho e mtime que o registro guarda, sem recalcular o hash a cada `yby`), e o não confiável entra com um manifesto sintético, pelo nome do arquivo e só com o `command`, que cai na verificação do executor. O `yby plugin` e o `yby init` usam a mesma verificação; o init pula os hooks dos não confiáveis e avisa. O registro é gravado num temporário e trocado por `Rename`. * **Arquivos do projeto**: `.yby/tools/*.yaml` (ferramentas do Bard) e `.yby/prompts/*.txt` só valem depois de `yby plugin trust `, que guarda o SHA-256 em `~/.yby/trusted-files.json`. Se o arquivo mudar, a confiança cai. * **Plugin chamado por plugin**: o Bard só roda o Sentinel e o Atlas que passam pela mesma verificação; sem ela, o `/ferramentas` mostra "não confiável · rode yby plugin trust ". ### Plugin que abre plugin (`YBY_BIN`) O `RunInteractive()` passa em `YBY_BIN` o caminho do executável do core. O `b` do Viz roda `$YBY_BIN bard --pergunta "…" --voltar Viz --context … --namespace …` (sem `YBY_BIN`, o `yby` do PATH): a chamada passa de novo pelo core e pela verificação de confiança. O Viz volta quando o Bard fecha pelo esc; o ctrl+c faz o yby sair com 130 e fecha o Viz também (no Windows, o core troca o código do ctrl+c por 130). --- ## 🧠 Arquitetura de IA (pkg/ai/) O sistema de IA do Yby usa uma **cadeia de decorators** (pattern Middleware) que envolve cada provider com camadas de funcionalidade: ``` Raw Provider (Ollama/OpenAI/Gemini/Bedrock) → CachedEmbeddingProvider (cache LRU de embeddings) → TokenAwareProvider (validação de context window) → CostTrackingProvider (logging de uso e custo) → RateLimitProvider (token bucket + circuit breaker) → RetryProvider (retry com backoff exponencial) ``` Os providers CLI (`claude-cli` e `gemini-cli`) passam só por `TokenAwareProvider` (com a janela do CLI) e `RetryProvider`: não geram embeddings, não informam uso de tokens e não devolvem erro HTTP. Falha do CLI que não adianta repetir (não autenticado, modelo inexistente) volta na primeira tentativa. ### Funcionalidades por Camada | Camada | Responsabilidade | Configuração | |--------|-----------------|--------------| | **Cache** | LRU com 1000 entries e TTL 1h para embeddings. Evita chamadas redundantes. | Automático | | **Token Aware** | Valida se o prompt cabe no context window (~4 chars/token). Rejeita se > 90%. | `knownModels` em tokencount.go | | **Cost Tracking** | Extrai `usage` das respostas OpenAI/Gemini. Loga via `slog.Info("ai.usage")`. | Automático | | **Rate Limit** | Token bucket + circuit breaker (abre após 5 erros 5xx, cooldown 30s). Respeita `Retry-After`. | `ai.rate_limit.requests_per_second` | | **Retry** | Backoff exponencial para erros 429/502/503. | `retry.DefaultOptions()` | ### Amazon Bedrock (build tag `aws`) O provider Bedrock é registrado via `init()` em `bedrock_factory.go`, usando o sistema de `registeredProviders` que permite registro condicional via build tags. Quando compilado com `-tags aws`: - **Completion/StreamCompletion**: Usa a Converse API (`Converse` e `ConverseStream`) para compatibilidade com múltiplos modelos (Claude, Titan, etc.) - **Embeddings**: Usa `InvokeModel` sequencial com modelos Titan Embeddings - **Prioridade**: Na cadeia de auto-detect, Bedrock fica após OpenAI: Ollama → Claude CLI → Gemini CLI → Gemini API → OpenAI API → Bedrock ### Vector Store O `VectorStore` (ChromemDB) suporta: `AddDocuments`, `Search`, `DeleteDocuments`, `DeleteByMetadata`, `Count`. Ao lado da coleção, grava em `identidade.json` com que embeddings o índice foi feito; `Conferir` diz se o provider ou o modelo mudou, sem gerar embedding, e `Recriar` apaga o índice para refazê-lo. ### Índice do Synapstor O `yby synapstor index` guarda o índice em `.synapstor/.index/`, com o manifest em `.synapstor/.index/manifest.json` (SHA-256 e número de trechos por arquivo): * **Trechos**: cada arquivo é partido pelas seções `##` (o texto antes da primeira também vira trecho), e seção longa vira mais de um trecho (IDs `caminho#n`, com `n` o número do trecho). Arquivo novo ou alterado tem os trechos antigos apagados (`DeleteByMetadata`) antes dos novos entrarem; arquivo removido sai do índice. * **Refazer do zero**: o `index` apaga e recria o índice com `--full`, quando os embeddings mudaram (outro provider ou modelo) e quando o índice não bate com o manifest. A busca e o Bard, diante de um índice de outro modelo, avisam "rode yby synapstor index --full". * **Trava**: dois `index` ao mesmo tempo no projeto são barrados por `.synapstor/.index/index.lock`. * **Embeddings**: Ollama, se estiver rodando; senão Gemini ou OpenAI configurados em `ai.embedding`; senão o modelo local paraphrase-multilingual-MiniLM-L12-v2 em int8 (entende português), baixado no primeiro uso para `~/.yby/models`. Os providers CLI não geram embeddings. ### Ollama Batch Embeddings Usa `/api/embed` (batch nativo, Ollama v0.5+), um texto por chamada, porque um UKI inteiro pode passar da janela do modelo. Fallback automático para `/api/embeddings` (sequencial) em versões antigas. --- ## 📊 Telemetria e Observabilidade O Yby coleta métricas de execução (nome, duração, sucesso/falha, timestamp) para cada comando. Os dados são: 1. Logados via `slog.Debug` para diagnóstico em tempo real. 2. Persistidos em `~/.yby/telemetry.jsonl` com rotação automática (5MB, 1 backup). 3. Exportáveis via `yby telemetry export`. A coleta respeita `telemetry.enabled` em `~/.yby/config.yaml` (ou `YBY_TELEMETRY_ENABLED=false`). --- ## 🛡️ Segurança (Hardened by Default) ### 1. Segredos em RAM (RAM-Only Secrets) Segredos são montados em `/run/secrets` (tmpfs), nunca tocando o disco e inacessíveis via `docker inspect`. ### 2. Isolamento de Rede * **Deny Ingress Padrão** no namespace `infra`. * Apenas pods autorizados podem falar com bancos de dados. ### 3. GitOps & Imutabilidade O ArgoCD reverte automaticamente alterações manuais (Self-Heal). O Git é a única fonte de verdade.