From b3565d0645f758a05c74500cd56a327785d89275 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 06:37:02 +0000 Subject: [PATCH 01/17] Initial plan From ce8b3ef848b71436bfc53e2e2766426d84b1f31f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 07:07:54 +0000 Subject: [PATCH 02/17] feat: add safe-output actions support for mounting custom GitHub Actions as MCP tools Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../setup/js/safe_output_action_handler.cjs | 102 ++++ .../setup/js/safe_output_handler_manager.cjs | 31 +- actions/setup/js/safe_output_helpers.cjs | 32 ++ pkg/workflow/compiler_safe_outputs_job.go | 21 +- pkg/workflow/compiler_safe_outputs_steps.go | 7 + pkg/workflow/compiler_types.go | 1 + pkg/workflow/safe_outputs_actions.go | 447 ++++++++++++++++++ pkg/workflow/safe_outputs_actions_test.go | 417 ++++++++++++++++ pkg/workflow/safe_outputs_config.go | 8 + pkg/workflow/safe_outputs_state.go | 11 + pkg/workflow/safe_outputs_tools_filtering.go | 39 +- 11 files changed, 1113 insertions(+), 3 deletions(-) create mode 100644 actions/setup/js/safe_output_action_handler.cjs create mode 100644 pkg/workflow/safe_outputs_actions.go create mode 100644 pkg/workflow/safe_outputs_actions_test.go diff --git a/actions/setup/js/safe_output_action_handler.cjs b/actions/setup/js/safe_output_action_handler.cjs new file mode 100644 index 0000000000..836d04c0b2 --- /dev/null +++ b/actions/setup/js/safe_output_action_handler.cjs @@ -0,0 +1,102 @@ +// @ts-check +/// + +/** + * @typedef {import('./types/handler-factory').HandlerFactoryFunction} HandlerFactoryFunction + */ + +const { replaceTemporaryIdReferences } = require("./temporary_id.cjs"); +const { getErrorMessage } = require("./error_helpers.cjs"); + +/** + * Main handler factory for a custom safe output action. + * + * Each configured safe-output action gets its own instance of this factory function, + * invoked with a config that includes `action_name` (the normalized tool name). + * + * The handler: + * 1. Enforces that the action is called at most once (per the spec). + * 2. Applies temporary ID substitutions to all string-valued fields in the payload. + * 3. Exports the processed payload as a step output named `action__payload`. + * + * The compiler generates a corresponding GitHub Actions step with: + * if: steps.process_safe_outputs.outputs.action__payload != '' + * uses: + * with: + * : ${{ fromJSON(steps.process_safe_outputs.outputs.action__payload). }} + * + * @type {HandlerFactoryFunction} + */ +async function main(config = {}) { + const actionName = config.action_name || "unknown_action"; + const outputKey = `action_${actionName}_payload`; + + core.info(`Custom action handler initialized: action_name=${actionName}, output_key=${outputKey}`); + + // Track whether this action has been called (enforces once-only constraint) + let called = false; + + /** + * Handler function that processes a single tool call for this action. + * Applies temporary ID substitutions and exports the payload as a step output. + * + * @param {Object} message - The tool call message from the agent output + * @param {Object} resolvedTemporaryIds - Map of temp IDs to resolved values (plain object) + * @param {Map} temporaryIdMap - Live map of temporary IDs (for substitution) + * @returns {Promise} Result with success/error status + */ + return async function handleCustomAction(message, resolvedTemporaryIds, temporaryIdMap) { + // Enforce once-only constraint + if (called) { + const error = `Action "${actionName}" can only be called once per workflow run`; + core.warning(error); + return { + success: false, + error, + }; + } + called = true; + + try { + core.info(`Processing custom action: ${actionName}`); + + // Build the processed payload by applying temporary ID substitutions to all + // string-valued fields. Non-string fields (numbers, booleans, objects, arrays) + // are passed through as-is. + const processedInputs = {}; + for (const [key, value] of Object.entries(message)) { + // Skip internal fields that are not action inputs + if (key === "type") { + continue; + } + + if (typeof value === "string") { + // Apply temporary ID reference substitution (e.g., "aw_abc1" → "42") + processedInputs[key] = replaceTemporaryIdReferences(value, temporaryIdMap); + } else { + processedInputs[key] = value; + } + } + + // Export the processed payload as a step output + const payloadJSON = JSON.stringify(processedInputs); + core.setOutput(outputKey, payloadJSON); + core.info(`✓ Custom action "${actionName}": exported payload as "${outputKey}" (${payloadJSON.length} bytes)`); + + return { + success: true, + action_name: actionName, + payload: payloadJSON, + }; + } catch (error) { + const errorMessage = getErrorMessage(error); + core.error(`Failed to process custom action "${actionName}": ${errorMessage}`); + return { + success: false, + error: `Failed to process custom action "${actionName}": ${errorMessage}`, + }; + } + }; +} + +module.exports = { main }; diff --git a/actions/setup/js/safe_output_handler_manager.cjs b/actions/setup/js/safe_output_handler_manager.cjs index b7a4fea575..e3a696e814 100644 --- a/actions/setup/js/safe_output_handler_manager.cjs +++ b/actions/setup/js/safe_output_handler_manager.cjs @@ -20,7 +20,7 @@ const { getIssuesToAssignCopilot } = require("./create_issue.cjs"); const { createReviewBuffer } = require("./pr_review_buffer.cjs"); const { sanitizeContent } = require("./sanitize_content.cjs"); const { createManifestLogger, ensureManifestExists, extractCreatedItemFromResult } = require("./safe_output_manifest.cjs"); -const { loadCustomSafeOutputJobTypes, loadCustomSafeOutputScriptHandlers } = require("./safe_output_helpers.cjs"); +const { loadCustomSafeOutputJobTypes, loadCustomSafeOutputScriptHandlers, loadCustomSafeOutputActionHandlers } = require("./safe_output_helpers.cjs"); const { emitSafeOutputActionOutputs } = require("./safe_outputs_action_outputs.cjs"); /** @@ -194,6 +194,35 @@ async function loadHandlers(config, prReviewBuffer) { } } + // Load custom action handlers from GH_AW_SAFE_OUTPUT_ACTIONS + // These are GitHub Actions configured in safe-outputs.actions. The handler applies + // temporary ID substitutions to the payload and exports `action__payload` outputs + // that compiler-generated `uses:` steps consume. + const customActionHandlers = loadCustomSafeOutputActionHandlers(); + if (customActionHandlers.size > 0) { + core.info(`Loading ${customActionHandlers.size} custom action handler(s): ${[...customActionHandlers.keys()].join(", ")}`); + const actionHandlerPath = require("path").join(__dirname, "safe_output_action_handler.cjs"); + for (const [actionType, actionName] of customActionHandlers) { + try { + const actionModule = require(actionHandlerPath); + if (actionModule && typeof actionModule.main === "function") { + const handlerConfig = { action_name: actionName, ...(config[actionType] || {}) }; + const messageHandler = await actionModule.main(handlerConfig); + if (typeof messageHandler !== "function") { + core.warning(`✗ Custom action handler ${actionType} main() did not return a function (got ${typeof messageHandler}) — this handler will be skipped`); + } else { + messageHandlers.set(actionType, messageHandler); + core.info(`✓ Loaded and initialized custom action handler for: ${actionType}`); + } + } else { + core.warning(`Custom action handler module does not export a main function — skipping ${actionType}`); + } + } catch (error) { + core.warning(`Failed to load custom action handler for ${actionType}: ${getErrorMessage(error)} — this handler will be skipped`); + } + } + } + core.info(`Loaded ${messageHandlers.size} handler(s)`); return messageHandlers; } diff --git a/actions/setup/js/safe_output_helpers.cjs b/actions/setup/js/safe_output_helpers.cjs index 6fe9dc01c3..d178fb75c3 100644 --- a/actions/setup/js/safe_output_helpers.cjs +++ b/actions/setup/js/safe_output_helpers.cjs @@ -363,12 +363,44 @@ function loadCustomSafeOutputScriptHandlers() { } } +/** + * Load custom safe output action handlers from environment variable. + * These are GitHub Actions configured in safe-outputs.actions that are processed + * by compiler-injected `uses:` steps after the handler manager exports their payloads. + * The handler manager processes the tool call, applies temporary ID substitutions, + * and exports `action__payload` outputs that the injected steps consume. + * @returns {Map} Map of normalized action type name to action name (for handler config) + */ +function loadCustomSafeOutputActionHandlers() { + const safeOutputActionsEnv = process.env.GH_AW_SAFE_OUTPUT_ACTIONS; + if (!safeOutputActionsEnv) { + return new Map(); + } + + try { + const safeOutputActions = JSON.parse(safeOutputActionsEnv); + // The environment variable is a map of normalized action names to themselves + const actionHandlers = new Map(Object.entries(safeOutputActions)); + if (typeof core !== "undefined") { + core.debug(`Loaded ${actionHandlers.size} custom safe output action handler(s): ${[...actionHandlers.keys()].join(", ")}`); + } + return actionHandlers; + } catch (error) { + if (typeof core !== "undefined") { + const { getErrorMessage } = require("./error_helpers.cjs"); + core.warning(`Failed to parse GH_AW_SAFE_OUTPUT_ACTIONS: ${getErrorMessage(error)}`); + } + return new Map(); + } +} + module.exports = { parseAllowedItems, parseMaxCount, resolveTarget, loadCustomSafeOutputJobTypes, loadCustomSafeOutputScriptHandlers, + loadCustomSafeOutputActionHandlers, resolveIssueNumber, extractAssignees, matchesBlockedPattern, diff --git a/pkg/workflow/compiler_safe_outputs_job.go b/pkg/workflow/compiler_safe_outputs_job.go index fa84c71518..528fe28401 100644 --- a/pkg/workflow/compiler_safe_outputs_job.go +++ b/pkg/workflow/compiler_safe_outputs_job.go @@ -149,7 +149,8 @@ func (c *Compiler) buildConsolidatedSafeOutputsJob(data *WorkflowData, mainJobNa data.SafeOutputs.AutofixCodeScanningAlert != nil || data.SafeOutputs.MissingTool != nil || data.SafeOutputs.MissingData != nil || - len(data.SafeOutputs.Scripts) > 0 // Custom scripts run in the handler loop + len(data.SafeOutputs.Scripts) > 0 || // Custom scripts run in the handler loop + len(data.SafeOutputs.Actions) > 0 // Custom actions need handler to export their payloads // Note: All project-related operations are now handled by the unified handler. // The project handler manager has been removed. @@ -222,6 +223,24 @@ func (c *Compiler) buildConsolidatedSafeOutputsJob(data *WorkflowData, mainJobNa outputs["create_agent_session_session_url"] = "${{ steps.create_agent_session.outputs.session_url }}" } + // 5. Custom action steps — compiler-generated steps for each configured safe-output action. + // These steps run after the handler manager, which processes the agent payload and exports + // a JSON payload output for each action tool call. Each step is guarded by an `if:` condition + // that checks whether the handler manager exported a payload for this action. + if len(data.SafeOutputs.Actions) > 0 { + // Resolve action.yml for all actions (fetches inputs/descriptions at compile time) + c.resolveAllActions(data, markdownPath) + + actionStepYAML := c.buildActionSteps(data) + steps = append(steps, actionStepYAML...) + + // Register each action as having a handler manager output + for actionName := range data.SafeOutputs.Actions { + normalizedName := stringutil.NormalizeSafeOutputIdentifier(actionName) + safeOutputStepNames = append(safeOutputStepNames, "action_"+normalizedName) + } + } + // The outputs and permissions are configured in the handler manager section above if data.SafeOutputs.AddReviewer != nil { outputs["add_reviewer_reviewers_added"] = "${{ steps.process_safe_outputs.outputs.reviewers_added }}" diff --git a/pkg/workflow/compiler_safe_outputs_steps.go b/pkg/workflow/compiler_safe_outputs_steps.go index 438360066d..3ebd872716 100644 --- a/pkg/workflow/compiler_safe_outputs_steps.go +++ b/pkg/workflow/compiler_safe_outputs_steps.go @@ -349,6 +349,13 @@ func (c *Compiler) buildHandlerManagerStep(data *WorkflowData) []string { consolidatedSafeOutputsStepsLog.Print("Added GH_AW_SAFE_OUTPUT_SCRIPTS env var for custom script handlers") } + // Add GH_AW_SAFE_OUTPUT_ACTIONS so the handler manager can load custom action handlers. + // The env var maps normalized action names to themselves (reserved for future extensibility). + if customActionsJSON := buildCustomSafeOutputActionsJSON(data); customActionsJSON != "" { + steps = append(steps, fmt.Sprintf(" GH_AW_SAFE_OUTPUT_ACTIONS: %q\n", customActionsJSON)) + consolidatedSafeOutputsStepsLog.Print("Added GH_AW_SAFE_OUTPUT_ACTIONS env var for custom action handlers") + } + // Add custom safe output env vars c.addCustomSafeOutputEnvVars(&steps, data) diff --git a/pkg/workflow/compiler_types.go b/pkg/workflow/compiler_types.go index 71c2b86ee9..eb3cba6662 100644 --- a/pkg/workflow/compiler_types.go +++ b/pkg/workflow/compiler_types.go @@ -502,6 +502,7 @@ type SafeOutputsConfig struct { IDToken *string `yaml:"id-token,omitempty"` // Override id-token permission: "write" to force-add, "none" to disable auto-detection ConcurrencyGroup string `yaml:"concurrency-group,omitempty"` // Concurrency group for the safe-outputs job (cancel-in-progress is always false) Environment string `yaml:"environment,omitempty"` // Override the GitHub deployment environment for the safe-outputs job (defaults to the top-level environment: field) + Actions map[string]*SafeOutputActionConfig `yaml:"actions,omitempty"` // Custom GitHub Actions mounted as safe output tools (resolved at compile time) AutoInjectedCreateIssue bool `yaml:"-"` // Internal: true when create-issues was automatically injected by the compiler (not user-configured) } diff --git a/pkg/workflow/safe_outputs_actions.go b/pkg/workflow/safe_outputs_actions.go new file mode 100644 index 0000000000..ff4d836425 --- /dev/null +++ b/pkg/workflow/safe_outputs_actions.go @@ -0,0 +1,447 @@ +package workflow + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + "time" + + "github.com/github/gh-aw/pkg/logger" + "github.com/github/gh-aw/pkg/stringutil" + "go.yaml.in/yaml/v3" +) + +var safeOutputActionsLog = logger.New("workflow:safe_outputs_actions") + +// SafeOutputActionConfig holds configuration for a single custom safe output action. +// Each configured action is resolved at compile time to get its inputs from action.yml, +// and is mounted as an MCP tool that the AI agent can call once per workflow run. +type SafeOutputActionConfig struct { + Uses string `yaml:"uses"` + Description string `yaml:"description,omitempty"` // optional override of the action's description + + // Computed at compile time (not from frontmatter): + ResolvedRef string `yaml:"-"` // Pinned action reference (e.g., "owner/repo@sha # v1") + Inputs map[string]*ActionYAMLInput `yaml:"-"` // Inputs parsed from action.yml + ActionDescription string `yaml:"-"` // Description from action.yml +} + +// ActionYAMLInput holds an input definition parsed from a GitHub Action's action.yml. +type ActionYAMLInput struct { + Description string `yaml:"description,omitempty"` + Required bool `yaml:"required,omitempty"` + Default string `yaml:"default,omitempty"` +} + +// actionYAMLFile is the parsed structure of a GitHub Action's action.yml. +type actionYAMLFile struct { + Name string `yaml:"name"` + Description string `yaml:"description"` + Inputs map[string]*ActionYAMLInput `yaml:"inputs"` +} + +// actionRef holds the parsed components of a GitHub Action `uses` field. +type actionRef struct { + // Repo is the GitHub repository slug (e.g., "owner/repo"). + Repo string + // Subdir is the sub-directory within the repository (e.g., "path/to/action"). + // Empty string means the action.yml is at the repository root. + Subdir string + // Ref is the git ref (tag, SHA, or branch) to checkout (e.g., "v1", "main"). + Ref string + // IsLocal is true when the `uses` value is a local path (e.g., "./path/to/action"). + IsLocal bool + // LocalPath is the filesystem path (only set when IsLocal is true). + LocalPath string +} + +// parseActionsConfig parses the safe-outputs.actions section from a raw frontmatter map. +// It returns a map of action names to their configurations. +func parseActionsConfig(actionsMap map[string]any) map[string]*SafeOutputActionConfig { + if actionsMap == nil { + return nil + } + + result := make(map[string]*SafeOutputActionConfig) + for actionName, actionValue := range actionsMap { + actionConfigMap, ok := actionValue.(map[string]any) + if !ok { + safeOutputActionsLog.Printf("Warning: action %q config is not a map, skipping", actionName) + continue + } + + actionConfig := &SafeOutputActionConfig{} + + if uses, ok := actionConfigMap["uses"].(string); ok { + actionConfig.Uses = uses + } + if description, ok := actionConfigMap["description"].(string); ok { + actionConfig.Description = description + } + + if actionConfig.Uses == "" { + safeOutputActionsLog.Printf("Warning: action %q is missing required 'uses' field, skipping", actionName) + continue + } + + result[actionName] = actionConfig + } + + return result +} + +// parseActionUsesField parses a GitHub Action `uses` field into its components. +// Supported formats: +// - "owner/repo@ref" -> repo root action +// - "owner/repo/subdir@ref" -> sub-directory action +// - "./local/path" -> local filesystem action +func parseActionUsesField(uses string) (*actionRef, error) { + if strings.HasPrefix(uses, "./") || strings.HasPrefix(uses, "../") { + return &actionRef{IsLocal: true, LocalPath: uses}, nil + } + + // External action: split on "@" to get ref + atIdx := strings.LastIndex(uses, "@") + if atIdx < 0 { + return nil, fmt.Errorf("invalid action ref %q: missing @ref suffix", uses) + } + + refStr := uses[atIdx+1:] + repoAndPath := uses[:atIdx] + + // Split repo from subdir: first two path segments are owner/repo + parts := strings.SplitN(repoAndPath, "/", 3) + if len(parts) < 2 { + return nil, fmt.Errorf("invalid action ref %q: expected owner/repo format", uses) + } + + repo := parts[0] + "/" + parts[1] + var subdir string + if len(parts) == 3 { + subdir = parts[2] + } + + return &actionRef{ + Repo: repo, + Subdir: subdir, + Ref: refStr, + }, nil +} + +// fetchAndParseActionYAML resolves the inputs and description from the action.yml +// for each configured action. Results are stored in the action config's computed fields. +// This function should be called before tool generation and step generation. +func (c *Compiler) fetchAndParseActionYAML(actionName string, config *SafeOutputActionConfig, markdownPath string, data *WorkflowData) { + if config.Uses == "" { + return + } + + ref, err := parseActionUsesField(config.Uses) + if err != nil { + safeOutputActionsLog.Printf("Warning: failed to parse uses field %q for action %q: %v", config.Uses, actionName, err) + return + } + + var actionYAML *actionYAMLFile + var resolvedRef string + + if ref.IsLocal { + actionYAML, err = readLocalActionYAML(ref.LocalPath, markdownPath) + if err != nil { + safeOutputActionsLog.Printf("Warning: failed to read local action.yml for %q at %s: %v", actionName, ref.LocalPath, err) + } + resolvedRef = config.Uses // local paths stay as-is + } else { + // Pin the action ref and fetch the action.yml + pinned, pinErr := GetActionPinWithData(ref.Repo, ref.Ref, data) + if pinErr != nil { + safeOutputActionsLog.Printf("Warning: failed to pin action %q (%s@%s): %v", actionName, ref.Repo, ref.Ref, pinErr) + // Fall back to using the original ref + resolvedRef = config.Uses + } else { + resolvedRef = pinned + } + + actionYAML, err = fetchRemoteActionYAML(ref.Repo, ref.Subdir, ref.Ref) + if err != nil { + safeOutputActionsLog.Printf("Warning: failed to fetch action.yml for %q (%s): %v", actionName, config.Uses, err) + } + } + + config.ResolvedRef = resolvedRef + + if actionYAML != nil { + config.Inputs = actionYAML.Inputs + config.ActionDescription = actionYAML.Description + } +} + +// fetchRemoteActionYAML fetches and parses action.yml from a GitHub repository. +// It tries both action.yml and action.yaml filenames. +func fetchRemoteActionYAML(repo, subdir, ref string) (*actionYAMLFile, error) { + for _, filename := range []string{"action.yml", "action.yaml"} { + var contentPath string + if subdir != "" { + contentPath = subdir + "/" + filename + } else { + contentPath = filename + } + + apiPath := fmt.Sprintf("/repos/%s/contents/%s?ref=%s", repo, contentPath, ref) + safeOutputActionsLog.Printf("Fetching action YAML from: %s", apiPath) + + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + cmd := ExecGHContext(ctx, "api", apiPath, "--jq", ".content") + output, err := cmd.Output() + cancel() + if err != nil { + safeOutputActionsLog.Printf("Failed to fetch %s from %s@%s: %v", filename, repo, ref, err) + continue + } + + // GitHub API returns base64-encoded content with newlines + b64Content := strings.ReplaceAll(strings.TrimSpace(string(output)), "\\n", "\n") + // Remove JSON string quotes if present + b64Content = strings.Trim(b64Content, "\"") + decoded, decErr := base64.StdEncoding.DecodeString(b64Content) + if decErr != nil { + safeOutputActionsLog.Printf("Failed to decode content for %s: %v", contentPath, decErr) + continue + } + + actionYAML, parseErr := parseActionYAMLContent(decoded) + if parseErr != nil { + safeOutputActionsLog.Printf("Failed to parse %s: %v", contentPath, parseErr) + continue + } + + return actionYAML, nil + } + + return nil, fmt.Errorf("could not find action.yml or action.yaml in %s@%s (subdir=%q)", repo, ref, subdir) +} + +// readLocalActionYAML reads and parses a local action.yml file. +func readLocalActionYAML(localPath, markdownPath string) (*actionYAMLFile, error) { + baseDir := filepath.Dir(markdownPath) + + // Strip leading "./" from the local path + cleanPath := strings.TrimPrefix(localPath, "./") + actionDir := filepath.Join(baseDir, cleanPath) + + for _, filename := range []string{"action.yml", "action.yaml"} { + fullPath := filepath.Join(actionDir, filename) + content, err := os.ReadFile(fullPath) + if err != nil { + continue + } + return parseActionYAMLContent(content) + } + + return nil, fmt.Errorf("could not find action.yml or action.yaml at %s", actionDir) +} + +// parseActionYAMLContent parses raw action.yml YAML content. +func parseActionYAMLContent(content []byte) (*actionYAMLFile, error) { + var parsed actionYAMLFile + if err := yaml.Unmarshal(content, &parsed); err != nil { + return nil, fmt.Errorf("failed to parse action YAML: %w", err) + } + return &parsed, nil +} + +// generateActionToolDefinition creates an MCP tool definition for a custom safe output action. +// The tool name is the normalized action name. Inputs are derived from the action.yml. +func generateActionToolDefinition(actionName string, config *SafeOutputActionConfig) map[string]any { + normalizedName := stringutil.NormalizeSafeOutputIdentifier(actionName) + + description := config.Description + if description == "" { + description = config.ActionDescription + } + if description == "" { + description = fmt.Sprintf("Run the %s action", actionName) + } + // Append once-only constraint to description + description += " (can only be called once)" + + inputSchema := map[string]any{ + "type": "object", + "properties": make(map[string]any), + "additionalProperties": false, + } + + var requiredFields []string + properties := inputSchema["properties"].(map[string]any) + + if config.Inputs != nil { + // Sort for deterministic output + inputNames := make([]string, 0, len(config.Inputs)) + for k := range config.Inputs { + inputNames = append(inputNames, k) + } + sort.Strings(inputNames) + + for _, inputName := range inputNames { + inputDef := config.Inputs[inputName] + property := map[string]any{ + "type": "string", + } + if inputDef.Description != "" { + property["description"] = inputDef.Description + } + if inputDef.Default != "" { + property["default"] = inputDef.Default + } + if inputDef.Required { + requiredFields = append(requiredFields, inputName) + } + properties[inputName] = property + } + } + + if len(requiredFields) > 0 { + sort.Strings(requiredFields) + inputSchema["required"] = requiredFields + } + + return map[string]any{ + "name": normalizedName, + "description": description, + "inputSchema": inputSchema, + } +} + +// buildCustomSafeOutputActionsJSON builds a JSON mapping of normalized action names +// used for the GH_AW_SAFE_OUTPUT_ACTIONS env var of the handler manager step. +// This allows the handler manager to load and dispatch messages to action handlers. +// The map value is the normalized action name (same as key) for future extensibility. +func buildCustomSafeOutputActionsJSON(data *WorkflowData) string { + if data.SafeOutputs == nil || len(data.SafeOutputs.Actions) == 0 { + return "" + } + + actionMapping := make(map[string]string, len(data.SafeOutputs.Actions)) + for actionName := range data.SafeOutputs.Actions { + normalizedName := stringutil.NormalizeSafeOutputIdentifier(actionName) + actionMapping[normalizedName] = normalizedName + } + + // Sort keys for deterministic output + keys := make([]string, 0, len(actionMapping)) + for k := range actionMapping { + keys = append(keys, k) + } + sort.Strings(keys) + + ordered := make(map[string]string, len(keys)) + for _, k := range keys { + ordered[k] = actionMapping[k] + } + + jsonBytes, err := json.Marshal(ordered) + if err != nil { + safeOutputActionsLog.Printf("Warning: failed to marshal custom safe output actions: %v", err) + return "" + } + return string(jsonBytes) +} + +// actionOutputKey returns the step output key for a given normalized action name. +// The handler exports this key and the compiler uses it in step conditions and with: blocks. +func actionOutputKey(normalizedName string) string { + return "action_" + normalizedName + "_payload" +} + +// buildActionSteps generates the YAML steps for all configured safe output actions. +// Each step: +// - Is guarded by an `if:` condition checking the payload output from process_safe_outputs +// - Uses the resolved action reference +// - Has a `with:` block populated from parsed payload output via fromJSON +func (c *Compiler) buildActionSteps(data *WorkflowData) []string { + if data.SafeOutputs == nil || len(data.SafeOutputs.Actions) == 0 { + return nil + } + + // Sort action names for deterministic output + actionNames := make([]string, 0, len(data.SafeOutputs.Actions)) + for name := range data.SafeOutputs.Actions { + actionNames = append(actionNames, name) + } + sort.Strings(actionNames) + + var steps []string + + for _, actionName := range actionNames { + config := data.SafeOutputs.Actions[actionName] + normalizedName := stringutil.NormalizeSafeOutputIdentifier(actionName) + outputKey := actionOutputKey(normalizedName) + + // Determine the action reference to use in the step + actionRef := config.ResolvedRef + if actionRef == "" { + // Fall back to original uses value if resolution failed + actionRef = config.Uses + } + + // Display name: prefer the user description, then action description, then action name + displayName := config.Description + if displayName == "" { + displayName = config.ActionDescription + } + if displayName == "" { + displayName = actionName + } + + steps = append(steps, fmt.Sprintf(" - name: %s\n", displayName)) + steps = append(steps, fmt.Sprintf(" id: action_%s\n", normalizedName)) + steps = append(steps, fmt.Sprintf(" if: steps.process_safe_outputs.outputs.%s != ''\n", outputKey)) + steps = append(steps, fmt.Sprintf(" uses: %s\n", actionRef)) + + // Build the with: block + if len(config.Inputs) > 0 { + steps = append(steps, " with:\n") + + inputNames := make([]string, 0, len(config.Inputs)) + for k := range config.Inputs { + inputNames = append(inputNames, k) + } + sort.Strings(inputNames) + + for _, inputName := range inputNames { + steps = append(steps, fmt.Sprintf(" %s: ${{ fromJSON(steps.process_safe_outputs.outputs.%s).%s }}\n", + inputName, outputKey, inputName)) + } + } else { + // When inputs couldn't be resolved, pass the raw payload as a single input + steps = append(steps, " with:\n") + steps = append(steps, fmt.Sprintf(" payload: ${{ steps.process_safe_outputs.outputs.%s }}\n", outputKey)) + } + } + + return steps +} + +// resolveAllActions fetches action.yml for all configured actions and populates +// the computed fields (ResolvedRef, Inputs, ActionDescription) in each config. +// This should be called once during compilation before tool generation and step generation. +func (c *Compiler) resolveAllActions(data *WorkflowData, markdownPath string) { + if data.SafeOutputs == nil || len(data.SafeOutputs.Actions) == 0 { + return + } + + safeOutputActionsLog.Printf("Resolving %d custom safe output action(s)", len(data.SafeOutputs.Actions)) + for actionName, config := range data.SafeOutputs.Actions { + if config.ResolvedRef != "" { + // Already resolved (e.g., called multiple times) + continue + } + c.fetchAndParseActionYAML(actionName, config, markdownPath, data) + safeOutputActionsLog.Printf("Resolved action %q: ref=%q, inputs=%d", actionName, config.ResolvedRef, len(config.Inputs)) + } +} diff --git a/pkg/workflow/safe_outputs_actions_test.go b/pkg/workflow/safe_outputs_actions_test.go new file mode 100644 index 0000000000..5b09ff7523 --- /dev/null +++ b/pkg/workflow/safe_outputs_actions_test.go @@ -0,0 +1,417 @@ +//go:build !integration + +package workflow + +import ( + "encoding/json" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestParseActionsConfig verifies parsing of safe-outputs.actions configuration +func TestParseActionsConfig(t *testing.T) { + actionsMap := map[string]any{ + "my-tool": map[string]any{ + "uses": "owner/repo@v1", + "description": "My custom tool", + }, + "another-tool": map[string]any{ + "uses": "owner/other-repo/subdir@v2", + }, + } + + result := parseActionsConfig(actionsMap) + + require.NotNil(t, result, "Should return non-nil result") + require.Len(t, result, 2, "Should have two actions") + + myTool, exists := result["my-tool"] + require.True(t, exists, "Should have my-tool action") + assert.Equal(t, "owner/repo@v1", myTool.Uses, "Uses should match") + assert.Equal(t, "My custom tool", myTool.Description, "Description should match") + + anotherTool, exists := result["another-tool"] + require.True(t, exists, "Should have another-tool action") + assert.Equal(t, "owner/other-repo/subdir@v2", anotherTool.Uses, "Uses should match") + assert.Empty(t, anotherTool.Description, "Description should be empty") +} + +// TestParseActionsConfigMissingUses verifies actions without uses are skipped +func TestParseActionsConfigMissingUses(t *testing.T) { + actionsMap := map[string]any{ + "invalid-tool": map[string]any{ + "description": "No uses field", + }, + "valid-tool": map[string]any{ + "uses": "owner/repo@v1", + }, + } + + result := parseActionsConfig(actionsMap) + + require.Len(t, result, 1, "Should only have the valid action") + _, exists := result["invalid-tool"] + assert.False(t, exists, "Should not have invalid-tool (missing uses)") + _, exists = result["valid-tool"] + assert.True(t, exists, "Should have valid-tool") +} + +// TestParseActionsConfigEmpty verifies empty map returns nil or empty +func TestParseActionsConfigEmpty(t *testing.T) { + result := parseActionsConfig(map[string]any{}) + assert.Empty(t, result, "Should return empty result for empty map") + + result = parseActionsConfig(nil) + assert.Nil(t, result, "Should return nil for nil input") +} + +// TestParseActionUsesField verifies parsing of different uses field formats +func TestParseActionUsesField(t *testing.T) { + tests := []struct { + name string + uses string + wantRepo string + wantSubdir string + wantRef string + wantLocal bool + wantErr bool + }{ + { + name: "root action", + uses: "owner/repo@v1", + wantRepo: "owner/repo", + wantRef: "v1", + }, + { + name: "sub-directory action", + uses: "owner/repo/subpath@v2", + wantRepo: "owner/repo", + wantSubdir: "subpath", + wantRef: "v2", + }, + { + name: "deep sub-directory action", + uses: "owner/repo/path/to/action@v3", + wantRepo: "owner/repo", + wantSubdir: "path/to/action", + wantRef: "v3", + }, + { + name: "local path", + uses: "./local/path", + wantLocal: true, + }, + { + name: "local path with parent", + uses: "../parent/path", + wantLocal: true, + }, + { + name: "missing ref", + uses: "owner/repo", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ref, err := parseActionUsesField(tt.uses) + if tt.wantErr { + assert.Error(t, err, "Should return error") + return + } + require.NoError(t, err, "Should not return error") + assert.Equal(t, tt.wantLocal, ref.IsLocal, "IsLocal mismatch") + if tt.wantLocal { + return + } + assert.Equal(t, tt.wantRepo, ref.Repo, "Repo mismatch") + assert.Equal(t, tt.wantSubdir, ref.Subdir, "Subdir mismatch") + assert.Equal(t, tt.wantRef, ref.Ref, "Ref mismatch") + }) + } +} + +// TestGenerateActionToolDefinition verifies tool definition generation +func TestGenerateActionToolDefinition(t *testing.T) { + config := &SafeOutputActionConfig{ + Uses: "owner/repo@v1", + Description: "My custom action tool", + ResolvedRef: "owner/repo@abc123 # v1", + ActionDescription: "Default description from action.yml", + Inputs: map[string]*ActionYAMLInput{ + "title": { + Description: "The title input", + Required: true, + }, + "body": { + Description: "The body input", + Required: false, + Default: "default body", + }, + }, + } + + tool := generateActionToolDefinition("my-tool", config) + + require.NotNil(t, tool, "Tool definition should not be nil") + assert.Equal(t, "my_tool", tool["name"], "Tool name should be normalized") + assert.Equal(t, "My custom action tool (can only be called once)", tool["description"], "Description should use user override + constraint") + + schema, ok := tool["inputSchema"].(map[string]any) + require.True(t, ok, "inputSchema should be a map") + assert.Equal(t, "object", schema["type"]) + assert.Equal(t, false, schema["additionalProperties"]) + + properties, ok := schema["properties"].(map[string]any) + require.True(t, ok, "properties should be a map") + assert.Len(t, properties, 2, "Should have 2 properties") + + titleProp, ok := properties["title"].(map[string]any) + require.True(t, ok, "title property should exist") + assert.Equal(t, "string", titleProp["type"]) + assert.Equal(t, "The title input", titleProp["description"]) + + bodyProp, ok := properties["body"].(map[string]any) + require.True(t, ok, "body property should exist") + assert.Equal(t, "string", bodyProp["type"]) + assert.Equal(t, "default body", bodyProp["default"]) + + required, ok := schema["required"].([]string) + require.True(t, ok, "required should be a []string") + assert.Equal(t, []string{"title"}, required, "Only title should be required") +} + +// TestGenerateActionToolDefinitionFallbackDescription verifies description fallback order +func TestGenerateActionToolDefinitionFallbackDescription(t *testing.T) { + tests := []struct { + name string + config *SafeOutputActionConfig + wantDescription string + }{ + { + name: "user description takes precedence", + config: &SafeOutputActionConfig{ + Description: "User description", + ActionDescription: "Action description", + }, + wantDescription: "User description (can only be called once)", + }, + { + name: "action description used when no user description", + config: &SafeOutputActionConfig{ + ActionDescription: "Action description", + }, + wantDescription: "Action description (can only be called once)", + }, + { + name: "fallback to action name", + config: &SafeOutputActionConfig{}, + wantDescription: "Run the my-action action (can only be called once)", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tool := generateActionToolDefinition("my-action", tt.config) + assert.Equal(t, tt.wantDescription, tool["description"], "Description should match expected") + }) + } +} + +// TestGenerateActionToolDefinitionNoInputs verifies tool with no inputs (resolution failed) +func TestGenerateActionToolDefinitionNoInputs(t *testing.T) { + config := &SafeOutputActionConfig{ + Uses: "owner/repo@v1", + } + + tool := generateActionToolDefinition("my-tool", config) + + schema, ok := tool["inputSchema"].(map[string]any) + require.True(t, ok, "inputSchema should be a map") + properties, ok := schema["properties"].(map[string]any) + require.True(t, ok, "properties should be a map") + assert.Empty(t, properties, "No properties when inputs unknown") + assert.Nil(t, schema["required"], "No required fields when inputs unknown") +} + +// TestBuildCustomSafeOutputActionsJSON verifies JSON generation for GH_AW_SAFE_OUTPUT_ACTIONS +func TestBuildCustomSafeOutputActionsJSON(t *testing.T) { + data := &WorkflowData{ + SafeOutputs: &SafeOutputsConfig{ + Actions: map[string]*SafeOutputActionConfig{ + "my-tool": {Uses: "owner/repo@v1"}, + "another-tool": {Uses: "owner/repo2@v2"}, + }, + }, + } + + jsonStr := buildCustomSafeOutputActionsJSON(data) + require.NotEmpty(t, jsonStr, "Should return non-empty JSON") + + var result map[string]string + err := json.Unmarshal([]byte(jsonStr), &result) + require.NoError(t, err, "Should be valid JSON") + + assert.Equal(t, "my_tool", result["my_tool"], "Normalized name should be in map") + assert.Equal(t, "another_tool", result["another_tool"], "Normalized name should be in map") +} + +// TestBuildCustomSafeOutputActionsJSONEmpty verifies empty result when no actions +func TestBuildCustomSafeOutputActionsJSONEmpty(t *testing.T) { + assert.Empty(t, buildCustomSafeOutputActionsJSON(&WorkflowData{SafeOutputs: &SafeOutputsConfig{}}), "Should return empty for no actions") + assert.Empty(t, buildCustomSafeOutputActionsJSON(&WorkflowData{SafeOutputs: nil}), "Should return empty for nil SafeOutputs") +} + +// TestBuildActionSteps verifies step generation for configured actions +func TestBuildActionSteps(t *testing.T) { + compiler := NewCompiler() + data := &WorkflowData{ + SafeOutputs: &SafeOutputsConfig{ + Actions: map[string]*SafeOutputActionConfig{ + "my-tool": { + Uses: "owner/repo@v1", + Description: "My tool description", + ResolvedRef: "owner/repo@abc123 # v1", + Inputs: map[string]*ActionYAMLInput{ + "title": {Required: true}, + "body": {Required: false}, + }, + }, + }, + }, + } + + steps := compiler.buildActionSteps(data) + require.NotEmpty(t, steps, "Should generate steps") + + fullYAML := strings.Join(steps, "") + assert.Contains(t, fullYAML, "My tool description", "Should use description as step name") + assert.Contains(t, fullYAML, "id: action_my_tool", "Should have step ID") + assert.Contains(t, fullYAML, "steps.process_safe_outputs.outputs.action_my_tool_payload != ''", "Should have if condition") + assert.Contains(t, fullYAML, "uses: owner/repo@abc123 # v1", "Should use resolved ref") + assert.Contains(t, fullYAML, "title:", "Should have title input") + assert.Contains(t, fullYAML, "body:", "Should have body input") + assert.Contains(t, fullYAML, "fromJSON(steps.process_safe_outputs.outputs.action_my_tool_payload).title", "Should use fromJSON for title") + assert.Contains(t, fullYAML, "fromJSON(steps.process_safe_outputs.outputs.action_my_tool_payload).body", "Should use fromJSON for body") +} + +// TestBuildActionStepsFallbackPayload verifies step uses payload when inputs unknown +func TestBuildActionStepsFallbackPayload(t *testing.T) { + compiler := NewCompiler() + data := &WorkflowData{ + SafeOutputs: &SafeOutputsConfig{ + Actions: map[string]*SafeOutputActionConfig{ + "unknown-inputs-tool": { + Uses: "owner/repo@v1", + ResolvedRef: "owner/repo@abc123 # v1", + // No Inputs: action.yml couldn't be fetched + }, + }, + }, + } + + steps := compiler.buildActionSteps(data) + require.NotEmpty(t, steps, "Should generate steps even without inputs") + + fullYAML := strings.Join(steps, "") + assert.Contains(t, fullYAML, "payload:", "Should use payload as single with: key when inputs unknown") + assert.Contains(t, fullYAML, "steps.process_safe_outputs.outputs.action_unknown_inputs_tool_payload", "Should reference payload output") +} + +// TestBuildActionStepsEmpty verifies no steps when no actions +func TestBuildActionStepsEmpty(t *testing.T) { + compiler := NewCompiler() + data := &WorkflowData{ + SafeOutputs: &SafeOutputsConfig{}, + } + assert.Nil(t, compiler.buildActionSteps(data), "Should return nil for empty actions") +} + +// TestExtractSafeOutputsConfigIncludesActions verifies extractSafeOutputsConfig handles actions +func TestExtractSafeOutputsConfigIncludesActions(t *testing.T) { + compiler := NewCompiler() + frontmatter := map[string]any{ + "safe-outputs": map[string]any{ + "actions": map[string]any{ + "my-action": map[string]any{ + "uses": "owner/repo@v1", + "description": "My action", + }, + }, + }, + } + + config := compiler.extractSafeOutputsConfig(frontmatter) + + require.NotNil(t, config, "Should extract config") + require.Len(t, config.Actions, 1, "Should have 1 action") + + action, exists := config.Actions["my-action"] + require.True(t, exists, "Should have my-action") + assert.Equal(t, "owner/repo@v1", action.Uses, "Uses should match") + assert.Equal(t, "My action", action.Description, "Description should match") +} + +// TestHandlerManagerStepIncludesActionsEnvVar verifies GH_AW_SAFE_OUTPUT_ACTIONS env var +func TestHandlerManagerStepIncludesActionsEnvVar(t *testing.T) { + compiler := NewCompiler() + workflowData := &WorkflowData{ + SafeOutputs: &SafeOutputsConfig{ + CreateIssues: &CreateIssuesConfig{}, + Actions: map[string]*SafeOutputActionConfig{ + "my-action": {Uses: "owner/repo@v1"}, + }, + }, + } + + steps := compiler.buildHandlerManagerStep(workflowData) + fullYAML := strings.Join(steps, "") + + assert.Contains(t, fullYAML, "GH_AW_SAFE_OUTPUT_ACTIONS", "Should include GH_AW_SAFE_OUTPUT_ACTIONS env var") + assert.Contains(t, fullYAML, "my_action", "Should include normalized action name") +} + +// TestHandlerManagerStepNoActionsEnvVar verifies GH_AW_SAFE_OUTPUT_ACTIONS absent when no actions +func TestHandlerManagerStepNoActionsEnvVar(t *testing.T) { + compiler := NewCompiler() + workflowData := &WorkflowData{ + SafeOutputs: &SafeOutputsConfig{ + CreateIssues: &CreateIssuesConfig{}, + }, + } + + steps := compiler.buildHandlerManagerStep(workflowData) + fullYAML := strings.Join(steps, "") + + assert.NotContains(t, fullYAML, "GH_AW_SAFE_OUTPUT_ACTIONS", "Should not include GH_AW_SAFE_OUTPUT_ACTIONS when no actions") +} + +// TestHasAnySafeOutputEnabledWithActions verifies Actions are detected as enabled +func TestHasAnySafeOutputEnabledWithActions(t *testing.T) { + config := &SafeOutputsConfig{ + Actions: map[string]*SafeOutputActionConfig{ + "my-action": {Uses: "owner/repo@v1"}, + }, + } + assert.True(t, hasAnySafeOutputEnabled(config), "Should detect actions as enabled safe outputs") +} + +// TestHasNonBuiltinSafeOutputsEnabledWithActions verifies Actions count as non-builtin +func TestHasNonBuiltinSafeOutputsEnabledWithActions(t *testing.T) { + config := &SafeOutputsConfig{ + Actions: map[string]*SafeOutputActionConfig{ + "my-action": {Uses: "owner/repo@v1"}, + }, + } + assert.True(t, hasNonBuiltinSafeOutputsEnabled(config), "Actions should count as non-builtin safe outputs") +} + +// TestActionOutputKey verifies the output key naming convention +func TestActionOutputKey(t *testing.T) { + assert.Equal(t, "action_my_tool_payload", actionOutputKey("my_tool")) + assert.Equal(t, "action_another_action_payload", actionOutputKey("another_action")) +} diff --git a/pkg/workflow/safe_outputs_config.go b/pkg/workflow/safe_outputs_config.go index d0c124a7ff..70146ca9fc 100644 --- a/pkg/workflow/safe_outputs_config.go +++ b/pkg/workflow/safe_outputs_config.go @@ -539,6 +539,14 @@ func (c *Compiler) extractSafeOutputsConfig(frontmatter map[string]any) *SafeOut } } + // Handle actions (custom GitHub Actions mounted as safe output tools) + if actions, exists := outputMap["actions"]; exists { + if actionsMap, ok := actions.(map[string]any); ok { + config.Actions = parseActionsConfig(actionsMap) + safeOutputsConfigLog.Printf("Configured %d custom safe-output action(s)", len(config.Actions)) + } + } + // Handle app configuration for GitHub App token minting if app, exists := outputMap["github-app"]; exists { if appMap, ok := app.(map[string]any); ok { diff --git a/pkg/workflow/safe_outputs_state.go b/pkg/workflow/safe_outputs_state.go index 267c163251..a8efdd51e9 100644 --- a/pkg/workflow/safe_outputs_state.go +++ b/pkg/workflow/safe_outputs_state.go @@ -84,6 +84,12 @@ func hasAnySafeOutputEnabled(safeOutputs *SafeOutputsConfig) bool { return true } + // Check Actions separately as it's a map + if len(safeOutputs.Actions) > 0 { + safeOutputReflectionLog.Printf("Found %d custom actions enabled", len(safeOutputs.Actions)) + return true + } + // Use reflection to check all pointer fields val := reflect.ValueOf(safeOutputs).Elem() for fieldName := range safeOutputFieldMapping { @@ -136,6 +142,11 @@ func hasNonBuiltinSafeOutputsEnabled(safeOutputs *SafeOutputsConfig) bool { return true } + // Custom actions are always non-builtin + if len(safeOutputs.Actions) > 0 { + return true + } + // Check non-builtin pointer fields using the pre-computed list val := reflect.ValueOf(safeOutputs).Elem() for _, fieldName := range nonBuiltinSafeOutputFieldNames { diff --git a/pkg/workflow/safe_outputs_tools_filtering.go b/pkg/workflow/safe_outputs_tools_filtering.go index 08f83190da..6533dfea76 100644 --- a/pkg/workflow/safe_outputs_tools_filtering.go +++ b/pkg/workflow/safe_outputs_tools_filtering.go @@ -249,8 +249,25 @@ func generateFilteredToolsJSON(data *WorkflowData, markdownPath string) (string, } } + // Add custom action tools from SafeOutputs.Actions + if len(data.SafeOutputs.Actions) > 0 { + safeOutputsConfigLog.Printf("Adding %d custom action tools", len(data.SafeOutputs.Actions)) + + actionNames := make([]string, 0, len(data.SafeOutputs.Actions)) + for actionName := range data.SafeOutputs.Actions { + actionNames = append(actionNames, actionName) + } + sort.Strings(actionNames) + + for _, actionName := range actionNames { + actionConfig := data.SafeOutputs.Actions[actionName] + customTool := generateActionToolDefinition(actionName, actionConfig) + filteredTools = append(filteredTools, customTool) + } + } + if safeOutputsConfigLog.Enabled() { - safeOutputsConfigLog.Printf("Filtered %d tools from %d total tools (including %d custom jobs, %d custom scripts)", len(filteredTools), len(allTools), len(data.SafeOutputs.Jobs), len(data.SafeOutputs.Scripts)) + safeOutputsConfigLog.Printf("Filtered %d tools from %d total tools (including %d custom jobs, %d custom scripts, %d custom actions)", len(filteredTools), len(allTools), len(data.SafeOutputs.Jobs), len(data.SafeOutputs.Scripts), len(data.SafeOutputs.Actions)) } // Add dynamic dispatch_workflow tools @@ -763,6 +780,26 @@ func generateDynamicTools(data *WorkflowData, markdownPath string) ([]map[string } } + // Add custom action tools from SafeOutputs.Actions + // Each configured action is exposed as an MCP tool with schema derived from action.yml. + // The compiler resolves action.yml at compile time; if resolution fails the tool is still + // added with an empty inputSchema so the agent can still attempt to call it. + if len(data.SafeOutputs.Actions) > 0 { + safeOutputsConfigLog.Printf("Adding %d custom action tools to dynamic tools", len(data.SafeOutputs.Actions)) + + actionNames := make([]string, 0, len(data.SafeOutputs.Actions)) + for actionName := range data.SafeOutputs.Actions { + actionNames = append(actionNames, actionName) + } + sort.Strings(actionNames) + + for _, actionName := range actionNames { + actionConfig := data.SafeOutputs.Actions[actionName] + customTool := generateActionToolDefinition(actionName, actionConfig) + dynamicTools = append(dynamicTools, customTool) + } + } + // Add dynamic dispatch_workflow tools if data.SafeOutputs.DispatchWorkflow != nil && len(data.SafeOutputs.DispatchWorkflow.Workflows) > 0 { safeOutputsConfigLog.Printf("Adding %d dispatch_workflow tools", len(data.SafeOutputs.DispatchWorkflow.Workflows)) From b55023829bf24b99540ec4414daa6d5c15280b34 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 07:12:41 +0000 Subject: [PATCH 03/17] fix: address code review comments - fix base64 decoding and use INTERNAL_MESSAGE_FIELDS set Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/safe_output_action_handler.cjs | 15 +++++++++++++-- pkg/workflow/safe_outputs_actions.go | 13 +++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/actions/setup/js/safe_output_action_handler.cjs b/actions/setup/js/safe_output_action_handler.cjs index 836d04c0b2..da002f76fe 100644 --- a/actions/setup/js/safe_output_action_handler.cjs +++ b/actions/setup/js/safe_output_action_handler.cjs @@ -8,6 +8,15 @@ const { replaceTemporaryIdReferences } = require("./temporary_id.cjs"); const { getErrorMessage } = require("./error_helpers.cjs"); +/** + * Internal safe-output message fields that should not be forwarded as action inputs. + * These fields are part of the safe-output messaging protocol and are not user-defined. + * Maintained as an explicit set so future protocol fields can be added without silently + * forwarding them to external action `with:` inputs. + * @type {Set} + */ +const INTERNAL_MESSAGE_FIELDS = new Set(["type"]); + /** * Main handler factory for a custom safe output action. * @@ -65,8 +74,10 @@ async function main(config = {}) { // are passed through as-is. const processedInputs = {}; for (const [key, value] of Object.entries(message)) { - // Skip internal fields that are not action inputs - if (key === "type") { + // Skip internal safe-output messaging fields that are not action inputs. + // Maintained as an explicit set to allow future additions without silently + // forwarding new internal fields to external action steps. + if (INTERNAL_MESSAGE_FIELDS.has(key)) { continue; } diff --git a/pkg/workflow/safe_outputs_actions.go b/pkg/workflow/safe_outputs_actions.go index ff4d836425..f5e245e1d9 100644 --- a/pkg/workflow/safe_outputs_actions.go +++ b/pkg/workflow/safe_outputs_actions.go @@ -204,10 +204,15 @@ func fetchRemoteActionYAML(repo, subdir, ref string) (*actionYAMLFile, error) { continue } - // GitHub API returns base64-encoded content with newlines - b64Content := strings.ReplaceAll(strings.TrimSpace(string(output)), "\\n", "\n") - // Remove JSON string quotes if present - b64Content = strings.Trim(b64Content, "\"") + // GitHub API returns base64-encoded content with embedded newlines (line-wrapping every ~76 chars). + // The `gh api --jq .content` output is a raw string value (no surrounding quotes). + // We strip all whitespace (newlines and spaces) from the base64 string before decoding. + b64Content := strings.Map(func(r rune) rune { + if r == '\n' || r == '\r' || r == ' ' { + return -1 // remove character + } + return r + }, strings.TrimSpace(string(output))) decoded, decErr := base64.StdEncoding.DecodeString(b64Content) if decErr != nil { safeOutputActionsLog.Printf("Failed to decode content for %s: %v", contentPath, decErr) From 1b7f9bbf2be8c7e19827d7b777b627fa15173767 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 12:45:11 +0000 Subject: [PATCH 04/17] feat: add env field per action, redact strings with sanitizeContent, move requires to top Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../setup/js/safe_output_action_handler.cjs | 16 ++- actions/setup/js/safe_output_helpers.cjs | 7 +- go.mod | 2 +- pkg/workflow/safe_outputs_actions.go | 26 ++++- pkg/workflow/safe_outputs_actions_test.go | 103 ++++++++++++++++++ 5 files changed, 142 insertions(+), 12 deletions(-) diff --git a/actions/setup/js/safe_output_action_handler.cjs b/actions/setup/js/safe_output_action_handler.cjs index da002f76fe..3ee73b1f3b 100644 --- a/actions/setup/js/safe_output_action_handler.cjs +++ b/actions/setup/js/safe_output_action_handler.cjs @@ -7,6 +7,7 @@ const { replaceTemporaryIdReferences } = require("./temporary_id.cjs"); const { getErrorMessage } = require("./error_helpers.cjs"); +const { sanitizeContent } = require("./sanitize_content.cjs"); /** * Internal safe-output message fields that should not be forwarded as action inputs. @@ -69,9 +70,11 @@ async function main(config = {}) { try { core.info(`Processing custom action: ${actionName}`); - // Build the processed payload by applying temporary ID substitutions to all - // string-valued fields. Non-string fields (numbers, booleans, objects, arrays) - // are passed through as-is. + // Build the processed payload by: + // 1. Applying temporary ID reference substitutions to string fields + // 2. Redacting (sanitizing) all string fields via sanitizeContent() before export. + // This prevents prompt-injected content from leaking URLs, mentions, or harmful + // content into external action inputs. const processedInputs = {}; for (const [key, value] of Object.entries(message)) { // Skip internal safe-output messaging fields that are not action inputs. @@ -82,8 +85,11 @@ async function main(config = {}) { } if (typeof value === "string") { - // Apply temporary ID reference substitution (e.g., "aw_abc1" → "42") - processedInputs[key] = replaceTemporaryIdReferences(value, temporaryIdMap); + // Apply temporary ID reference substitution (e.g., "aw_abc1" → "42"), then + // sanitize to redact malicious URLs, neutralize bot-trigger phrases, and + // escape @mentions that could cause unintended notifications in the action. + const substituted = replaceTemporaryIdReferences(value, temporaryIdMap); + processedInputs[key] = sanitizeContent(substituted); } else { processedInputs[key] = value; } diff --git a/actions/setup/js/safe_output_helpers.cjs b/actions/setup/js/safe_output_helpers.cjs index d178fb75c3..47967926ee 100644 --- a/actions/setup/js/safe_output_helpers.cjs +++ b/actions/setup/js/safe_output_helpers.cjs @@ -6,6 +6,9 @@ * Provides common validation and target resolution logic */ +const { getErrorMessage } = require("./error_helpers.cjs"); +const { matchesSimpleGlob } = require("./glob_pattern_helpers.cjs"); + /** * Parse a comma-separated list of allowed items from environment variable * @param {string|undefined} envValue - Environment variable value @@ -250,7 +253,6 @@ function loadCustomSafeOutputJobTypes() { return new Set(jobTypes); } catch (error) { if (typeof core !== "undefined") { - const { getErrorMessage } = require("./error_helpers.cjs"); core.warning(`Failed to parse GH_AW_SAFE_OUTPUT_JOBS: ${getErrorMessage(error)}`); } return new Set(); @@ -317,7 +319,6 @@ function extractAssignees(message) { * @returns {boolean} True if username matches the blocked pattern */ function matchesBlockedPattern(username, pattern) { - const { matchesSimpleGlob } = require("./glob_pattern_helpers.cjs"); return matchesSimpleGlob(username, pattern); } @@ -356,7 +357,6 @@ function loadCustomSafeOutputScriptHandlers() { return scriptHandlers; } catch (error) { if (typeof core !== "undefined") { - const { getErrorMessage } = require("./error_helpers.cjs"); core.warning(`Failed to parse GH_AW_SAFE_OUTPUT_SCRIPTS: ${getErrorMessage(error)}`); } return new Map(); @@ -387,7 +387,6 @@ function loadCustomSafeOutputActionHandlers() { return actionHandlers; } catch (error) { if (typeof core !== "undefined") { - const { getErrorMessage } = require("./error_helpers.cjs"); core.warning(`Failed to parse GH_AW_SAFE_OUTPUT_ACTIONS: ${getErrorMessage(error)}`); } return new Map(); diff --git a/go.mod b/go.mod index eebfb2ef10..0972db58ec 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/sourcegraph/conc v0.3.0 github.com/spf13/cobra v1.10.2 github.com/stretchr/testify v1.11.1 + go.yaml.in/yaml/v3 v3.0.4 golang.org/x/crypto v0.48.0 golang.org/x/mod v0.33.0 golang.org/x/term v0.40.0 @@ -102,7 +103,6 @@ require ( go.opentelemetry.io/otel/metric v1.39.0 // indirect go.opentelemetry.io/otel/trace v1.39.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v4 v4.0.0-rc.4 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/net v0.51.0 // indirect diff --git a/pkg/workflow/safe_outputs_actions.go b/pkg/workflow/safe_outputs_actions.go index f5e245e1d9..090b944959 100644 --- a/pkg/workflow/safe_outputs_actions.go +++ b/pkg/workflow/safe_outputs_actions.go @@ -22,8 +22,9 @@ var safeOutputActionsLog = logger.New("workflow:safe_outputs_actions") // Each configured action is resolved at compile time to get its inputs from action.yml, // and is mounted as an MCP tool that the AI agent can call once per workflow run. type SafeOutputActionConfig struct { - Uses string `yaml:"uses"` - Description string `yaml:"description,omitempty"` // optional override of the action's description + Uses string `yaml:"uses"` + Description string `yaml:"description,omitempty"` // optional override of the action's description + Env map[string]string `yaml:"env,omitempty"` // additional environment variables for the injected step // Computed at compile time (not from frontmatter): ResolvedRef string `yaml:"-"` // Pinned action reference (e.g., "owner/repo@sha # v1") @@ -83,6 +84,14 @@ func parseActionsConfig(actionsMap map[string]any) map[string]*SafeOutputActionC if description, ok := actionConfigMap["description"].(string); ok { actionConfig.Description = description } + if envMap, ok := actionConfigMap["env"].(map[string]any); ok { + actionConfig.Env = make(map[string]string, len(envMap)) + for k, v := range envMap { + if vStr, ok := v.(string); ok { + actionConfig.Env[k] = vStr + } + } + } if actionConfig.Uses == "" { safeOutputActionsLog.Printf("Warning: action %q is missing required 'uses' field, skipping", actionName) @@ -408,6 +417,19 @@ func (c *Compiler) buildActionSteps(data *WorkflowData) []string { steps = append(steps, fmt.Sprintf(" if: steps.process_safe_outputs.outputs.%s != ''\n", outputKey)) steps = append(steps, fmt.Sprintf(" uses: %s\n", actionRef)) + // Build optional env: block for per-action environment variables + if len(config.Env) > 0 { + steps = append(steps, " env:\n") + envKeys := make([]string, 0, len(config.Env)) + for k := range config.Env { + envKeys = append(envKeys, k) + } + sort.Strings(envKeys) + for _, envKey := range envKeys { + steps = append(steps, fmt.Sprintf(" %s: %s\n", envKey, config.Env[envKey])) + } + } + // Build the with: block if len(config.Inputs) > 0 { steps = append(steps, " with:\n") diff --git a/pkg/workflow/safe_outputs_actions_test.go b/pkg/workflow/safe_outputs_actions_test.go index 5b09ff7523..7f74164380 100644 --- a/pkg/workflow/safe_outputs_actions_test.go +++ b/pkg/workflow/safe_outputs_actions_test.go @@ -415,3 +415,106 @@ func TestActionOutputKey(t *testing.T) { assert.Equal(t, "action_my_tool_payload", actionOutputKey("my_tool")) assert.Equal(t, "action_another_action_payload", actionOutputKey("another_action")) } + +// TestParseActionsConfigWithEnv verifies parsing of env field in actions config +func TestParseActionsConfigWithEnv(t *testing.T) { + actionsMap := map[string]any{ + "my-tool": map[string]any{ + "uses": "owner/repo@v1", + "env": map[string]any{ + "MY_VAR": "my-value", + "OTHER_VAR": "other-value", + }, + }, + } + + result := parseActionsConfig(actionsMap) + require.Len(t, result, 1, "Should have one action") + + myTool := result["my-tool"] + require.NotNil(t, myTool, "Should have my-tool") + require.Len(t, myTool.Env, 2, "Should have 2 env vars") + assert.Equal(t, "my-value", myTool.Env["MY_VAR"], "MY_VAR should match") + assert.Equal(t, "other-value", myTool.Env["OTHER_VAR"], "OTHER_VAR should match") +} + +// TestBuildActionStepsWithEnv verifies that env vars are emitted in generated steps +func TestBuildActionStepsWithEnv(t *testing.T) { + compiler := NewCompiler() + data := &WorkflowData{ + SafeOutputs: &SafeOutputsConfig{ + Actions: map[string]*SafeOutputActionConfig{ + "my-tool": { + Uses: "owner/repo@v1", + ResolvedRef: "owner/repo@abc123 # v1", + Env: map[string]string{ + "MY_SECRET": "${{ secrets.MY_SECRET }}", + "MY_VAR": "static-value", + }, + Inputs: map[string]*ActionYAMLInput{ + "title": {Required: true}, + }, + }, + }, + }, + } + + steps := compiler.buildActionSteps(data) + require.NotEmpty(t, steps, "Should generate steps") + + fullYAML := strings.Join(steps, "") + assert.Contains(t, fullYAML, "env:", "Should have env block") + assert.Contains(t, fullYAML, "MY_SECRET: ${{ secrets.MY_SECRET }}", "Should have MY_SECRET env var") + assert.Contains(t, fullYAML, "MY_VAR: static-value", "Should have MY_VAR env var") + // Env block should appear before with: block + envIdx := strings.Index(fullYAML, "env:") + withIdx := strings.Index(fullYAML, "with:") + assert.Less(t, envIdx, withIdx, "env: should appear before with:") +} + +// TestBuildActionStepsNoEnv verifies that no env block is emitted when Env is empty +func TestBuildActionStepsNoEnv(t *testing.T) { + compiler := NewCompiler() + data := &WorkflowData{ + SafeOutputs: &SafeOutputsConfig{ + Actions: map[string]*SafeOutputActionConfig{ + "my-tool": { + Uses: "owner/repo@v1", + ResolvedRef: "owner/repo@abc123 # v1", + Inputs: map[string]*ActionYAMLInput{ + "title": {Required: true}, + }, + }, + }, + }, + } + + steps := compiler.buildActionSteps(data) + fullYAML := strings.Join(steps, "") + assert.NotContains(t, fullYAML, "env:", "Should not have env block when Env is nil/empty") +} + +// TestExtractSafeOutputsConfigIncludesActionsWithEnv verifies env is parsed via extractSafeOutputsConfig +func TestExtractSafeOutputsConfigIncludesActionsWithEnv(t *testing.T) { + compiler := NewCompiler() + frontmatter := map[string]any{ + "safe-outputs": map[string]any{ + "actions": map[string]any{ + "my-action": map[string]any{ + "uses": "owner/repo@v1", + "env": map[string]any{ + "TOKEN": "${{ secrets.MY_TOKEN }}", + }, + }, + }, + }, + } + + config := compiler.extractSafeOutputsConfig(frontmatter) + + require.NotNil(t, config, "Should extract config") + action := config.Actions["my-action"] + require.NotNil(t, action, "Should have my-action") + require.Len(t, action.Env, 1, "Should have 1 env var") + assert.Equal(t, "${{ secrets.MY_TOKEN }}", action.Env["TOKEN"], "TOKEN env var should match") +} From 44a547d4c17d161af1eed4d1bcf19b18231b8ac7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 13:24:14 +0000 Subject: [PATCH 05/17] feat: add add-smoked-label action to smoke-codex, skip ${{ inputs from with: block Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/smoke-codex.lock.yml | 23 +++++- .github/workflows/smoke-codex.md | 7 ++ pkg/parser/schemas/main_workflow_schema.json | 31 ++++++++ pkg/workflow/safe_outputs_actions.go | 41 ++++++++--- pkg/workflow/safe_outputs_actions_test.go | 74 ++++++++++++++++++++ 5 files changed, 165 insertions(+), 11 deletions(-) diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index e1ae4d497a..0e37c3d2db 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -27,7 +27,7 @@ # - shared/gh.md # - shared/reporting.md # -# gh-aw-metadata: {"schema_version":"v2","frontmatter_hash":"57064b51acff99a53ad08aada3ddf9626cdf25a44c87298d5df01726d62273e5","strict":true} +# gh-aw-metadata: {"schema_version":"v2","frontmatter_hash":"f0c83e64ff01b5e650c92aaaf519cf17c35ab121d84d633cf4da7cb48488592c","strict":true} name: "Smoke Codex" "on": @@ -446,7 +446,17 @@ jobs: "remove_labels": " CONSTRAINTS: Only these labels can be removed: [smoke]." }, "repo_params": {}, - "dynamic_tools": [] + "dynamic_tools": [ + { + "description": "Add the 'smoked' label to the current pull request (can only be called once)", + "inputSchema": { + "additionalProperties": false, + "properties": {}, + "type": "object" + }, + "name": "add_smoked_label" + } + ] } GH_AW_SAFE_OUTPUTS_TOOLS_META_EOF cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF' @@ -1530,6 +1540,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,127.0.0.1,172.30.0.1,::1,api.openai.com,api.snapcraft.io,app.renovatebot.com,appveyor.com,archive.ubuntu.com,azure.archive.ubuntu.com,badgen.net,cdn.playwright.dev,circleci.com,codacy.com,codeclimate.com,codecov.io,codeload.github.com,coveralls.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,deepsource.io,docs.github.com,drone.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,go.dev,golang.org,goproxy.io,host.docker.internal,img.shields.io,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,localhost,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,openai.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkg.go.dev,playwright.download.prss.microsoft.com,ppa.launchpad.net,proxy.golang.org,raw.githubusercontent.com,readthedocs.io,readthedocs.org,renovatebot.com,s.symcb.com,s.symcd.com,security.ubuntu.com,semaphoreci.com,shields.io,snyk.io,sonarcloud.io,sonarqube.com,storage.googleapis.com,sum.golang.org,travis-ci.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} + GH_AW_SAFE_OUTPUT_ACTIONS: "{\"add_smoked_label\":\"add_smoked_label\"}" GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"hide_older_comments\":true,\"max\":2},\"add_labels\":{\"allowed\":[\"smoke-codex\"]},\"create_issue\":{\"close_older_issues\":true,\"expires\":2,\"labels\":[\"automation\",\"testing\"],\"max\":1},\"hide_comment\":{\"max\":5},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"remove_labels\":{\"allowed\":[\"smoke\"]},\"unassign_from_user\":{\"allowed\":[\"githubactionagent\"],\"max\":1}}" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} @@ -1538,6 +1549,14 @@ jobs: setupGlobals(core, github, context, exec, io); const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs'); await main(); + - name: Add the 'smoked' label to the current pull request + id: action_add_smoked_label + if: steps.process_safe_outputs.outputs.action_add_smoked_label_payload != '' + uses: actions-ecosystem/action-add-labels@v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + payload: ${{ steps.process_safe_outputs.outputs.action_add_smoked_label_payload }} - name: Upload Safe Output Items Manifest if: always() uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 diff --git a/.github/workflows/smoke-codex.md b/.github/workflows/smoke-codex.md index 2b8f27305b..cd0316b115 100644 --- a/.github/workflows/smoke-codex.md +++ b/.github/workflows/smoke-codex.md @@ -62,6 +62,12 @@ safe-outputs: run-started: "🔮 The ancient spirits stir... [{workflow_name}]({run_url}) awakens to divine this {event_type}..." run-success: "✨ The prophecy is fulfilled... [{workflow_name}]({run_url}) has completed its mystical journey. The stars align. 🌟" run-failure: "🌑 The shadows whisper... [{workflow_name}]({run_url}) {status}. The oracle requires further meditation..." + actions: + add-smoked-label: + uses: actions-ecosystem/action-add-labels@v1 + description: Add the 'smoked' label to the current pull request + env: + GITHUB_TOKEN: ${{ github.token }} timeout-minutes: 15 checkout: - fetch-depth: 2 @@ -99,6 +105,7 @@ If all tests pass: - Use the `add_labels` safe-output tool to add the label `smoke-codex` to the pull request - Use the `remove_labels` safe-output tool to remove the label `smoke` from the pull request - Use the `unassign_from_user` safe-output tool to unassign the user `githubactionagent` from the pull request (this is a fictitious user used for testing) +- Use the `add_smoked_label` safe-output action tool to add the label `smoked` to the pull request (call it with `{"labels": "smoked"}`) **Important**: If no action is needed after completing your analysis, you **MUST** call the `noop` safe-output tool with a brief explanation. Failing to call any safe-output tool is the most common cause of safe-output workflow failures. diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json index d0e54ea6bb..c78d67d7a7 100644 --- a/pkg/parser/schemas/main_workflow_schema.json +++ b/pkg/parser/schemas/main_workflow_schema.json @@ -7829,6 +7829,37 @@ } ] ] + }, + "actions": { + "type": "object", + "description": "Custom GitHub Actions to mount as once-callable MCP tools. Each action is resolved at compile time to derive its input schema from action.yml, and a guarded `uses:` step is injected in the safe_outputs job. Action names containing dashes will be automatically normalized to underscores (e.g., 'add-smoked-label' becomes 'add_smoked_label').", + "patternProperties": { + "^[a-zA-Z_][a-zA-Z0-9_-]*$": { + "type": "object", + "description": "Configuration for a custom safe output action.", + "properties": { + "uses": { + "type": "string", + "description": "The GitHub Action to use. Supports owner/repo@ref, owner/repo/subdir@ref, or ./local/path.", + "examples": ["actions-ecosystem/action-add-labels@v1", "owner/repo@v1", "owner/repo/subdir@v1"] + }, + "description": { + "type": "string", + "description": "Optional description override for the MCP tool. Defaults to the action's description from action.yml." + }, + "env": { + "type": "object", + "description": "Additional environment variables to set on the injected action step. Useful for passing secrets like GITHUB_TOKEN.", + "additionalProperties": { + "type": "string" + }, + "examples": [{ "GITHUB_TOKEN": "${{ github.token }}" }] + } + }, + "required": ["uses"], + "additionalProperties": false + } + } } }, "additionalProperties": false diff --git a/pkg/workflow/safe_outputs_actions.go b/pkg/workflow/safe_outputs_actions.go index 090b944959..24ea917578 100644 --- a/pkg/workflow/safe_outputs_actions.go +++ b/pkg/workflow/safe_outputs_actions.go @@ -269,6 +269,18 @@ func parseActionYAMLContent(content []byte) (*actionYAMLFile, error) { return &parsed, nil } +// isGitHubExpressionDefault returns true if the input's default value is a GitHub Actions +// expression (e.g., "${{ github.token }}" or "${{ github.event.pull_request.number }}"). +// Such inputs should not be included in the MCP tool schema or the generated `with:` block +// so that GitHub Actions can apply the defaults naturally rather than having them overridden +// with an empty string from a missing JSON key in the agent payload. +func isGitHubExpressionDefault(input *ActionYAMLInput) bool { + if input == nil { + return false + } + return strings.HasPrefix(strings.TrimSpace(input.Default), "${{") +} + // generateActionToolDefinition creates an MCP tool definition for a custom safe output action. // The tool name is the normalized action name. Inputs are derived from the action.yml. func generateActionToolDefinition(actionName string, config *SafeOutputActionConfig) map[string]any { @@ -303,6 +315,12 @@ func generateActionToolDefinition(actionName string, config *SafeOutputActionCon for _, inputName := range inputNames { inputDef := config.Inputs[inputName] + // Skip inputs whose defaults are GitHub expression (e.g. "${{ github.token }}"). + // These are implementation details (authentication, context values) that the agent + // should not provide — GitHub Actions will apply the defaults automatically. + if isGitHubExpressionDefault(inputDef) { + continue + } property := map[string]any{ "type": "string", } @@ -432,17 +450,22 @@ func (c *Compiler) buildActionSteps(data *WorkflowData) []string { // Build the with: block if len(config.Inputs) > 0 { - steps = append(steps, " with:\n") - - inputNames := make([]string, 0, len(config.Inputs)) - for k := range config.Inputs { - inputNames = append(inputNames, k) + // Filter to only inputs that the agent should provide (exclude those with GitHub + // expression defaults like "${{ github.token }}" — GitHub Actions applies them naturally). + agentInputNames := make([]string, 0, len(config.Inputs)) + for k, v := range config.Inputs { + if !isGitHubExpressionDefault(v) { + agentInputNames = append(agentInputNames, k) + } } - sort.Strings(inputNames) + sort.Strings(agentInputNames) - for _, inputName := range inputNames { - steps = append(steps, fmt.Sprintf(" %s: ${{ fromJSON(steps.process_safe_outputs.outputs.%s).%s }}\n", - inputName, outputKey, inputName)) + if len(agentInputNames) > 0 { + steps = append(steps, " with:\n") + for _, inputName := range agentInputNames { + steps = append(steps, fmt.Sprintf(" %s: ${{ fromJSON(steps.process_safe_outputs.outputs.%s).%s }}\n", + inputName, outputKey, inputName)) + } } } else { // When inputs couldn't be resolved, pass the raw payload as a single input diff --git a/pkg/workflow/safe_outputs_actions_test.go b/pkg/workflow/safe_outputs_actions_test.go index 7f74164380..c92f2c5d04 100644 --- a/pkg/workflow/safe_outputs_actions_test.go +++ b/pkg/workflow/safe_outputs_actions_test.go @@ -518,3 +518,77 @@ func TestExtractSafeOutputsConfigIncludesActionsWithEnv(t *testing.T) { require.Len(t, action.Env, 1, "Should have 1 env var") assert.Equal(t, "${{ secrets.MY_TOKEN }}", action.Env["TOKEN"], "TOKEN env var should match") } + +// TestIsGitHubExpressionDefault verifies detection of GitHub expression defaults +func TestIsGitHubExpressionDefault(t *testing.T) { + tests := []struct { + name string + input *ActionYAMLInput + expected bool + }{ + {"nil input", nil, false}, + {"no default", &ActionYAMLInput{}, false}, + {"static default", &ActionYAMLInput{Default: "latest"}, false}, + {"github token expression", &ActionYAMLInput{Default: "${{ github.token }}"}, true}, + {"pr number expression", &ActionYAMLInput{Default: "${{ github.event.pull_request.number }}"}, true}, + {"expression with leading whitespace", &ActionYAMLInput{Default: " ${{ github.token }}"}, true}, + {"partial expression no closing", &ActionYAMLInput{Default: "${{ incomplete"}, true}, // starts with ${{ + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expected, isGitHubExpressionDefault(tt.input), "isGitHubExpressionDefault result should match") + }) + } +} + +// TestBuildActionStepsSkipsGitHubExpressionDefaultInputs verifies inputs with ${{ defaults are excluded +func TestBuildActionStepsSkipsGitHubExpressionDefaultInputs(t *testing.T) { + compiler := NewCompiler() + data := &WorkflowData{ + SafeOutputs: &SafeOutputsConfig{ + Actions: map[string]*SafeOutputActionConfig{ + "add-labels": { + Uses: "actions-ecosystem/action-add-labels@v1", + ResolvedRef: "actions-ecosystem/action-add-labels@abc123 # v1", + Inputs: map[string]*ActionYAMLInput{ + "github_token": {Required: true, Default: "${{ github.token }}"}, + "number": {Required: false, Default: "${{ github.event.pull_request.number }}"}, + "labels": {Required: true}, + }, + }, + }, + }, + } + + steps := compiler.buildActionSteps(data) + fullYAML := strings.Join(steps, "") + + // Only 'labels' should be in with: block + assert.Contains(t, fullYAML, "labels:", "labels should be in with: block") + assert.NotContains(t, fullYAML, "github_token:", "github_token should be excluded (has ${{ default})") + assert.NotContains(t, fullYAML, "number:", "number should be excluded (has ${{ default})") +} + +// TestGenerateActionToolDefinitionSkipsGitHubExpressionInputs verifies schema omits ${{ inputs +func TestGenerateActionToolDefinitionSkipsGitHubExpressionInputs(t *testing.T) { + config := &SafeOutputActionConfig{ + Uses: "actions-ecosystem/action-add-labels@v1", + Inputs: map[string]*ActionYAMLInput{ + "github_token": {Required: true, Default: "${{ github.token }}"}, + "number": {Required: false, Default: "${{ github.event.pull_request.number }}"}, + "labels": {Required: true, Description: "Labels to add"}, + }, + } + + tool := generateActionToolDefinition("add-labels", config) + + schema, ok := tool["inputSchema"].(map[string]any) + require.True(t, ok, "inputSchema should be a map") + properties, ok := schema["properties"].(map[string]any) + require.True(t, ok, "properties should be a map") + + assert.Contains(t, properties, "labels", "labels should be in schema") + assert.NotContains(t, properties, "github_token", "github_token should be excluded from schema") + assert.NotContains(t, properties, "number", "number should be excluded from schema") +} From 84df56f8d0f0aef406f361af7e6dceb38bf27f06 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 14:18:44 +0000 Subject: [PATCH 06/17] fix: address code review - resolve actions early, use pinned SHA for fetch, fix fallback schema Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/aw/actions-lock.json | 5 + .github/workflows/smoke-claude.lock.yml | 2 + .github/workflows/smoke-codex.lock.yml | 41 +++++---- pkg/workflow/compiler_jobs.go | 8 ++ pkg/workflow/compiler_safe_outputs_job.go | 4 +- pkg/workflow/data/action_pins.json | 5 + pkg/workflow/safe_outputs_actions.go | 107 ++++++++++++++++------ pkg/workflow/safe_outputs_actions_test.go | 47 +++++++++- 8 files changed, 168 insertions(+), 51 deletions(-) diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index 6ca9158024..743652c946 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -1,5 +1,10 @@ { "entries": { + "actions-ecosystem/action-add-labels@v1": { + "repo": "actions-ecosystem/action-add-labels", + "version": "v1", + "sha": "18f1af5e3544586314bbe15c0273249c770b2daf" + }, "actions/ai-inference@v2.0.7": { "repo": "actions/ai-inference", "version": "v2.0.7", diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index b0d7a0ad13..c9f93bb762 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -2629,6 +2629,8 @@ jobs: /// // Auto-generated safe-output script handler: post-slack-message + const { sanitizeContent } = require("./sanitize_content.cjs"); + /** @type {import('./types/safe-output-script').SafeOutputScriptMain} */ async function main(config = {}) { const { channel, message } = config; diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index 0e37c3d2db..ba99018cad 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -107,6 +107,19 @@ jobs: setupGlobals(core, github, context, exec, io); const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); await main(core, context); + - name: Add hooray reaction for immediate feedback + id: react + if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_REACTION: "hooray" + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/add_reaction.cjs'); + await main(); - name: Validate CODEX_API_KEY or OPENAI_API_KEY secret id: validate-secret run: ${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh CODEX_API_KEY OPENAI_API_KEY Codex https://github.github.com/gh-aw/reference/engines/#openai-codex @@ -122,19 +135,6 @@ jobs: .agents sparse-checkout-cone-mode: true fetch-depth: 1 - - name: Add hooray reaction for immediate feedback - id: react - if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_REACTION: "hooray" - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('${{ runner.temp }}/gh-aw/actions/add_reaction.cjs'); - await main(); - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: @@ -411,7 +411,7 @@ jobs: with: node-version: '24' package-manager-cache: false - - name: Install Codex + - name: Install Codex CLI run: npm install -g @openai/codex@latest - name: Install AWF binary run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.24.3 @@ -450,8 +450,13 @@ jobs: { "description": "Add the 'smoked' label to the current pull request (can only be called once)", "inputSchema": { - "additionalProperties": false, - "properties": {}, + "additionalProperties": true, + "properties": { + "payload": { + "description": "JSON-encoded payload to pass to the action", + "type": "string" + } + }, "type": "object" }, "name": "add_smoked_label" @@ -1552,12 +1557,12 @@ jobs: - name: Add the 'smoked' label to the current pull request id: action_add_smoked_label if: steps.process_safe_outputs.outputs.action_add_smoked_label_payload != '' - uses: actions-ecosystem/action-add-labels@v1 + uses: actions-ecosystem/action-add-labels@18f1af5e3544586314bbe15c0273249c770b2daf # v1 env: GITHUB_TOKEN: ${{ github.token }} with: payload: ${{ steps.process_safe_outputs.outputs.action_add_smoked_label_payload }} - - name: Upload Safe Output Items Manifest + - name: Upload Safe Outputs Items Manifest if: always() uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: diff --git a/pkg/workflow/compiler_jobs.go b/pkg/workflow/compiler_jobs.go index 88a35cb1f7..160d0285b2 100644 --- a/pkg/workflow/compiler_jobs.go +++ b/pkg/workflow/compiler_jobs.go @@ -198,6 +198,14 @@ func (c *Compiler) buildJobs(data *WorkflowData, markdownPath string) error { // Extract lock filename for timestamp check lockFilename := filepath.Base(stringutil.MarkdownToLockFile(markdownPath)) + // Resolve custom safe-output actions early so that tool schemas (derived from action.yml) + // are available when buildMainJobWrapper → generateMCPSetup → generateToolsMetaJSON → + // generateDynamicTools runs. Without this early resolution the dynamic_tools entry for + // each action tool would have an empty schema because Inputs/ActionDescription are nil. + if data.SafeOutputs != nil && len(data.SafeOutputs.Actions) > 0 { + c.resolveAllActions(data, markdownPath) + } + // Build pre-activation and activation jobs _, activationJobCreated, err := c.buildPreActivationAndActivationJobs(data, frontmatter, lockFilename) if err != nil { diff --git a/pkg/workflow/compiler_safe_outputs_job.go b/pkg/workflow/compiler_safe_outputs_job.go index 8ebc563796..36e82de6f2 100644 --- a/pkg/workflow/compiler_safe_outputs_job.go +++ b/pkg/workflow/compiler_safe_outputs_job.go @@ -228,7 +228,9 @@ func (c *Compiler) buildConsolidatedSafeOutputsJob(data *WorkflowData, mainJobNa // a JSON payload output for each action tool call. Each step is guarded by an `if:` condition // that checks whether the handler manager exported a payload for this action. if len(data.SafeOutputs.Actions) > 0 { - // Resolve action.yml for all actions (fetches inputs/descriptions at compile time) + // resolveAllActions was already called early in buildJobs (before generateToolsMetaJSON) + // so action configs already have Inputs/ActionDescription populated. We only call it + // again here as a safety net in case compileSafeOutputsJob is called independently. c.resolveAllActions(data, markdownPath) actionStepYAML := c.buildActionSteps(data) diff --git a/pkg/workflow/data/action_pins.json b/pkg/workflow/data/action_pins.json index 6ca9158024..743652c946 100644 --- a/pkg/workflow/data/action_pins.json +++ b/pkg/workflow/data/action_pins.json @@ -1,5 +1,10 @@ { "entries": { + "actions-ecosystem/action-add-labels@v1": { + "repo": "actions-ecosystem/action-add-labels", + "version": "v1", + "sha": "18f1af5e3544586314bbe15c0273249c770b2daf" + }, "actions/ai-inference@v2.0.7": { "repo": "actions/ai-inference", "version": "v2.0.7", diff --git a/pkg/workflow/safe_outputs_actions.go b/pkg/workflow/safe_outputs_actions.go index 24ea917578..eb6b1aecab 100644 --- a/pkg/workflow/safe_outputs_actions.go +++ b/pkg/workflow/safe_outputs_actions.go @@ -168,15 +168,24 @@ func (c *Compiler) fetchAndParseActionYAML(actionName string, config *SafeOutput } else { // Pin the action ref and fetch the action.yml pinned, pinErr := GetActionPinWithData(ref.Repo, ref.Ref, data) + var fetchRef string if pinErr != nil { safeOutputActionsLog.Printf("Warning: failed to pin action %q (%s@%s): %v", actionName, ref.Repo, ref.Ref, pinErr) // Fall back to using the original ref resolvedRef = config.Uses + fetchRef = ref.Ref } else { resolvedRef = pinned + // Extract the pinned SHA from the reference (format: "repo@sha # tag") + // and use it to fetch action.yml so the schema matches the exact pinned version. + if sha := extractSHAFromPinnedRef(pinned); sha != "" { + fetchRef = sha + } else { + fetchRef = ref.Ref + } } - actionYAML, err = fetchRemoteActionYAML(ref.Repo, ref.Subdir, ref.Ref) + actionYAML, err = fetchRemoteActionYAML(ref.Repo, ref.Subdir, fetchRef) if err != nil { safeOutputActionsLog.Printf("Warning: failed to fetch action.yml for %q (%s): %v", actionName, config.Uses, err) } @@ -192,6 +201,27 @@ func (c *Compiler) fetchAndParseActionYAML(actionName string, config *SafeOutput // fetchRemoteActionYAML fetches and parses action.yml from a GitHub repository. // It tries both action.yml and action.yaml filenames. + +// extractSHAFromPinnedRef parses the SHA from a pinned action reference string. +// The format produced by formatActionReference is "repo@sha # version". +// Returns the SHA string, or empty string if it cannot be parsed. +func extractSHAFromPinnedRef(pinned string) string { + // Find the @ separator between repo and sha + _, afterAt, found := strings.Cut(pinned, "@") + if !found { + return "" + } + // Strip the "# version" comment + if commentIdx := strings.Index(afterAt, " #"); commentIdx >= 0 { + afterAt = strings.TrimSpace(afterAt[:commentIdx]) + } + // Validate it looks like a full SHA (40 hex chars) + if isValidFullSHA(afterAt) { + return afterAt + } + return "" +} + func fetchRemoteActionYAML(repo, subdir, ref string) (*actionYAMLFile, error) { for _, filename := range []string{"action.yml", "action.yaml"} { var contentPath string @@ -296,6 +326,27 @@ func generateActionToolDefinition(actionName string, config *SafeOutputActionCon // Append once-only constraint to description description += " (can only be called once)" + // When action.yml could not be fetched at compile time (Inputs == nil), generate a + // permissive fallback schema so the agent can still call the tool. The runtime step + // passes the raw payload through a single `payload` input rather than individual fields. + if config.Inputs == nil { + inputSchema := map[string]any{ + "type": "object", + "properties": map[string]any{ + "payload": map[string]any{ + "type": "string", + "description": "JSON-encoded payload to pass to the action", + }, + }, + "additionalProperties": true, + } + return map[string]any{ + "name": normalizedName, + "description": description, + "inputSchema": inputSchema, + } + } + inputSchema := map[string]any{ "type": "object", "properties": make(map[string]any), @@ -305,36 +356,34 @@ func generateActionToolDefinition(actionName string, config *SafeOutputActionCon var requiredFields []string properties := inputSchema["properties"].(map[string]any) - if config.Inputs != nil { - // Sort for deterministic output - inputNames := make([]string, 0, len(config.Inputs)) - for k := range config.Inputs { - inputNames = append(inputNames, k) + // Sort for deterministic output + inputNames := make([]string, 0, len(config.Inputs)) + for k := range config.Inputs { + inputNames = append(inputNames, k) + } + sort.Strings(inputNames) + + for _, inputName := range inputNames { + inputDef := config.Inputs[inputName] + // Skip inputs whose defaults are GitHub expression (e.g. "${{ github.token }}"). + // These are implementation details (authentication, context values) that the agent + // should not provide — GitHub Actions will apply the defaults automatically. + if isGitHubExpressionDefault(inputDef) { + continue } - sort.Strings(inputNames) - - for _, inputName := range inputNames { - inputDef := config.Inputs[inputName] - // Skip inputs whose defaults are GitHub expression (e.g. "${{ github.token }}"). - // These are implementation details (authentication, context values) that the agent - // should not provide — GitHub Actions will apply the defaults automatically. - if isGitHubExpressionDefault(inputDef) { - continue - } - property := map[string]any{ - "type": "string", - } - if inputDef.Description != "" { - property["description"] = inputDef.Description - } - if inputDef.Default != "" { - property["default"] = inputDef.Default - } - if inputDef.Required { - requiredFields = append(requiredFields, inputName) - } - properties[inputName] = property + property := map[string]any{ + "type": "string", + } + if inputDef.Description != "" { + property["description"] = inputDef.Description + } + if inputDef.Default != "" { + property["default"] = inputDef.Default + } + if inputDef.Required { + requiredFields = append(requiredFields, inputName) } + properties[inputName] = property } if len(requiredFields) > 0 { diff --git a/pkg/workflow/safe_outputs_actions_test.go b/pkg/workflow/safe_outputs_actions_test.go index c92f2c5d04..e9687edcb1 100644 --- a/pkg/workflow/safe_outputs_actions_test.go +++ b/pkg/workflow/safe_outputs_actions_test.go @@ -222,20 +222,24 @@ func TestGenerateActionToolDefinitionFallbackDescription(t *testing.T) { } } -// TestGenerateActionToolDefinitionNoInputs verifies tool with no inputs (resolution failed) +// TestGenerateActionToolDefinitionNoInputs verifies the fallback schema when resolution failed (Inputs == nil) func TestGenerateActionToolDefinitionNoInputs(t *testing.T) { config := &SafeOutputActionConfig{ Uses: "owner/repo@v1", + // Inputs is nil (action.yml resolution failed) } tool := generateActionToolDefinition("my-tool", config) schema, ok := tool["inputSchema"].(map[string]any) require.True(t, ok, "inputSchema should be a map") + // Fallback schema should be permissive (additionalProperties: true) so agent can still call the tool + assert.Equal(t, true, schema["additionalProperties"], "Fallback schema should allow additional properties") + // Should have a payload property to hint to the agent what to send properties, ok := schema["properties"].(map[string]any) require.True(t, ok, "properties should be a map") - assert.Empty(t, properties, "No properties when inputs unknown") - assert.Nil(t, schema["required"], "No required fields when inputs unknown") + assert.Contains(t, properties, "payload", "Fallback schema should include a 'payload' property") + assert.Nil(t, schema["required"], "No required fields in fallback schema") } // TestBuildCustomSafeOutputActionsJSON verifies JSON generation for GH_AW_SAFE_OUTPUT_ACTIONS @@ -592,3 +596,40 @@ func TestGenerateActionToolDefinitionSkipsGitHubExpressionInputs(t *testing.T) { assert.NotContains(t, properties, "github_token", "github_token should be excluded from schema") assert.NotContains(t, properties, "number", "number should be excluded from schema") } + +// TestExtractSHAFromPinnedRef verifies SHA extraction from pinned action references +func TestExtractSHAFromPinnedRef(t *testing.T) { + tests := []struct { + name string + pinned string + expected string + }{ + { + name: "standard pinned reference", + pinned: "actions-ecosystem/action-add-labels@" + strings.Repeat("a", 40) + " # v1", + expected: strings.Repeat("a", 40), + }, + { + name: "no @ separator", + pinned: "no-at-sign", + expected: "", + }, + { + name: "non-SHA after @", + pinned: "owner/repo@v1 # v1", + expected: "", + }, + { + name: "empty string", + pinned: "", + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := extractSHAFromPinnedRef(tt.pinned) + assert.Equal(t, tt.expected, result, "extractSHAFromPinnedRef result should match") + }) + } +} From 398b143c8320e9194e7e5906ee5eb7a76a555b44 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 14:41:12 +0000 Subject: [PATCH 07/17] fix: update MessageHandlerFunction type to accept optional temporaryIdMap parameter Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/smoke-codex.lock.yml | 16 ++++++++++++---- actions/setup/js/safe_output_action_handler.cjs | 2 +- actions/setup/js/types/handler-factory.d.ts | 3 ++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index ba99018cad..a4060f236f 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -450,13 +450,20 @@ jobs: { "description": "Add the 'smoked' label to the current pull request (can only be called once)", "inputSchema": { - "additionalProperties": true, + "additionalProperties": false, "properties": { - "payload": { - "description": "JSON-encoded payload to pass to the action", + "labels": { + "description": "The labels' name to be added. Must be separated with line breaks if there're multiple labels.", + "type": "string" + }, + "number": { + "description": "The number of the issue or pull request.", "type": "string" } }, + "required": [ + "labels" + ], "type": "object" }, "name": "add_smoked_label" @@ -1561,7 +1568,8 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} with: - payload: ${{ steps.process_safe_outputs.outputs.action_add_smoked_label_payload }} + labels: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).labels }} + number: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).number }} - name: Upload Safe Outputs Items Manifest if: always() uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 diff --git a/actions/setup/js/safe_output_action_handler.cjs b/actions/setup/js/safe_output_action_handler.cjs index 3ee73b1f3b..3359e685e6 100644 --- a/actions/setup/js/safe_output_action_handler.cjs +++ b/actions/setup/js/safe_output_action_handler.cjs @@ -55,7 +55,7 @@ async function main(config = {}) { * @param {Map} temporaryIdMap - Live map of temporary IDs (for substitution) * @returns {Promise} Result with success/error status */ - return async function handleCustomAction(message, resolvedTemporaryIds, temporaryIdMap) { + return async function handleCustomAction(message, resolvedTemporaryIds, temporaryIdMap = new Map()) { // Enforce once-only constraint if (called) { const error = `Action "${actionName}" can only be called once per workflow run`; diff --git a/actions/setup/js/types/handler-factory.d.ts b/actions/setup/js/types/handler-factory.d.ts index b40b336a27..848817b2a2 100644 --- a/actions/setup/js/types/handler-factory.d.ts +++ b/actions/setup/js/types/handler-factory.d.ts @@ -67,9 +67,10 @@ type HandlerResult = HandlerSuccessResult | HandlerErrorResult; * * @param message - The safe output message to process * @param resolvedTemporaryIds - Map of temporary IDs that have been resolved to actual issue/PR/discussion numbers + * @param temporaryIdMap - Live Map of temporary IDs for in-flight substitutions (may be used by action handlers) * @returns Promise resolving to result with success status and details */ -type MessageHandlerFunction = (message: any, resolvedTemporaryIds: ResolvedTemporaryIds) => Promise; +type MessageHandlerFunction = (message: any, resolvedTemporaryIds: ResolvedTemporaryIds, temporaryIdMap?: Map) => Promise; /** * Main factory function signature for safe output handlers From ead4e55897c98335b3e311889a187d341cdd8a82 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 14:51:07 +0000 Subject: [PATCH 08/17] Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/smoke-codex.lock.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index b89c3a4976..d8d72613fb 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -1561,6 +1561,15 @@ jobs: setupGlobals(core, github, context, exec, io); const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs'); await main(); + - name: Add the 'smoked' label to the current pull request + id: action_add_smoked_label + if: steps.process_safe_outputs.outputs.action_add_smoked_label_payload != '' + uses: actions-ecosystem/action-add-labels@18f1af5e3544586314bbe15c0273249c770b2daf # v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + labels: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).labels }} + number: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).number }} - name: Upload safe output items if: always() uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 From bdc20c17df25c4e83332b770c7396856c2ae0f9b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 14:56:29 +0000 Subject: [PATCH 09/17] chore: recompile workflows Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/smoke-codex.lock.yml | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index d8d72613fb..2c73bf9bca 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -450,20 +450,13 @@ jobs: { "description": "Add the 'smoked' label to the current pull request (can only be called once)", "inputSchema": { - "additionalProperties": false, + "additionalProperties": true, "properties": { - "labels": { - "description": "The labels' name to be added. Must be separated with line breaks if there're multiple labels.", - "type": "string" - }, - "number": { - "description": "The number of the issue or pull request.", + "payload": { + "description": "JSON-encoded payload to pass to the action", "type": "string" } }, - "required": [ - "labels" - ], "type": "object" }, "name": "add_smoked_label" @@ -1568,8 +1561,7 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} with: - labels: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).labels }} - number: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).number }} + payload: ${{ steps.process_safe_outputs.outputs.action_add_smoked_label_payload }} - name: Upload safe output items if: always() uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 From 7a554f931cee6b7e0035c88214d3d3d336f166b6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 14:58:37 +0000 Subject: [PATCH 10/17] Add changeset [skip-ci] --- .changeset/patch-add-safe-output-actions.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/patch-add-safe-output-actions.md diff --git a/.changeset/patch-add-safe-output-actions.md b/.changeset/patch-add-safe-output-actions.md new file mode 100644 index 0000000000..664ce396aa --- /dev/null +++ b/.changeset/patch-add-safe-output-actions.md @@ -0,0 +1,5 @@ +--- +"gh-aw": patch +--- + +Add support for `safe-outputs.actions` to mount custom GitHub Actions as once-callable safe output tools, including compile-time action metadata resolution and generated guarded workflow steps. From 67d4dd5a75f61e1362c34c3a9b83ca6da53a97f3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 15:10:24 +0000 Subject: [PATCH 11/17] fix: add continue-on-error to Upload safe output items step to prevent 409 conflict Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/agent-performance-analyzer.lock.yml | 1 + .github/workflows/agent-persona-explorer.lock.yml | 1 + .github/workflows/ai-moderator.lock.yml | 1 + .github/workflows/archie.lock.yml | 1 + .github/workflows/artifacts-summary.lock.yml | 1 + .github/workflows/audit-workflows.lock.yml | 1 + .github/workflows/auto-triage-issues.lock.yml | 1 + .github/workflows/blog-auditor.lock.yml | 1 + .github/workflows/bot-detection.lock.yml | 1 + .github/workflows/brave.lock.yml | 1 + .github/workflows/breaking-change-checker.lock.yml | 1 + .github/workflows/changeset.lock.yml | 1 + .github/workflows/ci-coach.lock.yml | 1 + .github/workflows/ci-doctor.lock.yml | 1 + .github/workflows/claude-code-user-docs-review.lock.yml | 1 + .github/workflows/cli-consistency-checker.lock.yml | 1 + .github/workflows/cli-version-checker.lock.yml | 1 + .github/workflows/cloclo.lock.yml | 1 + .github/workflows/code-scanning-fixer.lock.yml | 1 + .github/workflows/code-simplifier.lock.yml | 1 + .github/workflows/commit-changes-analyzer.lock.yml | 1 + .github/workflows/constraint-solving-potd.lock.yml | 1 + .github/workflows/contribution-check.lock.yml | 1 + .github/workflows/copilot-agent-analysis.lock.yml | 1 + .github/workflows/copilot-cli-deep-research.lock.yml | 1 + .github/workflows/copilot-pr-merged-report.lock.yml | 1 + .github/workflows/copilot-pr-nlp-analysis.lock.yml | 1 + .github/workflows/copilot-pr-prompt-analysis.lock.yml | 1 + .github/workflows/copilot-session-insights.lock.yml | 1 + .github/workflows/craft.lock.yml | 1 + .github/workflows/daily-architecture-diagram.lock.yml | 1 + .github/workflows/daily-assign-issue-to-user.lock.yml | 1 + .github/workflows/daily-cli-performance.lock.yml | 1 + .github/workflows/daily-cli-tools-tester.lock.yml | 1 + .github/workflows/daily-code-metrics.lock.yml | 1 + .github/workflows/daily-compiler-quality.lock.yml | 1 + .github/workflows/daily-copilot-token-report.lock.yml | 1 + .github/workflows/daily-doc-healer.lock.yml | 1 + .github/workflows/daily-doc-updater.lock.yml | 1 + .github/workflows/daily-fact.lock.yml | 1 + .github/workflows/daily-file-diet.lock.yml | 1 + .github/workflows/daily-firewall-report.lock.yml | 1 + .github/workflows/daily-function-namer.lock.yml | 1 + .github/workflows/daily-issues-report.lock.yml | 1 + .github/workflows/daily-malicious-code-scan.lock.yml | 1 + .github/workflows/daily-mcp-concurrency-analysis.lock.yml | 1 + .github/workflows/daily-multi-device-docs-tester.lock.yml | 1 + .github/workflows/daily-news.lock.yml | 1 + .github/workflows/daily-observability-report.lock.yml | 1 + .github/workflows/daily-performance-summary.lock.yml | 1 + .github/workflows/daily-regulatory.lock.yml | 1 + .github/workflows/daily-rendering-scripts-verifier.lock.yml | 1 + .github/workflows/daily-repo-chronicle.lock.yml | 1 + .github/workflows/daily-safe-output-integrator.lock.yml | 1 + .github/workflows/daily-safe-output-optimizer.lock.yml | 1 + .github/workflows/daily-safe-outputs-conformance.lock.yml | 1 + .github/workflows/daily-secrets-analysis.lock.yml | 1 + .github/workflows/daily-security-red-team.lock.yml | 1 + .github/workflows/daily-semgrep-scan.lock.yml | 1 + .github/workflows/daily-syntax-error-quality.lock.yml | 1 + .github/workflows/daily-team-evolution-insights.lock.yml | 1 + .github/workflows/daily-team-status.lock.yml | 1 + .github/workflows/daily-testify-uber-super-expert.lock.yml | 1 + .github/workflows/daily-workflow-updater.lock.yml | 1 + .github/workflows/dead-code-remover.lock.yml | 1 + .github/workflows/deep-report.lock.yml | 1 + .github/workflows/delight.lock.yml | 1 + .github/workflows/dependabot-burner.lock.yml | 1 + .github/workflows/dependabot-go-checker.lock.yml | 1 + .github/workflows/dev-hawk.lock.yml | 1 + .github/workflows/dev.lock.yml | 1 + .github/workflows/developer-docs-consolidator.lock.yml | 1 + .github/workflows/dictation-prompt.lock.yml | 1 + .github/workflows/discussion-task-miner.lock.yml | 1 + .github/workflows/docs-noob-tester.lock.yml | 1 + .github/workflows/draft-pr-cleanup.lock.yml | 1 + .github/workflows/duplicate-code-detector.lock.yml | 1 + .github/workflows/example-workflow-analyzer.lock.yml | 1 + .github/workflows/firewall-escape.lock.yml | 1 + .github/workflows/functional-pragmatist.lock.yml | 1 + .github/workflows/github-mcp-structural-analysis.lock.yml | 1 + .github/workflows/github-mcp-tools-report.lock.yml | 1 + .github/workflows/github-remote-mcp-auth-test.lock.yml | 1 + .github/workflows/glossary-maintainer.lock.yml | 1 + .github/workflows/go-fan.lock.yml | 1 + .github/workflows/go-logger.lock.yml | 1 + .github/workflows/go-pattern-detector.lock.yml | 1 + .github/workflows/gpclean.lock.yml | 1 + .github/workflows/grumpy-reviewer.lock.yml | 1 + .github/workflows/hourly-ci-cleaner.lock.yml | 1 + .github/workflows/instructions-janitor.lock.yml | 1 + .github/workflows/issue-arborist.lock.yml | 1 + .github/workflows/issue-monster.lock.yml | 1 + .github/workflows/issue-triage-agent.lock.yml | 1 + .github/workflows/jsweep.lock.yml | 1 + .github/workflows/layout-spec-maintainer.lock.yml | 1 + .github/workflows/lockfile-stats.lock.yml | 1 + .github/workflows/mcp-inspector.lock.yml | 1 + .github/workflows/mergefest.lock.yml | 1 + .github/workflows/notion-issue-summary.lock.yml | 1 + .github/workflows/org-health-report.lock.yml | 1 + .github/workflows/pdf-summary.lock.yml | 1 + .github/workflows/plan.lock.yml | 1 + .github/workflows/portfolio-analyst.lock.yml | 1 + .github/workflows/pr-nitpick-reviewer.lock.yml | 1 + .github/workflows/pr-triage-agent.lock.yml | 1 + .github/workflows/prompt-clustering-analysis.lock.yml | 1 + .github/workflows/python-data-charts.lock.yml | 1 + .github/workflows/q.lock.yml | 1 + .github/workflows/refiner.lock.yml | 1 + .github/workflows/release.lock.yml | 1 + .github/workflows/repo-audit-analyzer.lock.yml | 1 + .github/workflows/repo-tree-map.lock.yml | 1 + .github/workflows/repository-quality-improver.lock.yml | 1 + .github/workflows/research.lock.yml | 1 + .github/workflows/safe-output-health.lock.yml | 1 + .github/workflows/schema-consistency-checker.lock.yml | 1 + .github/workflows/scout.lock.yml | 1 + .github/workflows/security-alert-burndown.campaign.g.lock.yml | 1 + .github/workflows/security-compliance.lock.yml | 1 + .github/workflows/security-review.lock.yml | 1 + .github/workflows/semantic-function-refactor.lock.yml | 1 + .github/workflows/sergo.lock.yml | 1 + .github/workflows/slide-deck-maintainer.lock.yml | 1 + .github/workflows/smoke-agent-all-merged.lock.yml | 1 + .github/workflows/smoke-agent-all-none.lock.yml | 1 + .github/workflows/smoke-agent-public-approved.lock.yml | 1 + .github/workflows/smoke-agent-public-none.lock.yml | 1 + .github/workflows/smoke-agent-scoped-approved.lock.yml | 1 + .github/workflows/smoke-call-workflow.lock.yml | 1 + .github/workflows/smoke-claude.lock.yml | 1 + .github/workflows/smoke-codex.lock.yml | 1 + .github/workflows/smoke-copilot-arm.lock.yml | 1 + .github/workflows/smoke-copilot.lock.yml | 1 + .github/workflows/smoke-create-cross-repo-pr.lock.yml | 1 + .github/workflows/smoke-gemini.lock.yml | 1 + .github/workflows/smoke-multi-pr.lock.yml | 1 + .github/workflows/smoke-project.lock.yml | 1 + .github/workflows/smoke-temporary-id.lock.yml | 1 + .github/workflows/smoke-test-tools.lock.yml | 1 + .github/workflows/smoke-update-cross-repo-pr.lock.yml | 1 + .github/workflows/smoke-workflow-call-with-inputs.lock.yml | 1 + .github/workflows/smoke-workflow-call.lock.yml | 1 + .github/workflows/stale-repo-identifier.lock.yml | 1 + .github/workflows/static-analysis-report.lock.yml | 1 + .github/workflows/step-name-alignment.lock.yml | 1 + .github/workflows/sub-issue-closer.lock.yml | 1 + .github/workflows/super-linter.lock.yml | 1 + .github/workflows/technical-doc-writer.lock.yml | 1 + .github/workflows/terminal-stylist.lock.yml | 1 + .github/workflows/test-create-pr-error-handling.lock.yml | 1 + .github/workflows/test-dispatcher.lock.yml | 1 + .github/workflows/test-project-url-default.lock.yml | 1 + .github/workflows/tidy.lock.yml | 1 + .github/workflows/typist.lock.yml | 1 + .github/workflows/ubuntu-image-analyzer.lock.yml | 1 + .github/workflows/unbloat-docs.lock.yml | 1 + .github/workflows/update-astro.lock.yml | 1 + .github/workflows/video-analyzer.lock.yml | 1 + .github/workflows/weekly-blog-post-writer.lock.yml | 1 + .github/workflows/weekly-editors-health-check.lock.yml | 1 + .github/workflows/weekly-issue-summary.lock.yml | 1 + .github/workflows/weekly-safe-outputs-spec-review.lock.yml | 1 + .github/workflows/workflow-generator.lock.yml | 1 + .github/workflows/workflow-health-manager.lock.yml | 1 + .github/workflows/workflow-normalizer.lock.yml | 1 + .github/workflows/workflow-skill-extractor.lock.yml | 1 + pkg/workflow/compiler_safe_outputs_job.go | 4 ++++ 168 files changed, 171 insertions(+) diff --git a/.github/workflows/agent-performance-analyzer.lock.yml b/.github/workflows/agent-performance-analyzer.lock.yml index 7e50bc6e71..f1b27546ec 100644 --- a/.github/workflows/agent-performance-analyzer.lock.yml +++ b/.github/workflows/agent-performance-analyzer.lock.yml @@ -1313,6 +1313,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/agent-persona-explorer.lock.yml b/.github/workflows/agent-persona-explorer.lock.yml index eaa7f009d6..125a09d7d6 100644 --- a/.github/workflows/agent-persona-explorer.lock.yml +++ b/.github/workflows/agent-persona-explorer.lock.yml @@ -1173,6 +1173,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/ai-moderator.lock.yml b/.github/workflows/ai-moderator.lock.yml index 71088a0ea1..cd0015c3d3 100644 --- a/.github/workflows/ai-moderator.lock.yml +++ b/.github/workflows/ai-moderator.lock.yml @@ -1036,6 +1036,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml index 589db97cd6..84173a58ee 100644 --- a/.github/workflows/archie.lock.yml +++ b/.github/workflows/archie.lock.yml @@ -1192,6 +1192,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml index 52bd94d7bd..8545f15751 100644 --- a/.github/workflows/artifacts-summary.lock.yml +++ b/.github/workflows/artifacts-summary.lock.yml @@ -1088,6 +1088,7 @@ jobs: echo "Token invalidation step complete." - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index 41a55bfbbf..767b500259 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -1370,6 +1370,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/auto-triage-issues.lock.yml b/.github/workflows/auto-triage-issues.lock.yml index 6b809476a9..4d6f00a561 100644 --- a/.github/workflows/auto-triage-issues.lock.yml +++ b/.github/workflows/auto-triage-issues.lock.yml @@ -1134,6 +1134,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/blog-auditor.lock.yml b/.github/workflows/blog-auditor.lock.yml index 1782a2e67e..28ccddd591 100644 --- a/.github/workflows/blog-auditor.lock.yml +++ b/.github/workflows/blog-auditor.lock.yml @@ -1166,6 +1166,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/bot-detection.lock.yml b/.github/workflows/bot-detection.lock.yml index 9e939b2c6b..ff8b6b85c7 100644 --- a/.github/workflows/bot-detection.lock.yml +++ b/.github/workflows/bot-detection.lock.yml @@ -1791,6 +1791,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml index 1b0c6c86d8..b0b291cfee 100644 --- a/.github/workflows/brave.lock.yml +++ b/.github/workflows/brave.lock.yml @@ -1177,6 +1177,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/breaking-change-checker.lock.yml b/.github/workflows/breaking-change-checker.lock.yml index dbf218e5b4..360707bc98 100644 --- a/.github/workflows/breaking-change-checker.lock.yml +++ b/.github/workflows/breaking-change-checker.lock.yml @@ -1142,6 +1142,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index e2f36649cd..69cbf15676 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -1156,6 +1156,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/ci-coach.lock.yml b/.github/workflows/ci-coach.lock.yml index 4957659c64..f300531481 100644 --- a/.github/workflows/ci-coach.lock.yml +++ b/.github/workflows/ci-coach.lock.yml @@ -1178,6 +1178,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml index 7dc32a49f6..393f638379 100644 --- a/.github/workflows/ci-doctor.lock.yml +++ b/.github/workflows/ci-doctor.lock.yml @@ -1245,6 +1245,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/claude-code-user-docs-review.lock.yml b/.github/workflows/claude-code-user-docs-review.lock.yml index 98c33196d6..b1f83c31a1 100644 --- a/.github/workflows/claude-code-user-docs-review.lock.yml +++ b/.github/workflows/claude-code-user-docs-review.lock.yml @@ -1127,6 +1127,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml index 4a872c0ab0..b0797d0141 100644 --- a/.github/workflows/cli-consistency-checker.lock.yml +++ b/.github/workflows/cli-consistency-checker.lock.yml @@ -1031,6 +1031,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml index 3488192b8d..3d4b0cadb8 100644 --- a/.github/workflows/cli-version-checker.lock.yml +++ b/.github/workflows/cli-version-checker.lock.yml @@ -1132,6 +1132,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index 7ebd09206c..83657b9e47 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -1583,6 +1583,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/code-scanning-fixer.lock.yml b/.github/workflows/code-scanning-fixer.lock.yml index 90931d5f46..a3aecee206 100644 --- a/.github/workflows/code-scanning-fixer.lock.yml +++ b/.github/workflows/code-scanning-fixer.lock.yml @@ -1293,6 +1293,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/code-simplifier.lock.yml b/.github/workflows/code-simplifier.lock.yml index f47de0b83a..5fa2492f00 100644 --- a/.github/workflows/code-simplifier.lock.yml +++ b/.github/workflows/code-simplifier.lock.yml @@ -1170,6 +1170,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/commit-changes-analyzer.lock.yml b/.github/workflows/commit-changes-analyzer.lock.yml index 485bcfce3b..86f98cf1e2 100644 --- a/.github/workflows/commit-changes-analyzer.lock.yml +++ b/.github/workflows/commit-changes-analyzer.lock.yml @@ -1096,6 +1096,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/constraint-solving-potd.lock.yml b/.github/workflows/constraint-solving-potd.lock.yml index c190b12157..d9f1687c46 100644 --- a/.github/workflows/constraint-solving-potd.lock.yml +++ b/.github/workflows/constraint-solving-potd.lock.yml @@ -1036,6 +1036,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/contribution-check.lock.yml b/.github/workflows/contribution-check.lock.yml index a415068d8d..b32fc7ce47 100644 --- a/.github/workflows/contribution-check.lock.yml +++ b/.github/workflows/contribution-check.lock.yml @@ -1074,6 +1074,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml index a120736984..edb4305214 100644 --- a/.github/workflows/copilot-agent-analysis.lock.yml +++ b/.github/workflows/copilot-agent-analysis.lock.yml @@ -1249,6 +1249,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/copilot-cli-deep-research.lock.yml b/.github/workflows/copilot-cli-deep-research.lock.yml index ead9c43c24..e8ba3e0217 100644 --- a/.github/workflows/copilot-cli-deep-research.lock.yml +++ b/.github/workflows/copilot-cli-deep-research.lock.yml @@ -1168,6 +1168,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/copilot-pr-merged-report.lock.yml b/.github/workflows/copilot-pr-merged-report.lock.yml index 07ef1bd12d..f707149d70 100644 --- a/.github/workflows/copilot-pr-merged-report.lock.yml +++ b/.github/workflows/copilot-pr-merged-report.lock.yml @@ -1212,6 +1212,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index 0b22bf5524..f52f4a3afd 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -1252,6 +1252,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index 0fb5275d2c..79fc078666 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -1188,6 +1188,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index 7b126a037c..5e6c2785ca 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -1312,6 +1312,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index 1534e88c42..702378c858 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -1211,6 +1211,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-architecture-diagram.lock.yml b/.github/workflows/daily-architecture-diagram.lock.yml index 0632a159c0..f929c072ed 100644 --- a/.github/workflows/daily-architecture-diagram.lock.yml +++ b/.github/workflows/daily-architecture-diagram.lock.yml @@ -1152,6 +1152,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-assign-issue-to-user.lock.yml b/.github/workflows/daily-assign-issue-to-user.lock.yml index 6ef8de7077..6a44a61555 100644 --- a/.github/workflows/daily-assign-issue-to-user.lock.yml +++ b/.github/workflows/daily-assign-issue-to-user.lock.yml @@ -1040,6 +1040,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-cli-performance.lock.yml b/.github/workflows/daily-cli-performance.lock.yml index 4b7b81197f..9e34c5593a 100644 --- a/.github/workflows/daily-cli-performance.lock.yml +++ b/.github/workflows/daily-cli-performance.lock.yml @@ -1337,6 +1337,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-cli-tools-tester.lock.yml b/.github/workflows/daily-cli-tools-tester.lock.yml index 942a4651bd..f857169dc5 100644 --- a/.github/workflows/daily-cli-tools-tester.lock.yml +++ b/.github/workflows/daily-cli-tools-tester.lock.yml @@ -1119,6 +1119,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml index 108369b05c..538557459a 100644 --- a/.github/workflows/daily-code-metrics.lock.yml +++ b/.github/workflows/daily-code-metrics.lock.yml @@ -1291,6 +1291,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-compiler-quality.lock.yml b/.github/workflows/daily-compiler-quality.lock.yml index e124fcf432..7db8cbd068 100644 --- a/.github/workflows/daily-compiler-quality.lock.yml +++ b/.github/workflows/daily-compiler-quality.lock.yml @@ -1102,6 +1102,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-copilot-token-report.lock.yml b/.github/workflows/daily-copilot-token-report.lock.yml index df1b803bc9..0438f31284 100644 --- a/.github/workflows/daily-copilot-token-report.lock.yml +++ b/.github/workflows/daily-copilot-token-report.lock.yml @@ -1261,6 +1261,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-doc-healer.lock.yml b/.github/workflows/daily-doc-healer.lock.yml index 7af814d0d4..04e221e6f2 100644 --- a/.github/workflows/daily-doc-healer.lock.yml +++ b/.github/workflows/daily-doc-healer.lock.yml @@ -1406,6 +1406,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml index e1fb9065a8..653f832dcd 100644 --- a/.github/workflows/daily-doc-updater.lock.yml +++ b/.github/workflows/daily-doc-updater.lock.yml @@ -1354,6 +1354,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-fact.lock.yml b/.github/workflows/daily-fact.lock.yml index 9f36d87e94..5436aa8938 100644 --- a/.github/workflows/daily-fact.lock.yml +++ b/.github/workflows/daily-fact.lock.yml @@ -1053,6 +1053,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml index c7743f4135..2d73ec5d97 100644 --- a/.github/workflows/daily-file-diet.lock.yml +++ b/.github/workflows/daily-file-diet.lock.yml @@ -1203,6 +1203,7 @@ jobs: echo "Token invalidation step complete." - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml index b7693129bc..0b8f27e792 100644 --- a/.github/workflows/daily-firewall-report.lock.yml +++ b/.github/workflows/daily-firewall-report.lock.yml @@ -1198,6 +1198,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-function-namer.lock.yml b/.github/workflows/daily-function-namer.lock.yml index de0848ed99..6a81ad2907 100644 --- a/.github/workflows/daily-function-namer.lock.yml +++ b/.github/workflows/daily-function-namer.lock.yml @@ -1169,6 +1169,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-issues-report.lock.yml b/.github/workflows/daily-issues-report.lock.yml index b911c8bf7e..4541e3bd23 100644 --- a/.github/workflows/daily-issues-report.lock.yml +++ b/.github/workflows/daily-issues-report.lock.yml @@ -1205,6 +1205,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-malicious-code-scan.lock.yml b/.github/workflows/daily-malicious-code-scan.lock.yml index 538da9a571..a4d32ac7f8 100644 --- a/.github/workflows/daily-malicious-code-scan.lock.yml +++ b/.github/workflows/daily-malicious-code-scan.lock.yml @@ -919,6 +919,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-mcp-concurrency-analysis.lock.yml b/.github/workflows/daily-mcp-concurrency-analysis.lock.yml index 02ab045a72..535f6733c2 100644 --- a/.github/workflows/daily-mcp-concurrency-analysis.lock.yml +++ b/.github/workflows/daily-mcp-concurrency-analysis.lock.yml @@ -1188,6 +1188,7 @@ jobs: echo "Token invalidation step complete." - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-multi-device-docs-tester.lock.yml b/.github/workflows/daily-multi-device-docs-tester.lock.yml index a3dc711a67..43abbc1a07 100644 --- a/.github/workflows/daily-multi-device-docs-tester.lock.yml +++ b/.github/workflows/daily-multi-device-docs-tester.lock.yml @@ -1214,6 +1214,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index c7472b56b4..4afa6abe7e 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -1329,6 +1329,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-observability-report.lock.yml b/.github/workflows/daily-observability-report.lock.yml index bf3431db93..8d2c0832b8 100644 --- a/.github/workflows/daily-observability-report.lock.yml +++ b/.github/workflows/daily-observability-report.lock.yml @@ -1181,6 +1181,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-performance-summary.lock.yml b/.github/workflows/daily-performance-summary.lock.yml index eadc6195eb..2dfdd528ee 100644 --- a/.github/workflows/daily-performance-summary.lock.yml +++ b/.github/workflows/daily-performance-summary.lock.yml @@ -1640,6 +1640,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-regulatory.lock.yml b/.github/workflows/daily-regulatory.lock.yml index 050c428220..3a85464437 100644 --- a/.github/workflows/daily-regulatory.lock.yml +++ b/.github/workflows/daily-regulatory.lock.yml @@ -1561,6 +1561,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-rendering-scripts-verifier.lock.yml b/.github/workflows/daily-rendering-scripts-verifier.lock.yml index b5f5afa7f8..a4f3955e8e 100644 --- a/.github/workflows/daily-rendering-scripts-verifier.lock.yml +++ b/.github/workflows/daily-rendering-scripts-verifier.lock.yml @@ -1356,6 +1356,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml index 8d814b87b3..c25be96870 100644 --- a/.github/workflows/daily-repo-chronicle.lock.yml +++ b/.github/workflows/daily-repo-chronicle.lock.yml @@ -1120,6 +1120,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-safe-output-integrator.lock.yml b/.github/workflows/daily-safe-output-integrator.lock.yml index 2e06453ec7..9768584889 100644 --- a/.github/workflows/daily-safe-output-integrator.lock.yml +++ b/.github/workflows/daily-safe-output-integrator.lock.yml @@ -1134,6 +1134,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-safe-output-optimizer.lock.yml b/.github/workflows/daily-safe-output-optimizer.lock.yml index 893b52e42b..09a1423a69 100644 --- a/.github/workflows/daily-safe-output-optimizer.lock.yml +++ b/.github/workflows/daily-safe-output-optimizer.lock.yml @@ -1289,6 +1289,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-safe-outputs-conformance.lock.yml b/.github/workflows/daily-safe-outputs-conformance.lock.yml index eae081cacd..9ee64804a4 100644 --- a/.github/workflows/daily-safe-outputs-conformance.lock.yml +++ b/.github/workflows/daily-safe-outputs-conformance.lock.yml @@ -1100,6 +1100,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-secrets-analysis.lock.yml b/.github/workflows/daily-secrets-analysis.lock.yml index 4bbaf69c8d..6406744be4 100644 --- a/.github/workflows/daily-secrets-analysis.lock.yml +++ b/.github/workflows/daily-secrets-analysis.lock.yml @@ -1067,6 +1067,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-security-red-team.lock.yml b/.github/workflows/daily-security-red-team.lock.yml index 8cb68e138b..5f08891c9d 100644 --- a/.github/workflows/daily-security-red-team.lock.yml +++ b/.github/workflows/daily-security-red-team.lock.yml @@ -1104,6 +1104,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-semgrep-scan.lock.yml b/.github/workflows/daily-semgrep-scan.lock.yml index cacfdef810..4b399d134d 100644 --- a/.github/workflows/daily-semgrep-scan.lock.yml +++ b/.github/workflows/daily-semgrep-scan.lock.yml @@ -1066,6 +1066,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-syntax-error-quality.lock.yml b/.github/workflows/daily-syntax-error-quality.lock.yml index d88bf17404..5642a5f743 100644 --- a/.github/workflows/daily-syntax-error-quality.lock.yml +++ b/.github/workflows/daily-syntax-error-quality.lock.yml @@ -1077,6 +1077,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-team-evolution-insights.lock.yml b/.github/workflows/daily-team-evolution-insights.lock.yml index 001e1eecfa..df933be580 100644 --- a/.github/workflows/daily-team-evolution-insights.lock.yml +++ b/.github/workflows/daily-team-evolution-insights.lock.yml @@ -1098,6 +1098,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-team-status.lock.yml b/.github/workflows/daily-team-status.lock.yml index c102861d3f..1a47286aa9 100644 --- a/.github/workflows/daily-team-status.lock.yml +++ b/.github/workflows/daily-team-status.lock.yml @@ -1099,6 +1099,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-testify-uber-super-expert.lock.yml b/.github/workflows/daily-testify-uber-super-expert.lock.yml index 9c9273b4d7..df7f45fec1 100644 --- a/.github/workflows/daily-testify-uber-super-expert.lock.yml +++ b/.github/workflows/daily-testify-uber-super-expert.lock.yml @@ -1313,6 +1313,7 @@ jobs: echo "Token invalidation step complete." - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/daily-workflow-updater.lock.yml b/.github/workflows/daily-workflow-updater.lock.yml index 670d33c852..9328c2ec00 100644 --- a/.github/workflows/daily-workflow-updater.lock.yml +++ b/.github/workflows/daily-workflow-updater.lock.yml @@ -1091,6 +1091,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/dead-code-remover.lock.yml b/.github/workflows/dead-code-remover.lock.yml index e3b83cbef1..a95969f1d8 100644 --- a/.github/workflows/dead-code-remover.lock.yml +++ b/.github/workflows/dead-code-remover.lock.yml @@ -1193,6 +1193,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/deep-report.lock.yml b/.github/workflows/deep-report.lock.yml index 57960c0e01..347b7df84f 100644 --- a/.github/workflows/deep-report.lock.yml +++ b/.github/workflows/deep-report.lock.yml @@ -1340,6 +1340,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/delight.lock.yml b/.github/workflows/delight.lock.yml index 00fb96165d..c9c837f706 100644 --- a/.github/workflows/delight.lock.yml +++ b/.github/workflows/delight.lock.yml @@ -1217,6 +1217,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/dependabot-burner.lock.yml b/.github/workflows/dependabot-burner.lock.yml index 4a8faee6d9..e2fd6da772 100644 --- a/.github/workflows/dependabot-burner.lock.yml +++ b/.github/workflows/dependabot-burner.lock.yml @@ -1076,6 +1076,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/dependabot-go-checker.lock.yml b/.github/workflows/dependabot-go-checker.lock.yml index b3525a653b..b0e15842ee 100644 --- a/.github/workflows/dependabot-go-checker.lock.yml +++ b/.github/workflows/dependabot-go-checker.lock.yml @@ -1062,6 +1062,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml index 6c752ab208..df7f6d070f 100644 --- a/.github/workflows/dev-hawk.lock.yml +++ b/.github/workflows/dev-hawk.lock.yml @@ -1181,6 +1181,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index 957afa93a2..20ce1679b4 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -1028,6 +1028,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index aa2ba94b56..e6b7d5ae35 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -1520,6 +1520,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index a2899383cb..c5b79d1b13 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -1238,6 +1238,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/discussion-task-miner.lock.yml b/.github/workflows/discussion-task-miner.lock.yml index 2419a6f0f3..46622dfc1c 100644 --- a/.github/workflows/discussion-task-miner.lock.yml +++ b/.github/workflows/discussion-task-miner.lock.yml @@ -1211,6 +1211,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml index cf7c9bd113..b96c8a2d53 100644 --- a/.github/workflows/docs-noob-tester.lock.yml +++ b/.github/workflows/docs-noob-tester.lock.yml @@ -1082,6 +1082,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/draft-pr-cleanup.lock.yml b/.github/workflows/draft-pr-cleanup.lock.yml index 8f42adfdb8..ac789bd6c1 100644 --- a/.github/workflows/draft-pr-cleanup.lock.yml +++ b/.github/workflows/draft-pr-cleanup.lock.yml @@ -1076,6 +1076,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml index 63b29e2cf5..a3dbdeb5a4 100644 --- a/.github/workflows/duplicate-code-detector.lock.yml +++ b/.github/workflows/duplicate-code-detector.lock.yml @@ -1097,6 +1097,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/example-workflow-analyzer.lock.yml b/.github/workflows/example-workflow-analyzer.lock.yml index 8876483f25..2f6986f901 100644 --- a/.github/workflows/example-workflow-analyzer.lock.yml +++ b/.github/workflows/example-workflow-analyzer.lock.yml @@ -1164,6 +1164,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/firewall-escape.lock.yml b/.github/workflows/firewall-escape.lock.yml index 20bd45d057..5807c3cdd2 100644 --- a/.github/workflows/firewall-escape.lock.yml +++ b/.github/workflows/firewall-escape.lock.yml @@ -1259,6 +1259,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/functional-pragmatist.lock.yml b/.github/workflows/functional-pragmatist.lock.yml index c4fd605bc1..b3957cdf97 100644 --- a/.github/workflows/functional-pragmatist.lock.yml +++ b/.github/workflows/functional-pragmatist.lock.yml @@ -1104,6 +1104,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/github-mcp-structural-analysis.lock.yml b/.github/workflows/github-mcp-structural-analysis.lock.yml index 2630408164..b4c3ad69ec 100644 --- a/.github/workflows/github-mcp-structural-analysis.lock.yml +++ b/.github/workflows/github-mcp-structural-analysis.lock.yml @@ -1176,6 +1176,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml index 68d4a7ae68..fa9c56f3de 100644 --- a/.github/workflows/github-mcp-tools-report.lock.yml +++ b/.github/workflows/github-mcp-tools-report.lock.yml @@ -1213,6 +1213,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/github-remote-mcp-auth-test.lock.yml b/.github/workflows/github-remote-mcp-auth-test.lock.yml index 498e7d61af..58af158312 100644 --- a/.github/workflows/github-remote-mcp-auth-test.lock.yml +++ b/.github/workflows/github-remote-mcp-auth-test.lock.yml @@ -1045,6 +1045,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/glossary-maintainer.lock.yml b/.github/workflows/glossary-maintainer.lock.yml index e999c40c39..0dec5955a4 100644 --- a/.github/workflows/glossary-maintainer.lock.yml +++ b/.github/workflows/glossary-maintainer.lock.yml @@ -1441,6 +1441,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/go-fan.lock.yml b/.github/workflows/go-fan.lock.yml index 0f9bf2fd62..d08db5c522 100644 --- a/.github/workflows/go-fan.lock.yml +++ b/.github/workflows/go-fan.lock.yml @@ -1170,6 +1170,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index 17972f4611..dd5c2b4fb2 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -1373,6 +1373,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml index 938ff45d68..7fb666f460 100644 --- a/.github/workflows/go-pattern-detector.lock.yml +++ b/.github/workflows/go-pattern-detector.lock.yml @@ -1163,6 +1163,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/gpclean.lock.yml b/.github/workflows/gpclean.lock.yml index dc8ab39c11..4db81b8c4b 100644 --- a/.github/workflows/gpclean.lock.yml +++ b/.github/workflows/gpclean.lock.yml @@ -1072,6 +1072,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml index 29b6b91aad..a6924be62c 100644 --- a/.github/workflows/grumpy-reviewer.lock.yml +++ b/.github/workflows/grumpy-reviewer.lock.yml @@ -1217,6 +1217,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/hourly-ci-cleaner.lock.yml b/.github/workflows/hourly-ci-cleaner.lock.yml index 660b454beb..ec387f588c 100644 --- a/.github/workflows/hourly-ci-cleaner.lock.yml +++ b/.github/workflows/hourly-ci-cleaner.lock.yml @@ -1211,6 +1211,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml index 78df62b7e7..248244f987 100644 --- a/.github/workflows/instructions-janitor.lock.yml +++ b/.github/workflows/instructions-janitor.lock.yml @@ -1194,6 +1194,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/issue-arborist.lock.yml b/.github/workflows/issue-arborist.lock.yml index 378da86600..87a2d2ac30 100644 --- a/.github/workflows/issue-arborist.lock.yml +++ b/.github/workflows/issue-arborist.lock.yml @@ -1095,6 +1095,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/issue-monster.lock.yml b/.github/workflows/issue-monster.lock.yml index efd91245e3..0eed28dc01 100644 --- a/.github/workflows/issue-monster.lock.yml +++ b/.github/workflows/issue-monster.lock.yml @@ -1838,6 +1838,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/issue-triage-agent.lock.yml b/.github/workflows/issue-triage-agent.lock.yml index 40157af169..a4b2ef527b 100644 --- a/.github/workflows/issue-triage-agent.lock.yml +++ b/.github/workflows/issue-triage-agent.lock.yml @@ -1036,6 +1036,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/jsweep.lock.yml b/.github/workflows/jsweep.lock.yml index 6190b2242f..d3303f4d9c 100644 --- a/.github/workflows/jsweep.lock.yml +++ b/.github/workflows/jsweep.lock.yml @@ -1147,6 +1147,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/layout-spec-maintainer.lock.yml b/.github/workflows/layout-spec-maintainer.lock.yml index 68e68f215d..3e06bcbd6f 100644 --- a/.github/workflows/layout-spec-maintainer.lock.yml +++ b/.github/workflows/layout-spec-maintainer.lock.yml @@ -1133,6 +1133,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/lockfile-stats.lock.yml b/.github/workflows/lockfile-stats.lock.yml index 722c7d3255..b36c082c9b 100644 --- a/.github/workflows/lockfile-stats.lock.yml +++ b/.github/workflows/lockfile-stats.lock.yml @@ -1118,6 +1118,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index fd972055b0..9c984de9e2 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -1829,6 +1829,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml index 2ff44e94d1..86be37626d 100644 --- a/.github/workflows/mergefest.lock.yml +++ b/.github/workflows/mergefest.lock.yml @@ -1220,6 +1220,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/notion-issue-summary.lock.yml b/.github/workflows/notion-issue-summary.lock.yml index 39f9854de4..f0de34b1e6 100644 --- a/.github/workflows/notion-issue-summary.lock.yml +++ b/.github/workflows/notion-issue-summary.lock.yml @@ -1046,6 +1046,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/org-health-report.lock.yml b/.github/workflows/org-health-report.lock.yml index d96590dd3a..5c41ac525d 100644 --- a/.github/workflows/org-health-report.lock.yml +++ b/.github/workflows/org-health-report.lock.yml @@ -1127,6 +1127,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml index d805e0a064..02f6896c99 100644 --- a/.github/workflows/pdf-summary.lock.yml +++ b/.github/workflows/pdf-summary.lock.yml @@ -1261,6 +1261,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml index d41cc20bab..742570b2a9 100644 --- a/.github/workflows/plan.lock.yml +++ b/.github/workflows/plan.lock.yml @@ -1185,6 +1185,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/portfolio-analyst.lock.yml b/.github/workflows/portfolio-analyst.lock.yml index b43e7e0d9e..7a7642000e 100644 --- a/.github/workflows/portfolio-analyst.lock.yml +++ b/.github/workflows/portfolio-analyst.lock.yml @@ -1209,6 +1209,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml index 73a3b961f9..acec7df98d 100644 --- a/.github/workflows/pr-nitpick-reviewer.lock.yml +++ b/.github/workflows/pr-nitpick-reviewer.lock.yml @@ -1285,6 +1285,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/pr-triage-agent.lock.yml b/.github/workflows/pr-triage-agent.lock.yml index dddb2494a3..b36976ba45 100644 --- a/.github/workflows/pr-triage-agent.lock.yml +++ b/.github/workflows/pr-triage-agent.lock.yml @@ -1196,6 +1196,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml index 4afc652797..08eb8757a9 100644 --- a/.github/workflows/prompt-clustering-analysis.lock.yml +++ b/.github/workflows/prompt-clustering-analysis.lock.yml @@ -1260,6 +1260,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index 577ec6ee17..9b041939df 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -1192,6 +1192,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index fa0e71e814..cf0a1e6df5 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -1422,6 +1422,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/refiner.lock.yml b/.github/workflows/refiner.lock.yml index bc6200896e..ff9edc9d23 100644 --- a/.github/workflows/refiner.lock.yml +++ b/.github/workflows/refiner.lock.yml @@ -1185,6 +1185,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index eec0f31824..00b314e1b1 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -1415,6 +1415,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/repo-audit-analyzer.lock.yml b/.github/workflows/repo-audit-analyzer.lock.yml index 70791a2e54..dd0539b8f9 100644 --- a/.github/workflows/repo-audit-analyzer.lock.yml +++ b/.github/workflows/repo-audit-analyzer.lock.yml @@ -1070,6 +1070,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/repo-tree-map.lock.yml b/.github/workflows/repo-tree-map.lock.yml index a47364f72f..1f0a98213e 100644 --- a/.github/workflows/repo-tree-map.lock.yml +++ b/.github/workflows/repo-tree-map.lock.yml @@ -1036,6 +1036,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml index b9c0c59a09..61a091cbb3 100644 --- a/.github/workflows/repository-quality-improver.lock.yml +++ b/.github/workflows/repository-quality-improver.lock.yml @@ -1081,6 +1081,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/research.lock.yml b/.github/workflows/research.lock.yml index b280598653..3690da9730 100644 --- a/.github/workflows/research.lock.yml +++ b/.github/workflows/research.lock.yml @@ -1069,6 +1069,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml index b1ef2e328b..ddad80a1f8 100644 --- a/.github/workflows/safe-output-health.lock.yml +++ b/.github/workflows/safe-output-health.lock.yml @@ -1219,6 +1219,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/schema-consistency-checker.lock.yml b/.github/workflows/schema-consistency-checker.lock.yml index 93fcd7c8cb..6f24bd136e 100644 --- a/.github/workflows/schema-consistency-checker.lock.yml +++ b/.github/workflows/schema-consistency-checker.lock.yml @@ -1118,6 +1118,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml index 614fca5179..a402ec565c 100644 --- a/.github/workflows/scout.lock.yml +++ b/.github/workflows/scout.lock.yml @@ -1451,6 +1451,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/security-alert-burndown.campaign.g.lock.yml b/.github/workflows/security-alert-burndown.campaign.g.lock.yml index aaa9f44344..6d71089937 100644 --- a/.github/workflows/security-alert-burndown.campaign.g.lock.yml +++ b/.github/workflows/security-alert-burndown.campaign.g.lock.yml @@ -1324,6 +1324,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/security-compliance.lock.yml b/.github/workflows/security-compliance.lock.yml index d2a3a83af8..829ebc7ed7 100644 --- a/.github/workflows/security-compliance.lock.yml +++ b/.github/workflows/security-compliance.lock.yml @@ -1175,6 +1175,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/security-review.lock.yml b/.github/workflows/security-review.lock.yml index 4eae68d43e..297d4fbc74 100644 --- a/.github/workflows/security-review.lock.yml +++ b/.github/workflows/security-review.lock.yml @@ -1292,6 +1292,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml index 1880ea02c1..2292b765a3 100644 --- a/.github/workflows/semantic-function-refactor.lock.yml +++ b/.github/workflows/semantic-function-refactor.lock.yml @@ -1161,6 +1161,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/sergo.lock.yml b/.github/workflows/sergo.lock.yml index 32ee19bf39..7b7503ff6f 100644 --- a/.github/workflows/sergo.lock.yml +++ b/.github/workflows/sergo.lock.yml @@ -1169,6 +1169,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/slide-deck-maintainer.lock.yml b/.github/workflows/slide-deck-maintainer.lock.yml index 8697bb9665..c636b0f995 100644 --- a/.github/workflows/slide-deck-maintainer.lock.yml +++ b/.github/workflows/slide-deck-maintainer.lock.yml @@ -1270,6 +1270,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-agent-all-merged.lock.yml b/.github/workflows/smoke-agent-all-merged.lock.yml index 9bd03c253d..77a579e3a5 100644 --- a/.github/workflows/smoke-agent-all-merged.lock.yml +++ b/.github/workflows/smoke-agent-all-merged.lock.yml @@ -1092,6 +1092,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-agent-all-none.lock.yml b/.github/workflows/smoke-agent-all-none.lock.yml index b1b0705f1a..603a41bc16 100644 --- a/.github/workflows/smoke-agent-all-none.lock.yml +++ b/.github/workflows/smoke-agent-all-none.lock.yml @@ -1092,6 +1092,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-agent-public-approved.lock.yml b/.github/workflows/smoke-agent-public-approved.lock.yml index ba609c5202..afe946b6e1 100644 --- a/.github/workflows/smoke-agent-public-approved.lock.yml +++ b/.github/workflows/smoke-agent-public-approved.lock.yml @@ -1140,6 +1140,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-agent-public-none.lock.yml b/.github/workflows/smoke-agent-public-none.lock.yml index 60616dcb5f..192fed655a 100644 --- a/.github/workflows/smoke-agent-public-none.lock.yml +++ b/.github/workflows/smoke-agent-public-none.lock.yml @@ -1092,6 +1092,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-agent-scoped-approved.lock.yml b/.github/workflows/smoke-agent-scoped-approved.lock.yml index 016436cf5a..5b3916b309 100644 --- a/.github/workflows/smoke-agent-scoped-approved.lock.yml +++ b/.github/workflows/smoke-agent-scoped-approved.lock.yml @@ -1096,6 +1096,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-call-workflow.lock.yml b/.github/workflows/smoke-call-workflow.lock.yml index b780e0a719..e92a956586 100644 --- a/.github/workflows/smoke-call-workflow.lock.yml +++ b/.github/workflows/smoke-call-workflow.lock.yml @@ -1071,6 +1071,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index bceba229df..24dc14c9df 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -2665,6 +2665,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index 2c73bf9bca..5005320155 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -1564,6 +1564,7 @@ jobs: payload: ${{ steps.process_safe_outputs.outputs.action_add_smoked_label_payload }} - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-copilot-arm.lock.yml b/.github/workflows/smoke-copilot-arm.lock.yml index ed506a67b2..f036c2e8f6 100644 --- a/.github/workflows/smoke-copilot-arm.lock.yml +++ b/.github/workflows/smoke-copilot-arm.lock.yml @@ -2026,6 +2026,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 81e12c6dfe..ab42a8037c 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -2073,6 +2073,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-create-cross-repo-pr.lock.yml b/.github/workflows/smoke-create-cross-repo-pr.lock.yml index a851eb6b98..c1b5296564 100644 --- a/.github/workflows/smoke-create-cross-repo-pr.lock.yml +++ b/.github/workflows/smoke-create-cross-repo-pr.lock.yml @@ -1257,6 +1257,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-gemini.lock.yml b/.github/workflows/smoke-gemini.lock.yml index c9fc00abc6..005bf1a488 100644 --- a/.github/workflows/smoke-gemini.lock.yml +++ b/.github/workflows/smoke-gemini.lock.yml @@ -1327,6 +1327,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-multi-pr.lock.yml b/.github/workflows/smoke-multi-pr.lock.yml index 0813b6b450..c0742380a4 100644 --- a/.github/workflows/smoke-multi-pr.lock.yml +++ b/.github/workflows/smoke-multi-pr.lock.yml @@ -1245,6 +1245,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-project.lock.yml b/.github/workflows/smoke-project.lock.yml index b5d84288a7..bece7c3ae3 100644 --- a/.github/workflows/smoke-project.lock.yml +++ b/.github/workflows/smoke-project.lock.yml @@ -1382,6 +1382,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-temporary-id.lock.yml b/.github/workflows/smoke-temporary-id.lock.yml index d6b7324428..f361e8221e 100644 --- a/.github/workflows/smoke-temporary-id.lock.yml +++ b/.github/workflows/smoke-temporary-id.lock.yml @@ -1183,6 +1183,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-test-tools.lock.yml b/.github/workflows/smoke-test-tools.lock.yml index 94f59597c7..e678247272 100644 --- a/.github/workflows/smoke-test-tools.lock.yml +++ b/.github/workflows/smoke-test-tools.lock.yml @@ -1142,6 +1142,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-update-cross-repo-pr.lock.yml b/.github/workflows/smoke-update-cross-repo-pr.lock.yml index c05d0a815c..a4173f8e9d 100644 --- a/.github/workflows/smoke-update-cross-repo-pr.lock.yml +++ b/.github/workflows/smoke-update-cross-repo-pr.lock.yml @@ -1256,6 +1256,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/smoke-workflow-call-with-inputs.lock.yml b/.github/workflows/smoke-workflow-call-with-inputs.lock.yml index 31712032f4..fe5f00055c 100644 --- a/.github/workflows/smoke-workflow-call-with-inputs.lock.yml +++ b/.github/workflows/smoke-workflow-call-with-inputs.lock.yml @@ -1138,6 +1138,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: ${{ needs.activation.outputs.artifact_prefix }}agent diff --git a/.github/workflows/smoke-workflow-call.lock.yml b/.github/workflows/smoke-workflow-call.lock.yml index c60f14c723..8cc4f49005 100644 --- a/.github/workflows/smoke-workflow-call.lock.yml +++ b/.github/workflows/smoke-workflow-call.lock.yml @@ -1132,6 +1132,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: ${{ needs.activation.outputs.artifact_prefix }}agent diff --git a/.github/workflows/stale-repo-identifier.lock.yml b/.github/workflows/stale-repo-identifier.lock.yml index 8d4ed10d7d..2d552c2f2d 100644 --- a/.github/workflows/stale-repo-identifier.lock.yml +++ b/.github/workflows/stale-repo-identifier.lock.yml @@ -1185,6 +1185,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml index 192c517687..46304019db 100644 --- a/.github/workflows/static-analysis-report.lock.yml +++ b/.github/workflows/static-analysis-report.lock.yml @@ -1201,6 +1201,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/step-name-alignment.lock.yml b/.github/workflows/step-name-alignment.lock.yml index 086c4f07be..7524b8369f 100644 --- a/.github/workflows/step-name-alignment.lock.yml +++ b/.github/workflows/step-name-alignment.lock.yml @@ -1131,6 +1131,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/sub-issue-closer.lock.yml b/.github/workflows/sub-issue-closer.lock.yml index 3761a47f7d..82fbfdbf17 100644 --- a/.github/workflows/sub-issue-closer.lock.yml +++ b/.github/workflows/sub-issue-closer.lock.yml @@ -1078,6 +1078,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index f9e450e69f..af327bbda2 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -1080,6 +1080,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index 3e53ef1272..4e3dfd3c00 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -1460,6 +1460,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/terminal-stylist.lock.yml b/.github/workflows/terminal-stylist.lock.yml index f9124e6d71..aef9389f2f 100644 --- a/.github/workflows/terminal-stylist.lock.yml +++ b/.github/workflows/terminal-stylist.lock.yml @@ -1055,6 +1055,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/test-create-pr-error-handling.lock.yml b/.github/workflows/test-create-pr-error-handling.lock.yml index f902a970c5..99c9503d02 100644 --- a/.github/workflows/test-create-pr-error-handling.lock.yml +++ b/.github/workflows/test-create-pr-error-handling.lock.yml @@ -1166,6 +1166,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/test-dispatcher.lock.yml b/.github/workflows/test-dispatcher.lock.yml index 0100d839a7..735a062f00 100644 --- a/.github/workflows/test-dispatcher.lock.yml +++ b/.github/workflows/test-dispatcher.lock.yml @@ -1007,6 +1007,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/test-project-url-default.lock.yml b/.github/workflows/test-project-url-default.lock.yml index 45528477a1..206e2cf7e8 100644 --- a/.github/workflows/test-project-url-default.lock.yml +++ b/.github/workflows/test-project-url-default.lock.yml @@ -1075,6 +1075,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index 99ee6e564a..b7aba2bbb5 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -1286,6 +1286,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml index 864271590f..3e9e97a2bb 100644 --- a/.github/workflows/typist.lock.yml +++ b/.github/workflows/typist.lock.yml @@ -1136,6 +1136,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/ubuntu-image-analyzer.lock.yml b/.github/workflows/ubuntu-image-analyzer.lock.yml index 2b8abae287..b03ca6a4d9 100644 --- a/.github/workflows/ubuntu-image-analyzer.lock.yml +++ b/.github/workflows/ubuntu-image-analyzer.lock.yml @@ -1192,6 +1192,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index dbab44b3f5..945f361949 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -1601,6 +1601,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/update-astro.lock.yml b/.github/workflows/update-astro.lock.yml index c8bcf46274..0f31138c43 100644 --- a/.github/workflows/update-astro.lock.yml +++ b/.github/workflows/update-astro.lock.yml @@ -1202,6 +1202,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml index d33c3f97ce..5695e9c7b5 100644 --- a/.github/workflows/video-analyzer.lock.yml +++ b/.github/workflows/video-analyzer.lock.yml @@ -1072,6 +1072,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/weekly-blog-post-writer.lock.yml b/.github/workflows/weekly-blog-post-writer.lock.yml index d85cde0f0d..6e1ed43a13 100644 --- a/.github/workflows/weekly-blog-post-writer.lock.yml +++ b/.github/workflows/weekly-blog-post-writer.lock.yml @@ -1426,6 +1426,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/weekly-editors-health-check.lock.yml b/.github/workflows/weekly-editors-health-check.lock.yml index 51dbc7144e..a06f197a9f 100644 --- a/.github/workflows/weekly-editors-health-check.lock.yml +++ b/.github/workflows/weekly-editors-health-check.lock.yml @@ -1167,6 +1167,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml index b5470c1885..91191361e3 100644 --- a/.github/workflows/weekly-issue-summary.lock.yml +++ b/.github/workflows/weekly-issue-summary.lock.yml @@ -1111,6 +1111,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/weekly-safe-outputs-spec-review.lock.yml b/.github/workflows/weekly-safe-outputs-spec-review.lock.yml index 387fb37200..abff6e05e1 100644 --- a/.github/workflows/weekly-safe-outputs-spec-review.lock.yml +++ b/.github/workflows/weekly-safe-outputs-spec-review.lock.yml @@ -1099,6 +1099,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/workflow-generator.lock.yml b/.github/workflows/workflow-generator.lock.yml index d10b92c1c1..a3705fc3ee 100644 --- a/.github/workflows/workflow-generator.lock.yml +++ b/.github/workflows/workflow-generator.lock.yml @@ -1198,6 +1198,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/workflow-health-manager.lock.yml b/.github/workflows/workflow-health-manager.lock.yml index 0aa72c1ae6..aa72747537 100644 --- a/.github/workflows/workflow-health-manager.lock.yml +++ b/.github/workflows/workflow-health-manager.lock.yml @@ -1268,6 +1268,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/workflow-normalizer.lock.yml b/.github/workflows/workflow-normalizer.lock.yml index 0f5c7a0fb0..5288b98ac1 100644 --- a/.github/workflows/workflow-normalizer.lock.yml +++ b/.github/workflows/workflow-normalizer.lock.yml @@ -1123,6 +1123,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/.github/workflows/workflow-skill-extractor.lock.yml b/.github/workflows/workflow-skill-extractor.lock.yml index d97ff3606f..4c781d9d4c 100644 --- a/.github/workflows/workflow-skill-extractor.lock.yml +++ b/.github/workflows/workflow-skill-extractor.lock.yml @@ -1093,6 +1093,7 @@ jobs: await main(); - name: Upload safe output items if: always() + continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent diff --git a/pkg/workflow/compiler_safe_outputs_job.go b/pkg/workflow/compiler_safe_outputs_job.go index 8800b73126..56476a9abe 100644 --- a/pkg/workflow/compiler_safe_outputs_job.go +++ b/pkg/workflow/compiler_safe_outputs_job.go @@ -525,10 +525,14 @@ func buildDetectionSuccessCondition() ConditionNode { // The file is written to /tmp/gh-aw/safe-output-items.jsonl so it is merged into the // same "agent" artifact that the main job uploads, rather than a separate artifact. // prefix is prepended to the artifact name; use empty string for non-workflow_call workflows. +// continue-on-error is set to true because actions/upload-artifact v4+ returns a 409 +// conflict when a second job tries to upload to an artifact name that already exists; +// the upload conflict must not fail the safe_outputs job. func buildSafeOutputItemsManifestUploadStep(prefix string) []string { return []string{ " - name: Upload safe output items\n", " if: always()\n", + " continue-on-error: true\n", fmt.Sprintf(" uses: %s\n", GetActionPin("actions/upload-artifact")), " with:\n", fmt.Sprintf(" name: %sagent\n", prefix), From 29c9973c63b5239f2d2dd84fca68de844593b1cd Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Thu, 19 Mar 2026 10:37:59 -0700 Subject: [PATCH 12/17] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- pkg/workflow/safe_outputs_tools_filtering.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/workflow/safe_outputs_tools_filtering.go b/pkg/workflow/safe_outputs_tools_filtering.go index 6533dfea76..3190fbdec0 100644 --- a/pkg/workflow/safe_outputs_tools_filtering.go +++ b/pkg/workflow/safe_outputs_tools_filtering.go @@ -253,6 +253,12 @@ func generateFilteredToolsJSON(data *WorkflowData, markdownPath string) (string, if len(data.SafeOutputs.Actions) > 0 { safeOutputsConfigLog.Printf("Adding %d custom action tools", len(data.SafeOutputs.Actions)) + // Ensure all configured actions are resolved (action.yml metadata loaded) + // before generating tool definitions that depend on ActionDescription/Inputs. + if err := resolveAllActions(); err != nil { + return "", fmt.Errorf("failed to resolve actions before generating safe-output tools: %w", err) + } + actionNames := make([]string, 0, len(data.SafeOutputs.Actions)) for actionName := range data.SafeOutputs.Actions { actionNames = append(actionNames, actionName) From b3559c92e6f7d0a721c4a92b4c7d537ab6d52508 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 18:02:48 +0000 Subject: [PATCH 13/17] fix: remove stale resolveAllActions() call, add action handler tests, clean up comments Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../js/safe_output_action_handler.test.cjs | 117 ++++++++++++++++++ actions/setup/js/safe_output_helpers.test.cjs | 47 ++++++- pkg/workflow/safe_outputs_actions.go | 5 +- pkg/workflow/safe_outputs_tools_filtering.go | 11 +- 4 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 actions/setup/js/safe_output_action_handler.test.cjs diff --git a/actions/setup/js/safe_output_action_handler.test.cjs b/actions/setup/js/safe_output_action_handler.test.cjs new file mode 100644 index 0000000000..1b214221a2 --- /dev/null +++ b/actions/setup/js/safe_output_action_handler.test.cjs @@ -0,0 +1,117 @@ +// @ts-check + +import { describe, it, expect, beforeEach, vi } from "vitest"; +import { main } from "./safe_output_action_handler.cjs"; + +describe("safe_output_action_handler", () => { + beforeEach(() => { + // Provide a mock global `core` matching the @actions/core API surface used by the handler. + global.core = { + info: vi.fn(), + debug: vi.fn(), + warning: vi.fn(), + error: vi.fn(), + setOutput: vi.fn(), + setFailed: vi.fn(), + }; + }); + + describe("main() — factory", () => { + it("should return a function (the handler) when called", async () => { + const handler = await main({ action_name: "my_action" }); + expect(typeof handler).toBe("function"); + }); + + it("should use 'unknown_action' when config is not provided", async () => { + const handler = await main(); + expect(typeof handler).toBe("function"); + }); + }); + + describe("handler — basic payload export", () => { + it("should export the payload as a step output and return success", async () => { + const handler = await main({ action_name: "add_label" }); + + const message = { type: "add_label", labels: "bug" }; + const result = await handler(message, {}, new Map()); + + expect(result.success).toBe(true); + expect(result.action_name).toBe("add_label"); + + // 'type' (an INTERNAL_MESSAGE_FIELDS member) must be stripped from the exported payload + const exported = JSON.parse(global.core.setOutput.mock.calls[0][1]); + expect(exported).toHaveProperty("labels", "bug"); + expect(exported).not.toHaveProperty("type"); + }); + + it("should use the correct output key format action__payload", async () => { + const handler = await main({ action_name: "my_action" }); + await handler({ type: "my_action", key: "value" }, {}, new Map()); + + expect(global.core.setOutput).toHaveBeenCalledWith("action_my_action_payload", expect.any(String)); + }); + + it("should pass through non-string values without sanitization", async () => { + const handler = await main({ action_name: "my_action" }); + const message = { type: "my_action", count: 42, active: true }; + + await handler(message, {}, new Map()); + + const exported = JSON.parse(global.core.setOutput.mock.calls[0][1]); + expect(exported.count).toBe(42); + expect(exported.active).toBe(true); + }); + }); + + describe("handler — once-only enforcement", () => { + it("should return an error on the second call", async () => { + const handler = await main({ action_name: "my_action" }); + const message = { labels: "bug" }; + + const first = await handler(message, {}, new Map()); + expect(first.success).toBe(true); + + const second = await handler(message, {}, new Map()); + expect(second.success).toBe(false); + expect(second.error).toContain("can only be called once"); + + // setOutput should only be called once (for the first invocation) + expect(global.core.setOutput).toHaveBeenCalledTimes(1); + }); + }); + + describe("handler — INTERNAL_MESSAGE_FIELDS filtering", () => { + it("should strip 'type' from the exported payload", async () => { + const handler = await main({ action_name: "my_action" }); + await handler({ type: "my_action", title: "hello" }, {}, new Map()); + + const exported = JSON.parse(global.core.setOutput.mock.calls[0][1]); + expect(exported).not.toHaveProperty("type"); + expect(exported).toHaveProperty("title", "hello"); + }); + }); + + describe("handler — temporaryIdMap substitution", () => { + it("should substitute temporary ID references in string values", async () => { + const handler = await main({ action_name: "my_action" }); + // The temporary ID pattern is "#aw_XXXX" (3-12 alphanumeric chars with #aw_ prefix) + const temporaryIdMap = new Map([["aw_abc1", { repo: "owner/repo", number: 99 }]]); + await handler({ type: "my_action", body: "Fixes #aw_abc1" }, {}, temporaryIdMap); + + const exported = JSON.parse(global.core.setOutput.mock.calls[0][1]); + // replaceTemporaryIdReferences should replace '#aw_abc1' with the issue reference + expect(exported.body).not.toContain("#aw_abc1"); + }); + }); + + describe("handler — empty payload", () => { + it("should handle an empty message (only internal fields)", async () => { + const handler = await main({ action_name: "my_action" }); + const result = await handler({ type: "my_action" }, {}, new Map()); + + expect(result.success).toBe(true); + const exported = JSON.parse(global.core.setOutput.mock.calls[0][1]); + expect(exported).toEqual({}); + }); + }); +}); diff --git a/actions/setup/js/safe_output_helpers.test.cjs b/actions/setup/js/safe_output_helpers.test.cjs index 6cc63b2291..9e68fe46f9 100644 --- a/actions/setup/js/safe_output_helpers.test.cjs +++ b/actions/setup/js/safe_output_helpers.test.cjs @@ -1,4 +1,4 @@ -import { describe, it, expect, beforeEach } from "vitest"; +import { describe, it, expect, beforeEach, vi } from "vitest"; describe("safe_output_helpers", () => { let helpers; @@ -658,4 +658,49 @@ describe("safe_output_helpers", () => { } }); }); + + describe("loadCustomSafeOutputActionHandlers", () => { + beforeEach(() => { + delete process.env.GH_AW_SAFE_OUTPUT_ACTIONS; + global.core = { + info: vi.fn(), + debug: vi.fn(), + warning: vi.fn(), + error: vi.fn(), + }; + }); + + it("should return empty map when GH_AW_SAFE_OUTPUT_ACTIONS is not set", () => { + const result = helpers.loadCustomSafeOutputActionHandlers(); + expect(result).toBeInstanceOf(Map); + expect(result.size).toBe(0); + }); + + it("should parse and return action handlers map from env var", () => { + process.env.GH_AW_SAFE_OUTPUT_ACTIONS = JSON.stringify({ + add_smoked_label: "add_smoked_label", + notify_slack: "notify_slack", + }); + + const result = helpers.loadCustomSafeOutputActionHandlers(); + expect(result).toBeInstanceOf(Map); + expect(result.size).toBe(2); + expect(result.get("add_smoked_label")).toBe("add_smoked_label"); + expect(result.get("notify_slack")).toBe("notify_slack"); + }); + + it("should return empty map when env var contains invalid JSON", () => { + process.env.GH_AW_SAFE_OUTPUT_ACTIONS = "not-valid-json"; + const result = helpers.loadCustomSafeOutputActionHandlers(); + expect(result).toBeInstanceOf(Map); + expect(result.size).toBe(0); + }); + + it("should return empty map when env var contains empty object", () => { + process.env.GH_AW_SAFE_OUTPUT_ACTIONS = JSON.stringify({}); + const result = helpers.loadCustomSafeOutputActionHandlers(); + expect(result).toBeInstanceOf(Map); + expect(result.size).toBe(0); + }); + }); }); diff --git a/pkg/workflow/safe_outputs_actions.go b/pkg/workflow/safe_outputs_actions.go index eb6b1aecab..9f76c3881c 100644 --- a/pkg/workflow/safe_outputs_actions.go +++ b/pkg/workflow/safe_outputs_actions.go @@ -199,9 +199,6 @@ func (c *Compiler) fetchAndParseActionYAML(actionName string, config *SafeOutput } } -// fetchRemoteActionYAML fetches and parses action.yml from a GitHub repository. -// It tries both action.yml and action.yaml filenames. - // extractSHAFromPinnedRef parses the SHA from a pinned action reference string. // The format produced by formatActionReference is "repo@sha # version". // Returns the SHA string, or empty string if it cannot be parsed. @@ -222,6 +219,8 @@ func extractSHAFromPinnedRef(pinned string) string { return "" } +// fetchRemoteActionYAML fetches and parses action.yml from a GitHub repository. +// It tries both action.yml and action.yaml filenames. func fetchRemoteActionYAML(repo, subdir, ref string) (*actionYAMLFile, error) { for _, filename := range []string{"action.yml", "action.yaml"} { var contentPath string diff --git a/pkg/workflow/safe_outputs_tools_filtering.go b/pkg/workflow/safe_outputs_tools_filtering.go index 3190fbdec0..b8e9a53155 100644 --- a/pkg/workflow/safe_outputs_tools_filtering.go +++ b/pkg/workflow/safe_outputs_tools_filtering.go @@ -249,16 +249,13 @@ func generateFilteredToolsJSON(data *WorkflowData, markdownPath string) (string, } } - // Add custom action tools from SafeOutputs.Actions + // Add custom action tools from SafeOutputs.Actions. + // Action resolution (action.yml fetch + pinning) is done once in buildJobs before + // generateToolsMetaJSON/generateFilteredToolsJSON are called, so Inputs and + // ActionDescription are already populated here. if len(data.SafeOutputs.Actions) > 0 { safeOutputsConfigLog.Printf("Adding %d custom action tools", len(data.SafeOutputs.Actions)) - // Ensure all configured actions are resolved (action.yml metadata loaded) - // before generating tool definitions that depend on ActionDescription/Inputs. - if err := resolveAllActions(); err != nil { - return "", fmt.Errorf("failed to resolve actions before generating safe-output tools: %w", err) - } - actionNames := make([]string, 0, len(data.SafeOutputs.Actions)) for actionName := range data.SafeOutputs.Actions { actionNames = append(actionNames, actionName) From 8cc1b77409716b8db59e85a23b74834ce70367a6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 19:15:20 +0000 Subject: [PATCH 14/17] Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/smoke-codex.lock.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index 5005320155..854c7b9646 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -450,13 +450,20 @@ jobs: { "description": "Add the 'smoked' label to the current pull request (can only be called once)", "inputSchema": { - "additionalProperties": true, + "additionalProperties": false, "properties": { - "payload": { - "description": "JSON-encoded payload to pass to the action", + "labels": { + "description": "The labels' name to be added. Must be separated with line breaks if there're multiple labels.", + "type": "string" + }, + "number": { + "description": "The number of the issue or pull request.", "type": "string" } }, + "required": [ + "labels" + ], "type": "object" }, "name": "add_smoked_label" @@ -1561,7 +1568,8 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} with: - payload: ${{ steps.process_safe_outputs.outputs.action_add_smoked_label_payload }} + labels: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).labels }} + number: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).number }} - name: Upload safe output items if: always() continue-on-error: true From a588b348db67aa867ec8503ef2c02c0c4ab1817f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 20:47:54 +0000 Subject: [PATCH 15/17] test: add integration tests for safe-outputs.actions compilation Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/compile_integration_test.go | 267 ++++++++++++++++++ .../test-copilot-safe-output-actions.md | 23 ++ 2 files changed, 290 insertions(+) create mode 100644 pkg/cli/workflows/test-copilot-safe-output-actions.md diff --git a/pkg/cli/compile_integration_test.go b/pkg/cli/compile_integration_test.go index b38477598f..659ea65eea 100644 --- a/pkg/cli/compile_integration_test.go +++ b/pkg/cli/compile_integration_test.go @@ -1127,3 +1127,270 @@ Test workflow to verify actions-lock.json path handling when compiling from subd t.Logf("Integration test passed - actions-lock.json created at correct location") } + +// TestCompileSafeOutputsActions verifies that a workflow with safe-outputs.actions +// compiles successfully and produces the expected output in the lock file: +// - GH_AW_SAFE_OUTPUT_ACTIONS env var on the process_safe_outputs step +// - An injected action step with the correct id and if-condition +func TestCompileSafeOutputsActions(t *testing.T) { + setup := setupIntegrationTest(t) + defer setup.cleanup() + + testWorkflow := `--- +name: Test Safe Output Actions +on: + workflow_dispatch: +permissions: + contents: read + pull-requests: read +engine: copilot +safe-outputs: + actions: + add-label: + uses: actions-ecosystem/action-add-labels@v1 + description: Add a label to the current PR + env: + GITHUB_TOKEN: ${{ github.token }} +--- + +# Test Safe Output Actions + +When done, call add_label with the appropriate label. +` + testWorkflowPath := filepath.Join(setup.workflowsDir, "test-safe-output-actions.md") + if err := os.WriteFile(testWorkflowPath, []byte(testWorkflow), 0644); err != nil { + t.Fatalf("Failed to write test workflow file: %v", err) + } + + cmd := exec.Command(setup.binaryPath, "compile", testWorkflowPath) + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("CLI compile command failed: %v\nOutput: %s", err, string(output)) + } + + lockFilePath := filepath.Join(setup.workflowsDir, "test-safe-output-actions.lock.yml") + lockContent, err := os.ReadFile(lockFilePath) + if err != nil { + t.Fatalf("Failed to read lock file: %v", err) + } + lockContentStr := string(lockContent) + + // Verify GH_AW_SAFE_OUTPUT_ACTIONS is emitted on the process_safe_outputs step + if !strings.Contains(lockContentStr, "GH_AW_SAFE_OUTPUT_ACTIONS") { + t.Errorf("Lock file should contain GH_AW_SAFE_OUTPUT_ACTIONS\nLock file content:\n%s", lockContentStr) + } + + // Verify the injected action step id + if !strings.Contains(lockContentStr, "id: action_add_label") { + t.Errorf("Lock file should contain step 'id: action_add_label'\nLock file content:\n%s", lockContentStr) + } + + // Verify the injected action step if-condition + if !strings.Contains(lockContentStr, "action_add_label_payload") { + t.Errorf("Lock file should contain 'action_add_label_payload' in the step if-condition\nLock file content:\n%s", lockContentStr) + } + + // Verify the env block is included in the action step + if !strings.Contains(lockContentStr, "GITHUB_TOKEN") { + t.Errorf("Lock file should contain GITHUB_TOKEN env var in the action step\nLock file content:\n%s", lockContentStr) + } + + // Verify the handler manager step is present (required to process action payloads) + if !strings.Contains(lockContentStr, "safe_output_handler_manager.cjs") { + t.Errorf("Lock file should contain the safe_output_handler_manager.cjs step\nLock file content:\n%s", lockContentStr) + } +} + +// TestCompileSafeOutputsActionsMultiple verifies that multiple actions in safe-outputs.actions +// all generate separate action steps and all appear in GH_AW_SAFE_OUTPUT_ACTIONS. +func TestCompileSafeOutputsActionsMultiple(t *testing.T) { + setup := setupIntegrationTest(t) + defer setup.cleanup() + + testWorkflow := `--- +name: Test Multiple Safe Output Actions +on: + workflow_dispatch: +permissions: + contents: read + issues: read + pull-requests: read +engine: copilot +safe-outputs: + actions: + add-bug-label: + uses: actions-ecosystem/action-add-labels@v1 + description: Add a bug label + env: + GITHUB_TOKEN: ${{ github.token }} + close-issue: + uses: peter-evans/close-issue@v3 + description: Close the issue +--- + +# Test Multiple Safe Output Actions + +Call add_bug_label or close_issue as appropriate. +` + testWorkflowPath := filepath.Join(setup.workflowsDir, "test-multi-safe-output-actions.md") + if err := os.WriteFile(testWorkflowPath, []byte(testWorkflow), 0644); err != nil { + t.Fatalf("Failed to write test workflow file: %v", err) + } + + cmd := exec.Command(setup.binaryPath, "compile", testWorkflowPath) + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("CLI compile command failed: %v\nOutput: %s", err, string(output)) + } + + lockFilePath := filepath.Join(setup.workflowsDir, "test-multi-safe-output-actions.lock.yml") + lockContent, err := os.ReadFile(lockFilePath) + if err != nil { + t.Fatalf("Failed to read lock file: %v", err) + } + lockContentStr := string(lockContent) + + // Both action steps must be present + if !strings.Contains(lockContentStr, "id: action_add_bug_label") { + t.Errorf("Lock file should contain step 'id: action_add_bug_label'\nLock file content:\n%s", lockContentStr) + } + if !strings.Contains(lockContentStr, "id: action_close_issue") { + t.Errorf("Lock file should contain step 'id: action_close_issue'\nLock file content:\n%s", lockContentStr) + } + + // Both payloads must appear in if-conditions + if !strings.Contains(lockContentStr, "action_add_bug_label_payload") { + t.Errorf("Lock file should contain 'action_add_bug_label_payload'\nLock file content:\n%s", lockContentStr) + } + if !strings.Contains(lockContentStr, "action_close_issue_payload") { + t.Errorf("Lock file should contain 'action_close_issue_payload'\nLock file content:\n%s", lockContentStr) + } + + // GH_AW_SAFE_OUTPUT_ACTIONS must mention both tools + if !strings.Contains(lockContentStr, "add_bug_label") { + t.Errorf("Lock file should contain 'add_bug_label' in GH_AW_SAFE_OUTPUT_ACTIONS\nLock file content:\n%s", lockContentStr) + } + if !strings.Contains(lockContentStr, "close_issue") { + t.Errorf("Lock file should contain 'close_issue' in GH_AW_SAFE_OUTPUT_ACTIONS\nLock file content:\n%s", lockContentStr) + } +} + +// TestCompileSafeOutputsActionsCombinedWithBuiltin verifies that safe-outputs.actions +// can be used alongside built-in safe-output handlers (add-comment, create-issue, etc.) +// without compilation errors. +func TestCompileSafeOutputsActionsCombinedWithBuiltin(t *testing.T) { + setup := setupIntegrationTest(t) + defer setup.cleanup() + + testWorkflow := `--- +name: Combined Safe Outputs +on: + workflow_dispatch: +permissions: + contents: read + issues: read + pull-requests: read +engine: copilot +safe-outputs: + add-comment: + max: 1 + add-labels: + allowed: [bug, enhancement] + actions: + apply-fix: + uses: actions-ecosystem/action-add-labels@v1 + description: Apply fix label + env: + GITHUB_TOKEN: ${{ github.token }} +--- + +# Combined Safe Outputs + +Use add_comment, add_labels, or apply_fix as appropriate. +` + testWorkflowPath := filepath.Join(setup.workflowsDir, "test-combined-safe-outputs.md") + if err := os.WriteFile(testWorkflowPath, []byte(testWorkflow), 0644); err != nil { + t.Fatalf("Failed to write test workflow file: %v", err) + } + + cmd := exec.Command(setup.binaryPath, "compile", testWorkflowPath) + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("CLI compile command failed: %v\nOutput: %s", err, string(output)) + } + + lockFilePath := filepath.Join(setup.workflowsDir, "test-combined-safe-outputs.lock.yml") + lockContent, err := os.ReadFile(lockFilePath) + if err != nil { + t.Fatalf("Failed to read lock file: %v", err) + } + lockContentStr := string(lockContent) + + // Verify both built-in and action tools are present + if !strings.Contains(lockContentStr, "GH_AW_SAFE_OUTPUT_ACTIONS") { + t.Errorf("Lock file should contain GH_AW_SAFE_OUTPUT_ACTIONS\nLock file content:\n%s", lockContentStr) + } + if !strings.Contains(lockContentStr, "id: action_apply_fix") { + t.Errorf("Lock file should contain step 'id: action_apply_fix'\nLock file content:\n%s", lockContentStr) + } + // Verify built-in handler config is still present + if !strings.Contains(lockContentStr, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG") { + t.Errorf("Lock file should contain GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG\nLock file content:\n%s", lockContentStr) + } +} + +// TestCompileSafeOutputsActionsOnlyNoBuiltin verifies that a workflow with only +// safe-outputs.actions (no built-in handlers) still compiles correctly and emits +// the safe_outputs job. +func TestCompileSafeOutputsActionsOnlyNoBuiltin(t *testing.T) { + setup := setupIntegrationTest(t) + defer setup.cleanup() + + testWorkflow := `--- +name: Actions Only Safe Outputs +on: + workflow_dispatch: +permissions: + contents: read + pull-requests: read +engine: copilot +safe-outputs: + actions: + pin-pr: + uses: actions-ecosystem/action-add-labels@v1 + description: Pin the PR +--- + +# Actions Only Safe Outputs + +Call pin_pr to pin the pull request. +` + testWorkflowPath := filepath.Join(setup.workflowsDir, "test-actions-only-safe-outputs.md") + if err := os.WriteFile(testWorkflowPath, []byte(testWorkflow), 0644); err != nil { + t.Fatalf("Failed to write test workflow file: %v", err) + } + + cmd := exec.Command(setup.binaryPath, "compile", testWorkflowPath) + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("CLI compile command failed: %v\nOutput: %s", err, string(output)) + } + + lockFilePath := filepath.Join(setup.workflowsDir, "test-actions-only-safe-outputs.lock.yml") + lockContent, err := os.ReadFile(lockFilePath) + if err != nil { + t.Fatalf("Failed to read lock file: %v", err) + } + lockContentStr := string(lockContent) + + // Verify the safe_outputs job is created + if !strings.Contains(lockContentStr, "safe_outputs") { + t.Errorf("Lock file should contain a 'safe_outputs' job\nLock file content:\n%s", lockContentStr) + } + if !strings.Contains(lockContentStr, "GH_AW_SAFE_OUTPUT_ACTIONS") { + t.Errorf("Lock file should contain GH_AW_SAFE_OUTPUT_ACTIONS\nLock file content:\n%s", lockContentStr) + } + if !strings.Contains(lockContentStr, "id: action_pin_pr") { + t.Errorf("Lock file should contain step 'id: action_pin_pr'\nLock file content:\n%s", lockContentStr) + } +} diff --git a/pkg/cli/workflows/test-copilot-safe-output-actions.md b/pkg/cli/workflows/test-copilot-safe-output-actions.md new file mode 100644 index 0000000000..87c1dc8a46 --- /dev/null +++ b/pkg/cli/workflows/test-copilot-safe-output-actions.md @@ -0,0 +1,23 @@ +--- +on: + workflow_dispatch: +permissions: + contents: read + pull-requests: read +engine: copilot +safe-outputs: + actions: + add-smoked-label: + uses: actions-ecosystem/action-add-labels@v1 + description: Add the 'smoked' label to the current pull request + env: + GITHUB_TOKEN: ${{ github.token }} +--- + +# Test Safe Output Actions + +This workflow demonstrates `safe-outputs.actions`, which mounts a GitHub Action +as a once-callable MCP tool. + +When done, call `add_smoked_label` with `{"labels": "smoked"}` to add the label +to the current pull request. From 31250a12da87f8a4da4676271b6049be045876f7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 20:58:45 +0000 Subject: [PATCH 16/17] chore: merge main and recompile Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/smoke-codex.lock.yml | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index c5bc5638e2..6b67607ca6 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -450,20 +450,13 @@ jobs: { "description": "Add the 'smoked' label to the current pull request (can only be called once)", "inputSchema": { - "additionalProperties": false, + "additionalProperties": true, "properties": { - "labels": { - "description": "The labels' name to be added. Must be separated with line breaks if there're multiple labels.", - "type": "string" - }, - "number": { - "description": "The number of the issue or pull request.", + "payload": { + "description": "JSON-encoded payload to pass to the action", "type": "string" } }, - "required": [ - "labels" - ], "type": "object" }, "name": "add_smoked_label" @@ -1568,8 +1561,7 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} with: - labels: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).labels }} - number: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).number }} + payload: ${{ steps.process_safe_outputs.outputs.action_add_smoked_label_payload }} - name: Upload safe output items if: always() continue-on-error: true From de5f3ce5339c25c3f43587a30b063fe990d6b3e5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 21:55:56 +0000 Subject: [PATCH 17/17] fix: remove unrelated continue-on-error change from safe output upload step Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Agent-Logs-Url: https://github.com/github/gh-aw/sessions/7c570bd1-3259-455c-a206-db36b9f7d3b6 --- .github/workflows/agent-performance-analyzer.lock.yml | 1 - .github/workflows/agent-persona-explorer.lock.yml | 1 - .github/workflows/ai-moderator.lock.yml | 1 - .github/workflows/archie.lock.yml | 1 - .github/workflows/artifacts-summary.lock.yml | 1 - .github/workflows/audit-workflows.lock.yml | 1 - .github/workflows/auto-triage-issues.lock.yml | 1 - .github/workflows/blog-auditor.lock.yml | 1 - .github/workflows/bot-detection.lock.yml | 1 - .github/workflows/brave.lock.yml | 1 - .github/workflows/breaking-change-checker.lock.yml | 1 - .github/workflows/changeset.lock.yml | 1 - .github/workflows/ci-coach.lock.yml | 1 - .github/workflows/ci-doctor.lock.yml | 1 - .github/workflows/claude-code-user-docs-review.lock.yml | 1 - .github/workflows/cli-consistency-checker.lock.yml | 1 - .github/workflows/cli-version-checker.lock.yml | 1 - .github/workflows/cloclo.lock.yml | 1 - .github/workflows/code-scanning-fixer.lock.yml | 1 - .github/workflows/code-simplifier.lock.yml | 1 - .github/workflows/commit-changes-analyzer.lock.yml | 1 - .github/workflows/constraint-solving-potd.lock.yml | 1 - .github/workflows/contribution-check.lock.yml | 1 - .github/workflows/copilot-agent-analysis.lock.yml | 1 - .github/workflows/copilot-cli-deep-research.lock.yml | 1 - .github/workflows/copilot-pr-merged-report.lock.yml | 1 - .github/workflows/copilot-pr-nlp-analysis.lock.yml | 1 - .github/workflows/copilot-pr-prompt-analysis.lock.yml | 1 - .github/workflows/copilot-session-insights.lock.yml | 1 - .github/workflows/craft.lock.yml | 1 - .github/workflows/daily-architecture-diagram.lock.yml | 1 - .github/workflows/daily-assign-issue-to-user.lock.yml | 1 - .github/workflows/daily-cli-performance.lock.yml | 1 - .github/workflows/daily-cli-tools-tester.lock.yml | 1 - .github/workflows/daily-code-metrics.lock.yml | 1 - .github/workflows/daily-compiler-quality.lock.yml | 1 - .github/workflows/daily-copilot-token-report.lock.yml | 1 - .github/workflows/daily-doc-healer.lock.yml | 1 - .github/workflows/daily-doc-updater.lock.yml | 1 - .github/workflows/daily-fact.lock.yml | 1 - .github/workflows/daily-file-diet.lock.yml | 1 - .github/workflows/daily-firewall-report.lock.yml | 1 - .github/workflows/daily-function-namer.lock.yml | 1 - .github/workflows/daily-issues-report.lock.yml | 1 - .github/workflows/daily-malicious-code-scan.lock.yml | 1 - .github/workflows/daily-mcp-concurrency-analysis.lock.yml | 1 - .github/workflows/daily-multi-device-docs-tester.lock.yml | 1 - .github/workflows/daily-news.lock.yml | 1 - .github/workflows/daily-observability-report.lock.yml | 1 - .github/workflows/daily-performance-summary.lock.yml | 1 - .github/workflows/daily-regulatory.lock.yml | 1 - .github/workflows/daily-rendering-scripts-verifier.lock.yml | 1 - .github/workflows/daily-repo-chronicle.lock.yml | 1 - .github/workflows/daily-safe-output-integrator.lock.yml | 1 - .github/workflows/daily-safe-output-optimizer.lock.yml | 1 - .github/workflows/daily-safe-outputs-conformance.lock.yml | 1 - .github/workflows/daily-secrets-analysis.lock.yml | 1 - .github/workflows/daily-security-red-team.lock.yml | 1 - .github/workflows/daily-semgrep-scan.lock.yml | 1 - .github/workflows/daily-syntax-error-quality.lock.yml | 1 - .github/workflows/daily-team-evolution-insights.lock.yml | 1 - .github/workflows/daily-team-status.lock.yml | 1 - .github/workflows/daily-testify-uber-super-expert.lock.yml | 1 - .github/workflows/daily-workflow-updater.lock.yml | 1 - .github/workflows/dead-code-remover.lock.yml | 1 - .github/workflows/deep-report.lock.yml | 1 - .github/workflows/delight.lock.yml | 1 - .github/workflows/dependabot-burner.lock.yml | 1 - .github/workflows/dependabot-go-checker.lock.yml | 1 - .github/workflows/dev-hawk.lock.yml | 1 - .github/workflows/dev.lock.yml | 1 - .github/workflows/developer-docs-consolidator.lock.yml | 1 - .github/workflows/dictation-prompt.lock.yml | 1 - .github/workflows/discussion-task-miner.lock.yml | 1 - .github/workflows/docs-noob-tester.lock.yml | 1 - .github/workflows/draft-pr-cleanup.lock.yml | 1 - .github/workflows/duplicate-code-detector.lock.yml | 1 - .github/workflows/example-workflow-analyzer.lock.yml | 1 - .github/workflows/firewall-escape.lock.yml | 1 - .github/workflows/functional-pragmatist.lock.yml | 1 - .github/workflows/github-mcp-structural-analysis.lock.yml | 1 - .github/workflows/github-mcp-tools-report.lock.yml | 1 - .github/workflows/github-remote-mcp-auth-test.lock.yml | 1 - .github/workflows/glossary-maintainer.lock.yml | 1 - .github/workflows/go-fan.lock.yml | 1 - .github/workflows/go-logger.lock.yml | 1 - .github/workflows/go-pattern-detector.lock.yml | 1 - .github/workflows/gpclean.lock.yml | 1 - .github/workflows/grumpy-reviewer.lock.yml | 1 - .github/workflows/hourly-ci-cleaner.lock.yml | 1 - .github/workflows/instructions-janitor.lock.yml | 1 - .github/workflows/issue-arborist.lock.yml | 1 - .github/workflows/issue-monster.lock.yml | 1 - .github/workflows/issue-triage-agent.lock.yml | 1 - .github/workflows/jsweep.lock.yml | 1 - .github/workflows/layout-spec-maintainer.lock.yml | 1 - .github/workflows/lockfile-stats.lock.yml | 1 - .github/workflows/mcp-inspector.lock.yml | 1 - .github/workflows/mergefest.lock.yml | 1 - .github/workflows/notion-issue-summary.lock.yml | 1 - .github/workflows/org-health-report.lock.yml | 1 - .github/workflows/pdf-summary.lock.yml | 1 - .github/workflows/plan.lock.yml | 1 - .github/workflows/portfolio-analyst.lock.yml | 1 - .github/workflows/pr-nitpick-reviewer.lock.yml | 1 - .github/workflows/pr-triage-agent.lock.yml | 1 - .github/workflows/prompt-clustering-analysis.lock.yml | 1 - .github/workflows/python-data-charts.lock.yml | 1 - .github/workflows/q.lock.yml | 1 - .github/workflows/refiner.lock.yml | 1 - .github/workflows/release.lock.yml | 1 - .github/workflows/repo-audit-analyzer.lock.yml | 1 - .github/workflows/repo-tree-map.lock.yml | 1 - .github/workflows/repository-quality-improver.lock.yml | 1 - .github/workflows/research.lock.yml | 1 - .github/workflows/safe-output-health.lock.yml | 1 - .github/workflows/schema-consistency-checker.lock.yml | 1 - .github/workflows/scout.lock.yml | 1 - .github/workflows/security-alert-burndown.campaign.g.lock.yml | 1 - .github/workflows/security-compliance.lock.yml | 1 - .github/workflows/security-review.lock.yml | 1 - .github/workflows/semantic-function-refactor.lock.yml | 1 - .github/workflows/sergo.lock.yml | 1 - .github/workflows/slide-deck-maintainer.lock.yml | 1 - .github/workflows/smoke-agent-all-merged.lock.yml | 1 - .github/workflows/smoke-agent-all-none.lock.yml | 1 - .github/workflows/smoke-agent-public-approved.lock.yml | 1 - .github/workflows/smoke-agent-public-none.lock.yml | 1 - .github/workflows/smoke-agent-scoped-approved.lock.yml | 1 - .github/workflows/smoke-call-workflow.lock.yml | 1 - .github/workflows/smoke-claude.lock.yml | 1 - .github/workflows/smoke-codex.lock.yml | 1 - .github/workflows/smoke-copilot-arm.lock.yml | 1 - .github/workflows/smoke-copilot.lock.yml | 1 - .github/workflows/smoke-create-cross-repo-pr.lock.yml | 1 - .github/workflows/smoke-gemini.lock.yml | 1 - .github/workflows/smoke-multi-pr.lock.yml | 1 - .github/workflows/smoke-project.lock.yml | 1 - .github/workflows/smoke-temporary-id.lock.yml | 1 - .github/workflows/smoke-test-tools.lock.yml | 1 - .github/workflows/smoke-update-cross-repo-pr.lock.yml | 1 - .github/workflows/smoke-workflow-call-with-inputs.lock.yml | 1 - .github/workflows/smoke-workflow-call.lock.yml | 1 - .github/workflows/stale-repo-identifier.lock.yml | 1 - .github/workflows/static-analysis-report.lock.yml | 1 - .github/workflows/step-name-alignment.lock.yml | 1 - .github/workflows/sub-issue-closer.lock.yml | 1 - .github/workflows/super-linter.lock.yml | 1 - .github/workflows/technical-doc-writer.lock.yml | 1 - .github/workflows/terminal-stylist.lock.yml | 1 - .github/workflows/test-create-pr-error-handling.lock.yml | 1 - .github/workflows/test-dispatcher.lock.yml | 1 - .github/workflows/test-project-url-default.lock.yml | 1 - .github/workflows/tidy.lock.yml | 1 - .github/workflows/typist.lock.yml | 1 - .github/workflows/ubuntu-image-analyzer.lock.yml | 1 - .github/workflows/unbloat-docs.lock.yml | 1 - .github/workflows/update-astro.lock.yml | 1 - .github/workflows/video-analyzer.lock.yml | 1 - .github/workflows/weekly-blog-post-writer.lock.yml | 1 - .github/workflows/weekly-editors-health-check.lock.yml | 1 - .github/workflows/weekly-issue-summary.lock.yml | 1 - .github/workflows/weekly-safe-outputs-spec-review.lock.yml | 1 - .github/workflows/workflow-generator.lock.yml | 1 - .github/workflows/workflow-health-manager.lock.yml | 1 - .github/workflows/workflow-normalizer.lock.yml | 1 - .github/workflows/workflow-skill-extractor.lock.yml | 1 - pkg/workflow/compiler_safe_outputs_job.go | 4 ---- 168 files changed, 171 deletions(-) diff --git a/.github/workflows/agent-performance-analyzer.lock.yml b/.github/workflows/agent-performance-analyzer.lock.yml index 8aaf42d1c3..033e618d9e 100644 --- a/.github/workflows/agent-performance-analyzer.lock.yml +++ b/.github/workflows/agent-performance-analyzer.lock.yml @@ -1313,7 +1313,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/agent-persona-explorer.lock.yml b/.github/workflows/agent-persona-explorer.lock.yml index 05d8a25ea7..95e237f2c0 100644 --- a/.github/workflows/agent-persona-explorer.lock.yml +++ b/.github/workflows/agent-persona-explorer.lock.yml @@ -1173,7 +1173,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/ai-moderator.lock.yml b/.github/workflows/ai-moderator.lock.yml index 497e9d8d43..8ad596aa11 100644 --- a/.github/workflows/ai-moderator.lock.yml +++ b/.github/workflows/ai-moderator.lock.yml @@ -1036,7 +1036,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml index ff19c9a82d..65d85aef3f 100644 --- a/.github/workflows/archie.lock.yml +++ b/.github/workflows/archie.lock.yml @@ -1192,7 +1192,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml index 1c9625d6b5..6345d383ad 100644 --- a/.github/workflows/artifacts-summary.lock.yml +++ b/.github/workflows/artifacts-summary.lock.yml @@ -1035,7 +1035,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index 6a4348b04c..625bd7d07a 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -1370,7 +1370,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/auto-triage-issues.lock.yml b/.github/workflows/auto-triage-issues.lock.yml index d4071cad71..030bb514bc 100644 --- a/.github/workflows/auto-triage-issues.lock.yml +++ b/.github/workflows/auto-triage-issues.lock.yml @@ -1134,7 +1134,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/blog-auditor.lock.yml b/.github/workflows/blog-auditor.lock.yml index 223c3ae878..5094a933ae 100644 --- a/.github/workflows/blog-auditor.lock.yml +++ b/.github/workflows/blog-auditor.lock.yml @@ -1166,7 +1166,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/bot-detection.lock.yml b/.github/workflows/bot-detection.lock.yml index 11d04cc4bc..ee45511901 100644 --- a/.github/workflows/bot-detection.lock.yml +++ b/.github/workflows/bot-detection.lock.yml @@ -1791,7 +1791,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml index 89d9b8b9df..793d5979b2 100644 --- a/.github/workflows/brave.lock.yml +++ b/.github/workflows/brave.lock.yml @@ -1177,7 +1177,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/breaking-change-checker.lock.yml b/.github/workflows/breaking-change-checker.lock.yml index b749ba5f8e..f012e02344 100644 --- a/.github/workflows/breaking-change-checker.lock.yml +++ b/.github/workflows/breaking-change-checker.lock.yml @@ -1131,7 +1131,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index b35dd37c05..ebd12dbcb7 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -1156,7 +1156,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/ci-coach.lock.yml b/.github/workflows/ci-coach.lock.yml index 746483d94c..68e905b157 100644 --- a/.github/workflows/ci-coach.lock.yml +++ b/.github/workflows/ci-coach.lock.yml @@ -1178,7 +1178,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml index f763449d9c..64a8b2564f 100644 --- a/.github/workflows/ci-doctor.lock.yml +++ b/.github/workflows/ci-doctor.lock.yml @@ -1245,7 +1245,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/claude-code-user-docs-review.lock.yml b/.github/workflows/claude-code-user-docs-review.lock.yml index dcdc21e502..b0d22248e8 100644 --- a/.github/workflows/claude-code-user-docs-review.lock.yml +++ b/.github/workflows/claude-code-user-docs-review.lock.yml @@ -1127,7 +1127,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml index 4eeb859ad9..c7fe9e075b 100644 --- a/.github/workflows/cli-consistency-checker.lock.yml +++ b/.github/workflows/cli-consistency-checker.lock.yml @@ -1031,7 +1031,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml index d5f04aa28f..e9c265068d 100644 --- a/.github/workflows/cli-version-checker.lock.yml +++ b/.github/workflows/cli-version-checker.lock.yml @@ -1132,7 +1132,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index a0be1d3d69..dac5b4ff12 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -1583,7 +1583,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/code-scanning-fixer.lock.yml b/.github/workflows/code-scanning-fixer.lock.yml index 8b785be4cb..422c7f9b23 100644 --- a/.github/workflows/code-scanning-fixer.lock.yml +++ b/.github/workflows/code-scanning-fixer.lock.yml @@ -1282,7 +1282,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/code-simplifier.lock.yml b/.github/workflows/code-simplifier.lock.yml index 5bf761b441..ae8788447d 100644 --- a/.github/workflows/code-simplifier.lock.yml +++ b/.github/workflows/code-simplifier.lock.yml @@ -1159,7 +1159,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/commit-changes-analyzer.lock.yml b/.github/workflows/commit-changes-analyzer.lock.yml index 5cdcd50a61..4682427c43 100644 --- a/.github/workflows/commit-changes-analyzer.lock.yml +++ b/.github/workflows/commit-changes-analyzer.lock.yml @@ -1096,7 +1096,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/constraint-solving-potd.lock.yml b/.github/workflows/constraint-solving-potd.lock.yml index 708c22ffc9..3c173fb48f 100644 --- a/.github/workflows/constraint-solving-potd.lock.yml +++ b/.github/workflows/constraint-solving-potd.lock.yml @@ -1036,7 +1036,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/contribution-check.lock.yml b/.github/workflows/contribution-check.lock.yml index 918b9fcb50..5b3d902b92 100644 --- a/.github/workflows/contribution-check.lock.yml +++ b/.github/workflows/contribution-check.lock.yml @@ -1074,7 +1074,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml index 1274436648..d5f09af749 100644 --- a/.github/workflows/copilot-agent-analysis.lock.yml +++ b/.github/workflows/copilot-agent-analysis.lock.yml @@ -1249,7 +1249,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/copilot-cli-deep-research.lock.yml b/.github/workflows/copilot-cli-deep-research.lock.yml index 777baec583..fb93afbaea 100644 --- a/.github/workflows/copilot-cli-deep-research.lock.yml +++ b/.github/workflows/copilot-cli-deep-research.lock.yml @@ -1168,7 +1168,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/copilot-pr-merged-report.lock.yml b/.github/workflows/copilot-pr-merged-report.lock.yml index 7c9396e936..8c9f1f0487 100644 --- a/.github/workflows/copilot-pr-merged-report.lock.yml +++ b/.github/workflows/copilot-pr-merged-report.lock.yml @@ -1212,7 +1212,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index 8daa0d2e23..0e28f1b030 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -1252,7 +1252,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index 2378b93625..daab70ed8e 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -1188,7 +1188,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index de448de29f..3e2ef5aa86 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -1312,7 +1312,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index 12219598ab..ef67803b1b 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -1211,7 +1211,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-architecture-diagram.lock.yml b/.github/workflows/daily-architecture-diagram.lock.yml index 9721a89dfb..9aac2413cd 100644 --- a/.github/workflows/daily-architecture-diagram.lock.yml +++ b/.github/workflows/daily-architecture-diagram.lock.yml @@ -1152,7 +1152,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-assign-issue-to-user.lock.yml b/.github/workflows/daily-assign-issue-to-user.lock.yml index 823d4a82bc..9c8fb658da 100644 --- a/.github/workflows/daily-assign-issue-to-user.lock.yml +++ b/.github/workflows/daily-assign-issue-to-user.lock.yml @@ -1040,7 +1040,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-cli-performance.lock.yml b/.github/workflows/daily-cli-performance.lock.yml index 7a90670151..5c5d18c510 100644 --- a/.github/workflows/daily-cli-performance.lock.yml +++ b/.github/workflows/daily-cli-performance.lock.yml @@ -1337,7 +1337,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-cli-tools-tester.lock.yml b/.github/workflows/daily-cli-tools-tester.lock.yml index a486f23424..f8fa6dffe1 100644 --- a/.github/workflows/daily-cli-tools-tester.lock.yml +++ b/.github/workflows/daily-cli-tools-tester.lock.yml @@ -1119,7 +1119,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml index e76c046739..ff95f32b56 100644 --- a/.github/workflows/daily-code-metrics.lock.yml +++ b/.github/workflows/daily-code-metrics.lock.yml @@ -1291,7 +1291,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-compiler-quality.lock.yml b/.github/workflows/daily-compiler-quality.lock.yml index dd4227a1c5..cc4267de0e 100644 --- a/.github/workflows/daily-compiler-quality.lock.yml +++ b/.github/workflows/daily-compiler-quality.lock.yml @@ -1102,7 +1102,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-copilot-token-report.lock.yml b/.github/workflows/daily-copilot-token-report.lock.yml index f71498b386..21a9ed0670 100644 --- a/.github/workflows/daily-copilot-token-report.lock.yml +++ b/.github/workflows/daily-copilot-token-report.lock.yml @@ -1261,7 +1261,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-doc-healer.lock.yml b/.github/workflows/daily-doc-healer.lock.yml index 5a60cc8fa2..a740382d7e 100644 --- a/.github/workflows/daily-doc-healer.lock.yml +++ b/.github/workflows/daily-doc-healer.lock.yml @@ -1406,7 +1406,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml index a857247cf8..fbf1cc3375 100644 --- a/.github/workflows/daily-doc-updater.lock.yml +++ b/.github/workflows/daily-doc-updater.lock.yml @@ -1354,7 +1354,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-fact.lock.yml b/.github/workflows/daily-fact.lock.yml index 525ffb36d0..752fefc776 100644 --- a/.github/workflows/daily-fact.lock.yml +++ b/.github/workflows/daily-fact.lock.yml @@ -1053,7 +1053,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml index 12d9c0c2dc..d4b6682496 100644 --- a/.github/workflows/daily-file-diet.lock.yml +++ b/.github/workflows/daily-file-diet.lock.yml @@ -1141,7 +1141,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml index 11bd279a72..15d3276363 100644 --- a/.github/workflows/daily-firewall-report.lock.yml +++ b/.github/workflows/daily-firewall-report.lock.yml @@ -1198,7 +1198,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-function-namer.lock.yml b/.github/workflows/daily-function-namer.lock.yml index 5b62b90455..c48432b95e 100644 --- a/.github/workflows/daily-function-namer.lock.yml +++ b/.github/workflows/daily-function-namer.lock.yml @@ -1169,7 +1169,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-issues-report.lock.yml b/.github/workflows/daily-issues-report.lock.yml index 22f7c1a94d..7b6380997c 100644 --- a/.github/workflows/daily-issues-report.lock.yml +++ b/.github/workflows/daily-issues-report.lock.yml @@ -1176,7 +1176,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-malicious-code-scan.lock.yml b/.github/workflows/daily-malicious-code-scan.lock.yml index 5816ebbac4..401add5152 100644 --- a/.github/workflows/daily-malicious-code-scan.lock.yml +++ b/.github/workflows/daily-malicious-code-scan.lock.yml @@ -919,7 +919,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-mcp-concurrency-analysis.lock.yml b/.github/workflows/daily-mcp-concurrency-analysis.lock.yml index 9c3b77cc44..2307c98974 100644 --- a/.github/workflows/daily-mcp-concurrency-analysis.lock.yml +++ b/.github/workflows/daily-mcp-concurrency-analysis.lock.yml @@ -1137,7 +1137,6 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/create_agent_session.cjs'); await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-multi-device-docs-tester.lock.yml b/.github/workflows/daily-multi-device-docs-tester.lock.yml index e35b6bfa11..98380fd04a 100644 --- a/.github/workflows/daily-multi-device-docs-tester.lock.yml +++ b/.github/workflows/daily-multi-device-docs-tester.lock.yml @@ -1214,7 +1214,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index 2db8ed54be..6a138a941d 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -1329,7 +1329,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-observability-report.lock.yml b/.github/workflows/daily-observability-report.lock.yml index b9411272f6..c042a4f833 100644 --- a/.github/workflows/daily-observability-report.lock.yml +++ b/.github/workflows/daily-observability-report.lock.yml @@ -1181,7 +1181,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-performance-summary.lock.yml b/.github/workflows/daily-performance-summary.lock.yml index fdc5b3b321..cc99410339 100644 --- a/.github/workflows/daily-performance-summary.lock.yml +++ b/.github/workflows/daily-performance-summary.lock.yml @@ -1640,7 +1640,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-regulatory.lock.yml b/.github/workflows/daily-regulatory.lock.yml index 7c8b356241..57dd0d0281 100644 --- a/.github/workflows/daily-regulatory.lock.yml +++ b/.github/workflows/daily-regulatory.lock.yml @@ -1561,7 +1561,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-rendering-scripts-verifier.lock.yml b/.github/workflows/daily-rendering-scripts-verifier.lock.yml index 518ce1e456..0586d54650 100644 --- a/.github/workflows/daily-rendering-scripts-verifier.lock.yml +++ b/.github/workflows/daily-rendering-scripts-verifier.lock.yml @@ -1345,7 +1345,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml index 10ed612dff..8d7cfd3cfe 100644 --- a/.github/workflows/daily-repo-chronicle.lock.yml +++ b/.github/workflows/daily-repo-chronicle.lock.yml @@ -1120,7 +1120,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-safe-output-integrator.lock.yml b/.github/workflows/daily-safe-output-integrator.lock.yml index b59e5daf67..98c9539a9f 100644 --- a/.github/workflows/daily-safe-output-integrator.lock.yml +++ b/.github/workflows/daily-safe-output-integrator.lock.yml @@ -1134,7 +1134,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-safe-output-optimizer.lock.yml b/.github/workflows/daily-safe-output-optimizer.lock.yml index 22ee644fab..9456e0c3ab 100644 --- a/.github/workflows/daily-safe-output-optimizer.lock.yml +++ b/.github/workflows/daily-safe-output-optimizer.lock.yml @@ -1278,7 +1278,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-safe-outputs-conformance.lock.yml b/.github/workflows/daily-safe-outputs-conformance.lock.yml index a0cbcbd6d5..ec45d07d92 100644 --- a/.github/workflows/daily-safe-outputs-conformance.lock.yml +++ b/.github/workflows/daily-safe-outputs-conformance.lock.yml @@ -1100,7 +1100,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-secrets-analysis.lock.yml b/.github/workflows/daily-secrets-analysis.lock.yml index be56acfa9f..e27c7c2a8a 100644 --- a/.github/workflows/daily-secrets-analysis.lock.yml +++ b/.github/workflows/daily-secrets-analysis.lock.yml @@ -1067,7 +1067,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-security-red-team.lock.yml b/.github/workflows/daily-security-red-team.lock.yml index b2816e5bbc..d573d49004 100644 --- a/.github/workflows/daily-security-red-team.lock.yml +++ b/.github/workflows/daily-security-red-team.lock.yml @@ -1104,7 +1104,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-semgrep-scan.lock.yml b/.github/workflows/daily-semgrep-scan.lock.yml index 9dc33e32f7..003809ba90 100644 --- a/.github/workflows/daily-semgrep-scan.lock.yml +++ b/.github/workflows/daily-semgrep-scan.lock.yml @@ -1066,7 +1066,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-syntax-error-quality.lock.yml b/.github/workflows/daily-syntax-error-quality.lock.yml index 9478009484..37fef3c3b4 100644 --- a/.github/workflows/daily-syntax-error-quality.lock.yml +++ b/.github/workflows/daily-syntax-error-quality.lock.yml @@ -1077,7 +1077,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-team-evolution-insights.lock.yml b/.github/workflows/daily-team-evolution-insights.lock.yml index 343aa74c25..cae609fef9 100644 --- a/.github/workflows/daily-team-evolution-insights.lock.yml +++ b/.github/workflows/daily-team-evolution-insights.lock.yml @@ -1098,7 +1098,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-team-status.lock.yml b/.github/workflows/daily-team-status.lock.yml index 6fdb43780c..fc0f455dd6 100644 --- a/.github/workflows/daily-team-status.lock.yml +++ b/.github/workflows/daily-team-status.lock.yml @@ -1099,7 +1099,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-testify-uber-super-expert.lock.yml b/.github/workflows/daily-testify-uber-super-expert.lock.yml index 35d79b4b69..ee33c3fbaa 100644 --- a/.github/workflows/daily-testify-uber-super-expert.lock.yml +++ b/.github/workflows/daily-testify-uber-super-expert.lock.yml @@ -1251,7 +1251,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/daily-workflow-updater.lock.yml b/.github/workflows/daily-workflow-updater.lock.yml index bacde287cb..eaa2115252 100644 --- a/.github/workflows/daily-workflow-updater.lock.yml +++ b/.github/workflows/daily-workflow-updater.lock.yml @@ -1091,7 +1091,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/dead-code-remover.lock.yml b/.github/workflows/dead-code-remover.lock.yml index 45b4fa2ff9..a6059823a5 100644 --- a/.github/workflows/dead-code-remover.lock.yml +++ b/.github/workflows/dead-code-remover.lock.yml @@ -1182,7 +1182,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/deep-report.lock.yml b/.github/workflows/deep-report.lock.yml index c3db1469a3..37613264f9 100644 --- a/.github/workflows/deep-report.lock.yml +++ b/.github/workflows/deep-report.lock.yml @@ -1340,7 +1340,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/delight.lock.yml b/.github/workflows/delight.lock.yml index 298633aac9..07cd647ee6 100644 --- a/.github/workflows/delight.lock.yml +++ b/.github/workflows/delight.lock.yml @@ -1217,7 +1217,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/dependabot-burner.lock.yml b/.github/workflows/dependabot-burner.lock.yml index 03c6b1d40b..e1ac66db36 100644 --- a/.github/workflows/dependabot-burner.lock.yml +++ b/.github/workflows/dependabot-burner.lock.yml @@ -1076,7 +1076,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/dependabot-go-checker.lock.yml b/.github/workflows/dependabot-go-checker.lock.yml index ab4a1a5b98..d84249c54c 100644 --- a/.github/workflows/dependabot-go-checker.lock.yml +++ b/.github/workflows/dependabot-go-checker.lock.yml @@ -1062,7 +1062,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml index e30969b396..c6cbc625f9 100644 --- a/.github/workflows/dev-hawk.lock.yml +++ b/.github/workflows/dev-hawk.lock.yml @@ -1181,7 +1181,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index 1566cb96a5..089479d262 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -1028,7 +1028,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index 199308fd2e..73a745dc30 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -1520,7 +1520,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index d78694945d..2c9e9738b1 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -1238,7 +1238,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/discussion-task-miner.lock.yml b/.github/workflows/discussion-task-miner.lock.yml index 3a4aa8b230..84f420f142 100644 --- a/.github/workflows/discussion-task-miner.lock.yml +++ b/.github/workflows/discussion-task-miner.lock.yml @@ -1187,7 +1187,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml index f63b167b39..a5b3b36194 100644 --- a/.github/workflows/docs-noob-tester.lock.yml +++ b/.github/workflows/docs-noob-tester.lock.yml @@ -1082,7 +1082,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/draft-pr-cleanup.lock.yml b/.github/workflows/draft-pr-cleanup.lock.yml index 8bbe499b09..de79c4a73c 100644 --- a/.github/workflows/draft-pr-cleanup.lock.yml +++ b/.github/workflows/draft-pr-cleanup.lock.yml @@ -1076,7 +1076,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml index 6c99109a3e..f115c83318 100644 --- a/.github/workflows/duplicate-code-detector.lock.yml +++ b/.github/workflows/duplicate-code-detector.lock.yml @@ -1097,7 +1097,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/example-workflow-analyzer.lock.yml b/.github/workflows/example-workflow-analyzer.lock.yml index 8183090c3d..c5fef3ddef 100644 --- a/.github/workflows/example-workflow-analyzer.lock.yml +++ b/.github/workflows/example-workflow-analyzer.lock.yml @@ -1164,7 +1164,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/firewall-escape.lock.yml b/.github/workflows/firewall-escape.lock.yml index 1b00b38e0f..5c9964c1bc 100644 --- a/.github/workflows/firewall-escape.lock.yml +++ b/.github/workflows/firewall-escape.lock.yml @@ -1259,7 +1259,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/functional-pragmatist.lock.yml b/.github/workflows/functional-pragmatist.lock.yml index da6a318d34..e9bef655cc 100644 --- a/.github/workflows/functional-pragmatist.lock.yml +++ b/.github/workflows/functional-pragmatist.lock.yml @@ -1104,7 +1104,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/github-mcp-structural-analysis.lock.yml b/.github/workflows/github-mcp-structural-analysis.lock.yml index 66b6e0ac9d..44daa87097 100644 --- a/.github/workflows/github-mcp-structural-analysis.lock.yml +++ b/.github/workflows/github-mcp-structural-analysis.lock.yml @@ -1176,7 +1176,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml index a3eea2e7c0..f621cf0957 100644 --- a/.github/workflows/github-mcp-tools-report.lock.yml +++ b/.github/workflows/github-mcp-tools-report.lock.yml @@ -1213,7 +1213,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/github-remote-mcp-auth-test.lock.yml b/.github/workflows/github-remote-mcp-auth-test.lock.yml index 76874b374a..cd82686742 100644 --- a/.github/workflows/github-remote-mcp-auth-test.lock.yml +++ b/.github/workflows/github-remote-mcp-auth-test.lock.yml @@ -1045,7 +1045,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/glossary-maintainer.lock.yml b/.github/workflows/glossary-maintainer.lock.yml index faf2ab0f82..b69431ccc9 100644 --- a/.github/workflows/glossary-maintainer.lock.yml +++ b/.github/workflows/glossary-maintainer.lock.yml @@ -1441,7 +1441,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/go-fan.lock.yml b/.github/workflows/go-fan.lock.yml index 55388aabd4..2fd3a29cac 100644 --- a/.github/workflows/go-fan.lock.yml +++ b/.github/workflows/go-fan.lock.yml @@ -1170,7 +1170,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index ee9a2bd6dd..7febbd9159 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -1373,7 +1373,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml index 1918ece4a0..9f4d5ead9e 100644 --- a/.github/workflows/go-pattern-detector.lock.yml +++ b/.github/workflows/go-pattern-detector.lock.yml @@ -1163,7 +1163,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/gpclean.lock.yml b/.github/workflows/gpclean.lock.yml index 8d558aa429..b27bd04f71 100644 --- a/.github/workflows/gpclean.lock.yml +++ b/.github/workflows/gpclean.lock.yml @@ -1072,7 +1072,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml index 7d061be293..4695b7cccd 100644 --- a/.github/workflows/grumpy-reviewer.lock.yml +++ b/.github/workflows/grumpy-reviewer.lock.yml @@ -1193,7 +1193,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/hourly-ci-cleaner.lock.yml b/.github/workflows/hourly-ci-cleaner.lock.yml index f6aef522b1..59442fd4dc 100644 --- a/.github/workflows/hourly-ci-cleaner.lock.yml +++ b/.github/workflows/hourly-ci-cleaner.lock.yml @@ -1211,7 +1211,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml index 2ffbab5580..97505e32cd 100644 --- a/.github/workflows/instructions-janitor.lock.yml +++ b/.github/workflows/instructions-janitor.lock.yml @@ -1194,7 +1194,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/issue-arborist.lock.yml b/.github/workflows/issue-arborist.lock.yml index e483049e00..da2a408001 100644 --- a/.github/workflows/issue-arborist.lock.yml +++ b/.github/workflows/issue-arborist.lock.yml @@ -1066,7 +1066,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/issue-monster.lock.yml b/.github/workflows/issue-monster.lock.yml index 9310ce4b76..005f8063a6 100644 --- a/.github/workflows/issue-monster.lock.yml +++ b/.github/workflows/issue-monster.lock.yml @@ -1802,7 +1802,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/issue-triage-agent.lock.yml b/.github/workflows/issue-triage-agent.lock.yml index ee784aa6d9..f7bcb8c937 100644 --- a/.github/workflows/issue-triage-agent.lock.yml +++ b/.github/workflows/issue-triage-agent.lock.yml @@ -1012,7 +1012,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/jsweep.lock.yml b/.github/workflows/jsweep.lock.yml index e078329a40..680e4124a2 100644 --- a/.github/workflows/jsweep.lock.yml +++ b/.github/workflows/jsweep.lock.yml @@ -1147,7 +1147,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/layout-spec-maintainer.lock.yml b/.github/workflows/layout-spec-maintainer.lock.yml index b5f130e8f8..6ad3988ac1 100644 --- a/.github/workflows/layout-spec-maintainer.lock.yml +++ b/.github/workflows/layout-spec-maintainer.lock.yml @@ -1133,7 +1133,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/lockfile-stats.lock.yml b/.github/workflows/lockfile-stats.lock.yml index 65b0c3f486..79a1047b68 100644 --- a/.github/workflows/lockfile-stats.lock.yml +++ b/.github/workflows/lockfile-stats.lock.yml @@ -1118,7 +1118,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index 990cc4c2ab..f10bfc913a 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -1829,7 +1829,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml index a92e731b91..9b74f2ce38 100644 --- a/.github/workflows/mergefest.lock.yml +++ b/.github/workflows/mergefest.lock.yml @@ -1220,7 +1220,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/notion-issue-summary.lock.yml b/.github/workflows/notion-issue-summary.lock.yml index 0be1f510c2..d460aed971 100644 --- a/.github/workflows/notion-issue-summary.lock.yml +++ b/.github/workflows/notion-issue-summary.lock.yml @@ -1046,7 +1046,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/org-health-report.lock.yml b/.github/workflows/org-health-report.lock.yml index b3cdf624ed..9e6c80721d 100644 --- a/.github/workflows/org-health-report.lock.yml +++ b/.github/workflows/org-health-report.lock.yml @@ -1103,7 +1103,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml index 8071a7c039..47871d6435 100644 --- a/.github/workflows/pdf-summary.lock.yml +++ b/.github/workflows/pdf-summary.lock.yml @@ -1261,7 +1261,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml index c91f9cd0f8..079f78fba4 100644 --- a/.github/workflows/plan.lock.yml +++ b/.github/workflows/plan.lock.yml @@ -1185,7 +1185,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/portfolio-analyst.lock.yml b/.github/workflows/portfolio-analyst.lock.yml index 06cfa8b51d..2c618c8d93 100644 --- a/.github/workflows/portfolio-analyst.lock.yml +++ b/.github/workflows/portfolio-analyst.lock.yml @@ -1209,7 +1209,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml index 8ad76ca2af..8d87089640 100644 --- a/.github/workflows/pr-nitpick-reviewer.lock.yml +++ b/.github/workflows/pr-nitpick-reviewer.lock.yml @@ -1285,7 +1285,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/pr-triage-agent.lock.yml b/.github/workflows/pr-triage-agent.lock.yml index b6f399541e..5e9f19c49a 100644 --- a/.github/workflows/pr-triage-agent.lock.yml +++ b/.github/workflows/pr-triage-agent.lock.yml @@ -1172,7 +1172,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml index 8f08d798f6..198489128f 100644 --- a/.github/workflows/prompt-clustering-analysis.lock.yml +++ b/.github/workflows/prompt-clustering-analysis.lock.yml @@ -1260,7 +1260,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index 5566240a3e..cdcd2a5b30 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -1192,7 +1192,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index 63acc91ae6..a17390ef71 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -1422,7 +1422,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/refiner.lock.yml b/.github/workflows/refiner.lock.yml index 3d8cdf3a4b..aee6a94bc2 100644 --- a/.github/workflows/refiner.lock.yml +++ b/.github/workflows/refiner.lock.yml @@ -1161,7 +1161,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 82a5e68c62..f57f7399a4 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -1415,7 +1415,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/repo-audit-analyzer.lock.yml b/.github/workflows/repo-audit-analyzer.lock.yml index 39e439b2d6..861cff40b9 100644 --- a/.github/workflows/repo-audit-analyzer.lock.yml +++ b/.github/workflows/repo-audit-analyzer.lock.yml @@ -1070,7 +1070,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/repo-tree-map.lock.yml b/.github/workflows/repo-tree-map.lock.yml index 3a09fce079..aa843b6da4 100644 --- a/.github/workflows/repo-tree-map.lock.yml +++ b/.github/workflows/repo-tree-map.lock.yml @@ -1036,7 +1036,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml index 0781364e7a..5013608ea7 100644 --- a/.github/workflows/repository-quality-improver.lock.yml +++ b/.github/workflows/repository-quality-improver.lock.yml @@ -1081,7 +1081,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/research.lock.yml b/.github/workflows/research.lock.yml index f39bd9fdd8..53d142349b 100644 --- a/.github/workflows/research.lock.yml +++ b/.github/workflows/research.lock.yml @@ -1069,7 +1069,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml index f58995ce3b..bfe4e13fc4 100644 --- a/.github/workflows/safe-output-health.lock.yml +++ b/.github/workflows/safe-output-health.lock.yml @@ -1219,7 +1219,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/schema-consistency-checker.lock.yml b/.github/workflows/schema-consistency-checker.lock.yml index 6d01a07dac..e8eebced22 100644 --- a/.github/workflows/schema-consistency-checker.lock.yml +++ b/.github/workflows/schema-consistency-checker.lock.yml @@ -1118,7 +1118,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml index 5c7eb23e1a..2f8ba78f27 100644 --- a/.github/workflows/scout.lock.yml +++ b/.github/workflows/scout.lock.yml @@ -1451,7 +1451,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/security-alert-burndown.campaign.g.lock.yml b/.github/workflows/security-alert-burndown.campaign.g.lock.yml index df03998b2c..22766d5b1b 100644 --- a/.github/workflows/security-alert-burndown.campaign.g.lock.yml +++ b/.github/workflows/security-alert-burndown.campaign.g.lock.yml @@ -1324,7 +1324,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/security-compliance.lock.yml b/.github/workflows/security-compliance.lock.yml index 86f96d5bd3..4586152854 100644 --- a/.github/workflows/security-compliance.lock.yml +++ b/.github/workflows/security-compliance.lock.yml @@ -1175,7 +1175,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/security-review.lock.yml b/.github/workflows/security-review.lock.yml index 434c6468f6..f93507f44c 100644 --- a/.github/workflows/security-review.lock.yml +++ b/.github/workflows/security-review.lock.yml @@ -1292,7 +1292,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml index 1c2b2cfbba..d24350a9b5 100644 --- a/.github/workflows/semantic-function-refactor.lock.yml +++ b/.github/workflows/semantic-function-refactor.lock.yml @@ -1161,7 +1161,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/sergo.lock.yml b/.github/workflows/sergo.lock.yml index 2e757fc635..128e54bda1 100644 --- a/.github/workflows/sergo.lock.yml +++ b/.github/workflows/sergo.lock.yml @@ -1169,7 +1169,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/slide-deck-maintainer.lock.yml b/.github/workflows/slide-deck-maintainer.lock.yml index f4c76eaf0b..86b67e9d54 100644 --- a/.github/workflows/slide-deck-maintainer.lock.yml +++ b/.github/workflows/slide-deck-maintainer.lock.yml @@ -1259,7 +1259,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-agent-all-merged.lock.yml b/.github/workflows/smoke-agent-all-merged.lock.yml index 5de6c14099..b2c48b439d 100644 --- a/.github/workflows/smoke-agent-all-merged.lock.yml +++ b/.github/workflows/smoke-agent-all-merged.lock.yml @@ -1092,7 +1092,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-agent-all-none.lock.yml b/.github/workflows/smoke-agent-all-none.lock.yml index 1fc5b6ea3a..2b5a7763f0 100644 --- a/.github/workflows/smoke-agent-all-none.lock.yml +++ b/.github/workflows/smoke-agent-all-none.lock.yml @@ -1092,7 +1092,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-agent-public-approved.lock.yml b/.github/workflows/smoke-agent-public-approved.lock.yml index bef84783a2..1f4d5bb66b 100644 --- a/.github/workflows/smoke-agent-public-approved.lock.yml +++ b/.github/workflows/smoke-agent-public-approved.lock.yml @@ -1140,7 +1140,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-agent-public-none.lock.yml b/.github/workflows/smoke-agent-public-none.lock.yml index 4cd731a9de..fce82aaa74 100644 --- a/.github/workflows/smoke-agent-public-none.lock.yml +++ b/.github/workflows/smoke-agent-public-none.lock.yml @@ -1092,7 +1092,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-agent-scoped-approved.lock.yml b/.github/workflows/smoke-agent-scoped-approved.lock.yml index 5145bba526..d6c24073c8 100644 --- a/.github/workflows/smoke-agent-scoped-approved.lock.yml +++ b/.github/workflows/smoke-agent-scoped-approved.lock.yml @@ -1096,7 +1096,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-call-workflow.lock.yml b/.github/workflows/smoke-call-workflow.lock.yml index a23d87c881..3398bed301 100644 --- a/.github/workflows/smoke-call-workflow.lock.yml +++ b/.github/workflows/smoke-call-workflow.lock.yml @@ -1071,7 +1071,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index b96f87ab00..957bbf08fd 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -2665,7 +2665,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index 6b67607ca6..fbd43c9e6d 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -1564,7 +1564,6 @@ jobs: payload: ${{ steps.process_safe_outputs.outputs.action_add_smoked_label_payload }} - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-copilot-arm.lock.yml b/.github/workflows/smoke-copilot-arm.lock.yml index ba51a432f9..3f22db53ef 100644 --- a/.github/workflows/smoke-copilot-arm.lock.yml +++ b/.github/workflows/smoke-copilot-arm.lock.yml @@ -2026,7 +2026,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 0816c5534b..7285241531 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -2073,7 +2073,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-create-cross-repo-pr.lock.yml b/.github/workflows/smoke-create-cross-repo-pr.lock.yml index 642e3754d6..524675b3c2 100644 --- a/.github/workflows/smoke-create-cross-repo-pr.lock.yml +++ b/.github/workflows/smoke-create-cross-repo-pr.lock.yml @@ -1257,7 +1257,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-gemini.lock.yml b/.github/workflows/smoke-gemini.lock.yml index 2f4e55c239..7adabe5bc9 100644 --- a/.github/workflows/smoke-gemini.lock.yml +++ b/.github/workflows/smoke-gemini.lock.yml @@ -1327,7 +1327,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-multi-pr.lock.yml b/.github/workflows/smoke-multi-pr.lock.yml index 5edb64cc4b..532e9147db 100644 --- a/.github/workflows/smoke-multi-pr.lock.yml +++ b/.github/workflows/smoke-multi-pr.lock.yml @@ -1245,7 +1245,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-project.lock.yml b/.github/workflows/smoke-project.lock.yml index b9f4db9d7b..338e7d7388 100644 --- a/.github/workflows/smoke-project.lock.yml +++ b/.github/workflows/smoke-project.lock.yml @@ -1382,7 +1382,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-temporary-id.lock.yml b/.github/workflows/smoke-temporary-id.lock.yml index 211338efa0..599fbc3bb4 100644 --- a/.github/workflows/smoke-temporary-id.lock.yml +++ b/.github/workflows/smoke-temporary-id.lock.yml @@ -1183,7 +1183,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-test-tools.lock.yml b/.github/workflows/smoke-test-tools.lock.yml index 96c3b3eaeb..e04b7bc426 100644 --- a/.github/workflows/smoke-test-tools.lock.yml +++ b/.github/workflows/smoke-test-tools.lock.yml @@ -1142,7 +1142,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-update-cross-repo-pr.lock.yml b/.github/workflows/smoke-update-cross-repo-pr.lock.yml index 7aed35068d..c77cdda019 100644 --- a/.github/workflows/smoke-update-cross-repo-pr.lock.yml +++ b/.github/workflows/smoke-update-cross-repo-pr.lock.yml @@ -1256,7 +1256,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/smoke-workflow-call-with-inputs.lock.yml b/.github/workflows/smoke-workflow-call-with-inputs.lock.yml index 3aef9b8827..3f82bca191 100644 --- a/.github/workflows/smoke-workflow-call-with-inputs.lock.yml +++ b/.github/workflows/smoke-workflow-call-with-inputs.lock.yml @@ -1138,7 +1138,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: ${{ needs.activation.outputs.artifact_prefix }}safe-output-items diff --git a/.github/workflows/smoke-workflow-call.lock.yml b/.github/workflows/smoke-workflow-call.lock.yml index 709be08fca..96b8d7428a 100644 --- a/.github/workflows/smoke-workflow-call.lock.yml +++ b/.github/workflows/smoke-workflow-call.lock.yml @@ -1132,7 +1132,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: ${{ needs.activation.outputs.artifact_prefix }}safe-output-items diff --git a/.github/workflows/stale-repo-identifier.lock.yml b/.github/workflows/stale-repo-identifier.lock.yml index c6a1dd75ac..d60c4f077f 100644 --- a/.github/workflows/stale-repo-identifier.lock.yml +++ b/.github/workflows/stale-repo-identifier.lock.yml @@ -1161,7 +1161,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml index 9e2c85987f..37c2a72730 100644 --- a/.github/workflows/static-analysis-report.lock.yml +++ b/.github/workflows/static-analysis-report.lock.yml @@ -1201,7 +1201,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/step-name-alignment.lock.yml b/.github/workflows/step-name-alignment.lock.yml index c1128a5425..37a18528d2 100644 --- a/.github/workflows/step-name-alignment.lock.yml +++ b/.github/workflows/step-name-alignment.lock.yml @@ -1131,7 +1131,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/sub-issue-closer.lock.yml b/.github/workflows/sub-issue-closer.lock.yml index 402b5a7a7b..f0145a4f2e 100644 --- a/.github/workflows/sub-issue-closer.lock.yml +++ b/.github/workflows/sub-issue-closer.lock.yml @@ -1078,7 +1078,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index 4d2b2949ed..9d44361c2a 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -1080,7 +1080,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index 6d3f3b07cb..8507096860 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -1460,7 +1460,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/terminal-stylist.lock.yml b/.github/workflows/terminal-stylist.lock.yml index 74bb6cebf8..123164f45f 100644 --- a/.github/workflows/terminal-stylist.lock.yml +++ b/.github/workflows/terminal-stylist.lock.yml @@ -1055,7 +1055,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/test-create-pr-error-handling.lock.yml b/.github/workflows/test-create-pr-error-handling.lock.yml index 13997bd7c8..ef1e72399f 100644 --- a/.github/workflows/test-create-pr-error-handling.lock.yml +++ b/.github/workflows/test-create-pr-error-handling.lock.yml @@ -1166,7 +1166,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/test-dispatcher.lock.yml b/.github/workflows/test-dispatcher.lock.yml index 6b820ae441..7c87cc34c2 100644 --- a/.github/workflows/test-dispatcher.lock.yml +++ b/.github/workflows/test-dispatcher.lock.yml @@ -1007,7 +1007,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/test-project-url-default.lock.yml b/.github/workflows/test-project-url-default.lock.yml index 60ffcf7341..6370633480 100644 --- a/.github/workflows/test-project-url-default.lock.yml +++ b/.github/workflows/test-project-url-default.lock.yml @@ -1075,7 +1075,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index 0b9ec75898..5c494791ef 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -1286,7 +1286,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml index 5b9560d24c..366a6f2694 100644 --- a/.github/workflows/typist.lock.yml +++ b/.github/workflows/typist.lock.yml @@ -1136,7 +1136,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/ubuntu-image-analyzer.lock.yml b/.github/workflows/ubuntu-image-analyzer.lock.yml index 0b2c55c8ea..429538b2fb 100644 --- a/.github/workflows/ubuntu-image-analyzer.lock.yml +++ b/.github/workflows/ubuntu-image-analyzer.lock.yml @@ -1181,7 +1181,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index 40e3477500..402f4642d3 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -1601,7 +1601,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/update-astro.lock.yml b/.github/workflows/update-astro.lock.yml index 2b0a1c319b..13391073d6 100644 --- a/.github/workflows/update-astro.lock.yml +++ b/.github/workflows/update-astro.lock.yml @@ -1202,7 +1202,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml index bac10fdc95..c43c9cfbe9 100644 --- a/.github/workflows/video-analyzer.lock.yml +++ b/.github/workflows/video-analyzer.lock.yml @@ -1072,7 +1072,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/weekly-blog-post-writer.lock.yml b/.github/workflows/weekly-blog-post-writer.lock.yml index 682cdd3e2f..c232479a87 100644 --- a/.github/workflows/weekly-blog-post-writer.lock.yml +++ b/.github/workflows/weekly-blog-post-writer.lock.yml @@ -1426,7 +1426,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/weekly-editors-health-check.lock.yml b/.github/workflows/weekly-editors-health-check.lock.yml index c089e8c39b..ca3603d33c 100644 --- a/.github/workflows/weekly-editors-health-check.lock.yml +++ b/.github/workflows/weekly-editors-health-check.lock.yml @@ -1167,7 +1167,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml index 290c6d5513..b8097d00ad 100644 --- a/.github/workflows/weekly-issue-summary.lock.yml +++ b/.github/workflows/weekly-issue-summary.lock.yml @@ -1087,7 +1087,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/weekly-safe-outputs-spec-review.lock.yml b/.github/workflows/weekly-safe-outputs-spec-review.lock.yml index 8b9515b633..549a93fa3e 100644 --- a/.github/workflows/weekly-safe-outputs-spec-review.lock.yml +++ b/.github/workflows/weekly-safe-outputs-spec-review.lock.yml @@ -1075,7 +1075,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/workflow-generator.lock.yml b/.github/workflows/workflow-generator.lock.yml index 669900fd83..13e4277ff1 100644 --- a/.github/workflows/workflow-generator.lock.yml +++ b/.github/workflows/workflow-generator.lock.yml @@ -1174,7 +1174,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/workflow-health-manager.lock.yml b/.github/workflows/workflow-health-manager.lock.yml index a86cb9401b..fa1bd9a4dd 100644 --- a/.github/workflows/workflow-health-manager.lock.yml +++ b/.github/workflows/workflow-health-manager.lock.yml @@ -1268,7 +1268,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/workflow-normalizer.lock.yml b/.github/workflows/workflow-normalizer.lock.yml index 004f4a7d53..4edde59aa9 100644 --- a/.github/workflows/workflow-normalizer.lock.yml +++ b/.github/workflows/workflow-normalizer.lock.yml @@ -1123,7 +1123,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/.github/workflows/workflow-skill-extractor.lock.yml b/.github/workflows/workflow-skill-extractor.lock.yml index 47221b3999..c05acb58cc 100644 --- a/.github/workflows/workflow-skill-extractor.lock.yml +++ b/.github/workflows/workflow-skill-extractor.lock.yml @@ -1093,7 +1093,6 @@ jobs: await main(); - name: Upload safe output items if: always() - continue-on-error: true uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output-items diff --git a/pkg/workflow/compiler_safe_outputs_job.go b/pkg/workflow/compiler_safe_outputs_job.go index d6edd10a0e..147fe78ca0 100644 --- a/pkg/workflow/compiler_safe_outputs_job.go +++ b/pkg/workflow/compiler_safe_outputs_job.go @@ -526,14 +526,10 @@ func buildDetectionSuccessCondition() ConditionNode { // "agent" artifact) to avoid a 409 Conflict when both the agent job and safe_outputs job // try to upload an artifact with the same name in the same workflow run. // prefix is prepended to the artifact name; use empty string for non-workflow_call workflows. -// continue-on-error is set to true because actions/upload-artifact v4+ returns a 409 -// conflict when a second job tries to upload to an artifact name that already exists; -// the upload conflict must not fail the safe_outputs job. func buildSafeOutputItemsManifestUploadStep(prefix string) []string { return []string{ " - name: Upload safe output items\n", " if: always()\n", - " continue-on-error: true\n", fmt.Sprintf(" uses: %s\n", GetActionPin("actions/upload-artifact")), " with:\n", fmt.Sprintf(" name: %s%s\n", prefix, constants.SafeOutputItemsArtifactName),