CI/CD
GitHub Actions-cache: hoe die werkt en wat die verbergt
De GitHub Actions-cache bewaart bestanden tussen workflowruns, zodat jobs downloads overslaan die ze al hebben gedaan. Dat maakt builds sneller. Het betekent ook dat pakketten in uw build terechtkomen zonder te zijn opgehaald, en dat zien de meeste records van een build nooit.
Bijgewerkt op
Hoe de cache werkt
De action actions/cache slaat aan het einde van een job een set paden op onder een sleutel, en zet die aan het begin van een latere job terug. Een typische npm-opzet cachet de downloadcache van de pakketbeheerder en baseert de sleutel op de lockfile:
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
restore-keys: |
npm-${{ runner.os }}-
- run: npm ci
Bij het terugzetten zoekt de action eerst naar een exacte match met key, daarna naar een gedeeltelijke match, en vervolgens naar elk restore-keys-prefix op volgorde. Wanneer meerdere caches bij een prefix passen, zet de action de meest recent gemaakte terug. Die terugvaloptie houdt builds snel nadat de lockfile is gewijzigd, en betekent ook dat een job kan starten vanuit een cache die voor een oudere lockfile is gebouwd.
Vaak hebt u de action helemaal niet nodig. setup-node, setup-python, setup-java, setup-go, setup-ruby en setup-dotnet hebben ingebouwde caching. Voor Node.js cachet setup-node globale pakketgegevens voor npm, Yarn en pnpm, niet node_modules, en zet het npm-caching automatisch aan wanneer package.json npm als packageManager declareert.
Scope en limieten
| Regel | Wat GitHub doet |
|---|---|
| Welke caches een run kan terugzetten | Die van de eigen branch en de standaardbranch; pull requests ook die van hun basisbranch |
| Wat een pull request kan schrijven | Alleen caches binnen de scope van zijn merge ref, niet van de standaardbranch |
| Opslag | Standaard 10 GB per repository; eigenaars van organisaties en enterprises kunnen dit verhogen |
| Verwijdering | Vermeldingen die meer dan 7 dagen niet zijn gebruikt, en de minst recent gebruikte wanneer de opslag vol is |
| Secrets | Cache ze niet: iedereen met toegang tot pull requests kan de inhoud van caches lezen |
Wat de cache voor uw SBOM verbergt
Een cache is een kortere weg langs de pakketregistry. Daar is hij voor bedoeld, en daarom brengt hij ook elk record van wat een build heeft gebruikt in de war:
- Geen download, geen spoor. Pakketten die uit een cache worden teruggezet, worden geïnstalleerd zonder verzoek aan de registry. Een record dat is opgebouwd uit het netwerkverkeer van de build mist ze, tenzij het de cache volgt.
-
Oude inhoud onder een nieuwe sleutel. Een gedeeltelijke
restore-keys-match zet een cache terug die voor een eerdere lockfile is gebouwd. De installatie voegt vervolgens toe of vervangt wat is gewijzigd, maar waar de job mee begon, is niet wat de huidige lockfile beschrijft. - Meer dan uw afhankelijkheden. Caches bevatten ook buildtools, compilers en gegenereerde bestanden, die in geen enkel applicatiemanifest staan.
- Een scan kan het niet zien. Een SBOM op basis van de lockfile beschrijft wat de lockfile zegt, of de job precies dat nu uit zijn cache heeft geïnstalleerd of niet.
Voor hoe dit in het bredere probleem past, zie waarom een lockfile geen record is van wat is geleverd en transitieve afhankelijkheden.
Cachevergiftiging
Caches worden gedeeld tussen workflows in een repository, waardoor ze een route tussen die workflows vormen. In mei 2024 toonde beveiligingsonderzoeker Adnan Khan aan dat iedereen die code kan uitvoeren in de context van de standaardbranch, via een kwetsbare pull_request_target-workflow of een gecompromitteerde afhankelijkheid, bestanden kan overschrijven in workflows die caches terugzetten. Met het cachetoken van een draaiende job kan een aanvaller de cache van de repository vullen zodat GitHub legitieme vermeldingen verwijdert, en daarna vergiftigde vermeldingen onder dezelfde sleutels schrijven. Een releaseworkflow die ze terugzet, voert de bestanden van de aanvaller uit met zijn eigen secrets.
Om het risico te beperken:
- Bouw releases vanuit een schone staat, of vanuit caches die alleen de releaseworkflow schrijft.
- Draai nooit niet-vertrouwde pull-requestcode in de context van de standaardbranch.
- Houd secrets en tokens uit gecachete paden.
- Behandel wat een cache heeft teruggezet als een invoer van de build die evenveel controle nodig heeft als een download.
Hoe CRACI met caches omgaat
CRACI is een GitHub Actions-runner, dus actions/cache en de setup-*-caches werken zoals nu, naast caching van containerlagen. Caching is ook een van de redenen waarom CRACI builds ongeveer twee keer zo snel draait als door GitHub gehoste runners, met snellere hardware en kortere wachtrijen.
Wat verandert, is het record. De proxy van CRACI die pakketten herkent, legt de pakketten vast die een job ophaalt, en het bewijs reist mee met caches: wanneer een job een cache terugzet, neemt CRACI de afhankelijkheden die het kent mee naar de SBOM van die job.
- Volledigheid per cache. Elke cache heeft een volledigheidsstatus, net als elke job. Een job die een onvolledige cache terugzet, krijgt een onvolledige SBOM, en een cache die hij oplevert, neemt die status mee, zodat een gat nooit stilzwijgend verandert in een volledig record.
- Niet gokken op basis van het archief. CRACI leest geen pakketmanifests in het cachearchief. Het weet wat er in een cache zit, omdat het de job heeft vastgelegd die de cache heeft opgeleverd.
-
Eén cache per producerende job houdt dat bewijs betrouwbaar, samen met een egressbeleid dat in de producerende job is ingesteld op
default: deny. De gids over cache- en SBOM-volledigheid bevat de details.
Zie SBOM's tijdens de build voor hoe het vastleggen werkt, of boek een demo om een van uw gecachete workflows op CRACI te draaien.
GitHub Actions-cache: veelgestelde vragen
Hoe lang bewaart GitHub een Actions-cache?
GitHub verwijdert cachevermeldingen die meer dan 7 dagen niet zijn gebruikt. Wanneer een repository boven zijn opslaglimiet uitkomt, standaard 10 GB, verwijdert GitHub daarnaast caches op volgorde van laatste gebruik, de oudste eerst.
Cachet setup-node node_modules?
Nee. De cache-invoer van actions/setup-node cachet de globale pakketgegevens van de pakketbeheerder voor npm, Yarn of pnpm, niet node_modules. De installatiestap draait nog steeds, maar leest pakketten uit de teruggezette cache in plaats van ze te downloaden.
Kan een pull request caches van de main-branch lezen?
Ja. Een workflowrun kan caches terugzetten van zijn eigen branch en de standaardbranch, en een pull request kan ook caches van zijn basisbranch terugzetten. Caches die in een pull request zijn gemaakt, vallen onder de scope van zijn merge ref, dus ze kunnen niet in de scope van de standaardbranch worden geschreven.
Is het veilig om de Actions-cache in releaseworkflows te gebruiken?
Dat is een afweging. Onderzoek uit 2024 toonde aan dat iedereen die code kan draaien in een workflow op de standaardbranch caches kan vergiftigen die andere workflows terugzetten, ook releaseworkflows. Workflows die releases publiceren of deployment-secrets bevatten, kunnen veiliger bouwen vanuit een schone staat of vanuit caches die alleen zij zelf schrijven.
Verandert een teruggezette cache mijn SBOM?
Dat kan. Pakketten die uit een cache worden teruggezet, worden geïnstalleerd zonder te worden gedownload, dus een record dat is opgebouwd uit netwerkverkeer mist ze, tenzij het de cache volgt. En een scan van de lockfile vertelt u niet of de cache precies die versies bevatte.
Behoud uw caches én een volledige SBOM
Draai uw workflow op CRACI: caches versnellen de build nog steeds, en de afhankelijkheden die ze bevatten, blijven in de vastgelegde SBOM van elke job.
Demo boeken