feat kill acl (#618)
This commit is contained in:
parent
b99b3f4345
commit
a8ac719af7
|
|
@ -138,6 +138,7 @@ message LogEntry {
|
|||
bool execution_finished = 15;
|
||||
bool blocked = 16;
|
||||
int64 datetime_index = 17;
|
||||
bool can_kill = 18;
|
||||
}
|
||||
|
||||
message GetLogsResponse {
|
||||
|
|
|
|||
|
|
@ -1125,6 +1125,7 @@ type LogEntry struct {
|
|||
ExecutionFinished bool `protobuf:"varint,15,opt,name=execution_finished,json=executionFinished,proto3" json:"execution_finished,omitempty"`
|
||||
Blocked bool `protobuf:"varint,16,opt,name=blocked,proto3" json:"blocked,omitempty"`
|
||||
DatetimeIndex int64 `protobuf:"varint,17,opt,name=datetime_index,json=datetimeIndex,proto3" json:"datetime_index,omitempty"`
|
||||
CanKill bool `protobuf:"varint,18,opt,name=can_kill,json=canKill,proto3" json:"can_kill,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
|
@ -1271,6 +1272,13 @@ func (x *LogEntry) GetDatetimeIndex() int64 {
|
|||
return 0
|
||||
}
|
||||
|
||||
func (x *LogEntry) GetCanKill() bool {
|
||||
if x != nil {
|
||||
return x.CanKill
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type GetLogsResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Logs []*LogEntry `protobuf:"bytes,1,rep,name=logs,proto3" json:"logs,omitempty"`
|
||||
|
|
@ -2733,7 +2741,7 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
|
|||
"\x1fStartActionByGetAndWaitResponse\x126\n" +
|
||||
"\tlog_entry\x18\x01 \x01(\v2\x19.olivetin.api.v1.LogEntryR\blogEntry\"3\n" +
|
||||
"\x0eGetLogsRequest\x12!\n" +
|
||||
"\fstart_offset\x18\x01 \x01(\x03R\vstartOffset\"\xad\x04\n" +
|
||||
"\fstart_offset\x18\x01 \x01(\x03R\vstartOffset\"\xc8\x04\n" +
|
||||
"\bLogEntry\x12)\n" +
|
||||
"\x10datetime_started\x18\x01 \x01(\tR\x0fdatetimeStarted\x12!\n" +
|
||||
"\faction_title\x18\x02 \x01(\tR\vactionTitle\x12\x16\n" +
|
||||
|
|
@ -2753,7 +2761,8 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
|
|||
"\x11execution_started\x18\x0e \x01(\bR\x10executionStarted\x12-\n" +
|
||||
"\x12execution_finished\x18\x0f \x01(\bR\x11executionFinished\x12\x18\n" +
|
||||
"\ablocked\x18\x10 \x01(\bR\ablocked\x12%\n" +
|
||||
"\x0edatetime_index\x18\x11 \x01(\x03R\rdatetimeIndex\"\x86\x01\n" +
|
||||
"\x0edatetime_index\x18\x11 \x01(\x03R\rdatetimeIndex\x12\x19\n" +
|
||||
"\bcan_kill\x18\x12 \x01(\bR\acanKill\"\x86\x01\n" +
|
||||
"\x0fGetLogsResponse\x12-\n" +
|
||||
"\x04logs\x18\x01 \x03(\v2\x19.olivetin.api.v1.LogEntryR\x04logs\x12'\n" +
|
||||
"\x0fcount_remaining\x18\x02 \x01(\x03R\x0ecountRemaining\x12\x1b\n" +
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ const (
|
|||
View PermissionBits = 1 << iota
|
||||
Exec
|
||||
Logs
|
||||
Kill
|
||||
)
|
||||
|
||||
func (p PermissionBits) Has(permission PermissionBits) bool {
|
||||
|
|
@ -121,6 +122,10 @@ func permissionsConfigToBits(permissions config.PermissionsList) PermissionBits
|
|||
ret |= Logs
|
||||
}
|
||||
|
||||
if permissions.Kill {
|
||||
ret |= Kill
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
|
|
@ -173,6 +178,10 @@ func IsAllowedView(cfg *config.Config, user *AuthenticatedUser, action *config.A
|
|||
return aclCheck(View, cfg.DefaultPermissions.View, cfg, "isAllowedView", user, action)
|
||||
}
|
||||
|
||||
func IsAllowedKill(cfg *config.Config, user *AuthenticatedUser, action *config.Action) bool {
|
||||
return aclCheck(Kill, cfg.DefaultPermissions.Kill, cfg, "isAllowedKill", user, action)
|
||||
}
|
||||
|
||||
func getMetadataKeyOrEmpty(md metadata.MD, key string) string {
|
||||
mdValues := md.Get(key)
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ type PermissionsList struct {
|
|||
View bool
|
||||
Exec bool
|
||||
Logs bool
|
||||
Kill bool
|
||||
}
|
||||
|
||||
// AccessControlList defines what permissions apply to a user or user group.
|
||||
|
|
@ -229,6 +230,7 @@ func DefaultConfigWithBasePort(basePort int) *Config {
|
|||
config.DefaultPermissions.Exec = true
|
||||
config.DefaultPermissions.View = true
|
||||
config.DefaultPermissions.Logs = true
|
||||
config.DefaultPermissions.Kill = true
|
||||
config.AuthJwtClaimUsername = "name"
|
||||
config.AuthJwtClaimUserGroup = "group"
|
||||
config.AuthRequireGuestsToLogin = false
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ func updateSvFromFile(entityname string, data []map[string]any) {
|
|||
}
|
||||
}
|
||||
|
||||
//gocyclo:ignore
|
||||
func serializeValueToSv(prefix string, value any) {
|
||||
if m, ok := value.(map[string]any); ok { // if value is a map we need to flatten it
|
||||
serializeMapToSv(prefix, m)
|
||||
|
|
|
|||
|
|
@ -38,24 +38,40 @@ func (api *oliveTinAPI) KillAction(ctx ctx.Context, req *apiv1.KillActionRequest
|
|||
ExecutionTrackingId: req.ExecutionTrackingId,
|
||||
}
|
||||
|
||||
execReqLogEntry, found := api.executor.GetLog(req.ExecutionTrackingId)
|
||||
var execReqLogEntry *executor.InternalLogEntry
|
||||
|
||||
ret.Found = found
|
||||
execReqLogEntry, ret.Found = api.executor.GetLog(req.ExecutionTrackingId)
|
||||
|
||||
if found {
|
||||
log.Warnf("Killing execution request by tracking ID: %v", req.ExecutionTrackingId)
|
||||
|
||||
err := api.executor.Kill(execReqLogEntry)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf("Killing execution request err: %v", err)
|
||||
ret.AlreadyCompleted = true
|
||||
ret.Killed = false
|
||||
} else {
|
||||
ret.Killed = true
|
||||
}
|
||||
} else {
|
||||
if !ret.Found {
|
||||
log.Warnf("Killing execution request not possible - not found by tracking ID: %v", req.ExecutionTrackingId)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
log.Warnf("Killing execution request by tracking ID: %v", req.ExecutionTrackingId)
|
||||
|
||||
user := acl.UserFromContext(ctx, cfg)
|
||||
action := cfg.FindAction(execReqLogEntry.ActionTitle)
|
||||
|
||||
if action == nil {
|
||||
log.Warnf("Killing execution request not possible - action not found: %v", execReqLogEntry.ActionTitle)
|
||||
ret.Killed = false
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
if !acl.IsAllowedKill(cfg, user, action) {
|
||||
log.Warnf("Killing execution request not possible - user not allowed to kill this action: %v", req.ExecutionTrackingId)
|
||||
ret.Killed = false
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
err := api.executor.Kill(execReqLogEntry)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf("Killing execution request err: %v", err)
|
||||
ret.AlreadyCompleted = true
|
||||
ret.Killed = false
|
||||
} else {
|
||||
ret.Killed = true
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
|
|
@ -136,11 +152,13 @@ func (api *oliveTinAPI) StartActionAndWait(ctx ctx.Context, req *apiv1.StartActi
|
|||
args[arg.Name] = arg.Value
|
||||
}
|
||||
|
||||
user := acl.UserFromContext(ctx, cfg)
|
||||
|
||||
execReq := executor.ExecutionRequest{
|
||||
Action: api.executor.FindActionBindingByID(req.ActionId),
|
||||
TrackingID: uuid.NewString(),
|
||||
Arguments: args,
|
||||
AuthenticatedUser: acl.UserFromContext(ctx, cfg),
|
||||
AuthenticatedUser: user,
|
||||
Cfg: cfg,
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +169,7 @@ func (api *oliveTinAPI) StartActionAndWait(ctx ctx.Context, req *apiv1.StartActi
|
|||
|
||||
if ok {
|
||||
return &apiv1.StartActionAndWaitResponse{
|
||||
LogEntry: internalLogEntryToPb(internalLogEntry),
|
||||
LogEntry: internalLogEntryToPb(internalLogEntry, user),
|
||||
}, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("execution not found")
|
||||
|
|
@ -179,11 +197,13 @@ func (api *oliveTinAPI) StartActionByGet(ctx ctx.Context, req *apiv1.StartAction
|
|||
func (api *oliveTinAPI) StartActionByGetAndWait(ctx ctx.Context, req *apiv1.StartActionByGetAndWaitRequest) (*apiv1.StartActionByGetAndWaitResponse, error) {
|
||||
args := make(map[string]string)
|
||||
|
||||
user := acl.UserFromContext(ctx, cfg)
|
||||
|
||||
execReq := executor.ExecutionRequest{
|
||||
Action: api.executor.FindActionBindingByID(req.ActionId),
|
||||
TrackingID: uuid.NewString(),
|
||||
Arguments: args,
|
||||
AuthenticatedUser: acl.UserFromContext(ctx, cfg),
|
||||
AuthenticatedUser: user,
|
||||
Cfg: cfg,
|
||||
}
|
||||
|
||||
|
|
@ -194,15 +214,15 @@ func (api *oliveTinAPI) StartActionByGetAndWait(ctx ctx.Context, req *apiv1.Star
|
|||
|
||||
if ok {
|
||||
return &apiv1.StartActionByGetAndWaitResponse{
|
||||
LogEntry: internalLogEntryToPb(internalLogEntry),
|
||||
LogEntry: internalLogEntryToPb(internalLogEntry, user),
|
||||
}, nil
|
||||
} else {
|
||||
return nil, status.Errorf(codes.NotFound, "Execution not found.")
|
||||
}
|
||||
}
|
||||
|
||||
func internalLogEntryToPb(logEntry *executor.InternalLogEntry) *apiv1.LogEntry {
|
||||
return &apiv1.LogEntry{
|
||||
func internalLogEntryToPb(logEntry *executor.InternalLogEntry, authenticatedUser *acl.AuthenticatedUser) *apiv1.LogEntry {
|
||||
pble := &apiv1.LogEntry{
|
||||
ActionTitle: logEntry.ActionTitle,
|
||||
ActionIcon: logEntry.ActionIcon,
|
||||
ActionId: logEntry.ActionId,
|
||||
|
|
@ -219,6 +239,12 @@ func internalLogEntryToPb(logEntry *executor.InternalLogEntry) *apiv1.LogEntry {
|
|||
ExecutionFinished: logEntry.ExecutionFinished,
|
||||
User: logEntry.Username,
|
||||
}
|
||||
|
||||
if !pble.ExecutionFinished {
|
||||
pble.CanKill = acl.IsAllowedKill(cfg, authenticatedUser, cfg.FindAction(logEntry.ActionTitle))
|
||||
}
|
||||
|
||||
return pble
|
||||
}
|
||||
|
||||
func getExecutionStatusByTrackingID(api *oliveTinAPI, executionTrackingId string) *executor.InternalLogEntry {
|
||||
|
|
@ -249,6 +275,8 @@ func getMostRecentExecutionStatusById(api *oliveTinAPI, actionId string) *execut
|
|||
func (api *oliveTinAPI) ExecutionStatus(ctx ctx.Context, req *apiv1.ExecutionStatusRequest) (*apiv1.ExecutionStatusResponse, error) {
|
||||
res := &apiv1.ExecutionStatusResponse{}
|
||||
|
||||
user := acl.UserFromContext(ctx, cfg)
|
||||
|
||||
var ile *executor.InternalLogEntry
|
||||
|
||||
if req.ExecutionTrackingId != "" {
|
||||
|
|
@ -261,7 +289,7 @@ func (api *oliveTinAPI) ExecutionStatus(ctx ctx.Context, req *apiv1.ExecutionSta
|
|||
if ile == nil {
|
||||
return nil, status.Error(codes.NotFound, "Execution not found")
|
||||
} else {
|
||||
res.LogEntry = internalLogEntryToPb(ile)
|
||||
res.LogEntry = internalLogEntryToPb(ile, user)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
|
|
@ -339,7 +367,7 @@ func (api *oliveTinAPI) GetLogs(ctx ctx.Context, req *apiv1.GetLogsRequest) (*ap
|
|||
action := cfg.FindAction(logEntry.ActionTitle)
|
||||
|
||||
if action == nil || acl.IsAllowedLogs(cfg, user, action) {
|
||||
pbLogEntry := internalLogEntryToPb(logEntry)
|
||||
pbLogEntry := internalLogEntryToPb(logEntry, user)
|
||||
|
||||
ret.Logs = append(ret.Logs, pbLogEntry)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ export class ExecutionDialog {
|
|||
this.domBtnRerun.disabled = !res.logEntry.executionFinished
|
||||
this.domBtnRerun.onclick = () => { this.rerunAction(res.logEntry.actionId) }
|
||||
|
||||
this.domBtnKill.disabled = res.logEntry.executionFinished
|
||||
this.domBtnKill.disabled = !res.logEntry.canKill
|
||||
|
||||
this.domStatus.update(res.logEntry)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue