# Forge

## Vad det är

En forge, på engelska även software forge eller code forge och i vardagligt tal ofta git-forge, är
den server ett team utser till hemvist för sina repon, tillsammans med tjänsterna som körs runt
dem. Git kräver ingen sådan server. Varje fullständig klon bär hela historiken, och tekniskt sett är
ingen kopia förmer än någon annan. Ett team behöver ändå ett ställe att pusha till, ett ställe som
avgör vem som får läsa och skriva och ett ställe där samtalet om koden förs. Det stället är forgen.

Under ytan lagrar en forge bare-repon, alltså repon som bara innehåller historiken och inga
utcheckade filer, och den talar ett eller flera av gits överföringsprotokoll. Git-projektets bok
räknar upp fyra: det lokala protokollet mot en katalog på samma maskin, HTTP, SSH och gits eget
protokoll, en daemon på port 9418 helt utan autentisering. Allt annat byggs ovanpå, och hur mycket
som byggs skiljer sig kraftigt.

Forgejos dokumentation visar den fullt utbyggda änden av skalan: ärendehantering, pull requests, en
inbyggd wiki, ett paketregister för många språks ekosystem, Forgejo Actions för att köra jobb,
spegling av repon, migrering från andra tjänster, skydd av grenar och taggar samt webhookar. Soft
Serve står i den andra änden. Projektet kallar sig en git-server för kommandoraden som man hostar
själv: en enda binärfil, `soft`, som servar repon över SSH, HTTP eller git-protokollet, styr
åtkomsten med publika SSH-nycklar och har stöd för medverkande, privata repon och webhookar. Båda
räknas som forge. Det som skiljer dem är hur stor del av teamets arbete de försöker rymma.

Servrarna har också börjat tala med varandra. ForgeFed är ett federationsprotokoll för plattformar
som hostar och samordnar mjukvaruprojekt, byggt som en utvidgning av ActivityPub. Det beskriver
repon, ärendehanterare, patchhanterare, projekt och team som aktörer som skickar aktiviteter till
varandra. Målet är ett gemensamt språk i ett nätverk av forgar och projektverktyg: en person på en
server ska kunna öppna ett ärende mot ett repo på en annan, och ett repo ska kunna flytta mellan
servrar medan den gamla kopian arkiveras som skrivskyddad och pekar vidare till sitt nya hem.

## Varför det spelar roll

Det är på forgen som en regel går att genomdriva. En regel som bor på en utvecklares dator gäller
bara så länge den datorn är rätt uppsatt, medan en hook på servern körs vid varje push. Gits
`pre-receive`-hook läser varje pushad referens som ett gammalt id, ett nytt id och ett
referensnamn på standard in. Avslutar den med en annan status än noll uppdateras ingen referens
alls. Grenskydd, obligatorisk kodgranskning och krav på signerade commits hos de större forgarna är
förfiningar av samma idé: den gemensamma kopian säger nej till det som teamet har bestämt att inte
ta emot.

Att välja forge är också att välja vem som håller koden. En hostad tjänst tar på sig driften och
upptiden, och i gengäld ligger koden, åtkomstlistan och varje diskussion på någon annans hårdvara
och på någon annans villkor. Att hosta själv vänder på den avvägningen. Båda vägarna kostar något,
och skillnaden väger tyngst för ett företag som lovar sina kunder att veta var deras data finns.

En forge håller dessutom data som git inte håller. Commits och taggar följer med i varje klon, medan
ärenden, granskningstrådar, åtkomstlistor och hookar på serversidan bara finns på forgen. Den
gränsen bestämmer vad en säkerhetskopia måste omfatta och vad en flytt mellan två forgar måste få
med sig.

## Så ser det ut i praktiken

Den här webbplatsens kod ligger på en forge som företaget driver själv, och tre projekt visar vad
det krävde.

Källkoden låg tidigare hos en extern värdtjänst. Projektet där
[företaget driftsatte sin egen git-forge](/sv/portfolio/deployed-the-companys-own-git-forge-121/)
utgår från att den som kör en forge också kör allt som hör till: autentisering, åtkomstkontroll,
lagring, säkerhetskopior och ett ansikte utåt. Valet föll på Soft Serve, en enda binärfil som hålls
igång av operativsystemet, eftersom den är byggd för SSH först och saknar administrativt
webbgränssnitt. Den är privat som standard. Anonym åtkomst nekas, åtkomst utan nyckel nekas och
varje deklarerat repo är markerat som privat. SSH-lyssnaren binder bara till loopback-gränssnittet
på port 23231 och nås utifrån via en hoppserver. En multiplexer som skulle lägga HTTPS och git över
SSH på en och samma publika port är skriven men avstängd, eftersom en lyssnare som ingen använder är
attackyta. Resultatet sägs rakt ut: företaget hostar sin egen kod på sin egen hårdvara.

Webbplatsens eget repo bor där. Repots instruktioner pekar ut den egenhostade forgen, Soft Serve
över SSH, som kanonisk remote, kallar den äldre hostade kopian en kvarlämnad spegel och konstaterar
att det inte finns någon hostad CI. Kvalitetsgrinden körs lokalt och i git-hookar.

En hook på serversidan är den enda delen av uppsättningen som inte går att prova genom att köra den
på en laptop. Därför
[provkördes hooken mot ett riktigt bare-repo och en riktig push](/sv/portfolio/rehearsed-the-forge-side-ci-hook-151/)
innan den fick förtroende. Provkörningen skapar ett bare-repo, installerar hooken, klonar,
committar, pushar och verifierar både vägen där pushen godtas och vägen där den avvisas. Den hittade
två fel, och inget av dem syntes i filen. Det andra är det lärorika. När git kör en hook exporterar
det en variabel som pekar ut repots katalog, testsviten som hooken startade ärvde den, och nitton
tester blev röda på korrekt kod tills miljön rensades vid gränsen. Sidan anger också sin egen
begränsning: tvingade uppdateringar och borttagna grenar är pushar som provkörningen inte
konstruerar.

Forgen är en av flera tjänster på
[en enda värddator med en kärna och 512 MB minne](/sv/portfolio/ran-the-whole-company-on-one-512mb-host-109/):
samma maskin terminerar TLS för sju domäner, kör en onion-tjänst för Tor och servrar för Gemini och
Gopher, tar krypterade säkerhetskopior och spärrar intrångsförsök. Plattformar med webbpanel valdes
bort redan i designskedet, och ett dygns mätningar visade att det tillgängliga minnet aldrig föll
under ungefär 310 MB av 464.

## Var det går fel

Anonyma besökare får läsrätt som standard på vissa forgar. Soft Serves dokumentation anger att den
från start ger anonyma anslutningar skrivskyddad åtkomst, styrd av två inställningar, `anon-access`
och `allow-keyless`. En privat forge sätter den första till `no-access` och den andra till false,
och resultatet är värt att testa från en maskin där ingen nyckel är laddad. Gits egen daemon känner
bara till allt eller inget: enligt Git-projektets bok kan ett repo som den servar antingen klonas av
alla eller inte servas alls.

En hook som anropar git i en annan katalog träffar fel repo. Under en push kör git de mottagande
hookarna inne i bare-repot och exporterar `GIT_DIR` och närliggande variabler, så att git-kommandon
i hooken hittar rätt. Allt som hooken startar ärver dem, även en testkörning i en utcheckning
någon annanstans. Manualen för githooks säger att variablerna ska rensas innan man arbetar i ett
främmande repo. En minimal `pre-receive`-hook som testar varje pushad commit i en tillfällig katalog
gör det i ett subshell:

```sh
while read -r _ newrev _; do
  git cat-file -e "$newrev^{commit}" 2>/dev/null || continue
  tree=$(mktemp -d)
  git archive "$newrev" | tar -x -C "$tree"
  (
    unset $(git rev-parse --local-env-vars)
    cd "$tree" && ./run-tests
  ) || exit 1
done
```

En återställd forge kommer tillbaka med sin kod men utan sina regler. Vilken klon som helst kan
fylla en förlorad servers repon igen, men Git-projektets bok varnar för att hookar på serversidan
och liknande inställningar stannar på den gamla maskinen, och ärenden, granskningar, nycklar och
åtkomstlistor fanns aldrig i klonerna. Att säkerhetskopiera en forge betyder att säkerhetskopiera
dess datakatalog och dess konfiguration, att återställa båda på en annan maskin och att kontrollera
att en push som hooken ska avvisa faktiskt avvisas.

Varje lyssnare som en forge öppnar måste försvaras. Soft Serves exempelkonfiguration har SSH på
port 23231, HTTP på 23232, git-daemonen på 9418 och en statistikserver på 23233. Ett team som bara
pushar över SSH kan stänga av resten eller binda dem till loopback, så att de öppna portarna
motsvarar det som faktiskt används.

En flytt till en annan forge tar med koden och lämnar samtalet kvar. En spegelpush kopierar varje
referens under `refs/`, grenar och taggar inräknade, och mer än så kopierar den inte. Ärenden,
granskningstrådar, etiketter och åtkomstlistor kräver den nya forgens migreringsverktyg eller ett
protokoll som ForgeFed, som kopierar commits, taggar, ärenden, merge requests och kommentarer och
lämnar det gamla repot arkiverat med en hänvisning till det nya.

## Läs mer

- [ForgeFed-specifikationen](https://forgefed.org/spec/) — federationsprotokollet för forgar, med
  aktörerna, aktiviteterna och flytten som arkiverar ett gammalt repo.
- [Soft Serve](https://github.com/charmbracelet/soft-serve) — projektets egen dokumentation för en
  git-server i en enda binärfil med SSH först, inklusive `anon-access` och `allow-keyless`.
- [Forgejo-dokumentationen](https://forgejo.org/docs/latest/) — handledningar för administratörer
  och användare av en fullt utbyggd forge som man hostar själv, från installation och
  säkerhetskopiering till Actions och speglar.
- [githooks](https://git-scm.com/docs/githooks) — alla hookar som git kör, bl.a. `pre-receive`, och
  miljön som en push-hook ärver.
- [The Protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols) — de fyra sätt
  som git flyttar data mellan maskiner på, och vad vart och ett kostar i uppsättning och säkerhet.
- [ActivityPub](https://www.w3.org/TR/activitypub/) — W3C-rekommendationen som ForgeFed bygger
  ut.

<https://engineer.company/sv/glossary/forge/>
