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
106 changes: 100 additions & 6 deletions ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -5122,16 +5122,16 @@

responseBody := []byte{}

_, statErr := os.Stat(appPath)

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
This path depends on a
user-provided value
.
if statErr == nil {
// File exists, read it
file, err := os.Open(appPath)

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
This path depends on a
user-provided value
.
if err != nil {
return returnApp, openapiDef, err
}

defer file.Close()
responseBody, err = os.ReadFile(appPath)

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
This path depends on a
user-provided value
.
if err != nil {
log.Printf("[ERROR] Error reading file: %s", err)
return returnApp, openapiDef, err
Expand Down Expand Up @@ -5251,7 +5251,7 @@
// What a mess :)
// What it does is to download the file. That's it.
scriptPath := fmt.Sprintf("%s/scripts/%s.py", sourcepath, searchname)
_, statErr := os.Stat(scriptPath)

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
This path depends on a
user-provided value
.
if statErr != nil {
req, err := http.NewRequest(
"GET",
Expand All @@ -5273,7 +5273,7 @@
if err != nil {
log.Printf("[ERROR] Failed reading body for singul app script: %s", err)
} else {
err = os.WriteFile(scriptPath, scriptBody, 0644)

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
This path depends on a
user-provided value
.
if err != nil {
log.Printf("[ERROR] Error writing file: %s", err)
}
Expand All @@ -5295,7 +5295,7 @@
//return parsedApp, err
}

err = os.WriteFile(appPath, responseBody, 0644)

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.
This path depends on a
user-provided value
.
if err != nil {
log.Printf("[ERROR] Error writing file: %s", err)
return &parsedApp, openapiDef, err
Expand Down Expand Up @@ -8755,6 +8755,23 @@
log.Printf("[ERROR] AI Agent (2): Failed unmarshalling response into decisions. Response from sending AI Agent request to %s: %d - '%s'. Err: %s", fullUrl, llmStatusCode, string(body), err)
}

// Fallback: if resultMapping.Result is still empty after standard unmarshal, the Shuffle HTTP wrapper may have returned the "result" field as a raw nested JSON object (not a properly-escaped string), which causes Go's JSON decoder to skip the field entirely. Extract it via json.RawMessage so we get the bytes regardless of whether the value is a string or a nested object.
if len(resultMapping.Result) == 0 && len(body) > 0 {
rawMap := map[string]json.RawMessage{}
if jsonErr := json.Unmarshal(body, &rawMap); jsonErr == nil {
if rawResult, ok := rawMap["result"]; ok && len(rawResult) > 0 {
// If the raw value is a JSON string, unquote it to get the inner content. If it is an object/array, use it directly as a string.
var strVal string
if jsonErr2 := json.Unmarshal(rawResult, &strVal); jsonErr2 == nil && len(strVal) > 0 {
resultMapping.Result = strVal
} else {
// The value is a raw JSON object/array — use it directly as the result string.
resultMapping.Result = string(rawResult)
}
}
}
}

resultMapping.ExecutionId = execution.ExecutionId
resultMapping.Authorization = execution.Authorization
// Waiting 3
Expand Down Expand Up @@ -12274,6 +12291,22 @@
return workflow, nil
}

func isSensitiveParameter(paramName string) bool {
lowerName := strings.ToLower(strings.TrimSpace(paramName))
sensitiveKeywords := []string{
"apikey", "api_key", "key", "token", "password", "secret",
"auth", "credential", "authorization", "bearer", "api",
"privatekey", "private_key", "accesskey", "access_key",
"secretkey", "secret_key", "clientsecret", "client_secret",
}
for _, keyword := range sensitiveKeywords {
if strings.Contains(lowerName, keyword) {
return true
}
}
return false
}

func buildMinimalWorkflow(w *Workflow) *MinimalWorkflow {
if w == nil {
return nil
Expand All @@ -12283,45 +12316,106 @@
for _, a := range w.Actions {
var params []MinimalParameter
for _, p := range a.Parameters {
params = append(params, MinimalParameter{Name: p.Name, Value: p.Value})
paramValue := p.Value
// Redact sensitive parameter values
if isSensitiveParameter(p.Name) {
paramValue = "[REDACTED]"
}
params = append(params, MinimalParameter{Name: p.Name, Value: paramValue})
}

// Check if this action is the start node
isStart := false
if len(w.Start) > 0 && w.Start == a.ID {
isStart = true
}
// Also check the IsStartNode field on the action itself
if a.IsStartNode {
isStart = true
}

minActs = append(minActs, MinimalAction{
AppName: a.AppName,
AppID: a.AppID,
ID: a.ID,
Label: a.Label,
Name: a.Name,
Parameters: params,
Errors: a.Errors,
X: int64(a.Position.X),
Y: int64(a.Position.Y),
IsStart: isStart,
})
}

var minBrs []MinimalBranch
for _, b := range w.Branches {
var minConditions []MinimalCondition
for _, cond := range b.Conditions {
minConditions = append(minConditions, MinimalCondition{
Source: MinimalConditionParam{
ID: cond.Source.ID,
Name: cond.Source.Name,
Value: cond.Source.Value,
},
Condition: MinimalConditionParam{
ID: cond.Condition.ID,
Name: cond.Condition.Name,
Value: cond.Condition.Value,
},
Destination: MinimalConditionParam{
ID: cond.Destination.ID,
Name: cond.Destination.Name,
Value: cond.Destination.Value,
},
})
}

minBrs = append(minBrs, MinimalBranch{
ID: b.ID,
SourceID: b.SourceID,
DestinationID: b.DestinationID,
Label: b.Label,
Conditions: minConditions,
})
}

var minTrigs []MinimalTrigger
startTriggerID := ""
for _, t := range w.Triggers {
var params []MinimalParameter
for _, p := range t.Parameters {
params = append(params, MinimalParameter{Name: p.Name, Value: p.Value})
paramValue := p.Value
// Redact sensitive parameter values
if isSensitiveParameter(p.Name) {
paramValue = "[REDACTED]"
}
params = append(params, MinimalParameter{Name: p.Name, Value: paramValue})
}

isStart := false
if len(w.Start) > 0 && w.Start == t.ID {
isStart = true
startTriggerID = t.ID
}

minTrigs = append(minTrigs, MinimalTrigger{
ID: t.ID,
AppName: t.AppName,
Label: t.Label,
Parameters: params,
X: int64(t.Position.X),
Y: int64(t.Position.Y),
IsStart: isStart,
})
}

return &MinimalWorkflow{
Actions: minActs,
Branches: minBrs,
Triggers: minTrigs,
Errors: w.Errors,
Actions: minActs,
Branches: minBrs,
Triggers: minTrigs,
Errors: w.Errors,
StartTriggerID: startTriggerID,
}
}

Expand Down
4 changes: 2 additions & 2 deletions blobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import (
func IsShuffleApp(app WorkflowApp) bool {
parsedAppname := strings.ReplaceAll(strings.ToLower(app.Name), " ", "_")

skipAuthAppnames := []string{"openai", "shuffle_datastore", "shuffle_workflows", "shuffle_detection", "shuffle_sensors", "shuffle_monitors", "shuffle_host_monitors"}
skipAuthAppIds := []string{"5d19dd82517870c68d40cacad9b5ca91", "b82668d868f6dc7ac1dc14caa92c674b", "b598b078fd5c531699fca803c172ce72", "afda48b8d1f7dc7ac3caae87b2c072e9", "7f12d725c356677d28db042170444448", "48a954b9440b3913b8a2620e57b94a75"}
skipAuthAppnames := []string{"openai", "shuffle_datastore", "shuffle_workflows", "shuffle_detection", "shuffle_sensors", "shuffle_monitors", "shuffle_host_monitors", "shuffles_app_management"}
skipAuthAppIds := []string{"5d19dd82517870c68d40cacad9b5ca91", "b82668d868f6dc7ac1dc14caa92c674b", "b598b078fd5c531699fca803c172ce72", "afda48b8d1f7dc7ac3caae87b2c072e9", "7f12d725c356677d28db042170444448", "48a954b9440b3913b8a2620e57b94a75", "605e31b19889e38f179fab112297eb42"}

isShuffleApp := false
if project.Environment == "cloud" && len(app.ID) > 0 {
Expand Down
Loading
Loading