feat: add security sink detection patterns for JavaScript/TypeScript
- Introduced `sink-detect.js` with various security sink detection patterns categorized by type (e.g., command injection, SQL injection, file operations). - Implemented functions to build a lookup map for fast sink detection and to match sink calls against known patterns. - Added `package-lock.json` for dependency management.
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
// Sprint: SPRINT_5200_0001_0001 - Starter Policy Template
|
||||
// Task: T6 - Starter Policy Tests
|
||||
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using FluentAssertions;
|
||||
using Json.Schema;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace StellaOps.Policy.Pack.Tests;
|
||||
|
||||
public class StarterPolicyPackTests
|
||||
{
|
||||
private readonly string _testDataPath;
|
||||
private readonly IDeserializer _yamlDeserializer;
|
||||
|
||||
public StarterPolicyPackTests()
|
||||
{
|
||||
_testDataPath = Path.Combine(AppContext.BaseDirectory, "TestData");
|
||||
_yamlDeserializer = new DeserializerBuilder()
|
||||
.WithNamingConvention(YamlDotNet.Serialization.NamingConventions.CamelCaseNamingConvention.Instance)
|
||||
.Build();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StarterDay1Policy_Exists()
|
||||
{
|
||||
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
|
||||
File.Exists(policyPath).Should().BeTrue("starter-day1.yaml should exist");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StarterDay1Policy_HasValidYamlStructure()
|
||||
{
|
||||
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
|
||||
var content = File.ReadAllText(policyPath);
|
||||
|
||||
var act = () => _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
|
||||
act.Should().NotThrow("YAML should be valid and parseable");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StarterDay1Policy_HasRequiredFields()
|
||||
{
|
||||
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
|
||||
var content = File.ReadAllText(policyPath);
|
||||
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
|
||||
|
||||
policy.Should().ContainKey("apiVersion", "Policy should have apiVersion field");
|
||||
policy.Should().ContainKey("kind", "Policy should have kind field");
|
||||
policy.Should().ContainKey("metadata", "Policy should have metadata field");
|
||||
policy.Should().ContainKey("spec", "Policy should have spec field");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StarterDay1Policy_HasCorrectApiVersion()
|
||||
{
|
||||
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
|
||||
var content = File.ReadAllText(policyPath);
|
||||
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
|
||||
|
||||
policy["apiVersion"].Should().Be("policy.stellaops.io/v1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StarterDay1Policy_HasCorrectKind()
|
||||
{
|
||||
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
|
||||
var content = File.ReadAllText(policyPath);
|
||||
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
|
||||
|
||||
policy["kind"].Should().Be("PolicyPack");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StarterDay1Policy_HasValidMetadata()
|
||||
{
|
||||
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
|
||||
var content = File.ReadAllText(policyPath);
|
||||
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
|
||||
|
||||
var metadata = policy["metadata"] as Dictionary<object, object>;
|
||||
metadata.Should().NotBeNull();
|
||||
metadata!.Should().ContainKey("name");
|
||||
metadata.Should().ContainKey("version");
|
||||
metadata.Should().ContainKey("description");
|
||||
|
||||
metadata["name"].Should().Be("starter-day1");
|
||||
metadata["version"].ToString().Should().MatchRegex(@"^\d+\.\d+\.\d+(-[a-zA-Z0-9]+)?$", "version should be semver");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StarterDay1Policy_HasRulesSection()
|
||||
{
|
||||
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
|
||||
var content = File.ReadAllText(policyPath);
|
||||
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
|
||||
|
||||
var spec = policy["spec"] as Dictionary<object, object>;
|
||||
spec.Should().NotBeNull();
|
||||
spec!.Should().ContainKey("rules");
|
||||
|
||||
var rules = spec["rules"] as List<object>;
|
||||
rules.Should().NotBeNull();
|
||||
rules!.Should().HaveCountGreaterThan(0, "Policy should have at least one rule");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StarterDay1Policy_HasSettingsSection()
|
||||
{
|
||||
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
|
||||
var content = File.ReadAllText(policyPath);
|
||||
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
|
||||
|
||||
var spec = policy["spec"] as Dictionary<object, object>;
|
||||
spec.Should().NotBeNull();
|
||||
spec!.Should().ContainKey("settings");
|
||||
|
||||
var settings = spec["settings"] as Dictionary<object, object>;
|
||||
settings.Should().NotBeNull();
|
||||
settings!.Should().ContainKey("defaultAction");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("block-reachable-high-critical")]
|
||||
[InlineData("warn-reachable-medium")]
|
||||
[InlineData("allow-unreachable")]
|
||||
[InlineData("fail-on-unknowns")]
|
||||
[InlineData("block-kev")]
|
||||
[InlineData("default-allow")]
|
||||
public void StarterDay1Policy_ContainsExpectedRule(string ruleName)
|
||||
{
|
||||
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
|
||||
var content = File.ReadAllText(policyPath);
|
||||
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
|
||||
|
||||
var spec = policy["spec"] as Dictionary<object, object>;
|
||||
var rules = spec!["rules"] as List<object>;
|
||||
|
||||
var ruleNames = rules!.Cast<Dictionary<object, object>>()
|
||||
.Select(r => r["name"]?.ToString())
|
||||
.Where(n => n != null)
|
||||
.ToList();
|
||||
|
||||
ruleNames.Should().Contain(ruleName, $"Policy should contain rule '{ruleName}'");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StarterDay1Policy_HasDefaultAllowRuleWithLowestPriority()
|
||||
{
|
||||
var policyPath = Path.Combine(_testDataPath, "starter-day1.yaml");
|
||||
var content = File.ReadAllText(policyPath);
|
||||
var policy = _yamlDeserializer.Deserialize<Dictionary<string, object>>(content);
|
||||
|
||||
var spec = policy["spec"] as Dictionary<object, object>;
|
||||
var rules = spec!["rules"] as List<object>;
|
||||
|
||||
var defaultAllowRule = rules!.Cast<Dictionary<object, object>>()
|
||||
.FirstOrDefault(r => r["name"]?.ToString() == "default-allow");
|
||||
|
||||
defaultAllowRule.Should().NotBeNull("Policy should have a default-allow rule");
|
||||
|
||||
var priority = Convert.ToInt32(defaultAllowRule!["priority"]);
|
||||
priority.Should().Be(0, "default-allow rule should have the lowest priority (0)");
|
||||
|
||||
var action = defaultAllowRule["action"]?.ToString();
|
||||
action.Should().Be("allow", "default-allow rule should have action 'allow'");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user