Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
154 changes: 154 additions & 0 deletions KustoSchemaTools.Tests/Model/ManagedIdentityPolicyTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using KustoSchemaTools.Model;
using KustoSchemaTools.Changes;
using Microsoft.Extensions.Logging;
using Moq;

namespace KustoSchemaTools.Tests.ManagedIdentity
{
public class ManagedIdentityPolicyTests
{
[Fact]
public void CreateScript_SingleUsage_GeneratesCorrectKql()
{
// Arrange
var policy = new ManagedIdentityPolicy
{
ObjectId = "12345678-1234-1234-1234-123456789abc",
AllowedUsages = new List<string> { "NativeIngestion" }
};

// Act
var script = policy.CreateScript("MyDatabase");

// Assert
Assert.Equal("ManagedIdentityPolicy", script.Kind);
Assert.Equal(80, script.Script.Order);
Assert.Contains(".alter-merge database MyDatabase policy managed_identity", script.Script.Text);
Assert.Contains("\"ObjectId\": \"12345678-1234-1234-1234-123456789abc\"", script.Script.Text);
Assert.Contains("\"AllowedUsages\": \"NativeIngestion\"", script.Script.Text);
}

[Fact]
public void CreateScript_MultipleUsages_JoinsWithComma()
{
// Arrange
var policy = new ManagedIdentityPolicy
{
ObjectId = "12345678-1234-1234-1234-123456789abc",
AllowedUsages = new List<string> { "AutomatedFlows", "ExternalTable", "NativeIngestion" }
};

// Act
var script = policy.CreateScript("MyDatabase");

// Assert
Assert.Contains("\"AllowedUsages\": \"AutomatedFlows, ExternalTable, NativeIngestion\"", script.Script.Text);
}

[Fact]
public void CreateScript_DatabaseNameUsedInKql()
{
// Arrange
var policy = new ManagedIdentityPolicy
{
ObjectId = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
AllowedUsages = new List<string> { "ExternalTable" }
};

// Act
var script = policy.CreateScript("TargetDatabase");

// Assert
Assert.StartsWith(".alter-merge database TargetDatabase policy managed_identity", script.Script.Text);
}

[Fact]
public void CreateScript_WrapsJsonInBackticks()
{
// Arrange
var policy = new ManagedIdentityPolicy
{
ObjectId = "12345678-1234-1234-1234-123456789abc",
AllowedUsages = new List<string> { "NativeIngestion" }
};

// Act
var script = policy.CreateScript("MyDatabase");

// Assert
Assert.Contains("```", script.Script.Text);
Assert.EndsWith("```", script.Script.Text);
}

[Fact]
public void DatabaseChanges_WithManagedIdentityPolicies_GeneratesScript()
{
// Arrange
var loggerMock = new Mock<ILogger>();
var oldState = new Database { Name = "TestDb" };
var newState = new Database
{
Name = "TestDb",
ManagedIdentityPolicies = new List<ManagedIdentityPolicy>
{
new ManagedIdentityPolicy
{
ObjectId = "12345678-1234-1234-1234-123456789abc",
AllowedUsages = new List<string> { "NativeIngestion" }
}
}
};

// Act
var changes = DatabaseChanges.GenerateChanges(oldState, newState, "TestDb", loggerMock.Object);

// Assert
Assert.NotEmpty(changes);
var scripts = changes.SelectMany(c => c.Scripts).ToList();
Assert.NotEmpty(scripts);
var managedIdentityScript = scripts.FirstOrDefault(s => s.Kind == "ManagedIdentityPolicy");
Assert.NotNull(managedIdentityScript);
Assert.Contains(".alter-merge database TestDb policy managed_identity", managedIdentityScript.Script.Text);
Assert.Contains("12345678-1234-1234-1234-123456789abc", managedIdentityScript.Script.Text);
}

[Fact]
public void DatabaseChanges_WithUnchangedManagedIdentityPolicies_GeneratesNoChanges()
{
// Arrange
var loggerMock = new Mock<ILogger>();
var policy = new ManagedIdentityPolicy
{
ObjectId = "12345678-1234-1234-1234-123456789abc",
AllowedUsages = new List<string> { "NativeIngestion" }
};
var oldState = new Database
{
Name = "TestDb",
ManagedIdentityPolicies = new List<ManagedIdentityPolicy> { policy }
};
var newState = new Database
{
Name = "TestDb",
ManagedIdentityPolicies = new List<ManagedIdentityPolicy>
{
new ManagedIdentityPolicy
{
ObjectId = "12345678-1234-1234-1234-123456789abc",
AllowedUsages = new List<string> { "NativeIngestion" }
}
}
};

// Act
var changes = DatabaseChanges.GenerateChanges(oldState, newState, "TestDb", loggerMock.Object);

// Assert - no database-level changes since policies are identical
var databaseScriptChanges = changes
.SelectMany(c => c.Scripts)
.Where(s => s.Kind == "ManagedIdentityPolicy")
.ToList();
Assert.Empty(databaseScriptChanges);
}
}
}
4 changes: 4 additions & 0 deletions KustoSchemaTools/Changes/DatabaseChanges.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,17 @@ public static List<IChange> GenerateChanges(Database oldState, Database newState
otherFromScripts.AddRange(oldState.Scripts.Select(itm => new DatabaseScriptContainer(itm, "DatabaseScript")));
if (oldState.DefaultRetentionAndCache != null)
otherFromScripts.AddRange(oldState.DefaultRetentionAndCache.CreateScripts(name, "database"));
if (oldState.ManagedIdentityPolicies != null)
otherFromScripts.AddRange(oldState.ManagedIdentityPolicies.Select(p => p.CreateScript(name)));
}

var otherToScripts = new List<DatabaseScriptContainer>();
if (newState.Scripts != null)
otherToScripts.AddRange(newState.Scripts.Select(itm => new DatabaseScriptContainer(itm, "DatabaseScript")));
if (newState.DefaultRetentionAndCache != null)
otherToScripts.AddRange(newState.DefaultRetentionAndCache.CreateScripts(name, "database"));
if (newState.ManagedIdentityPolicies != null)
otherToScripts.AddRange(newState.ManagedIdentityPolicies.Select(p => p.CreateScript(name)));

if (otherToScripts.Count > 0)
{
Expand Down
2 changes: 2 additions & 0 deletions KustoSchemaTools/Model/Database.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
{
public string Name { get; set; }
public string Team { get; set; } = "";
public RetentionAndCachePolicy DefaultRetentionAndCache { get; set; } = new RetentionAndCachePolicy();

Check warning on line 11 in KustoSchemaTools/Model/Database.cs

View workflow job for this annotation

GitHub Actions / build

'RetentionAndCachePolicy' is obsolete: 'Use policies instead'

public List<AADObject> Monitors { get; set; } = new List<AADObject>();

Expand Down Expand Up @@ -37,6 +37,8 @@

public Dictionary<string, FollowerDatabase> Followers { get; set; } = new Dictionary<string, FollowerDatabase>();

public List<ManagedIdentityPolicy> ManagedIdentityPolicies { get; set; } = new List<ManagedIdentityPolicy>();

public string EscapedName => Name.BracketIfIdentifier();
}
}
20 changes: 20 additions & 0 deletions KustoSchemaTools/Model/ManagedIdentityPolicy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using KustoSchemaTools.Changes;
using Newtonsoft.Json;
using KustoSchemaTools.Helpers;
using KustoSchemaTools.Parser;

namespace KustoSchemaTools.Model
{
public class ManagedIdentityPolicy
{
public string ObjectId { get; set; }
public List<string> AllowedUsages { get; set; } = new List<string>();

public DatabaseScriptContainer CreateScript(string databaseName)
{
var policyObjects = new[] { new { ObjectId = ObjectId, AllowedUsages = string.Join(", ", AllowedUsages) } };
var json = JsonConvert.SerializeObject(policyObjects, Serialization.JsonPascalCase);
return new DatabaseScriptContainer("ManagedIdentityPolicy", 80, $".alter-merge database {databaseName.BracketIfIdentifier()} policy managed_identity ```{json}```");
}
}
}
Loading