2 pontos por GN⁺ 2023-09-24 | 1 comentários | Compartilhar no WhatsApp
  • O GitHub Actions é útil em termos de produtividade e funcionalidades, mas na escrita de workflows reais, atrasos na depuração, erros de segurança, ausência de tipagem e falta de ações oficiais levam a perda recorrente de tempo
  • Mesmo pequenas mudanças exigem repetir git add; git commit; git push e checar logs no navegador, e houve caso em que até um workflow simples de release exigiu 4 commits e releases que falharam
  • Expansões ${{... }}, pull_request_target, permissões padrão amplas do GITHUB_TOKEN e referências de SHA de forks são todos pontos de segurança fáceis de errar; em especial, o SHA de fork pode parecer um commit do repositório pretendido
  • Entradas de actions não têm validação com type:, e workflow_call e workflow_dispatch também diferem no escopo de suporte, então é preciso lidar manualmente com strings em estilo CSV ou entradas achatadas em vez de arrays e objetos
  • Validação no momento do push, verificações de segurança em tempo de execução, redução das permissões padrão do token em repositórios pessoais, checagem de tipos mais rígida e mais ações oficiais ou semi-oficiais poderiam aumentar a confiabilidade dos workflows

Útil, mas atrapalha repetidamente no dia a dia com GitHub Actions

  • O GitHub Actions é uma ferramenta que, desde 2019, ajuda muito em produtividade e sensação de estabilidade, a ponto de ser usada todos os dias em projetos profissionais e pessoais
  • A expansão de funcionalidades também continuou de forma constante
  • Ainda assim, no processo real de desenvolvimento, ele também pode ser causa de grande frustração e perda de tempo

Depurar é pesado demais até para erros pequenos

  • Houve um caso em que, ao configurar um workflow de release, foram necessários 4 commits e 4 releases com falha só para corrigir erros pequenos
    • não usar ${{ ... }} onde era necessário
    • esquecer uma relação em needs:
  • O ciclo atual de depuração tem muitas etapas mesmo para verificar um erro simples
    • é preciso sair do ambiente de desenvolvimento e ir para o navegador
    • encontrar a aba correta
    • clicar até entrar no resumo do Actions e na tela de status
    • atualizar logs de console em buffer procurando o próximo erro
  • Mesmo uma mudança pequena pode levar mais de 30 segundos em todo o processo
  • Direções de melhoria

    • Deveria haver um shell de depuração interativo ou, no mínimo, a possibilidade de reexecutar o workflow com pequenas mudanças sem precisar de git add; git commit; git push
    • Configurações do repositório deveriam permitir rejeitar workflows claramente inválidos no momento do push
      • sintaxe que não pode funcionar
      • referência a jobs ou steps inexistentes
      • casos em que um workflow simplesmente não roda por causa de YAML inválido

Erros de segurança acontecem com facilidade demais

  • No GitHub Actions, é fácil um workflow escrito pelo usuário acabar vulnerável sem querer
  • Ao usar expansões ${{ ... }} no shell ou em outros contextos de execução, se o valor expandido vier de entrada controlada pelo usuário, isso pode levar à injeção de código malicioso
    • No exemplo, código pode ser injetado por meio de inputs.frob e vazar $MY_IMPORTANT_SECRET
  • pull_request_target é muito difícil de usar com segurança em workflows que não sejam triviais
    • O caso de uso pretendido parece ser algo restrito, como colocar labels ou comentar em PRs vindos de forks
    • Mas, na prática, ele fica exposto como uma grande armadilha
  • Permissões em nível de workflow e job também tendem a ser configuradas em excesso
    • O acesso padrão do GITHUB_TOKEN comum é muito amplo
    • Em repositórios de contas pessoais, é frequente esquecer de reduzir as permissões padrão do token
    • Sem saber exatamente quais permissões são necessárias, acaba-se concedendo privilégios em excesso
  • O modelo de permissões do GitHub aumenta a confusão ao forçar tudo em um único eixo read/write/none
    • id-token: write permite ler o token OpenID Connect do workflow
    • Algumas operações GET de security advisory exigem permissão write, enquanto outras exigem apenas read

Actions fixadas por SHA podem se confundir com commits de fork

  • Uma referência como actions/checkout@c7d749a2d57b4b375d1ebcd17cfbfb60c676f18e pode, na verdade, não ser um commit do repositório actions/checkout
  • Esse SHA pode ser um commit em um fork dentro da rede de actions/checkout e, por causa do uso de alternates pelo GitHub, parecer pertencer ao repositório pai
  • Texto relacionado da Chainguard divide o problema em três partes
    • referências a SHA de forks e de repositórios de destino não são visualmente distinguíveis
    • a API REST do GitHub em /repos/{user}/{repo}/commits/{ref} retorna um JSON que parece referenciar apenas {user}/{repo}, mesmo quando {ref} existe só em um fork
    • se não for possível distinguir SHAs de fork e não-fork, é possível contornar as restrições de fontes confiáveis do GitHub Actions
  • A resposta do GitHub até agora se limitou basicamente a adicionar um aviso na documentação
  • Direções de melhoria

    • É necessário um modo de segurança paranoica para workflows que rejeite workflows claramente inseguros no momento do push
    • Assim como instrumentações de runtime tipo AddressSanitizer, deveria ser possível falhar um workflow durante a execução ao detectar padrões perigosos para segurança
      • Ex.: falhar se actions/checkout for usado em pull_request_target com uma ref diferente da do repositório de destino
    • Também se pode considerar descontinuar ou remover pull_request_target
    • Mesmo em repositórios pessoais, deveria ser possível configurar escopos padrão do GITHUB_TOKEN de forma mais restritiva, como já ocorre em organizações e empresas
    • Actions fixadas por SHA que não existam no repositório referenciado e existam apenas em um fork deveriam ser rejeitadas por padrão

O sistema de tipos carece de consistência e expressividade

  • Uma GitHub Action customizada pode definir entradas em inputs:, mas entradas de actions não têm imposição de tipo
  • Declarações como type: number não funcionam para entradas de actions
  • Até dentro do GitHub Actions o suporte a tipos é inconsistente
    • workflow_call: suporte a boolean, number, string
    • workflow_dispatch: suporte a boolean, choice, number, string
    • action inputs: sem suporte a tipos
  • Mesmo entradas com suporte a tipos não permitem estruturas compostas, como arrays e objetos
    • não é possível uma entrada de array como paths: [foo, bar, baz]
    • não é possível uma entrada de objeto com hierarquia em headers:
  • Em vez disso, autores de actions acabam exigindo formatos improvisados
    • implementar parsing de CSV manualmente em algo como paths: foo,bar,baz
    • achatar estruturas naturais em algo como header-foo, header-baz
  • Isso não é bom nem para manutenção nem para segurança
    • é preciso gerenciar manualmente um único namespace plano de entradas
    • para entradas complexas, acaba-se criando linguagens ad hoc e não especificadas
  • Direções de melhoria

    • Autores de actions e workflows deveriam poder usar type: em todos os lugares
    • choice também não deveria ficar restrito a workflow_dispatch, mas disponível em todos os contextos
    • Quando for possível inferir tipos estaticamente, mudanças de workflow com tipos inválidos deveriam ser rejeitadas no momento do push
    • É necessário ter type: object e type: array
    • Mesmo que não seja perfeito por permitir tipos internos heterogêneos, ainda seria melhor do que o estado atual
    • Se necessário, isso poderia ser passado como string serializada em JSON
    • O GitHub Actions já tem a função fromJSON(...)

Actions oficiais estão diretamente ligadas à confiança na plataforma

  • O ecossistema de terceiros do GitHub Actions tem muitas actions de alta qualidade
  • Abaixo dele, há as actions oficiais mantidas pelo GitHub
    • operações essenciais de git: actions/checkout
    • tarefas do GitHub e gerenciamento de repositório: actions/{upload,download}-artifact, actions/cache, actions/stale
    • configuração essencial: actions/setup-python, actions/setup-node
  • Essas actions têm alta importância e uso geral, então há muito valor em existirem implementações oficiais e mantidas
  • Mas o número de actions oficiais é pequeno, e há casos em que até tarefas que se conectam diretamente a recursos do GitHub não são oferecidas como action oficial
    • Ex.: uma action para adicionar programaticamente um pull request à merge queue
    • O GitHub CLI tem gh pr merge, mas isso não é exposto como action
  • Casos de actions oficiais descontinuadas

  • Direções para melhorar o ecossistema

    • Tarefas que conectam diretamente diferentes partes da infraestrutura do GitHub, e que hoje exigem chamadas REST API ou execução manual de gh, merecem existir como actions oficiais
    • O GitHub poderia colaborar com grandes actions de terceiros para criar uma organização semi-oficial como community-actions
      • actions revisadas pelo GitHub
      • conformidade com boas práticas de segurança em repositórios
      • atualizações de versão semântica
      • uma trilha de confiança clara para actions importantes do ecossistema

Ferramentas existentes e o roadmap do GitHub

  • Muitas pessoas recomendam o emulador local de GitHub Actions nektos/act
    • ele é útil para iterar e depurar workflows simples com rapidez
    • mas é visto como uma ferramenta com perdas, já que imagens e eventos podem não corresponder totalmente ao ambiente real do GitHub
  • rhysd/actionlint é usado para lint local e lint de segurança
    • uma limitação é que ele só faz lint de workflows e não de actions
  • A extensão GitHub Actions para VS Code oferece lint no editor e integração com workflows do repositório
    • é baseada no schema JSON público
    • mostra workflows em execução, autocompletação de variáveis etc.
    • mas ainda há casos que ela não detecta, como typos em secrets ou em nomes de outputs gerados dinamicamente, então a depuração via add-commit-push ainda é necessária
  • Julian Dunn, responsável pela gestão do projeto GitHub Actions, compartilhou algumas funcionalidades em andamento e prioridades
    • a depuração interativa está no roadmap público do GitHub Actions
    • também está no roadmap público o trabalho para sair do pinning por tags e SHA em workflows e avançar para algo mais imutável
    • o GitHub considera prioridade a saúde e a qualidade do ecossistema de actions oficiais, e adota a estratégia de manter um número pequeno delas para conseguir dar manutenção e atenção suficientes a cada uma

1 comentários

 
GN⁺ 2023-09-24
Opiniões no Hacker News
  • Há duas maneiras de usar workflows do GitHub Actions. 1) “Programar” com GitHub Actions, plugando ferramentas do Marketplace até para coisas como enviar e-mails, fazendo o YAML crescer para 500–1000 linhas, cheio de condicionais e difícil de entender
    2) Usar GitHub Actions apenas como “configuração” e ficar perguntando: “dá para empurrar essa complexidade do YAML para um script?”. Se até o envio de e-mail for colocado em um script, o workflow termina com umas 50–60 linhas, e dá para depurar o script localmente, praticamente eliminando aquele ciclo idiota de push-debug-commit. Sempre que entro em uma equipe nova, digo que o 1 é o caminho da loucura e que o 2 é o razoável, mas cerca de metade ainda escolhe o 1. A falta de ferramentas de depuração e o lock-in de fornecedor também viram problemas muito menores quando se escolhe o 2

    • Concordo bastante com essa visão. Quando você não tenta programar o GitHub Actions em YAML e o trata apenas como algo baseado em execução de tarefas, muita dor desaparece
      Ainda assim, muitas vezes não basta empurrar tudo para uma linguagem de programação de verdade. Há casos em que é preciso usar recursos específicos de fornecedor do GHA, explicitar dependências entre jobs ou chamar uma REST API que já está bem abstraída como uma action. É possível reimplementar na linguagem que você quiser, mas isso não elimina a dependência do fornecedor e continua sendo frágil. No fim, a proposta de valor do lock-in de fornecedor do GHA é muito forte, então é preciso ter vantagens mais fortes para convencer as pessoas a seguirem a opção 2
    • A abordagem 2 também facilita para o desenvolvedor executar o build localmente. Você passa a usar a mesma cadeia de build na depuração local e nos ambientes de teste/staging/produção, sem precisar manter procedimentos de build diferentes
      Isso vale não só para o GHA, mas para qualquer servidor de build. O servidor de build deve ser um executor de scripts que adiciona histórico, gestão de artefatos, permissões/auditoria, enquanto o processo real de build deve ser delegado ao repositório que está sendo buildado
    • Boa perspectiva. Mas, para automatizar o próprio GitHub, por exemplo em tarefas como atribuição de papéis ou marcação com tags, a opção 1 é difícil de evitar. Mesmo assim, hoje eu preferiria fazer boa parte disso manualmente a passar pelo ciclo horrível de depuração do GHA
      Como referência, existe o nektos/act, que tenta reproduzir localmente o comportamento do GHA: https://github.com/nektos/act
    • Fico curioso sobre como se depuram actions. É absurdo gastar tanto tempo no loop commit-action-debug-change. Concordo totalmente que a abordagem 2 torna a depuração de scripts muito mais fácil. CI deve ser executável localmente, mas o GitHub Actions, mesmo com algumas ferramentas, não é fácil de usar assim
    • O principal motivo para buscar a opção 2 é poder rodar builds localmente mesmo se o GitHub cair e, se necessário, mover tudo para outro lugar com facilidade
      Build/testes/assinatura/deploy etc. devem ser escritos como scripts o mais portáveis possível, e esses scripts devem sempre funcionar localmente. Vejo o GitHub apenas como algo que prepara automaticamente o ambiente para executar esses scripts e de fato os executa
  • O loop de git commit, push e wait é uma experiência de usuário horrível. Os usuários merecem pipelines portáveis que rodem em qualquer lugar, inclusive na máquina local. O Act resolve esse problema até certo ponto, mas em geral não representa fielmente o ambiente real
    Muitos pipelines não podem ser executados localmente como em produção, mas, em estágios de desenvolvimento menos críticos, não há motivo para não capturar esses workflows e executá-los localmente. O Garden oferece pipelines portáveis e acrescenta cache em todo o grafo de dependências. Alguns clientes reduziram o tempo de execução em mais de 80%, e os desenvolvedores veem imediatamente se os testes passaram ou falharam sem precisar dar push primeiro para o git. É open source: https://github.com/nektos/act, https://docs.garden.io

    • Se as pessoas, em vez de socar scripts bash dentro das actions, fizessem as actions apenas chamarem make ou scripts bash, esse problema não existiria. CI/CD e desenvolvedores devem usar os mesmos alvos/comandos, como make release
    • Parece que perdemos muito do princípio de que “CI não deve ser especial como um floco de neve” quando começamos a criar equipes especializadas em DevOps e ferramentas de DevOps. No momento em que algo vira uma profissão, sinto que se chega ao ponto de inflexão em que aquilo fica excessivamente complexo. Vejo o mesmo fenômeno no Agile com A maiúsculo e em scrum masters que precisam preencher o tempo
    • Já acabei investigando o lugar errado várias vezes por causa das imperfeições do Act. Por enquanto voltei ao loop antigo e espero que melhore com o tempo
    • Pipelines de build também precisam de algo como Terraform. Se você usa Bitbucket, que Deus ajude
    • A landing page do garden.io aparece quebrada no iOS. Ela transborda para a direita da tela
  • Concordo totalmente com a dor de depurar execuções do GH Actions. A única ferramenta disponível é ativar o debug e executar de novo. Acabo com um monte de commits lixo criados só para corrigir ou depurar pipelines, e a maioria é basicamente jogar coisas para ver se funciona
    Mesmo algo bem básico, como lógica reutilizável, é desnecessariamente complexo ou mal documentado. Depois que você descobre, é até fácil, mas a documentação do GitHub era péssima. Parecia que, para ter reutilização, era preciso tornar uma action pública ou colocá-la em outro repositório, mas na prática dá para criar um novo arquivo YAML com a lógica reutilizável. Só que ele precisa ficar na raiz da pasta workflows para funcionar. Trabalhar com GH Actions é realmente doloroso, mas, depois que funciona, é muito conveniente. Seria bom ter algo como um runner local para testar actions antes de commitar e dar push

    • Uma forma de lidar com isso é usar draft PRs. Dá para executar mudanças no YAML da action em um draft PR e, quando estiver satisfeito, fazer squash dos commits de forma adequada no PR de merge real, sem levar a bagunça junto. Para depurar ou desenvolver lógica de GH Action, draft PRs funcionaram bem
    • Não faz tudo, mas existe uma ferramenta bem útil: https://github.com/nektos/act
    • Quando estou consertando CI, sempre subo em uma feature branch e, no fim, faço squash merge. Quase nunca é uma correção rápida de uma vez só; sempre acaba virando de 3 a 10 commits
    • Já tentei executar imagens do GitHub runner, ou imagens que as imitavam, mas a configuração e o comportamento de alguns recursos eram dolorosos demais. Desisti depois de dois dias
      Isso não é um problema só do GitHub. Outras grandes plataformas de CI também não são muito melhores em termos de workflows e integrações. Hoje tento colocar tudo em scripts tanto quanto possível
    • Esse é o principal motivo pelo qual criamos o Earthly: executar builds localmente e obter consistência com o CI
  • GitHub Actions é um sistema de CI/CD péssimo. Ele não permite executar etapas em paralelo na mesma VM, e trabalhos baseados em contêiner são tratados como cidadãos de segunda classe
    Por causa do primeiro problema, não dá para paralelizar a configuração de credenciais locais ou dependências de ambiente. Dá raiva ver google-github-actions/setup-gcloud levar mais de um minuto. Por causa do segundo problema, é muito difícil expressar a configuração do ambiente de CI com um Dockerfile dentro do repositório, fazer o CI reconstruir a imagem quando o conteúdo dela muda e deixar workflows que dependem dessa imagem aguardando, e, quando o conteúdo não mudou, não reconstruir e executar imediatamente com as dependências já instaladas. No GitHub Actions, você acaba tentando repopular o cache todas as vezes. O cache tem limite de 5 GB, não dá para aumentar nem pagando, e é descartado em FIFO, então, se passar de 5 GB, na prática é como se não existisse. Sinto muita falta do Concourse. Ele permitia jobs paralelos, triggers de pipeline personalizados, entrar por SSH no ambiente de CI para depurar, executar tarefas pontuais sem pipeline, passar o conteúdo de diretórios entre jobs sem criar artefatos, e coisas assim. GitHub Actions está mais para um CI/CD de brinquedo que ficou popular pela facilidade de começar — basta colocar um arquivo em .github/workflows e usar. É bom para atrair usuários, mas, depois dos recursos iniciais, não é poderoso o suficiente para ser chamado de “o melhor”

    • Por causa do limite de cache de 5 GB, agora talvez eu consiga investigar aquele problema de “cache de build quebrando de forma estranha”. Obrigado por avisar
    • Concourse é excelente. Eu não sabia que a equipe tinha sido desfeita, que pena. A forma de comunicação do Zito também era ótima
    • Acho que foi mais o VMWare, depois da aquisição, que o desfez, e não a Pivotal. Havia muita gente internamente que gostava do Concourse. Mas eu saí antes da aquisição
      Debug por SSH e tarefas pontuais eram um sonho
    • Você chegou a ver o Tekton? https://tekton.dev/
    • Já existe uma solução que considera muitos desses problemas. Gostaria de ouvir algumas opiniões. Se puder compartilhar seu e-mail ou entrar em contato pelo lawnchair@lawnchair.net, seria ótimo
  • Não entendo como ainda não resolveram o fato de o GitHub não conseguir distinguir referências SHA de forks e de não forks, permitindo que um fork contorne as configurações de segurança do GitHub Actions
    Se controles de segurança podem ser facilmente burlados, isso é uma questão de segurança grave. É verdade que você precisa convencer alguém a usar o seu SHA, mas engenharia social geralmente é a parte fácil

  • Sinceramente, chega a dar vergonha de tão ruim. Também é estranho que falhas de build não relacionadas notifiquem, por acaso, apenas o maintainer mais recente que fez merge por último. Eu poderia nem saber que minha atualização/build estava falhando havia uma semana até um maintainer recém-adicionado me avisar no Matrix
    A cache action está visivelmente quebrada, e parece não ter mantenedor. Se a UI quebra ou a aba é descarregada, você nem consegue acompanhar em tail os logs de build de uma etapa. Praticamente não há abstrações para tornar workflows portáveis entre nós de trabalho. As imagens padrão são quase um desastre. No começo eu achava apenas irritante por serem inchadas demais, mas, quanto mais investigava, mais pensava: “isso ficou nas mãos de alguém da Microsoft que não entende Linux”. Não há esforço para oferecer imagens mais leves para quem usa Nix ou Docker. Estou saindo do GitHub, e o principal motivo é que o Actions me fez acordar para a realidade. O motivo de eu não programar em YAML é que vejo YAML como uma desonra criada por dinheiro de VC despejado sobre um ecossistema que não conhece tecnologias modernas e realmente úteis

    • Quando a Microsoft comprou o GitHub, não era meio óbvio que algo assim aconteceria?
  • Recomendo fortemente https://pre-commit.ci. Não tenho ligação com eles; sou apenas um usuário satisfeito
    A ideia é escrever hooks, ou usar hooks existentes, que verificam o código antes do commit e, quando possível, o corrigem; depois do push, o CI verifica de novo e, se necessário, até faz commits automáticos com as correções. O cache automático é tão bom que chega a ser difícil acreditar na velocidade, e como a mesma configuração é usada na máquina de desenvolvimento local e no CI, muitos problemas de depuração são reduzidos. É gratuito para open source. Ele não faz coisas como releases automáticos, só verificações, mas faz isso muito bem

    • Em projetos Python, é especialmente bom usar isso junto com tox. O tox cria um virtualenv de acordo com a versão do Python que você quer testar e executa os testes dentro dele
      Para verificar o próprio código-fonte, também dá para rodar análises estáticas com skip_install = True. Basta executar em um contêiner que tenha o tox instalado como ferramenta global e todas as versões necessárias do Python. Por exemplo, há uma imagem como https://github.com/georgek/docker-python-multiversion. Ela não é mantida, mas é fácil de atualizar. Um boilerplate com algo como [tox] envlist = py{310,311}, [testenv] e, em [testenv:check], pre-commit run --all-files --show-diff-on-failure já é suficiente
  • Depois de passar vezes demais pelo loop git commit; git push; repeat, encontrei https://github.com/mxschmitt/action-tmate. Ele abre um acesso shell entre as etapas, então não resolve todos os problemas, mas às vezes reduz bastante o sofrimento

  • Pessoalmente, eu gostaria de poder anexar relatórios HTML a uma action run sem precisar usar algo como actions/upload-artifact
    Especialmente em builds de teste, muitas vezes quero ver rapidamente o relatório HTML gerado. As formas que conheço hoje são upload-artifact ou GH Pages, mas GH Pages não é muito bom quando há várias saídas de relatório no mesmo repositório ou quando você quer ver rapidamente um relatório antigo, não o mais recente. Seria bom ter uma action simples, tipo attach-report, que adicionasse um link para o relatório HTML ao resumo do job e renderizasse o HTML ao clicar. Outros sistemas automatizados de CI/CD oferecem, por padrão, suporte muito mais rico para capturar e visualizar relatórios HTML

    • Não é HTML, mas é possível adicionar saída em Markdown diretamente a $GITHUB_STEP_SUMMARY, sem passar por upload de artefatos ou coisas do tipo
  • Vejo o GH Actions, na prática, como algo bem próximo de um rebranding do “Azure Pipelines” da Microsoft. Como alguém que já usou todas as formas anteriores dos pipelines de build e release do TFS/VSTS/AzDO, essa equipe não é boa nisso
    O Azure Pipelines só ficou minimamente utilizável porque todas as abordagens tentadas antes literalmente falharam. Também houve um projeto para executar pipelines localmente, permitindo um loop edit-run-debug em um ambiente pessoal sem commits, mas é claro que foi cancelado: https://github.com/microsoft/azure-pipelines-agent/pull/2687/files#diff-570b52bcb927a5365c22d17a21e8e19e1ba3427c7f3ec16ea64b7b3d14e4ee20. Ainda assim, há ferramentas que melhoram a qualidade de vida. Por exemplo, uma extensão do VS Code que reconhece a sintaxe: https://marketplace.visualstudio.com/items?itemName=ms-azure-devops.azure-pipelines. Para dizer algo um pouco polêmico: se tivessem usado XML em vez de YAML, apenas a declaração xmlns no topo já permitiria validação na maioria dos bons editores de código, sem intervenção adicional do usuário. XML é horrível, mas ao descartá-lo por completo também perdemos muitos recursos úteis junto

    • Eu entendia que o GHA era um projeto que já estava avançando de forma independente dentro do GitHub antes da aquisição pela Microsoft. Fico curioso se isso quer dizer que o GHA foi recriado sobre o AzP, se simplesmente deram um novo nome ao AzP, ou se significa outra coisa
    • É mais provável que seja mais assim do que a maioria imagina. Depois da aquisição, uma parte considerável da equipe do AzDo foi transferida para trabalhar no GitHub Actions/Projects
    • Eu concordava até o último parágrafo. XML machuca os olhos. Em vez do terror de colchetes angulares e camelCase, eu ficaria com um documento YAML bem formatado, ainda que haja algum sofrimento