PVS-Studio agora está no Chocolatey: verificando o Chocolatey no Azure DevOps

PVS-Studio agora está no Chocolatey: verificando o Chocolatey no Azure DevOps
Continuamos a tornar o uso do PVS-Studio mais conveniente. Nosso analisador agora está disponível no Chocolatey, um gerenciador de pacotes para Windows. Acreditamos que isso facilitará a implantação do PVS-Studio, principalmente, em serviços em nuvem. Para não ir longe, vamos verificar o código fonte do mesmo Chocolatey. O Azure DevOps atuará como um sistema de CI.

Aqui está uma lista de nossos outros artigos sobre o tema integração com sistemas em nuvem:

Aconselho que preste atenção ao primeiro artigo sobre integração com Azure DevOps, pois neste caso alguns pontos são omitidos para não serem duplicados.

Então, os heróis deste artigo:

Estúdio PVS é uma ferramenta de análise estática de código projetada para identificar erros e vulnerabilidades potenciais em programas escritos em C, C++, C# e Java. É executado em sistemas Windows, Linux e macOS de 64 bits e pode analisar código projetado para plataformas ARM integradas e de 32 bits, 64 bits. Se esta é a primeira vez que você tenta a análise estática de código para verificar seus projetos, recomendamos que você se familiarize com um artigo sobre como visualizar rapidamente os avisos mais interessantes do PVS-Studio e avaliar os recursos desta ferramenta.

DevOps do Azure — um conjunto de serviços em nuvem que cobrem em conjunto todo o processo de desenvolvimento. Esta plataforma inclui ferramentas como Azure Pipelines, Azure Boards, Azure Artifacts, Azure Repos, Azure Test Plans, que permitem agilizar o processo de criação de software e melhorar a sua qualidade.

Chocolatey é um gerenciador de pacotes de código aberto para Windows. O objetivo do projeto é automatizar todo o ciclo de vida do software, desde a instalação até a atualização e desinstalação em sistemas operacionais Windows.

Sobre o uso do Chocolatey

Você pode ver como instalar o próprio gerenciador de pacotes neste link. A documentação completa para instalação do analisador está disponível em link Consulte a seção Instalação usando o gerenciador de pacotes Chocolatey. Vou repetir brevemente alguns pontos daí.

Comando para instalar a versão mais recente do analisador:

choco install pvs-studio

Comando para instalar uma versão específica do pacote PVS-Studio:

choco install pvs-studio --version=7.05.35617.2075

Por padrão, apenas o núcleo do analisador, o componente Core, é instalado. Todos os outros sinalizadores (Standalone, JavaCore, IDEA, MSVS2010, MSVS2012, MSVS2013, MSVS2015, MSVS2017, MSVS2019) podem ser passados ​​usando --package-parameters.

Um exemplo de comando que instalará um analisador com plugin para Visual Studio 2019:

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

Agora vejamos um exemplo de uso conveniente do analisador no Azure DevOps.

Fixação

Deixe-me lembrá-lo de que há uma seção separada sobre questões como registrar uma conta, criar um Build Pipeline e sincronizar sua conta com um projeto localizado no repositório GitHub. artigo. Nossa configuração começará imediatamente com a gravação de um arquivo de configuração.

Primeiro, vamos configurar um gatilho de inicialização, indicando que iniciaremos apenas para alterações no dominar filial:

trigger:
- master

Em seguida, precisamos selecionar uma máquina virtual. Por enquanto será um agente hospedado pela Microsoft com Windows Server 2019 e Visual Studio 2019:

pool:
  vmImage: 'windows-latest'

Vamos passar para o corpo do arquivo de configuração (bloco passos). Apesar de você não poder instalar software arbitrário em uma máquina virtual, não adicionei um contêiner Docker. Podemos adicionar Chocolatey como uma extensão para Azure DevOps. Para fazer isso, vamos para link. Clique Obtenha gratuitamente. A seguir, se você já estiver autorizado, basta selecionar sua conta e, caso contrário, faça o mesmo após a autorização.

PVS-Studio agora está no Chocolatey: verificando o Chocolatey no Azure DevOps

Aqui você precisa selecionar onde adicionaremos a extensão e clicar no botão Instale.

PVS-Studio agora está no Chocolatey: verificando o Chocolatey no Azure DevOps

Após a instalação bem-sucedida, clique em Prossiga para a organização:

PVS-Studio agora está no Chocolatey: verificando o Chocolatey no Azure DevOps

Agora você pode ver o modelo para a tarefa Chocolatey na janela tarefas ao editar um arquivo de configuração azure-pipelines.yml:

PVS-Studio agora está no Chocolatey: verificando o Chocolatey no Azure DevOps

Clique em Chocolatey e veja uma lista de campos:

PVS-Studio agora está no Chocolatey: verificando o Chocolatey no Azure DevOps

Aqui precisamos selecionar instalar em campo com as equipes. EM Nome do arquivo Nuspec indique o nome do pacote necessário – pvs-studio. Se você não especificar a versão, será instalada a mais recente, o que nos convém perfeitamente. Vamos apertar o botão adicionar e veremos a tarefa gerada no arquivo de configuração.

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

A seguir, vamos passar para a parte principal do nosso arquivo:

- task: CmdLine@2
  inputs:
    script: 

Agora precisamos criar um arquivo com a licença do analisador. Aqui PVSNAME и PVSKEY – nomes de variáveis ​​cujos valores especificamos nas configurações. Eles armazenarão o login e a chave de licença do PVS-Studio. Para definir seus valores, abra o menu Variáveis->Nova variável. Vamos criar variáveis PVSNAME para login e PVSKEY para a chave do analisador. Não se esqueça de marcar a caixa Mantenha este valor em segredo para PVSKEY. Código de comando:

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

Vamos construir o projeto usando o arquivo bat localizado no repositório:

сall build.bat

Vamos criar uma pasta onde serão armazenados os arquivos com os resultados do analisador:

сall mkdir PVSTestResults

Vamos começar a analisar o projeto:

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

Convertemos nosso relatório para o formato html usando o utilitário PlogСonverter:

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

Agora você precisa criar uma tarefa para poder fazer upload do relatório.

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

O arquivo de configuração completo fica assim:

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

Vamos clicar Salvar->Salvar->Executar para executar a tarefa. Vamos baixar o relatório acessando a aba de tarefas.

PVS-Studio agora está no Chocolatey: verificando o Chocolatey no Azure DevOps

O projeto Chocolatey contém apenas 37615 linhas de código C#. Vejamos alguns dos erros encontrados.

Resultado dos testes

Aviso N1

Aviso do analisador: V3005 A variável 'Provider' é atribuída a si mesma. CrytpoHashProviderSpecs.cs38

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

O analisador detectou uma atribuição da variável a si mesmo, o que não faz sentido. Muito provavelmente, no lugar de uma dessas variáveis ​​deveria haver outra. Bem, ou isso é um erro de digitação e a tarefa extra pode simplesmente ser removida.

Aviso N2

Aviso do analisador: V3093 [CWE-480] O operador '&' avalia ambos os operandos. Talvez um operador de curto-circuito '&&' deva ser usado. 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;
  }
}

Diferença do operador & da operadora && é que se o lado esquerdo da expressão for falso, então o lado direito ainda será calculado, o que neste caso implica chamadas de método desnecessárias system.directory_exists.

No fragmento considerado, esta é uma falha menor. Sim, esta condição pode ser otimizada substituindo o operador & pelo operador &&, mas do ponto de vista prático, isso não afeta nada. Porém, em outros casos, a confusão entre & e && pode causar sérios problemas quando o lado direito da expressão é tratado com valores incorretos/inválidos. Por exemplo, em nossa coleção de erros, identificado usando o diagnóstico V3093, há este caso:

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

Mesmo que o índice k estiver incorreto, ele será usado para acessar um elemento do array. Como resultado, uma exceção será lançada IndexOutOfRangeException.

Avisos N3, N4

Aviso do analisador: V3022 [CWE-571] A expressão 'shortPrompt' é sempre verdadeira. InteractivePrompt.cs 101
Aviso do analisador: V3022 [CWE-571] A expressão 'shortPrompt' é sempre verdadeira. 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
    ....
  }
  ....
}

Neste caso, existe uma lógica estranha por trás do funcionamento do operador ternário. Vejamos mais de perto: se a condição que marquei com o número 1 for atendida, passaremos para a condição 2, que é sempre verdadeiro, o que significa que será executada a linha 3. Se a condição 1 for falsa, iremos para a linha marcada com o número 4, condição na qual também é sempre verdadeiro, o que significa que será executada a linha 5. Assim, as condições marcadas com o comentário 0 nunca serão cumpridas, o que pode não ser exatamente a lógica de funcionamento que o programador esperava.

Aviso N5

Aviso do analisador: V3123 [CWE-783] Talvez o operador '?:' funcione de maneira diferente do esperado. A sua prioridade é inferior à prioridade de outros operadores na sua condição. Opções.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);
  }
}

O diagnóstico funcionou para a linha:

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

Já que a variável j algumas linhas acima for inicializado com zero, o operador ternário retornará o valor falso. Devido a esta condição, o corpo do loop será executado apenas uma vez. Parece-me que este trecho de código não funciona como o programador pretendia.

Aviso N6

Aviso do analisador: V3022 [CWE-571] A expressão 'installedPackageVersions.Count != 1' é sempre verdadeira. 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);
    }
    ....
  }
  ....
}

Há uma condição aninhada estranha aqui: instaladoPackageVersions.Count! = 1que sempre será verdadeiro. Freqüentemente, esse aviso indica um erro lógico no código e, em outros casos, simplesmente indica uma verificação redundante.

Aviso N7

Aviso do analisador: V3001 Existem subexpressões idênticas 'commandArguments.contains("-apikey")' à esquerda e à direita 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");
}

O programador que escreveu esta seção do código copiou e colou as duas últimas linhas e esqueceu de editá-las. Por causa disso, os usuários do Chocolatey não conseguiram aplicar o parâmetro Chave API mais algumas maneiras. Semelhante aos parâmetros acima, posso oferecer as seguintes opções:

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

Erros de copiar e colar têm grandes chances de aparecer mais cedo ou mais tarde em qualquer projeto com grande quantidade de código-fonte, e uma das melhores ferramentas para combatê-los é a análise estática.

PS E como sempre, esse erro tende a aparecer no final de uma condição multilinha :). Veja a publicação "Efeito de última linha".

Aviso N8

Aviso do analisador: V3095 [CWE-476] O objeto 'installedPackage' foi usado antes de ser verificado em relação a nulo. Verifique linhas: 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)
  {
    ....
  }
  ....
}

Erro clássico: objeto primeiro pacote instalado é usado e depois verificado nulo. Este diagnóstico nos informa sobre um dos dois problemas no programa: ou pacote instalado nunca igual nulo, o que é duvidoso, e então a verificação é redundante, ou podemos obter um erro grave no código - uma tentativa de acessar uma referência nula.

Conclusão

Então demos mais um pequeno passo - agora usar o PVS-Studio tornou-se ainda mais fácil e conveniente. Gostaria também de dizer que o Chocolatey é um bom gerenciador de pacotes com um pequeno número de erros no código, que podem ser ainda menores ao usar o PVS-Studio.

Nós convidamos baixar e experimente o PVS-Studio. O uso regular de um analisador estático melhorará a qualidade e a confiabilidade do código que sua equipe desenvolve e ajudará a evitar muitos vulnerabilidades de dia zero.

PS

Antes da publicação, enviamos o artigo aos desenvolvedores do Chocolatey e eles o receberam bem. Não encontramos nada crítico, mas eles, por exemplo, gostaram do bug que encontramos relacionado à chave “api-key”.

PVS-Studio agora está no Chocolatey: verificando o Chocolatey no Azure DevOps

Se você quiser compartilhar este artigo com um público que fala inglês, use o link de tradução: Vladislav Stolyarov. PVS-Studio agora está em Chocolatey: Verificando Chocolatey no Azure DevOps.

Fonte: habr.com

Adicionar um comentário