Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
b38b524
Add deprecated detection rules as sibling nav page
Mpdreamz Apr 22, 2026
996386e
Highlight parent nav item when current page has no nav link
Mpdreamz Apr 22, 2026
9042a9a
style: run prettier on pages-nav.ts
Mpdreamz Apr 24, 2026
fb87edf
Merge branch 'main' into feature/deprecated-detection-rules
Mpdreamz Apr 24, 2026
f915644
Bump OpenTelemetry packages to 1.15.x to address moderate CVEs
Mpdreamz Apr 24, 2026
256f308
Swap Tomlet with Tomlyn, add tests (#3214)
cotti Apr 30, 2026
9141470
Use defensive TryGetValue in ReadTactic to match surrounding patterns
cotti Apr 30, 2026
ba70441
Merge branch 'main' into feature/deprecated-detection-rules
Mpdreamz Apr 30, 2026
659ba2c
Merge branch 'main' into feature/deprecated-detection-rules
Mpdreamz Apr 30, 2026
6af5b68
Cache cross-link index across serve hot reloads (#3219)
theletterf Apr 30, 2026
74e4f45
[Automation] Bump product version numbers (#3215)
elastic-observability-automation[bot] Apr 30, 2026
d9adb0d
chore: Update config/versions.yml edot-collector 9.3.4 (#3222)
elastic-observability-automation[bot] Apr 30, 2026
2bad508
[Changelog] Strip dash from title prefix (#3226)
lcawl May 4, 2026
39ad15f
Add description-visibility option to changelog directive (#3224)
lcawl May 4, 2026
5f0a9f2
Add --report option for changelog add command (#3227)
lcawl May 4, 2026
0a05ecc
Bump release-drafter/release-drafter from 7.2.0 to 7.2.1 (#3230)
dependabot[bot] May 4, 2026
950ebe9
Retry S3 link registry fetch on transient errors in match command (#3…
Mpdreamz May 4, 2026
7abe8e1
[Changelog] Fix missing links in changelog directive and render comma…
lcawl May 4, 2026
4067128
[Stack 9.4.0] assembler + version bump (#3070)
shainaraskas May 5, 2026
eaa2bc8
fix(cross-links): use codex path shape in fallback error URL (#3174)
theletterf May 5, 2026
780c468
Bump AWSSDK.S3 from 4.0.21.2 to 4.0.22.1 (#3240)
dependabot[bot] May 5, 2026
8b540c4
Bump Elastic.Clients.Elasticsearch from 9.3.5 to 9.3.6 (#3241)
dependabot[bot] May 5, 2026
2773e59
Bump AWSSDK.DynamoDBv2 from 4.0.17.9 to 4.0.18 (#3239)
dependabot[bot] May 5, 2026
420030c
Bump wait-on from 9.0.3 to 9.0.5 in /src/Elastic.Documentation.Site (…
dependabot[bot] May 5, 2026
38b7b6a
Bump globals from 17.4.0 to 17.5.0 in /src/Elastic.Documentation.Site…
dependabot[bot] May 5, 2026
da06237
Bump @types/katex in /src/Elastic.Documentation.Site (#3234)
dependabot[bot] May 5, 2026
539324c
Bump amondnet/vercel-action in /actions/publish-vercel (#3232)
dependabot[bot] May 5, 2026
919d11e
fix: upgrade @tanstack/react-query from 5.96.2 to 5.97.0 (#3217)
nkammah May 5, 2026
f553c14
Bump axios from 1.15.0 to 1.16.0 in /src/Elastic.Documentation.Site (…
dependabot[bot] May 5, 2026
1d888d2
Bump the eslint group across 1 directory with 2 updates (#3233)
dependabot[bot] May 5, 2026
90bc137
[Automation] Bump product version numbers (#3247)
elastic-observability-automation[bot] May 5, 2026
8266040
[Automation] Bump product version numbers (#3249)
elastic-observability-automation[bot] May 5, 2026
4c36217
Add white-label branding support for isolated builds (#3159)
Mpdreamz May 6, 2026
93c4917
Adds video guidance to syntax ref guide (#3253)
jmikell821 May 6, 2026
de07e08
Harden branding image symlink check to cover ancestor directories (#3…
Mpdreamz May 6, 2026
d24074c
feat(tooling): migrate docs-builder CLI from ConsoleAppFramework to N…
Mpdreamz May 7, 2026
04df402
fix: applies-switch and tab-set first tab hidden when block contains …
Mpdreamz May 7, 2026
8870d0e
feat(cli): support llm exporter alias with argh EnumValue (#3265)
Mpdreamz May 7, 2026
142c9d2
Restore --exporters aliases and shorthand sets (#3266)
Mpdreamz May 7, 2026
03fd16d
Allow .plan extension for assembler deploy apply (#3267)
Mpdreamz May 7, 2026
c203395
Continue white-label branding support for isolated builds (#3259)
Mpdreamz May 7, 2026
0f1b72c
Update ECS version per 9.4 release (#3252)
taylor-swanson May 7, 2026
b381ea8
Remove UTF-8 BOM from changelog command outputs (#3243)
lcawl May 7, 2026
5307c31
[Automation] Bump product version numbers (#3257)
elastic-observability-automation[bot] May 7, 2026
8ca38c4
Edit changelog bundle docs (#3213)
lcawl May 7, 2026
38fc55e
fix: upgrade @tanstack/react-query from 5.97.0 to 5.99.0 (#3258)
reakaleek May 7, 2026
fcad874
Skip AWS auth in docs preview when docs build fails (#3269)
Mpdreamz May 7, 2026
701e6d1
feat(cli-docs): auto-generate CLI reference from schema JSON (#3221)
Mpdreamz May 7, 2026
59503a5
Return exit code 1 on CTRL+C cancellation (#3264)
Mpdreamz May 7, 2026
2c4c206
[Automation] Bump product version numbers (#3273)
elastic-observability-automation[bot] May 8, 2026
e84e8b4
fix: upgrade @tanstack/react-query from 5.99.0 to 5.99.1 (#3277)
Mpdreamz May 11, 2026
74ec10f
Bump @babel/plugin-transform-modules-systemjs (#3276)
dependabot[bot] May 11, 2026
e6ea19c
Remove stale GetOrCreateWriteFs — use inline _writeFsPath approach fr…
Mpdreamz May 11, 2026
b0a3067
Merge origin/main
Mpdreamz May 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
<PackageVersion Include="MartinCostello.Logging.XUnit.v3" Version="0.7.1" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.3" />
<PackageVersion Include="Microsoft.OpenApi" Version="3.1.1" />
<PackageVersion Include="Tomlyn" Version="2.3.2" />
<PackageVersion Include="TUnit" Version="0.25.21" />
<PackageVersion Include="xunit.v3.extensibility.core" Version="2.0.2" />
<PackageVersion Include="WireMock.Net" Version="1.6.11" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<PackageReference Include="Nullean.Argh.Interfaces" />
<PackageReference Include="Nullean.ScopedFileSystem" />
<PackageReference Include="System.IO.Abstractions.TestingHelpers" />
<PackageReference Include="Samboy063.Tomlet" />
<PackageReference Include="Tomlyn" />
<PackageReference Include="Vecc.YamlDotNet.Analyzers.StaticGenerator" />
<PackageReference Include="YamlDotNet" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,30 @@ public record DetectionRuleOverviewRef : FileRef
{
public IReadOnlyCollection<string> DetectionRuleFolders { get; }

/// <summary>Optional path to a markdown file whose content prefixes the deprecated rules listing page.</summary>
public string? DeprecatedFile { get; init; }

/// <summary>
/// The resolved deprecated-rules overview FileRef that should appear as a sibling to this ref in the nav.
/// Set by <c>ResolveRuleOverviewReference</c> when a <c>_deprecated</c> subfolder is detected.
/// </summary>
public FileRef? DeprecatedSiblingRef { get; init; }

public DetectionRuleOverviewRef(
string pathRelativeToDocumentationSet,
string pathRelativeToContainer,
IReadOnlyCollection<string> detectionRulesFolders,
IReadOnlyCollection<ITableOfContentsItem> children,
string context
string context,
string? deprecatedFile = null
) : base(pathRelativeToDocumentationSet, pathRelativeToContainer, false, children, context)
{
PathRelativeToDocumentationSet = pathRelativeToDocumentationSet;
PathRelativeToContainer = pathRelativeToContainer;
DetectionRuleFolders = detectionRulesFolders;
Children = children;
Context = context;
DeprecatedFile = deprecatedFile;
}

public static IReadOnlyCollection<ITableOfContentsItem> CreateTableOfContentItems(IReadOnlyCollection<IDirectoryInfo> sourceFolders, string context, IDirectoryInfo baseDirectory)
Expand All @@ -38,6 +49,18 @@ public static IReadOnlyCollection<ITableOfContentsItem> CreateTableOfContentItem
.ToArray();
}

public static IReadOnlyCollection<ITableOfContentsItem> CreateDeprecatedTableOfContentItems(IReadOnlyCollection<IDirectoryInfo> sourceFolders, string context, IDirectoryInfo baseDirectory)
{
var tocItems = new List<ITableOfContentsItem>();
foreach (var detectionRuleFolder in sourceFolders)
{
var children = ReadDeprecatedDetectionRuleFolder(detectionRuleFolder, context, baseDirectory);
tocItems.AddRange(children);
}

return tocItems.ToArray();
}

private static IReadOnlyCollection<ITableOfContentsItem> ReadDetectionRuleFolder(IDirectoryInfo directory, string context, IDirectoryInfo baseDirectory)
{
IReadOnlyCollection<ITableOfContentsItem> children = directory
Expand All @@ -62,4 +85,25 @@ private static IReadOnlyCollection<ITableOfContentsItem> ReadDetectionRuleFolder

return children;
}

private static IReadOnlyCollection<ITableOfContentsItem> ReadDeprecatedDetectionRuleFolder(IDirectoryInfo directory, string context, IDirectoryInfo baseDirectory)
{
IReadOnlyCollection<ITableOfContentsItem> children = directory
.EnumerateFiles("*.*", SearchOption.AllDirectories)
.Where(f => !f.Attributes.HasFlag(FileAttributes.Hidden) && !f.Attributes.HasFlag(FileAttributes.System))
.Where(f => !f.Directory!.Attributes.HasFlag(FileAttributes.Hidden) && !f.Directory!.Attributes.HasFlag(FileAttributes.System))
// skip symlinks
.Where(f => f.LinkTarget == null)
.Where(f => f.Extension == ".toml")
// only include files inside _deprecated subdirectories
.Where(f => f.FullName.Contains($"{Path.DirectorySeparatorChar}_deprecated{Path.DirectorySeparatorChar}"))
.Select(f =>
{
var relativePath = Path.GetRelativePath(baseDirectory.Parent!.FullName, f.FullName);
return (ITableOfContentsItem)new DetectionRuleRef(f, relativePath, context);
})
.ToArray();

return children;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,12 @@ private static TableOfContents ResolveTableOfContents(
};

if (resolvedItem != null)
{
resolved.Add(resolvedItem);
// Emit the deprecated rules overview as a sibling immediately after the active rules ref
if (resolvedItem is DetectionRuleOverviewRef { DeprecatedSiblingRef: { } deprecatedSibling })
resolved.Add(deprecatedSibling);
}
}

return resolved;
Expand Down Expand Up @@ -453,9 +458,33 @@ private static ITableOfContentsItem ResolveRuleOverviewReference(IDiagnosticsCol
.ToList();
var tomlChildren = DetectionRuleOverviewRef.CreateTableOfContentItems(tocSourceFolders, context, baseDirectory);

var children = resolvedChildren.Concat(tomlChildren).ToList();
var children = resolvedChildren.ToList();
children.AddRange(tomlChildren);

return new DetectionRuleOverviewRef(fullPath, pathRelativeToContainer, detectionRuleRef.DetectionRuleFolders, children, context);
// Auto-detect _deprecated subdirectories. When found, build the deprecated overview FileRef
// and attach it as DeprecatedSiblingRef so ResolveTableOfContents can emit it as a sibling,
// not as a child nested under the active rules.
FileRef? deprecatedSiblingRef = null;
var hasDeprecatedRules = tocSourceFolders.Any(d =>
d.Exists && d.EnumerateDirectories("_deprecated", SearchOption.TopDirectoryOnly).Any());
if (hasDeprecatedRules)
{
var deprecatedFileName = detectionRuleRef.DeprecatedFile ?? "deprecated-detection-rules.md";
var overviewDir = fileSystem.Path.GetDirectoryName(fullPath);
var deprecatedFullPath = string.IsNullOrEmpty(overviewDir)
? deprecatedFileName
: $"{overviewDir}/{deprecatedFileName}";
var deprecatedPathRelativeToContainer = string.IsNullOrEmpty(containerPath)
? deprecatedFullPath
: deprecatedFullPath.Substring(containerPath.Length + 1);
var deprecatedTomlChildren = DetectionRuleOverviewRef.CreateDeprecatedTableOfContentItems(tocSourceFolders, context, baseDirectory);
deprecatedSiblingRef = new FileRef(deprecatedFullPath, deprecatedPathRelativeToContainer, false, deprecatedTomlChildren, context);
}

return new DetectionRuleOverviewRef(fullPath, pathRelativeToContainer, detectionRuleRef.DetectionRuleFolders, children, context, detectionRuleRef.DeprecatedFile)
{
DeprecatedSiblingRef = deprecatedSiblingRef
};
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public class TocItemYamlConverter : IYamlTypeConverter
}
value = childrenList;
}
else if (key.Value is "detection_rules" or "exclude")
else if (key.Value is "detection_rules" or "exclude" or "deprecated_detection_rules")
{
// Parse the children list manually
var childrenList = new List<string>();
Expand Down Expand Up @@ -144,11 +144,8 @@ public class TocItemYamlConverter : IYamlTypeConverter
if (dictionary.TryGetValue("detection_rules", out var detectionRulesObj) && detectionRulesObj is string[] detectionRulesFolders &&
dictionary.TryGetValue("file", out var detectionRulesFilePath) && detectionRulesFilePath is string detectionRulesFile)
{
// Create the index file reference (FolderIndexFileRef to mark it as the folder's index)
// Store ONLY the file name - the folder path will be prepended during resolution
// This allows validation to check if the file itself has deep paths
// PathRelativeToContainer will be set during resolution
return new DetectionRuleOverviewRef(detectionRulesFile, detectionRulesFile, detectionRulesFolders, children, placeholderContext);
var deprecatedFile = dictionary.TryGetValue("deprecated_file", out var deprecatedFileObj) && deprecatedFileObj is string df ? df : null;
return new DetectionRuleOverviewRef(detectionRulesFile, detectionRulesFile, detectionRulesFolders, children, placeholderContext, deprecatedFile);
}

// Check for file reference (file: or hidden:)
Expand Down
10 changes: 9 additions & 1 deletion src/Elastic.Documentation.Site/Assets/pages-nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,16 @@ export function initNav() {

// Normalize pathname by removing trailing slash to handle both URL variants
const pathname = window.location.pathname.replace(/\/$/, '')

// When the page is a hidden nav item (e.g. an individual detection rule), the server
// emits docs:nav-active pointing to the nearest visible ancestor so we can highlight it.
const navActiveMeta = document.querySelector<HTMLMetaElement>(
'meta[name="docs:nav-active"]'
)
const activePathname = navActiveMeta?.content ?? pathname

const navItems = $$(
'a[href="' + pathname + '"], a[href="' + pathname + '/"]',
'a[href="' + activePathname + '"], a[href="' + activePathname + '/"]',
pagesNav
)
navItems.forEach((el) => {
Expand Down
4 changes: 4 additions & 0 deletions src/Elastic.Documentation.Site/Layout/_Head.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
@await RenderPartialAsync(_Favicon.Create(Model))
<meta name="robots" content="@(Model.AllowIndexing ? "index, follow" : "noindex, nofollow")">
<meta name="htmx-config" content='{"selfRequestsOnly": true}'>
@if (!string.IsNullOrEmpty(Model.NavigationActiveUrl))
{
<meta name="docs:nav-active" content="@Model.NavigationActiveUrl">
}
<meta property="og:type" content="website"/>
<meta property="og:title" content="@Model.Title"/>
<meta property="og:description" content="@Model.Description"/>
Expand Down
7 changes: 7 additions & 0 deletions src/Elastic.Documentation.Site/_ViewModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ public record GlobalLayoutViewModel
/// <summary>Breadcrumb trail for codex sub-header (Home / Group / Docset).</summary>
public IReadOnlyList<CodexBreadcrumb>? CodexBreadcrumbs { get; init; }

/// <summary>
/// When the current page is a hidden nav item (e.g. an individual detection rule page),
/// the URL of its nearest visible ancestor. The client uses this to highlight the correct
/// nav entry when the page has no rendered nav link of its own.
/// </summary>
public string? NavigationActiveUrl { get; init; }


// Header properties for isolated mode
public string? HeaderTitle { get; init; }
Expand Down
4 changes: 4 additions & 0 deletions src/Elastic.Markdown/Elastic.Markdown.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
<ProjectReference Include="..\Elastic.Documentation.Svg\Elastic.Documentation.Svg.csproj" />
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="Elastic.Markdown.Tests"/>
</ItemGroup>

<ItemGroup>
<UpToDateCheckInput Remove="Myst\Directives\AppliesSwitch\AppliesItemView.cshtml" />
<UpToDateCheckInput Remove="Myst\Directives\AppliesSwitch\AppliesSwitchView.cshtml" />
Expand Down
Loading
Loading