AUR-406 — Perfil parser worker offline (parser-worker-v1)
Documento histórico do board. Pode descrever componentes removidos; para uso atual, consulte o guia do produto.
Este documento descreve a entrada parser-worker-v1 publicada no registry
canônico de profiles. O card publica somente documentos: nenhum engine é
invocado, nenhum worker é implementado, nenhuma gramática é escrita 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/parser-worker-profile.schema.json |
| Profile | .board/oci/profiles/parser-worker-v1.json |
| Lock | .board/locks/oci/parser-worker-v1.lock.json |
| Registry | .board/oci/profiles/registry.v1.json |
O registry passa a publicar exatamente seis chaves, em ordem canônica
crescente: bootstrap-readonly-v1, fake-provider-v1, go-git-offline-v1,
go-unit-offline-v1, parser-worker-v1, registry-v1. Nenhuma chave existente
muda de digest, schema ou lock.
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 e tmpfs limitado) o probe devolve
bash 5.2.26, go1.21.13 e uma única interface de rede, lo; git está
ausente dessa imagem. O worker de parsing é um processo Go que lê blobs pela
entrada padrão e não executa comando Git, então a imagem de bootstrap basta e a
imagem golang pinada por go-git-offline-v1 — a única localmente presente com
git 2.39.2 — não é necessária aqui.
Somente aurum-bootstrap-go-bash@sha256:<64 hex> é aceito. Uma tag mutável
(aurum-bootstrap-go-bash:1.21), um nome sem digest ou outro repositório é
rejeitado com mutable-input antes de qualquer resolução de imagem.
Plano declarado
Limites e isolamento:
| 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) |
Capacidades do worker de parsing, todas verificadas pelo loader:
| Chave | Valor | Efeito |
|---|---|---|
worker |
digest-pinned |
o binário do worker só é admitido content-addressed |
worker_root |
/tmp/aurum-parser-worker |
o worker vive no tmpfs limitado, nunca no checkout |
grammar_set |
digest-pinned |
o grammar set só é admitido content-addressed |
grammar_set_root |
/tmp/aurum-parser-grammars |
as gramáticas vivem no tmpfs limitado, nunca no checkout |
code_execution |
denied |
o código analisado é dado, nunca programa: nada dele é executado |
host_filesystem |
denied |
nenhum caminho do host é legível ou gravável pelo plano |
subprocess |
denied |
a allowlist de subprocesso é vazia; qualquer subprocesso é negado |
blob_source |
stdin |
blobs entram apenas pela entrada padrão, nunca por arquivo do host |
max_blob_bytes |
1048576 |
blob limitado; 0 é ilimitado e é recusado |
max_blobs |
256 |
número de blobs por execução limitado |
parse_timeout_seconds |
5 |
wall-clock por blob analisado |
worker: "digest-pinned" e grammar_set: "digest-pinned" pinam a exigência,
não os bytes: o binário do worker, as gramáticas e qualquer parser de linguagem
são não-objetivos deste card e pertencem ao card de implementação dependente. O
que este card garante é que um worker ou um grammar set sem digest nunca é
resolvido.
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 |
AURUM_PARSER_WORKER_ROOT |
/tmp/aurum-parser-worker |
AURUM_PARSER_GRAMMAR_ROOT |
/tmp/aurum-parser-grammars |
HTTP_PROXY |
(vazio) |
HTTPS_PROXY |
(vazio) |
NO_PROXY |
* |
AURUM_PARSER_WORKER_ROOT/worker_root e
AURUM_PARSER_GRAMMAR_ROOT/grammar_set_root são duas grafias dos mesmos dois
diretórios; o teste de integração recusa qualquer divergência entre elas, porque
uma divergência é exatamente um filesystem que o plano não limitou. 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 (ValidateRegistryAUR406 / ValidateProfileAUR406) é
side-effect-free, não abre socket, 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 parse_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 parser-worker-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 worker/grammar set sem digest |
unsafe-plan |
limite obrigatório relaxado, blob ilimitado, root de worker/gramática fora do tmpfs, blob vindo do host, execução de código/subprocesso/filesystem do host habilitados, 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 |
Mutantes provados
O acceptance executa cada mutante contra bytes reais em disco e exige o código declarado; o restore volta byte-idêntico.
| Mutante | Mudança | Código |
|---|---|---|
| MUT-001 | chave parser-worker-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 |
| execução de código | code_execution para allowed |
unsafe-plan |
| filesystem do host | host_filesystem para read-only |
unsafe-plan |
| subprocesso | subprocess para allowed |
unsafe-plan |
| gramática fora do tmpfs | grammar_set_root para /workspace/.board |
unsafe-plan |
| worker fora do tmpfs | worker_root para /workspace/internal |
unsafe-plan |
| blob do host | blob_source para host-file |
unsafe-plan |
| blob ilimitado | max_blob_bytes para 0 |
unsafe-plan |
| grammar set sem digest | grammar_set para unpinned |
digest-invalid |
| worker sem digest | worker para mutable |
digest-invalid |
| limite ausente | parse_timeout_seconds removido do documento |
schema-invalid |
| credential real | HTTP_PROXY para uma chave com forma real (montada 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 sexta 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 (6) 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/contracts/AUR-404.go— aridade exata do registry (5para6).
Cada extensão é aditiva: nenhuma rejeição anterior desaparece, nenhuma igualdade vira desigualdade e nenhuma aridade exata vira mínimo. Nenhum desses loaders lê os documentos do parser worker: cada um checa apenas os caminhos declarados e a forma do digest, de modo que registrar o parser worker não pode re-apontar silenciosamente o plano Go unit, o plano Git nem o plano do fake provider.
A aridade total do registry é asserida em tests/unit/AUR-406.go, que este card
possui. tests/contracts/AUR-406.go não assere aridade: este card é dono da
chave parser-worker-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/parser-worker-profile.schema.json \
.board/locks/oci/parser-worker-v1.lock.json
printf '%s' "$(sed -n 's/.*"image": "\(.*\)".*/\1/p' \
.board/locks/oci/parser-worker-v1.lock.json)" | sha256sum
# o runtime da imagem pinada ainda satisfaz o plano?
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; ls /sys/class/net'