Blog ·
Een omzettingsscript dat te breed liep
Een typografiescript krulde een apostrof in een citaat van programma-uitvoer, in een artikel dat het nooit had mogen raken. Elke controle bleef groen.
Door Provibr
Frans en Italiaans vragen een typografische apostrof in plaats van een rechte, en er is een test die dat afdwingt. Dat teken rechtstreeks in een bronbestand schrijven is onbetrouwbaar: afhankelijk van hoe het bestand tot stand komt kan een shell, een heredoc of een bewerkingsgereedschap het weer platslaan. Dus schrijven we het rechte teken en draaien we daarna een klein script dat het omzet.
Dat script maskeert code. Alles tussen backticks en alles in een omheind blok wordt met rust gelaten, want een apostrof in een codefragment zou het fragment veranderen, en dan zou de feitenvergelijking terecht rood gaan.
Hij is als glob over een hele taalmap gedraaid. Hij zette een apostrof om in een citaat van programma-uitvoer, in een artikel dat door een andere ronde geschreven was en dat toevallig in dezelfde map stond.
De maskering klopte en het doel niet
De regel die hij beschadigde was een citaat van wat een commando afdrukte, tussen guillemets gezet als lopende tekst in plaats van als code gemarkeerd. Iets van de vorm Locking administration user's password. Die apostrof hoort bij de machine die hem produceerde, en hem krullen laat het artikel beweren dat de machine iets zei wat hij niet zei.
De maskeerregel klopt. Backticks en omheinde blokken zijn code. Een citaat van programma-uitvoer dat als proza gezet is, is niet als code gemarkeerd en is aan de tekens niet van proza te onderscheiden, want dat is precies wat het is: proza, dat een machine citeert.
Het defect zit dus niet in de maskering. Het zit in de selectie. Drie artikelen van andere rondes zijn gewijzigd door een script dat geschreven was om er vier aan te raken.
Waarom de buildcontrole het niet opmerkte
Dit is het deel dat verder reikt dan één script.
Onze artikelen worden gegenereerd. De bron is markdown, de uitvoer bestaat uit gecommitte gegenereerde bestanden, en er is een controle die vanuit de bron opnieuw bouwt en eist dat het resultaat byte-identiek is aan wat er gecommit staat. Lopen die uiteen, dan gaat hij rood.
Ze liepen niet uiteen. Het script wijzigde de bron, de build draaide, de uitvoer werd opnieuw gegenereerd uit de gewijzigde bron, en die twee kwamen perfect overeen. De controle beantwoordt "is de uitvoer in overeenstemming met de bron", en dat is een echte vraag maar niet deze. Niets in de pijplijn beantwoordt "heeft deze ronde alleen gewijzigd wat ze hoorde te wijzigen".
De typografietest evenmin, om dezelfde reden andersom: een gekrulde apostrof is in het Frans het juiste teken. De wijziging bracht het bestand meer in lijn met de regel, niet minder.
Het enige dat het liet zien was git status op paden buiten de eigen bestanden van de ronde. Dat is nu de regel: nadat je een omzetting gedraaid hebt, som je de gewijzigde bestanden op en bevestig je dat ze allemaal van jou zijn.
De regel die eruit volgt
Draai een omzettingsscript op de bestandsnamen van je eigen ronde. Nooit op een glob over een map.
Dat klinkt vanzelfsprekend als het opgeschreven staat, en het was niet vanzelfsprekend tijdens het schrijven, want een glob over een taalmap is de natuurlijke manier om "zet de Franse artikelen om" uit te drukken en het script had een correcte veiligheidseigenschap waardoor het veilig voelde: het eist minstens één vervanging per bestand, zodat een run die stilletjes niets doet geen succes kan melden. Die controle gaat over leeg succes. Ze zegt niets over reikwijdte.
Een veiligheidscontrole die beschermt tegen te weinig doen is geen veiligheidscontrole tegen te veel doen. Dat zijn aparte eigenschappen en ze vragen om aparte mechanismen.
Twee kleinere versies van hetzelfde probleem
De ronde die hierop stuitte liep ook tegen twee vertaalfouten aan die uit dezelfde familie komen: iets wat immuun voor bewerking had moeten zijn, was niet als zodanig gemarkeerd.
Een cachingdirectief stond als kale tekst in de bron in plaats van tussen backticks. Twee talen vertaalden het, wat van een sleutelwoord een zinsnede maakt, en een ervan maakte er bovendien van een duur van één jaar een meervoud. Geen van beide wordt door de feitenvergelijking gevangen, want die vergelijking dekt wat tussen backticks staat en wat een cijfer is, en een kaal sleutelwoord is geen van beide. De reparatie is het in alle negen talen als token te markeren, waarna de vergelijking het voorgoed dekt.
De tweede was een tabel met interfacelabels. Het Engelse artikel gebruikte hem om te laten zien dat twee lijsten met namen uit elkaar gelopen waren, en zei er expliciet bij dat die afwijking in het Engels gemeten was. Zes van de acht vertalingen vertaalden de tabel. Een vertaald namenpaar is geen mildere versie van de meting; het is een andere meting, een die nooit gedaan is. Dat kostte 26 vervangingen om ongedaan te maken.
Beide fouten hebben dezelfde vorm als de apostrof: een stuk tekst dat data is in plaats van taal, op een plek waar niets het als data markeert.
Wat een controle beantwoordt is smaller dan wat ze lijkt te beantwoorden
De drie mechanismen die hier meespelen zijn elk correct en beantwoordden elk een vraag naast de vraag die ertoe deed.
| Controle | De vraag die ze beantwoordt | De vraag die ze niet beantwoordt |
|---|---|---|
| De contentbuildcontrole | is de gegenereerde uitvoer in overeenstemming met de bron | raakte deze wijziging alleen de bedoelde bestanden |
| De typografietest | gebruikt dit bestand de juiste tekens voor zijn taal | staan die tekens op de juiste plekken |
| De eigen bewaking van het script | kreeg dit bestand minstens één vervanging | kreeg een bestand een vervanging die het niet had mogen krijgen |
Geen van deze is slecht ontworpen. De fout is de aanname dat een muur van groene controles dekking is, terwijl het in werkelijkheid dekking is van de dingen waar iemand aan gedacht heeft.
Het goedkoopste tegenwicht daarvoor is niet nog een controle. Het is naar de diff kijken, op het niveau van bestandsnamen, voordat je iets commit wat een script gemaakt heeft.
Wat we zouden opschrijven
- Begrens een omzetting tot de bestanden van je eigen ronde. Een glob over een map is geen begrenzing maar een categorie.
- Een bewaking tegen te weinig doen zegt niets over te veel doen. Dat zijn verschillende eigenschappen.
- Een citaat van programma-uitvoer is data. Markeer het als code, of een tekstomzetting behandelt het als taal.
- Een consistentiecontrole tussen bron en uitvoer is blind voor een wijziging in allebei. Ze gaat over overeenstemming, niet over bedoeling.
- Een wijziging die een bestand correcter maakt is de moeilijkste om op te merken, want elk kwaliteitssignaal wijst de goede kant op.
- Lees de bestandslijst van je eigen diff. Het is de enige controle die de reikwijdtevraag beantwoordt.
- Alles wat een sleutelwoord is hoort in de bron tussen backticks, in elke taal, of iemand vertaalt het en geen enkele test maalt erom.
- Een vertaalde meting is een verzonnen meting. Als het punt van een tabel is dat twee dingen verschillen, dan is de tabel bewijs en geen proza.
Voor de duidelijkheid over wat dit is: de schade is teruggedraaid, de ronde eindigde met de contentcontrole op 815 van de 815 gegenereerde bestanden byte-identiek, de websuite op 4546 groen, de package-, gateway- en toolssuites op 7236 groen, de feitenvergelijking over 1240 alinea's zonder bevindingen, links op 81 van de 81, tabellen op 99 van de 99 en de layoutveeg op 108 van de 108 op 390 pixels tegen een productiebuild. De typografietest is rood bewezen met twee geplante defecten en daarna groen. Onbewezen: er is één lezer per vertaling, drie talen zijn alleen op layout, typografie en HTTP-status gecontroleerd, en de cijfers die uit eerdere rondes geciteerd zijn, zijn hier niet opnieuw gemeten.
Uit het platformwerk aan Provibr. Wat een tweede lezer in dezelfde acht artikelen vond staat in drie fouten die geen script kon zien, en wat negen catalogi met een vaste verzameling knoppen doen staat in zestienduizend sleutels, negen talen.