Add support for defined custom safe-output scripts#21582
Add support for defined custom safe-output scripts#21582
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
|
Hey
If you'd like a hand finishing the remaining items, you can use this prompt with your coding agent:
|
|
@copilot keep working |
All checklist items are complete. The implementation adds Usage example: safe-outputs:
scripts:
slack-post-message:
description: Post a message to Slack
inputs:
channel:
description: Target channel
required: true
type: string
message:
description: Message text
required: true
type: string
script: |
async function main(config = {}) {
const { channel, message } = config;
return async function handleSlackPostMessage(item) {
// ... handler logic using github, context, core globals
return { success: true };
};
}
module.exports = { main };How it works:
Build, lint, and all 15 new unit tests pass. 174 existing workflows recompile cleanly. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot use the same trick as in MCP-scripts or actions/github-script and let the user write the body of main directly , then wrap it with main when writing the JavaScript file in the action. |
…only Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in bda995e. Users now write only the body of Before (required boilerplate): async function main(config = {}) {
const { channel } = config;
return async (msg) => ({ success: true });
}
module.exports = { main };After (just the body): const { channel } = config;
return async (msg) => ({ success: true });The compiler generates the full module file with the Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot update smoke-claude to use safe-output scripts to post a ficticious slack message. |
…scripts to schema Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in 9de4b93. scripts:
post-slack-message:
description: Post a message to a fictitious Slack channel (smoke test only)
inputs:
channel: { type: string, required: true }
message: { type: string, required: true }
script: |
const { channel, message } = config;
return async function handlePostSlackMessage(item) {
const targetChannel = item.data?.channel || channel || "#general";
const text = item.data?.message || message || "(no message)";
core.info(`[FICTITIOUS SLACK] → ${targetChannel}: ${text}`);
return { success: true, channel: targetChannel, message: text };
};The Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot generate the typescript definition so that users know the typedefinition of config. (put it in a separate file) |
…e-claude script body Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in 6ca853f. Created
Also fixed the smoke-claude example script to use Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
Adds
safe-outputs.scriptssupport — inline JavaScript handlers that run within the consolidated safe-outputs job's handler loop, similar tosafe-outputs.jobsbut without creating a separate GitHub Actions job.Usage
Users write only the body of the handler setup function — the compiler automatically wraps it with
async function main(config = {}) { ... }andmodule.exports = { main };, the same pattern used by MCP-scripts andactions/github-script:The compiler generates the full module file:
How It Works
${RUNNER_TEMP}/gh-aw/actions/safe_output_script_<name>.cjsvia a heredoc step in the safe-outputs job, wrapping the user's body inasync function main(config = {}) { ... }andmodule.exports = { main };.GH_AW_SAFE_OUTPUT_SCRIPTS(a JSON map of normalized name → filename) is passed as an env var to the handler manager step.main(config), and dispatches messages of the matching type to the returned handler function.Changes Made
compiler_types.go— AddedScripts map[string]*SafeScriptConfigfield toSafeOutputsConfigsafe_scripts.go— New file:SafeScriptConfigstruct, parsing helpers, JSON env var builder, andgenerateCustomScriptToolDefinition()safe_outputs_config.go— Parsescripts:key from frontmattersafe_outputs_state.go— Include Scripts inhasAnySafeOutputEnabled()andhasNonBuiltinSafeOutputsEnabled()safe_outputs_config_generation.go— Emit script config intoGH_AW_SAFE_OUTPUTS_HANDLER_CONFIGsafe_outputs_tools_filtering.go— Include script tool definitions in filtered and dynamic tools JSONcompiler_safe_outputs_job.go—generateSafeOutputScriptContent()wraps user body withmain()+module.exports;buildCustomScriptFilesStep()writes wrapped scripts via heredoc; scripts included inhasHandlerManagerTypescompiler_safe_outputs_steps.go— EmitGH_AW_SAFE_OUTPUT_SCRIPTSenv var on handler manager stepsafe_output_helpers.cjs—loadCustomSafeOutputScriptHandlers()parsesGH_AW_SAFE_OUTPUT_SCRIPTSsafe_output_handler_manager.cjs— Loads and dispatches to custom script handlers after built-in HANDLER_MAP handlersmain_workflow_schema.json— Addedscriptsas a validsafe-outputsproperty with full sub-schema forinputsandscriptfieldssmoke-claude.md— Addedpost-slack-messagescript as a real-world usage example, with a corresponding test step (Fix orphan removal on "gh aw remove" #11) that exercises thepost_slack_messagetoolactions/setup/js/types/safe-output-script.d.ts— New TypeScript definition file documenting the types available when writing a custom safe-output scriptTypeScript Definitions
The new
safe-output-script.d.tsfile exports the following types for script authors:SafeOutputScriptInputDefinitiontype,description,required,default,options)SafeOutputScriptConfigconfigparameter ofmain()— static YAML metadata (description+inputsschema)SafeOutputScriptItem<TInputs>SafeOutputScriptHandler<TInputs>main()SafeOutputScriptMain<TInputs>Testing
make build,make fmt,make lintall passsmoke-claudeworkflow recompiles cleanly with the newpost-slack-messagescriptOriginal prompt
📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.