Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
b6cfffd
feat(lgpd): schema de pedidos do titular e linha de consentimento ass…
hbgit Sep 29, 2026
16d27ee
feat(lgpd): serviço de direitos do titular — revogação por finalidade…
hbgit Sep 29, 2026
62fb0ae
feat(lgpd): RPCs de consentimento e pedidos do titular, com store ORM…
hbgit Sep 29, 2026
f640fc2
feat(paciente): contrato de direitos do titular no cliente e decisão …
hbgit Sep 29, 2026
9d3d62c
feat(paciente): revogar e conceder consentimento em Meus dados (LGPD-…
hbgit Sep 29, 2026
d3100a1
feat(paciente): pedidos de exclusão e correção em Meus dados (LGPD-RF08)
hbgit Sep 29, 2026
6cc1d38
docs(lgpd): registra os direitos do titular no app paciente e o que f…
hbgit Sep 29, 2026
6207f8c
fix(paciente): revogar lembretes vale no aparelho mesmo se o recarreg…
hbgit Sep 29, 2026
00748c4
chore: atualiza os marcadores locais do headroom
hbgit Sep 29, 2026
db7b9a1
chore: ignora os marcadores locais do headroom
hbgit Sep 29, 2026
4aabe16
docs: plano do QR do onboarding e dos documentos legais do app paciente
hbgit Sep 29, 2026
8197d57
feat(paciente): conteúdo versionado do Termo de Uso e da Política de …
hbgit Sep 29, 2026
6a58637
feat(paciente): telas de Privacidade e termos com resumo visual e his…
hbgit Sep 29, 2026
9d38ba4
feat(backend): aceite versionado do Termo de Uso no onboarding (LGPD-…
hbgit Sep 29, 2026
407aa68
feat(paciente): aceite explícito do Termo de Uso e da Política no cad…
hbgit Sep 29, 2026
ffe8352
feat(acs): generateInvite na camada de rede, sobre onboarding.generat…
hbgit Sep 29, 2026
1887833
feat(acs): tela Convidar paciente com QR Code do convite de onboardin…
hbgit Sep 29, 2026
8dea0c8
feat(paciente): leitura do QR Code do convite pela câmera no onboardi…
hbgit Sep 29, 2026
9911cdb
docs: registra o QR do onboarding e os documentos legais do app paciente
hbgit Sep 29, 2026
8775274
fix: achados da revisão final do QR do onboarding e dos documentos le…
hbgit Sep 29, 2026
d98bab0
docs: plano do aceite do Termo de Uso no login por OTP
hbgit Sep 29, 2026
871f694
feat(backend): patients.acceptTermsOfUse para o aceite do termo fora …
hbgit Sep 29, 2026
1d78e98
feat(paciente): convite ao aceite do Termo de Uso depois do login por…
hbgit Sep 29, 2026
a1ce53a
docs: sessão do onboarding já é de 1h; registra o aceite do termo no …
hbgit Sep 29, 2026
faaf126
fix(paciente): checagem do aceite com teto de 3 s, texto sem tom de o…
hbgit Sep 29, 2026
0d66a71
docs: plano de fechamento das pendências do app paciente
hbgit Sep 29, 2026
356f18b
feat(backend): status do aceite sem ler o painel, aceite idempotente,…
hbgit Sep 29, 2026
7d9bc60
fix(paciente): login consulta só o status do aceite; toque duplo na c…
hbgit Sep 29, 2026
e459147
fix(acs): convite expirado some da tela e pede um novo
hbgit Sep 29, 2026
a89f313
docs: registra o fechamento das pendências do app paciente
hbgit Sep 29, 2026
ff407cd
fix(acs): validade do convite medida do recebimento, imune ao relógio…
hbgit Sep 29, 2026
cd18f95
fix(backend): aceite do termo atômico e advisory locks de duas chaves…
hbgit Sep 29, 2026
0c825c2
feat(backend): registro de token de push condicionado ao consentiment…
hbgit Sep 29, 2026
abf1f71
fix(paciente): tocar fora do diálogo de correção não apaga o rascunho
hbgit Sep 29, 2026
61e2fe5
feat(paciente): registra o token de push do aparelho quando há consen…
hbgit Sep 29, 2026
bace4e3
docs: registra os menores fechados e o registro de push do paciente
hbgit Sep 29, 2026
8b183de
docs: plano da rodada de menores adiados e push do paciente
hbgit Sep 29, 2026
df8d8a8
fix(backend): registro de token e revogação sob o mesmo lock por titu…
hbgit Sep 29, 2026
501d8ce
docs: RF14 passa a usar Gorush; Riverpod só no push do paciente
hbgit Sep 29, 2026
4c6649f
feat(infra): Gorush opcional no Compose e GORUSH_URL no backend (RF14)
hbgit Sep 29, 2026
1cd6871
feat(backend): cliente do Gorush com tempo limite e poda de tokens in…
hbgit Sep 29, 2026
f8b2c63
feat(backend): notices.sendSegmented com segmentação SQL e consentime…
hbgit Sep 29, 2026
944d801
feat(acs): tela de envio de aviso comunitário (RF14)
hbgit Sep 29, 2026
96ab8ce
feat(paciente): provider Riverpod e canal nativo para o token de push…
hbgit Sep 29, 2026
65dd4f6
docs: registra o envio de avisos por Gorush e o que ainda não está pr…
hbgit Sep 29, 2026
aa4f3ae
fix(backend): timeout do envio é resultado desconhecido, aceitos sem …
hbgit Sep 29, 2026
80cae83
docs: revisa o plano dos menores do push e do aviso de 15 dias contra…
hbgit Sep 29, 2026
fc1d881
fix(backend): revogação de push atômica, auditoria da troca de dono e…
hbgit Sep 29, 2026
876bbab
feat(backend): agenda e aviso de 15 dias de mudança dos termos (LGPD-…
hbgit Sep 29, 2026
5a09bed
feat(paciente): cartão de aviso de mudança dos termos e push sem queb…
hbgit Sep 29, 2026
c607da3
docs: registra os menores do push fechados e o aviso de mudança dos t…
hbgit Sep 29, 2026
2f2931c
fix: cartão de aviso fora da aba de urgência; regra dos 15 dias sem a…
hbgit Sep 29, 2026
49d311f
docs: registra os achados do revisor final dos menores do push e do a…
hbgit Sep 29, 2026
8375a68
docs: plano dos menores do RF14 e do texto novo dos termos
hbgit Sep 30, 2026
d96af6b
fix(backend): poda do teto por titular, desempates estáveis e rastro …
hbgit Sep 30, 2026
d9ee730
fix(backend): cliente do Gorush encerrável e tolerante, envio não vir…
hbgit Sep 30, 2026
db4bd60
feat(paciente): texto novo dos termos durante os 15 dias, contraste e…
hbgit Sep 30, 2026
b70f5b5
docs: registra os menores do RF14 fechados e o texto novo dos termos
hbgit Sep 30, 2026
2d38bcc
fix(paciente): detalhe do texto novo não se diz vigente; leitor da ag…
hbgit Sep 30, 2026
3c3d6be
chore: ignora google-services.json (credencial do projeto Firebase, n…
hbgit Sep 30, 2026
69810c1
docs: plano do Gorush com FCM e teste ponta a ponta no emulador
hbgit Sep 30, 2026
f1c7fb9
fix(infra): Gorush 1.22.0 fixada, iOS desligado, log visível e token …
hbgit Sep 30, 2026
84de261
feat(paciente): lado nativo Android do token FCM, com o plugin do Goo…
hbgit Sep 30, 2026
c8605ba
test(e2e): registro real do token FCM e ferramenta de envio do ACS (R…
hbgit Sep 30, 2026
9fabc1c
test(e2e): aviso do ACS chega ao emulador pelo Gorush e FCM reais; co…
hbgit Sep 30, 2026
24d7329
docs: registra o que foi provado contra o Gorush e o FCM reais no emu…
hbgit Sep 30, 2026
d5ecd73
fix(paciente): auto-init do FCM desligado e testes de push só com PUS…
hbgit Sep 30, 2026
bfec72c
fix(paciente): token de push só é pedido ao provedor com consentiment…
hbgit Sep 30, 2026
c4f1c7c
docs: registra a bateria e2e do paciente no emulador 5554 e o que seg…
hbgit Sep 30, 2026
1168873
fix(paciente,backend): consulta leve de consentimento (patients.hasGr…
hbgit Sep 30, 2026
2c9d4ab
test(e2e): stack de e2e com o banco de teste e sem login de desenvolv…
hbgit Sep 30, 2026
58d8231
test(e2e): fixtures sintéticas geradas por execução e seeder do banco…
hbgit Sep 30, 2026
ec89dad
test(e2e): relé do código OTP do gateway de log para o emulador
hbgit Sep 30, 2026
efc32d2
test(paciente): integração entra pelo OTP real com fixtures; login de…
hbgit Sep 30, 2026
6b4a5a6
test(paciente): jornada completa pela tela contra o banco de teste (O…
hbgit Sep 30, 2026
a23d7e0
test(e2e): push do ACS institucional até o emulador contra o banco de…
hbgit Sep 30, 2026
841fdf5
test(e2e): runner único do teste completo do paciente, espera ativa d…
hbgit Sep 30, 2026
e73a763
test(e2e): achados da revisão independente — senha do ACS fora do arg…
hbgit Sep 30, 2026
b1d491c
test(e2e): fecha os Minors da revisão — Host do relé, guarda do seede…
hbgit Sep 30, 2026
6eec8e1
ci: script que decodifica secrets em base64 (chave do FCM e google-se…
hbgit Sep 30, 2026
d007f29
ci(android-e2e): push e2e com o Gorush e o FCM reais quando há creden…
hbgit Sep 30, 2026
c4a5179
ci: invariantes das credenciais do FCM e do emulador com Play Services
hbgit Sep 30, 2026
2df8e0e
ci(android-e2e): decodifica as credenciais do FCM, usa o emulador com…
hbgit Sep 30, 2026
86e13e2
docs: credenciais do FCM e push e2e no CI (secrets, destinos e o que …
hbgit Sep 30, 2026
32e6e88
ci: Gorush roda com o uid do dono da chave 0600 e as credenciais só e…
hbgit Sep 30, 2026
16f7435
ci: erro de base64 inválido traz diagnóstico sem valores (tamanho, al…
hbgit Sep 30, 2026
9e35b7b
docs: CI com Gorush e FCM reais provado no runner (run 36790685752) e…
hbgit Sep 30, 2026
cc22d2b
ci: decode_secret_file endurecido — set +x, nome de variável validado…
hbgit Sep 30, 2026
e99deca
ci: guarda cobre env de workflow, with:, toJSON(secrets), colchetes e…
hbgit Sep 30, 2026
f0666dc
ci: fecha os 10 Minors da revisão do CI do FCM (trap down, cabeçalho …
hbgit Sep 30, 2026
5febbaa
merge: integra origin/develop (tema claro/escuro, ci_invariants, guia…
hbgit Oct 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .claude/.headroom_wrap_marker.json

This file was deleted.

26 changes: 0 additions & 26 deletions .claude/.headroom_wrap_owners.json

This file was deleted.

9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,12 @@ SMS_GATEWAY=
# credencial do broker não pode viajar no app. A correção é credencial por
# dispositivo / mTLS, registrada como lacuna conhecida.
# ---------------------------------------------------------------------------

# --- Avisos push (RF14) ----------------------------------------------------
# Gorush é o relé para FCM/APNs e continua exigindo as credenciais dos
# provedores (arquivos fora do repositório). Vazio desliga o envio de avisos.
# Para ligar: `docker compose --profile push up` e GORUSH_URL=http://gorush:8088.
GORUSH_URL=
GORUSH_CREDENTIALS_DIR=
GORUSH_IOS_KEY_ID=
GORUSH_IOS_TEAM_ID=
53 changes: 47 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ jobs:
run: |
python3 -c 'import yaml' 2>/dev/null || { sudo apt-get update && sudo apt-get install -y python3-yaml; }
./scripts/qa/ci_invariants.sh
- name: Testes dos scripts de CI
run: |
./scripts/ci/decode_secret_file_test.sh
./scripts/qa/ci_push_e2e_test.sh
./scripts/qa/ci_invariants_fcm_test.sh
serverpod-backend:
runs-on: ubuntu-24.04
defaults:
Expand Down Expand Up @@ -214,11 +219,6 @@ jobs:
GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }}
steps:
- uses: actions/checkout@v7
# Sem isto o emulador roda por emulação de CPU em software: medido, o log
# dizia "ProbeKVM: This user doesn't have permissions to use KVM", o boot
# levava ~12 min e cada `adb install` de 45 a 95 s. O runner tem
# /dev/kvm, só não para o usuário do job — a regra do udev abre o
# dispositivo. É o passo documentado pelo android-emulator-runner.
- name: Habilita KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \
Expand Down Expand Up @@ -254,12 +254,15 @@ jobs:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-36-x86_64-pixel_7-ubuntu-24.04
# target no nome: o push e2e precisa de Play Services (a imagem padrão da action é
# AOSP, sem ele); trocar o target sem trocar a chave restauraria o AVD antigo.
key: avd-36-google_apis-x86_64-pixel_7-ubuntu-24.04
- name: Gera o snapshot do AVD para o cache
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 36
target: google_apis
arch: x86_64
profile: pixel_7
force-avd-creation: false
Expand All @@ -278,10 +281,39 @@ jobs:
(cd apps/patient && flutter pub get) & p2=$!
(cd apps/acs && flutter pub get) & p3=$!
wait $p1 && wait $p2 && wait $p3
# Credenciais do FCM para o push e2e (Gorush e FCM reais). Cada secret é um arquivo em
# base64 (`base64 -w0 arquivo`). A chave da conta de serviço vai para um arquivo
# temporário (0600) e GOOGLE_APPLICATION_CREDENTIALS aponta para ele; o
# google-services.json vai para onde o build do paciente o procura (sem ele o APK
# compila e degrada para "sem push"). Sem os secrets (PR de fork) os passos só avisam
# e o job roda como sempre. Cada secret entra por `env:` do PASSO: nunca em `run:`
# (injeção de script) e nunca no `env:` do job (toda ação de terceiros o veria) —
# ci_invariants.sh vigia as duas coisas. Ficam LOGO ANTES do E2E (e depois do
# setup de Java/Flutter/caches/AVD): as credenciais só existem em disco quando quem as usa roda,
# e nenhuma ação de terceiros que não precisa delas as lê — o guarda também exige isso.
- name: Decodifica a credencial do FCM
env:
FCM_CREDENTIALS_BASE64: ${{ secrets.FCM_CREDENTIALS_BASE64 }}
run: |
./scripts/ci/decode_secret_file.sh --env FCM_CREDENTIALS_BASE64 \
--kind service_account --temp-export GOOGLE_APPLICATION_CREDENTIALS
- name: Decodifica o google-services.json
env:
GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}
run: |
./scripts/ci/decode_secret_file.sh --env GOOGLE_SERVICES_JSON_BASE64 \
--kind google_services --package br.com.prismrr.sinalacs.patient \
--to apps/patient/android/app/google-services.json
# Sem isto o emulador roda por emulação de CPU em software: medido, o log
# dizia "ProbeKVM: This user doesn't have permissions to use KVM", o boot
# levava ~12 min e cada `adb install` de 45 a 95 s. O runner tem
# /dev/kvm, só não para o usuário do job — a regra do udev abre o
# dispositivo. É o passo documentado pelo android-emulator-runner.
- name: E2E no emulador Android
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 36
target: google_apis
arch: x86_64
profile: pixel_7
force-avd-creation: false
Expand All @@ -296,6 +328,15 @@ jobs:
# container. O pós-passo do flutter-action faz hashFiles('**/pubspec.lock')
# sobre o workspace inteiro, não consegue ler pg_data/ e derruba o job
# depois de o E2E ter passado — medido no run 36494654391.
# Apaga as credenciais mesmo se o E2E falhar. Num runner hospedado o disco é descartado
# ao fim do job, mas o passo mantém a regra verdadeira em qualquer runner (inclusive um
# autohospedado no futuro) e tira o google-services.json e a chave do Gorush do workspace.
- name: Remove as credenciais do FCM
if: always()
run: |
./scripts/ci/decode_secret_file.sh --cleanup-temp GOOGLE_APPLICATION_CREDENTIALS
./scripts/ci/decode_secret_file.sh --cleanup-file apps/patient/android/app/google-services.json
./scripts/ci/decode_secret_file.sh --cleanup-file infra/docker/gorush/credentials/fcm-service-account.json
- name: Remove pg_data/ do workspace
if: always()
run: sudo rm -rf pg_data
Expand Down
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,17 @@ graphify-out/
apps/acs/assets/certs/
apps/patient/assets/certs/
.worktrees/

# Estado local do proxy headroom (PID e timestamps), reescrito a cada sessão
.claude/.headroom_wrap_*.json
infra/docker/gorush/credentials/

# Google services
google-services.json
fcm-service-account.json

# Fixtures e segredos da stack de e2e (gerados por scripts/qa/e2e_stack.sh seed)
.e2e/

__pycache__/
*.pyc
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Two core flows:

A third app, `apps/admin`, is a read-only backoffice (Indicadores, Microáreas, Alertas, Auditoria) on mock data.

Main RPC endpoints (`backend/sinalacs_server/lib/src/endpoints/`): `auth` (`loginInstitutional`, `requestOtp`, `verifyOtp`, `developmentLogin` — the last only with `ENABLE_DEV_LOGIN`), `onboarding`, `triage.evaluate`, `alerts` (`createRedAlert`, `acknowledge`, `statusFor`), `patients` (`listMicroArea`, `myData`, chronic conditions), `visits` (`sync`, `pull`), `health.check`.
Main RPC endpoints (`backend/sinalacs_server/lib/src/endpoints/`): `auth` (`loginInstitutional`, `requestOtp`, `verifyOtp`, `developmentLogin` — the last only with `ENABLE_DEV_LOGIN`), `onboarding`, `triage.evaluate`, `alerts` (`createRedAlert`, `acknowledge`, `statusFor`), `patients` (`listMicroArea`, `myData`, chronic conditions, `updateConsent`, `requestDataDeletion`, `requestDataCorrection`), `visits` (`sync`, `pull`), `health.check`.

`PROGRESS.md` holds milestone status and the open items with owners. `spec/validation_report.md` is stale in both directions (items it lists as open are closed, and its test counts are far below the real ones) — verify against the code before trusting it.

Expand All @@ -23,7 +23,7 @@ Read these before making product/architecture decisions — when project docs co
- [spec/stack.md](spec/stack.md) — stack/infra architecture decisions.
- [spec/ui_design.md](spec/ui_design.md) — visual language and UX behavior.
- [spec/lgpd_design.md](spec/lgpd_design.md) — privacy/LGPD design.
- [spec/lgpd_data_audit.md](spec/lgpd_data_audit.md) — field-by-field LGPD sensitivity classification for every persisted table (16 domain tables plus Serverpod's own; the count changes with every migration — re-measure it in the `definition.sql` of the latest `backend/sinalacs_server/migrations/*/`, and see L-17 of `spec/validation_report.md` for the drift this line has already accumulated).
- [spec/lgpd_data_audit.md](spec/lgpd_data_audit.md) — field-by-field LGPD sensitivity classification for every persisted table (18 domain tables plus Serverpod's own; the count changes with every migration — re-measure it in the `definition.sql` of the latest `backend/sinalacs_server/migrations/*/`, and see L-17 of `spec/validation_report.md` for the drift this line has already accumulated).
- [spec/ux_accessibility_assessment.md](spec/ux_accessibility_assessment.md) — WCAG 2.2 AA audit (contrast, touch targets, semantics) for the ACS/patient/admin apps; read before touching any color used as text/icon, not just fill.
- [spec/ux_ui_test_plan.md](spec/ux_ui_test_plan.md) — UX/UI test plan derived from `spec/ui_design.md` (visual/interaction behavior, complementary to the accessibility assessment).
- [AGENTS.md](AGENTS.md) — full agent working rules (Portuguese), summarized below.
Expand Down Expand Up @@ -105,7 +105,7 @@ Product/architecture source of truth (PRD, UX flows, LGPD design, stack decision
- Keep triage/prioritization logic deterministic and consistent with the Manchester Protocol model referenced in the PRD — do not make risk classification probabilistic or user-overridable.
- When touching sync behavior (backend `SyncFsm` or the ACS `offline_visit_queue.dart`), preserve retry/queue/conflict semantics — offline-first correctness is the primary architectural risk called out in `AGENTS.md`.
- When reusing a clinical fill color (`red`/`accent`/`danger`/`yellow`/`green`) as text or icon color in the Flutter apps, use the `*OnSurface` token and measure contrast against the surface it actually renders on (commonly `Card`/`surfaceRaised`), not the Scaffold background — see the WCAG contrast tokens section in [apps/CLAUDE.md](apps/CLAUDE.md), `spec/ux_accessibility_assessment.md` and each app's `test/contrast_tokens_test.dart`.
- CI lives in [.github/workflows/ci.yml](.github/workflows/ci.yml) and runs on every PR, on pushes to `main`/`develop`, and by hand (`gh workflow run CI --ref <branch>`). 9 jobs: `workflow-lint`, `serverpod-backend`, `backend-docker-build`, `patient-app`, `acs-app`, `admin-app`, `coverage-report`, `android-e2e` (the only one that boots a real emulator against the stack), `admin-android-build`. `workflow-lint` runs actionlint plus `scripts/qa/ci_invariants.sh`, which fails when: this job list drifts from `JOBS_DOCUMENTADOS`; a job leaves the pinned runner (`RUNNER = 'ubuntu-24.04'`, never `ubuntu-latest`); an action drops below its node24 major (`checkout@v7`, `setup-java@v6`, `cache@v6`, `upload-artifact@v7`); the workflow gains a `paths` filter or loses the per-PR/per-SHA `concurrency` group; `android-e2e` loses its `pg_data/` cleanup step; or the AVD cache key does not end in `-<RUNNER>`.
- CI lives in [.github/workflows/ci.yml](.github/workflows/ci.yml) and runs on every PR, on pushes to `main`/`develop`, and by hand (`gh workflow run CI --ref <branch>`). 9 jobs: `workflow-lint`, `serverpod-backend`, `backend-docker-build`, `patient-app`, `acs-app`, `admin-app`, `coverage-report`, `android-e2e` (the only one that boots a real emulator against the stack), `admin-android-build`. `workflow-lint` runs actionlint plus `scripts/qa/ci_invariants.sh`, which fails when: this job list drifts from `JOBS_DOCUMENTADOS`; a job leaves the pinned runner (`RUNNER = 'ubuntu-24.04'`, never `ubuntu-latest`); an action drops below its node24 major (`checkout@v7`, `setup-java@v6`, `cache@v6`, `upload-artifact@v7`); the workflow gains a `paths` filter or loses the per-PR/per-SHA `concurrency` group; `android-e2e` loses its `pg_data/` cleanup step; or the AVD cache key does not end in `-<RUNNER>`. `workflow-lint` also runs `scripts/ci/decode_secret_file_test.sh`, `scripts/qa/ci_push_e2e_test.sh` and `scripts/qa/ci_invariants_fcm_test.sh`, and `ci_invariants.sh` additionally fails when the secrets `FCM_CREDENTIALS_BASE64`/`GOOGLE_SERVICES_JSON_BASE64` appear inside a `run:` or in the job-level `env:`, when a decode step comes after the E2E step, when the `if: always()` cleanup step is missing, when the emulator loses `target: google_apis` (Play Services; the action's default image is AOSP and FCM returns no token) or when the AVD cache key does not contain it. `android-e2e` decodes both secrets (service-account key to a temp file + `GOOGLE_APPLICATION_CREDENTIALS`, `google-services.json` into `apps/patient/android/app/`) and, when they exist, ends with `scripts/qa/ci_push_e2e.sh` (real Gorush and FCM); without them (fork PRs) it skips.
- `main` and `develop` are protected: the 8 checks from `./scripts/qa/ci_invariants.sh --checks-obrigatorios` (every job except `android-e2e`, tied to GitHub Actions app 15368) must pass to merge, and `main` also requires a PR; admins can still push directly. `android-e2e` has been green since the fixes of 2026-09-28 but stays informational until it builds a longer history. The script does not read the live protection: after renaming or adding a job, re-apply it (see `CONTRIBUTING.md` › CI e merge) or PRs wait forever for a check that no longer exists. Moving to Ubuntu 26.04 (`ubuntu-latest` migrates on 2026-10-19; a rehearsal ran 9/9 green) is a PR that changes `runs-on`, `RUNNER` and the AVD key suffix together, and needs an actionlint that knows the `ubuntu-26.04` label. History in `docs/ci-audit/2026-09-28-avaliacao-ci-develop.md`; known gaps in the guard are issues #19–#21, #23–#24 (#22 fixed — `on:` as a string/list is normalized instead of crashing, and an unrecognized flag exits 2 with a usage message instead of silently exiting 0).
- Never commit real patient data, credentials, or the dev Docker Compose secrets into anything beyond local development.

Expand Down
Loading
Loading