Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d37fba137e | ||
|
|
e73d79b520 | ||
|
|
b0e3e7dc74 | ||
|
|
290033680b | ||
|
|
3ea0baa147 | ||
|
|
e01aa3dce3 | ||
|
|
8bc1d78fc9 | ||
|
|
00778175fd | ||
|
|
34eff4e012 |
@@ -33,8 +33,9 @@ jobs:
|
|||||||
|
|
||||||
build-client-windows:
|
build-client-windows:
|
||||||
needs: validate-client
|
needs: validate-client
|
||||||
if: startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && inputs.build_windows == 'true')
|
# .NET can publish a self-contained Windows x64 client from Linux.
|
||||||
runs-on: windows
|
# This keeps releases independent of a Windows Gitea runner.
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -50,10 +51,14 @@ jobs:
|
|||||||
./build/build-client-package.ps1
|
./build/build-client-package.ps1
|
||||||
|
|
||||||
- name: Build release manifest for tags
|
- name: Build release manifest for tags
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
$tag = "${{ github.ref_name }}"
|
$ref = if ($env:GITHUB_REF) { $env:GITHUB_REF } else { $env:GITEA_REF }
|
||||||
|
if ($ref -notlike "refs/tags/v*") {
|
||||||
|
Write-Host "Not a version tag; skipping release manifest."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
$tag = Split-Path -Leaf $ref
|
||||||
$artifactUrl = "https://gitea.officecom.cloud/officecom/oc-sentinel/releases/download/$tag/OCSentinelClient-win-x64.zip"
|
$artifactUrl = "https://gitea.officecom.cloud/officecom/oc-sentinel/releases/download/$tag/OCSentinelClient-win-x64.zip"
|
||||||
./build/build-release-manifest.ps1 -ArtifactUrl $artifactUrl
|
./build/build-release-manifest.ps1 -ArtifactUrl $artifactUrl
|
||||||
|
|
||||||
@@ -66,3 +71,39 @@ jobs:
|
|||||||
artifacts/OCSentinelClient-win-x64.zip.sha256
|
artifacts/OCSentinelClient-win-x64.zip.sha256
|
||||||
artifacts/version.json
|
artifacts/version.json
|
||||||
if-no-files-found: warn
|
if-no-files-found: warn
|
||||||
|
|
||||||
|
- name: Publish Gitea release assets
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$ref = if ($env:GITHUB_REF) { $env:GITHUB_REF } else { $env:GITEA_REF }
|
||||||
|
if ($ref -notlike "refs/tags/v*") {
|
||||||
|
Write-Host "Not a version tag; skipping Gitea release publication."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = @{ Authorization = "token $env:GITEA_TOKEN" }
|
||||||
|
$repository = if ($env:GITEA_REPOSITORY) { $env:GITEA_REPOSITORY } else { $env:GITHUB_REPOSITORY }
|
||||||
|
$serverUrl = if ($env:GITEA_SERVER_URL) { $env:GITEA_SERVER_URL } else { $env:GITHUB_SERVER_URL }
|
||||||
|
if ([string]::IsNullOrWhiteSpace($env:GITEA_TOKEN) -or [string]::IsNullOrWhiteSpace($repository) -or [string]::IsNullOrWhiteSpace($serverUrl)) {
|
||||||
|
throw "Gitea release environment is incomplete. Expected GITEA_TOKEN, repository, and server URL."
|
||||||
|
}
|
||||||
|
$baseUrl = "$serverUrl/api/v1/repos/$repository"
|
||||||
|
$tag = Split-Path -Leaf $ref
|
||||||
|
$releaseBody = @{
|
||||||
|
tag_name = $tag
|
||||||
|
target_commitish = "${{ github.sha }}"
|
||||||
|
name = "OfficeCom Sentinel $tag"
|
||||||
|
body = "Automated OfficeCom Sentinel client release."
|
||||||
|
} | ConvertTo-Json
|
||||||
|
|
||||||
|
try {
|
||||||
|
$release = Invoke-RestMethod -Method Get -Headers $headers -Uri "$baseUrl/releases/tags/$tag"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$release = Invoke-RestMethod -Method Post -Headers $headers -ContentType "application/json" -Body $releaseBody -Uri "$baseUrl/releases"
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($file in @("artifacts/OCSentinelClient-win-x64.zip", "artifacts/OCSentinelClient-win-x64.zip.sha256", "artifacts/version.json")) {
|
||||||
|
$assetName = [System.IO.Path]::GetFileName($file)
|
||||||
|
Invoke-RestMethod -Method Post -Headers $headers -InFile $file -ContentType "application/octet-stream" -Uri "$baseUrl/releases/$($release.id)/assets?name=$assetName" | Out-Null
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"channel": "stable",
|
"channel": "stable",
|
||||||
"version": "1.2.3",
|
"version": "1.2.6",
|
||||||
"publishedAtUtc": "2026-07-16T22:58:05.1732183Z",
|
"publishedAtUtc": "2026-07-25T00:00:00Z",
|
||||||
"artifactUrl": "https://gitea.officecom.cloud/officecom/oc-sentinel/releases/download/v1.2.3/OCSentinelClient-win-x64.zip",
|
"artifactUrl": "https://gitea.officecom.cloud/officecom/oc-sentinel/releases/download/v1.2.6/OCSentinelClient-win-x64.zip",
|
||||||
"sha256": "50c7da8ff9cb96852493d4d89ad32bfd004a99fcf94b6acc70f8070ceaf737f2",
|
"sha256": "d6256f3e376701bff18d9dfd8d5825498e85fb6d94c15227828a50678693d097",
|
||||||
"minUpdaterVersion": "1.0.0"
|
"minUpdaterVersion": "1.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ internal sealed class AttackScanner
|
|||||||
{
|
{
|
||||||
SchemaVersion = "2.0",
|
SchemaVersion = "2.0",
|
||||||
MachineName = Environment.MachineName,
|
MachineName = Environment.MachineName,
|
||||||
|
NinjaOne = GetNinjaOneContext(),
|
||||||
GeneratedAtLocal = generatedAtLocal,
|
GeneratedAtLocal = generatedAtLocal,
|
||||||
GeneratedAtUtc = generatedAtUtc,
|
GeneratedAtUtc = generatedAtUtc,
|
||||||
ClientVersion = BuildMetadata.Version,
|
ClientVersion = BuildMetadata.Version,
|
||||||
@@ -89,6 +90,24 @@ internal sealed class AttackScanner
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static NinjaOneContext GetNinjaOneContext()
|
||||||
|
{
|
||||||
|
return new NinjaOneContext
|
||||||
|
{
|
||||||
|
OrganizationId = ReadEnvironmentVariable("NINJA_ORGANIZATION_ID"),
|
||||||
|
OrganizationName = ReadEnvironmentVariable("NINJA_ORGANIZATION_NAME"),
|
||||||
|
MachineId = ReadEnvironmentVariable("NINJA_AGENT_MACHINE_ID"),
|
||||||
|
NodeId = ReadEnvironmentVariable("NINJA_AGENT_NODE_ID"),
|
||||||
|
LocationId = ReadEnvironmentVariable("NINJA_LOCATION_ID"),
|
||||||
|
LocationName = ReadEnvironmentVariable("NINJA_LOCATION_NAME")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ReadEnvironmentVariable(string name)
|
||||||
|
{
|
||||||
|
return Environment.GetEnvironmentVariable(name)?.Trim() ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
private static ScannerConfiguration LoadConfiguration(ScanOptions options)
|
private static ScannerConfiguration LoadConfiguration(ScanOptions options)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(options.ConfigPath))
|
if (string.IsNullOrWhiteSpace(options.ConfigPath))
|
||||||
|
|||||||
@@ -5,7 +5,10 @@ internal static class ScanAndUploadCommand
|
|||||||
public static int Execute(string[] args)
|
public static int Execute(string[] args)
|
||||||
{
|
{
|
||||||
string outputPath = @"C:\ProgramData\OCSentinel\reports\latest.json";
|
string outputPath = @"C:\ProgramData\OCSentinel\reports\latest.json";
|
||||||
|
string? clientConfigPath = null;
|
||||||
|
string? secretPath = null;
|
||||||
bool hasOutput = false;
|
bool hasOutput = false;
|
||||||
|
var scanArgs = new List<string>();
|
||||||
|
|
||||||
for (int i = 0; i < args.Length; i++)
|
for (int i = 0; i < args.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -13,11 +16,26 @@ internal static class ScanAndUploadCommand
|
|||||||
{
|
{
|
||||||
outputPath = args[i + 1];
|
outputPath = args[i + 1];
|
||||||
hasOutput = true;
|
hasOutput = true;
|
||||||
break;
|
scanArgs.Add(args[i]);
|
||||||
|
scanArgs.Add(args[++i]);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.Equals(args[i], "--client-config", StringComparison.OrdinalIgnoreCase) && i + 1 < args.Length)
|
||||||
|
{
|
||||||
|
clientConfigPath = args[++i];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(args[i], "--secret-path", StringComparison.OrdinalIgnoreCase) && i + 1 < args.Length)
|
||||||
|
{
|
||||||
|
secretPath = args[++i];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
scanArgs.Add(args[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<string> scanArgs = [.. args];
|
|
||||||
if (!hasOutput)
|
if (!hasOutput)
|
||||||
{
|
{
|
||||||
scanArgs.Add("--output");
|
scanArgs.Add("--output");
|
||||||
@@ -36,6 +54,16 @@ internal static class ScanAndUploadCommand
|
|||||||
outputPath
|
outputPath
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(clientConfigPath))
|
||||||
|
{
|
||||||
|
uploadArgs.AddRange(["--client-config", clientConfigPath]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(secretPath))
|
||||||
|
{
|
||||||
|
uploadArgs.AddRange(["--secret-path", secretPath]);
|
||||||
|
}
|
||||||
|
|
||||||
return UploadCommand.Execute([.. uploadArgs]);
|
return UploadCommand.Execute([.. uploadArgs]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ internal sealed record ScanResult
|
|||||||
|
|
||||||
public string MachineName { get; init; } = string.Empty;
|
public string MachineName { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
// Populated only for runs launched by NinjaOne automation.
|
||||||
|
public NinjaOneContext NinjaOne { get; init; } = new();
|
||||||
|
|
||||||
public DateTimeOffset GeneratedAtLocal { get; init; }
|
public DateTimeOffset GeneratedAtLocal { get; init; }
|
||||||
|
|
||||||
public DateTimeOffset GeneratedAtUtc { get; init; }
|
public DateTimeOffset GeneratedAtUtc { get; init; }
|
||||||
@@ -111,6 +114,21 @@ internal sealed record ScanResult
|
|||||||
public List<string> Errors { get; init; } = [];
|
public List<string> Errors { get; init; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal sealed record NinjaOneContext
|
||||||
|
{
|
||||||
|
public string OrganizationId { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
public string OrganizationName { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
public string MachineId { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
public string NodeId { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
public string LocationId { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
public string LocationName { get; init; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
internal sealed record ScanRuntimeMetadata
|
internal sealed record ScanRuntimeMetadata
|
||||||
{
|
{
|
||||||
public DateTimeOffset StartedAtUtc { get; init; }
|
public DateTimeOffset StartedAtUtc { get; init; }
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<RootNamespace>OCSentinelCli</RootNamespace>
|
<RootNamespace>OCSentinelCli</RootNamespace>
|
||||||
<Product>OfficeCom Sentinel</Product>
|
<Product>OfficeCom Sentinel</Product>
|
||||||
<Company>OfficeCom</Company>
|
<Company>OfficeCom</Company>
|
||||||
<Version>1.2.4</Version>
|
<Version>1.2.7</Version>
|
||||||
<AssemblyVersion>1.2.3.0</AssemblyVersion>
|
<AssemblyVersion>1.2.3.0</AssemblyVersion>
|
||||||
<FileVersion>1.2.3.0</FileVersion>
|
<FileVersion>1.2.3.0</FileVersion>
|
||||||
<InformationalVersion>1.2.3</InformationalVersion>
|
<InformationalVersion>1.2.3</InformationalVersion>
|
||||||
|
|||||||
Reference in New Issue
Block a user