Manter metadados fora do código executável

ShellBeginner
Pratique Agora

Introdução

Um colaborador propõe uma alteração de código com título e descrição. Uma tarefa de compilação transforma esses metadados em um artefato de prévia. Integração contínua (CI) significa executar tarefas assim automaticamente quando chegam alterações. Um executor é o programa que realiza a tarefa. Aqui você inicia por conta própria um pequeno executor local fornecido.

Todas as pessoas e eventos são sintéticos. O executor usa Bash real em um contêiner descartável, sem rede nem credenciais de implantação. production em release.conf é um valor local de teste: não implanta nada. O exercício modela substituição de texto e execução do shell, não gatilhos ou permissões de uma plataforma hospedada. O terminal CI Workshop é seu espaço de manutenção; Topology explica o fluxo e mostra os canais reais ao atualizar a página.

Você executará uma compilação normal, rastreará uma injeção, editará dois arquivos curtos e testará novamente a preservação exata dos metadados. Basta familiaridade básica com o terminal; o JSON e a sintaxe Bash necessários são ensinados antes do uso.

Executar uma compilação normal

Nesta etapa, você verá o resultado esperado antes de investigar: o título exato do colaborador vira um artefato e o canal permanece preview.

Selecione a aba CI Workshop na interface do laboratório para começar esta etapa.

Mude para a aba CI Workshop. pwd exibe o diretório atual; ls lista seus arquivos. O espaço de trabalho é /home/labex/project/ci-workshop.

Mude para a aba CI Workshop antes de executar o comando a seguir.

pwd
ls

cat exibe um arquivo de texto. Um objeto JSON usa chaves ao redor de campos nomeados; dois-pontos ligam o nome ao valor. Strings JSON usam aspas duplas. Dentro delas, \n representa uma quebra de linha. Leia o evento normal:

cat events/ordinary.json

Seu title é Improve search results. body é uma descrição com várias linhas. Esses valores vêm de um colaborador e são dados; a compilação não deve confiar neles como comandos.

Leia a pequena definição da tarefa e seu script:

cat job.json
cat build.sh
Item Significado neste executor local
script Arquivo Bash a executar, atualmente build.sh
env Mapeamento de nomes de ambiente para strings; agora vazio {}
{{event.title}} Substituir este marcador exato pelo título antes de iniciar Bash
{{event.body}} A mesma substituição para a descrição
artifact.txt Arquivo de metadados criado pela compilação
release.conf Canal inicializado como preview a cada execução

Bash lê instruções do shell. TITLE="..." atribui uma variável; não coloque espaços ao redor de =. "$TITLE" expande o valor como um único argumento e preserva espaços e quebras de linha. printf '%s' escreve uma string sem adicionar uma quebra; as aspas simples mantêm %s literal. > redireciona a saída para um arquivo, substituindo o conteúdo anterior. O ponto e vírgula separa comandos. set -euo pipefail interrompe o script em falhas comuns de comandos, variáveis indefinidas e pipelines; isso não impede injeção.

ci é o comando do executor fornecido. run recebe um evento sem .json e um novo nome de diretório de saída. Toda execução começa com uma configuração preview nova:

ci run ordinary first

Espere channel=preview e exit=0. Código zero indica que Bash terminou com sucesso. Inspecione script gerado, artefato e configuração com show:

ci show first

O artefato aparece como string JSON, "Improve search results", permitindo representar quebras invisíveis mais adiante. É o conteúdo real do arquivo, não um sinal simulado de sucesso. A seção final deve mostrar preview. Mude para a aba Topology e atualize: a linha first lê esse mesmo arquivo.

Repetir run com first causa intencionalmente um erro de diretório existente para não sobrescrever evidências antigas. Escolha outro nome, como first-again. Uma execução com falha também mantém o script gerado e build.log em runs/NAME para diagnóstico.

Rastrear a substituição perigosa

Nesta etapa, você observará dados virarem código executável e alterarem o canal dentro de uma demonstração isolada.

Selecione a aba CI Workshop na interface do laboratório para começar esta etapa.

O fluxo é evento → tarefa → código shell gerado → Bash → artefato. O momento perigoso é a substituição antes de Bash analisar as aspas. Aspas duplas protegem expansão de variável em um comando já analisado; não protegem um valor bruto inserido no código antes da análise.

Leia o evento de demonstração inofensivo fornecido:

Mude para a aba CI Workshop antes de executar o comando a seguir.

cat events/hostile.json

O title contém aspas duplas, ponto e vírgula, printf, outro ponto e vírgula e #. Em Bash, a aspa termina a string original, o ponto e vírgula inicia outro comando e # comenta o restante da linha. Esse printf altera apenas o release.conf sintético desta execução. O \" de JSON codifica uma aspa, mas não a torna segura ao inseri-la depois em código shell.

Execute o evento em um espaço novo:

ci run hostile demo
ci show demo

Espere channel=production, embora o executor tenha inicializado preview. Encontre o printf inserido entre os pontos e vírgulas em generated.sh: Bash realmente o executou. O artefato pode conter apenas Update, pois o restante virou sintaxe em vez de dados do título. Esse é o defeito a reparar.

demo é separado de first, e nenhuma execução altera job.json ou build.sh. Mude para a aba Topology e atualize a página para comparar os canais reais. Uma linha production significa um exemplo modificado, nunca uma publicação real. Não execute o texto do evento manualmente no shell de manutenção.

Topology comparando os canais da execução normal e da demonstração vulnerável

O risco geral é documentado na explicação do GitHub sobre injeções de scripts. Nossos marcadores e formato são deliberadamente menores que GitHub Actions; o mecanismo comum é substituir antes de analisar.

Passar o valor como dados

Nesta etapa, você manterá o texto fora do código shell e preservará espaços, aspas e várias linhas.

Selecione a aba CI Workshop na interface do laboratório para começar esta etapa.

Uma variável de ambiente é uma string nomeada entregue a um novo processo. O mapeamento env pode defini-la diretamente, sem gerar uma atribuição shell. Em JSON, um mapeamento é outro objeto entre chaves. Defina BUILD_TITLE a partir de {{event.title}} e deixe Bash expandir "$BUILD_TITLE" durante a execução. Bash não reinterpreta aspas, pontos e vírgulas, $() ou acentos graves dentro do valor expandido como novos comandos. Não use eval nem passe o valor para bash -c: isso faria outra análise.

Substituiremos dois arquivos com here-documents. cat > filename <<'JSON' escreve as linhas seguintes até uma linha contendo apenas JSON. O delimitador entre aspas impede o shell de manutenção de expandir $ ou outra sintaxe. Copie o bloco inteiro, incluindo o delimitador final. Como substitui todo o arquivo, também permite recuperação após erros de digitação.

Mude para a aba CI Workshop antes de executar o comando a seguir.

cat > job.json <<'JSON'
{
  "script": "build.sh",
  "env": {
    "BUILD_TITLE": "{{event.title}}"
  }
}
JSON

Agora substitua o script. O delimitador BASH tem o mesmo papel de escrita literal. O script usa diretamente a variável de ambiente e não contém marcador do colaborador.

cat > build.sh <<'BASH'
set -euo pipefail
printf '%s' "$BUILD_TITLE" > artifact.txt
printf 'channel='; cat release.conf
BASH

Leia os dois arquivos novamente com cat. Uma vírgula ou chave ausente causa erro JSON; um nome de ambiente incorreto causa erro de variável indefinida. Reescreva o bloco completo correspondente e tente outra vez. Uma execução antiga reflete o script anterior; use outro nome:

ci run ordinary repaired
ci show repaired

O código gerado agora contém "$BUILD_TITLE", não os caracteres do título. O artefato continua com Improve search results e o canal é preview.

Leia os exemplos de pontuação e várias linhas antes de testar:

cat events/quotes.json
cat events/multiline.json

\n na string JSON representa uma quebra real; o último \n também deve permanecer. O apóstrofo de O'Brien e aspas duplas em um título são dados legítimos. O mesmo mapeamento passa um body com várias linhas: a referência vira {{event.body}}, enquanto a regra de aspas na variável continua igual. Você reutilizará isso nas notas de versão do desafio.

ci test normal executa a tarefa e o script enviados sem modificá-los com eventos normais, de pontuação e várias linhas em diretórios temporários descartáveis. Compara bytes exatos e verifica preview. Exclui apenas esses diretórios, mantendo arquivos enviados e execuções salvas.

ci test normal

Espere uma linha exact metadata; channel=preview por exemplo. Remover pontuação, juntar linhas, fixar um título, rejeitar todos os eventos ou pular a compilação falha neste teste de função útil. A falha identifica o exemplo; leia-o e corrija seus dois arquivos antes de repetir.

Testar novamente o limite da compilação

Nesta etapa, você confirmará que a mesma tarefa corrigida preserva metadados normais e impede o efeito demonstrado.

Selecione a aba CI Workshop na interface do laboratório para começar esta etapa.

Repita o exemplo hostil com um novo nome de saída:

Mude para a aba CI Workshop antes de executar o comando a seguir.

ci run hostile repaired-hostile
ci show repaired-hostile

O artefato deve conter o título hostil inteiro como texto. Pontos e vírgulas e aspas aparecem na representação JSON, enquanto release.conf continua em preview. A evidência antiga de demo não muda, pois pertence a outro espaço.

Outro exemplo contém $() e acentos graves, formas de substituição de comandos quando estão no código shell. Dentro de um valor de ambiente expandido entre aspas duplas, os caracteres continuam sendo dados. Leia o exemplo:

cat events/substitution.json

Execute os cinco casos com os mesmos arquivos enviados:

ci test all

ordinary, quotes, multiline, hostile e substitution devem preservar os metadados exatos e preview, seguidos da mensagem de limpeza. Isso verifica Bash real e arquivos de saída, não uma frase de log ou um resultado inventado secure=true. A verificação de conclusão repete esses testes temporários sem alterar tarefa, script ou execuções salvas.

Se apenas o caso hostil falhar, procure marcadores restantes no script ou nova análise da variável. Se pontuação ou várias linhas falharem, confira printf '%s' com uma variável entre aspas duplas. Não exclua entradas difíceis: preservar metadados legítimos faz parte do objetivo. Mude para a aba Topology e atualize a página para ver repaired-hostile ao lado do demo histórico.

Topology mostrando que a execução corrigida preserva o canal preview

Resumo

Você rastreou metadados pelo executor local até Bash real, reproduziu uma alteração isolada de configuração e reparou o limite com mapeamento de ambiente e expansão entre aspas. Os testes exatos preservaram pontuação, várias linhas e o canal de prévia. Aplique agora o mesmo raciocínio às notas de versão.