Rename Concelier Source modules to Connector
Some checks failed
Build Test Deploy / build-test (push) Has been cancelled
Build Test Deploy / authority-container (push) Has been cancelled
Build Test Deploy / docs (push) Has been cancelled
Build Test Deploy / deploy (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Build Test Deploy / build-test (push) Has been cancelled
Build Test Deploy / authority-container (push) Has been cancelled
Build Test Deploy / docs (push) Has been cancelled
Build Test Deploy / deploy (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Acsc.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Connector options governing ACSC feed access and retry behaviour.
|
||||
/// </summary>
|
||||
public sealed class AcscOptions
|
||||
{
|
||||
public const string HttpClientName = "acsc";
|
||||
|
||||
private static readonly TimeSpan DefaultRequestTimeout = TimeSpan.FromSeconds(45);
|
||||
private static readonly TimeSpan DefaultFailureBackoff = TimeSpan.FromMinutes(5);
|
||||
private static readonly TimeSpan DefaultInitialBackfill = TimeSpan.FromDays(120);
|
||||
|
||||
public AcscOptions()
|
||||
{
|
||||
Feeds = new List<AcscFeedOptions>
|
||||
{
|
||||
new() { Slug = "alerts", RelativePath = "/acsc/view-all-content/alerts/rss" },
|
||||
new() { Slug = "advisories", RelativePath = "/acsc/view-all-content/advisories/rss" },
|
||||
new() { Slug = "news", RelativePath = "/acsc/view-all-content/news/rss", Enabled = false },
|
||||
new() { Slug = "publications", RelativePath = "/acsc/view-all-content/publications/rss", Enabled = false },
|
||||
new() { Slug = "threats", RelativePath = "/acsc/view-all-content/threats/rss", Enabled = false },
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base endpoint for direct ACSC fetches.
|
||||
/// </summary>
|
||||
public Uri BaseEndpoint { get; set; } = new("https://www.cyber.gov.au/", UriKind.Absolute);
|
||||
|
||||
/// <summary>
|
||||
/// Optional relay endpoint used when Akamai terminates direct HTTP/2 connections.
|
||||
/// </summary>
|
||||
public Uri? RelayEndpoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default mode when no preference has been captured in connector state. When <c>true</c>, the relay will be preferred for initial fetches.
|
||||
/// </summary>
|
||||
public bool PreferRelayByDefault { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If enabled, the connector may switch to the relay endpoint when direct fetches fail.
|
||||
/// </summary>
|
||||
public bool EnableRelayFallback { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If set, the connector will always use the relay endpoint and skip direct attempts.
|
||||
/// </summary>
|
||||
public bool ForceRelay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timeout applied to fetch requests (overrides HttpClient default).
|
||||
/// </summary>
|
||||
public TimeSpan RequestTimeout { get; set; } = DefaultRequestTimeout;
|
||||
|
||||
/// <summary>
|
||||
/// Backoff applied when marking fetch failures.
|
||||
/// </summary>
|
||||
public TimeSpan FailureBackoff { get; set; } = DefaultFailureBackoff;
|
||||
|
||||
/// <summary>
|
||||
/// Look-back period used when deriving initial published cursors.
|
||||
/// </summary>
|
||||
public TimeSpan InitialBackfill { get; set; } = DefaultInitialBackfill;
|
||||
|
||||
/// <summary>
|
||||
/// User-agent header sent with outbound requests.
|
||||
/// </summary>
|
||||
public string UserAgent { get; set; } = "StellaOps/Concelier (+https://stella-ops.org)";
|
||||
|
||||
/// <summary>
|
||||
/// RSS feeds requested during fetch.
|
||||
/// </summary>
|
||||
public IList<AcscFeedOptions> Feeds { get; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP version policy requested for outbound requests.
|
||||
/// </summary>
|
||||
public HttpVersionPolicy VersionPolicy { get; set; } = HttpVersionPolicy.RequestVersionOrLower;
|
||||
|
||||
/// <summary>
|
||||
/// Default HTTP version requested when connecting to ACSC (defaults to HTTP/2 but allows downgrade).
|
||||
/// </summary>
|
||||
public Version RequestVersion { get; set; } = HttpVersion.Version20;
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (BaseEndpoint is null || !BaseEndpoint.IsAbsoluteUri)
|
||||
{
|
||||
throw new InvalidOperationException("ACSC BaseEndpoint must be an absolute URI.");
|
||||
}
|
||||
|
||||
if (!BaseEndpoint.AbsoluteUri.EndsWith("/", StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException("ACSC BaseEndpoint must include a trailing slash.");
|
||||
}
|
||||
|
||||
if (RelayEndpoint is not null && !RelayEndpoint.IsAbsoluteUri)
|
||||
{
|
||||
throw new InvalidOperationException("ACSC RelayEndpoint must be an absolute URI when specified.");
|
||||
}
|
||||
|
||||
if (RelayEndpoint is not null && !RelayEndpoint.AbsoluteUri.EndsWith("/", StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException("ACSC RelayEndpoint must include a trailing slash when specified.");
|
||||
}
|
||||
|
||||
if (RequestTimeout <= TimeSpan.Zero)
|
||||
{
|
||||
throw new InvalidOperationException("ACSC RequestTimeout must be positive.");
|
||||
}
|
||||
|
||||
if (FailureBackoff < TimeSpan.Zero)
|
||||
{
|
||||
throw new InvalidOperationException("ACSC FailureBackoff cannot be negative.");
|
||||
}
|
||||
|
||||
if (InitialBackfill <= TimeSpan.Zero)
|
||||
{
|
||||
throw new InvalidOperationException("ACSC InitialBackfill must be positive.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(UserAgent))
|
||||
{
|
||||
throw new InvalidOperationException("ACSC UserAgent cannot be empty.");
|
||||
}
|
||||
|
||||
if (Feeds.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("At least one ACSC feed must be configured.");
|
||||
}
|
||||
|
||||
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
for (var i = 0; i < Feeds.Count; i++)
|
||||
{
|
||||
var feed = Feeds[i];
|
||||
feed.Validate(i);
|
||||
|
||||
if (!feed.Enabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!seen.Add(feed.Slug))
|
||||
{
|
||||
throw new InvalidOperationException($"Duplicate ACSC feed slug '{feed.Slug}' detected. Slugs must be unique (case-insensitive).");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user