MCPcopy Create free account
hub / github.com/github/gh-aw / main

Function main

actions/setup/js/dispatch_workflow.cjs:24–321  ·  view source on GitHub ↗

* Main handler factory for dispatch_workflow * Returns a message handler function that processes individual dispatch_workflow messages * @type {HandlerFactoryFunction}

(config = {})

Source from the content-addressed store, hash-verified

22 * @type {HandlerFactoryFunction}
23 */
24async function main(config = {}) {
25 // Extract configuration
26 const allowedWorkflows = config.workflows || [];
27 const maxCount = config.max || 1;
28 const workflowFiles = config.workflow_files || {}; // Map of workflow name to file extension
29 const awContextWorkflows = new Set(config.aw_context_workflows || []); // Workflows that accept aw_context input
30 const githubClient = await createAuthenticatedGitHubClient(config);
31 const { defaultTargetRepo, allowedRepos } = resolveTargetRepoConfig(config);
32
33 // Resolve the dispatch destination repository from target-repo config, falling back to context.repo
34 const contextRepoSlug = `${context.repo.owner}/${context.repo.repo}`;
35 const normalizedTargetRepo = (defaultTargetRepo ?? "").toString().trim();
36
37 let resolvedRepoSlug = contextRepoSlug;
38 let repo = context.repo;
39
40 if (normalizedTargetRepo) {
41 const parsedRepo = parseRepoSlug(normalizedTargetRepo);
42 if (!parsedRepo) {
43 core.warning(`Invalid 'target-repo' configuration value '${normalizedTargetRepo}'; falling back to workflow context repository ${contextRepoSlug}.`);
44 } else {
45 resolvedRepoSlug = normalizedTargetRepo;
46 repo = parsedRepo;
47 }
48 }
49
50 const isCrossRepoDispatch = resolvedRepoSlug !== contextRepoSlug;
51
52 // SEC-005: Enforce cross-repository allowlist per Safe Outputs Specification §3.2.6 (SP6).
53 // Default-deny: cross-repo dispatch is only permitted when an explicit allowlist is configured
54 // and the resolved target repo is present in that list. Uses validateTargetRepo from
55 // repo_helpers.cjs for consistent slug validation and glob-pattern matching (e.g. "org/*").
56 if (isCrossRepoDispatch) {
57 if (allowedRepos.size === 0) {
58 throw new Error(
59 `E004: Cross-repository dispatch to '${resolvedRepoSlug}' is not permitted. No allowlist is configured. Define 'allowed-repos' in the workflow's 'safe-outputs.dispatch-workflow' section to enable cross-repository dispatch.`
60 );
61 }
62 const repoValidation = validateTargetRepo(resolvedRepoSlug, contextRepoSlug, allowedRepos);
63 if (!repoValidation.valid) {
64 throw new Error(`E004: ${repoValidation.error}`);
65 }
66 core.info(`Cross-repo allowlist check passed for ${resolvedRepoSlug}`);
67 }
68
69 core.info(`Dispatch workflow configuration: max=${maxCount}`);
70 if (allowedWorkflows.length > 0) {
71 core.info(`Allowed workflows: ${allowedWorkflows.join(", ")}`);
72 }
73 if (Object.keys(workflowFiles).length > 0) {
74 core.info(`Workflow files: ${JSON.stringify(workflowFiles)}`);
75 }
76 if (isCrossRepoDispatch) {
77 core.info(`Dispatching to target repo: ${resolvedRepoSlug}`);
78 }
79
80 // Track how many items we've processed for max limit
81 let processedCount = 0;

Callers

nothing calls this directly

Calls 13

resolveTargetRepoConfigFunction · 0.85
validateTargetRepoFunction · 0.85
isStagedModeFunction · 0.85
getDefaultBranchRefFunction · 0.85
buildAwContextFunction · 0.85
logStagedPreviewInfoFunction · 0.85
errorMethod · 0.80
parseRepoSlugFunction · 0.70
resolveIssueNumberFunction · 0.70

Tested by

no test coverage detected