@@ -276,7 +276,7 @@ func RunGraph(ctx context.Context, graphName string, graphContent []byte, opts R
276276 return CreateErr (nil , err , "failed to load yaml" )
277277 }
278278
279- ag , errs := LoadGraph (graphYaml , nil , "" , false )
279+ ag , errs := LoadGraph (graphYaml , nil , "" , false , opts )
280280 if len (errs ) > 0 {
281281 return CreateErr (nil , errs [0 ], "failed to load graph" )
282282 }
@@ -287,8 +287,23 @@ func RunGraph(ctx context.Context, graphName string, graphContent []byte, opts R
287287 }
288288
289289 entryNode , isBaseNode := entry .(NodeBaseInterface )
290- isGitHubAction := os .Getenv ("GITHUB_ACTIONS" ) == "true"
291- isGitHubWorkflow := isBaseNode && entryNode .GetNodeTypeId () == "core/gh-start@v1"
290+
291+ // isGitHubActions: Determines if this run should behave as a GitHub Action.
292+ // True when either running on actual GitHub Actions (system env), or an external
293+ // caller (e.g., web app) explicitly requests GitHub Actions behavior via OverrideEnv.
294+ // This affects input variable handling, context loading, and other GitHub-specific behavior.
295+ //
296+ // **Important** we haven't loaded the config file yet, so we can only look at overriden envs,
297+ // .env (already set in os.GetEnv) or shell.
298+ isGitHubActions := opts .OverrideEnv ["GITHUB_ACTIONS" ] == "true" || os .Getenv ("GITHUB_ACTIONS" ) == "true" || entryNode .GetNodeTypeId () == "core/gh-start@v1"
299+
300+ // mimickGitHubEnv: Determines if we need to set up a simulated GitHub environment. The easiest
301+ // approach for now is to just check a bunch of env vars. The user may have set one or the other
302+ // (through .env or shell) but unlikely all of them but they are by a real GitHub Actions runner.
303+ mimickGitHubEnv := isGitHubActions && os .Getenv ("GITHUB_RUN_ID" ) == "" &&
304+ os .Getenv ("RUNNER_TEMP" ) == "" &&
305+ os .Getenv ("GITHUB_API_URL" ) == "" &&
306+ os .Getenv ("GITHUB_RETENTION_DAYS" ) == ""
292307
293308 // Initialize trackers with their respective categories
294309 envTracker := newValueMap [string ]("env" )
@@ -301,19 +316,21 @@ func RunGraph(ctx context.Context, graphName string, graphContent []byte, opts R
301316 if opts .ConfigFile != "" {
302317 if _ , err := os .Stat (opts .ConfigFile ); err == nil {
303318 localConfig , err := utils .LoadConfig (opts .ConfigFile )
304- if err == nil {
305- configName := filepath .Base (opts .ConfigFile )
306- envTracker .set (localConfig .Env , configName , true , false )
307- inputTracker .set (localConfig .Inputs , configName , true , false )
308- secretTracker .set (localConfig .Secrets , configName , true , true )
319+ if err != nil {
320+ return CreateErr (nil , err , "failed to load config file" )
309321 }
322+
323+ configName := filepath .Base (opts .ConfigFile )
324+ envTracker .set (localConfig .Env , configName , true , false )
325+ inputTracker .set (localConfig .Inputs , configName , true , false )
326+ secretTracker .set (localConfig .Secrets , configName , true , true )
310327 }
311328 }
312329
313330 rawEnv := utils .GetAllEnvMapCopy ()
314331
315332 // normalize all inputs/secrets with ACT_* iif we're in GitHub
316- if isGitHubWorkflow {
333+ if isGitHubActions {
317334 prefixedRawEnv := make (map [string ]utils.EnvKV )
318335 for k , v := range rawEnv {
319336 prefixedKey := k
@@ -366,15 +383,15 @@ func RunGraph(ctx context.Context, graphName string, graphContent []byte, opts R
366383 secretTracker .setSingle (key , v .Value , fmt .Sprintf ("%s (%s)" , source , k ), true , true )
367384
368385 // GitHub specifics
369- case isGitHubWorkflow && k == "ACT_INPUT_MATRIX" :
386+ case isGitHubActions && k == "ACT_INPUT_MATRIX" :
370387 if m , err := decodeJsonFromEnvValue [any ](v .Value ); err == nil {
371388 matrixTracker .set (m , source , true , true )
372389 }
373- case isGitHubWorkflow && k == "ACT_INPUT_NEEDS" :
390+ case isGitHubActions && k == "ACT_INPUT_NEEDS" :
374391 if m , err := decodeJsonFromEnvValue [any ](v .Value ); err == nil {
375392 needsTracker .set (m , source , true , true )
376393 }
377- case isGitHubWorkflow && k == "ACT_INPUT_TOKEN" :
394+ case isGitHubActions && k == "ACT_INPUT_TOKEN" :
378395 secretTracker .setSingle ("GITHUB_TOKEN" , v .Value , source , true , true )
379396
380397 default :
@@ -413,7 +430,7 @@ func RunGraph(ctx context.Context, graphName string, graphContent []byte, opts R
413430 }()
414431 }
415432
416- if ! isGitHubAction && isGitHubWorkflow {
433+ if mimickGitHubEnv {
417434 // If we are running a github actions workflow, then mimic a GitHub Actions environment
418435 // But only do is if we are NOT already in GitHub Actions
419436 err = SetupGitHubActionsEnv (finalEnv )
@@ -439,7 +456,7 @@ func RunGraph(ctx context.Context, graphName string, graphContent []byte, opts R
439456 // construct the `github` context
440457 var ghContext map [string ]any
441458 var errGh error
442- if isGitHubWorkflow {
459+ if isGitHubActions {
443460 ghContext , errGh = LoadGitHubContext (finalEnv , finalInputs , finalSecrets )
444461 if errGh != nil {
445462 return CreateErr (nil , errGh , "failed to load github context" )
@@ -450,7 +467,7 @@ func RunGraph(ctx context.Context, graphName string, graphContent []byte, opts R
450467 ctx ,
451468 & ag ,
452469 graphName ,
453- isGitHubWorkflow ,
470+ isGitHubActions ,
454471 debugCb ,
455472 finalEnv ,
456473 finalInputs ,
@@ -467,7 +484,7 @@ func RunGraph(ctx context.Context, graphName string, graphContent []byte, opts R
467484 return entry .ExecuteEntry (c , nil , opts .Args )
468485}
469486
470- func LoadGraph (graphYaml map [string ]any , parent NodeBaseInterface , parentId string , validate bool ) (ActionGraph , []error ) {
487+ func LoadGraph (graphYaml map [string ]any , parent NodeBaseInterface , parentId string , validate bool , opts RunOpts ) (ActionGraph , []error ) {
471488
472489 var (
473490 collectedErrors []error
@@ -492,7 +509,7 @@ func LoadGraph(graphYaml map[string]any, parent NodeBaseInterface, parentId stri
492509 collectedErrors = append (collectedErrors , err )
493510 }
494511
495- err = LoadNodes (& ag , parent , parentId , graphYaml , validate , & collectedErrors )
512+ err = LoadNodes (& ag , parent , parentId , graphYaml , validate , & collectedErrors , opts )
496513 if err != nil && ! validate {
497514 return ActionGraph {}, []error {err }
498515 }
@@ -570,14 +587,14 @@ func anyToPortDefinition[T any](o any) (T, error) {
570587 return ret , err
571588}
572589
573- func LoadNodes (ag * ActionGraph , parent NodeBaseInterface , parentId string , nodesYaml map [string ]any , validate bool , errs * []error ) error {
590+ func LoadNodes (ag * ActionGraph , parent NodeBaseInterface , parentId string , nodesYaml map [string ]any , validate bool , errs * []error , opts RunOpts ) error {
574591 nodesList , err := utils .GetTypedPropertyByPath [[]any ](nodesYaml , "nodes" )
575592 if err != nil {
576593 return collectOrReturn (err , validate , errs )
577594 }
578595
579596 for _ , nodeData := range nodesList {
580- n , id , err := LoadNode (parent , parentId , nodeData , validate , errs )
597+ n , id , err := LoadNode (parent , parentId , nodeData , validate , errs , opts )
581598 if err != nil {
582599 return err
583600 }
@@ -592,7 +609,7 @@ func LoadNodes(ag *ActionGraph, parent NodeBaseInterface, parentId string, nodes
592609 return nil
593610}
594611
595- func LoadNode (parent NodeBaseInterface , parentId string , nodeData any , validate bool , errs * []error ) (NodeBaseInterface , string , error ) {
612+ func LoadNode (parent NodeBaseInterface , parentId string , nodeData any , validate bool , errs * []error , opts RunOpts ) (NodeBaseInterface , string , error ) {
596613 nodeI , ok := nodeData .(map [string ]any )
597614 if ! ok {
598615 err := CreateErr (nil , nil , "node is not a map" )
@@ -635,9 +652,9 @@ func LoadNode(parent NodeBaseInterface, parentId string, nodeData any, validate
635652 fullPath = parentId + "/" + id
636653 }
637654 if strings .HasPrefix (nodeType , "github.com/" ) {
638- n , factoryErrs = NewGhActionNode (nodeType , parent , fullPath , validate )
655+ n , factoryErrs = NewGhActionNode (nodeType , parent , fullPath , validate , opts )
639656 } else {
640- n , factoryErrs = NewNodeInstance (nodeType , parent , fullPath , nodeI , validate )
657+ n , factoryErrs = NewNodeInstance (nodeType , parent , fullPath , nodeI , validate , opts )
641658 }
642659
643660 if len (factoryErrs ) > 0 {
0 commit comments