-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add secret management functionalities
Introduced secret management services with CRUD operations, notifications, and bulk actions. Added unique name generation and validation for secrets, and implemented corresponding API endpoints.
- Loading branch information
1 parent
34f59be
commit ed4e8a8
Showing
36 changed files
with
632 additions
and
4 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
30 changes: 30 additions & 0 deletions
30
src/modules/Elsa.Secrets.Api/Endpoints/Secrets/BulkDelete/Endpoint.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using Elsa.Abstractions; | ||
using Elsa.Secrets.BulkActions; | ||
using Elsa.Secrets.Management; | ||
using JetBrains.Annotations; | ||
|
||
namespace Elsa.Secrets.Api.Endpoints.Secrets.BulkDelete; | ||
|
||
/// Deletes an agent. | ||
[UsedImplicitly] | ||
public class Endpoint(ISecretManager manager) : ElsaEndpoint<BulkDeleteRequest, BulkDeleteResponse> | ||
{ | ||
/// <inheritdoc /> | ||
public override void Configure() | ||
{ | ||
Post("/bulk-actions/secrets/delete"); | ||
ConfigurePermissions("secrets:delete"); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override async Task<BulkDeleteResponse> ExecuteAsync(BulkDeleteRequest req, CancellationToken ct) | ||
{ | ||
var ids = req.Ids; | ||
var filter = new SecretFilter | ||
{ | ||
Ids = ids | ||
}; | ||
var count = await manager.DeleteManyAsync(filter, ct); | ||
return new BulkDeleteResponse(count); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
src/modules/Elsa.Secrets.Api/Endpoints/Secrets/Create/Endpoint.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using Elsa.Abstractions; | ||
using Elsa.Secrets.Management; | ||
using Elsa.Workflows.Contracts; | ||
using JetBrains.Annotations; | ||
|
||
namespace Elsa.Secrets.Api.Endpoints.Secrets.Create; | ||
|
||
[UsedImplicitly] | ||
internal class Endpoint(ISecretManager manager, IIdentityGenerator identityGenerator) : ElsaEndpoint<SecretInputModel, SecretModel> | ||
{ | ||
public override void Configure() | ||
{ | ||
Post("/secrets"); | ||
ConfigurePermissions("write:secrets"); | ||
} | ||
|
||
public override async Task<SecretModel> ExecuteAsync(SecretInputModel request, CancellationToken cancellationToken) | ||
{ | ||
var newEntity = new Secret | ||
{ | ||
Id = identityGenerator.GenerateId(), | ||
SecretId = identityGenerator.GenerateId(), | ||
Version = 1, | ||
Name = request.Name.Trim(), | ||
Type = request.Type?.Trim(), | ||
Description = request.Description.Trim(), | ||
EncryptedValue = request.EncryptedValue, | ||
IV = request.IV, | ||
EncryptionKeyId = request.EncryptionKeyId, | ||
Algorithm = request.Algorithm, | ||
ExpiresAt = request.ExpiresAt, | ||
RotationPolicy = request.RotationPolicy, | ||
Status = SecretStatus.Active | ||
}; | ||
|
||
await manager.AddAsync(newEntity, cancellationToken); | ||
|
||
var secretModel = newEntity.ToModel(); | ||
return secretModel; | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
src/modules/Elsa.Secrets.Api/Endpoints/Secrets/Delete/Endpoint.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
using Elsa.Abstractions; | ||
using Elsa.Secrets.Management; | ||
using JetBrains.Annotations; | ||
|
||
namespace Elsa.Secrets.Api.Endpoints.Secrets.Delete; | ||
|
||
/// Deletes a secret. | ||
[UsedImplicitly] | ||
public class Endpoint(ISecretManager manager) : ElsaEndpoint<Request> | ||
{ | ||
/// <inheritdoc /> | ||
public override void Configure() | ||
{ | ||
Delete("/secrets/{id}"); | ||
ConfigurePermissions("secrets:delete"); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override async Task HandleAsync(Request req, CancellationToken ct) | ||
{ | ||
var entity = await manager.GetAsync(req.Id, ct); | ||
|
||
if(entity == null) | ||
{ | ||
await SendNotFoundAsync(ct); | ||
return; | ||
} | ||
|
||
await manager.DeleteAsync(entity, ct); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
src/modules/Elsa.Secrets.Api/Endpoints/Secrets/Delete/Request.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using System.ComponentModel.DataAnnotations; | ||
|
||
namespace Elsa.Secrets.Api.Endpoints.Secrets.Delete; | ||
|
||
public class Request | ||
{ | ||
[Required] public string Id { get; set; } = default!; | ||
} |
25 changes: 25 additions & 0 deletions
25
src/modules/Elsa.Secrets.Api/Endpoints/Secrets/GenerateUniqueName/Endpoint.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using Elsa.Abstractions; | ||
using Elsa.Secrets.Management; | ||
using Elsa.Secrets.UniqueName; | ||
using JetBrains.Annotations; | ||
|
||
namespace Elsa.Secrets.Api.Endpoints.Secrets.GenerateUniqueName; | ||
|
||
/// Generates a unique name for a secret. | ||
[UsedImplicitly] | ||
public class Endpoint(ISecretManager manager) : ElsaEndpointWithoutRequest<GenerateUniqueNameResponse> | ||
{ | ||
/// <inheritdoc /> | ||
public override void Configure() | ||
{ | ||
Post("/actions/secrets/generate-unique-name"); | ||
ConfigurePermissions("secrets:write"); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override async Task<GenerateUniqueNameResponse> ExecuteAsync(CancellationToken ct) | ||
{ | ||
var newName = await manager.GenerateUniqueNameAsync(ct); | ||
return new(newName); | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
src/modules/Elsa.Secrets.Api/Endpoints/Secrets/Get/Endpoint.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
using Elsa.Abstractions; | ||
using Elsa.Secrets.Management; | ||
using JetBrains.Annotations; | ||
|
||
namespace Elsa.Secrets.Api.Endpoints.Secrets.Get; | ||
|
||
/// Gets a secret. | ||
[UsedImplicitly] | ||
public class Endpoint(ISecretManager agentManager) : ElsaEndpoint<Request, SecretModel> | ||
{ | ||
/// <inheritdoc /> | ||
public override void Configure() | ||
{ | ||
Get("/secrets/{id}"); | ||
ConfigurePermissions("secrets:read"); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override async Task<SecretModel> ExecuteAsync(Request req, CancellationToken ct) | ||
{ | ||
var entity = await agentManager.GetAsync(req.Id, ct); | ||
|
||
if(entity == null) | ||
{ | ||
await SendNotFoundAsync(ct); | ||
return null!; | ||
} | ||
|
||
return entity.ToModel(); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
src/modules/Elsa.Secrets.Api/Endpoints/Secrets/Get/Request.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using System.ComponentModel.DataAnnotations; | ||
|
||
namespace Elsa.Secrets.Api.Endpoints.Secrets.Get; | ||
|
||
public class Request | ||
{ | ||
[Required] public string Id { get; set; } = default!; | ||
} |
25 changes: 25 additions & 0 deletions
25
src/modules/Elsa.Secrets.Api/Endpoints/Secrets/IsUniqueName/Endpoint.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using Elsa.Abstractions; | ||
using Elsa.Secrets.Management; | ||
using Elsa.Secrets.UniqueName; | ||
using JetBrains.Annotations; | ||
|
||
namespace Elsa.Secrets.Api.Endpoints.Secrets.IsUniqueName; | ||
|
||
/// Checks if a name is unique. | ||
[UsedImplicitly] | ||
public class Endpoint(ISecretManager agentManager) : ElsaEndpoint<IsUniqueNameRequest, IsUniqueNameResponse> | ||
{ | ||
/// <inheritdoc /> | ||
public override void Configure() | ||
{ | ||
Post("/queries/secrets/is-unique-name"); | ||
ConfigurePermissions("secrets:write"); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override async Task<IsUniqueNameResponse> ExecuteAsync(IsUniqueNameRequest req, CancellationToken ct) | ||
{ | ||
var isUnique = await agentManager.IsNameUniqueAsync(req.Name, req.Id, ct); | ||
return new(isUnique); | ||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
src/modules/Elsa.Secrets.Api/Endpoints/Secrets/Update/Endpoint.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
using Elsa.Abstractions; | ||
using Elsa.Common.Contracts; | ||
using Elsa.Secrets.Management; | ||
using JetBrains.Annotations; | ||
|
||
namespace Elsa.Secrets.Api.Endpoints.Secrets.Update; | ||
|
||
/// Updates an agent. | ||
[UsedImplicitly] | ||
public class Endpoint(ISecretManager agentManager, ISystemClock systemClock) : ElsaEndpoint<SecretInputModel, SecretModel> | ||
{ | ||
/// <inheritdoc /> | ||
public override void Configure() | ||
{ | ||
Post("/secrets/{id}"); | ||
ConfigurePermissions("secrets:write"); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override async Task<SecretModel> ExecuteAsync(SecretInputModel req, CancellationToken ct) | ||
{ | ||
var id = Route<string>("id")!; | ||
var entity = await agentManager.GetAsync(id, ct); | ||
|
||
if (entity == null) | ||
{ | ||
await SendNotFoundAsync(ct); | ||
return null!; | ||
} | ||
|
||
var isNameDuplicate = await IsNameDuplicateAsync(req.Name, id, ct); | ||
|
||
if (isNameDuplicate) | ||
{ | ||
AddError("Another secret already exists with the specified name"); | ||
await SendErrorsAsync(cancellation: ct); | ||
return entity.ToModel(); | ||
} | ||
|
||
entity.Name = req.Name.Trim(); | ||
entity.Description = req.Description.Trim(); | ||
entity.Algorithm = req.Algorithm; | ||
entity.Type = req.Type; | ||
entity.EncryptedValue = req.EncryptedValue; | ||
entity.IV = req.IV; | ||
entity.ExpiresAt = req.ExpiresAt; | ||
entity.RotationPolicy = req.RotationPolicy; | ||
entity.EncryptionKeyId = req.EncryptionKeyId; | ||
entity.UpdatedAt = systemClock.UtcNow; | ||
|
||
await agentManager.UpdateAsync(entity, ct); | ||
return entity.ToModel(); | ||
} | ||
|
||
private async Task<bool> IsNameDuplicateAsync(string name, string id, CancellationToken cancellationToken) | ||
{ | ||
return !await agentManager.IsNameUniqueAsync(name, id, cancellationToken); | ||
} | ||
} |
This file contains 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
31 changes: 31 additions & 0 deletions
31
src/modules/Elsa.Secrets.Management/Contracts/ISecretManager.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
namespace Elsa.Secrets.Management; | ||
|
||
public interface ISecretManager | ||
{ | ||
/// Adds a new entity to the store. | ||
Task AddAsync(Secret entity, CancellationToken cancellationToken = default); | ||
|
||
/// Updates the entity to the store. | ||
Task UpdateAsync(Secret entity, CancellationToken cancellationToken = default); | ||
|
||
/// Gets the entity from the store. | ||
Task<Secret?> GetAsync(string id, CancellationToken cancellationToken = default); | ||
|
||
/// Finds the entity from the store. | ||
Task<Secret?> FindAsync(SecretFilter filter, CancellationToken cancellationToken = default); | ||
|
||
/// Gets all entities from the store. | ||
Task<IEnumerable<Secret>> ListAsync(CancellationToken cancellationToken = default); | ||
|
||
/// Deletes the entity from the store. | ||
Task DeleteAsync(Secret entity, CancellationToken cancellationToken = default); | ||
|
||
/// Deletes all entities from the store matching the specified filter. | ||
Task<long> DeleteManyAsync(SecretFilter filter, CancellationToken cancellationToken = default); | ||
|
||
/// Generates a unique name. | ||
Task<string> GenerateUniqueNameAsync(CancellationToken cancellationToken = default); | ||
|
||
/// Checks if a name is unique. | ||
Task<bool> IsNameUniqueAsync(string name, string? notId, CancellationToken cancellationToken = default); | ||
} |
This file contains 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
Oops, something went wrong.