Ti serve davvero WordPress? Migra il tuo blog su S3 + CloudFront con Claude in meno di un'ora
Tradotto dall'originale in spagnolo. Leggi in spagnolo
WordPress, Drupal, Joomla — sono piattaforme mature e risolvono molti casi. E sì, per un sito con utenti, form, e-commerce o una redazione, hanno ancora senso. Ma se tutto quello che fai è pubblicare articoli, stai pagando un prezzo alto per cose che non usi: PHP, un database, plugin da patchare e un pannello di admin esposto su internet.
L’alternativa è vecchia e noiosa: HTML statico in un bucket S3, servito da CloudFront. Quello che è cambiato è il costo della migrazione. Con Claude Code, la migrazione completa — contenuti, infrastruttura in stage e prod, pipeline — mi ha richiesto tra 30 e 50 minuti.
Come riferimento: stimo che un senior dev che conosce AWS, facendo la stessa cosa a mano per un sito di 50 post, impieghi tra 3 e 5 giorni di lavoro — circa 20-35 ore. La maggior parte non è l’infra, ma convertire e ripulire i contenuti post per post e replicare il theme. Se ha già l’infra in Terraform o CDK, si scende a un giorno e mezzo o due. Resta comunque un’altra scala.
Ecco il passo passo, con i dettagli tecnici e — soprattutto — il modello di sicurezza.

Ti serve un CMS? I trade-off
Prima di migrare, conviene essere onesti su cosa perdi e cosa guadagni.
Cosa guadagni:
- Superficie d’attacco quasi nulla — niente PHP, niente database, niente
/wp-admin. Non c’è nulla da eseguire lato server, quindi non c’è nulla da sfruttare. - Zero manutenzione — basta update di core, plugin e theme. Un sito statico di cinque anni fa funziona ancora allo stesso modo.
- Costo — per un blog piccolo, centesimi al mese. CloudFront ha un free tier di 1 TB di traffico al mese.
- Performance — tutto viene servito dall’edge di CloudFront. Nessun render per request.
- Versioning vero — l’intero sito vive in Git. Ogni modifica ha cronologia, review e rollback.
Cosa perdi:
- Commenti — si risolvono con un servizio esterno (Giscus, per esempio) oppure si eliminano. Io li ho eliminati.
- Form — ti serve un endpoint separato (Lambda, Formspree). Aggiunge un pezzo in movimento.
- Ricerca — solo lato client (Pagefind, Lunr). Funziona bene fino a qualche migliaio di post.
- L’editor visuale — scrivi in Markdown. Se non fa per te, più sotto ti mostro come Claude risolve questa parte.
Se la lista di quello che perdi non ti pesa, continua a leggere.
L’architettura
Il design finale è semplice:
- GitHub repo — i contenuti in Markdown e il generatore di siti statici (uso Astro).
- GitHub Actions — una pipeline che fa il build e pubblica su stage a ogni push su
main, e su prod dopo un’approvazione manuale. - S3 — due bucket privati, uno per ambiente. Niente website hosting, niente accesso pubblico.
- CloudFront — una distribuzione per ambiente, con Origin Access Control (OAC) per leggere dal bucket, un certificato ACM e una CloudFront Function per gli URL.
- IAM — due identità diverse, con permessi diversi: una temporanea perché Claude faccia la migrazione, e un role per ambiente per la pipeline, via OIDC.
Il modello di sicurezza, prima di toccare qualsiasi cosa
L’idea iniziale era dare a Claude una access key, creare il repo, creare le pipeline e fine. Funziona. Ma rivedendola emergono tre problemi, e li ho corretti prima di iniziare:
- Claude non può avere permessi IAM. Se lo user di Claude può creare role e policy, può concedersi qualsiasi permesso — è escalation di privilegi by design. L’OIDC provider e i role della pipeline li crei tu.
- La pipeline non usa access key. Niente
AWS_ACCESS_KEY_IDnei GitHub Secrets. GitHub Actions si autentica su AWS con OIDC e riceve credenziali temporanee, e la trust policy limita quale repo e quale ambiente può assumere ciascun role. - Claude non può modificare la pipeline. Se l’agente può modificare
.github/workflows/, può cambiare dove si pubblica e con quali permessi. I workflow li committi tu, e il token di Claude non ha il permesso di toccarli.
La regola che applico: l’agente opera entro i limiti; non definisce mai i limiti.
Passo passo
1. Crea l’IAM user per Claude
Nella console IAM, crea uno user senza accesso alla console — per esempio claude-migration. Assegnagli questa policy inline. Sostituisci mi-blog con il prefisso dei tuoi bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "SiteBucketsOnly",
"Effect": "Allow",
"Action": [
"s3:CreateBucket",
"s3:PutBucketPolicy",
"s3:GetBucketPolicy",
"s3:PutBucketPublicAccessBlock",
"s3:GetBucketPublicAccessBlock",
"s3:PutBucketOwnershipControls",
"s3:PutEncryptionConfiguration",
"s3:ListBucket",
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::mi-blog-*",
"arn:aws:s3:::mi-blog-*/*"
]
},
{
"Sid": "CloudFront",
"Effect": "Allow",
"Action": [
"cloudfront:CreateDistribution",
"cloudfront:UpdateDistribution",
"cloudfront:GetDistribution",
"cloudfront:GetDistributionConfig",
"cloudfront:ListDistributions",
"cloudfront:CreateOriginAccessControl",
"cloudfront:GetOriginAccessControl",
"cloudfront:ListOriginAccessControls",
"cloudfront:CreateFunction",
"cloudfront:UpdateFunction",
"cloudfront:DescribeFunction",
"cloudfront:TestFunction",
"cloudfront:PublishFunction",
"cloudfront:CreateResponseHeadersPolicy",
"cloudfront:ListResponseHeadersPolicies",
"cloudfront:ListCachePolicies",
"cloudfront:CreateInvalidation",
"cloudfront:GetInvalidation"
],
"Resource": "*"
},
{
"Sid": "Certificates",
"Effect": "Allow",
"Action": [
"acm:RequestCertificate",
"acm:DescribeCertificate",
"acm:ListCertificates"
],
"Resource": "*"
}
]
}
Tre cose da notare:
- S3 è limitato per ARN — Claude può toccare solo i bucket che iniziano con il tuo prefisso. Non c’è
s3:DeleteBucket: cancellare un bucket è una tua decisione. - CloudFront usa
"Resource": "*"— la creazione di distribuzioni non ammette restrizioni per risorsa. È il punto più ampio della policy, ed è il motivo per cui la key esiste solo durante la migrazione. - Non c’è nessuna azione IAM. Di proposito.
Se durante la migrazione compare un AccessDenied, Claude ti dirà quale azione manca. Aggiungi solo quella. Non mettere cloudfront:* per sbloccare.
Crea la access key dello user e configurala in un profile dedicato, non in quello di default:
aws configure --profile claude-migration
export AWS_PROFILE=claude-migration
aws sts get-caller-identity
Non incollare mai la key nella chat con Claude. L’agente usa il profile; non ha bisogno di vedere il segreto.
2. Crea il repo e limita quello che Claude può fare
Crea il repo su GitHub (privato, anche se il sito è pubblico — non serve esporre le bozze). Poi genera un fine-grained personal access token:
- Repository access — solo questo repo.
- Contents — read and write.
- Pull requests — read and write.
- Workflows — nessun accesso. Così Claude non può fare push di modifiche in
.github/workflows/. - Expiration — 7 giorni.
Lato Claude Code, aggiungi un .claude/settings.json nel repo con regole sui permessi:
{
"permissions": {
"deny": [
"Read(~/.aws/**)",
"Bash(aws iam:*)",
"Bash(aws s3 rb:*)"
],
"ask": [
"Bash(aws cloudfront create-distribution:*)",
"Bash(aws cloudfront update-distribution:*)",
"Bash(aws s3 sync:*)",
"Bash(git push:*)"
]
}
}
Tieni presente che questo è un secondo livello, non quello principale. Un deny su Read non impedisce un cat da Bash. Il controllo vero è la policy IAM del passo precedente. Le regole di Claude Code servono a far passare le operazioni importanti dalla tua approvazione.
3. Migra i contenuti: Claude legge WordPress via MCP
Qui non ci sono export, né XML, né script di conversione. Installo il plugin AI Engine (di Meow Apps) su WordPress, che espone un MCP server, e collego Claude direttamente al sito. Claude legge tutti i post, le categorie e i tag, scarica le immagini e costruisce il nuovo sito. Fa tutto Claude.
Per l’autenticazione uso OAuth, non un Bearer Token statico. La differenza conta:
- Nessun segreto condiviso — non c’è un token da copiare, incollare in un comando e che finisce nella history della shell o in un file di config.
- Identità reale — ogni autorizzazione è legata a un utente WordPress, con un login normale e una schermata di consenso che mostra quale app chiede l’accesso e con quale ruolo.
- Revoca con un clic — il pannello Connected Apps di AI Engine elenca ogni autorizzazione attiva.
In WordPress, AI Engine → Settings → MCP: attiva l’MCP server. Con OAuth non serve definire un Bearer Token — AI Engine pubblica gli endpoint di discovery (/.well-known/oauth-*) e il client si registra da solo via Dynamic Client Registration. Dal repo:
claude mcp add --transport http wp-origen https://mi-sitio.com/wp-json/mcp/v1/http
Poi, dentro Claude Code, esegui /mcp, scegli wp-origen e Authenticate. Si apre il browser, fai login su WordPress e approvi. Il token resta nello storage sicuro di Claude Code, non in un file del repo.
Ed ecco la distinzione che più spesso sfugge: con OAuth, Claude ha i permessi dell’utente con cui fai login. Se approvi come admin, Claude è admin — può cancellare post, cambiare settings, installare plugin se il gruppo è esposto. OAuth migliora l’autenticazione; non restringe l’autorizzazione. Per questo:
- Crea un utente dedicato — per esempio
claude-migracion, con il ruolo più basso che gli permetta di leggere quello che ti serve. Non approvare con il tuo account admin. - Esponi solo il necessario — nella schermata MCP, lascia attivo solo il gruppo WordPress (post, media, tassonomie). Plugins, Themes e Dynamic REST, spenti.
- Controlla il WAF — alcuni hosting bloccano i POST verso
/wp-json/mcp/v1/oauth/registere la registrazione fallisce. Se succede, bisogna consentire/.well-known/oauth-*e/wp-json/mcp/v1/*.
Se la tua versione di AI Engine richiede un utente admin per l’MCP, il trade-off cambia: un Bearer Token con access level Read-Only viene limitato lato server, e allora può essere l’opzione più sicura delle due. Verificalo prima di scegliere.
Come secondo livello, blocca le tool di scrittura lato Claude Code. Aggiungi al .claude/settings.json:
{
"permissions": {
"deny": [
"mcp__wp-origen__wp_create_post",
"mcp__wp-origen__wp_update_post",
"mcp__wp-origen__wp_delete_post",
"mcp__wp-origen__wp_upload_media",
"mcp__wp-origen__wp_update_option"
]
}
}
I nomi esatti delle tool dipendono dalla versione del plugin — con /mcp vedi l’elenco. Blocca tutto ciò che scrive. A Claude servono solo le tool di lettura.
Con l’MCP collegato, il prompt:
Conectate al MCP wp-origen y migrá el sitio a Astro en este repo.
- Leé todos los posts publicados, con sus categorías, tags y excerpt.
- Convertí cada post a Markdown en una content collection, con front
matter: title, date, slug, categories, tags, description.
- Mantené exactamente las mismas URLs que en WordPress.
- Bajá todas las imágenes referenciadas (incluida la featured image)
a public/images/ y reescribí las rutas.
- Convertí los shortcodes y bloques de Gutenberg a HTML limpio.
- Ignorá comentarios, drafts y páginas de sistema.
- No escribas nada en WordPress: sólo lectura.
- Antes de escribir código, armá un plan en PLAN.md y esperá mi OK.
Rivedi il piano. Con attenzione. Quello che si rompe di più in questa fase sono gli URL: se cambiano, perdi la SEO accumulata e tutti i link esterni. In Astro, la route è definita dalla struttura di src/pages/ — per esempio src/pages/[year]/[month]/[slug].astro se il tuo WordPress usa /%year%/%monthnum%/%postname%/. Se la struttura coincide, non ci sono redirect da mantenere.
Lascia il build.format di Astro su directory (il default): genera /mi-post/index.html, che è ciò che poi risolve la CloudFront Function del passo 4. E crea src/pages/404.astro — il build lo trasforma in 404.html.
Per l’anteprima in locale:
npm run dev
E qui c’è un rischio che spesso sfugge: il contenuto che Claude sta leggendo è untrusted (non affidabile). Post vecchi, HTML incollato da altri siti, un commento spam che è passato. Un testo con istruzioni nascoste è un vettore di prompt injection — e con un MCP che può scrivere sul tuo sito live, il danno possibile non è più solo locale. Per questo le tool di scrittura vanno in deny, non in ask, e per questo i permessi AWS sono minimi.
L’alternativa senza MCP è l’export nativo (Tools → Export, formato WXR) più una copia di wp-content/uploads. Non tocca il sito live, ma tocca a te scaricare e organizzare i file. Per un sito con pochi post, l’MCP è parecchio più veloce.
4. Chiedi a Claude l’infrastruttura
Con il sito che fa il build in locale, chiedi a Claude di creare l’infra per stage e prod. Questo è ciò che deve risultare, e ciò che conviene verificare:
- Bucket privati — Block Public Access attivo su tutti e quattro i flag, niente static website hosting. CloudFront legge tramite l’endpoint REST del bucket, non quello website.
- Origin Access Control — non il legacy OAI. Il bucket accetta
s3:GetObjectsolo da quella distribuzione specifica. - Certificato ACM in
us-east-1— CloudFront accetta solo certificati di quella region, indipendentemente da dove si trovino i bucket. La validazione è via DNS. - Response headers policy — HSTS,
X-Content-Type-Options,X-Frame-Options,Referrer-Policy. La managed policy SecurityHeadersPolicy copre le basi. - TLS minimo —
TLSv1.2_2021e redirect da HTTP a HTTPS.
La bucket policy che deve risultare in prod:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontOAC",
"Effect": "Allow",
"Principal": { "Service": "cloudfront.amazonaws.com" },
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::mi-blog-prod/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::ACCOUNT_ID:distribution/DISTRIBUTION_ID"
}
}
}
]
}
5. Collega GitHub ad AWS via OIDC (questo lo fai tu)
Questo è il passo che non delego a Claude, perché richiede permessi IAM. Prima, l’identity provider (una volta per account):
aws iam create-open-id-connect-provider \
--url https://token.actions.githubusercontent.com \
--client-id-list sts.amazonaws.com
Poi, un role per ambiente. La trust policy del role di prod:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:TU_USUARIO/TU_REPO:environment:production"
}
}
}
]
}
La condizione su sub è quella che garantisce “solo questo repo può pubblicare”. E va oltre: solo un job che gira nell’environment production di quel repo può assumere il role. Usa StringEquals, non StringLike con wildcard — un repo:TU_USUARIO/* apre l’accesso a tutti i tuoi repo.
Il role di stage è identico, con environment:staging e puntato sul bucket di stage.
I permessi del role di prod — solo ciò che serve al deploy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::mi-blog-prod"
},
{
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:DeleteObject", "s3:GetObject"],
"Resource": "arn:aws:s3:::mi-blog-prod/*"
},
{
"Effect": "Allow",
"Action": "cloudfront:CreateInvalidation",
"Resource": "arn:aws:cloudfront::ACCOUNT_ID:distribution/DISTRIBUTION_ID"
}
]
}
Qui CreateInvalidation ammette la restrizione per ARN. La pipeline può pubblicare in un bucket e invalidare una distribuzione. Nient’altro.
6. Le pipeline di stage e prod
Nel repo, Settings → Environments, crea due environment:
- staging — deployment branch: solo
main. Variabili:AWS_ROLE_ARN,BUCKET,DISTRIBUTION_ID,SITE_URL. - production — deployment branch: solo
main, required reviewer: tu. Le stesse variabili, con i valori di prod.
Sono variabili, non secret. Un role ARN non è un segreto — senza il token OIDC del tuo repo non serve a nulla.
Il workflow, in .github/workflows/deploy.yml, ha tre job:
- check — gira a ogni PR. Installa le dipendenze con
npm cie fa il build. Non chiede credenziali AWS. - deploy-stage — gira a ogni push su
main, nell’environmentstaging. Fa il build, assume il role di stage via OIDC, carica il sito conaws s3 sync --deletee invalida la cache di CloudFront. - deploy-prod — dipende da stage e gira nell’environment
production. Gli stessi passi, con il role e le variabili di prod.
Due dettagli che fanno la differenza: il permesso id-token: write è dichiarato solo nei job di deploy, non a livello di workflow, e tutti e tre i job leggono tutto dalle variabili dell’environment — lo stesso codice pubblica su stage o su prod a seconda di dove gira.
Il flusso diventa questo: una PR fa solo il build — senza credenziali AWS, quindi una PR malevola non può pubblicare nulla. Un merge su main pubblica su stage automaticamente. Prod resta in attesa della tua approvazione nella scheda Actions. Approvi, e pubblica.
Sull’invalidazione: /* conta come un solo path, e i primi 1.000 path al mese sono gratuiti. Per un blog, invalidare tutto a ogni deploy è l’opzione più semplice e non costa nulla.
Fare il build due volte (una per ambiente) è voluto: l’URL del sito cambia, e Astro lo incorpora nell’HTML — canonical, sitemap, RSS. In astro.config.mjs:
export default defineConfig({
site: process.env.SITE_URL,
build: { format: 'directory' },
});
Nella pipeline, SITE_URL arriva dalla variabile dell’environment. Il costo sono pochi secondi in più di build.
7. Proteggi la pipeline
La pipeline ora è l’unica strada verso prod. Questo la rende l’asset da proteggere:
- Branch protection su
main— PR obbligatoria, status checkcheckverde, niente force push. - CODEOWNERS su
.github/— qualsiasi modifica ai workflow richiede la tua review. - Required reviewer su production — già configurato nel passo precedente. È l’ultimo controllo umano prima di pubblicare.
8. Cutover
Con prod pubblicato e verificato sull’URL di CloudFront (dxxxx.cloudfront.net):
- Abbassa il TTL del record DNS a 300 secondi, il giorno prima.
- Punta il dominio alla distribuzione: un alias record in Route 53, o un CNAME presso il tuo provider (per l’apex, usa ALIAS/ANAME se supportato).
- Verifica che i vecchi URL rispondano. Basta uno script semplice che percorra la sitemap di WordPress e confronti i codici HTTP.
- Tieni WordPress spento — non cancellato — per un paio di settimane, nel caso salti fuori qualcosa che è sfuggito.
9. Chiudi tutto ciò che hai aperto per la migrazione
Prima, la key AWS:
aws iam update-access-key \
--user-name claude-migration \
--access-key-id AKIAXXXXXXXXXXXXXXXX \
--status Inactive
E toglila da ~/.aws/credentials. Una key inattiva su disco è ancora una key che aspetta che qualcuno la riattivi.
Il mio consiglio, in realtà, è fare un passo in più: cancellarla. Quando ti serve, ne crei una nuova — ci vogliono dieci secondi e ti assicura che nessuna key vecchia resti dimenticata. Revoca anche il token di GitHub, o lascialo scadere.
Poi, l’MCP. Se WordPress resta online durante il periodo di transizione, revoca l’autorizzazione in Connected Apps, disattiva l’MCP in AI Engine e cancella l’utente claude-migracion. Se il plugin serviva solo per la migrazione, disinstallalo. E lato Claude Code:
claude mcp remove wp-origen
Un MCP con permessi di scrittura su un sito che non usi più è esattamente il tipo di cosa che si dimentica e resta aperta.
Claude è il tuo editor “visuale”
Ecco cosa convince chi non vuole saperne di Markdown né di Git. Il pannello di WordPress sparisce, e l’editor diventa una conversazione. Apri Claude Code nel repo e gli dici:
Creá un post nuevo. Este es mi draft:
[tu texto, bla bla]
Categoría Tecnología.
Levantá npm run dev para que lo revise.
Cuando te dé el OK, creá una branch, commiteá y abrí un PR.
Controlli su localhost:4321, chiedi modifiche — “accorcia l’intro”, “sposta l’immagine sotto il primo paragrafo”, “cambia il titolo” — e approvi. Claude apre la PR, il check passa, fai il merge, stage si aggiorna da solo, approvi prod. Fatto.
Per questo non servono credenziali AWS. A Claude basta il token di GitHub — il deploy lo fa la pipeline. È la configurazione che lascio in modo permanente.
Uno skill con le regole del tuo blog
Il prompt qui sopra funziona, ma lascia molto a ciò che Claude deduce dai post esistenti. Il modo per fissarlo è uno skill: un file con le regole di come deve essere un post, che Claude carica ogni volta che gliene chiedi uno. È quello che fa un editor — conoscere il manuale di stile senza che tu debba ripeterlo.
Vive nel repo, in .claude/skills/nuevo-post/SKILL.md:
---
name: nuevo-post
description: Crea o edita posts del blog. Usar siempre que se pida
escribir, corregir o publicar un post.
---
# Nuevo post
## Front matter (obligatorio)
- title, date (ISO), slug en kebab-case, description (máx. 160 caracteres)
- categories: sólo Tecnología, Seguridad o AI
- tags: entre 2 y 5
## Estilo
- Español, primera persona, frases cortas.
- Términos técnicos en inglés, sin traducir.
- Apertura con el problema, no con una definición.
- Un H2 por sección. Nada de H1 en el cuerpo.
## Imágenes
- En public/images/[slug]/, formato webp, máx. 1600px de ancho.
- alt obligatorio y descriptivo.
- La principal va debajo de la intro.
## Flujo
1. Crear el archivo en src/content/blog/[slug].md como draft: true.
2. Levantar npm run dev y pasar la URL local.
3. Aplicar los cambios que pida.
4. Con el OK: draft: false, branch post/[slug], commit y PR.
Nunca pushear directo a main.
Con lo skill, il prompt si riduce a “crea un post da questo draft”. Il resto — formato, immagini, categorie, il flusso fino alla PR — è già definito.
La verifica di sicurezza, in sintesi
Questi sono i rischi che ho esaminato, e come resta ciascuno:
- Access key a lunga durata — mitigato. Esiste solo durante la migrazione, in un profile separato, e poi viene cancellata. Rischio residuo: la finestra della migrazione, meno di un’ora.
- Escalation di privilegi via IAM — eliminato. Lo user di Claude non ha nessuna azione IAM; i role della pipeline li crei tu.
- Policy di CloudFront con
Resource: *— accettato. È un limite dell’API. Durante la migrazione, Claude potrebbe modificare altre distribuzioni dell’account. Se hai altre distribuzioni in produzione, fai la migrazione in un account separato di AWS Organizations. - Credenziali su GitHub — eliminato. OIDC con credenziali temporanee, niente secret.
- Un altro repo che pubblica nel tuo bucket — eliminato. La trust policy richiede repo ed environment esatti.
- Agente che modifica la pipeline — mitigato. Il token non ha il permesso Workflows, e CODEOWNERS richiede la tua review.
- Prompt injection dai contenuti importati — mitigato, non eliminato. Il blast radius è limitato dai permessi, e i comandi sensibili richiedono la tua approvazione.
- Bucket esposto — eliminato. Block Public Access, niente website hosting, OAC legato a una distribuzione.
s3 sync --deleteche cancella troppo — accettato. Se un build esce vuoto, cancella il sito. Attiva il versioning sul bucket di prod: recuperi qualsiasi versione precedente per pochi centesimi.- MCP con scrittura sul WordPress live — mitigato. OAuth con un utente dedicato a ruolo basso, solo il gruppo WordPress esposto, tool di scrittura in
deny, e autorizzazione revocata e MCP spento alla fine. Rischio residuo: l’endpoint resta esposto su internet finché è attivo, e i permessi reali sono quelli del ruolo dell’utente. - Supply chain — mitigato. Action fissate per SHA,
npm cicon lockfile committato.
Meno di un’ora? Dipende
Per un blog di qualche decina di post, sì. Quei 30-50 minuti sono tempo mio passato a rivedere e approvare; buona parte non è lavoro di Claude, ma attesa: la validazione del certificato ACM, il deploy iniziale di CloudFront (diversi minuti) e la propagazione DNS. Se il sito ha centinaia di post con shortcode custom dei plugin, aggiungi tempo di revisione — la conversione avrà bisogno di più di un’iterazione.
Questo è un modo di farlo. I componenti sono intercambiabili — Astro con Hugo, AI Engine con l’export nativo, GitHub Actions con un’altra CI, Route 53 con il tuo DNS attuale. Quello che non cambierei è il modello dei permessi: l’agente con il minimo e per un tempo limitato, la pipeline senza key, e un umano che approva ciò che arriva in prod.
