@hybridlabor-api/aos 4.7.2 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/agents.md +1 -1
- package/.agents/nodes.json +1 -1
- package/.agents/vendor-manifest.json +23 -1
- package/.claude/agents/godmode-media-eventtech.md +1 -1
- package/.claude/hooks/conventional-commits.mjs +125 -0
- package/.claude/hooks/env-file-protection.mjs +105 -0
- package/.claude/hooks/go-gate.mjs +101 -81
- package/.claude/settings.json +13 -0
- package/.opencode/agents/godmode-media-eventtech.md +1 -1
- package/.opencode/plugins/bdb-aos.js +31 -4
- package/README.de.md +1 -1
- package/README.md +1 -1
- package/README.pt.md +1 -1
- package/THIRD_PARTY_NOTICES.md +88 -0
- package/docs/skills_table.md +1 -1
- package/installer.js +309 -101
- package/package.json +6 -2
- package/packages/aos-cli/README.md +80 -0
- package/packages/aos-cli/bin/aos-cli.mjs +134 -0
- package/packages/aos-cli/core-skills.json +12 -0
- package/packages/aos-cli/extensions/aos.ts +321 -0
- package/packages/aos-cli/package-lock.json +1923 -0
- package/packages/aos-cli/package.json +29 -0
- package/packages/aos-cli/scripts/check-theme.mjs +63 -0
- package/packages/aos-cli/themes/aos.json +97 -0
- package/scripts/build-plugin-manifest.mjs +131 -0
- package/scripts/validate-skills.mjs +81 -6
- package/skills/basic/ao-orchestrator/SKILL.md +116 -0
- package/skills/global_config/agenttrail/SKILL.md +6 -1
- package/skills/global_config/ask-tim/SKILL.md +4 -4
- package/skills/global_config/bash-script-generator/SKILL.md +201 -0
- package/skills/global_config/bash-script-generator/assets/templates/standard-template.sh +96 -0
- package/skills/global_config/bash-script-generator/docs/bash-scripting-guide.md +729 -0
- package/skills/global_config/bash-script-generator/docs/generation-best-practices.md +193 -0
- package/skills/global_config/bash-script-generator/docs/script-patterns.md +566 -0
- package/skills/global_config/bash-script-generator/docs/text-processing-guide.md +437 -0
- package/skills/global_config/bash-script-generator/examples/log-analyzer.sh +92 -0
- package/skills/global_config/bash-script-generator/scripts/generate_script_template.sh +123 -0
- package/skills/global_config/bash-script-generator/scripts/run_ci_checks.sh +172 -0
- package/skills/global_config/bash-script-generator/scripts/test_generator.sh +413 -0
- package/skills/global_config/bash-script-validator/SKILL.md +249 -0
- package/skills/global_config/bash-script-validator/docs/awk-reference.md +449 -0
- package/skills/global_config/bash-script-validator/docs/bash-reference.md +468 -0
- package/skills/global_config/bash-script-validator/docs/common-mistakes.md +623 -0
- package/skills/global_config/bash-script-validator/docs/grep-reference.md +395 -0
- package/skills/global_config/bash-script-validator/docs/regex-reference.md +391 -0
- package/skills/global_config/bash-script-validator/docs/sed-reference.md +454 -0
- package/skills/global_config/bash-script-validator/docs/shell-reference.md +463 -0
- package/skills/global_config/bash-script-validator/docs/shellcheck-reference.md +399 -0
- package/skills/global_config/bash-script-validator/examples/bad-bash.sh +55 -0
- package/skills/global_config/bash-script-validator/examples/bad-shell.sh +54 -0
- package/skills/global_config/bash-script-validator/examples/good-bash.sh +71 -0
- package/skills/global_config/bash-script-validator/examples/good-shell.sh +69 -0
- package/skills/global_config/bash-script-validator/scripts/run_ci_checks.sh +23 -0
- package/skills/global_config/bash-script-validator/scripts/shellcheck_wrapper.sh +174 -0
- package/skills/global_config/bash-script-validator/scripts/test_validate.sh +446 -0
- package/skills/global_config/bash-script-validator/scripts/validate.sh +512 -0
- package/skills/global_config/ci-pipeline/SKILL.md +135 -0
- package/skills/global_config/dispatching-parallel-agents/SKILL.md +170 -0
- package/skills/global_config/dockerfile-generator/SKILL.md +1038 -0
- package/skills/global_config/dockerfile-generator/examples/example.dockerignore +95 -0
- package/skills/global_config/dockerfile-generator/examples/golang-distroless.Dockerfile +34 -0
- package/skills/global_config/dockerfile-generator/examples/java-springboot.Dockerfile +45 -0
- package/skills/global_config/dockerfile-generator/examples/nextjs-production.Dockerfile +49 -0
- package/skills/global_config/dockerfile-generator/examples/nodejs-multistage.Dockerfile +55 -0
- package/skills/global_config/dockerfile-generator/examples/python-fastapi.Dockerfile +48 -0
- package/skills/global_config/dockerfile-generator/references/language_specific_guides.md +510 -0
- package/skills/global_config/dockerfile-generator/references/multistage_builds.md +570 -0
- package/skills/global_config/dockerfile-generator/references/optimization_patterns.md +492 -0
- package/skills/global_config/dockerfile-generator/references/security_best_practices.md +375 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_dockerignore.sh +199 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_golang.sh +172 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_java.sh +185 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_nodejs.sh +279 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_python.sh +218 -0
- package/skills/global_config/dockerfile-generator/scripts/test_generator.sh +210 -0
- package/skills/global_config/dockerfile-validator/SKILL.md +300 -0
- package/skills/global_config/dockerfile-validator/examples/.dockerignore.example +34 -0
- package/skills/global_config/dockerfile-validator/examples/bad-example.Dockerfile +37 -0
- package/skills/global_config/dockerfile-validator/examples/golang-distroless.Dockerfile +50 -0
- package/skills/global_config/dockerfile-validator/examples/good-example.Dockerfile +52 -0
- package/skills/global_config/dockerfile-validator/examples/python-optimized.Dockerfile +53 -0
- package/skills/global_config/dockerfile-validator/examples/security-issues.Dockerfile +42 -0
- package/skills/global_config/dockerfile-validator/references/docker_best_practices.md +348 -0
- package/skills/global_config/dockerfile-validator/references/optimization_guide.md +473 -0
- package/skills/global_config/dockerfile-validator/references/security_checklist.md +208 -0
- package/skills/global_config/dockerfile-validator/scripts/dockerfile-validate.sh +699 -0
- package/skills/global_config/dockerfile-validator/scripts/test_validate.sh +35 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn-lock-read.Dockerfile +6 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn.Dockerfile +6 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/from-platform-nonroot.Dockerfile +7 -0
- package/skills/global_config/dockerfile-validator/tests/test_regression.sh +164 -0
- package/skills/global_config/finishing-a-development-branch/SKILL.md +228 -0
- package/skills/global_config/github-actions-generator/SKILL.md +353 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/composite/action.yml +82 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/Dockerfile +25 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/action.yml +42 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/entrypoint.sh +27 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/action.yml +33 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/index.js +50 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/package.json +27 -0
- package/skills/global_config/github-actions-generator/assets/templates/workflow/basic_workflow.yml +242 -0
- package/skills/global_config/github-actions-generator/assets/templates/workflow/reusable_workflow.yml +106 -0
- package/skills/global_config/github-actions-generator/examples/README.md +147 -0
- package/skills/global_config/github-actions-generator/examples/actions/setup-node-cached/action.yml +93 -0
- package/skills/global_config/github-actions-generator/examples/caching/docker-buildkit.yml +256 -0
- package/skills/global_config/github-actions-generator/examples/security/dependency-review.yml +62 -0
- package/skills/global_config/github-actions-generator/examples/security/sbom-attestation.yml +119 -0
- package/skills/global_config/github-actions-generator/examples/triggers/chatops-commands.yml +475 -0
- package/skills/global_config/github-actions-generator/examples/triggers/repository-dispatch.yml +418 -0
- package/skills/global_config/github-actions-generator/examples/triggers/workflow-orchestration.yml +404 -0
- package/skills/global_config/github-actions-generator/examples/workflows/docker-build-push.yml +68 -0
- package/skills/global_config/github-actions-generator/examples/workflows/go-ci.yml +161 -0
- package/skills/global_config/github-actions-generator/examples/workflows/monorepo-ci.yml +340 -0
- package/skills/global_config/github-actions-generator/examples/workflows/multi-environment-deploy.yml +406 -0
- package/skills/global_config/github-actions-generator/examples/workflows/nodejs-ci.yml +122 -0
- package/skills/global_config/github-actions-generator/examples/workflows/python-ci.yml +157 -0
- package/skills/global_config/github-actions-generator/examples/workflows/scheduled-tasks.yml +376 -0
- package/skills/global_config/github-actions-generator/references/advanced-triggers.md +917 -0
- package/skills/global_config/github-actions-generator/references/best-practices.md +755 -0
- package/skills/global_config/github-actions-generator/references/common-actions.md +715 -0
- package/skills/global_config/github-actions-generator/references/custom-actions.md +320 -0
- package/skills/global_config/github-actions-generator/references/expressions-and-contexts.md +688 -0
- package/skills/global_config/github-actions-generator/references/modern-features.md +421 -0
- package/skills/global_config/github-actions-generator/scripts/test_generator.sh +344 -0
- package/skills/global_config/github-actions-templates/SKILL.md +7 -0
- package/skills/global_config/github-actions-validator/SKILL.md +576 -0
- package/skills/global_config/github-actions-validator/examples/README.md +88 -0
- package/skills/global_config/github-actions-validator/examples/outdated-versions.yml +76 -0
- package/skills/global_config/github-actions-validator/examples/valid-ci.yml +79 -0
- package/skills/global_config/github-actions-validator/examples/with-errors.yml +47 -0
- package/skills/global_config/github-actions-validator/references/act_usage.md +233 -0
- package/skills/global_config/github-actions-validator/references/action_versions.md +122 -0
- package/skills/global_config/github-actions-validator/references/actionlint_usage.md +343 -0
- package/skills/global_config/github-actions-validator/references/common_errors.md +512 -0
- package/skills/global_config/github-actions-validator/references/modern_features.md +384 -0
- package/skills/global_config/github-actions-validator/references/runners.md +317 -0
- package/skills/global_config/github-actions-validator/scripts/install_tools.sh +113 -0
- package/skills/global_config/github-actions-validator/scripts/validate_workflow.sh +910 -0
- package/skills/global_config/github-actions-validator/tests/test_validate_workflow.sh +237 -0
- package/skills/global_config/makefile-generator/SKILL.md +614 -0
- package/skills/global_config/makefile-generator/assets/templates/.gitkeep +1 -0
- package/skills/global_config/makefile-generator/docs/makefile-structure.md +530 -0
- package/skills/global_config/makefile-generator/docs/optimization-guide.md +784 -0
- package/skills/global_config/makefile-generator/docs/patterns-guide.md +642 -0
- package/skills/global_config/makefile-generator/docs/security-guide.md +361 -0
- package/skills/global_config/makefile-generator/docs/targets-guide.md +642 -0
- package/skills/global_config/makefile-generator/docs/variables-guide.md +596 -0
- package/skills/global_config/makefile-generator/scripts/add_standard_targets.sh +539 -0
- package/skills/global_config/makefile-generator/scripts/generate_makefile_template.sh +690 -0
- package/skills/global_config/makefile-generator/test/test_helper_scripts.sh +190 -0
- package/skills/global_config/makefile-validator/SKILL.md +244 -0
- package/skills/global_config/makefile-validator/docs/bake-tool.md +1000 -0
- package/skills/global_config/makefile-validator/docs/best-practices.md +858 -0
- package/skills/global_config/makefile-validator/docs/common-mistakes.md +944 -0
- package/skills/global_config/makefile-validator/examples/bad-makefile.mk +77 -0
- package/skills/global_config/makefile-validator/examples/good-makefile.mk +103 -0
- package/skills/global_config/makefile-validator/scripts/test_validate.sh +382 -0
- package/skills/global_config/makefile-validator/scripts/validate_makefile.sh +712 -0
- package/skills/global_config/{MCP_Manage → mcp-manage}/SKILL.md +3 -3
- package/skills/global_config/requesting-code-review/SKILL.md +98 -0
- package/skills/global_config/requesting-code-review/code-reviewer.md +198 -0
- package/skills/global_config/using-git-worktrees/SKILL.md +170 -0
- package/skills/global_config/verification-before-completion/SKILL.md +123 -0
- package/skills/global_config/writing-plans/SKILL.md +126 -46
- package/skills/global_config/writing-plans-legacy/SKILL.md +139 -0
|
@@ -0,0 +1,917 @@
|
|
|
1
|
+
# Advanced GitHub Actions Triggers
|
|
2
|
+
|
|
3
|
+
**Last Updated:** November 2025
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This guide covers advanced trigger patterns for GitHub Actions workflows beyond the basic `push`, `pull_request`, and `schedule` triggers. These patterns enable workflow orchestration, external integrations, ChatOps, and complex automation scenarios.
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
1. [Workflow Orchestration](#workflow-orchestration)
|
|
12
|
+
2. [External Integration](#external-integration)
|
|
13
|
+
3. [ChatOps Patterns](#chatops-patterns)
|
|
14
|
+
4. [Deployment Triggers](#deployment-triggers)
|
|
15
|
+
5. [Advanced Path Filtering](#advanced-path-filtering)
|
|
16
|
+
6. [Security Patterns](#security-patterns)
|
|
17
|
+
7. [GitHub Services Integration](#github-services-integration)
|
|
18
|
+
8. [Best Practices](#best-practices)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Workflow Orchestration
|
|
23
|
+
|
|
24
|
+
### workflow_run Trigger
|
|
25
|
+
|
|
26
|
+
The `workflow_run` trigger allows you to chain workflows together, running one workflow after another completes. This is the **recommended pattern** for handling external pull requests securely.
|
|
27
|
+
|
|
28
|
+
#### Basic Syntax
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
name: Deploy Application
|
|
32
|
+
|
|
33
|
+
on:
|
|
34
|
+
workflow_run:
|
|
35
|
+
workflows: ["CI Pipeline"]
|
|
36
|
+
types: [completed]
|
|
37
|
+
branches: [main, staging]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Trigger Types
|
|
41
|
+
|
|
42
|
+
- `requested` - Workflow run was requested
|
|
43
|
+
- `in_progress` - Workflow run is currently running
|
|
44
|
+
- `completed` - Workflow run has finished (success, failure, or cancelled)
|
|
45
|
+
|
|
46
|
+
#### Use Cases
|
|
47
|
+
|
|
48
|
+
**1. Deployment After CI Success**
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
# deploy.yml - Separate deployment workflow
|
|
52
|
+
name: Deploy to Production
|
|
53
|
+
|
|
54
|
+
on:
|
|
55
|
+
workflow_run:
|
|
56
|
+
workflows: ["CI Pipeline"]
|
|
57
|
+
types: [completed]
|
|
58
|
+
branches: [main]
|
|
59
|
+
|
|
60
|
+
jobs:
|
|
61
|
+
deploy:
|
|
62
|
+
# Only deploy if CI passed
|
|
63
|
+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
|
|
66
|
+
environment:
|
|
67
|
+
name: production
|
|
68
|
+
url: https://example.com
|
|
69
|
+
|
|
70
|
+
steps:
|
|
71
|
+
- name: Checkout code
|
|
72
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
73
|
+
|
|
74
|
+
- name: Download build artifacts from CI
|
|
75
|
+
uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4
|
|
76
|
+
with:
|
|
77
|
+
name: build-artifacts
|
|
78
|
+
run-id: ${{ github.event.workflow_run.id }}
|
|
79
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
80
|
+
|
|
81
|
+
- name: Deploy application
|
|
82
|
+
run: |
|
|
83
|
+
echo "Deploying commit ${{ github.event.workflow_run.head_sha }}"
|
|
84
|
+
# Deployment commands here
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**2. Security Scanning for External PRs**
|
|
88
|
+
|
|
89
|
+
```yaml
|
|
90
|
+
# security-scan.yml - Runs after CI for external PRs
|
|
91
|
+
name: Security Scan
|
|
92
|
+
|
|
93
|
+
on:
|
|
94
|
+
workflow_run:
|
|
95
|
+
workflows: ["CI"]
|
|
96
|
+
types: [completed]
|
|
97
|
+
|
|
98
|
+
permissions:
|
|
99
|
+
security-events: write
|
|
100
|
+
contents: read
|
|
101
|
+
|
|
102
|
+
jobs:
|
|
103
|
+
scan:
|
|
104
|
+
# Only scan if CI passed and it was a PR
|
|
105
|
+
if: |
|
|
106
|
+
github.event.workflow_run.conclusion == 'success' &&
|
|
107
|
+
github.event.workflow_run.event == 'pull_request'
|
|
108
|
+
runs-on: ubuntu-latest
|
|
109
|
+
|
|
110
|
+
steps:
|
|
111
|
+
- name: Checkout PR code
|
|
112
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
113
|
+
with:
|
|
114
|
+
ref: ${{ github.event.workflow_run.head_sha }}
|
|
115
|
+
|
|
116
|
+
- name: Run security scan
|
|
117
|
+
run: |
|
|
118
|
+
# Security scanning without exposing secrets to PR
|
|
119
|
+
npm audit --audit-level=high
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Accessing Workflow Run Information
|
|
123
|
+
|
|
124
|
+
```yaml
|
|
125
|
+
steps:
|
|
126
|
+
- name: Get workflow run details
|
|
127
|
+
run: |
|
|
128
|
+
echo "Workflow: ${{ github.event.workflow_run.name }}"
|
|
129
|
+
echo "Conclusion: ${{ github.event.workflow_run.conclusion }}"
|
|
130
|
+
echo "Head SHA: ${{ github.event.workflow_run.head_sha }}"
|
|
131
|
+
echo "Head Branch: ${{ github.event.workflow_run.head_branch }}"
|
|
132
|
+
echo "Run ID: ${{ github.event.workflow_run.id }}"
|
|
133
|
+
echo "Event: ${{ github.event.workflow_run.event }}"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### Security Benefits
|
|
137
|
+
|
|
138
|
+
✅ **Safer than `pull_request_target`** for external PRs:
|
|
139
|
+
- Runs with workflow file from target branch (not PR)
|
|
140
|
+
- No access to PR code by default
|
|
141
|
+
- Secrets are safe from malicious PRs
|
|
142
|
+
- Must explicitly checkout PR code if needed
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## External Integration
|
|
147
|
+
|
|
148
|
+
### repository_dispatch Trigger
|
|
149
|
+
|
|
150
|
+
The `repository_dispatch` trigger allows external systems to trigger workflows via the GitHub API. This enables integration with webhooks, custom dashboards, monitoring systems, and other external tools.
|
|
151
|
+
|
|
152
|
+
#### Basic Syntax
|
|
153
|
+
|
|
154
|
+
```yaml
|
|
155
|
+
name: Handle External Event
|
|
156
|
+
|
|
157
|
+
on:
|
|
158
|
+
repository_dispatch:
|
|
159
|
+
types: [deploy-prod, deploy-staging, run-migration, rebuild-cache]
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### Event Types
|
|
163
|
+
|
|
164
|
+
Event types are custom strings you define. Common patterns:
|
|
165
|
+
- `deploy-<environment>` - Deployment triggers
|
|
166
|
+
- `run-<task>` - Task execution
|
|
167
|
+
- `notify-<event>` - Notification handling
|
|
168
|
+
|
|
169
|
+
#### Triggering via API
|
|
170
|
+
|
|
171
|
+
**Using curl:**
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
curl -X POST \
|
|
175
|
+
-H "Authorization: token $GITHUB_TOKEN" \
|
|
176
|
+
-H "Accept: application/vnd.github.v3+json" \
|
|
177
|
+
https://api.github.com/repos/OWNER/REPO/dispatches \
|
|
178
|
+
-d '{
|
|
179
|
+
"event_type": "deploy-prod",
|
|
180
|
+
"client_payload": {
|
|
181
|
+
"version": "v1.2.3",
|
|
182
|
+
"requestor": "monitoring-system",
|
|
183
|
+
"environment": "production",
|
|
184
|
+
"rollback": false
|
|
185
|
+
}
|
|
186
|
+
}'
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Using Python:**
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
import requests
|
|
193
|
+
|
|
194
|
+
def trigger_deployment(repo, token, version, environment):
|
|
195
|
+
url = f"https://api.github.com/repos/{repo}/dispatches"
|
|
196
|
+
headers = {
|
|
197
|
+
"Authorization": f"token {token}",
|
|
198
|
+
"Accept": "application/vnd.github.v3+json"
|
|
199
|
+
}
|
|
200
|
+
payload = {
|
|
201
|
+
"event_type": f"deploy-{environment}",
|
|
202
|
+
"client_payload": {
|
|
203
|
+
"version": version,
|
|
204
|
+
"requestor": "api",
|
|
205
|
+
"environment": environment
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
response = requests.post(url, json=payload, headers=headers)
|
|
209
|
+
return response.status_code == 204
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Using Node.js (Octokit):**
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
const { Octokit } = require("@octokit/rest");
|
|
216
|
+
|
|
217
|
+
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
|
|
218
|
+
|
|
219
|
+
await octokit.repos.createDispatchEvent({
|
|
220
|
+
owner: "OWNER",
|
|
221
|
+
repo: "REPO",
|
|
222
|
+
event_type: "deploy-prod",
|
|
223
|
+
client_payload: {
|
|
224
|
+
version: "v1.2.3",
|
|
225
|
+
requestor: "api",
|
|
226
|
+
environment: "production"
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
#### Handling Dispatch Events
|
|
232
|
+
|
|
233
|
+
```yaml
|
|
234
|
+
name: External Deployment Trigger
|
|
235
|
+
|
|
236
|
+
on:
|
|
237
|
+
repository_dispatch:
|
|
238
|
+
types: [deploy-prod, deploy-staging, deploy-dev]
|
|
239
|
+
|
|
240
|
+
jobs:
|
|
241
|
+
deploy:
|
|
242
|
+
runs-on: ubuntu-latest
|
|
243
|
+
|
|
244
|
+
steps:
|
|
245
|
+
- name: Parse dispatch payload
|
|
246
|
+
id: payload
|
|
247
|
+
run: |
|
|
248
|
+
echo "Event Type: ${{ github.event.action }}"
|
|
249
|
+
echo "Version: ${{ github.event.client_payload.version }}"
|
|
250
|
+
echo "Environment: ${{ github.event.client_payload.environment }}"
|
|
251
|
+
echo "Requestor: ${{ github.event.client_payload.requestor }}"
|
|
252
|
+
|
|
253
|
+
# Set outputs for later steps
|
|
254
|
+
echo "version=${{ github.event.client_payload.version }}" >> $GITHUB_OUTPUT
|
|
255
|
+
echo "environment=${{ github.event.client_payload.environment }}" >> $GITHUB_OUTPUT
|
|
256
|
+
|
|
257
|
+
- name: Checkout specific version
|
|
258
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
259
|
+
with:
|
|
260
|
+
ref: ${{ steps.payload.outputs.version }}
|
|
261
|
+
|
|
262
|
+
- name: Deploy to environment
|
|
263
|
+
env:
|
|
264
|
+
ENVIRONMENT: ${{ steps.payload.outputs.environment }}
|
|
265
|
+
VERSION: ${{ steps.payload.outputs.version }}
|
|
266
|
+
run: |
|
|
267
|
+
echo "Deploying $VERSION to $ENVIRONMENT"
|
|
268
|
+
# Deployment logic here
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
#### Use Cases
|
|
272
|
+
|
|
273
|
+
**1. Webhook Integration**
|
|
274
|
+
|
|
275
|
+
Trigger workflows from external monitoring/alerting systems:
|
|
276
|
+
|
|
277
|
+
```yaml
|
|
278
|
+
on:
|
|
279
|
+
repository_dispatch:
|
|
280
|
+
types: [incident-detected, performance-degradation]
|
|
281
|
+
|
|
282
|
+
jobs:
|
|
283
|
+
handle-alert:
|
|
284
|
+
runs-on: ubuntu-latest
|
|
285
|
+
steps:
|
|
286
|
+
- name: Process alert
|
|
287
|
+
run: |
|
|
288
|
+
SEVERITY="${{ github.event.client_payload.severity }}"
|
|
289
|
+
MESSAGE="${{ github.event.client_payload.message }}"
|
|
290
|
+
|
|
291
|
+
echo "Alert received: $MESSAGE (Severity: $SEVERITY)"
|
|
292
|
+
|
|
293
|
+
if [[ "$SEVERITY" == "critical" ]]; then
|
|
294
|
+
# Trigger emergency procedures
|
|
295
|
+
echo "Initiating critical incident response"
|
|
296
|
+
fi
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**2. Manual Trigger from Dashboard**
|
|
300
|
+
|
|
301
|
+
Custom deployment dashboard that triggers GitHub Actions:
|
|
302
|
+
|
|
303
|
+
```yaml
|
|
304
|
+
on:
|
|
305
|
+
repository_dispatch:
|
|
306
|
+
types: [dashboard-deploy]
|
|
307
|
+
|
|
308
|
+
jobs:
|
|
309
|
+
deploy:
|
|
310
|
+
runs-on: ubuntu-latest
|
|
311
|
+
|
|
312
|
+
environment:
|
|
313
|
+
name: ${{ github.event.client_payload.environment }}
|
|
314
|
+
|
|
315
|
+
steps:
|
|
316
|
+
- name: Validate payload
|
|
317
|
+
run: |
|
|
318
|
+
# Validate required fields
|
|
319
|
+
if [[ -z "${{ github.event.client_payload.version }}" ]]; then
|
|
320
|
+
echo "Error: version is required"
|
|
321
|
+
exit 1
|
|
322
|
+
fi
|
|
323
|
+
|
|
324
|
+
if [[ -z "${{ github.event.client_payload.approver }}" ]]; then
|
|
325
|
+
echo "Error: approver is required"
|
|
326
|
+
exit 1
|
|
327
|
+
fi
|
|
328
|
+
|
|
329
|
+
- name: Deploy
|
|
330
|
+
run: |
|
|
331
|
+
echo "Deploying version ${{ github.event.client_payload.version }}"
|
|
332
|
+
echo "Approved by: ${{ github.event.client_payload.approver }}"
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**3. Cross-Repository Triggers**
|
|
336
|
+
|
|
337
|
+
Trigger workflow in repo A from repo B:
|
|
338
|
+
|
|
339
|
+
```yaml
|
|
340
|
+
# In Repository A
|
|
341
|
+
on:
|
|
342
|
+
repository_dispatch:
|
|
343
|
+
types: [dependency-updated]
|
|
344
|
+
|
|
345
|
+
jobs:
|
|
346
|
+
rebuild:
|
|
347
|
+
runs-on: ubuntu-latest
|
|
348
|
+
steps:
|
|
349
|
+
- name: Rebuild with new dependency
|
|
350
|
+
run: |
|
|
351
|
+
echo "Dependency ${{ github.event.client_payload.dependency }} updated to ${{ github.event.client_payload.version }}"
|
|
352
|
+
# Rebuild logic
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
#### Security Considerations
|
|
356
|
+
|
|
357
|
+
🔒 **Token Security:**
|
|
358
|
+
- Use a Personal Access Token (PAT) or GitHub App token
|
|
359
|
+
- Minimum required scope: `repo` (for private repos) or `public_repo` (for public repos)
|
|
360
|
+
- Store token in secrets, never in code
|
|
361
|
+
- Rotate tokens regularly
|
|
362
|
+
|
|
363
|
+
🔒 **Payload Validation:**
|
|
364
|
+
- Always validate `client_payload` fields
|
|
365
|
+
- Sanitize user input to prevent injection
|
|
366
|
+
- Use allowlists for critical fields
|
|
367
|
+
|
|
368
|
+
```yaml
|
|
369
|
+
- name: Validate environment
|
|
370
|
+
run: |
|
|
371
|
+
ENV="${{ github.event.client_payload.environment }}"
|
|
372
|
+
|
|
373
|
+
# Only allow specific environments
|
|
374
|
+
if [[ ! "$ENV" =~ ^(dev|staging|production)$ ]]; then
|
|
375
|
+
echo "Error: Invalid environment: $ENV"
|
|
376
|
+
exit 1
|
|
377
|
+
fi
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## ChatOps Patterns
|
|
383
|
+
|
|
384
|
+
### issue_comment Trigger
|
|
385
|
+
|
|
386
|
+
The `issue_comment` trigger allows you to implement ChatOps - executing workflows via commands in issue or PR comments.
|
|
387
|
+
|
|
388
|
+
#### Basic Syntax
|
|
389
|
+
|
|
390
|
+
```yaml
|
|
391
|
+
name: ChatOps Commands
|
|
392
|
+
|
|
393
|
+
on:
|
|
394
|
+
issue_comment:
|
|
395
|
+
types: [created, edited]
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
#### Comment Types
|
|
399
|
+
|
|
400
|
+
- `created` - New comment posted
|
|
401
|
+
- `edited` - Comment was edited
|
|
402
|
+
- `deleted` - Comment was deleted (rarely used)
|
|
403
|
+
|
|
404
|
+
#### Implementing ChatOps Commands
|
|
405
|
+
|
|
406
|
+
**Full ChatOps Example:**
|
|
407
|
+
|
|
408
|
+
```yaml
|
|
409
|
+
name: ChatOps - Deploy Command
|
|
410
|
+
|
|
411
|
+
on:
|
|
412
|
+
issue_comment:
|
|
413
|
+
types: [created]
|
|
414
|
+
|
|
415
|
+
jobs:
|
|
416
|
+
deploy:
|
|
417
|
+
# Security checks (CRITICAL!)
|
|
418
|
+
if: |
|
|
419
|
+
github.event.issue.pull_request &&
|
|
420
|
+
startsWith(github.event.comment.body, '/deploy') &&
|
|
421
|
+
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
|
|
422
|
+
|
|
423
|
+
runs-on: ubuntu-latest
|
|
424
|
+
|
|
425
|
+
permissions:
|
|
426
|
+
contents: read
|
|
427
|
+
pull-requests: write
|
|
428
|
+
deployments: write
|
|
429
|
+
|
|
430
|
+
steps:
|
|
431
|
+
# Step 1: React to comment to show command received
|
|
432
|
+
- name: Add reaction to comment
|
|
433
|
+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
|
434
|
+
with:
|
|
435
|
+
script: |
|
|
436
|
+
await github.rest.reactions.createForIssueComment({
|
|
437
|
+
owner: context.repo.owner,
|
|
438
|
+
repo: context.repo.repo,
|
|
439
|
+
comment_id: context.payload.comment.id,
|
|
440
|
+
content: 'rocket'
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
# Step 2: Parse command and arguments
|
|
444
|
+
- name: Parse deploy command
|
|
445
|
+
id: parse
|
|
446
|
+
run: |
|
|
447
|
+
COMMAND="${{ github.event.comment.body }}"
|
|
448
|
+
|
|
449
|
+
# Extract environment (default: staging)
|
|
450
|
+
ENV=$(echo "$COMMAND" | grep -oP '/deploy\s+\K\w+' || echo 'staging')
|
|
451
|
+
|
|
452
|
+
# Validate environment
|
|
453
|
+
if [[ ! "$ENV" =~ ^(dev|staging|production)$ ]]; then
|
|
454
|
+
echo "error=Invalid environment: $ENV" >> $GITHUB_OUTPUT
|
|
455
|
+
exit 1
|
|
456
|
+
fi
|
|
457
|
+
|
|
458
|
+
echo "environment=$ENV" >> $GITHUB_OUTPUT
|
|
459
|
+
echo "pr_number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT
|
|
460
|
+
|
|
461
|
+
# Step 3: Get PR details
|
|
462
|
+
- name: Get PR branch
|
|
463
|
+
id: pr
|
|
464
|
+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
|
465
|
+
with:
|
|
466
|
+
script: |
|
|
467
|
+
const pr = await github.rest.pulls.get({
|
|
468
|
+
owner: context.repo.owner,
|
|
469
|
+
repo: context.repo.repo,
|
|
470
|
+
pull_number: ${{ steps.parse.outputs.pr_number }}
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
core.setOutput('ref', pr.data.head.ref);
|
|
474
|
+
core.setOutput('sha', pr.data.head.sha);
|
|
475
|
+
core.setOutput('repo', pr.data.head.repo.full_name);
|
|
476
|
+
|
|
477
|
+
# Step 4: Checkout PR code
|
|
478
|
+
- name: Checkout PR code
|
|
479
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
480
|
+
with:
|
|
481
|
+
ref: ${{ steps.pr.outputs.ref }}
|
|
482
|
+
repository: ${{ steps.pr.outputs.repo }}
|
|
483
|
+
|
|
484
|
+
# Step 5: Deploy
|
|
485
|
+
- name: Deploy to environment
|
|
486
|
+
id: deploy
|
|
487
|
+
env:
|
|
488
|
+
ENVIRONMENT: ${{ steps.parse.outputs.environment }}
|
|
489
|
+
PR_SHA: ${{ steps.pr.outputs.sha }}
|
|
490
|
+
run: |
|
|
491
|
+
echo "Deploying PR #${{ steps.parse.outputs.pr_number }} to $ENVIRONMENT"
|
|
492
|
+
echo "SHA: $PR_SHA"
|
|
493
|
+
|
|
494
|
+
# Deployment logic here
|
|
495
|
+
DEPLOY_URL="https://$ENVIRONMENT.example.com"
|
|
496
|
+
echo "url=$DEPLOY_URL" >> $GITHUB_OUTPUT
|
|
497
|
+
|
|
498
|
+
# Step 6: Comment with results
|
|
499
|
+
- name: Comment deployment result
|
|
500
|
+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
|
501
|
+
with:
|
|
502
|
+
script: |
|
|
503
|
+
const environment = '${{ steps.parse.outputs.environment }}';
|
|
504
|
+
const url = '${{ steps.deploy.outputs.url }}';
|
|
505
|
+
|
|
506
|
+
await github.rest.issues.createComment({
|
|
507
|
+
owner: context.repo.owner,
|
|
508
|
+
repo: context.repo.repo,
|
|
509
|
+
issue_number: ${{ steps.parse.outputs.pr_number }},
|
|
510
|
+
body: `✅ Deployed to **${environment}**\n\n🔗 ${url}\n\nTriggered by: @${{ github.event.comment.user.login }}`
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
# Step 7: Handle failures
|
|
514
|
+
- name: Comment on failure
|
|
515
|
+
if: failure()
|
|
516
|
+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
|
517
|
+
with:
|
|
518
|
+
script: |
|
|
519
|
+
await github.rest.issues.createComment({
|
|
520
|
+
owner: context.repo.owner,
|
|
521
|
+
repo: context.repo.repo,
|
|
522
|
+
issue_number: ${{ github.event.issue.number }},
|
|
523
|
+
body: `❌ Deployment failed\n\nCheck the [workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.`
|
|
524
|
+
});
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
#### Common ChatOps Commands
|
|
528
|
+
|
|
529
|
+
**1. /deploy [environment]**
|
|
530
|
+
```yaml
|
|
531
|
+
startsWith(github.event.comment.body, '/deploy')
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
**2. /run-tests [suite]**
|
|
535
|
+
```yaml
|
|
536
|
+
startsWith(github.event.comment.body, '/run-tests')
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
**3. /benchmark**
|
|
540
|
+
```yaml
|
|
541
|
+
contains(github.event.comment.body, '/benchmark')
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
**4. /approve**
|
|
545
|
+
```yaml
|
|
546
|
+
github.event.comment.body == '/approve'
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
#### Permission Checking
|
|
550
|
+
|
|
551
|
+
**Author Association Levels:**
|
|
552
|
+
|
|
553
|
+
- `OWNER` - Repository owner
|
|
554
|
+
- `MEMBER` - Organization member
|
|
555
|
+
- `COLLABORATOR` - Repository collaborator
|
|
556
|
+
- `CONTRIBUTOR` - Has contributed to repo
|
|
557
|
+
- `FIRST_TIME_CONTRIBUTOR` - First contribution
|
|
558
|
+
- `FIRST_TIMER` - First time interacting
|
|
559
|
+
- `NONE` - No association
|
|
560
|
+
|
|
561
|
+
**Check permissions:**
|
|
562
|
+
|
|
563
|
+
```yaml
|
|
564
|
+
# Only owners and members
|
|
565
|
+
if: contains(fromJSON('["OWNER", "MEMBER"]'), github.event.comment.author_association)
|
|
566
|
+
|
|
567
|
+
# More permissive
|
|
568
|
+
if: contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR", "CONTRIBUTOR"]'), github.event.comment.author_association)
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
**Advanced permission check with team membership:**
|
|
572
|
+
|
|
573
|
+
```yaml
|
|
574
|
+
steps:
|
|
575
|
+
- name: Check team membership
|
|
576
|
+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
|
577
|
+
with:
|
|
578
|
+
script: |
|
|
579
|
+
const teams = ['deployment-team', 'admin-team'];
|
|
580
|
+
const user = context.payload.comment.user.login;
|
|
581
|
+
|
|
582
|
+
let authorized = false;
|
|
583
|
+
for (const team of teams) {
|
|
584
|
+
try {
|
|
585
|
+
await github.rest.teams.getMembershipForUserInOrg({
|
|
586
|
+
org: context.repo.owner,
|
|
587
|
+
team_slug: team,
|
|
588
|
+
username: user
|
|
589
|
+
});
|
|
590
|
+
authorized = true;
|
|
591
|
+
break;
|
|
592
|
+
} catch (error) {
|
|
593
|
+
// User not in this team
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (!authorized) {
|
|
598
|
+
core.setFailed(`User ${user} not authorized`);
|
|
599
|
+
}
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
#### Security Best Practices for ChatOps
|
|
603
|
+
|
|
604
|
+
🔒 **Always validate:**
|
|
605
|
+
1. Command is from a PR: `github.event.issue.pull_request`
|
|
606
|
+
2. User has permissions: `github.event.comment.author_association`
|
|
607
|
+
3. Command format is valid
|
|
608
|
+
4. Arguments are sanitized
|
|
609
|
+
|
|
610
|
+
🔒 **Never:**
|
|
611
|
+
- Execute arbitrary code from comments
|
|
612
|
+
- Use comment content in shell commands without validation
|
|
613
|
+
- Trust external PR authors for sensitive operations
|
|
614
|
+
|
|
615
|
+
🔒 **Use environment variables:**
|
|
616
|
+
|
|
617
|
+
```yaml
|
|
618
|
+
# BAD - Command injection risk
|
|
619
|
+
- run: echo ${{ github.event.comment.body }}
|
|
620
|
+
|
|
621
|
+
# GOOD - Safe
|
|
622
|
+
- env:
|
|
623
|
+
COMMENT: ${{ github.event.comment.body }}
|
|
624
|
+
run: echo "$COMMENT"
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
---
|
|
628
|
+
|
|
629
|
+
## Deployment Triggers
|
|
630
|
+
|
|
631
|
+
### deployment and deployment_status
|
|
632
|
+
|
|
633
|
+
These triggers integrate with GitHub's deployment API.
|
|
634
|
+
|
|
635
|
+
#### deployment Trigger
|
|
636
|
+
|
|
637
|
+
```yaml
|
|
638
|
+
name: Handle Deployment
|
|
639
|
+
|
|
640
|
+
on:
|
|
641
|
+
deployment:
|
|
642
|
+
|
|
643
|
+
jobs:
|
|
644
|
+
deploy:
|
|
645
|
+
runs-on: ubuntu-latest
|
|
646
|
+
|
|
647
|
+
steps:
|
|
648
|
+
- name: Get deployment info
|
|
649
|
+
run: |
|
|
650
|
+
echo "Environment: ${{ github.event.deployment.environment }}"
|
|
651
|
+
echo "Ref: ${{ github.event.deployment.ref }}"
|
|
652
|
+
echo "Task: ${{ github.event.deployment.task }}"
|
|
653
|
+
echo "Payload: ${{ toJSON(github.event.deployment.payload) }}"
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
#### deployment_status Trigger
|
|
657
|
+
|
|
658
|
+
```yaml
|
|
659
|
+
name: Post-Deployment Actions
|
|
660
|
+
|
|
661
|
+
on:
|
|
662
|
+
deployment_status:
|
|
663
|
+
|
|
664
|
+
jobs:
|
|
665
|
+
notify:
|
|
666
|
+
if: github.event.deployment_status.state == 'success'
|
|
667
|
+
runs-on: ubuntu-latest
|
|
668
|
+
|
|
669
|
+
steps:
|
|
670
|
+
- name: Send notification
|
|
671
|
+
run: |
|
|
672
|
+
echo "Deployment to ${{ github.event.deployment.environment }} succeeded"
|
|
673
|
+
# Send Slack/email notification
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
---
|
|
677
|
+
|
|
678
|
+
## Advanced Path Filtering
|
|
679
|
+
|
|
680
|
+
### Complex Path Patterns
|
|
681
|
+
|
|
682
|
+
```yaml
|
|
683
|
+
on:
|
|
684
|
+
push:
|
|
685
|
+
paths:
|
|
686
|
+
# Include specific paths
|
|
687
|
+
- 'src/**'
|
|
688
|
+
- 'lib/**/*.js'
|
|
689
|
+
|
|
690
|
+
# Exclude paths (ignore)
|
|
691
|
+
- '!src/**/*.md'
|
|
692
|
+
- '!src/**/*.test.js'
|
|
693
|
+
- '!**/__tests__/**'
|
|
694
|
+
|
|
695
|
+
# Only specific file types
|
|
696
|
+
- '**.py'
|
|
697
|
+
- '**.yaml'
|
|
698
|
+
- '**.yml'
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
### Path Filters with Multiple Triggers
|
|
702
|
+
|
|
703
|
+
```yaml
|
|
704
|
+
on:
|
|
705
|
+
pull_request:
|
|
706
|
+
paths:
|
|
707
|
+
- 'backend/**'
|
|
708
|
+
push:
|
|
709
|
+
branches: [main]
|
|
710
|
+
paths:
|
|
711
|
+
- 'backend/**'
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
### Monorepo Path Filtering
|
|
715
|
+
|
|
716
|
+
```yaml
|
|
717
|
+
on:
|
|
718
|
+
pull_request:
|
|
719
|
+
paths:
|
|
720
|
+
- 'packages/frontend/**'
|
|
721
|
+
- 'packages/shared/**'
|
|
722
|
+
- '!packages/**/README.md'
|
|
723
|
+
- '!packages/**/*.test.*'
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
---
|
|
727
|
+
|
|
728
|
+
## Security Patterns
|
|
729
|
+
|
|
730
|
+
### pull_request vs pull_request_target
|
|
731
|
+
|
|
732
|
+
| Trigger | Context | Secrets | Use Case | Risk Level |
|
|
733
|
+
|---------|---------|---------|----------|------------|
|
|
734
|
+
| `pull_request` | PR branch | ❌ No access | Standard PR validation | ✅ Safe |
|
|
735
|
+
| `pull_request_target` | Target branch | ✅ Full access | Write to PR from fork | ⚠️ High risk |
|
|
736
|
+
| `workflow_run` | Target branch | ✅ Full access | Post-CI for external PRs | ✅ Safe (if used correctly) |
|
|
737
|
+
|
|
738
|
+
### Safe Patterns
|
|
739
|
+
|
|
740
|
+
**✅ Standard PR validation:**
|
|
741
|
+
|
|
742
|
+
```yaml
|
|
743
|
+
on:
|
|
744
|
+
pull_request:
|
|
745
|
+
branches: [main]
|
|
746
|
+
|
|
747
|
+
# Safe: No secrets exposed, runs PR code in isolation
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
**✅ Post-CI processing with workflow_run:**
|
|
751
|
+
|
|
752
|
+
```yaml
|
|
753
|
+
on:
|
|
754
|
+
workflow_run:
|
|
755
|
+
workflows: ["CI"]
|
|
756
|
+
types: [completed]
|
|
757
|
+
|
|
758
|
+
# Safe: Runs after CI, has secrets, but uses target branch code
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
**⚠️ Dangerous: pull_request_target**
|
|
762
|
+
|
|
763
|
+
```yaml
|
|
764
|
+
on:
|
|
765
|
+
pull_request_target:
|
|
766
|
+
branches: [main]
|
|
767
|
+
|
|
768
|
+
# DANGEROUS: External PRs can access secrets!
|
|
769
|
+
# Only use if you explicitly checkout target branch code
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
### Securing pull_request_target
|
|
773
|
+
|
|
774
|
+
If you must use `pull_request_target`:
|
|
775
|
+
|
|
776
|
+
```yaml
|
|
777
|
+
on:
|
|
778
|
+
pull_request_target:
|
|
779
|
+
|
|
780
|
+
jobs:
|
|
781
|
+
comment:
|
|
782
|
+
runs-on: ubuntu-latest
|
|
783
|
+
|
|
784
|
+
steps:
|
|
785
|
+
# SAFE: Don't checkout PR code
|
|
786
|
+
- name: Comment on PR
|
|
787
|
+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
|
788
|
+
with:
|
|
789
|
+
script: |
|
|
790
|
+
await github.rest.issues.createComment({
|
|
791
|
+
issue_number: context.issue.number,
|
|
792
|
+
owner: context.repo.owner,
|
|
793
|
+
repo: context.repo.repo,
|
|
794
|
+
body: 'Thanks for your contribution!'
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
# UNSAFE: Never do this!
|
|
798
|
+
# - uses: actions/checkout@v4
|
|
799
|
+
# with:
|
|
800
|
+
# ref: ${{ github.event.pull_request.head.sha }}
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
---
|
|
804
|
+
|
|
805
|
+
## GitHub Services Integration
|
|
806
|
+
|
|
807
|
+
### check_run and check_suite
|
|
808
|
+
|
|
809
|
+
```yaml
|
|
810
|
+
on:
|
|
811
|
+
check_run:
|
|
812
|
+
types: [created, rerequested, completed]
|
|
813
|
+
|
|
814
|
+
on:
|
|
815
|
+
check_suite:
|
|
816
|
+
types: [completed, requested]
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
### status
|
|
820
|
+
|
|
821
|
+
```yaml
|
|
822
|
+
on:
|
|
823
|
+
status:
|
|
824
|
+
|
|
825
|
+
jobs:
|
|
826
|
+
handle-status:
|
|
827
|
+
runs-on: ubuntu-latest
|
|
828
|
+
steps:
|
|
829
|
+
- name: Check status
|
|
830
|
+
run: |
|
|
831
|
+
echo "State: ${{ github.event.state }}"
|
|
832
|
+
echo "Context: ${{ github.event.context }}"
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
### package
|
|
836
|
+
|
|
837
|
+
```yaml
|
|
838
|
+
on:
|
|
839
|
+
package:
|
|
840
|
+
types: [published, updated]
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
---
|
|
844
|
+
|
|
845
|
+
## Best Practices
|
|
846
|
+
|
|
847
|
+
### 1. Choose the Right Trigger
|
|
848
|
+
|
|
849
|
+
| Scenario | Recommended Trigger |
|
|
850
|
+
|----------|-------------------|
|
|
851
|
+
| Standard PR validation | `pull_request` |
|
|
852
|
+
| External PR with secrets | `workflow_run` after `pull_request` |
|
|
853
|
+
| Deploy after CI | `workflow_run` |
|
|
854
|
+
| Manual dashboard trigger | `repository_dispatch` |
|
|
855
|
+
| ChatOps commands | `issue_comment` |
|
|
856
|
+
| Scheduled cleanup | `schedule` |
|
|
857
|
+
| External webhook | `repository_dispatch` |
|
|
858
|
+
|
|
859
|
+
### 2. Security Checklist
|
|
860
|
+
|
|
861
|
+
- [ ] Validate user permissions
|
|
862
|
+
- [ ] Sanitize all inputs
|
|
863
|
+
- [ ] Use environment variables, not direct interpolation
|
|
864
|
+
- [ ] Never trust external PR code with secrets
|
|
865
|
+
- [ ] Use `workflow_run` instead of `pull_request_target` when possible
|
|
866
|
+
- [ ] Implement allowlists for critical operations
|
|
867
|
+
- [ ] Log all security-sensitive actions
|
|
868
|
+
|
|
869
|
+
### 3. Performance Optimization
|
|
870
|
+
|
|
871
|
+
- Use `workflow_run` to separate slow jobs from fast CI
|
|
872
|
+
- Filter triggers with `paths` to avoid unnecessary runs
|
|
873
|
+
- Use `concurrency` to cancel outdated runs
|
|
874
|
+
- Implement conditional job execution
|
|
875
|
+
|
|
876
|
+
### 4. Debugging
|
|
877
|
+
|
|
878
|
+
**Check trigger details:**
|
|
879
|
+
|
|
880
|
+
```yaml
|
|
881
|
+
- name: Debug trigger info
|
|
882
|
+
run: |
|
|
883
|
+
echo "Event name: ${{ github.event_name }}"
|
|
884
|
+
echo "Event: ${{ toJSON(github.event) }}"
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
**Test repository_dispatch locally:**
|
|
888
|
+
|
|
889
|
+
```bash
|
|
890
|
+
# Set token
|
|
891
|
+
export GITHUB_TOKEN="your_token"
|
|
892
|
+
|
|
893
|
+
# Trigger workflow
|
|
894
|
+
curl -X POST \
|
|
895
|
+
-H "Authorization: token $GITHUB_TOKEN" \
|
|
896
|
+
-H "Accept: application/vnd.github.v3+json" \
|
|
897
|
+
https://api.github.com/repos/OWNER/REPO/dispatches \
|
|
898
|
+
-d '{"event_type":"test","client_payload":{"debug":true}}'
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
---
|
|
902
|
+
|
|
903
|
+
## Example Workflows
|
|
904
|
+
|
|
905
|
+
See the `examples/triggers/` directory for complete working examples:
|
|
906
|
+
|
|
907
|
+
- `workflow-orchestration.yml` - CI → Deploy workflow chaining
|
|
908
|
+
- `repository-dispatch.yml` - External API triggers
|
|
909
|
+
- `chatops-commands.yml` - Full ChatOps implementation
|
|
910
|
+
|
|
911
|
+
---
|
|
912
|
+
|
|
913
|
+
## Resources
|
|
914
|
+
|
|
915
|
+
- [GitHub Actions Events Documentation](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows)
|
|
916
|
+
- [Security Hardening for GitHub Actions](https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions)
|
|
917
|
+
- [GitHub API - Repository Dispatch](https://docs.github.com/en/rest/repos/repos#create-a-repository-dispatch-event)
|