vstest中作为环境变量的秘密

时间:2020-05-04 14:16:54

标签: azure-devops vstest

在测试中,我使用的是环境变量。出于安全原因,在将其设置为Azure Devops管道时,我需要将其标记为秘密。是否可以在vstest任务中将其作为参数传递?

2 个答案:

答案 0 :(得分:1)

我已经经历过了。无法在命令行上将变量传递给VSTest,这意味着您必须跳过一些麻烦。

您有几种选择:

  • 使用带有TestRunParameters部分的运行设置文件,然后在测试本身内通过TestContext.Properties["variableName"]访问它。您可以使用标准令牌替换模式来转换XML文件。

  • 使用app.config或appsettings.json(取决于您的平台)。除了您使用标准配置类检索值外,这与上面的工作原理几乎相同。

  • 向您的管道添加一个步骤,以设置适当的环境变量。出于安全性考虑,机密不会自动自动映射到环境变量,但是没有什么可以阻止您自己这样做。

  • 将机密值移动到密钥库或其他外部机密存储中,并配置测试以在运行时提取机密。

答案 1 :(得分:1)

表面上没有足够的声誉来评论@ daniel-mann的答案,我需要自己回答一个答案。

关于运行设置文件的使用;

是的,我敢肯定您可以这样做,但是有一种更简单的方法。在任务定义中,您可以选择覆盖测试运行参数。

对于非YAML管道,请在“替代测试运行参数”选项中执行此操作(工具提示显示“ 替代在runsettings文件的TestRunParameters部分或testsettings文件的Properties部分中定义的参数。例如: -key1 value1 -key2 value2。“),然后这样:

-SomeSecret $(SomeSecret)

对于YAML管道,您可以执行以下操作:

overrideTestrunParameters: '-SomeSecret $(SomeSecret)'

令人高兴的是,您要覆盖的测试运行参数不需要在runsettings文件中存在。实际上,根本不需要运行设置文件!

通常,这种方法的坏处是您必须通过“ TestContext.Properties”集合(对于NUnit)访问您的秘密,如果您想要一个透明的解决方案,该解决方案同样可以很好地工作,那么这确实很烂用于本地开发(使用“用户机密”)和Azure管道中。

与此相关的另一个潜在坏处是,这些“被覆盖”的测试运行参数仅仅是-仅用于该测试运行的参数。如果您碰巧混合使用了.NET Framework和.NET Core测试,则需要在两个不同的测试运行中执行这些测试(以使其完全起作用...),然后需要复制这些替代。 (因为需要一些相同的秘密)。

关于在管道中添加其他任务以设置适当的环境变量;

绝对。使用“批处理脚本”任务非常适合此操作,您只需将基于秘密的变量作为参数传递给脚本,然后在脚本文件中提取它们。

但是,要使此功能按预期工作,您将需要允许任务修改环境。

对于非YAML管道,这是通过选中“修改环境”复选框来完成的。

对于YAML管道,您可以这样做:

- task: BatchScript@1
  displayName: 'Export key vault vars as env. vars (for tests)'
  inputs:
    filename: 'ExportKeyVaultEnvironmentVariables.cmd'
    arguments: '$(SomeSecret)'
    modifyEnvironment: true

在“ ExportKeyVaultEnvironmentVariables.cmd”脚本中,只需执行以下操作:

set SomeSecret=%1

注意::如果您的机密偶然有一些有趣的字符,尤其是带有尾随的“ =”字符,则您可能会遇到以下事实:在脚本中收集参数时得到的不是您发送的内。

您可以通过将参数括在双引号中来避免此问题,如下所示:

arguments: '"$(SomeSecret)"'

然后使用“〜”参数修饰符删除所有引号,从而收集参数,如下所示:

set SomeSecret=%~1

此方法的一个不错的好处是,您闪亮的新完整环境变量将在其余管道中持续存在。回到我的“坏事”,即可能必须复制测试运行参数覆盖,这在这里不需要。

关于OP提及的其他选项;

当然,在这种情况下,您将不需要“批处理脚本”任务(需要调用脚本文件),而仅需要“命令行”任务。

但是,请注意可能的陷阱!是的,如果您通过“ Environment.GetEnvironmentVariable”访问它,这将为您的测试代码创建一个环境变量。

就我而言,我正在构建一个“ IConfigurationRoot”实例,如下所示:

/// <summary>
/// Gets a configuration instance, based on user secrets (for local test execution) and environment variables (for Azure pipeline execution).
/// </summary>
/// <typeparam name="T">The type of the class that represents the "runtime" (and thus is able to get hold of any configuration).</typeparam>
/// <returns>An <see cref="IConfigurationRoot"/> instance.</returns>
public static IConfigurationRoot GetConfigurationRoot<T>()
    where T : class =>
    new ConfigurationBuilder()
        //// Note: The "AddUserSecrets" method requires the "Microsoft.Extensions.Configuration.UserSecrets" package
        .AddUserSecrets<T>()
        //// Note: The "AddEnvironmentVariables" method requires the "Microsoft.Extensions.Configuration.EnvironmentVariables" package
        .AddEnvironmentVariables()
        .Build();

这可以通过添加各种“配置提供程序”来实现,最终使您可以通过“ configuration["SomeSecret"]”无缝访问它们。

但是,我发现,如果我没有误会,是即使添加的“ EnvironmentVariablesConfigurationProvider”中仍然无法使用“ SomeSecret”,即使我可以通过上面的方法直接访问它提到的方法。走吧(但是我可能会误会...)。

可能的替代方法(但仅适用于YAML管道吗?);

对于YAML管道,您似乎可以为任务显式设置环境变量,如下所示:

- task: VSTest@2
  env:
    SomeSecret: $(SomeSecret)
[...]

我自己还没有测试过,但是看到一位同事做过(我自己,我目前没有YAML管道)。至少可以使用“ Environment.GetEnvironmentVariable”来拾取此变量,但是我不知道是否可以通过“ IConfigurationRoot”实例来获取。

我没有看到在非YAML管道中实现相同目标的任何选择。

但是同样,这也遭受着同样的“必须在多个测试运行中复制环境变量”的问题。

也可以在Azure DevOps guys

中查看我对自己问题的解决方案