sitemap and rss

This commit is contained in:
Gabriel Franco 2026-09-29 12:12:07 -03:00
parent 2db8a6925e
commit 5f114e21e7
13 changed files with 227 additions and 1 deletions

View file

@ -3,6 +3,7 @@ import { defineConfig } from 'astro/config';
import react from '@astrojs/react'; import react from '@astrojs/react';
import mdx from '@astrojs/mdx'; import mdx from '@astrojs/mdx';
import sitemap from '@astrojs/sitemap'
import tailwindcss from '@tailwindcss/vite'; import tailwindcss from '@tailwindcss/vite';
import vercel from '@astrojs/vercel'; import vercel from '@astrojs/vercel';
@ -18,7 +19,7 @@ export default defineConfig({
}, },
}, },
integrations: [react(), mdx()], integrations: [react(), mdx(), sitemap()],
adapter: vercel({ adapter: vercel({
webAnalytics: { enabled: true }, webAnalytics: { enabled: true },

192
package-lock.json generated
View file

@ -11,6 +11,8 @@
"@astrojs/markdown-satteri": "^0.4.0", "@astrojs/markdown-satteri": "^0.4.0",
"@astrojs/mdx": "^8.0.0", "@astrojs/mdx": "^8.0.0",
"@astrojs/react": "^6.0.5", "@astrojs/react": "^6.0.5",
"@astrojs/rss": "^4.0.19",
"@astrojs/sitemap": "^3.7.4",
"@astrojs/vercel": "^11.0.9", "@astrojs/vercel": "^11.0.9",
"@tailwindcss/vite": "^4.3.3", "@tailwindcss/vite": "^4.3.3",
"@types/react": "^19.2.18", "@types/react": "^19.2.18",
@ -289,6 +291,27 @@
"react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0"
} }
}, },
"node_modules/@astrojs/rss": {
"version": "4.0.19",
"resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-4.0.19.tgz",
"integrity": "sha512-e+z5wYeYtffQdHQO8c2tkSd2JEBdAuRXJV4ZEU5IxkYeE6e39woDd7nw1PH1Kk2tEYNCYuKdylnnbhGmt61awA==",
"license": "MIT",
"dependencies": {
"fast-xml-parser": "^5.5.7",
"piccolore": "^0.1.3",
"zod": "^4.3.6"
}
},
"node_modules/@astrojs/sitemap": {
"version": "3.7.4",
"resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.4.tgz",
"integrity": "sha512-LbKNC24bdUWcQf/pThB6qLlSqHojxGjZDURIzFocY8rlWnAn2t74nnhnK6S5x0NHriHoAduLEpVjRykmeGiVvA==",
"license": "MIT",
"dependencies": {
"sitemap": "^9.0.0",
"zod": "^4.3.6"
}
},
"node_modules/@astrojs/telemetry": { "node_modules/@astrojs/telemetry": {
"version": "3.3.3", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.3.tgz", "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.3.tgz",
@ -1894,6 +1917,18 @@
"@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4"
} }
}, },
"node_modules/@nodable/entities": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-3.1.0.tgz",
"integrity": "sha512-LsS/DjHr+uDM647Gru/cA8+J3a3HfhttwCKLyuoyN7yXTFCxKBtSgMQBvrW9yNPa2/zDRUNuGPaH5QUFoa4arQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/nodable"
}
],
"license": "MIT"
},
"node_modules/@oslojs/encoding": { "node_modules/@oslojs/encoding": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz",
@ -2898,6 +2933,15 @@
"@types/unist": "*" "@types/unist": "*"
} }
}, },
"node_modules/@types/node": {
"version": "24.19.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.19.0.tgz",
"integrity": "sha512-zY+5tKxXdhGh1PYI0ac+7juvEu4OI6vWtVVoj5i2m42jxAY1U+zHGt6QCyOFwykdP62sM3MJ9stoYYUw5aCWew==",
"license": "MIT",
"dependencies": {
"undici-types": ">=7.24.0 <7.24.7"
}
},
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "19.2.18", "version": "19.2.18",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz",
@ -2916,6 +2960,15 @@
"@types/react": "^19.2.0" "@types/react": "^19.2.0"
} }
}, },
"node_modules/@types/sax": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz",
"integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/unist": { "node_modules/@types/unist": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
@ -3155,6 +3208,24 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/anynum": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz",
"integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT"
},
"node_modules/arg": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
"license": "MIT"
},
"node_modules/argparse": { "node_modules/argparse": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@ -3941,6 +4012,45 @@
"fast-string-width": "^3.0.2" "fast-string-width": "^3.0.2"
} }
}, },
"node_modules/fast-xml-builder": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.1.tgz",
"integrity": "sha512-pIM/1n3ntFXKYrUZwW7QCK0gAW7XY+wzj1YMIV3tLDvPj/V+zTGJK5e3/4WJfwj0qWw2ElNXiTixda/R+3YSug==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT",
"dependencies": {
"path-expression-matcher": "^1.6.2",
"xml-naming": "^0.3.0"
}
},
"node_modules/fast-xml-parser": {
"version": "5.11.2",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.11.2.tgz",
"integrity": "sha512-R9iDuNrQYeQut46cn2r2wHKn4HYzVDvDm5J1wW+koZewykv0yuO2HChTYeZtrULyHIDM9cj9TUXloCsueCQUog==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT",
"dependencies": {
"@nodable/entities": "^3.0.1",
"fast-xml-builder": "^1.2.0",
"is-unsafe": "^2.0.0",
"path-expression-matcher": "^1.6.2",
"strnum": "^2.4.2",
"xml-naming": "^0.3.0"
},
"bin": {
"fxparser": "src/cli/cli.js"
}
},
"node_modules/fdir": { "node_modules/fdir": {
"version": "6.5.0", "version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
@ -4227,6 +4337,18 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/is-unsafe": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-2.0.2.tgz",
"integrity": "sha512-HgbIHPBH0KHHCcjLfGsCvhtPTVxjaAZlXjwdz7/GQC40SjSe4sfQsar8J5VFo8JOSbarkpV0OLG95bbaNd9aAQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT"
},
"node_modules/isexe": { "node_modules/isexe": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@ -5036,6 +5158,21 @@
"integrity": "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==", "integrity": "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/path-expression-matcher": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz",
"integrity": "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/path-key": { "node_modules/path-key": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@ -5469,6 +5606,25 @@
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/sitemap": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/sitemap/-/sitemap-9.0.1.tgz",
"integrity": "sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==",
"license": "MIT",
"dependencies": {
"@types/node": "^24.9.2",
"@types/sax": "^1.2.1",
"arg": "^5.0.0",
"sax": "^1.4.1"
},
"bin": {
"sitemap": "dist/esm/cli.js"
},
"engines": {
"node": ">=20.19.5",
"npm": ">=10.8.2"
}
},
"node_modules/smol-toml": { "node_modules/smol-toml": {
"version": "1.8.0", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.8.0.tgz", "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.8.0.tgz",
@ -5523,6 +5679,21 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/strnum": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.2.tgz",
"integrity": "sha512-rDG3Ah4TV0k1hWvLSzkZtMmLN9+eS+h3knq4MP6A42Y3Yh5qGNnOUs1jJkoSr8FG5dsL28c7KgkIBzSEykqtuw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT",
"dependencies": {
"anynum": "^1.0.1"
}
},
"node_modules/svgo": { "node_modules/svgo": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-4.1.0.tgz", "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.1.0.tgz",
@ -5692,6 +5863,12 @@
"node": ">=22.19.0" "node": ">=22.19.0"
} }
}, },
"node_modules/undici-types": {
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz",
"integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
"license": "MIT"
},
"node_modules/unified": { "node_modules/unified": {
"version": "11.0.5", "version": "11.0.5",
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
@ -6113,6 +6290,21 @@
"node": ">= 6.0" "node": ">= 6.0"
} }
}, },
"node_modules/xml-naming": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.3.0.tgz",
"integrity": "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT",
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/xxhash-wasm": { "node_modules/xxhash-wasm": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz",

View file

@ -16,6 +16,8 @@
"@astrojs/markdown-satteri": "^0.4.0", "@astrojs/markdown-satteri": "^0.4.0",
"@astrojs/mdx": "^8.0.0", "@astrojs/mdx": "^8.0.0",
"@astrojs/react": "^6.0.5", "@astrojs/react": "^6.0.5",
"@astrojs/rss": "^4.0.19",
"@astrojs/sitemap": "^3.7.4",
"@astrojs/vercel": "^11.0.9", "@astrojs/vercel": "^11.0.9",
"@tailwindcss/vite": "^4.3.3", "@tailwindcss/vite": "^4.3.3",
"@types/react": "^19.2.18", "@types/react": "^19.2.18",

4
public/robots.txt Normal file
View file

@ -0,0 +1,4 @@
User-agent: *
Allow: /
Sitemap: https://gabeefran.co/sitemap-index.xml

View file

@ -10,6 +10,7 @@ const posts = defineCollection({
title: z.string(), title: z.string(),
description: z.string(), description: z.string(),
pubDate: z.coerce.date(), pubDate: z.coerce.date(),
slug: z.string(),
updatedDate: z.coerce.date().optional(), updatedDate: z.coerce.date().optional(),
tags: z.array(z.string()).default([]), tags: z.array(z.string()).default([]),
draft: z.boolean().default(false), draft: z.boolean().default(false),

View file

@ -1,5 +1,6 @@
--- ---
title: "This blog's Hello World (or whatever you want to call this site)" title: "This blog's Hello World (or whatever you want to call this site)"
slug: "hello-world"
description: "A short note on why this exists and what I plan to write about here." description: "A short note on why this exists and what I plan to write about here."
pubDate: 2026-09-22 pubDate: 2026-09-22
tags: ["meta", "blogging"] tags: ["meta", "blogging"]

View file

@ -1,5 +1,6 @@
--- ---
title: "Spotify's Time Capsule Change and the Enshittification of Software" title: "Spotify's Time Capsule Change and the Enshittification of Software"
slug: "spotify-complaining"
description: "Spotify just removed one of its best features. Beyond a bit of complaining, I want to open a debate about what software is turning into." description: "Spotify just removed one of its best features. Beyond a bit of complaining, I want to open a debate about what software is turning into."
pubDate: 2026-09-2 pubDate: 2026-09-2
tags: ["software", "life"] tags: ["software", "life"]

View file

@ -1,6 +1,7 @@
--- ---
title: "Understanding Plugin4Shell: An Exploit That Uses a Simple Git Trick to Fool AI Coding Agents" title: "Understanding Plugin4Shell: An Exploit That Uses a Simple Git Trick to Fool AI Coding Agents"
description: "A git branch named after a commit hash was enough to make AI coding agents run unverified plugins. I reproduced the Plugin4Shell trick on GitHub and Forgejo." description: "A git branch named after a commit hash was enough to make AI coding agents run unverified plugins. I reproduced the Plugin4Shell trick on GitHub and Forgejo."
slug: "understanding-plugin4shell-git-trick-ai-coding-agents"
pubDate: 2026-09-28 pubDate: 2026-09-28
tags: ["cybersecurity", "git", "ai", "software"] tags: ["cybersecurity", "git", "ai", "software"]
seoKeywords: "Plugin4Shell, git branch named after commit hash, SHA pinning bypass, AI coding agents security, Claude Code plugin vulnerability, supply chain attack, git internals, Forgejo" seoKeywords: "Plugin4Shell, git branch named after commit hash, SHA pinning bypass, AI coding agents security, Claude Code plugin vulnerability, supply chain attack, git internals, Forgejo"

View file

@ -2,6 +2,7 @@
title: "O Hello World desse blog (ou seja lá como você queira chamar esse site)" title: "O Hello World desse blog (ou seja lá como você queira chamar esse site)"
description: "Uma nota curta sobre por que isso existe e sobre o que pretendo escrever aqui." description: "Uma nota curta sobre por que isso existe e sobre o que pretendo escrever aqui."
pubDate: 2026-09-22 pubDate: 2026-09-22
slug: "hello-world"
tags: ["meta", "blogging"] tags: ["meta", "blogging"]
--- ---

View file

@ -1,6 +1,7 @@
--- ---
title: "A mudança na cápsula do tempo do Spotify e a bostificação do software" title: "A mudança na cápsula do tempo do Spotify e a bostificação do software"
description: "Spotify simplesmente removeu uma das suas melhores funcionalidades. Além de reclamar um pouco, quero abrir um debate sobre o que os softwares estão se tornando." description: "Spotify simplesmente removeu uma das suas melhores funcionalidades. Além de reclamar um pouco, quero abrir um debate sobre o que os softwares estão se tornando."
slug: "spotify-complaining"
pubDate: 2026-09-2 pubDate: 2026-09-2
tags: ["software", "life"] tags: ["software", "life"]
--- ---

View file

@ -1,6 +1,7 @@
--- ---
title: "Entendendo o Plugin4Shell: um exploit que usa um truque simples do git para enganar agentes de IA de programação" title: "Entendendo o Plugin4Shell: um exploit que usa um truque simples do git para enganar agentes de IA de programação"
description: "Uma branch do git com o nome de um hash de commit bastou para fazer agentes de IA de programação rodarem plugins não verificados. Reproduzi o truque do Plugin4Shell no GitHub e no Forgejo." description: "Uma branch do git com o nome de um hash de commit bastou para fazer agentes de IA de programação rodarem plugins não verificados. Reproduzi o truque do Plugin4Shell no GitHub e no Forgejo."
slug: "understanding-plugin4shell-git-trick-ai-coding-agents"
pubDate: 2026-09-28 pubDate: 2026-09-28
tags: ["cybersecurity", "git", "ai", "software"] tags: ["cybersecurity", "git", "ai", "software"]
seoKeywords: "Plugin4Shell, branch do git com nome de hash de commit, bypass de SHA pinning, segurança de agentes de IA de programação, vulnerabilidade de plugin do Claude Code, ataque à cadeia de suprimentos, internals do git, Forgejo" seoKeywords: "Plugin4Shell, branch do git com nome de hash de commit, bypass de SHA pinning, segurança de agentes de IA de programação, vulnerabilidade de plugin do Claude Code, ataque à cadeia de suprimentos, internals do git, Forgejo"

View file

@ -34,6 +34,7 @@ const canonicalURL = new URL(Astro.url.pathname, Astro.site);
<link rel="alternate" hreflang="en" href={new URL(Astro.url.pathname.replace(/^\/pt/, '') || '/', Astro.site)} /> <link rel="alternate" hreflang="en" href={new URL(Astro.url.pathname.replace(/^\/pt/, '') || '/', Astro.site)} />
<link rel="alternate" hreflang="pt-BR" href={new URL(`/pt${Astro.url.pathname.replace(/^\/pt/, '')}`, Astro.site)} /> <link rel="alternate" hreflang="pt-BR" href={new URL(`/pt${Astro.url.pathname.replace(/^\/pt/, '')}`, Astro.site)} />
<meta name="generator" content={Astro.generator} /> <meta name="generator" content={Astro.generator} />
<link rel="sitemap" href="/sitemap-index.xml" />
<title>{title}</title> <title>{title}</title>
<meta name="description" content={description} /> <meta name="description" content={description} />

19
src/pages/feed.xml.ts Normal file
View file

@ -0,0 +1,19 @@
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';
export async function GET(context) {
const blog = await getCollection('posts');
return rss({
title: 'gabeefran.co',
description: 'Gabriel Franco\'s notes about computer science and other topics',
site: context.site,
items: blog.map((post) => ({
title: post.data.title,
pubDate: post.data.pubDate,
description: post.data.description,
// Compute RSS link from post `slug`
// This example assumes all posts are rendered as `/blog/[slug]` routes
link: `/posts/${post.data.slug}/`,
})),
});
}