PVS-Studio nyní v Chocolatey: kontrola Chocolatey z Azure DevOps

PVS-Studio nyní v Chocolatey: kontrola Chocolatey z Azure DevOps
Pokračujeme ve zjednodušení používání PVS-Studio. Nyní je náš analyzátor dostupný v Chocolatey, správci balíčků pro Windows. Věříme, že to usnadní nasazení PVS-Studio, zejména v cloudových službách. Abychom nešli daleko, podívejme se na zdrojový kód samotného Chocolatey. CI systémem bude Azure DevOps.

Zde je seznam našich dalších článků na téma integrace s cloudovými systémy:

Doporučuji zaměřit se na první článek o integraci s Azure DevOps, protože zde byly některé body vynechány, aby nedošlo k duplicování.

A tak, hrdinové tohoto článku:

PVS-Studio — nástroj pro statickou analýzu kódu, určený k odhalování chyb a potenciálních zranitelností v programech napsaných v jazycích C, C++, C# a Java. Funguje na 64bitových systémech Windows, Linux a macOS a může analyzovat kód určený pro 32bitové, 64bitové a vestavěné ARM platformy. Pokud se statickou analýzou kódu pro kontrolu svých projektů setkáváte poprvé, doporučujeme se seznámit se článek jak rychle zobrazit nejzajímavější upozornění PVS-Studio a ocenit možnosti tohoto nástroje.

Azure DevOps — sada cloudových služeb, které dohromady pokrývají celý proces vývoje. Tato platforma zahrnuje nástroje jako Azure Pipelines, Azure Boards, Azure Artifacts, Azure Repos, Azure Test Plans, které pomáhají zrychlit proces vytváření softwaru a zvýšit jeho kvalitu.

Chocolatey – správce balíčků pro Windows s otevřeným zdrojovým kódem. Cílem projektu je automatizovat celý životní cyklus softwaru od instalace po aktualizaci a odstraňování v operačních systémech Windows.

O používání Chocolatey

Podívat se, jak nainstalovat samotného správce balíčků, můžete na této odkazu. Komplexní dokumentace k instalaci analyzátoru je k dispozici na odkazu v sekci „Instalace pomocí správce balíčků Chocolatey“. Stručně opakuji některé body odtud.

Příkaz pro instalaci nejnovější verze analyzátoru:

choco install pvs-studio

Příkaz pro instalaci konkrétní verze balíčku PVS-Studio:

choco install pvs-studio --version=7.05.35617.2075

Výchozí instalací se nastaví pouze jádro analyzátoru — komponent Core. Všechny ostatní příznaky (Standalone, JavaCore, IDEA, MSVS2010, MSVS2012, MSVS2013, MSVS2015, MSVS2017, MSVS2019) lze předat pomocí —package-parameters.

Příklad příkazu, který nainstaluje analyzátor s pluginem pro Visual Studio 2019:

choco install pvs-studio --package-parameters="'/MSVS2019'"

Nyní se podíváme na příklad pohodlného použití analyzátoru v Azure DevOps.

Nastavení

Připomínám, že problémy jako registrace účtu, vytvoření Build Pipeline a synchronizace účtu s projektem v repozitáři na GitHubu, mají svůj vlastní neaktuální statistika. Naše nastavení začne přímo psaním konfiguračního souboru.

Nejprve nastavíme spouštěcí trigger, a to tak, že uvedeme, že provádíme spuštění pouze pro změny v master větvi:

trigger:
- master

Dále musíme vybrat virtuální stroj. V tuto chvíli to bude Microsoft-hosted agent s Windows Server 2019 a Visual Studio 2019:

pool:
  vmImage: 'windows-latest'

Přejdeme k tělu konfiguračního souboru (blok steps). I když není možné na virtuální stroj nainstalovat libovolný software, nepřidával jsem Docker kontejner. Můžeme přidat Chocolatey jako rozšíření pro Azure DevOps. K tomu přejdeme na odkazu. Klikneme na Získat zdarma. Dále, pokud jste již přihlášeni, jednoduše vyberte svůj účet, a pokud ne, proveďte to po přihlášení.

PVS-Studio nyní v Chocolatey: kontrola Chocolatey z Azure DevOps

Zde je třeba vybrat, kam přidáme rozšíření, a stisknout tlačítko Nainstalovat.

PVS-Studio nyní v Chocolatey: kontrola Chocolatey z Azure DevOps

Po úspěšné instalaci klikneme na Pokračovat k organizaci:

PVS-Studio nyní v Chocolatey: kontrola Chocolatey z Azure DevOps

Nyní můžeme vidět šablonu úlohy Chocolatey v okně tasks při úpravě konfiguračního souboru azure-pipelines.yml:

PVS-Studio nyní v Chocolatey: kontrola Chocolatey z Azure DevOps

Klikneme na Chocolatey a uvidíme seznam polí:

PVS-Studio nyní v Chocolatey: kontrola Chocolatey z Azure DevOps

Zde musíme vybrat install v poli s příkazy. V Nuspec File Name uvedeme název požadovaného balíčku – pvs-studio. Pokud neuvedeme verzi, nainstaluje se poslední, což nám zcela vyhovuje. Klikneme na tlačítko add a uvidíme vytvořenou úlohu v konfiguračním souboru.

steps:
- task: ChocolateyCommand@0
  inputs:
    command: 'install'
    installPackageId: 'pvs-studio'

Dále přejdeme k hlavní části našeho souboru:

- task: CmdLine@2
  inputs:
    script: 

Nyní musíme vytvořit soubor s licencí analyzátoru. Zde PVSNAME a PVSKEY – názvy proměnných, jejichž hodnoty uvádíme v nastavení. Budou obsahovat přihlašovací jméno a licenční klíč PVS-Studio. Abychom nastavili jejich hodnoty, otevřeme nabídku Proměnné->Nová proměnná. Vytvoříme proměnné PVSNAME pro přihlašovací jméno a PVSKEY pro klíč analyzátoru. Nezapomeňte zaškrtnout Tuto hodnotu si uchovejte v tajnosti pro PVSKEY. Příkazový kód:

call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" credentials 
–u $(PVSNAME) –n $(PVSKEY)

Sestavíme projekt pomocí bat-souboru uloženého v repozitáři:

call build.bat

Vytvoříme složku, kde budou uloženy soubory s výsledky práce analyzátoru:

call mkdir PVSTestResults

Spustíme analýzu projektu:

call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" 
–t .srcchocolatey.sln –o .PVSTestResultsChoco.plog 

Převedeme naši zprávu do formátu html pomocí nástroje PlogConverter:

call "C:Program Files (x86)PVS-StudioPlogConverter.exe" 
–t html –o PVSTestResults .PVSTestResultsChoco.plog

Nyní je potřeba vytvořit úlohu pro export zprávy.

- task: PublishBuildArtifacts@1
  inputs:
    pathToPublish: PVSTestResults
    artifactName: PVSTestResults
    condition: always()

Celý konfigurační soubor vypadá takto:

trigger:
- master

pool:
  vmImage: 'windows-latest'

steps:
- task: ChocolateyCommand@0
  inputs:
    command: 'install'
    installPackageId: 'pvs-studio'

- task: CmdLine@2
  inputs:
    script: |
      call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" 
      credentials –u $(PVSNAME) –n $(PVSKEY)
      call build.bat
      call mkdir PVSTestResults
      call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" 
      –t .srcchocolatey.sln –o .PVSTestResultsChoco.plog
      call "C:Program Files (x86)PVS-StudioPlogConverter.exe" 
      –t html –o .PVSTestResults .PVSTestResultsChoco.plog

- task: PublishBuildArtifacts@1
  inputs:
    pathToPublish: PVSTestResults
    artifactName: PVSTestResults
    condition: always()

Klikněte Uložit->Uložit->Spustit pro spuštění úlohy. Exportujeme zprávu v sekci úlohy.

PVS-Studio nyní v Chocolatey: kontrola Chocolatey z Azure DevOps

Projekt Chocolatey obsahuje pouze 37615 řádků kódu C#. Podívejme se na některé z nalezených chyb.

Výsledky kontroly

Upozornění N1

Varování analyzátoru: V3005 Proměnná 'Provider' je přiřazena sama sobě. CrytpoHashProviderSpecs.cs 38

public abstract class CrytpoHashProviderSpecsBase : TinySpec
{
  ....
  protected CryptoHashProvider Provider;
  ....
  public override void Context()
  {
    Provider = Provider = new CryptoHashProvider(FileSystem.Object);
  }
}

Analyzátor zjistil přiřazení proměnné k sobě samé, což nedává smysl. Pravděpodobně by na místě jedné z těchto proměnných měla být nějaká jiná. Nebo je to chyba, a zbytečné přiřazení může být jednoduše odstraněno.

Upozornění N2

Varování analyzátoru: V3093 [CWE-480] Operátor '&&' vyhodnocuje obě operand. Mělo by se pravděpodobně místo toho použít zkrácený operátor '&&'. Platform.cs 64

public static PlatformType get_platform()
{
  switch (Environment.OSVersion.Platform)
  {
    case PlatformID.MacOSX:
    {
      ....
    }
    case PlatformID.Unix:
    if(file_system.directory_exists("/Applications")
      && file_system.directory_exists("/System")
      && file_system.directory_exists("/Users")
      && file_system.directory_exists("/Volumes"))
      {
        return PlatformType.Mac;
      }
        else
          return PlatformType.Linux;
    default:
      return PlatformType.Windows;
  }
}

Rozdíl mezi operátorem && a operátorem && je v tom, že pokud je levá strana výrazu - false, přesto bude spočítána pravá strana, což v tomto případě znamená zbytečné volání metody system.directory_exists.

Ve zvažovaném fragmentu se jedná o drobnou chybu. Ano, tuto podmínku lze optimalizovat, pokud nahradíme operator & operator &&, ale z praktického hlediska to na nic nemá vliv. Nicméně, v jiných případech může zmatení mezi & a && způsobit vážné problémy, pokud bude pravá strana výrazu pracovat s neplatnými/zakázanými hodnotami. Například v naší sbírce chyb, detekovaných pomocí diagnostiky V3093, máme takový případ:

if ((k < nct) & (s[k] != 0.0))

I když je index k neplatný, bude použit k přístupu k prvku pole. V důsledku toho dojde k vyvolání výjimky IndexOutOfRangeException.

Varování N3, N4

Varování analyzátoru: V3022 [CWE-571] Výraz ‘shortPrompt’ je vždy pravdivý. InteractivePrompt.cs 101
Varování analyzátoru: V3022 [CWE-571] Výraz ‘shortPrompt’ je vždy pravdivý. InteractivePrompt.cs 105

public static string 
prompt_for_confirmation(.... bool shortPrompt = false, ....)
{
  ....
  if (shortPrompt)
  {
    var choicePrompt = choice.is_equal_to(defaultChoice) ///1
    ?
    shortPrompt ///2
    ?
    "[[{0}]{1}]".format_with(choice.Substring(0, 1).ToUpperInvariant(), ///3
    choice.Substring(1,choice.Length - 1))
    :
    "[{0}]".format_with(choice.ToUpperInvariant()) ///0
    : 
    shortPrompt ///4
    ? 
    "[{0}]{1}".format_with(choice.Substring(0,1).ToUpperInvariant(), ///5
    choice.Substring(1,choice.Length - 1)) 
    :
    choice; ///0
    ....
  }
  ....
}

V tomto případě je přítomna podivná logika fungování ternárního operátoru. Podívejme se blíže: pokud bude splněna podmínka označená mnou číslem 1, přejdeme k podmínce 2, která je vždy true, což znamená, že se vykoná řádek 3. Pokud však podmínka 1 bude nepravdivá, přejdeme na řádek označený číslem 4, kde také podmínka je vždy true, což znamená, že se vykoná řádek 5. Takže podmínky označené komentářem 0 nikdy nebudou splněny, což nemusí být zcela logika, na kterou programátor spoléhá.

Varování N5

Varování analyzátoru: V3123 [CWE-783] Možná, že operator ‘?:’ funguje jinak, než se očekávalo. Jeho priorita je nižší než priorita jiných operátorů v jeho podmínce. Options.cs 1019

private static string GetArgumentName (...., string description)
{
  string[] nameStart;
  if (maxIndex == 1)
  {
    nameStart = new string[]{"{0:", "{"};
  }
  else
  {
    nameStart = new string[]{"{" + index + ":"};
  }
  for (int i = 0; i = 0 && j != 0 ? description [j++ - 1] == '{' : false);
    ....
    return maxIndex == 1 ? "VALUE" : "VALUE" + (index + 1);
  }
}

Diagnostika spustila na řádek:

while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false)

Jelikož proměnná j o několik řádků výše se inicializuje na nulu, ternární operátor vrátí hodnotu false. Kvůli této podmínce se tělo smyčky vykoná pouze jednou. Domnívám se, že tento úryvek kódu nefunguje tak, jak programátor zamýšlel.

Upozornění N6

Varování analyzátoru: V3022 [CWE-571] Výraz 'installedPackageVersions.Count != 1' je vždy pravdivý. NugetService.cs 1405

private void remove_nuget_cache_for_package(....)
{
  if (!config.AllVersions && installedPackageVersions.Count > 1)
  {
    const string allVersionsChoice = "Všechny verze";
    if (installedPackageVersions.Count != 1)
    {
      choices.Add(allVersionsChoice);
    }
    ....
  }
  ....
}

Zde je zvláštní vnořená podmínka: installedPackageVersions.Count != 1, která bude vždy true. Takové varování často naznačuje logickou chybu v kódu, a v ostatních případech pouze nadbytečnou kontrolu.

Upozornění N7

Varování analyzátoru: V3001 Existují identické podvýrazy 'commandArguments.contains("-apikey")' nalevo a napravo od operátoru '||'. ArgumentsUtility.cs 42

public static bool arguments_contain_sensitive_information(string
 commandArguments)
{
  return commandArguments.contains("-install-arguments-sensitive")
  || commandArguments.contains("-package-parameters-sensitive")
  || commandArguments.contains("apikey ")
  || commandArguments.contains("config ")
  || commandArguments.contains("push ")
  || commandArguments.contains("-p ")
  || commandArguments.contains("-p=")
  || commandArguments.contains("-password")
  || commandArguments.contains("-cp ")
  || commandArguments.contains("-cp=")
  || commandArguments.contains("-certpassword")
  || commandArguments.contains("-k ")
  || commandArguments.contains("-k=")
  || commandArguments.contains("-key ")
  || commandArguments.contains("-key=")
  || commandArguments.contains("-apikey")
  || commandArguments.contains("-api-key")
  || commandArguments.contains("-apikey")
  || commandArguments.contains("-api-key");
}

Programátor, který napsal tento úsek kódu, zkopíroval poslední dvě řádky a zapomněl je upravit. Kvůli tomu uživatelé Chocolatey ztratili možnost použít parametr apikey ještě dalším způsobem. Podobně jako parametry výše mohu navrhnout následující varianty:

commandArguments.contains("-apikey=");
commandArguments.contains("-api-key=");

Chyby z kopírování a vkládání mají velkou šanci se dříve nebo později objevit v jakémkoli projektu s velkým množstvím zdrojového kódu, a jedním z nejlepších prostředků boje proti nim je statická analýza.

P.S. A jako vždy, tato chyba má tendenci se objevit na konci vícerozměrné podmínky :). Viz publikaci "Efekt posledního řádku".

Upozornění N8

Varování analyzátoru: V3095 [CWE-476] Objekt 'installedPackage' byl použit, než byl ověřen na null. Zkontrolujte řádky: 910, 917. NugetService.cs 910

public virtual ConcurrentDictionary get_outdated(....)
{
  ....
  var pinnedPackageResult = outdatedPackages.GetOrAdd(
    packageName, 
    new PackageResult(installedPackage, 
                      _fileSystem.combine_paths(
                        ApplicationParameters.PackagesLocation, 
                        installedPackage.Id)));
  ....
  if (   installedPackage != null
      && !string.IsNullOrWhiteSpace(installedPackage.Version.SpecialVersion) 
      && !config.UpgradeCommand.ExcludePrerelease)
  {
    ....
  }
  ....
}

Klasická chyba: objekt je nejprve použit a poté kontrolován installedPackage na null. Tato diagnostika nám říká o jednom ze dvou problémů v programu: buď installedPackage nikdy není null, což je pochybné, a pak je kontrola nadbytečná, nebo potenciálně můžeme získat vážnou chybu v kódu – pokus o přístup na nulový odkaz.

Závěr

A máme za sebou ještě jeden malý krok – nyní je používání PVS-Studio ještě jednodušší a pohodlnější. Také chci říci, že Chocolatey je dobrý správce balíčků s malým počtem chyb v kódu, kterých by mohlo být ještě méně při používání PVS-Studio.

Zveme vás stáhnout a vyzkoušet PVS-Studio. Pravidelné používání statického analyzátoru zlepší kvalitu a spolehlivost kódu vyvíjeného vaším týmem a pomůže předejít mnoha zranitelnostem typu nula dne.

P.S.

Před publikováním jsme zaslali článek vývojářům Chocolatey, a ti jej dobře přijali. Nic kritického jsme nenalezli, ale jim se například líbila chyba, kterou jsme našli, týkající se klíče „api-key“.

PVS-Studio nyní v Chocolatey: kontrola Chocolatey z Azure DevOps

Pokud chcete sdílet tento článek s anglicky mluvícím publikem, prosím použijte odkaz na překlad: Vladislav Stolyarov. PVS-Studio nyní v Chocolatey: Kontrola Chocolatey pod Azure DevOps.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster