-
Notifications
You must be signed in to change notification settings - Fork 123
Expand file tree
/
Copy pathBinarySyftRunner.cs
More file actions
126 lines (110 loc) · 4.25 KB
/
BinarySyftRunner.cs
File metadata and controls
126 lines (110 loc) · 4.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
namespace Microsoft.ComponentDetection.Detectors.Linux;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.Extensions.Logging;
/// <summary>
/// Runs Syft by invoking a local Syft binary.
/// </summary>
internal class BinarySyftRunner : ISyftRunner
{
private static readonly SemaphoreSlim BinarySemaphore = new(2);
private static readonly int SemaphoreTimeout = Convert.ToInt32(
TimeSpan.FromHours(1).TotalMilliseconds);
private readonly string syftBinaryPath;
private readonly ICommandLineInvocationService commandLineInvocationService;
private readonly ILogger<BinarySyftRunner> logger;
/// <summary>
/// Initializes a new instance of the <see cref="BinarySyftRunner"/> class.
/// </summary>
/// <param name="syftBinaryPath">The path to the Syft binary.</param>
/// <param name="commandLineInvocationService">The command line invocation service.</param>
/// <param name="logger">The logger.</param>
public BinarySyftRunner(
string syftBinaryPath,
ICommandLineInvocationService commandLineInvocationService,
ILogger<BinarySyftRunner> logger)
{
this.syftBinaryPath = syftBinaryPath;
this.commandLineInvocationService = commandLineInvocationService;
this.logger = logger;
}
/// <inheritdoc/>
public async Task<bool> CanRunAsync(CancellationToken cancellationToken = default)
{
if (!await this.commandLineInvocationService.CanCommandBeLocatedAsync(this.syftBinaryPath, null, "--version"))
{
this.logger.LogInformation("Syft binary at {SyftBinaryPath} was not found in the local environment.", this.syftBinaryPath);
return false;
}
var result = await this.commandLineInvocationService.ExecuteCommandAsync(
this.syftBinaryPath,
null,
null,
cancellationToken,
"--version");
if (result.ExitCode != 0)
{
this.logger.LogInformation(
"Syft binary at {SyftBinaryPath} failed version check with exit code {ExitCode}. Stderr: {StdErr}",
this.syftBinaryPath,
result.ExitCode,
result.StdErr);
return false;
}
this.logger.LogInformation(
"Using Syft binary at {SyftBinaryPath}: {SyftVersion}",
this.syftBinaryPath,
result.StdOut?.Trim());
return true;
}
/// <inheritdoc/>
public async Task<(string Stdout, string Stderr)> RunSyftAsync(
ImageReference imageReference,
IList<string> arguments,
CancellationToken cancellationToken = default)
{
var (syftSourceKind, syftSource) = GetSyftSource(imageReference);
var acquired = false;
try
{
acquired = await BinarySemaphore.WaitAsync(SemaphoreTimeout, cancellationToken);
if (!acquired)
{
this.logger.LogWarning(
"Failed to enter the binary semaphore for image {ImageReference}",
imageReference.Reference);
return (string.Empty, string.Empty);
}
var parameters = new[] { syftSource, ISyftRunner.SyftSourceKindArgument, syftSourceKind }
.Concat(arguments)
.ToArray();
var result = await this.commandLineInvocationService.ExecuteCommandAsync(
this.syftBinaryPath,
null,
null,
cancellationToken,
parameters);
if (result.ExitCode != 0)
{
this.logger.LogError(
"Syft binary exited with code {ExitCode}. Stderr: {StdErr}",
result.ExitCode,
result.StdErr);
}
return (result.StdOut, result.StdErr);
}
finally
{
if (acquired)
{
BinarySemaphore.Release();
}
}
}
private static (string SyftSourceKind, string SyftSource) GetSyftSource(ImageReference imageReference) =>
(imageReference.GetSyftSourceKind(), imageReference.Reference);
}