diff --git a/.gitea/workflows/quality-gates-github.yml b/.gitea/workflows/quality-gates-github.yml index 1b6e20f..cba0f4b 100644 --- a/.gitea/workflows/quality-gates-github.yml +++ b/.gitea/workflows/quality-gates-github.yml @@ -46,6 +46,157 @@ jobs: 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 + - name: Dockerfile - registry @pzeta e ARG per stage (solo avviso) + shell: bash + # Solo avviso finche' i ~46 repo con il registry in minuscolo non sono + # corretti: bloccante oggi li farebbe diventare rossi tutti insieme. + # Diventa bloccante con la tappa 2 di PZeta_Touch/flux-repo#133. + continue-on-error: true + 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 + + 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: una ARG vale nello stage che la dichiara e in + # quelli che ne derivano (FROM ), come le ENV; quelle dichiarate + # prima del primo FROM valgono solo nelle righe FROM. Verificato sul + # log di BuildKit di nuxt-vue-components-docs v1.0.13: `FROM base AS + # deps` vede la NPM_VERSION dichiarata in `base`. + args=$(${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) + split("", scope); split("", inh) + for (k in varof) { split(k, p, SUBSEP); if (p[1] == base) inh[p[2]] = 1 } + for (k in inh) { scope[k] = 1; varof[stage, k] = 1 } + 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) + 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() + } + ' "$f" "$f" 2>/dev/null) + while IFS=' ' read -r n v st; do + [ -n "$n" ] || continue + findings="${findings}${f} ${n} arg ${v} ${st} + " + done <> "$GITHUB_STEP_SUMMARY" 2>/dev/null + fi + exit 0 + - name: Check outdated packages run: npm outdated || true