Skip to content
Open
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
28 changes: 28 additions & 0 deletions src/Core/SecretsManager/Entities/SecretVersion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
๏ปฟ#nullable enable
using Bit.Core.Entities;
using Bit.Core.Utilities;

namespace Bit.Core.SecretsManager.Entities;

public class SecretVersion : ITableObject<Guid>
{
public Guid Id { get; set; }

public Guid SecretId { get; set; }

public string Value { get; set; } = string.Empty;

public DateTime VersionDate { get; set; }

public Guid? EditorServiceAccountId { get; set; }

public Guid? EditorOrganizationUserId { get; set; }

public void SetNewId()
{
if (Id == default(Guid))
{
Id = CoreHelpers.GenerateComb();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public DatabaseContext(DbContextOptions<DatabaseContext> options)
public DbSet<Policy> Policies { get; set; }
public DbSet<Provider> Providers { get; set; }
public DbSet<Secret> Secret { get; set; }
public DbSet<SecretVersion> SecretVersion { get; set; }
public DbSet<ServiceAccount> ServiceAccount { get; set; }
public DbSet<Project> Project { get; set; }
public DbSet<ProviderUser> ProviderUsers { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
๏ปฟusing Bit.Infrastructure.EntityFramework.SecretsManager.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Bit.Infrastructure.EntityFramework.SecretsManager.Configurations;

public class SecretVersionEntityTypeConfiguration : IEntityTypeConfiguration<SecretVersion>
{
public void Configure(EntityTypeBuilder<SecretVersion> builder)
{
builder.Property(sv => sv.Id)
.ValueGeneratedNever();

builder.HasKey(sv => sv.Id)
.IsClustered();

builder.Property(sv => sv.Value)
.IsRequired();

builder.Property(sv => sv.VersionDate)
.IsRequired();

builder.HasOne(sv => sv.EditorServiceAccount)
.WithMany()
.HasForeignKey(sv => sv.EditorServiceAccountId)
.OnDelete(DeleteBehavior.SetNull);

builder.HasOne(sv => sv.EditorOrganizationUser)
.WithMany()
.HasForeignKey(sv => sv.EditorOrganizationUserId)
.OnDelete(DeleteBehavior.SetNull);

builder.HasIndex(sv => sv.SecretId)
.HasDatabaseName("IX_SecretVersion_SecretId");

builder.HasIndex(sv => sv.EditorServiceAccountId)
.HasDatabaseName("IX_SecretVersion_EditorServiceAccountId");

builder.HasIndex(sv => sv.EditorOrganizationUserId)
.HasDatabaseName("IX_SecretVersion_EditorOrganizationUserId");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class Secret : Core.SecretsManager.Entities.Secret
public virtual ICollection<UserSecretAccessPolicy> UserAccessPolicies { get; set; }
public virtual ICollection<GroupSecretAccessPolicy> GroupAccessPolicies { get; set; }
public virtual ICollection<ServiceAccountSecretAccessPolicy> ServiceAccountAccessPolicies { get; set; }
public virtual ICollection<SecretVersion> SecretVersions { get; set; }
}

public class SecretMapperProfile : Profile
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
๏ปฟ#nullable enable

using AutoMapper;

namespace Bit.Infrastructure.EntityFramework.SecretsManager.Models;

public class SecretVersion : Core.SecretsManager.Entities.SecretVersion
{
public Secret? Secret { get; set; }

public ServiceAccount? EditorServiceAccount { get; set; }

public Bit.Infrastructure.EntityFramework.Models.OrganizationUser? EditorOrganizationUser { get; set; }
}

public class SecretVersionMapperProfile : Profile
{
public SecretVersionMapperProfile()
{
CreateMap<Core.SecretsManager.Entities.SecretVersion, SecretVersion>()
.PreserveReferences()
.ReverseMap();
}
}
27 changes: 27 additions & 0 deletions src/Sql/dbo/SecretsManager/Tables/SecretVersion.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
CREATE TABLE [dbo].[SecretVersion] (
[Id] UNIQUEIDENTIFIER NOT NULL,
[SecretId] UNIQUEIDENTIFIER NOT NULL,
[Value] NVARCHAR (MAX) NOT NULL,
[VersionDate] DATETIME2 (7) NOT NULL,
[EditorServiceAccountId] UNIQUEIDENTIFIER NULL,
[EditorOrganizationUserId] UNIQUEIDENTIFIER NULL,
CONSTRAINT [PK_SecretVersion] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_SecretVersion_OrganizationUser] FOREIGN KEY ([EditorOrganizationUserId]) REFERENCES [dbo].[OrganizationUser] ([Id]) ON DELETE SET NULL,
CONSTRAINT [FK_SecretVersion_Secret] FOREIGN KEY ([SecretId]) REFERENCES [dbo].[Secret] ([Id]) ON DELETE CASCADE,
CONSTRAINT [FK_SecretVersion_ServiceAccount] FOREIGN KEY ([EditorServiceAccountId]) REFERENCES [dbo].[ServiceAccount] ([Id]) ON DELETE SET NULL
);

GO
CREATE NONCLUSTERED INDEX [IX_SecretVersion_SecretId]
ON [dbo].[SecretVersion]([SecretId] ASC);

GO
CREATE NONCLUSTERED INDEX [IX_SecretVersion_EditorServiceAccountId]
ON [dbo].[SecretVersion]([EditorServiceAccountId] ASC)
WHERE [EditorServiceAccountId] IS NOT NULL;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐ŸŒฑ Just wanted to point out that SQL Server is using filtered (partial) indexes while the EF migrations are using non-filtered indexes. Not really a big issue but something to keep in mind on whether we want to keep things as consistent as possible between environments. Mysql/Mariadb does not currently support filtered indexes (without a workaround) so we wouldn't be able to have all database platforms aligned 100% anyway.


GO
CREATE NONCLUSTERED INDEX [IX_SecretVersion_EditorOrganizationUserId]
ON [dbo].[SecretVersion]([EditorOrganizationUserId] ASC)
WHERE [EditorOrganizationUserId] IS NOT NULL;
GO
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
SET ANSI_NULLS ON;
SET QUOTED_IDENTIFIER ON;
GO

IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'SecretVersion' AND schema_id = SCHEMA_ID('dbo'))
BEGIN
CREATE TABLE [dbo].[SecretVersion] (
[Id] UNIQUEIDENTIFIER NOT NULL,
[SecretId] UNIQUEIDENTIFIER NOT NULL,
[Value] NVARCHAR (MAX) NOT NULL,
[VersionDate] DATETIME2 (7) NOT NULL,
[EditorServiceAccountId] UNIQUEIDENTIFIER NULL,
[EditorOrganizationUserId] UNIQUEIDENTIFIER NULL,
CONSTRAINT [PK_SecretVersion] PRIMARY KEY CLUSTERED ([Id] ASC)
);
END
GO

-- Ensure foreign keys exist
IF NOT EXISTS (
SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_SecretVersion_OrganizationUser'
)
BEGIN
ALTER TABLE [dbo].[SecretVersion]
ADD CONSTRAINT [FK_SecretVersion_OrganizationUser]
FOREIGN KEY ([EditorOrganizationUserId])
REFERENCES [dbo].[OrganizationUser] ([Id])
ON DELETE SET NULL;
END
GO

IF NOT EXISTS (
SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_SecretVersion_Secret'
)
BEGIN
ALTER TABLE [dbo].[SecretVersion]
ADD CONSTRAINT [FK_SecretVersion_Secret]
FOREIGN KEY ([SecretId])
REFERENCES [dbo].[Secret] ([Id])
ON DELETE CASCADE;
END
GO

IF NOT EXISTS (
SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_SecretVersion_ServiceAccount'
)
BEGIN
ALTER TABLE [dbo].[SecretVersion]
ADD CONSTRAINT [FK_SecretVersion_ServiceAccount]
FOREIGN KEY ([EditorServiceAccountId])
REFERENCES [dbo].[ServiceAccount] ([Id])
ON DELETE SET NULL;
END
GO

IF NOT EXISTS (
SELECT 1 FROM sys.indexes WHERE name = 'IX_SecretVersion_SecretId' AND object_id = OBJECT_ID('[dbo].[SecretVersion]')
)
BEGIN
CREATE NONCLUSTERED INDEX [IX_SecretVersion_SecretId]
ON [dbo].[SecretVersion]([SecretId] ASC);
END
GO

IF NOT EXISTS (
SELECT 1 FROM sys.indexes WHERE name = 'IX_SecretVersion_EditorServiceAccountId' AND object_id = OBJECT_ID('[dbo].[SecretVersion]')
)
BEGIN
CREATE NONCLUSTERED INDEX [IX_SecretVersion_EditorServiceAccountId]
ON [dbo].[SecretVersion]([EditorServiceAccountId] ASC)
WHERE [EditorServiceAccountId] IS NOT NULL;
END
GO

IF NOT EXISTS (
SELECT 1 FROM sys.indexes WHERE name = 'IX_SecretVersion_EditorOrganizationUserId' AND object_id = OBJECT_ID('[dbo].[SecretVersion]')
)
BEGIN
CREATE NONCLUSTERED INDEX [IX_SecretVersion_EditorOrganizationUserId]
ON [dbo].[SecretVersion]([EditorOrganizationUserId] ASC)
WHERE [EditorOrganizationUserId] IS NOT NULL;
END
GO
Loading
Loading