save progress
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
// <copyright file="AzureDevOpsGeneratorTests.cs" company="StellaOps">
|
||||
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Tools.WorkflowGenerator.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="AzureDevOpsGenerator"/>.
|
||||
/// </summary>
|
||||
[Trait("Category", "Unit")]
|
||||
public class AzureDevOpsGeneratorTests
|
||||
{
|
||||
private readonly AzureDevOpsGenerator _generator = new();
|
||||
|
||||
[Fact]
|
||||
public void Platform_ReturnsAzureDevOps()
|
||||
{
|
||||
_generator.Platform.Should().Be(CiPlatform.AzureDevOps);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlatformName_ReturnsAzureDevOps()
|
||||
{
|
||||
_generator.PlatformName.Should().Be("Azure DevOps");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DefaultFileName_ReturnsAzurePipelinesYml()
|
||||
{
|
||||
_generator.DefaultFileName.Should().Be("azure-pipelines.yml");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsPipelineName()
|
||||
{
|
||||
var options = WorkflowOptions.AzureDevOpsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("name: StellaOps Security Scan");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsTrigger()
|
||||
{
|
||||
var options = WorkflowOptions.AzureDevOpsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("trigger:");
|
||||
yaml.Should().Contain("branches:");
|
||||
yaml.Should().Contain("include:");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsPr()
|
||||
{
|
||||
var options = WorkflowOptions.AzureDevOpsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("pr:");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsPool()
|
||||
{
|
||||
var options = WorkflowOptions.AzureDevOpsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("pool:");
|
||||
yaml.Should().Contain("vmImage: 'ubuntu-latest'");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsStages()
|
||||
{
|
||||
var options = WorkflowOptions.AzureDevOpsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("stages:");
|
||||
yaml.Should().Contain("- stage: Security");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsBashTask()
|
||||
{
|
||||
var options = WorkflowOptions.AzureDevOpsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("task: Bash@3");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsPublishArtifact()
|
||||
{
|
||||
var options = WorkflowOptions.AzureDevOpsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("PublishBuildArtifacts@1");
|
||||
yaml.Should().Contain("artifactName: 'CodeAnalysisLogs'");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsCheckout()
|
||||
{
|
||||
var options = WorkflowOptions.AzureDevOpsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("- checkout: self");
|
||||
yaml.Should().Contain("fetchDepth: 0");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_WithSchedule_ContainsCron()
|
||||
{
|
||||
var options = WorkflowOptions.AzureDevOpsDefault with
|
||||
{
|
||||
Triggers = TriggerConfig.WeeklySchedule
|
||||
};
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("schedules:");
|
||||
yaml.Should().Contain("cron:");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_CorrectPlatform_ReturnsValid()
|
||||
{
|
||||
var options = WorkflowOptions.AzureDevOpsDefault;
|
||||
|
||||
var result = _generator.Validate(options);
|
||||
|
||||
result.IsValid.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_WrongPlatform_ReturnsInvalid()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
var result = _generator.Validate(options);
|
||||
|
||||
result.IsValid.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
// <copyright file="GitHubActionsGeneratorTests.cs" company="StellaOps">
|
||||
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Tools.WorkflowGenerator.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="GitHubActionsGenerator"/>.
|
||||
/// </summary>
|
||||
[Trait("Category", "Unit")]
|
||||
public class GitHubActionsGeneratorTests
|
||||
{
|
||||
private readonly GitHubActionsGenerator _generator = new();
|
||||
|
||||
[Fact]
|
||||
public void Platform_ReturnsGitHubActions()
|
||||
{
|
||||
_generator.Platform.Should().Be(CiPlatform.GitHubActions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlatformName_ReturnsGitHubActions()
|
||||
{
|
||||
_generator.PlatformName.Should().Be("GitHub Actions");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DefaultFileName_ReturnsYml()
|
||||
{
|
||||
_generator.DefaultFileName.Should().Be("stellaops-scan.yml");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsWorkflowName()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("name: StellaOps Security Scan");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsPushTrigger()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("push:");
|
||||
yaml.Should().Contain("- main");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsPullRequestTrigger()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("pull_request:");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsWorkflowDispatch()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("workflow_dispatch:");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsSecurityEventsPermission()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("security-events: write");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsCheckoutStep()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("uses: actions/checkout@v4");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsCliInstallation()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("curl -fsSL https://get.stellaops.io | sh");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsSarifUpload()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("github/codeql-action/upload-sarif@v3");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_WithCustomName_UsesCustomName()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault with
|
||||
{
|
||||
Name = "Custom Security Scan"
|
||||
};
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("name: Custom Security Scan");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_WithSchedule_ContainsCron()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault with
|
||||
{
|
||||
Triggers = TriggerConfig.WeeklySchedule
|
||||
};
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("schedule:");
|
||||
yaml.Should().Contain("cron: '0 0 * * 0'");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_WithNoComments_OmitsComments()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault with
|
||||
{
|
||||
IncludeComments = false
|
||||
};
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().NotContain("# StellaOps Security Scan Workflow");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_WithImageScan_UsesImageSyntax()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault with
|
||||
{
|
||||
Scan = ScanConfig.ContainerImage("myregistry.io/myimage:latest")
|
||||
};
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("image:myregistry.io/myimage:latest");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_WithReachability_IncludesReachabilityFlag()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault with
|
||||
{
|
||||
Scan = ScanConfig.DefaultRepository with { IncludeReachability = true }
|
||||
};
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("--reachability");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_WithFailOnSeverity_IncludesExitCode()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault with
|
||||
{
|
||||
Scan = ScanConfig.DefaultRepository with { FailOnSeverity = "high" }
|
||||
};
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("--exit-code-on high");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_WithEnvironmentVariables_IncludesEnvBlock()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault with
|
||||
{
|
||||
EnvironmentVariables = new Dictionary<string, string>
|
||||
{
|
||||
["STELLAOPS_API_KEY"] = "${{ secrets.STELLAOPS_API_KEY }}"
|
||||
}
|
||||
};
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("env:");
|
||||
yaml.Should().Contain("STELLAOPS_API_KEY:");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_WithCategory_IncludesCategory()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault with
|
||||
{
|
||||
Upload = UploadConfig.Default with { Category = "stellaops-scan" }
|
||||
};
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("category: stellaops-scan");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_CorrectPlatform_ReturnsValid()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
var result = _generator.Validate(options);
|
||||
|
||||
result.IsValid.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_WrongPlatform_ReturnsInvalid()
|
||||
{
|
||||
var options = WorkflowOptions.GitLabCiDefault;
|
||||
|
||||
var result = _generator.Validate(options);
|
||||
|
||||
result.IsValid.Should().BeFalse();
|
||||
result.Errors.Should().Contain(e => e.Contains("GitLabCi"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
// <copyright file="GitLabCiGeneratorTests.cs" company="StellaOps">
|
||||
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Tools.WorkflowGenerator.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="GitLabCiGenerator"/>.
|
||||
/// </summary>
|
||||
[Trait("Category", "Unit")]
|
||||
public class GitLabCiGeneratorTests
|
||||
{
|
||||
private readonly GitLabCiGenerator _generator = new();
|
||||
|
||||
[Fact]
|
||||
public void Platform_ReturnsGitLabCi()
|
||||
{
|
||||
_generator.Platform.Should().Be(CiPlatform.GitLabCi);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlatformName_ReturnsGitLabCiCd()
|
||||
{
|
||||
_generator.PlatformName.Should().Be("GitLab CI/CD");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DefaultFileName_ReturnsGitLabCiYml()
|
||||
{
|
||||
_generator.DefaultFileName.Should().Be(".gitlab-ci.yml");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsStages()
|
||||
{
|
||||
var options = WorkflowOptions.GitLabCiDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("stages:");
|
||||
yaml.Should().Contain("- security");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsVariables()
|
||||
{
|
||||
var options = WorkflowOptions.GitLabCiDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("variables:");
|
||||
yaml.Should().Contain("STELLAOPS_VERSION:");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsStellaopsJob()
|
||||
{
|
||||
var options = WorkflowOptions.GitLabCiDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("stellaops-scan:");
|
||||
yaml.Should().Contain("stage: security");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsRules()
|
||||
{
|
||||
var options = WorkflowOptions.GitLabCiDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("rules:");
|
||||
yaml.Should().Contain("$CI_COMMIT_BRANCH");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsArtifacts()
|
||||
{
|
||||
var options = WorkflowOptions.GitLabCiDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("artifacts:");
|
||||
yaml.Should().Contain("reports:");
|
||||
yaml.Should().Contain("sast:");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_ContainsCliInstallation()
|
||||
{
|
||||
var options = WorkflowOptions.GitLabCiDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("before_script:");
|
||||
yaml.Should().Contain("curl -fsSL https://get.stellaops.io | sh");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_DefaultOptions_AllowsFailure()
|
||||
{
|
||||
var options = WorkflowOptions.GitLabCiDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("allow_failure: true");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_WithFailOnSeverity_DoesNotAllowFailure()
|
||||
{
|
||||
var options = WorkflowOptions.GitLabCiDefault with
|
||||
{
|
||||
Scan = ScanConfig.DefaultRepository with { FailOnSeverity = "critical" }
|
||||
};
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().NotContain("allow_failure: true");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_WithMergeRequest_IncludesMrRule()
|
||||
{
|
||||
var options = WorkflowOptions.GitLabCiDefault;
|
||||
|
||||
var yaml = _generator.Generate(options);
|
||||
|
||||
yaml.Should().Contain("merge_request_event");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_CorrectPlatform_ReturnsValid()
|
||||
{
|
||||
var options = WorkflowOptions.GitLabCiDefault;
|
||||
|
||||
var result = _generator.Validate(options);
|
||||
|
||||
result.IsValid.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_WrongPlatform_ReturnsInvalid()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
var result = _generator.Validate(options);
|
||||
|
||||
result.IsValid.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
// <copyright file="GoldenFixtureTests.cs" company="StellaOps">
|
||||
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Tools.WorkflowGenerator.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Golden fixture tests for workflow generation.
|
||||
/// These tests ensure generated workflows match expected output.
|
||||
/// </summary>
|
||||
[Trait("Category", "Unit")]
|
||||
public class GoldenFixtureTests
|
||||
{
|
||||
[Fact]
|
||||
public void GitHubActions_Minimal_MatchesExpected()
|
||||
{
|
||||
var generator = new GitHubActionsGenerator();
|
||||
var options = new WorkflowOptions
|
||||
{
|
||||
Platform = CiPlatform.GitHubActions,
|
||||
Name = "StellaOps Scan",
|
||||
Triggers = new TriggerConfig { PushBranches = ["main"] },
|
||||
Scan = new ScanConfig { ScanPath = "." }
|
||||
};
|
||||
|
||||
var result = generator.Generate(options);
|
||||
|
||||
// Should contain workflow name
|
||||
result.Should().Contain("name: StellaOps Scan");
|
||||
// Should contain push trigger
|
||||
result.Should().Contain("push:");
|
||||
// Should have jobs section
|
||||
result.Should().Contain("jobs:");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GitHubActions_WithSchedule_IncludesCron()
|
||||
{
|
||||
var generator = new GitHubActionsGenerator();
|
||||
var options = new WorkflowOptions
|
||||
{
|
||||
Platform = CiPlatform.GitHubActions,
|
||||
Name = "Scheduled Scan",
|
||||
Triggers = new TriggerConfig
|
||||
{
|
||||
Schedule = "0 0 * * *"
|
||||
},
|
||||
Scan = new ScanConfig { ScanPath = "." }
|
||||
};
|
||||
|
||||
var result = generator.Generate(options);
|
||||
|
||||
result.Should().Contain("schedule:");
|
||||
result.Should().Contain("- cron: '0 0 * * *'");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GitHubActions_WithSarifUpload_IncludesCodeScanningAction()
|
||||
{
|
||||
var generator = new GitHubActionsGenerator();
|
||||
var options = new WorkflowOptions
|
||||
{
|
||||
Platform = CiPlatform.GitHubActions,
|
||||
Name = "Scan with SARIF",
|
||||
Triggers = new TriggerConfig { PushBranches = ["main"] },
|
||||
Scan = new ScanConfig { ScanPath = "." },
|
||||
Upload = new UploadConfig
|
||||
{
|
||||
UploadSarif = true,
|
||||
SarifFileName = "results.sarif"
|
||||
}
|
||||
};
|
||||
|
||||
var result = generator.Generate(options);
|
||||
|
||||
result.Should().Contain("github/codeql-action/upload-sarif");
|
||||
result.Should().Contain("sarif_file: results.sarif");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GitLabCi_Minimal_MatchesExpected()
|
||||
{
|
||||
var generator = new GitLabCiGenerator();
|
||||
var options = new WorkflowOptions
|
||||
{
|
||||
Platform = CiPlatform.GitLabCi,
|
||||
Name = "stellaops-scan",
|
||||
Scan = new ScanConfig { ScanPath = "." }
|
||||
};
|
||||
|
||||
var result = generator.Generate(options);
|
||||
|
||||
// Should contain stages
|
||||
result.Should().Contain("stages:");
|
||||
// Should have scan job
|
||||
result.Should().Contain("stellaops-scan:");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GitLabCi_WithRules_IncludesBranchFilter()
|
||||
{
|
||||
var generator = new GitLabCiGenerator();
|
||||
var options = new WorkflowOptions
|
||||
{
|
||||
Platform = CiPlatform.GitLabCi,
|
||||
Name = "stellaops-scan",
|
||||
Triggers = new TriggerConfig { PushBranches = ["main", "develop"] },
|
||||
Scan = new ScanConfig { ScanPath = "." }
|
||||
};
|
||||
|
||||
var result = generator.Generate(options);
|
||||
|
||||
result.Should().Contain("rules:");
|
||||
result.Should().Contain("$CI_COMMIT_BRANCH == \"main\"");
|
||||
result.Should().Contain("$CI_COMMIT_BRANCH == \"develop\"");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AzureDevOps_Minimal_MatchesExpected()
|
||||
{
|
||||
var generator = new AzureDevOpsGenerator();
|
||||
var options = new WorkflowOptions
|
||||
{
|
||||
Platform = CiPlatform.AzureDevOps,
|
||||
Name = "StellaOps Scan",
|
||||
Triggers = new TriggerConfig { PushBranches = ["main"] },
|
||||
Scan = new ScanConfig { ScanPath = "." }
|
||||
};
|
||||
|
||||
var result = generator.Generate(options);
|
||||
|
||||
// Should contain trigger configuration
|
||||
result.Should().Contain("trigger:");
|
||||
// Should have stages section
|
||||
result.Should().Contain("stages:");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AzureDevOps_WithPr_IncludesPrTrigger()
|
||||
{
|
||||
var generator = new AzureDevOpsGenerator();
|
||||
var options = new WorkflowOptions
|
||||
{
|
||||
Platform = CiPlatform.AzureDevOps,
|
||||
Name = "PR Scan",
|
||||
Triggers = new TriggerConfig { PullRequestBranches = ["main"] },
|
||||
Scan = new ScanConfig { ScanPath = "." }
|
||||
};
|
||||
|
||||
var result = generator.Generate(options);
|
||||
|
||||
result.Should().Contain("pr:");
|
||||
result.Should().Contain("branches:");
|
||||
result.Should().Contain("include:");
|
||||
result.Should().Contain("- main");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllPlatforms_WithAllTriggers_GenerateValidYaml()
|
||||
{
|
||||
var options = new WorkflowOptions
|
||||
{
|
||||
Platform = CiPlatform.GitHubActions,
|
||||
Name = "Full Test",
|
||||
Triggers = new TriggerConfig
|
||||
{
|
||||
PushBranches = ["main", "release/*"],
|
||||
PullRequestBranches = ["main"],
|
||||
Schedule = "0 0 * * 0",
|
||||
ManualTrigger = true
|
||||
},
|
||||
Scan = new ScanConfig
|
||||
{
|
||||
ScanPath = "./src"
|
||||
},
|
||||
Upload = new UploadConfig
|
||||
{
|
||||
UploadSarif = true
|
||||
}
|
||||
};
|
||||
|
||||
var githubGenerator = new GitHubActionsGenerator();
|
||||
var gitlabGenerator = new GitLabCiGenerator();
|
||||
var azureGenerator = new AzureDevOpsGenerator();
|
||||
|
||||
var githubResult = githubGenerator.Generate(options);
|
||||
var gitlabResult = gitlabGenerator.Generate(options with { Platform = CiPlatform.GitLabCi });
|
||||
var azureResult = azureGenerator.Generate(options with { Platform = CiPlatform.AzureDevOps });
|
||||
|
||||
// All should generate non-empty YAML
|
||||
githubResult.Should().NotBeNullOrEmpty();
|
||||
gitlabResult.Should().NotBeNullOrEmpty();
|
||||
azureResult.Should().NotBeNullOrEmpty();
|
||||
|
||||
// All should have scan path
|
||||
githubResult.Should().Contain("./src");
|
||||
gitlabResult.Should().Contain("./src");
|
||||
azureResult.Should().Contain("./src");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Factory_CreatesCorrectGeneratorForPlatform()
|
||||
{
|
||||
var factory = new WorkflowGeneratorFactory();
|
||||
|
||||
factory.GetGenerator(CiPlatform.GitHubActions).Should().BeOfType<GitHubActionsGenerator>();
|
||||
factory.GetGenerator(CiPlatform.GitLabCi).Should().BeOfType<GitLabCiGenerator>();
|
||||
factory.GetGenerator(CiPlatform.AzureDevOps).Should().BeOfType<AzureDevOpsGenerator>();
|
||||
factory.GetGenerator(CiPlatform.GiteaActions).Should().BeOfType<GitHubActionsGenerator>(); // Uses GH syntax
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\StellaOps.Tools.WorkflowGenerator\StellaOps.Tools.WorkflowGenerator.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.TestKit\StellaOps.TestKit.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,98 @@
|
||||
// <copyright file="WorkflowGeneratorFactoryTests.cs" company="StellaOps">
|
||||
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Tools.WorkflowGenerator.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="WorkflowGeneratorFactory"/>.
|
||||
/// </summary>
|
||||
[Trait("Category", "Unit")]
|
||||
public class WorkflowGeneratorFactoryTests
|
||||
{
|
||||
private readonly WorkflowGeneratorFactory _factory = new();
|
||||
|
||||
[Theory]
|
||||
[InlineData(CiPlatform.GitHubActions)]
|
||||
[InlineData(CiPlatform.GitLabCi)]
|
||||
[InlineData(CiPlatform.AzureDevOps)]
|
||||
[InlineData(CiPlatform.GiteaActions)]
|
||||
public void GetGenerator_SupportedPlatform_ReturnsGenerator(CiPlatform platform)
|
||||
{
|
||||
var generator = _factory.GetGenerator(platform);
|
||||
|
||||
generator.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetGenerator_GitHubActions_ReturnsGitHubActionsGenerator()
|
||||
{
|
||||
var generator = _factory.GetGenerator(CiPlatform.GitHubActions);
|
||||
|
||||
generator.Should().BeOfType<GitHubActionsGenerator>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetGenerator_GitLabCi_ReturnsGitLabCiGenerator()
|
||||
{
|
||||
var generator = _factory.GetGenerator(CiPlatform.GitLabCi);
|
||||
|
||||
generator.Should().BeOfType<GitLabCiGenerator>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetGenerator_AzureDevOps_ReturnsAzureDevOpsGenerator()
|
||||
{
|
||||
var generator = _factory.GetGenerator(CiPlatform.AzureDevOps);
|
||||
|
||||
generator.Should().BeOfType<AzureDevOpsGenerator>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetGenerator_GiteaActions_ReturnsGitHubActionsCompatibleGenerator()
|
||||
{
|
||||
// Gitea Actions is compatible with GitHub Actions syntax
|
||||
var generator = _factory.GetGenerator(CiPlatform.GiteaActions);
|
||||
|
||||
generator.Should().BeOfType<GitHubActionsGenerator>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_ValidOptions_ReturnsYaml()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
var yaml = _factory.Generate(options);
|
||||
|
||||
yaml.Should().NotBeNullOrEmpty();
|
||||
yaml.Should().Contain("name:");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_InvalidOptions_ThrowsException()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault with
|
||||
{
|
||||
Scan = new ScanConfig { ImageRef = null, ScanPath = null }
|
||||
};
|
||||
|
||||
var act = () => _factory.Generate(options);
|
||||
|
||||
act.Should().Throw<InvalidOperationException>()
|
||||
.WithMessage("*Invalid options*");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SupportedPlatforms_ContainsAllPlatforms()
|
||||
{
|
||||
var supported = _factory.SupportedPlatforms.ToList();
|
||||
|
||||
supported.Should().Contain(CiPlatform.GitHubActions);
|
||||
supported.Should().Contain(CiPlatform.GitLabCi);
|
||||
supported.Should().Contain(CiPlatform.AzureDevOps);
|
||||
supported.Should().Contain(CiPlatform.GiteaActions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
// <copyright file="WorkflowOptionsTests.cs" company="StellaOps">
|
||||
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Tools.WorkflowGenerator.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="WorkflowOptions"/>.
|
||||
/// </summary>
|
||||
[Trait("Category", "Unit")]
|
||||
public class WorkflowOptionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void Validate_ValidOptions_ReturnsValid()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
var result = options.Validate();
|
||||
|
||||
result.IsValid.Should().BeTrue();
|
||||
result.Errors.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_EmptyName_ReturnsInvalid()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault with
|
||||
{
|
||||
Name = ""
|
||||
};
|
||||
|
||||
var result = options.Validate();
|
||||
|
||||
result.IsValid.Should().BeFalse();
|
||||
result.Errors.Should().Contain(e => e.Contains("name"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_BothImageAndPath_ReturnsInvalid()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault with
|
||||
{
|
||||
Scan = new ScanConfig
|
||||
{
|
||||
ImageRef = "myimage:latest",
|
||||
ScanPath = "."
|
||||
}
|
||||
};
|
||||
|
||||
var result = options.Validate();
|
||||
|
||||
result.IsValid.Should().BeFalse();
|
||||
result.Errors.Should().Contain(e => e.Contains("Only one"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_NeitherImageNorPath_ReturnsInvalid()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault with
|
||||
{
|
||||
Scan = new ScanConfig
|
||||
{
|
||||
ImageRef = null,
|
||||
ScanPath = null
|
||||
}
|
||||
};
|
||||
|
||||
var result = options.Validate();
|
||||
|
||||
result.IsValid.Should().BeFalse();
|
||||
result.Errors.Should().Contain(e => e.Contains("Either"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GitHubActionsDefault_HasCorrectPlatform()
|
||||
{
|
||||
var options = WorkflowOptions.GitHubActionsDefault;
|
||||
|
||||
options.Platform.Should().Be(CiPlatform.GitHubActions);
|
||||
options.Runner.Should().Be("ubuntu-latest");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GitLabCiDefault_HasCorrectPlatform()
|
||||
{
|
||||
var options = WorkflowOptions.GitLabCiDefault;
|
||||
|
||||
options.Platform.Should().Be(CiPlatform.GitLabCi);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AzureDevOpsDefault_HasCorrectPlatform()
|
||||
{
|
||||
var options = WorkflowOptions.AzureDevOpsDefault;
|
||||
|
||||
options.Platform.Should().Be(CiPlatform.AzureDevOps);
|
||||
options.Runner.Should().Be("ubuntu-latest");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user