feat: Add Go module and workspace test fixtures

- Created expected JSON files for Go modules and workspaces.
- Added go.mod and go.sum files for example projects.
- Implemented private module structure with expected JSON output.
- Introduced vendored dependencies with corresponding expected JSON.
- Developed PostgresGraphJobStore for managing graph jobs.
- Established SQL migration scripts for graph jobs schema.
- Implemented GraphJobRepository for CRUD operations on graph jobs.
- Created IGraphJobRepository interface for repository abstraction.
- Added unit tests for GraphJobRepository to ensure functionality.
This commit is contained in:
StellaOps Bot
2025-12-06 20:04:03 +02:00
parent a6f1406509
commit 05597616d6
178 changed files with 12022 additions and 4545 deletions

View File

@@ -72,4 +72,71 @@ public sealed class PackRunSimulationEngineTests
Assert.True(evidence.RequiresRuntimeValue);
});
}
[Fact]
public void Simulate_LoopStep_SetsWillIterateStatus()
{
var manifest = TestManifests.Load(TestManifests.Loop);
var planner = new TaskPackPlanner();
var inputs = new Dictionary<string, JsonNode?>
{
["targets"] = new JsonArray { "a", "b", "c" }
};
var result = planner.Plan(manifest, inputs);
Assert.Empty(result.Errors);
Assert.NotNull(result.Plan);
var engine = new PackRunSimulationEngine();
var simResult = engine.Simulate(result.Plan);
var loopStep = simResult.Steps.Single(s => s.Kind == PackRunStepKind.Loop);
Assert.Equal(PackRunSimulationStatus.WillIterate, loopStep.Status);
Assert.Equal("process-loop", loopStep.Id);
Assert.NotNull(loopStep.LoopInfo);
Assert.Equal("target", loopStep.LoopInfo.Iterator);
Assert.Equal("idx", loopStep.LoopInfo.Index);
Assert.Equal(100, loopStep.LoopInfo.MaxIterations);
Assert.Equal("collect", loopStep.LoopInfo.AggregationMode);
}
[Fact]
public void Simulate_ConditionalStep_SetsWillBranchStatus()
{
var manifest = TestManifests.Load(TestManifests.Conditional);
var planner = new TaskPackPlanner();
var inputs = new Dictionary<string, JsonNode?>
{
["environment"] = JsonValue.Create("production")
};
var result = planner.Plan(manifest, inputs);
Assert.Empty(result.Errors);
Assert.NotNull(result.Plan);
var engine = new PackRunSimulationEngine();
var simResult = engine.Simulate(result.Plan);
var conditionalStep = simResult.Steps.Single(s => s.Kind == PackRunStepKind.Conditional);
Assert.Equal(PackRunSimulationStatus.WillBranch, conditionalStep.Status);
Assert.Equal("env-branch", conditionalStep.Id);
Assert.NotNull(conditionalStep.ConditionalInfo);
Assert.Equal(2, conditionalStep.ConditionalInfo.Branches.Count);
Assert.True(conditionalStep.ConditionalInfo.OutputUnion);
}
[Fact]
public void Simulate_PolicyGateStep_HasPolicyInfo()
{
var manifest = TestManifests.Load(TestManifests.PolicyGate);
var planner = new TaskPackPlanner();
var plan = planner.Plan(manifest).Plan!;
var engine = new PackRunSimulationEngine();
var result = engine.Simulate(plan);
var policyStep = result.Steps.Single(s => s.Kind == PackRunStepKind.GatePolicy);
Assert.Equal(PackRunSimulationStatus.RequiresPolicy, policyStep.Status);
Assert.NotNull(policyStep.PolicyInfo);
Assert.Equal("security-hold", policyStep.PolicyInfo.PolicyId);
Assert.Equal("abort", policyStep.PolicyInfo.FailureAction);
}
}

View File

@@ -1,8 +1,8 @@
using System.Text.Json.Nodes;
using StellaOps.TaskRunner.Core.TaskPacks;
namespace StellaOps.TaskRunner.Tests;
using System.Text.Json.Nodes;
using StellaOps.TaskRunner.Core.TaskPacks;
namespace StellaOps.TaskRunner.Tests;
internal static partial class TestManifests
{
public static TaskPackManifest Load(string yaml)
@@ -10,15 +10,15 @@ internal static partial class TestManifests
var loader = new TaskPackManifestLoader();
return loader.Deserialize(yaml);
}
public const string Sample = """
apiVersion: stellaops.io/pack.v1
kind: TaskPack
metadata:
name: sample-pack
version: 1.0.0
description: Sample pack for planner tests
tags: [tests]
public const string Sample = """
apiVersion: stellaops.io/pack.v1
kind: TaskPack
metadata:
name: sample-pack
version: 1.0.0
description: Sample pack for planner tests
tags: [tests]
spec:
inputs:
- name: dryRun
@@ -40,23 +40,23 @@ spec:
grants: ["packs.approve"]
steps:
- id: plan-step
name: Plan
run:
uses: builtin:plan
with:
dryRun: "{{ inputs.dryRun }}"
- id: approval
gate:
approval:
id: security-review
message: "Security approval required."
- id: apply-step
when: "{{ not inputs.dryRun }}"
run:
uses: builtin:apply
""";
public const string RequiredInput = """
name: Plan
run:
uses: builtin:plan
with:
dryRun: "{{ inputs.dryRun }}"
- id: approval
gate:
approval:
id: security-review
message: "Security approval required."
- id: apply-step
when: "{{ not inputs.dryRun }}"
run:
uses: builtin:apply
""";
public const string RequiredInput = """
apiVersion: stellaops.io/pack.v1
kind: TaskPack
metadata:
@@ -86,11 +86,11 @@ spec:
""";
public const string StepReference = """
apiVersion: stellaops.io/pack.v1
kind: TaskPack
metadata:
name: step-ref-pack
version: 1.0.0
apiVersion: stellaops.io/pack.v1
kind: TaskPack
metadata:
name: step-ref-pack
version: 1.0.0
spec:
sandbox:
mode: sealed
@@ -107,18 +107,18 @@ spec:
run:
uses: builtin:prepare
- id: consume
run:
uses: builtin:consume
with:
sourceSummary: "{{ steps.prepare.outputs.summary }}"
""";
public const string Map = """
apiVersion: stellaops.io/pack.v1
kind: TaskPack
metadata:
name: map-pack
version: 1.0.0
run:
uses: builtin:consume
with:
sourceSummary: "{{ steps.prepare.outputs.summary }}"
""";
public const string Map = """
apiVersion: stellaops.io/pack.v1
kind: TaskPack
metadata:
name: map-pack
version: 1.0.0
spec:
inputs:
- name: targets
@@ -139,19 +139,19 @@ spec:
map:
items: "{{ inputs.targets }}"
step:
id: echo-step
run:
uses: builtin:echo
with:
target: "{{ item }}"
""";
public const string Secret = """
apiVersion: stellaops.io/pack.v1
kind: TaskPack
metadata:
name: secret-pack
version: 1.0.0
id: echo-step
run:
uses: builtin:echo
with:
target: "{{ item }}"
""";
public const string Secret = """
apiVersion: stellaops.io/pack.v1
kind: TaskPack
metadata:
name: secret-pack
version: 1.0.0
spec:
secrets:
- name: apiKey
@@ -172,15 +172,15 @@ spec:
run:
uses: builtin:http
with:
token: "{{ secrets.apiKey }}"
""";
public const string Output = """
apiVersion: stellaops.io/pack.v1
kind: TaskPack
metadata:
name: output-pack
version: 1.0.0
token: "{{ secrets.apiKey }}"
""";
public const string Output = """
apiVersion: stellaops.io/pack.v1
kind: TaskPack
metadata:
name: output-pack
version: 1.0.0
spec:
sandbox:
mode: sealed
@@ -197,9 +197,9 @@ spec:
run:
uses: builtin:generate
outputs:
- name: bundlePath
type: file
path: artifacts/report.txt
- name: bundlePath
type: file
path: artifacts/report.txt
- name: evidenceModel
type: object
expression: "{{ steps.generate.outputs.evidence }}"
@@ -379,4 +379,87 @@ spec:
with:
url: "{{ inputs.targetUrl }}"
""";
public const string Loop = """
apiVersion: stellaops.io/pack.v1
kind: TaskPack
metadata:
name: loop-pack
version: 1.0.0
spec:
inputs:
- name: targets
type: array
required: true
sandbox:
mode: sealed
egressAllowlist: []
cpuLimitMillicores: 100
memoryLimitMiB: 128
quotaSeconds: 60
slo:
runP95Seconds: 300
approvalP95Seconds: 900
maxQueueDepth: 100
steps:
- id: process-loop
loop:
items: "{{ inputs.targets }}"
iterator: target
index: idx
maxIterations: 100
aggregation: collect
steps:
- id: process-item
run:
uses: builtin:process
""";
public const string Conditional = """
apiVersion: stellaops.io/pack.v1
kind: TaskPack
metadata:
name: conditional-pack
version: 1.0.0
spec:
inputs:
- name: environment
type: string
required: true
sandbox:
mode: sealed
egressAllowlist: []
cpuLimitMillicores: 100
memoryLimitMiB: 128
quotaSeconds: 60
slo:
runP95Seconds: 300
approvalP95Seconds: 900
maxQueueDepth: 100
steps:
- id: env-branch
conditional:
branches:
- condition: "{{ inputs.environment == 'production' }}"
steps:
- id: deploy-prod
run:
uses: builtin:deploy
with:
target: production
- condition: "{{ inputs.environment == 'staging' }}"
steps:
- id: deploy-staging
run:
uses: builtin:deploy
with:
target: staging
else:
- id: deploy-dev
run:
uses: builtin:deploy
with:
target: development
outputUnion: true
""";
}