PVS-Studio ahora está en Chocolatey: verificando Chocolatey desde Azure DevOps

PVS-Studio ahora está en Chocolatey: verificando Chocolatey desde Azure DevOps
Seguimos haciendo que el uso de PVS-Studio sea más conveniente. Nuestro analizador ahora está disponible en Chocolatey, un administrador de paquetes para Windows. Creemos que esto facilitará la implementación de PVS-Studio, en particular, en servicios en la nube. Para no ir muy lejos, revisemos el código fuente del mismo Chocolatey. Azure DevOps actuará como un sistema de CI.

Aquí hay una lista de nuestros otros artículos sobre el tema de la integración con sistemas en la nube:

Te aconsejo que prestes atención al primer artículo sobre la integración con Azure DevOps, ya que en este caso se omiten algunos puntos para no duplicarlos.

Entonces, los héroes de este artículo:

PVS-Estudio es una herramienta de análisis de código estático diseñada para identificar errores y posibles vulnerabilidades en programas escritos en C, C++, C# y Java. Se ejecuta en sistemas Windows, Linux y macOS de 64 bits y puede analizar código diseñado para plataformas ARM integradas y de 32 bits, 64 bits. Si es la primera vez que intentas el análisis de código estático para comprobar tus proyectos, te recomendamos que te familiarices con un articulo sobre cómo ver rápidamente las advertencias de PVS-Studio más interesantes y evaluar las capacidades de esta herramienta.

Azure DevOps — un conjunto de servicios en la nube que cubren conjuntamente todo el proceso de desarrollo. Esta plataforma incluye herramientas como Azure Pipelines, Azure Boards, Azure Artifacts, Azure Repos, Azure Test Plans, que permiten acelerar el proceso de creación de software y mejorar su calidad.

Chocolatey es un administrador de paquetes de código abierto para Windows. El objetivo del proyecto es automatizar todo el ciclo de vida del software, desde la instalación hasta la actualización y desinstalación en los sistemas operativos Windows.

Acerca del uso de chocolate

Puede ver cómo instalar el administrador de paquetes en este enlace. La documentación completa para instalar el analizador está disponible en enlace Consulte la sección Instalación utilizando el administrador de paquetes Chocolatey. Repetiré brevemente algunos puntos a partir de ahí.

Comando para instalar la última versión del analizador:

choco install pvs-studio

Comando para instalar una versión específica del paquete PVS-Studio:

choco install pvs-studio --version=7.05.35617.2075

De forma predeterminada, solo se instala el núcleo del analizador, el componente Core. Todos los demás indicadores (Standalone, JavaCore, IDEA, MSVS2010, MSVS2012, MSVS2013, MSVS2015, MSVS2017, MSVS2019) se pueden pasar usando --package-parameters.

Un ejemplo de un comando que instalará un analizador con un complemento para Visual Studio 2019:

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

Ahora veamos un ejemplo del uso conveniente del analizador en Azure DevOps.

Ajuste

Permítame recordarle que hay una sección separada sobre temas como registrar una cuenta, crear un Build Pipeline y sincronizar su cuenta con un proyecto ubicado en el repositorio de GitHub. artículo. Nuestra configuración comenzará inmediatamente con la escritura de un archivo de configuración.

Primero, configuremos un disparador de lanzamiento, indicando que lanzamos solo para cambios en dominar rama:

trigger:
- master

A continuación debemos seleccionar una máquina virtual. Por ahora será un agente alojado en Microsoft con Windows Server 2019 y Visual Studio 2019:

pool:
  vmImage: 'windows-latest'

Pasemos al cuerpo del archivo de configuración (bloque pasos). A pesar de que no se puede instalar software arbitrario en una máquina virtual, no agregué un contenedor Docker. Podemos agregar Chocolatey como extensión para Azure DevOps. Para hacer esto, vayamos a enlace. Hacer clic Consíguelo gratis. A continuación, si ya está autorizado, simplemente seleccione su cuenta y, si no, haga lo mismo después de la autorización.

PVS-Studio ahora está en Chocolatey: verificando Chocolatey desde Azure DevOps

Aquí debe seleccionar dónde agregaremos la extensión y hacer clic en el botón Instalar.

PVS-Studio ahora está en Chocolatey: verificando Chocolatey desde Azure DevOps

Después de una instalación exitosa, haga clic en Continuar con la organización:

PVS-Studio ahora está en Chocolatey: verificando Chocolatey desde Azure DevOps

Ahora puedes ver la plantilla para la tarea Chocolatey en la ventana. tareas al editar un archivo de configuración azure-pipelines.yml:

PVS-Studio ahora está en Chocolatey: verificando Chocolatey desde Azure DevOps

Haga clic en Chocolatey y vea una lista de campos:

PVS-Studio ahora está en Chocolatey: verificando Chocolatey desde Azure DevOps

Aquí debemos seleccionar instalar en el campo con los equipos. EN Nombre de archivo Nuspec indique el nombre del paquete requerido – pvs-studio. Si no especifica la versión, se instalará la última, lo que nos conviene completamente. Presionemos el botón add y veremos la tarea generada en el archivo de configuración.

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

A continuación, pasemos a la parte principal de nuestro archivo:

- task: CmdLine@2
  inputs:
    script: 

Ahora necesitamos crear un archivo con la licencia del analizador. Aquí NOMBREPV и PVSKEY – nombres de variables cuyos valores especificamos en la configuración. Almacenarán el inicio de sesión y la clave de licencia de PVS-Studio. Para establecer sus valores, abra el menú. Variables->Nueva variable. Creemos variables NOMBREPV para iniciar sesión y PVSKEY para la clave del analizador. No olvides marcar la casilla Mantenga este valor en secreto para PVSKEY. Código de comando:

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

Construyamos el proyecto usando el archivo bat ubicado en el repositorio:

сall build.bat

Creemos una carpeta donde se almacenarán los archivos con los resultados del analizador:

сall mkdir PVSTestResults

Empecemos analizando el proyecto:

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

Convertimos nuestro informe a formato html usando la utilidad PlogСonverter:

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

Ahora necesita crear una tarea para poder cargar el informe.

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

El archivo de configuración completo se ve así:

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()

hagamos clic Guardar->Guardar->Ejecutar para ejecutar la tarea. Descarguemos el informe yendo a la pestaña de tareas.

PVS-Studio ahora está en Chocolatey: verificando Chocolatey desde Azure DevOps

El proyecto Chocolatey contiene sólo 37615 líneas de código C#. Veamos algunos de los errores encontrados.

Resultados de la prueba

Advertencia N1

Advertencia del analizador: V3005 La variable 'Proveedor' se asigna a sí misma. CrytpoHashProviderSpecs.cs 38

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

El analizador detectó una asignación de la variable a sí mismo, lo cual no tiene sentido. Lo más probable es que en lugar de una de estas variables deba haber alguna otra. Bueno, o esto es un error tipográfico y la tarea adicional simplemente se puede eliminar.

Advertencia N2

Advertencia del analizador: V3093 [CWE-480] El operador '&' evalúa ambos operandos. Quizás debería usarse en su lugar un operador de cortocircuito '&&'. Plataforma.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;
  }
}

diferencia de operador & del operador && es que si el lado izquierdo de la expresión es false, entonces el lado derecho aún se calculará, lo que en este caso implica llamadas a métodos innecesarias sistema.directorio_existe.

En el fragmento considerado, se trata de un defecto menor. Sí, esta condición se puede optimizar reemplazando el operador & por el operador &&, pero desde un punto de vista práctico, esto no afecta en nada. Sin embargo, en otros casos, la confusión entre & y && puede causar serios problemas cuando el lado derecho de la expresión se trata con valores incorrectos/no válidos. Por ejemplo, en nuestra colección de errores, identificado utilizando el diagnóstico V3093, existe este caso:

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

Incluso si el índice k es incorrecto, se utilizará para acceder a un elemento de matriz. Como resultado, se lanzará una excepción. Excepción de índice fuera del rango.

Advertencias N3, N4

Advertencia del analizador: V3022 [CWE-571] La expresión 'shortPrompt' siempre es verdadera. InteractivePrompt.cs 101
Advertencia del analizador: V3022 [CWE-571] La expresión 'shortPrompt' siempre es verdadera. 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
    ....
  }
  ....
}

En este caso, hay una lógica extraña detrás del funcionamiento del operador ternario. Miremos más de cerca: si se cumple la condición que marqué con el número 1, entonces pasaremos a la condición 2, que siempre es verdadero, lo que significa que se ejecutará la línea 3. Si la condición 1 resulta ser falsa, entonces iremos a la línea marcada con el número 4, cuya condición también es siempre verdadero, lo que significa que se ejecutará la línea 5. Por lo tanto, las condiciones marcadas con el comentario 0 nunca se cumplirán, lo que puede no ser exactamente la lógica de operación que esperaba el programador.

Advertencia N5

Advertencia del analizador: V3123 [CWE-783] Quizás el operador '?:' funcione de una manera diferente a la esperada. Su prioridad es menor que la prioridad de otros operadores en su condición. Opciones.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 < nameStart.Length; ++i) 
  {
    int start, j = 0;
    do 
    {
      start = description.IndexOf (nameStart [i], j);
    } 
    while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false);
    ....
    return maxIndex == 1 ? "VALUE" : "VALUE" + (index + 1);
  }
}

El diagnóstico funcionó para la línea:

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

Dado que la variable j unas pocas líneas arriba se inicializa a cero, el operador ternario devolverá el valor false. Debido a esta condición, el cuerpo del bucle se ejecutará sólo una vez. Me parece que este fragmento de código no funciona en absoluto como pretendía el programador.

Advertencia N6

Advertencia del analizador: V3022 [CWE-571] La expresión 'installedPackageVersions.Count != 1' siempre es verdadera. NugetService.cs 1405

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

Hay una extraña condición anidada aquí: installPackageVersions.Count! = 1que siempre será verdadero. A menudo, una advertencia de este tipo indica un error lógico en el código y, en otros casos, simplemente indica una comprobación redundante.

Advertencia N7

Advertencia del analizador: V3001 Hay subexpresiones idénticas 'commandArguments.contains("-apikey")' a la izquierda y a la derecha de '||' operador. ArgumentosUtility.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");
}

El programador que escribió esta sección de código copió y pegó las dos últimas líneas y se olvidó de editarlas. Debido a esto, los usuarios de Chocolatey no pudieron aplicar el parámetro Clave API un par de formas más. De manera similar a los parámetros anteriores, puedo ofrecer las siguientes opciones:

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

Los errores de copiar y pegar tienen muchas posibilidades de aparecer tarde o temprano en cualquier proyecto con una gran cantidad de código fuente, y una de las mejores herramientas para combatirlos es el análisis estático.

PD: Y como siempre, este error tiende a aparecer al final de una condición de varias líneas :). Ver publicación "Efecto de última línea".

Advertencia N8

Advertencia del analizador: V3095 [CWE-476] El objeto 'installedPackage' se usó antes de verificarlo con nulo. Líneas de verificación: 910, 917. NugetService.cs 910

public virtual ConcurrentDictionary<string, PackageResult> 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)
  {
    ....
  }
  ....
}

Error clásico: objeto primero paquete instalado se utiliza y luego se verifica nulo. Este diagnóstico nos informa sobre uno de dos problemas en el programa: paquete instalado nunca igual nulo, lo cual es dudoso, y entonces la verificación es redundante, o podríamos obtener un error grave en el código: un intento de acceder a una referencia nula.

Conclusión

Así que hemos dado un pequeño paso más: ahora utilizar PVS-Studio se ha vuelto aún más fácil y cómodo. También me gustaría decir que Chocolatey es un buen administrador de paquetes con una pequeña cantidad de errores en el código, que podrían ser incluso menos cuando se usa PVS-Studio.

Nosotros invitamos descargar y prueba PVS-Studio. El uso regular de un analizador estático mejorará la calidad y confiabilidad del código que desarrolla su equipo y ayudará a prevenir muchos vulnerabilidades de día cero.

PS

Antes de su publicación, enviamos el artículo a los desarrolladores de Chocolatey y lo recibieron bien. No encontramos nada crítico, pero a ellos, por ejemplo, les gustó el error que encontramos relacionado con la clave "api-key".

PVS-Studio ahora está en Chocolatey: verificando Chocolatey desde Azure DevOps

Si desea compartir este artículo con una audiencia de habla inglesa, utilice el enlace de traducción: Vladislav Stolyarov. PVS-Studio ahora está en Chocolatey: verificando Chocolatey en Azure DevOps.

Fuente: habr.com

Añadir un comentario