9 Commits
Author SHA1 Message Date
LucaZanni b94bd6936a 🔒 fix(ci): la guardia Dockerfile blocca, e le ARG valgono solo nel loro stage
- via `continue-on-error`: i 56 repo difettosi sono stati corretti (tappa 2
  di PZeta_Touch/flux-repo#133), e su 238 Dockerfile del portale ne restano
  due, che non sono repository git e non passano di qui
- le ARG non si ereditano da `FROM <stage>`, come dice la documentazione
  Docker: la versione precedente presumeva il contrario e lasciava passare
  proprio i casi come nuxt-vue-components-docs, cioè quelli che tirano
  dentro npm 12 e fanno fallire la build al tag
- messaggi da ::warning a ::error, e uscita 1 quando trova qualcosa

Fixes #14 @1h30m
2026-09-12 10:32:27 +02:00
LucaZanni 5973ec9fcc 🐛 fix(ci): la guardia Dockerfile ignora le variabili assegnate nel RUN
- in un RUN espande la shell: una variabile assegnata nel comando stesso
  (VERSIONE="$(...)" && ... ${VERSIONE}) non è la ARG omonima. Era un falso
  avviso su algorithmic-trading, venues/ibkr-gateway/Dockerfile:143
- COPY, LABEL e le altre istruzioni espanse da Docker restano controllate
- collaudo con gawk e gawk --posix: algorithmic-trading 0 avvisi,
  pzeta-king prima della correzione 2, scada-runtime su main 10, Dockerfile
  sintetici con gli esiti attesi; bash -n sullo step estratto dallo YAML

Fixes #13 @25m
refs PZeta_Touch/flux-repo#133
2026-09-11 21:40:53 +02:00
LucaZanni 715860c357 🐛 fix(ci): la guardia Dockerfile dice quando non riesce a leggere le ARG
- l'analisi delle ARG diventa la funzione arg_scope, e all'avvio gira su
  un Dockerfile di prova con una ARG fuori scope nota: se l'awk del runner
  non la riconosce, un ::warning lo dice, il controllo delle ARG salta e
  quello del registry resta, invece di dichiarare in regola ciò che non ha
  potuto leggere
- regex portabile: [$][{]? al posto di \$\{?, che gawk --posix segnalava
  come escape sconosciuto
- collaudo su gawk e gawk --posix (Dockerfile sintetico, pzeta-king prima
  della correzione, vue-pzportal, node-xmlvalidation) e con un awk rotto;
  stesso step, identico, nelle due varianti quality-gates

Fixes #12 @25m
refs PZeta_Touch/flux-repo#133
2026-09-11 21:38:14 +02:00
LucaZanni 9b5159d89e ✨ feat(ci): la guardia Dockerfile anche in quality-gates-github
- stesso step di quality-gates.yml, identico, prima dell'install: i sei
  repository sulla variante -github, fra cui vue-pzportal, ne restavano
  fuori
- solo bash, indipendente da dove si scaricano le action; solo avviso come
  nell'originale

Fixes #11 @25m
refs PZeta_Touch/flux-repo#133
2026-09-11 21:27:00 +02:00
LucaZanni c593f29b0f 🐛 fix(ci): la guardia Dockerfile vede le ARG ereditate da uno stage padre
- una ARG passa agli stage che derivano da quello che la dichiara
  (FROM <stage>), come le ENV: lo prova il log BuildKit di
  nuxt-vue-components-docs v1.0.13, dove deps espande la NPM_VERSION di base
- prima era un falso avviso su ogni Dockerfile con la ARG in uno stage base
- nomi di stage confrontati senza distinzione di maiuscole, come in Docker
- collaudo su un Dockerfile sintetico (ARG globale, padre, fratello,
  nipote, ENV, predefinite, commenti nelle continuazioni): segnala solo i
  due casi attesi

Fixes #10 @25m
refs PZeta_Touch/flux-repo#133
2026-09-11 21:25:21 +02:00
LucaZanni 8949bc7f31 ✨ feat(ci): avviso sui Dockerfile col registry in minuscolo o ARG fuori stage
- quality-gates.yml: nuovo step prima dell'install che scansiona i Dockerfile
  del repository e segnala con ::warning file/riga, più una tabella nel job
  summary, (a) il registry @pzeta scritto pzeta_touch o pzeta e (b) le ARG
  usate in uno stage che non le dichiara
- solo avviso (continue-on-error, uscita sempre 0): bloccante oggi
  fermerebbe i ~46 repo che reggono solo perché pinnano npm 11; lo diventa
  con la tappa 2 di flux-repo#133
- analisi per stage in awk POSIX, collaudata anche con gawk --posix:
  scada-runtime 19 avvisi, pzeta-king 2, vue-pzportal 1, node-xmlvalidation 0

Fixes #9 @1h30m
refs PZeta_Touch/flux-repo#133
2026-09-11 21:21:24 +02:00
LucaZanni 81c871422e 🔧 fix(ci): la deroga al gate dei ruoli arriva allo step che deve saltare
- quality-gates.yml: `owns-auth-roles` esce dal campo `if:` dello step e viene
  letta come env `OWNS_AUTH_ROLES`. In posizione `if:` i valori `with:` del
  chiamante non raggiungono il contesto `inputs` di act_runner, quindi il gate
  bocciava proprio node-user-profiling, l'unico repo autorizzato a dichiarare
  ruoli: tre run rossi e ogni gate successivo saltato
- il nome del repository fa da rete di sicurezza accanto all'input: una deroga
  dichiarata e una constatata, cosi' regge anche se `inputs` non arrivasse
- verificato sui tre casi: deroga via input, deroga via nome con input vuoto,
  repo terzo con le stesse migrazioni (continua a fallire, nessuna regressione)

Fixes #8 @1h30m
2026-09-07 21:31:08 +02:00
LucaZanni 67fccd84e2 ✨ feat(ci): nessun modulo puo' dichiarare ruoli in auth.ruoli
- nuovo step in quality-gates.yml: cerca INSERT INTO auth.ruoli nei file .sql di
  migrations, seeds, sql e database/migrations, e fallisce spiegando cosa fare
  invece — dichiarare un gruppo d'area con i propri permessi, scegliendo il
  livello fra i tredici di piattaforma
- il contratto esisteva dal seed 13 di node-user-profiling e prevedeva questo
  controllo, che non era mai stato scritto: nove microfrontend lo hanno
  disatteso, 21 ruoli creati e 27 su 35 senza omonimo PostgreSQL. Un ruolo cosi'
  nel claim role del JWT e' un SET ROLE che non riesce, e l'utenza di collaudo
  del timesheet ne era la prova
- il boundary dopo `ruoli` tiene fuori auth.ruolipermessi; le righe di commento
  sono ignorate perche' spesso spiegano proprio questa regola
- una-tantum e rollback sono escluse: raccolgono delta generati e script di
  ritorno, fotografie di stati passati che riscrivere falserebbe
- nuovo input owns-auth-roles (default false): solo node-user-profiling, che
  possiede lo schema, lo mette a true. Unica deroga, ed e' esplicita
- verificato su tutti i 30 frontend con migrazioni e sui backend principali:
  nessuno fallisce dopo la ripulitura dei nove repo

Fixes #7 @1h
2026-08-28 10:40:25 +02:00
LucaZanni 6aca13b460 🐛 fix(capacitor-android): il wrapper gradle riceve il bit che Windows non gli da
- Aggiunto lo step "Rendi eseguibile gradlew" prima dei build APK e AAB
- Allineati capacitor-android.yml e la variante GitHub

Fixes #6 @1h30m
2026-08-27 18:47:34 +02:00
4 changed files with 459 additions and 0 deletions
@@ -189,6 +189,13 @@ jobs:
if: inputs.build-type == 'release' if: inputs.build-type == 'release'
run: echo '${{ secrets.KEYSTORE_BASE64 }}' | base64 -d > android/app/keystore.jks run: echo '${{ secrets.KEYSTORE_BASE64 }}' | base64 -d > android/app/keystore.jks
# Il wrapper arriva dal repo senza bit di esecuzione quando il progetto e'
# committato da Windows: git registra mode 100644 e il checkout sul runner
# Linux produce "./gradlew: Permission denied". Il chmod qui vale per ogni
# repo Capacitor, cosi' il difetto non va rincorso uno per uno.
- name: Rendi eseguibile gradlew
run: chmod +x android/gradlew
- name: Build Android (APK) - name: Build Android (APK)
if: inputs.output-format == 'apk' if: inputs.output-format == 'apk'
working-directory: android working-directory: android
+7
View File
@@ -189,6 +189,13 @@ jobs:
if: inputs.build-type == 'release' if: inputs.build-type == 'release'
run: echo '${{ secrets.KEYSTORE_BASE64 }}' | base64 -d > android/app/keystore.jks run: echo '${{ secrets.KEYSTORE_BASE64 }}' | base64 -d > android/app/keystore.jks
# Il wrapper arriva dal repo senza bit di esecuzione quando il progetto e'
# committato da Windows: git registra mode 100644 e il checkout sul runner
# Linux produce "./gradlew: Permission denied". Il chmod qui vale per ogni
# repo Capacitor, cosi' il difetto non va rincorso uno per uno.
- name: Rendi eseguibile gradlew
run: chmod +x android/gradlew
- name: Build Android (APK) - name: Build Android (APK)
if: inputs.output-format == 'apk' if: inputs.output-format == 'apk'
working-directory: android working-directory: android
+183
View File
@@ -46,6 +46,189 @@ jobs:
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Dockerfile - registry @pzeta e ARG per stage
shell: bash
# BLOCCANTE dal 12/09/2026, chiusa la tappa 2 di PZeta_Touch/flux-repo#133.
# Prima era solo un avviso, perche' 56 repo avevano ancora uno dei due
# difetti e bloccare li avrebbe fatti diventare rossi tutti insieme. Ora
# sono corretti: su 238 Dockerfile del portale ne restano difettosi due,
# `vue-conservazione` e `telegram-media-bot`, che non sono repository git
# e quindi non passano di qui.
run: |
# Due difetti che hanno rotto le release di node-xmlvalidation per due
# mesi senza che nessuno se ne accorgesse (PZeta_Touch/flux-repo#129,
# #133): (a) il registry @pzeta scritto in minuscolo nell'.npmrc
# generato dal Dockerfile, mentre i lockfile risolvono su PZeta_Touch;
# (b) una ARG usata in uno stage che non la dichiara, e che li' arriva
# vuota. Insieme, `npm install -g npm@` installa npm 12, che rifiuta
# l'URL scritto diverso (EALLOWREMOTE). Questo job non puo' accorgersene
# da solo: qui l'immagine non si costruisce, e la release fallisce solo
# al tag.
set +e
# La radice del repository e non working-directory: i Dockerfile stanno
# spesso fuori dalla cartella del package.
cd "${GITHUB_WORKSPACE:-.}" || exit 0
files=$(find . \( -name node_modules -o -name .git -o -name dist -o -name build \
-o -name .nuxt -o -name .output -o -name coverage \) -prune -o \
-type f \( -name 'Dockerfile' -o -name 'Dockerfile.*' -o -name '*.Dockerfile' \
-o -name '*.dockerfile' \) -print 2>/dev/null | sed 's|^\./||' | sort)
if [ -z "$files" ]; then
echo "Nessun Dockerfile: controllo non applicabile."
exit 0
fi
# (b) ARG fuori scope: una ARG vale SOLO nello stage che la dichiara.
# Quelle dichiarate prima del primo FROM valgono solo nelle righe FROM,
# e vanno ridichiarate dentro lo stage per essere viste dai RUN
# (documentazione Docker, "Scoping" in build/building/variables).
# Nessuna eredita' da `FROM <stage>`: le ENV si ereditano, le ARG no.
# Una versione precedente di questa guardia presumeva il contrario e
# lasciava passare proprio i casi come nuxt-vue-components-docs, dove
# la ARG dichiarata in `base` veniva usata in `deps` (#133).
arg_scope() {
${AWK:-awk} '
function trim(s) { sub(/^[ \t]+/, "", s); sub(/[ \t]+$/, "", s); return s }
# Nomi dichiarati da ARG/ENV: "A", "A=1", "A=1 B=2", "A valore".
function declared(rest, out, n, i, t) {
rest = trim(rest)
split("", out)
if (rest !~ /=/) { n = split(rest, t, /[ \t]+/); if (n > 0) out[t[1]] = 1; return }
n = split(rest, t, /[ \t]+/)
for (i = 1; i <= n; i++)
if (t[i] ~ /^[A-Za-z_][A-Za-z0-9_]*(=|$)/) { sub(/=.*/, "", t[i]); out[t[i]] = 1 }
}
function handle(kw, rest, ln, n, i, t, base, alias, k, p, s, v, d) {
if (pass == 1) {
if (kw == "ARG") { declared(rest, d); for (k in d) allargs[k] = 1 }
return
}
if (kw == "FROM") {
n = split(trim(rest), t, /[ \t]+/); i = 1
while (i <= n && t[i] ~ /^--/) i++
base = tolower(t[i]); alias = ""
if (i + 2 <= n && toupper(t[i + 1]) == "AS") alias = tolower(t[i + 2])
stages++
stage = (alias != "" ? alias : "#" stages)
# Scope nuovo e vuoto: niente viene ereditato dallo stage di base.
# (Nessun apostrofo qui dentro: chiuderebbe la stringa awk.)
split("", scope)
return
}
if (stage == "") return
if (kw == "ARG") { declared(rest, d); for (k in d) { scope[k] = 1; varof[stage, k] = 1 }; return }
s = rest
while (match(s, /[$][{]?[A-Za-z_][A-Za-z0-9_]*/)) {
v = substr(s, RSTART, RLENGTH); sub(/^[$][{]?/, "", v)
s = substr(s, RSTART + RLENGTH)
# In un RUN espande la shell: una variabile assegnata nel comando
# stesso (VERSIONE="$(...)" && ... ${VERSIONE}) non va scambiata per la ARG.
if (kw == "RUN" && match(rest, "(^|[^A-Za-z0-9_$])" v "=")) continue
if ((v in allargs) && !(v in scope) && !(v in predefined) && !((ln, v) in seen)) {
seen[ln, v] = 1
printf "%d\t%s\t%s\n", ln, v, stage
}
}
if (kw == "ENV") { declared(rest, d); for (k in d) { scope[k] = 1; varof[stage, k] = 1 } }
}
function flush() {
if (buf != "" && match(buf, /^[ \t]*[A-Za-z]+/)) {
kw = toupper(trim(substr(buf, RSTART, RLENGTH)))
handle(kw, substr(buf, RSTART + RLENGTH), start)
}
buf = ""
}
BEGIN {
np = split("TARGETPLATFORM TARGETOS TARGETARCH TARGETVARIANT BUILDPLATFORM BUILDOS BUILDARCH BUILDVARIANT HTTP_PROXY HTTPS_PROXY FTP_PROXY NO_PROXY ALL_PROXY http_proxy https_proxy ftp_proxy no_proxy all_proxy", pp, " ")
for (i = 1; i <= np; i++) predefined[pp[i]] = 1
}
FNR == 1 { pass++; buf = ""; stage = ""; stages = 0; split("", scope); split("", varof) }
{
line = $0; sub(/\r$/, "", line)
if (line ~ /^[ \t]*#/) next # commenti, anche dentro una continuazione
if (buf == "" && line ~ /^[ \t]*$/) next
if (buf == "") start = FNR
if (line ~ /\\[ \t]*$/) { sub(/\\[ \t]*$/, " ", line); buf = buf line; next }
buf = buf line
flush()
}
' "$1" "$1"
}
# Caso di prova: se l'awk di questo runner non riconosce una ARG fuori
# scope nota, il controllo (b) non e' affidabile e lo si dice, invece di
# dichiarare in regola un Dockerfile che non si e' potuto leggere.
argcheck=1
prova=$(mktemp)
printf 'ARG X=1\nFROM scratch AS a\nRUN echo ${X}\n' > "$prova"
if [ "$(arg_scope "$prova" 2>/dev/null | cut -f2)" != "X" ]; then
argcheck=0
echo "::warning::Guardia Dockerfile: l'analisi delle ARG non funziona con l'awk di questo runner ($(${AWK:-awk} -W version 2>&1 | head -1)). Il controllo (b) e' saltato, il (a) resta."
fi
rm -f "$prova"
findings=""
for f in $files; do
# (a) registry: npm confronta l'URL del lockfile come stringa, e i lockfile
# risolvono tutti su PZeta_Touch.
reg=$(grep -nE 'packages/(pzeta_touch|pzeta)/' "$f" 2>/dev/null | cut -d: -f1 | tr '\n' ' ' | sed 's/ *$//')
if [ -n "$reg" ]; then
findings="${findings}${f} ${reg%% *} registry $(echo "$reg" | sed 's/ /, /g') -
"
fi
# (b) ARG fuori scope, con arg_scope definita sopra.
args=""
[ "$argcheck" = "1" ] && args=$(arg_scope "$f" 2>/dev/null)
while IFS=' ' read -r n v st; do
[ -n "$n" ] || continue
findings="${findings}${f} ${n} arg ${v} ${st}
"
done <<EOF
$args
EOF
done
if [ -z "$findings" ]; then
if [ "$argcheck" = "1" ]; then
echo "Dockerfile: registry @pzeta e ARG per stage in regola."
else
echo "Dockerfile: registry @pzeta in regola; ARG per stage non verificate (vedi l'avviso sopra)."
fi
exit 0
fi
summary="## ❌ Dockerfile: difetti della #133"$'\n\n'"| File | Riga | Difetto |"$'\n'"|---|---|---|"$'\n'
count=0
while IFS=' ' read -r f n kind v st; do
[ -n "$f" ] || continue
count=$((count + 1))
if [ "$kind" = "registry" ]; then
msg="registry @pzeta in minuscolo (righe ${v}): i lockfile risolvono su PZeta_Touch e da npm 12 un URL scritto diverso viene rifiutato (EALLOWREMOTE). Scrivere https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/"
else
case "$st" in \#*) st="n. ${st#\#}, senza AS" ;; esac
effetto="il valore e' vuoto"
[ "$v" = "NPM_VERSION" ] && effetto="e' vuota, e 'npm install -g npm@' installa l'ultima ignorando il pin"
msg="ARG ${v} usata nello stage '${st}' senza dichiararla: li' ${effetto}. Aggiungere 'ARG ${v}' dopo il FROM dello stage."
fi
echo "::error file=${f},line=${n}::${msg}"
summary="${summary}| \`${f}\` | ${n} | ${msg} |"$'\n'
done <<EOF
$findings
EOF
echo ""
parola="difetti"; [ "$count" -eq 1 ] && parola="difetto"
echo "${count} ${parola}. Il job si ferma qui: con npm 12 la build dell'immagine"
echo "fallirebbe al tag, cioe' molto piu' tardi e su un log che nessuno guarda"
echo "(e' andata cosi' per due mesi con node-xmlvalidation, PZeta_Touch/flux-repo#129)."
if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then
printf '%s\n%s\n' "$summary" "Riferimento: PZeta_Touch/flux-repo#133" >> "$GITHUB_STEP_SUMMARY" 2>/dev/null
fi
exit 1
- name: Check outdated packages - name: Check outdated packages
run: npm outdated || true run: npm outdated || true
+262
View File
@@ -13,6 +13,13 @@ on:
npm-version: npm-version:
type: string type: string
default: '' default: ''
owns-auth-roles:
description: >-
Solo per il repository proprietario di auth.ruoli (node-user-profiling):
gli consente di dichiarare ruoli nelle proprie migrazioni. Ogni altro
repo deve lasciarlo a false, e il gate qui sotto glielo impedisce.
type: boolean
default: false
jobs: jobs:
quality-gates: quality-gates:
@@ -46,6 +53,261 @@ jobs:
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Nessun ruolo dichiarato fuori da node-user-profiling
shell: bash
env:
# La deroga stava nel campo `if:` dello step, e li' non arriva: nel
# workflow_call di act_runner i valori `with:` del chiamante non
# raggiungono il contesto `inputs` in quella posizione, quindi
# `!inputs.owns-auth-roles` restava vero anche con l'input a true e il
# gate falliva proprio in node-user-profiling, l'unico repository
# autorizzato a dichiarare ruoli. Letta come variabile d'ambiente la
# deroga arriva, e la si confronta come stringa.
OWNS_AUTH_ROLES: ${{ inputs.owns-auth-roles }}
run: |
# `auth.ruoli` appartiene a node-user-profiling e il suo contratto (seed
# 13, esteso dalla migrazione 19) vieta agli altri moduli di crearne.
# Non e' una formalita': il claim `role` del JWT e' il primo ruolo
# applicativo dell'utente e PostgREST ci fa un SET ROLE, ma i ruoli
# PostgreSQL esistono solo per i tredici livelli di piattaforma. Un
# ruolo per-modulo in quel claim e' una sessione che non parte.
# Nove microfrontend lo avevano disatteso: 21 ruoli, 27 su 35 senza
# omonimo PostgreSQL. Questo controllo esiste perche' non si ripeta.
set -uo pipefail
# Il nome del repository e' la rete di sicurezza della deroga: se
# nemmeno l'env dovesse arrivare, il proprietario dello schema si
# riconosce lo stesso e non resta bloccato dal proprio gate. Le due
# condizioni dicono la stessa cosa, una dichiarata e una constatata.
repo="${GITHUB_REPOSITORY:-}"
if [ "${OWNS_AUTH_ROLES:-}" = "true" ] || [ "${repo##*/}" = "node-user-profiling" ]; then
echo "Repository proprietario di auth.ruoli: controllo non applicabile."
exit 0
fi
dirs=""
for d in migrations seeds sql database/migrations; do
[ -d "$d" ] && dirs="$dirs $d"
done
if [ -z "$dirs" ]; then
echo "Nessuna cartella di migrazioni: controllo non applicabile."
exit 0
fi
# Il boundary dopo `ruoli` evita che auth.ruolipermessi finisca fra i
# match; il filtro sulle righe che iniziano per -- lascia passare i
# commenti, che spiegano spesso proprio questa regola.
# Fuori dal controllo le cartelle che non alimentano il catalogo delle
# migrazioni: `una-tantum` raccoglie i delta generati per riallineare a
# mano un tenant, `rollback` gli script di ritorno. Sono strumenti
# operativi, spesso fotografie di uno stato passato, e riscriverli
# significherebbe falsare la storia che documentano.
hits=$(grep -rniE --include='*.sql' \
--exclude-dir=una-tantum --exclude-dir=rollback \
'insert[[:space:]]+into[[:space:]]+auth\.ruoli([[:space:]]|\(|$)' \
$dirs 2>/dev/null \
| awk -F: '{ riga=$0; sub(/^[^:]*:[^:]*:/, "", riga); gsub(/^[[:space:]]+/, "", riga); if (riga !~ /^--/) print }' || true)
if [ -n "$hits" ]; then
echo "::error::Questo repository dichiara ruoli in auth.ruoli, che appartiene a node-user-profiling."
echo ""
echo "$hits"
echo ""
echo "Cosa fare invece: dichiarare un GRUPPO d'area con i permessi del modulo."
echo " INSERT INTO auth.gruppi (nome, nomecompleto, descrizione, tipogruppo, idruololivello)"
echo " ... poi INSERT INTO auth.gruppipermessi per collegarvi i propri permessi."
echo ""
echo "Il livello che accompagna il gruppo si sceglie fra i tredici di piattaforma"
echo "(manager, contabile, auditor, cfo, dipendente, viewer, operatore, cliente):"
echo "sono gli unici ad avere un ruolo PostgreSQL, senza il quale il SET ROLE fallisce."
echo "Esempio: vue-timesheet/migrations/12_gruppi_area.sql"
exit 1
fi
echo "Nessun INSERT INTO auth.ruoli: contratto rispettato."
- name: Dockerfile - registry @pzeta e ARG per stage
shell: bash
# BLOCCANTE dal 12/09/2026, chiusa la tappa 2 di PZeta_Touch/flux-repo#133.
# Prima era solo un avviso, perche' 56 repo avevano ancora uno dei due
# difetti e bloccare li avrebbe fatti diventare rossi tutti insieme. Ora
# sono corretti: su 238 Dockerfile del portale ne restano difettosi due,
# `vue-conservazione` e `telegram-media-bot`, che non sono repository git
# e quindi non passano di qui.
run: |
# Due difetti che hanno rotto le release di node-xmlvalidation per due
# mesi senza che nessuno se ne accorgesse (PZeta_Touch/flux-repo#129,
# #133): (a) il registry @pzeta scritto in minuscolo nell'.npmrc
# generato dal Dockerfile, mentre i lockfile risolvono su PZeta_Touch;
# (b) una ARG usata in uno stage che non la dichiara, e che li' arriva
# vuota. Insieme, `npm install -g npm@` installa npm 12, che rifiuta
# l'URL scritto diverso (EALLOWREMOTE). Questo job non puo' accorgersene
# da solo: qui l'immagine non si costruisce, e la release fallisce solo
# al tag.
set +e
# La radice del repository e non working-directory: i Dockerfile stanno
# spesso fuori dalla cartella del package.
cd "${GITHUB_WORKSPACE:-.}" || exit 0
files=$(find . \( -name node_modules -o -name .git -o -name dist -o -name build \
-o -name .nuxt -o -name .output -o -name coverage \) -prune -o \
-type f \( -name 'Dockerfile' -o -name 'Dockerfile.*' -o -name '*.Dockerfile' \
-o -name '*.dockerfile' \) -print 2>/dev/null | sed 's|^\./||' | sort)
if [ -z "$files" ]; then
echo "Nessun Dockerfile: controllo non applicabile."
exit 0
fi
# (b) ARG fuori scope: una ARG vale SOLO nello stage che la dichiara.
# Quelle dichiarate prima del primo FROM valgono solo nelle righe FROM,
# e vanno ridichiarate dentro lo stage per essere viste dai RUN
# (documentazione Docker, "Scoping" in build/building/variables).
# Nessuna eredita' da `FROM <stage>`: le ENV si ereditano, le ARG no.
# Una versione precedente di questa guardia presumeva il contrario e
# lasciava passare proprio i casi come nuxt-vue-components-docs, dove
# la ARG dichiarata in `base` veniva usata in `deps` (#133).
arg_scope() {
${AWK:-awk} '
function trim(s) { sub(/^[ \t]+/, "", s); sub(/[ \t]+$/, "", s); return s }
# Nomi dichiarati da ARG/ENV: "A", "A=1", "A=1 B=2", "A valore".
function declared(rest, out, n, i, t) {
rest = trim(rest)
split("", out)
if (rest !~ /=/) { n = split(rest, t, /[ \t]+/); if (n > 0) out[t[1]] = 1; return }
n = split(rest, t, /[ \t]+/)
for (i = 1; i <= n; i++)
if (t[i] ~ /^[A-Za-z_][A-Za-z0-9_]*(=|$)/) { sub(/=.*/, "", t[i]); out[t[i]] = 1 }
}
function handle(kw, rest, ln, n, i, t, base, alias, k, p, s, v, d) {
if (pass == 1) {
if (kw == "ARG") { declared(rest, d); for (k in d) allargs[k] = 1 }
return
}
if (kw == "FROM") {
n = split(trim(rest), t, /[ \t]+/); i = 1
while (i <= n && t[i] ~ /^--/) i++
base = tolower(t[i]); alias = ""
if (i + 2 <= n && toupper(t[i + 1]) == "AS") alias = tolower(t[i + 2])
stages++
stage = (alias != "" ? alias : "#" stages)
# Scope nuovo e vuoto: niente viene ereditato dallo stage di base.
# (Nessun apostrofo qui dentro: chiuderebbe la stringa awk.)
split("", scope)
return
}
if (stage == "") return
if (kw == "ARG") { declared(rest, d); for (k in d) { scope[k] = 1; varof[stage, k] = 1 }; return }
s = rest
while (match(s, /[$][{]?[A-Za-z_][A-Za-z0-9_]*/)) {
v = substr(s, RSTART, RLENGTH); sub(/^[$][{]?/, "", v)
s = substr(s, RSTART + RLENGTH)
# In un RUN espande la shell: una variabile assegnata nel comando
# stesso (VERSIONE="$(...)" && ... ${VERSIONE}) non va scambiata per la ARG.
if (kw == "RUN" && match(rest, "(^|[^A-Za-z0-9_$])" v "=")) continue
if ((v in allargs) && !(v in scope) && !(v in predefined) && !((ln, v) in seen)) {
seen[ln, v] = 1
printf "%d\t%s\t%s\n", ln, v, stage
}
}
if (kw == "ENV") { declared(rest, d); for (k in d) { scope[k] = 1; varof[stage, k] = 1 } }
}
function flush() {
if (buf != "" && match(buf, /^[ \t]*[A-Za-z]+/)) {
kw = toupper(trim(substr(buf, RSTART, RLENGTH)))
handle(kw, substr(buf, RSTART + RLENGTH), start)
}
buf = ""
}
BEGIN {
np = split("TARGETPLATFORM TARGETOS TARGETARCH TARGETVARIANT BUILDPLATFORM BUILDOS BUILDARCH BUILDVARIANT HTTP_PROXY HTTPS_PROXY FTP_PROXY NO_PROXY ALL_PROXY http_proxy https_proxy ftp_proxy no_proxy all_proxy", pp, " ")
for (i = 1; i <= np; i++) predefined[pp[i]] = 1
}
FNR == 1 { pass++; buf = ""; stage = ""; stages = 0; split("", scope); split("", varof) }
{
line = $0; sub(/\r$/, "", line)
if (line ~ /^[ \t]*#/) next # commenti, anche dentro una continuazione
if (buf == "" && line ~ /^[ \t]*$/) next
if (buf == "") start = FNR
if (line ~ /\\[ \t]*$/) { sub(/\\[ \t]*$/, " ", line); buf = buf line; next }
buf = buf line
flush()
}
' "$1" "$1"
}
# Caso di prova: se l'awk di questo runner non riconosce una ARG fuori
# scope nota, il controllo (b) non e' affidabile e lo si dice, invece di
# dichiarare in regola un Dockerfile che non si e' potuto leggere.
argcheck=1
prova=$(mktemp)
printf 'ARG X=1\nFROM scratch AS a\nRUN echo ${X}\n' > "$prova"
if [ "$(arg_scope "$prova" 2>/dev/null | cut -f2)" != "X" ]; then
argcheck=0
echo "::warning::Guardia Dockerfile: l'analisi delle ARG non funziona con l'awk di questo runner ($(${AWK:-awk} -W version 2>&1 | head -1)). Il controllo (b) e' saltato, il (a) resta."
fi
rm -f "$prova"
findings=""
for f in $files; do
# (a) registry: npm confronta l'URL del lockfile come stringa, e i lockfile
# risolvono tutti su PZeta_Touch.
reg=$(grep -nE 'packages/(pzeta_touch|pzeta)/' "$f" 2>/dev/null | cut -d: -f1 | tr '\n' ' ' | sed 's/ *$//')
if [ -n "$reg" ]; then
findings="${findings}${f} ${reg%% *} registry $(echo "$reg" | sed 's/ /, /g') -
"
fi
# (b) ARG fuori scope, con arg_scope definita sopra.
args=""
[ "$argcheck" = "1" ] && args=$(arg_scope "$f" 2>/dev/null)
while IFS=' ' read -r n v st; do
[ -n "$n" ] || continue
findings="${findings}${f} ${n} arg ${v} ${st}
"
done <<EOF
$args
EOF
done
if [ -z "$findings" ]; then
if [ "$argcheck" = "1" ]; then
echo "Dockerfile: registry @pzeta e ARG per stage in regola."
else
echo "Dockerfile: registry @pzeta in regola; ARG per stage non verificate (vedi l'avviso sopra)."
fi
exit 0
fi
summary="## ❌ Dockerfile: difetti della #133"$'\n\n'"| File | Riga | Difetto |"$'\n'"|---|---|---|"$'\n'
count=0
while IFS=' ' read -r f n kind v st; do
[ -n "$f" ] || continue
count=$((count + 1))
if [ "$kind" = "registry" ]; then
msg="registry @pzeta in minuscolo (righe ${v}): i lockfile risolvono su PZeta_Touch e da npm 12 un URL scritto diverso viene rifiutato (EALLOWREMOTE). Scrivere https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/"
else
case "$st" in \#*) st="n. ${st#\#}, senza AS" ;; esac
effetto="il valore e' vuoto"
[ "$v" = "NPM_VERSION" ] && effetto="e' vuota, e 'npm install -g npm@' installa l'ultima ignorando il pin"
msg="ARG ${v} usata nello stage '${st}' senza dichiararla: li' ${effetto}. Aggiungere 'ARG ${v}' dopo il FROM dello stage."
fi
echo "::error file=${f},line=${n}::${msg}"
summary="${summary}| \`${f}\` | ${n} | ${msg} |"$'\n'
done <<EOF
$findings
EOF
echo ""
parola="difetti"; [ "$count" -eq 1 ] && parola="difetto"
echo "${count} ${parola}. Il job si ferma qui: con npm 12 la build dell'immagine"
echo "fallirebbe al tag, cioe' molto piu' tardi e su un log che nessuno guarda"
echo "(e' andata cosi' per due mesi con node-xmlvalidation, PZeta_Touch/flux-repo#129)."
if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then
printf '%s\n%s\n' "$summary" "Riferimento: PZeta_Touch/flux-repo#133" >> "$GITHUB_STEP_SUMMARY" 2>/dev/null
fi
exit 1
- name: Check outdated packages - name: Check outdated packages
run: npm outdated || true run: npm outdated || true