You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Como operador da coleta, eu quero descobrir quais repositórios mudaram desde a última análise por um
workflow que eu possa despachar, para saber o tamanho do trabalho antes de clonar qualquer coisa.
Acceptance criteria
scripts/iris-cycle.sh — a descoberta
Query GraphQL devolve, para 100 repositórios de uma vez, o pushedAt da organização
git ls-remote --heads por repositório monta o digest de refs, sem clonar e sem consumir cota de API
16 leituras em paralelo (medido: 29,7 s para 608 repositórios, sem uma rejeição); 8 declarado como fallback
O digest segue o contrato, exatamente: v1:$(git ls-remote --heads "$URL" | LC_ALL=C sort | sha256sum | cut -d' ' -f1)
Falha ao montar o digest salta o repositório, conta a falha e segue — analisar sem poder gravar
o watermark deixaria aquele repositório pendente para sempre
Ao final, imprime o retrato de refs da organização — repositório, pushedAt e digest — mais
as falhas. Não clona, não analisa, não faz push, e não compara contra o watermark: dizer o que
está pendente exige a rota de leitura do watermark, e isso é trabalho da issue de seleção.
.github/workflows/iris-ingestion-worker.yml
on: workflow_call como único gatilho — sem schedule, sem push, sem workflow_dispatch
Checkout do próprio commit por job.workflow_repository + job.workflow_sha
Token do App cunhado dentro do job que o usa, com owner: inputs.organization || github.repository_owner
Clone via credential.helper lendo do ambiente — nunca token embutido na URL do remote
Todo uses: pinado por SHA de commit
O quatro escolhas do digest, cada uma com um motivo
Só refs/heads/ — tag não traz commit para analisar, e os deploys do DORA vêm do Datadog. LC_ALL=C na
ordenação, para que o locale da imagem do runner não mude o resultado. sha256, que o runner já tem. E
o prefixo v1:, para que uma revisão futura da normalização vire v2: e a reanálise da organização
inteira apareça como decisão, em vez de um dia em que tudo é reanalisado sem explicação.
A definição do digest é contrato, não detalhe de implementação: qualquer mudança nela invalida de
uma vez todos os digests já gravados.
Nada aqui nomeia uma organização
O App, a URL da plataforma e a organização a analisar entram por input, e a organização cai em github.repository_owner, que numa reusable workflow é o dono de quem chamou. Rodar esta coleta noutra
organização é apontar outro caller para o mesmo arquivo. Regra 6 do CLAUDE.md.
Por que descoberta e workflow na mesma issue
Um workflow_call que referencia um scripts/iris-cycle.sh inexistente falha no step. Juntos, entregam
algo completo e útil desde o primeiro merge: um workflow despachável que reporta o retrato de refs da
organização — que é, também, exatamente o insumo que o censo da Fase 4 publica.
Se encaixa em qual estágio?
Stage 2 — Ingestion: reliability of CLI → /api/ingest pipeline. A leitura centralizada da API do
GitHub reabre o non-goal de integrações externas do CLAUDE.md; a nota de governança da §2.2 do DD
registra que a exceção pedida é a mesma já concedida ao Datadog.
pip install . — sem release, sem wheel e sem resolver versão
Isso amarra engine, script de ciclo e definição do workflow ao mesmo commit por construção: um ciclo
nunca mistura duas versões do engine, e o workflow_dispatch fixa os três juntos ao escolher o ref.
A versão do pacote continua indo para analysis_runs.cli_version, e o commit fica no log do run.
Token fora do log
A action create-github-app-tokenmascara o token e o revoga no post-step
O clone usa credential.helper lendo do ambiente — nunca token embutido na URL do remote
O que fica declarado, e não mitigado
checkout, setup-python e create-github-app-token rodam no mesmo job que a chave do App. Pinar
cada uses: por SHA impede que uma tag passe a apontar para outro código, mas não protege de uma
versão que já seja maliciosa. Fica declarado em vez de mitigado, porque a alternativa seria manter
cópia própria de cada action.
Limitação conhecida do digest: PR vindo de fork
A branch de origem vive no fork, então o ls-remote do repositório não a vê — um PR de fork não muda o
digest. Alcança só os 3 repositórios públicos da organização, e o maior deles recebe push diário, o
que o corrige no ciclo seguinte. Se passar a pesar, a descoberta acrescenta a contagem de PRs abertos,
que cabe na query que já roda.
Duas credenciais, e nenhuma de banco
A chave do App fala com o GitHub — clonar e ler PRs
O token de ingestão fala com a plataforma, pelas rotas de leitura do watermark e de escrita do censo
O Supabase continua acessível só pela plataforma. Dar credencial de banco ao CI ampliaria o raio sem
necessidade — é por isso que o watermark é lido por rota, e não por query direta.
O token de ingestão é por organização, e o /api/ingest grava tudo sob o organization_id dele —
é também o que isola um tenant do outro.
Um job por ciclo é um token por ciclo
O ciclo é um job só, e isso é restrição de desenho, não acaso: o token do App é gerado dentro do
job que o usa e não atravessa job nenhum. O Actions não passa token por output, e passar significaria
guardá-lo — que é exatamente o que um token de uma hora existe para evitar.
O ciclo roda num único job; qualquer divisão futura em matrix precisa resolver a cunhagem por
shard antes, não depois
Fallback declarado da leitura de refs: 8 leituras em paralelo, medido em 57 s contra os 29,7 s com 16.
User story
Como operador da coleta, eu quero descobrir quais repositórios mudaram desde a última análise por um
workflow que eu possa despachar, para saber o tamanho do trabalho antes de clonar qualquer coisa.
Acceptance criteria
scripts/iris-cycle.sh— a descobertapushedAtda organizaçãogit ls-remote --headspor repositório monta o digest de refs, sem clonar e sem consumir cota de APIv1:$(git ls-remote --heads "$URL" | LC_ALL=C sort | sha256sum | cut -d' ' -f1)o watermark deixaria aquele repositório pendente para sempre
pushedAte digest — maisas falhas. Não clona, não analisa, não faz push, e não compara contra o watermark: dizer o que
está pendente exige a rota de leitura do watermark, e isso é trabalho da issue de seleção.
.github/workflows/iris-ingestion-worker.ymlon: workflow_callcomo único gatilho — semschedule, sempush, semworkflow_dispatchapp-id,iris-server-url,organization(opcional, default vazio)IRIS_WORKER_APP_KEYeIRIS_INGEST_TOKENdeclarados obrigatórios, nãoinheritruns-on: ubuntu-latest,timeout-minutes: 60,permissions: contents: readjob.workflow_repository+job.workflow_shaowner: inputs.organization || github.repository_ownercredential.helperlendo do ambiente — nunca token embutido na URL do remoteuses:pinado por SHA de commitO quatro escolhas do digest, cada uma com um motivo
Só
refs/heads/— tag não traz commit para analisar, e os deploys do DORA vêm do Datadog.LC_ALL=Cnaordenação, para que o locale da imagem do runner não mude o resultado.
sha256, que o runner já tem. Eo prefixo
v1:, para que uma revisão futura da normalização virev2:e a reanálise da organizaçãointeira apareça como decisão, em vez de um dia em que tudo é reanalisado sem explicação.
A definição do digest é contrato, não detalhe de implementação: qualquer mudança nela invalida de
uma vez todos os digests já gravados.
Nada aqui nomeia uma organização
O App, a URL da plataforma e a organização a analisar entram por input, e a organização cai em
github.repository_owner, que numa reusable workflow é o dono de quem chamou. Rodar esta coleta noutraorganização é apontar outro caller para o mesmo arquivo. Regra 6 do CLAUDE.md.
Por que descoberta e workflow na mesma issue
Um
workflow_callque referencia umscripts/iris-cycle.shinexistente falha no step. Juntos, entregamalgo completo e útil desde o primeiro merge: um workflow despachável que reporta o retrato de refs da
organização — que é, também, exatamente o insumo que o censo da Fase 4 publica.
Se encaixa em qual estágio?
Stage 2 — Ingestion: reliability of CLI →
/api/ingestpipeline. A leitura centralizada da API doGitHub reabre o non-goal de integrações externas do CLAUDE.md; a nota de governança da §2.2 do DD
registra que a exceção pedida é a mesma já concedida ao Datadog.
Links
O engine vem do commit do próprio worker
Os steps do job, além do checkout já descrito:
actions/setup-pythoncompython-version: "3.11"pip install .— sem release, sem wheel e sem resolver versãoIsso amarra engine, script de ciclo e definição do workflow ao mesmo commit por construção: um ciclo
nunca mistura duas versões do engine, e o
workflow_dispatchfixa os três juntos ao escolher oref.A versão do pacote continua indo para
analysis_runs.cli_version, e o commit fica no log do run.Token fora do log
create-github-app-tokenmascara o token e o revoga no post-stepcredential.helperlendo do ambiente — nunca token embutido na URL do remoteO que fica declarado, e não mitigado
checkout,setup-pythonecreate-github-app-tokenrodam no mesmo job que a chave do App. Pinarcada
uses:por SHA impede que uma tag passe a apontar para outro código, mas não protege de umaversão que já seja maliciosa. Fica declarado em vez de mitigado, porque a alternativa seria manter
cópia própria de cada action.
Limitação conhecida do digest: PR vindo de fork
A branch de origem vive no fork, então o
ls-remotedo repositório não a vê — um PR de fork não muda odigest. Alcança só os 3 repositórios públicos da organização, e o maior deles recebe push diário, o
que o corrige no ciclo seguinte. Se passar a pesar, a descoberta acrescenta a contagem de PRs abertos,
que cabe na query que já roda.
Duas credenciais, e nenhuma de banco
O Supabase continua acessível só pela plataforma. Dar credencial de banco ao CI ampliaria o raio sem
necessidade — é por isso que o watermark é lido por rota, e não por query direta.
O token de ingestão é por organização, e o
/api/ingestgrava tudo sob oorganization_iddele —é também o que isola um tenant do outro.
Um job por ciclo é um token por ciclo
O ciclo é um job só, e isso é restrição de desenho, não acaso: o token do App é gerado dentro do
job que o usa e não atravessa job nenhum. O Actions não passa token por output, e passar significaria
guardá-lo — que é exatamente o que um token de uma hora existe para evitar.
matrixprecisa resolver a cunhagem porshard antes, não depois
Fallback declarado da leitura de refs: 8 leituras em paralelo, medido em 57 s contra os 29,7 s com 16.