From 5b028688ba2cd70dfa08f04ead6abc2b97b65af2 Mon Sep 17 00:00:00 2001 From: Fabio Date: Tue, 29 Sep 2026 17:17:15 +0200 Subject: [PATCH] Primo giorno: script che preparano il PC di chi arriva configura.sh (token Gitea, git, chiave SSH, nomi dei server), verifica.sh (verde/rosso per ogni accesso), progetti.sh (scarica i repository visibili), e un CLAUDE.md che guida la persona senza chiederle mai un segreto in chat. Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 66 +++++++++++++++++++++++++++ README.md | 48 ++++++++++++++++++++ comune.sh | 53 ++++++++++++++++++++++ configura.sh | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++ progetti.sh | 83 ++++++++++++++++++++++++++++++++++ verifica.sh | 80 +++++++++++++++++++++++++++++++++ 6 files changed, 454 insertions(+) create mode 100644 CLAUDE.md create mode 100644 README.md create mode 100755 comune.sh create mode 100755 configura.sh create mode 100755 progetti.sh create mode 100755 verifica.sh diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..fcb3ce9 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,66 @@ +# Istruzioni per Claude: preparare il PC di chi arriva + +Chi apre questo repository è una persona **nuova in OTO**, spesso non +tecnica, al primo giorno. Il tuo compito: portarla da "ho solo le password +provvisorie" a "`./verifica.sh` è tutto verde e ho scaricato i miei +progetti". Parla semplice, un passo alla volta, e controlla ogni passo prima +di passare al successivo. + +La spiegazione per le persone sta in +`https://servizi.oto-farm.com/nuovo-collaboratore.html`: non contraddirla. + +## Regole che non si negoziano + +1. **Mai un segreto in chat.** Token Gitea, chiave e segreto AWS, password, + chiavi private: non chiederli e, se la persona li incolla, dille di + rigenerarli (un token finito in chat va considerato esposto). I segreti + li chiede `configura.sh` nel terminale, con l'input nascosto. +2. **Gli script che chiedono qualcosa li lancia la persona**, in un suo + terminale, non tu: tu non puoi rispondere al posto suo a un prompt + nascosto. Tu lanci solo `./verifica.sh` e i comandi di sola lettura. +3. **Non creare accessi e non chiederli.** Utenti AWS, utenti Gitea, VPN, + chiavi sui server li crea un amministratore (con gli script di `_OTO_IT`). + Se manca qualcosa, dillo con precisione ("serve che l'amministratore ti + aggiunga al repository X") e vai avanti col resto. +4. **Un "accesso negato" di AWS non è un guasto**: è il ruolo della persona. + Lo dici e prosegui. +5. **Non copiare file da altri PC** e non proporlo: se a un progetto manca un + segreto, va messo su AWS SSM da un amministratore. + +## L'ordine + +1. **Programmi**: `./verifica.sh` dice cosa manca tra git, Docker, AWS CLI. + Guida l'installazione per il sistema della persona (Linux, macOS o + Windows con WSL). +2. **AWS**, nel browser: entrare nella console con la password provvisoria, + sceglierne una nuova, attivare l'MFA, poi *nome in alto a destra → + Security credentials → Create access key* (uso: CLI). Poi nel terminale + `aws configure`, con regione `eu-central-1`. Controllo: + `aws sts get-caller-identity` deve mostrare `nome.cognome`. +3. **Gitea**, nel browser: cambiare la password provvisoria, poi + *Impostazioni → Applicazioni → Genera token* con permesso di scrittura + sui repository. +4. **`./configura.sh`**, nel terminale della persona: salva il token Gitea, + configura git, genera la chiave SSH, scrive i nomi dei server in + `~/.ssh/config`. +5. **La chiave SSH pubblica**: `configura.sh` la stampa. La persona la manda + all'amministratore (si può mandare in chat: è la parte pubblica). Ribadisci + che il file **senza** `.pub` non esce dal PC. +6. **VPN**: importare il file ricevuto (Linux: *Impostazioni → Rete → VPN → + + → Importa da file*). +7. **`./verifica.sh`**: tutto verde, o un elenco preciso di cosa manca e a chi + chiederlo. +8. **`./progetti.sh`**: scarica i progetti che la persona vede su Gitea. + Poi, in ogni progetto: `./start.sh` per i progetti con pannello, + `bin/local-init.sh` per Drupal e WordPress. Il resto lo spiega il + `CLAUDE.md` di quel progetto. + +## Stato al 29/09/2026: cosa non è ancora pronto + +Dillo alla persona, invece di farle scoprire un rosso inspiegabile: + +- **le chiavi SSH personali non sono ancora installate sui server**: il + controllo SSH resterà rosso finché l'amministratore non aggiunge la sua; +- **alcuni progetti non hanno ancora tutti i segreti su SSM**: in locale + qualcosa può mancare; +- la produzione nuova non esiste ancora: in `~/.ssh/config` c'è quella vecchia. diff --git a/README.md b/README.md new file mode 100644 index 0000000..ec9b3e1 --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# Primo giorno in OTO: preparare il PC + +Questo repository serve una volta sola: prepara il tuo PC per lavorare sui +progetti OTO. Non contiene segreti. I segreti dei progetti li scaricano i +progetti stessi da AWS, con il tuo accesso personale. + +La spiegazione completa (cosa sono i quattro accessi, chi li crea, cosa fai +quando qualcuno se ne va) è sul portale dei servizi, alla voce **Chi arriva → +Accessi e primo giorno**: `https://servizi.oto-farm.com/nuovo-collaboratore.html`. + +## Prima di iniziare ti servono + +Te li manda l'amministratore: + +- la **password provvisoria di AWS** (utente `nome.cognome`); +- la **password provvisoria di Gitea**, con cui hai scaricato questo repository; +- il **file della VPN**, che arriva dal fornitore della VPN. + +Sul PC ti servono installati **git**, **Docker**, la **AWS CLI** e +**Claude Code**. + +## Come si usa + +```bash +git clone https://git.oto-farm.com/admin/_OTO_IT_onboard.git +cd _OTO_IT_onboard +claude +``` + +e a Claude scrivi: **«configura la mia postazione»**. Ti guida passo per passo +e controlla ogni passo. + +Se preferisci fare da solo: + +```bash +./configura.sh # chiede quello che serve, una cosa per volta +./verifica.sh # dice verde o rosso per ogni accesso +./progetti.sh # scarica i progetti a cui hai accesso +``` + +Puoi rilanciarli quante volte vuoi: quello che è già a posto non viene +toccato. + +## Una regola + +**Token, password e chiavi private non si scrivono mai in chat, nemmeno a +Claude.** Quando serve un segreto, `configura.sh` lo chiede nel terminale senza +mostrarlo a schermo. diff --git a/comune.sh b/comune.sh new file mode 100755 index 0000000..32e2ef2 --- /dev/null +++ b/comune.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# +# Valori e funzioni condivisi dagli script di questo repository. +# Qui non ci sono segreti: solo nomi di server e percorsi. + +GITEA_URL="https://git.oto-farm.com" +GITEA_HOST="git.oto-farm.com" +AWS_REGIONE="eu-central-1" + +# Dove stanno le cose della persona, sul suo PC. Gli script dei progetti +# leggono da qui: non cambiarli senza cambiare anche loro. +TOKEN_GITEA_FILE="$HOME/.config/oto/gitea.token" +CHIAVE_SSH="$HOME/.ssh/oto_ed25519" +CARTELLA_PROGETTI="${CARTELLA_PROGETTI:-$HOME/Work/workspace/oto}" + +# I server, con i nomi che usano gli script dei progetti. Staging sta su rete +# privata: senza VPN non risponde. La produzione "vecchia" e' questa; quando +# arriva la nuova si cambia qui e si rilancia configura.sh. +STAGING_NOME="oto-staging" +STAGING_HOST="10.110.185.10" +PRODUZIONE_NOME="oto-produzione" +PRODUZIONE_HOST="vps-production.oto-farm.com" +UTENTE_SERVER="admin" + +# Un parametro che ogni ruolo di sviluppo puo' leggere: serve a verifica.sh +# per sapere se l'accesso AWS arriva davvero alla cassaforte. +SSM_PROVA="/oto/_comune/MAILTRAP_SMTP_USER" + +if [ -t 1 ] ; then + VERDE=$'\e[32m' ; ROSSO=$'\e[31m' ; GIALLO=$'\e[33m' ; GRASSETTO=$'\e[1m' ; FINE=$'\e[0m' +else + VERDE="" ; ROSSO="" ; GIALLO="" ; GRASSETTO="" ; FINE="" +fi + +ok () { echo " ${VERDE}✔${FINE} $*" ; } +male () { echo " ${ROSSO}✘${FINE} $*" ; } +attento () { echo " ${GIALLO}!${FINE} $*" ; } +titolo () { echo ; echo "${GRASSETTO}$*${FINE}" ; } + +c_e () { command -v "$1" > /dev/null 2>&1 ; } + +token_gitea () { + [ -s "$TOKEN_GITEA_FILE" ] && tr -d '[:space:]' < "$TOKEN_GITEA_FILE" +} + +# Stampa il nome utente Gitea del token, o niente se il token non vale. +utente_gitea () { + local token + token="$(token_gitea)" || return 1 + [ -n "$token" ] || return 1 + curl -s --max-time 10 -H "Authorization: token $token" "$GITEA_URL/api/v1/user" \ + | sed -n 's/.*"login":"\([^"]*\)".*/\1/p' +} diff --git a/configura.sh b/configura.sh new file mode 100755 index 0000000..01d5c2a --- /dev/null +++ b/configura.sh @@ -0,0 +1,124 @@ +#!/bin/bash +# +# PREPARA IL PC: token Gitea, git, chiave SSH, nomi dei server. +# +# ./configura.sh +# +# Si lancia nel proprio terminale (chiede il token Gitea con l'input +# nascosto). Si puo' rilanciare: quello che e' gia' a posto non viene toccato. +# Non crea accessi: quelli li crea un amministratore, qui si usano. + +set -u +cd "$(dirname "$0")" || exit 1 +. ./comune.sh + +# -------------------------------------------------------------------------- +titolo "1. AWS" +# -------------------------------------------------------------------------- +if ! c_e aws ; then + male "AWS CLI non installata: installala e rilancia questo script." +elif IDENTITA="$(aws sts get-caller-identity --query Arn --output text 2> /dev/null)" ; then + ok "accesso AWS: ${IDENTITA##*/}" +else + attento "AWS non ancora configurato. Nel terminale:" + echo " aws configure (regione: $AWS_REGIONE)" + echo " con la chiave che crei dalla console AWS (Security credentials)." +fi + +# -------------------------------------------------------------------------- +titolo "2. Gitea" +# -------------------------------------------------------------------------- +UTENTE="$(utente_gitea)" +if [ -n "$UTENTE" ] ; then + ok "token Gitea gia' salvato (utente $UTENTE)" +else + echo " Incolla il token Gitea (Impostazioni → Applicazioni → Genera token)." + echo " Non si vede mentre lo incolli, ed e' normale." + read -r -s -p " Token: " TOKEN ; echo + TOKEN="$(printf '%s' "$TOKEN" | tr -d '[:space:]')" + mkdir -p "$(dirname "$TOKEN_GITEA_FILE")" + chmod 700 "$(dirname "$TOKEN_GITEA_FILE")" + ( umask 077 ; printf '%s\n' "$TOKEN" > "$TOKEN_GITEA_FILE" ) + UTENTE="$(utente_gitea)" + if [ -n "$UTENTE" ] ; then + ok "token valido, salvato in $TOKEN_GITEA_FILE (utente $UTENTE)" + else + rm -f "$TOKEN_GITEA_FILE" + male "Gitea non accetta questo token: controlla di averlo copiato intero, o generane un altro." + fi +fi + +# git: chi sei, e come si ricorda le credenziali. Il token vale anche come +# password per git: lo si scrive una volta in ~/.git-credentials. +if [ -n "$UTENTE" ] ; then + [ -n "$(git config --global user.name)" ] || git config --global user.name "$UTENTE" + if [ -z "$(git config --global user.email)" ] ; then + read -r -p " La tua email di lavoro (per i commit): " EMAIL + [ -n "$EMAIL" ] && git config --global user.email "$EMAIL" + fi + [ -n "$(git config --global credential.helper)" ] || git config --global credential.helper store + CREDENZIALI="$HOME/.git-credentials" + if ! grep -q "@$GITEA_HOST" "$CREDENZIALI" 2> /dev/null ; then + ( umask 077 ; printf 'https://%s:%s@%s\n' "$UTENTE" "$(token_gitea)" "$GITEA_HOST" >> "$CREDENZIALI" ) + fi + ok "git configurato ($(git config --global user.name) <$(git config --global user.email)>)" +fi + +# -------------------------------------------------------------------------- +titolo "3. Chiave SSH" +# -------------------------------------------------------------------------- +if [ -f "$CHIAVE_SSH" ] ; then + ok "chiave gia' presente: $CHIAVE_SSH" +else + mkdir -p "$HOME/.ssh" && chmod 700 "$HOME/.ssh" + COMMENTO="${UTENTE:-$(whoami)}@oto" + ssh-keygen -q -t ed25519 -f "$CHIAVE_SSH" -C "$COMMENTO" -N "" \ + && ok "chiave creata: $CHIAVE_SSH" +fi +if [ -f "$CHIAVE_SSH.pub" ] ; then + echo + echo " Manda all'amministratore QUESTA riga (e' la parte pubblica, si puo' mandare in chat):" + echo + echo " $(cat "$CHIAVE_SSH.pub")" + echo + echo " Il file $CHIAVE_SSH, senza .pub, non esce mai da questo PC." +fi + +# -------------------------------------------------------------------------- +titolo "4. Nomi dei server in ~/.ssh/config" +# -------------------------------------------------------------------------- +# Un blocco fra due segni, riscritto intero a ogni giro: cosi' quando cambia +# un server basta rilanciare. Un nome gia' definito fuori dal blocco non si +# tocca (e' una configurazione tua). +CONFIG="$HOME/.ssh/config" +touch "$CONFIG" && chmod 600 "$CONFIG" +INIZIO="# >>> OTO (scritto da _OTO_IT_onboard/configura.sh) >>>" +FINE_BLOCCO="# <<< OTO <<<" +# Confronto esatto, non una regex: il segno contiene "/" e "(". +FUORI="$(awk -v i="$INIZIO" -v f="$FINE_BLOCCO" '$0 == i {dentro=1; next} $0 == f {dentro=0; next} !dentro' "$CONFIG")" + +BLOCCO="$INIZIO" +for VOCE in "$STAGING_NOME $STAGING_HOST" "$PRODUZIONE_NOME $PRODUZIONE_HOST" ; do + set -- $VOCE + if printf '%s\n' "$FUORI" | grep -qE "^Host[[:space:]]+$1([[:space:]]|\$)" ; then + attento "$1 e' gia' definito in $CONFIG: lo lascio com'e'" + continue + fi + BLOCCO="$BLOCCO +Host $1 + HostName $2 + User $UTENTE_SERVER + IdentitiesOnly yes + IdentityFile $CHIAVE_SSH +" +done +BLOCCO="$BLOCCO$FINE_BLOCCO" + +{ printf '%s\n' "$FUORI" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' ; echo ; printf '%s\n' "$BLOCCO" ; } > "$CONFIG.nuovo" \ + && mv "$CONFIG.nuovo" "$CONFIG" && chmod 600 "$CONFIG" +ok "ssh $STAGING_NOME e ssh $PRODUZIONE_NOME: configurati" + +# -------------------------------------------------------------------------- +titolo "Fatto" +# -------------------------------------------------------------------------- +echo " Ora: importa il file della VPN, poi lancia ./verifica.sh" diff --git a/progetti.sh b/progetti.sh new file mode 100755 index 0000000..637a848 --- /dev/null +++ b/progetti.sh @@ -0,0 +1,83 @@ +#!/bin/bash +# +# SCARICA I PROGETTI A CUI HAI ACCESSO SU GITEA. +# +# ./progetti.sh # elenca e chiede quali scaricare +# ./progetti.sh nome1 nome2 # scarica questi +# +# Li mette in $CARTELLA_PROGETTI (di solito ~/Work/workspace/oto). Un progetto +# gia' scaricato non si tocca. Vedi solo i repository che l'amministratore ti +# ha dato: se ne manca uno, e' da chiedere a lui. + +set -u +cd "$(dirname "$0")" || exit 1 +. ./comune.sh + +TOKEN="$(token_gitea)" +if [ -z "$TOKEN" ] || [ -z "$(utente_gitea)" ] ; then + male "token Gitea mancante o non valido: lancia prima ./configura.sh" + exit 1 +fi + +# Tutti i repository visibili, pagina per pagina. +ELENCO="" +PAGINA=1 +while : ; do + BLOCCO="$(curl -s --max-time 15 -H "Authorization: token $TOKEN" \ + "$GITEA_URL/api/v1/user/repos?limit=50&page=$PAGINA" \ + | grep -o '"full_name":"[^"]*"' | sed 's/"full_name":"\(.*\)"/\1/')" + [ -z "$BLOCCO" ] && break + ELENCO="$ELENCO +$BLOCCO" + PAGINA=$((PAGINA + 1)) +done +ELENCO="$(printf '%s\n' "$ELENCO" | grep -v '^$' | grep -v '/_OTO_IT_onboard$' | sort -u)" + +if [ -z "$ELENCO" ] ; then + attento "non vedi ancora nessun progetto: chiedi all'amministratore di aggiungerti ai repository" + exit 0 +fi + +if [ "$#" -gt 0 ] ; then + SCELTI="$*" +else + titolo "Progetti che puoi scaricare" + printf '%s\n' "$ELENCO" | sed 's#.*/##' | nl -w3 -s'. ' + echo + read -r -p "Numeri o nomi, separati da spazio (invio = nessuno, 'tutti' = tutti): " RISPOSTA + [ -z "$RISPOSTA" ] && exit 0 + if [ "$RISPOSTA" = "tutti" ] ; then + SCELTI="$(printf '%s\n' "$ELENCO" | sed 's#.*/##')" + else + SCELTI="" + for R in $RISPOSTA ; do + case "$R" in + *[!0-9]*) SCELTI="$SCELTI $R" ;; + *) SCELTI="$SCELTI $(printf '%s\n' "$ELENCO" | sed -n "${R}p" | sed 's#.*/##')" ;; + esac + done + fi +fi + +mkdir -p "$CARTELLA_PROGETTI" +titolo "Scarico in $CARTELLA_PROGETTI" +for NOME in $SCELTI ; do + COMPLETO="$(printf '%s\n' "$ELENCO" | grep -E "/$NOME\$" | head -n 1)" + if [ -z "$COMPLETO" ] ; then + male "$NOME: non lo vedi su Gitea" + continue + fi + if [ -d "$CARTELLA_PROGETTI/$NOME/.git" ] ; then + ok "$NOME: gia' scaricato" + continue + fi + if git clone -q "$GITEA_URL/$COMPLETO.git" "$CARTELLA_PROGETTI/$NOME" ; then + ok "$NOME" + else + male "$NOME: git clone non riuscito" + fi +done + +echo +echo " In ogni progetto: ./start.sh (progetti con pannello) oppure bin/local-init.sh" +echo " (Drupal e WordPress). Apri claude nella cartella del progetto: ti spiega il resto." diff --git a/verifica.sh b/verifica.sh new file mode 100755 index 0000000..e2187f0 --- /dev/null +++ b/verifica.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# +# DICE VERDE O ROSSO PER OGNI ACCESSO, e per ogni rosso cosa fare. +# +# ./verifica.sh +# +# Non modifica niente e non chiede niente: si puo' lanciare quando si vuole, +# anche da Claude. Esce 0 se e' tutto verde, 1 altrimenti. + +set -u +cd "$(dirname "$0")" || exit 1 +. ./comune.sh + +ROSSI=0 +rosso () { male "$@" ; ROSSI=$((ROSSI + 1)) ; } + +titolo "Programmi" +for P in git docker aws curl ssh ; do + if c_e "$P" ; then ok "$P" ; else rosso "$P non installato" ; fi +done +if c_e docker ; then + if docker info > /dev/null 2>&1 ; then ok "Docker risponde" + else rosso "Docker installato ma non risponde (e' acceso? il tuo utente e' nel gruppo docker?)" ; fi +fi +if c_e claude ; then ok "Claude Code" ; else attento "Claude Code non installato (non obbligatorio, ma ti guida)" ; fi + +titolo "AWS" +if c_e aws && IDENTITA="$(aws sts get-caller-identity --query Arn --output text 2> /dev/null)" ; then + ok "accesso: ${IDENTITA##*/}" + if aws ssm get-parameter --region "$AWS_REGIONE" --name "$SSM_PROVA" --query Parameter.Name --output text > /dev/null 2>&1 ; then + ok "legge i segreti comuni su SSM" + else + rosso "non legge SSM: all'amministratore serve darti il ruolo di sviluppo" + fi +else + rosso "AWS non configurato: aws configure (regione $AWS_REGIONE)" +fi + +titolo "Gitea" +UTENTE="$(utente_gitea)" +if [ -n "$UTENTE" ] ; then + ok "token valido (utente $UTENTE)" + if grep -q "@$GITEA_HOST" "$HOME/.git-credentials" 2> /dev/null || [ -n "$(git config --global credential.helper)" ] ; then + ok "git sa come entrare su $GITEA_HOST" + else + rosso "git non ha le credenziali di Gitea: rilancia ./configura.sh" + fi +else + rosso "token Gitea mancante o non valido: rilancia ./configura.sh" +fi + +titolo "Chiave SSH" +if [ -f "$CHIAVE_SSH" ] ; then ok "$CHIAVE_SSH" ; else rosso "chiave mancante: rilancia ./configura.sh" ; fi + +titolo "VPN e server" +# La VPN si riconosce da una cosa sola: staging, che sta su rete privata, +# risponde sulla porta SSH. +if timeout 5 bash -c "exec 3<>/dev/tcp/$STAGING_HOST/22" 2> /dev/null ; then + ok "VPN attiva (staging raggiungibile)" + if ssh -o BatchMode=yes -o ConnectTimeout=8 "$STAGING_NOME" true 2> /dev/null ; then + ok "entri su staging ($STAGING_NOME)" + else + rosso "staging non accetta la tua chiave: l'amministratore deve ancora aggiungerla" + fi +else + rosso "staging non raggiungibile: la VPN e' accesa?" +fi +if ssh -o BatchMode=yes -o ConnectTimeout=8 "$PRODUZIONE_NOME" true 2> /dev/null ; then + ok "entri in produzione ($PRODUZIONE_NOME)" +else + attento "produzione: non entri (normale se non hai il ruolo di rilascio, o se la tua chiave non e' ancora stata aggiunta)" +fi + +titolo "Risultato" +if [ "$ROSSI" = "0" ] ; then + ok "tutto a posto. Prossimo passo: ./progetti.sh" + exit 0 +fi +male "$ROSSI cose da sistemare (sopra, in rosso)" +exit 1