feat: Implement Wine CSP HTTP provider for GOST cryptographic operations
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
- Added WineCspHttpProvider class to interface with Wine-hosted CryptoPro CSP. - Implemented ICryptoProvider, ICryptoProviderDiagnostics, and IDisposable interfaces. - Introduced WineCspHttpSigner and WineCspHttpHasher for signing and hashing operations. - Created WineCspProviderOptions for configuration settings including service URL and key options. - Developed CryptoProGostSigningService to handle GOST signing operations and key management. - Implemented HTTP service for the Wine CSP with endpoints for signing, verification, and hashing. - Added Swagger documentation for API endpoints. - Included health checks and error handling for service availability. - Established DTOs for request and response models in the service.
This commit is contained in:
@@ -0,0 +1,766 @@
|
||||
using StellaOps.Scanner.Analyzers.Lang.Go.Internal;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang.Go.Tests.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="GoCapabilityScanner"/>.
|
||||
/// </summary>
|
||||
public sealed class GoCapabilityScannerTests
|
||||
{
|
||||
private const string TestFile = "test.go";
|
||||
|
||||
#region ScanFile - General Tests
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_NullContent_ReturnsEmpty()
|
||||
{
|
||||
var result = GoCapabilityScanner.ScanFile(null!, TestFile);
|
||||
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_EmptyContent_ReturnsEmpty()
|
||||
{
|
||||
var result = GoCapabilityScanner.ScanFile("", TestFile);
|
||||
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_WhitespaceContent_ReturnsEmpty()
|
||||
{
|
||||
var result = GoCapabilityScanner.ScanFile(" \n\t\n ", TestFile);
|
||||
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_NoPatterns_ReturnsEmpty()
|
||||
{
|
||||
const string code = @"
|
||||
package main
|
||||
|
||||
func main() {
|
||||
x := 1 + 2
|
||||
println(x)
|
||||
}";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_NormalizesBackslashesInPath()
|
||||
{
|
||||
const string code = @"cmd := exec.Command(""ls"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, @"C:\test\file.go");
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal("C:/test/file.go", result[0].SourceFile);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DeduplicatesSamePattern()
|
||||
{
|
||||
const string code = @"
|
||||
exec.Command(""ls"")
|
||||
exec.Command(""pwd"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
// Two different lines = two evidences
|
||||
Assert.Equal(2, result.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_SortsByFileLineThenKind()
|
||||
{
|
||||
const string code = @"
|
||||
os.Getenv(""PATH"")
|
||||
exec.Command(""ls"")
|
||||
os.Open(""file.txt"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.True(result.Count >= 3);
|
||||
for (int i = 1; i < result.Count; i++)
|
||||
{
|
||||
Assert.True(
|
||||
result[i - 1].SourceLine < result[i].SourceLine ||
|
||||
(result[i - 1].SourceLine == result[i].SourceLine &&
|
||||
result[i - 1].Kind <= result[i].Kind));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ScanFile - Comment Stripping
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_IgnoresSingleLineComments()
|
||||
{
|
||||
const string code = @"
|
||||
package main
|
||||
// exec.Command(""ls"") - this is a comment
|
||||
func main() {}";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_IgnoresMultiLineComments()
|
||||
{
|
||||
const string code = @"
|
||||
package main
|
||||
/*
|
||||
exec.Command(""ls"")
|
||||
os.Remove(""file"")
|
||||
*/
|
||||
func main() {}";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ScanFile - Exec Patterns
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsExecCommand()
|
||||
{
|
||||
const string code = @"cmd := exec.Command(""ls"", ""-la"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Exec, result[0].Kind);
|
||||
Assert.Equal("exec.Command", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Critical, result[0].Risk);
|
||||
Assert.Equal(1.0f, result[0].Confidence);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsExecCommandContext()
|
||||
{
|
||||
const string code = @"cmd := exec.CommandContext(ctx, ""ls"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Exec, result[0].Kind);
|
||||
Assert.Equal("exec.Command", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Critical, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsSyscallExec()
|
||||
{
|
||||
const string code = @"syscall.Exec(""/bin/sh"", args, env)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Exec, result[0].Kind);
|
||||
Assert.Equal("syscall.Exec", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Critical, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsSyscallForkExec()
|
||||
{
|
||||
const string code = @"syscall.ForkExec(""/bin/sh"", args, nil)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Exec, result[0].Kind);
|
||||
Assert.Equal("syscall.Exec", result[0].Pattern);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsStartProcess()
|
||||
{
|
||||
const string code = @"os.StartProcess(""/bin/ls"", []string{}, &attr)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Exec, result[0].Kind);
|
||||
Assert.Equal("os.StartProcess", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Critical, result[0].Risk);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ScanFile - Filesystem Patterns
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsCreate()
|
||||
{
|
||||
const string code = @"f, err := os.Create(""file.txt"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Filesystem, result[0].Kind);
|
||||
Assert.Equal("os.Open/Create", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Medium, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsOpen()
|
||||
{
|
||||
const string code = @"f, err := os.Open(""file.txt"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Filesystem, result[0].Kind);
|
||||
Assert.Equal("os.Open/Create", result[0].Pattern);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsOpenFile()
|
||||
{
|
||||
const string code = @"f, err := os.OpenFile(""file.txt"", os.O_RDWR, 0644)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Filesystem, result[0].Kind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsRemove()
|
||||
{
|
||||
const string code = @"os.Remove(""file.txt"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Filesystem, result[0].Kind);
|
||||
Assert.Equal("os.Remove/RemoveAll", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.High, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsRemoveAll()
|
||||
{
|
||||
const string code = @"os.RemoveAll(""/tmp/dir"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Filesystem, result[0].Kind);
|
||||
Assert.Equal("os.Remove/RemoveAll", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.High, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsChmod()
|
||||
{
|
||||
const string code = @"os.Chmod(""file.txt"", 0755)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Filesystem, result[0].Kind);
|
||||
Assert.Equal("os.Chmod/Chown", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.High, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsChown()
|
||||
{
|
||||
const string code = @"os.Chown(""file.txt"", 1000, 1000)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Filesystem, result[0].Kind);
|
||||
Assert.Equal("os.Chmod/Chown", result[0].Pattern);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsSymlink()
|
||||
{
|
||||
const string code = @"os.Symlink(""target"", ""link"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Filesystem, result[0].Kind);
|
||||
Assert.Equal("os.Symlink/Link", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.High, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsMkdir()
|
||||
{
|
||||
const string code = @"os.Mkdir(""dir"", 0755)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Filesystem, result[0].Kind);
|
||||
Assert.Equal("os.Mkdir", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Medium, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsReadFile()
|
||||
{
|
||||
const string code = @"data, _ := os.ReadFile(""file.txt"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Filesystem, result[0].Kind);
|
||||
Assert.Equal("os.ReadFile/WriteFile", result[0].Pattern);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsIoutilReadFile()
|
||||
{
|
||||
const string code = @"data, _ := ioutil.ReadFile(""file.txt"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Filesystem, result[0].Kind);
|
||||
Assert.Equal("ioutil", result[0].Pattern);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ScanFile - Network Patterns
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsNetDial()
|
||||
{
|
||||
const string code = @"conn, _ := net.Dial(""tcp"", ""localhost:8080"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Network, result[0].Kind);
|
||||
Assert.Equal("net.Dial", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Medium, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsNetListen()
|
||||
{
|
||||
const string code = @"ln, _ := net.Listen(""tcp"", "":8080"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Network, result[0].Kind);
|
||||
Assert.Equal("net.Listen", result[0].Pattern);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsHttpGet()
|
||||
{
|
||||
const string code = @"resp, _ := http.Get(""https://example.com"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Network, result[0].Kind);
|
||||
Assert.Equal("http.Get/Post", result[0].Pattern);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsHttpPost()
|
||||
{
|
||||
const string code = @"resp, _ := http.Post(""https://example.com"", ""application/json"", body)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Network, result[0].Kind);
|
||||
Assert.Equal("http.Get/Post", result[0].Pattern);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsHttpListenAndServe()
|
||||
{
|
||||
const string code = @"http.ListenAndServe("":8080"", nil)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Network, result[0].Kind);
|
||||
Assert.Equal("http.ListenAndServe", result[0].Pattern);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsNetLookupHost()
|
||||
{
|
||||
const string code = @"addrs, _ := net.LookupHost(""example.com"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Network, result[0].Kind);
|
||||
Assert.Equal("net.Lookup", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Low, result[0].Risk);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ScanFile - Environment Patterns
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsGetenv()
|
||||
{
|
||||
const string code = @"val := os.Getenv(""PATH"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Environment, result[0].Kind);
|
||||
Assert.Equal("os.Getenv", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Medium, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsLookupEnv()
|
||||
{
|
||||
const string code = @"val, ok := os.LookupEnv(""PATH"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Environment, result[0].Kind);
|
||||
Assert.Equal("os.Getenv", result[0].Pattern);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsSetenv()
|
||||
{
|
||||
const string code = @"os.Setenv(""MY_VAR"", ""value"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Environment, result[0].Kind);
|
||||
Assert.Equal("os.Setenv", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.High, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsOsEnviron()
|
||||
{
|
||||
const string code = @"env := os.Environ()";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Environment, result[0].Kind);
|
||||
Assert.Equal("os.Environ", result[0].Pattern);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ScanFile - Serialization Patterns
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsGobDecoder()
|
||||
{
|
||||
const string code = @"dec := gob.NewDecoder(reader)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Serialization, result[0].Kind);
|
||||
Assert.Equal("gob.Decoder/Encoder", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Medium, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsJsonUnmarshal()
|
||||
{
|
||||
const string code = @"json.Unmarshal(data, &obj)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Serialization, result[0].Kind);
|
||||
Assert.Equal("json", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Low, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsXmlUnmarshal()
|
||||
{
|
||||
const string code = @"xml.Unmarshal(data, &obj)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Serialization, result[0].Kind);
|
||||
Assert.Equal("xml.Unmarshal", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Medium, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsYamlUnmarshal()
|
||||
{
|
||||
const string code = @"yaml.Unmarshal(data, &obj)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Serialization, result[0].Kind);
|
||||
Assert.Equal("yaml.Unmarshal", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Medium, result[0].Risk);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ScanFile - Crypto Patterns
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsSha256New()
|
||||
{
|
||||
const string code = @"h := sha256.New()";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Crypto, result[0].Kind);
|
||||
Assert.Equal("crypto/hash", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Low, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsAesNewCipher()
|
||||
{
|
||||
const string code = @"block, _ := aes.NewCipher(key)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Crypto, result[0].Kind);
|
||||
Assert.Equal("crypto/cipher", result[0].Pattern);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsRsaGenerateKey()
|
||||
{
|
||||
const string code = @"key, _ := rsa.GenerateKey(rand.Reader, 2048)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Crypto, result[0].Kind);
|
||||
Assert.Equal("crypto/rsa", result[0].Pattern);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ScanFile - Database Patterns
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsSqlOpen()
|
||||
{
|
||||
const string code = @"db, _ := sql.Open(""postgres"", connStr)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Database, result[0].Kind);
|
||||
Assert.Equal("sql.Open", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Medium, result[0].Risk);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ScanFile - Dynamic Code Patterns
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsReflectValueCall()
|
||||
{
|
||||
const string code = @"
|
||||
import ""reflect""
|
||||
v.Call(args)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.DynamicCode, result[0].Kind);
|
||||
Assert.Equal("reflect.Value.Call", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.High, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsMethodByName()
|
||||
{
|
||||
const string code = @"m := v.MethodByName(""Execute"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.DynamicCode, result[0].Kind);
|
||||
Assert.Equal("reflect.MethodByName", result[0].Pattern);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ScanFile - Reflection Patterns
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsReflectTypeOf()
|
||||
{
|
||||
const string code = @"t := reflect.TypeOf(obj)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Reflection, result[0].Kind);
|
||||
Assert.Equal("reflect.TypeOf/ValueOf", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Low, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsReflectNew()
|
||||
{
|
||||
const string code = @"v := reflect.New(t)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Reflection, result[0].Kind);
|
||||
Assert.Equal("reflect.New", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Medium, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsRuntimeCaller()
|
||||
{
|
||||
const string code = @"_, file, line, _ := runtime.Caller(0)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.Reflection, result[0].Kind);
|
||||
Assert.Equal("runtime.Caller", result[0].Pattern);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ScanFile - Native Code Patterns
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsCgoImport()
|
||||
{
|
||||
const string code = @"import ""C""";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.NativeCode, result[0].Kind);
|
||||
Assert.Contains("C", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.High, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsUnsafePointer()
|
||||
{
|
||||
const string code = @"ptr := unsafe.Pointer(&x)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.NativeCode, result[0].Kind);
|
||||
Assert.Equal("unsafe.Pointer", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Critical, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsGoLinknameDirective()
|
||||
{
|
||||
const string code = @"//go:linkname localName runtime.someInternalFunc";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.NativeCode, result[0].Kind);
|
||||
Assert.Equal("go:linkname", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Critical, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsGoNoescapeDirective()
|
||||
{
|
||||
const string code = @"//go:noescape
|
||||
func unsafeFunc(ptr *byte)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.NativeCode, result[0].Kind);
|
||||
Assert.Equal("go:noescape", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.High, result[0].Risk);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsSyscallSyscall()
|
||||
{
|
||||
const string code = @"r1, r2, err := syscall.Syscall(SYS_WRITE, fd, buf, count)";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.NativeCode, result[0].Kind);
|
||||
Assert.Equal("syscall.Syscall", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Critical, result[0].Risk);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ScanFile - Plugin Patterns
|
||||
|
||||
[Fact]
|
||||
public void ScanFile_DetectsPluginOpen()
|
||||
{
|
||||
const string code = @"p, _ := plugin.Open(""plugin.so"")";
|
||||
var result = GoCapabilityScanner.ScanFile(code, TestFile);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(CapabilityKind.PluginLoading, result[0].Kind);
|
||||
Assert.Equal("plugin.Open", result[0].Pattern);
|
||||
Assert.Equal(CapabilityRisk.Critical, result[0].Risk);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GoCapabilityEvidence Tests
|
||||
|
||||
[Fact]
|
||||
public void Evidence_DeduplicationKey_IsCorrect()
|
||||
{
|
||||
var evidence = new GoCapabilityEvidence(
|
||||
CapabilityKind.Exec,
|
||||
"test.go",
|
||||
10,
|
||||
"exec.Command");
|
||||
|
||||
Assert.Equal("Exec|test.go|10|exec.Command", evidence.DeduplicationKey);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Evidence_ConfidenceIsClamped()
|
||||
{
|
||||
var evidence1 = new GoCapabilityEvidence(
|
||||
CapabilityKind.Exec, "test.go", 1, "pattern",
|
||||
confidence: 2.0f);
|
||||
var evidence2 = new GoCapabilityEvidence(
|
||||
CapabilityKind.Exec, "test.go", 1, "pattern",
|
||||
confidence: -1.0f);
|
||||
|
||||
Assert.Equal(1.0f, evidence1.Confidence);
|
||||
Assert.Equal(0.0f, evidence2.Confidence);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Evidence_CreateMetadata_IncludesAllFields()
|
||||
{
|
||||
var evidence = new GoCapabilityEvidence(
|
||||
CapabilityKind.Exec,
|
||||
"test.go",
|
||||
10,
|
||||
"exec.Command",
|
||||
snippet: "cmd := exec.Command(\"ls\")",
|
||||
confidence: 0.95f,
|
||||
risk: CapabilityRisk.Critical);
|
||||
|
||||
var metadata = evidence.CreateMetadata().ToDictionary(kv => kv.Key, kv => kv.Value);
|
||||
|
||||
Assert.Equal("exec", metadata["capability.kind"]);
|
||||
Assert.Equal("test.go:10", metadata["capability.source"]);
|
||||
Assert.Equal("exec.Command", metadata["capability.pattern"]);
|
||||
Assert.Equal("critical", metadata["capability.risk"]);
|
||||
Assert.Equal("0.95", metadata["capability.confidence"]);
|
||||
Assert.Contains("exec.Command", metadata["capability.snippet"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Evidence_ToLanguageEvidence_ReturnsCorrectFormat()
|
||||
{
|
||||
var evidence = new GoCapabilityEvidence(
|
||||
CapabilityKind.Exec,
|
||||
"test.go",
|
||||
10,
|
||||
"exec.Command");
|
||||
|
||||
var langEvidence = evidence.ToLanguageEvidence();
|
||||
|
||||
Assert.Equal(LanguageEvidenceKind.Metadata, langEvidence.Kind);
|
||||
Assert.Equal("test.go", langEvidence.Source);
|
||||
Assert.Equal("line:10", langEvidence.Locator);
|
||||
Assert.Equal("Exec:exec.Command", langEvidence.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user