Skip to content

Commit 9b1fa70

Browse files
Merge a1275f6 into 38354fb
2 parents 38354fb + a1275f6 commit 9b1fa70

11 files changed

Lines changed: 2479 additions & 553 deletions

File tree

.claude/settings.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(git fetch:*)",
5+
"Bash(git checkout:*)"
6+
]
7+
}
8+
}

.github/workflows/keyfactor-bootstrap-workflow-v3.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,17 @@ on:
1111

1212
jobs:
1313
call-starter-workflow:
14-
uses: keyfactor/actions/.github/workflows/starter.yml@v3.1.2
14+
uses: keyfactor/actions/.github/workflows/starter.yml@v5
15+
with:
16+
command_token_url: ${{ vars.COMMAND_TOKEN_URL }}
17+
command_hostname: ${{ vars.COMMAND_HOSTNAME }}
18+
command_base_api_path: ${{ vars.COMMAND_API_PATH }}
1519
secrets:
1620
token: ${{ secrets.V2BUILDTOKEN}}
17-
APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}}
1821
gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }}
1922
gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }}
2023
scan_token: ${{ secrets.SAST_TOKEN }}
24+
entra_username: ${{ secrets.DOCTOOL_ENTRA_USERNAME }}
25+
entra_password: ${{ secrets.DOCTOOL_ENTRA_PASSWD }}
26+
command_client_id: ${{ secrets.COMMAND_CLIENT_ID }}
27+
command_client_secret: ${{ secrets.COMMAND_CLIENT_SECRET }}

README.md

Lines changed: 334 additions & 229 deletions
Large diffs are not rendered by default.

cscglobal-caplugin/CSCGlobalCAPlugin.cs

Lines changed: 1102 additions & 150 deletions
Large diffs are not rendered by default.

cscglobal-caplugin/CSCGlobalCAPlugin.csproj

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
<PropertyGroup>
55
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
6-
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
6+
<TargetFrameworks>net10.0</TargetFrameworks>
77
<RootNamespace>Keyfactor.Extensions.CAPlugin.CSCGlobal</RootNamespace>
88
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
99
<ImplicitUsings>enable</ImplicitUsings>
@@ -16,24 +16,16 @@
1616
<Exec Condition="'$(Configuration)'=='DebugAndPush'" Command="PowerShell -ExecutionPolicy Bypass -File &quot;C:\Users\mkachkaev\source\repos\scripts\SyncScriptCSC.ps1&quot;&#xA;" />
1717
</Target>
1818

19-
20-
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
21-
<PackageReference Include="Keyfactor.AnyGateway.IAnyCAPlugin" Version="3.1.0" />
19+
<ItemGroup Condition="'$(TargetFramework)' == 'net10.0'">
20+
<PackageReference Include="Keyfactor.AnyGateway.IAnyCAPlugin" Version="3.3.0" />
2221
<PackageReference Include="Keyfactor.PKI" Version="8.1.1" />
2322
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
2423
</ItemGroup>
2524

26-
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
27-
<PackageReference Include="Keyfactor.AnyGateway.IAnyCAPlugin" Version="3.1.0" />
28-
<PackageReference Include="Keyfactor.PKI" Version="6.3.0" />
29-
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
30-
</ItemGroup>
31-
32-
3325
<ItemGroup>
3426
<None Update="manifest.json">
3527
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
3628
</None>
3729
</ItemGroup>
3830

39-
</Project>
31+
</Project>

cscglobal-caplugin/Client/CscGlobalClient.cs

Lines changed: 216 additions & 53 deletions
Large diffs are not rendered by default.

cscglobal-caplugin/Constants.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ namespace Keyfactor.Extensions.CAPlugin.CSCGlobal;
99

1010
public class Constants
1111
{
12+
public static string Enabled = "Enabled";
1213
public static string CscGlobalUrl = "CscGlobalUrl";
1314
public static string CscGlobalApiKey = "ApiKey";
1415
public static string BearerToken = "BearerToken";
1516
public static string DefaultPageSize = "DefaultPageSize";
16-
public static string TemplateSync = "TemplateSync";
1717
public static string SyncFilterDays = "SyncFilterDays";
18+
public static string RenewalWindowDays = "RenewalWindowDays";
19+
public static string DcvPollTimeoutSeconds = "DcvPollTimeoutSeconds";
1820
}
1921

2022
public class ProductIDs
@@ -26,8 +28,8 @@ public class ProductIDs
2628
"CSC TrustedSecure UC Certificate",
2729
"CSC TrustedSecure Premium Wildcard Certificate",
2830
"CSC TrustedSecure Domain Validated SSL",
29-
"CSC TrustedSecure Domain Validated Wildcard SSL",
30-
"CSC TrustedSecure Domain Validated UC Certificate"
31+
"CSC Trusted Secure Domain Validated Wildcard SSL",
32+
"CSC Trusted Secure Domain Validated UC Certificate"
3133
};
3234
}
3335

cscglobal-caplugin/FlowLogger.cs

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
// Copyright 2021 Keyfactor
2+
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
3+
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4+
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
5+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
6+
// and limitations under the License.
7+
8+
using System.Diagnostics;
9+
using System.Text;
10+
using Microsoft.Extensions.Logging;
11+
12+
namespace Keyfactor.Extensions.CAPlugin.CSCGlobal;
13+
14+
public enum FlowStepStatus
15+
{
16+
Success,
17+
Failed,
18+
Skipped,
19+
InProgress
20+
}
21+
22+
public class FlowStep
23+
{
24+
public string Name { get; set; }
25+
public FlowStepStatus Status { get; set; }
26+
public string Detail { get; set; }
27+
public long ElapsedMs { get; set; }
28+
public List<FlowStep> Children { get; } = new();
29+
}
30+
31+
/// <summary>
32+
/// Tracks high-level operation flow and renders a visual step diagram to Trace logs.
33+
/// Usage:
34+
/// using var flow = new FlowLogger(logger, "Enroll-New");
35+
/// flow.Step("ParseCSR");
36+
/// flow.Step("ValidateCSR", () => { ... });
37+
/// flow.Fail("CreateOrder", "API returned 400");
38+
/// // flow renders automatically on Dispose
39+
/// </summary>
40+
public sealed class FlowLogger : IDisposable
41+
{
42+
private readonly ILogger _logger;
43+
private readonly string _flowName;
44+
private readonly Stopwatch _totalTimer;
45+
private readonly List<FlowStep> _steps = new();
46+
private FlowStep _currentParent;
47+
private bool _disposed;
48+
49+
public FlowLogger(ILogger logger, string flowName)
50+
{
51+
_logger = logger;
52+
_flowName = flowName;
53+
_totalTimer = Stopwatch.StartNew();
54+
_logger.LogTrace("===== FLOW START: {FlowName} =====", _flowName);
55+
}
56+
57+
/// <summary>Record a completed step.</summary>
58+
public FlowLogger Step(string name, string detail = null)
59+
{
60+
var step = new FlowStep { Name = name, Status = FlowStepStatus.Success, Detail = detail };
61+
AddStep(step);
62+
_logger.LogTrace(" [{FlowName}] {StepName} ... OK{Detail}",
63+
_flowName, name, detail != null ? $" ({detail})" : "");
64+
return this;
65+
}
66+
67+
/// <summary>Record a step that executes an action and times it.</summary>
68+
public FlowLogger Step(string name, Action action, string detail = null)
69+
{
70+
var sw = Stopwatch.StartNew();
71+
var step = new FlowStep { Name = name, Detail = detail };
72+
try
73+
{
74+
_logger.LogTrace(" [{FlowName}] {StepName} ...", _flowName, name);
75+
action();
76+
sw.Stop();
77+
step.Status = FlowStepStatus.Success;
78+
step.ElapsedMs = sw.ElapsedMilliseconds;
79+
AddStep(step);
80+
_logger.LogTrace(" [{FlowName}] {StepName} ... OK ({Elapsed}ms){Detail}",
81+
_flowName, name, sw.ElapsedMilliseconds, detail != null ? $" {detail}" : "");
82+
}
83+
catch (Exception ex)
84+
{
85+
sw.Stop();
86+
step.Status = FlowStepStatus.Failed;
87+
step.ElapsedMs = sw.ElapsedMilliseconds;
88+
step.Detail = ex.Message;
89+
AddStep(step);
90+
_logger.LogTrace(" [{FlowName}] {StepName} ... FAILED ({Elapsed}ms): {Error}",
91+
_flowName, name, sw.ElapsedMilliseconds, ex.Message);
92+
throw;
93+
}
94+
return this;
95+
}
96+
97+
/// <summary>Record an async step that executes and times it.</summary>
98+
public async Task<FlowLogger> StepAsync(string name, Func<Task> action, string detail = null)
99+
{
100+
var sw = Stopwatch.StartNew();
101+
var step = new FlowStep { Name = name, Detail = detail };
102+
try
103+
{
104+
_logger.LogTrace(" [{FlowName}] {StepName} ...", _flowName, name);
105+
await action();
106+
sw.Stop();
107+
step.Status = FlowStepStatus.Success;
108+
step.ElapsedMs = sw.ElapsedMilliseconds;
109+
AddStep(step);
110+
_logger.LogTrace(" [{FlowName}] {StepName} ... OK ({Elapsed}ms){Detail}",
111+
_flowName, name, sw.ElapsedMilliseconds, detail != null ? $" {detail}" : "");
112+
}
113+
catch (Exception ex)
114+
{
115+
sw.Stop();
116+
step.Status = FlowStepStatus.Failed;
117+
step.ElapsedMs = sw.ElapsedMilliseconds;
118+
step.Detail = ex.Message;
119+
AddStep(step);
120+
_logger.LogTrace(" [{FlowName}] {StepName} ... FAILED ({Elapsed}ms): {Error}",
121+
_flowName, name, sw.ElapsedMilliseconds, ex.Message);
122+
throw;
123+
}
124+
return this;
125+
}
126+
127+
/// <summary>Record a failed step without throwing.</summary>
128+
public FlowLogger Fail(string name, string reason = null)
129+
{
130+
var step = new FlowStep { Name = name, Status = FlowStepStatus.Failed, Detail = reason };
131+
AddStep(step);
132+
_logger.LogTrace(" [{FlowName}] {StepName} ... FAILED{Reason}",
133+
_flowName, name, reason != null ? $": {reason}" : "");
134+
return this;
135+
}
136+
137+
/// <summary>Record a skipped step.</summary>
138+
public FlowLogger Skip(string name, string reason = null)
139+
{
140+
var step = new FlowStep { Name = name, Status = FlowStepStatus.Skipped, Detail = reason };
141+
AddStep(step);
142+
_logger.LogTrace(" [{FlowName}] {StepName} ... SKIPPED{Reason}",
143+
_flowName, name, reason != null ? $": {reason}" : "");
144+
return this;
145+
}
146+
147+
/// <summary>Start a branch (group of child steps).</summary>
148+
public FlowLogger Branch(string name)
149+
{
150+
var step = new FlowStep { Name = name, Status = FlowStepStatus.InProgress };
151+
AddStep(step);
152+
_currentParent = step;
153+
_logger.LogTrace(" [{FlowName}] >> Branch: {BranchName}", _flowName, name);
154+
return this;
155+
}
156+
157+
/// <summary>End the current branch.</summary>
158+
public FlowLogger EndBranch()
159+
{
160+
_currentParent = null;
161+
return this;
162+
}
163+
164+
private void AddStep(FlowStep step)
165+
{
166+
if (_currentParent != null)
167+
_currentParent.Children.Add(step);
168+
else
169+
_steps.Add(step);
170+
}
171+
172+
/// <summary>Render the visual flow diagram to Trace log.</summary>
173+
private string RenderFlow()
174+
{
175+
var sb = new StringBuilder();
176+
sb.AppendLine();
177+
sb.AppendLine($" ===== FLOW: {_flowName} ({_totalTimer.ElapsedMilliseconds}ms total) =====");
178+
sb.AppendLine();
179+
180+
for (var i = 0; i < _steps.Count; i++)
181+
{
182+
var step = _steps[i];
183+
var icon = GetStatusIcon(step.Status);
184+
var elapsed = step.ElapsedMs > 0 ? $" ({step.ElapsedMs}ms)" : "";
185+
var detail = !string.IsNullOrEmpty(step.Detail) ? $" [{step.Detail}]" : "";
186+
187+
sb.AppendLine($" {icon} {step.Name}{elapsed}{detail}");
188+
189+
// Render children (branch)
190+
if (step.Children.Count > 0)
191+
{
192+
for (var j = 0; j < step.Children.Count; j++)
193+
{
194+
var child = step.Children[j];
195+
var childIcon = GetStatusIcon(child.Status);
196+
var childElapsed = child.ElapsedMs > 0 ? $" ({child.ElapsedMs}ms)" : "";
197+
var childDetail = !string.IsNullOrEmpty(child.Detail) ? $" [{child.Detail}]" : "";
198+
var connector = j < step.Children.Count - 1 ? "| " : " ";
199+
sb.AppendLine($" |");
200+
sb.AppendLine($" +-- {childIcon} {child.Name}{childElapsed}{childDetail}");
201+
}
202+
}
203+
204+
// Connector between top-level steps
205+
if (i < _steps.Count - 1)
206+
{
207+
sb.AppendLine(" |");
208+
sb.AppendLine(" v");
209+
}
210+
}
211+
212+
sb.AppendLine();
213+
214+
// Final status line
215+
var finalStatus = _steps.Count > 0 && _steps.Last().Status == FlowStepStatus.Failed
216+
? "FAILED" : _steps.Any(s => s.Status == FlowStepStatus.Failed) ? "PARTIAL FAILURE" : "SUCCESS";
217+
sb.AppendLine($" ===== FLOW RESULT: {finalStatus} =====");
218+
219+
return sb.ToString();
220+
}
221+
222+
private static string GetStatusIcon(FlowStepStatus status)
223+
{
224+
return status switch
225+
{
226+
FlowStepStatus.Success => "[OK]",
227+
FlowStepStatus.Failed => "[FAIL]",
228+
FlowStepStatus.Skipped => "[SKIP]",
229+
FlowStepStatus.InProgress => "[...]",
230+
_ => "[?]"
231+
};
232+
}
233+
234+
public void Dispose()
235+
{
236+
if (_disposed) return;
237+
_disposed = true;
238+
_totalTimer.Stop();
239+
_logger.LogTrace(RenderFlow());
240+
}
241+
}

0 commit comments

Comments
 (0)