Repository navigation
SentinelToXDRMigration: qualification follow-ups, XDR static KQL override, and NPF metrics - #15474
Open
idoshabi07 wants to merge 7 commits into
Open
idoshabi07 wants to merge 7 commits into
idoshabi07 wants to merge 7 commits into
Conversation
…c override, and NPF metrics (Todos #0-Azure#6) - Todo #0: isolate Azure CLI profile in runtime consent and mock credential constructors in pytest conftest - Todo #1: add live CD + AR enablement, alert parity readiness, and --keep-enabled support - Todo #2: enforce strict V3.1 packaging verification for XDR Detections and XDR Workbooks - Todo #3: default workflow profile to qualification and fix Windows directory fsync in budget.py - Todo #4: add static KQL validation for XDR Detections and XDR Workbooks in Python and KqlValidationTests.cs - Todo Azure#5: project kqlRuntimeVerifiedRules SHA-256 hashes and downgrade semantic KQL errors on qualified rules - Todo Azure#6: emit NPF metrics instrumentation across pr-qualification-result.json, workflow-state.json, decision-manifest.json, and npf-pr-labeler.yaml Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2f9e241a-6b82-49ec-ac18-e83c833f2521
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2f9e241a-6b82-49ec-ac18-e83c833f2521
idoshabi07
force-pushed
the
toolkit-publication-qualification-followups
branch
from
October 28, 2026 13:39
9add21a to
e96de75
Compare
…ingestion Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2f9e241a-6b82-49ec-ac18-e83c833f2521
…rting Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2f9e241a-6b82-49ec-ac18-e83c833f2521
…c PR body Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2f9e241a-6b82-49ec-ac18-e83c833f2521
…om public PR body" This reverts commit 42d7959.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2f9e241a-6b82-49ec-ac18-e83c833f2521
|
|
||
| var candidateEvidenceFiles = new[] | ||
| { | ||
| Path.Combine(solutionDir, "Evidence", "pr-qualification", "pr-qualification-result.json"), |
| var candidateEvidenceFiles = new[] | ||
| { | ||
| Path.Combine(solutionDir, "Evidence", "pr-qualification", "pr-qualification-result.json"), | ||
| Path.Combine(solutionDir, "Evidence", "qualification-evidence.json") |
Comment on lines
+574
to
+577
| catch | ||
| { | ||
| // Ignore malformed evidence JSON and continue | ||
| } |
Comment on lines
+598
to
+601
| catch | ||
| { | ||
| // Ignore path resolution errors | ||
| } |
Comment on lines
+643
to
+696
| foreach (var token in verifiedRulesTokens) | ||
| { | ||
| if (token is JArray arr) | ||
| { | ||
| foreach (var item in arr) | ||
| { | ||
| if (item is JValue val && val.Type == JTokenType.String) | ||
| { | ||
| var strVal = val.Value<string>()?.Trim(); | ||
| if (!string.IsNullOrEmpty(strVal) && | ||
| (strVal.Equals(normalizedId, StringComparison.OrdinalIgnoreCase) | ||
| || strVal.Equals(strippedId, StringComparison.OrdinalIgnoreCase) | ||
| || queryHashes.Contains(strVal))) | ||
| { | ||
| return true; | ||
| } | ||
| } | ||
| else if (item is JObject obj) | ||
| { | ||
| var status = (string)obj["status"] ?? (string)obj["result"] ?? "PASS"; | ||
| if (!status.Equals("PASS", StringComparison.OrdinalIgnoreCase) | ||
| && !status.Equals("passed", StringComparison.OrdinalIgnoreCase) | ||
| && !status.Equals("true", StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| var entryHash = (string)obj["querySha256"] ?? (string)obj["queryHash"] ?? (string)obj["sha256"]; | ||
| if (!string.IsNullOrWhiteSpace(entryHash)) | ||
| { | ||
| if (queryHashes.Contains(entryHash.Trim())) | ||
| { | ||
| return true; | ||
| } | ||
| continue; | ||
| } | ||
|
|
||
| var ruleIds = new[] | ||
| { | ||
| (string)obj["ruleId"], | ||
| (string)obj["id"], | ||
| (string)obj["originalRuleId"], | ||
| (string)obj["sourceRuleId"] | ||
| }; | ||
| if (ruleIds.Any(r => !string.IsNullOrWhiteSpace(r) && | ||
| (r.Trim().Equals(normalizedId, StringComparison.OrdinalIgnoreCase) | ||
| || r.Trim().Equals(strippedId, StringComparison.OrdinalIgnoreCase)))) | ||
| { | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
| { | ||
| var basePath = Utils.GetTestDirectory(TestFolderDepthForSolutionParsers); | ||
| var tempSolutionDir = Path.Combine(basePath, "Solutions", $"_TempQualTest_{Guid.NewGuid():N}"); | ||
| var xdrDetDir = Path.Combine(tempSolutionDir, "XDR Detections"); |
| var basePath = Utils.GetTestDirectory(TestFolderDepthForSolutionParsers); | ||
| var tempSolutionDir = Path.Combine(basePath, "Solutions", $"_TempQualTest_{Guid.NewGuid():N}"); | ||
| var xdrDetDir = Path.Combine(tempSolutionDir, "XDR Detections"); | ||
| var evidenceDir = Path.Combine(tempSolutionDir, "Evidence", "pr-qualification"); |
| try | ||
| { | ||
| var ruleId = "xdr-11111111-2222-3333-4444-555555555555"; | ||
| var ruleFilePath = Path.Combine(xdrDetDir, "TempRule.yaml"); |
| } | ||
| } | ||
| }; | ||
| File.WriteAllText(Path.Combine(evidenceDir, "pr-qualification-result.json"), evidenceJson.ToString()); |
| protected override List<string> GetDirectoryPaths() | ||
| { | ||
| var basePath = Utils.GetTestDirectory(TestFolderDepth); | ||
| var solutionsDir = Path.Combine(basePath, "Solutions"); |
idoshabi07
marked this pull request as ready for review
October 29, 2026 15:01
| target = info.get("targetTable") or info.get("ahTable") | ||
| if isinstance(target, str) and target.strip(): | ||
| known.add(target.strip()) | ||
| except Exception: |
| existing_artifact.stat().st_mtime_ns, | ||
| hashlib.sha256(existing_artifact.read_bytes()).hexdigest(), | ||
| ) | ||
| run_started_ns = time.time_ns() |
| try: | ||
| resolved_run = max(1, int(env_val)) | ||
| break | ||
| except (TypeError, ValueError): |
| from pathlib import Path | ||
| import tempfile | ||
| from typing import Iterator | ||
| import unittest |
| if _PROCESS_GUARD_STACK is None: | ||
| stack = ExitStack() | ||
| stack.enter_context(isolated_auth_guard()) | ||
| _PROCESS_GUARD_STACK = stack |
| return original_run(self, result=result) | ||
|
|
||
| unittest.TestCase.run = _guarded_run # type: ignore[method-assign] | ||
| _UNITTEST_GUARD_INSTALLED = True |
| @@ -1,11 +1,18 @@ | |||
| from __future__ import annotations | |||
|
|
|||
| import json | |||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Required items, please complete
Change(s):
Reason for Change(s):
Version Updated:
Testing Completed:
Checked that the validations are passing and have addressed any issues that are present: