AUR-409 — Perfil de SCM falso offline (fake-scm-offline-v1)
Documento histórico do board. Pode descrever componentes removidos; para uso atual, consulte o guia do produto.
Este documento descreve a entrada fake-scm-offline-v1 publicada no registry
canônico de profiles. O card publica somente documentos: nenhum engine é
invocado, nenhum repositório é criado ou clonado, nenhum evento é reproduzido,
nenhum pull request é simulado, e o runner permanece fail-closed para esta chave
até um card de implementação dependente habilitá-la explicitamente.
Artefatos
| Artefato | Caminho |
|---|---|
| Schema | .board/schemas/fake-scm-offline-profile.schema.json |
| Profile | .board/oci/profiles/fake-scm-offline-v1.json |
| Lock | .board/locks/oci/fake-scm-offline-v1.lock.json |
| Registry | .board/oci/profiles/registry.v1.json |
O registry passa a publicar exatamente nove chaves, em ordem canônica
crescente: bootstrap-readonly-v1, docs-tool-offline-v1, fake-provider-v1,
fake-scm-offline-v1, go-git-offline-v1, go-unit-offline-v1,
parser-worker-v1, registry-v1, sqlite-offline-v1. Nenhuma chave existente
muda de digest, schema ou lock.
Em ordem lexicográfica C, fake-scm- ordena depois de fake-provider- —
p (0x70) precede s (0x73) no primeiro byte que difere — e antes de
go-git-. A nova chave ocupa portanto o índice 3, e as cinco chaves seguintes
(go-git-offline-v1, go-unit-offline-v1, parser-worker-v1, registry-v1,
sqlite-offline-v1) deslocam-se uma posição à direita. Nenhuma chave sai da
lista, nenhuma aridade exata vira mínimo e nenhuma igualdade vira desigualdade:
cada chave continua asserida no único índice que a ordem canônica lhe dá.
Imagem pinada
O lock fixa Go e Bash na imagem de bootstrap já presente localmente, por digest imutável:
aurum-bootstrap-go-bash@sha256:503ac356fa6bca4bad56fade87b5479ff371bd446ffb9c7db91f211323c7c73e
A imagem foi escolhida por prova, não por conveniência. Sob
--pull=never --network=none --read-only --user=65534:65534 --cap-drop=ALL
(mais --security-opt=no-new-privileges) os dois probes locais respondem:
| Imagem | Bash | Go | Binário de SCM | Transporte |
|---|---|---|---|---|
aurum-bootstrap-go-bash@sha256:503ac356… |
5.2.26 | go1.21.13 | git, hg, svn, git-lfs, gh ausentes |
git-upload-pack, git-receive-pack, ssh, curl ausentes; uma única interface, lo |
golang@sha256:4746d264… (imagem de go-git-offline-v1) |
presente | go1.21.13 | git 2.39.2 presente |
git-upload-pack, git-receive-pack, ssh e curl presentes |
Isso é o que determina o plano, e não o contrário. Para um SCM falso, o
esperado é justamente não precisar de um SCM real: scm_backend: "fake-local",
real_scm_binary: "denied", fake_scm_cgo: false e CGO_ENABLED: "0" fixam
uma implementação puro Go, e é exatamente por isso que a imagem correta é a
de bootstrap, que não carrega git, nem git-upload-pack, nem
git-receive-pack, nem ssh, nem curl. Usar a imagem golang de
go-git-offline-v1 seria trocar um plano cujas negações são estruturais por um
plano cujas negações dependem de ninguém invocar as ferramentas presentes.
go-git-offline-v1 continua sendo a chave dona daquele runtime; este profile é
outra chave, com outro lock, e não pode tomá-lo emprestado. Um backend git,
um real_scm_binary diferente de denied ou um fake ligado por cgo são
rejeitados com unsafe-plan. Nenhuma imagem foi construída, baixada ou
fabricada para este card.
Plano declarado
Contenção
| Chave | Valor |
|---|---|
network |
none |
user |
65534:65534 |
cap_drop / cap_add |
ALL / none |
mounts / devices / sockets |
none / none / none |
pull |
never |
tmpfs |
rw,nosuid,nodev |
checkout_readonly |
true |
read_only_rootfs |
true |
no_new_privileges |
true |
privileged |
false |
timeout_seconds |
60 |
memory_mb |
256 |
cpu_millis |
1000 |
pids_limit |
128 |
tmpfs_mb |
128 |
stdout_limit_bytes / stderr_limit_bytes |
65536 / 65536 |
max_input_files / max_input_bytes |
10000 / 67108864 |
module_cache |
/go/pkg/mod (module_cache_read_only: true) |
Superfície de SCM
| Chave | Valor | Efeito |
|---|---|---|
scm_backend |
fake-local |
o SCM é o fake local determinístico, nunca um cliente real |
real_scm_binary |
denied |
nenhum git/hg/svn do host ou da imagem é invocado |
fake_scm |
digest-pinned |
o fake só é admitido content-addressed |
fake_scm_cgo |
false |
fake puro Go: nenhuma lib nativa de version control |
fake_scm_root |
/tmp/aurum-fake-scm-engine |
o fake vive no tmpfs limitado |
event_set |
digest-pinned |
os eventos reproduzidos são pinados por conteúdo |
event_root |
/tmp/aurum-fake-scm-events |
os eventos vivem no tmpfs limitado |
response_set |
digest-pinned |
as respostas são pinadas por conteúdo |
repository_mode |
ephemeral |
os repositórios simulados existem só durante a execução |
repository_root |
/tmp/aurum-fake-scm-repos |
os repositórios vivem no tmpfs limitado, nunca no checkout |
remote_origin |
absent |
não existe origem: nem https://, nem git@host:path, nem ssh://, nem file://, nem ext:: |
remote_protocols |
["fake"] |
allowlist fechada: só o transporte in-process do fake |
custom_transport |
denied |
nenhum upload-pack/receive-pack customizado |
credential_helper |
denied |
nenhum credential helper é consultado |
askpass |
denied |
nenhum programa de askpass é executado |
hooks |
denied |
nenhum hook do repositório é executado |
submodules |
denied |
nenhum submódulo, portanto nenhum ponteiro para fora da árvore |
url_rewriting |
denied |
nenhuma reescrita insteadOf depois da validação |
publication |
denied |
nenhum push, nenhuma criação de PR, nenhuma release |
external_destination |
denied |
nenhum destino fora do fake local |
token |
absent |
nenhum token real integra o plano |
credential_sources |
denied |
nenhuma origem de credencial é consultada |
host_checkout |
denied |
o checkout do host nunca é o repositório de trabalho |
host_filesystem |
denied |
nenhum caminho do host é lido ou escrito |
subprocess |
denied |
nenhum processo externo é criado — é assim que um git real seria alcançado |
max_events |
1024 |
tamanho exato do log de eventos admissível |
max_event_bytes |
65536 |
teto exato por evento (64 KiB) |
max_responses |
64 |
número exato de respostas pinadas |
max_response_bytes |
65536 |
teto exato por resposta (64 KiB) |
max_repository_bytes |
33554432 |
teto exato do repositório (32 MiB) dentro do tmpfs de 128 MiB |
scm_timeout_seconds |
5 |
wall-clock por operação de SCM |
Cada limite é uma constante exata, nunca um mínimo: max_repository_bytes de
0 e de 34359738368 negam igualmente — o primeiro por ser ilimitado, o
segundo porque o repositório simulado não caberia no tmpfs que precisa contê-lo.
Independentemente das constantes, o loader exige
max_repository_bytes <= tmpfs_mb * 1024 * 1024,
max_events * max_event_bytes <= max_input_bytes e
max_responses * max_response_bytes <= max_input_bytes; com os valores
publicados, 1024 * 65536 é exatamente max_input_bytes.
fake_scm_root, event_root e repository_root são casados por expressões
ancoradas nas duas pontas, então /workspace, um traversal que começa dentro
do root limitado e sobe para fora dele (/tmp/aurum-fake-scm-repos/../../etc),
uma barra final (/tmp/aurum-fake-scm-repos/) e um irmão que apenas compartilha
o prefixo (/tmp/aurum-fake-scm-repos-host) são todos negados. Loader e camada
de integração exigem ainda que os três roots sejam distintos e que nenhum
contenha outro, porque um fake que morasse dentro da árvore de repositórios
tornaria uma entrada pinada gravável em tempo de replay.
remote_origin também é casado por expressão ancorada (^absent$), de modo que
um valor que apenas comece com o texto admitido — por exemplo
absent-but-really-https://… — é negado como qualquer URL explícita.
Comandos permitidos
["go", "test", "-mod=readonly", "./..."]
Qualquer outro comando, ou o mesmo comando com aridade diferente, invalida o plano. O ambiente é fechado sobre exatamente estas chaves:
| Variável | Valor |
|---|---|
GOPROXY |
off |
GOSUMDB |
off |
GONOSUMDB |
* |
GOTOOLCHAIN |
local |
CGO_ENABLED |
0 |
AURUM_FAKE_SCM_ROOT |
/tmp/aurum-fake-scm-engine |
AURUM_FAKE_SCM_EVENT_ROOT |
/tmp/aurum-fake-scm-events |
AURUM_FAKE_SCM_REPOSITORY_ROOT |
/tmp/aurum-fake-scm-repos |
GIT_CONFIG_NOSYSTEM |
1 |
GIT_CONFIG_GLOBAL |
/dev/null |
GIT_CONFIG_SYSTEM |
/dev/null |
GIT_TERMINAL_PROMPT |
0 |
GIT_ASKPASS |
/bin/false |
GIT_ALLOW_PROTOCOL |
none |
HTTP_PROXY |
(vazio) |
HTTPS_PROXY |
(vazio) |
NO_PROXY |
* |
As seis variáveis GIT_* são defesa em profundidade, não a defesa principal: a
imagem pinada não tem cliente de version control algum. Elas existem para que,
mesmo se um consumidor futuro colocasse um binário real ao alcance, todos os
canais de configuração de onde um credential helper, um programa de askpass, uma
reescrita insteadOf ou um transporte ext:: seriam lidos já estivessem
fechados no próprio plano. Cada uma é pinada por constante: GIT_ASKPASS para
um askpass real, GIT_ALLOW_PROTOCOL para ext, GIT_CONFIG_NOSYSTEM para
0, GIT_CONFIG_GLOBAL para um arquivo de configuração e GIT_TERMINAL_PROMPT
para 1 são mutantes provados, todos unsafe-plan.
As três variáveis AURUM_FAKE_SCM_* e os três roots declarados são duas grafias
dos mesmos diretórios; o teste de integração recusa qualquer divergência entre
elas, porque AURUM_FAKE_SCM_REPOSITORY_ROOT é exatamente onde um clone
simulado apareceria se apontasse para fora do tmpfs limitado. Nenhuma
credencial, valor de ambiente do host ou segredo entra no documento, e o loader
recusa qualquer valor com forma de credencial mesmo em campo cujo valor seja
pinado por constante.
Códigos de rejeição
O loader (ValidateRegistryAUR409 / ValidateProfileAUR409) é
side-effect-free, não abre socket, não executa comando de version control, não
cria subprocesso e devolve exatamente um código:
| Código | Causa |
|---|---|
registry-missing |
registry ausente ou não regular |
schema-invalid |
registry, schema ou profile fora da forma canônica (inclui chave duplicada dentro de um objeto JSON e limite obrigatório ausente, como scm_timeout_seconds) |
schema-missing |
documento de schema ausente |
schema-digest-mismatch |
schema_digest não reproduz os bytes do schema |
profile-missing |
documento do profile ausente |
profile-unregistered |
chave desconhecida, ou fake-scm-offline-v1 ausente do registry |
duplicate-profile |
a mesma chave publicada duas vezes |
order-invalid |
chaves fora da ordem canônica crescente |
credential-present |
valor de ambiente com forma de credential real |
digest-invalid |
digest vizinho fora do formato sha256:<64 hex>, ou fake, event set ou response set sem digest |
unsafe-plan |
limite obrigatório relaxado ou excedido, tmpfs ilimitado, log de eventos ou conjunto de respostas maior que o limite de entrada, repositório fora do tmpfs, roots sobrepostos, backend real, binário de SCM real, origem remota, allowlist de transporte ampliada, transporte customizado, credential helper, askpass, hook, submódulo, reescrita de URL, publicação, destino externo, token presente, origem de credencial, checkout do host, filesystem do host, subprocesso, repositório persistente, fake cgo, canal GIT_* reaberto, rede, mount, socket, device, root ou capability |
lock-missing |
lock ausente |
mutable-input |
imagem por tag mutável, repositório inesperado ou lock fora do schema |
lock-digest-mismatch |
lock_digest não reproduz os bytes do lock |
As constantes de segurança do schema são pinadas duas vezes: nos bytes do
documento de schema e em profileSchemaConstants409 /
environmentSchemaConstants409, dentro de tests/unit/AUR-409.go. Relaxar o
schema e recomputar o schema_digest no registry move os dois arquivos de forma
consistente e ainda assim falha, porque o mapa em Go não se move com eles.
Mutantes provados
O acceptance executa cada mutante contra bytes reais em disco, na cópia descartável, e exige o código declarado; o restore volta byte-idêntico.
| Mutante | Mudança | Código |
|---|---|---|
| MUT-001 | chave fake-scm-offline-v1 duplicada com bytes diferentes |
duplicate-profile |
| MUT-002 | imagem do lock por tag mutável | mutable-input |
| MUT-003 | network de none para host |
unsafe-plan |
| mount habilitado | mounts para bind |
unsafe-plan |
| socket habilitado | sockets para unix |
unsafe-plan |
| device habilitado | devices para /dev/fuse |
unsafe-plan |
| root | user para 0:0 |
unsafe-plan |
| capability adicionada | cap_add para SYS_ADMIN |
unsafe-plan |
| backend real | scm_backend para git |
unsafe-plan |
| binário real | real_scm_binary para git |
unsafe-plan |
| origem HTTPS | remote_origin para https://forge.example.com/… |
unsafe-plan |
| origem scp | remote_origin para git@forge.example.com:… |
unsafe-plan |
| origem SSH | remote_origin para ssh://forge.example.com/… |
unsafe-plan |
| origem file | remote_origin para file:///etc |
unsafe-plan |
| origem ext | remote_origin para ext::sh -c cat |
unsafe-plan |
| origem com prefixo | remote_origin para absent-but-really-https://… |
unsafe-plan |
| allowlist ampliada | remote_protocols ganha "https" |
unsafe-plan |
| allowlist trocada | remote_protocols para ["ext"] |
unsafe-plan |
| transporte customizado | custom_transport para upload-pack |
unsafe-plan |
| credential helper | credential_helper para store |
unsafe-plan |
| askpass | askpass para allowed |
unsafe-plan |
| hooks | hooks para allowed |
unsafe-plan |
| submódulo | submodules para recursive |
unsafe-plan |
| reescrita de URL | url_rewriting para insteadOf |
unsafe-plan |
| publicação | publication para push |
unsafe-plan |
| destino externo | external_destination para allowed |
unsafe-plan |
| token presente | token para present |
unsafe-plan |
| origem de credencial | credential_sources para environment |
unsafe-plan |
| checkout do host | host_checkout para read-write |
unsafe-plan |
| filesystem do host | host_filesystem para read-only |
unsafe-plan |
| subprocesso | subprocess para allowed |
unsafe-plan |
| fake cgo | fake_scm_cgo para true |
unsafe-plan |
| repositório persistente | repository_mode para persistent |
unsafe-plan |
| repositório no host | repository_root para /workspace |
unsafe-plan |
| traversal do repositório | repository_root para /tmp/aurum-fake-scm-repos/../../etc |
unsafe-plan |
| barra final | repository_root para /tmp/aurum-fake-scm-repos/ |
unsafe-plan |
| irmão com mesmo prefixo | repository_root para /tmp/aurum-fake-scm-repos-host |
unsafe-plan |
| eventos fora do tmpfs | event_root para /workspace/.board |
unsafe-plan |
| fake fora do tmpfs | fake_scm_root para /usr/local/bin |
unsafe-plan |
| repositório ilimitado | max_repository_bytes para 0 |
unsafe-plan |
| repositório gigante | max_repository_bytes para 34359738368 |
unsafe-plan |
| log de eventos gigante | max_events para 2048 |
unsafe-plan |
| resposta ilimitada | max_response_bytes para 0 |
unsafe-plan |
| tmpfs ilimitado | tmpfs_mb para 0 |
unsafe-plan |
| askpass por ambiente | GIT_ASKPASS para um askpass real |
unsafe-plan |
| protocolo por ambiente | GIT_ALLOW_PROTOCOL para ext |
unsafe-plan |
| config de sistema | GIT_CONFIG_NOSYSTEM para 0 |
unsafe-plan |
| config global | GIT_CONFIG_GLOBAL para um arquivo de configuração |
unsafe-plan |
| prompt de terminal | GIT_TERMINAL_PROMPT para 1 |
unsafe-plan |
| fake sem digest | fake_scm para unpinned |
digest-invalid |
| eventos sem digest | event_set para unpinned |
digest-invalid |
| respostas mutáveis | response_set para latest |
digest-invalid |
| limite ausente | scm_timeout_seconds removido do documento |
schema-invalid |
| credential real | HTTP_PROXY para um token com forma real (montado em runtime) |
credential-present |
O vetor de credential nunca aparece como literal em arquivo versionado: ele é
montado em runtime, dentro da cópia descartável do acceptance, para que o portão
de credenciais de oci-run não veja forma de segredo em nenhuma entrada
materializada nem em nenhuma saída.
Loaders vizinhos
Registrar uma nona chave fecha a allowlist dos loaders já entregues, então este card os estende no mesmo commit:
tests/unit/AUR-402.go— allowlist de chaves do registry canônico.tests/unit/AUR-403.go— allowlist, aridade (9) e ordem posicional.tests/unit/AUR-404.go— conjunto de chaves registradas eswitchdo loader.tests/unit/AUR-405.go— conjunto de chaves registradas eswitchdo loader.tests/unit/AUR-406.go— conjunto de chaves registradas eswitchdo loader.tests/unit/AUR-407.go— conjunto de chaves registradas eswitchdo loader.tests/unit/AUR-408.go— conjunto de chaves registradas eswitchdo loader.tests/contracts/AUR-404.go— aridade exata do registry (8para9).
Cada extensão é aditiva: nenhuma rejeição anterior desaparece, nenhuma igualdade vira desigualdade, nenhuma aridade exata vira mínimo e nenhuma chave sai de allowlist. Nenhum desses loaders lê os documentos do fake SCM: cada um checa apenas os caminhos declarados e a forma do digest, de modo que registrar o SCM falso não pode re-apontar silenciosamente o plano Go unit, o plano Git, o plano do fake provider, o plano do parser worker, o plano do state store nem o plano da ferramenta de documentação.
A aridade total do registry é asserida em tests/unit/AUR-409.go, que este card
possui. tests/contracts/AUR-409.go não assere aridade: este card é dono da
chave fake-scm-offline-v1, não do tamanho do registry, e a próxima carta de
profile deve quebrar apenas onde sua posse estiver declarada.
Diagnóstico offline
# a chave está publicada e em ordem?
grep -n '"key"' .board/oci/profiles/registry.v1.json
# os digests do registry reproduzem os bytes?
sha256sum .board/schemas/fake-scm-offline-profile.schema.json \
.board/locks/oci/fake-scm-offline-v1.lock.json
printf '%s' "$(sed -n 's/.*"image": "\(.*\)".*/\1/p' \
.board/locks/oci/fake-scm-offline-v1.lock.json)" | sha256sum
# o runtime da imagem pinada ainda satisfaz o plano puro Go sem SCM real?
docker run --rm --pull=never --network=none --read-only \
--user=65534:65534 --cap-drop=ALL --entrypoint= \
aurum-bootstrap-go-bash@sha256:503ac356fa6bca4bad56fade87b5479ff371bd446ffb9c7db91f211323c7c73e \
bash -c 'command -v go; command -v git || echo git-absent;
command -v git-upload-pack || echo upload-pack-absent;
command -v ssh || echo ssh-absent; ls /sys/class/net'