opencode-skills-collection 3.0.31 → 3.0.33

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.
Files changed (51) hide show
  1. package/bundled-skills/.antigravity-install-manifest.json +14 -1
  2. package/bundled-skills/bilig-workpaper/SKILL.md +12 -3
  3. package/bundled-skills/bumblebee/SKILL.md +6 -2
  4. package/bundled-skills/bun-development/SKILL.md +5 -3
  5. package/bundled-skills/cloud-penetration-testing/SKILL.md +5 -3
  6. package/bundled-skills/container-security-hardening/SKILL.md +1001 -0
  7. package/bundled-skills/container-security-hardening/references/base-image-comparison.md +245 -0
  8. package/bundled-skills/container-security-hardening/references/kubernetes-pod-security.md +567 -0
  9. package/bundled-skills/container-security-hardening/references/seccomp-profile-template.json +337 -0
  10. package/bundled-skills/doc2math/SKILL.md +102 -0
  11. package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
  12. package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
  13. package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
  14. package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
  15. package/bundled-skills/docs/users/bundles.md +1 -1
  16. package/bundled-skills/docs/users/claude-code-skills.md +1 -1
  17. package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
  18. package/bundled-skills/docs/users/getting-started.md +6 -2
  19. package/bundled-skills/docs/users/kiro-integration.md +1 -1
  20. package/bundled-skills/docs/users/usage.md +4 -4
  21. package/bundled-skills/docs/users/visual-guide.md +4 -4
  22. package/bundled-skills/environment-setup-guide/SKILL.md +10 -6
  23. package/bundled-skills/evolution/SKILL.md +5 -3
  24. package/bundled-skills/github-actions-advanced/SKILL.md +1100 -0
  25. package/bundled-skills/gitops-workflow/SKILL.md +5 -3
  26. package/bundled-skills/ii-commons/SKILL.md +15 -1
  27. package/bundled-skills/lemmaly/SKILL.md +15 -6
  28. package/bundled-skills/linkerd-patterns/SKILL.md +5 -3
  29. package/bundled-skills/longbridge/SKILL.md +95 -0
  30. package/bundled-skills/mercury-mcp/SKILL.md +9 -1
  31. package/bundled-skills/moatmri/SKILL.md +84 -0
  32. package/bundled-skills/nextjs-seo-indexing/SKILL.md +263 -0
  33. package/bundled-skills/openclaw-github-repo-commander/scripts/repo-audit.sh +42 -0
  34. package/bundled-skills/photopea-embedded-editor/SKILL.md +7 -3
  35. package/bundled-skills/runaway-guard/SKILL.md +331 -0
  36. package/bundled-skills/schema-markup-generator/SKILL.md +319 -0
  37. package/bundled-skills/sendblue/sendblue-api/SKILL.md +6 -1
  38. package/bundled-skills/sendblue/sendblue-cli/SKILL.md +6 -1
  39. package/bundled-skills/sendblue/sendblue-notify/SKILL.md +6 -1
  40. package/bundled-skills/sendblue/textme/SKILL.md +4 -0
  41. package/bundled-skills/social-metadata-hardening/SKILL.md +230 -0
  42. package/bundled-skills/socialclaw/SKILL.md +6 -1
  43. package/bundled-skills/uv-package-manager/resources/implementation-playbook.md +5 -3
  44. package/bundled-skills/varlock/SKILL.md +10 -6
  45. package/bundled-skills/vibe-code-cleanup/SKILL.md +231 -0
  46. package/bundled-skills/vibecode-production-qa-validator/SKILL.md +237 -0
  47. package/bundled-skills/wordpress-centric-high-seo-optimized-blogwriting-skill/SKILL.md +229 -162
  48. package/bundled-skills/yield-intelligence/SKILL.md +121 -0
  49. package/bundled-skills/youtube-full/SKILL.md +144 -0
  50. package/package.json +1 -1
  51. package/skills_index.json +330 -28
@@ -0,0 +1,1100 @@
1
+ ---
2
+ name: github-actions-advanced
3
+ description: >
4
+ Design, debug, and harden GitHub Actions CI/CD workflows, including reusable
5
+ workflows, matrix builds, self-hosted runners, OIDC authentication, caching,
6
+ environments, secrets, and release automation.
7
+ category: devops
8
+ risk: safe
9
+ source: community
10
+ date_added: "2026-05-30"
11
+ ---
12
+
13
+ # GitHub Actions Advanced Skill
14
+
15
+ Expert guidance for designing, writing, debugging, and securing **production-grade** GitHub Actions workflows.
16
+
17
+ ---
18
+
19
+ ## When to Use This Skill
20
+
21
+ - User mentions GitHub Actions, `.github/workflows`, CI/CD pipelines, runners, jobs, steps, or actions
22
+ - User wants to automate builds, tests, deployments, or releases via GitHub
23
+ - User asks about matrix builds, reusable workflows, composite actions, or self-hosted runners
24
+ - User needs help with OIDC authentication, caching strategies, or secrets management
25
+ - User says "my GitHub pipeline is failing" or "set up CI for my repo"
26
+ - User asks about workflow security, hardening, or environment protection rules
27
+
28
+ ## When NOT to Use This Skill
29
+
30
+ - The user is working with GitLab CI/CD → recommend `gitlab-ci-patterns`
31
+ - The user is working with CircleCI, Jenkins, or other CI platforms
32
+ - The task is purely about Docker image building without GitHub context → recommend `docker-expert`
33
+ - The task is about Kubernetes deployment configuration → recommend `kubernetes-architect`
34
+
35
+ ---
36
+
37
+ ## Step 1: Understand Context Before Responding
38
+
39
+ When invoked, first gather context:
40
+
41
+ ```bash
42
+ # Discover existing workflows in the repo
43
+ find .github/workflows -name "*.yml" -o -name "*.yaml" 2>/dev/null | head -20
44
+
45
+ # Check for composite actions
46
+ find .github/actions -name "action.yml" 2>/dev/null
47
+
48
+ # Detect tech stack (influences runner OS, language setup actions)
49
+ ls package.json requirements.txt Gemfile go.mod Cargo.toml pom.xml 2>/dev/null
50
+ ```
51
+
52
+ Then adapt recommendations to:
53
+ - Existing workflow patterns in the repo
54
+ - The tech stack and language runtime
55
+ - Whether this is a monorepo or single-project repo
56
+ - Whether self-hosted or GitHub-hosted runners are in use
57
+
58
+ ---
59
+
60
+ ## Workflow Structure Reference
61
+
62
+ ```yaml
63
+ name: Workflow Name
64
+
65
+ on: # Triggers (see Triggers section)
66
+ push:
67
+ branches: [main]
68
+
69
+ permissions: # Always declare — principle of least privilege
70
+ contents: read
71
+
72
+ env: # Workflow-level env vars
73
+ NODE_VERSION: '20'
74
+
75
+ concurrency: # Prevent duplicate runs
76
+ group: ${{ github.workflow }}-${{ github.ref }}
77
+ cancel-in-progress: true # Cancel older runs for same branch
78
+
79
+ jobs:
80
+ job-id:
81
+ name: Human-readable name
82
+ runs-on: ubuntu-24.04 # Pin OS version — never use -latest in prod
83
+ timeout-minutes: 15 # Always set — prevents runaway jobs
84
+ environment: production # Links to GitHub Environment (approvals/secrets)
85
+
86
+ steps:
87
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
88
+ - name: Step name
89
+ run: echo "hello"
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Triggers (`on:`)
95
+
96
+ ### Common Patterns
97
+
98
+ ```yaml
99
+ on:
100
+ push:
101
+ branches: [main, 'release/**']
102
+ paths-ignore: ['**.md', 'docs/**'] # Skip docs-only changes
103
+
104
+ pull_request:
105
+ types: [opened, synchronize, reopened]
106
+ branches: [main]
107
+
108
+ workflow_dispatch: # Manual trigger with inputs
109
+ inputs:
110
+ environment:
111
+ description: 'Deploy target'
112
+ required: true
113
+ type: choice
114
+ options: [staging, production]
115
+ dry-run:
116
+ description: 'Dry run only?'
117
+ type: boolean
118
+ default: false
119
+
120
+ schedule:
121
+ - cron: '0 2 * * 1' # Monday 2am UTC
122
+
123
+ workflow_call: # Called by other workflows (reusable)
124
+ inputs:
125
+ image-tag:
126
+ type: string
127
+ required: true
128
+ secrets:
129
+ deploy-token:
130
+ required: true
131
+
132
+ release:
133
+ types: [published] # Trigger only on published releases
134
+
135
+ pull_request_target: # Runs with repo secrets — use with care!
136
+ types: [labeled] # Gate with label + author_association check
137
+ ```
138
+
139
+ > **Security Warning:** `pull_request_target` runs with repo secrets. Only use after a maintainer labels the PR. Never check out fork code without explicit sandboxing.
140
+
141
+ ---
142
+
143
+ ## Reusable Workflows
144
+
145
+ Split large pipelines into composable units stored in `.github/workflows/`.
146
+
147
+ **Convention:** Prefix internal/reusable workflows with `_` (e.g., `_build.yml`).
148
+
149
+ ### Caller (`.github/workflows/deploy.yml`)
150
+
151
+ ```yaml
152
+ jobs:
153
+ call-build:
154
+ uses: ./.github/workflows/_build.yml # Same-repo reusable
155
+ # uses: org/repo/.github/workflows/build.yml@main # Cross-repo
156
+ with:
157
+ image-tag: ${{ github.sha }}
158
+ secrets: inherit # Pass all caller secrets down
159
+
160
+ call-test:
161
+ uses: ./.github/workflows/_test.yml
162
+ with:
163
+ node-version: '20'
164
+ secrets:
165
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # Explicit secret passing
166
+ ```
167
+
168
+ ### Reusable Workflow (`.github/workflows/_build.yml`)
169
+
170
+ ```yaml
171
+ on:
172
+ workflow_call:
173
+ inputs:
174
+ image-tag:
175
+ type: string
176
+ required: true
177
+ push:
178
+ type: boolean
179
+ default: false
180
+ secrets:
181
+ registry-token:
182
+ required: false
183
+ outputs:
184
+ digest:
185
+ description: "Image digest"
186
+ value: ${{ jobs.build.outputs.digest }}
187
+
188
+ jobs:
189
+ build:
190
+ runs-on: ubuntu-24.04
191
+ timeout-minutes: 20
192
+ outputs:
193
+ digest: ${{ steps.build.outputs.digest }}
194
+ steps:
195
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
196
+ - id: build
197
+ uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
198
+ with:
199
+ push: ${{ inputs.push }}
200
+ tags: myapp:${{ inputs.image-tag }}
201
+ ```
202
+
203
+ ---
204
+
205
+ ## Matrix Builds
206
+
207
+ ```yaml
208
+ jobs:
209
+ test:
210
+ strategy:
211
+ fail-fast: false # Don't cancel others if one fails
212
+ max-parallel: 4 # Limit concurrent runners
213
+ matrix:
214
+ os: [ubuntu-24.04, windows-2022, macos-14]
215
+ node: ['18', '20', '22']
216
+ exclude:
217
+ - os: windows-2022
218
+ node: '18'
219
+ include:
220
+ - os: ubuntu-24.04
221
+ node: '22'
222
+ experimental: true # Custom matrix variable
223
+
224
+ runs-on: ${{ matrix.os }}
225
+ timeout-minutes: 20
226
+
227
+ steps:
228
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
229
+ - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
230
+ with:
231
+ node-version: ${{ matrix.node }}
232
+ cache: 'npm'
233
+ - run: npm ci
234
+ - run: npm test
235
+ continue-on-error: ${{ matrix.experimental == true }}
236
+ ```
237
+
238
+ ### Dynamic Matrix via Script
239
+
240
+ ```yaml
241
+ jobs:
242
+ generate-matrix:
243
+ runs-on: ubuntu-24.04
244
+ outputs:
245
+ matrix: ${{ steps.set-matrix.outputs.matrix }}
246
+ steps:
247
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
248
+ - id: set-matrix
249
+ run: |
250
+ SERVICES=$(find services -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | jq -R -s -c 'split("\n")[:-1]')
251
+ printf 'matrix={"service":%s}\n' "$SERVICES" >> "$GITHUB_OUTPUT"
252
+
253
+ build:
254
+ needs: generate-matrix
255
+ strategy:
256
+ matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
257
+ runs-on: ubuntu-24.04
258
+ steps:
259
+ - env:
260
+ SERVICE: ${{ matrix.service }}
261
+ run: echo "Building $SERVICE"
262
+ ```
263
+
264
+ ---
265
+
266
+ ## Caching Strategies
267
+
268
+ ### Language Setup Actions (Preferred — No Extra Step Needed)
269
+
270
+ ```yaml
271
+ # Node.js
272
+ - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
273
+ with:
274
+ node-version: '20'
275
+ cache: 'npm' # or 'yarn' or 'pnpm'
276
+
277
+ # Python
278
+ - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
279
+ with:
280
+ python-version: '3.12'
281
+ cache: 'pip'
282
+
283
+ # Go
284
+ - uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
285
+ with:
286
+ go-version: '1.23'
287
+ cache: true
288
+
289
+ # Java / Gradle / Maven
290
+ - uses: actions/setup-java@7a6d8a8234af8eb26422e24052f73b12b0e46a27 # v4.6.0
291
+ with:
292
+ distribution: 'temurin'
293
+ java-version: '21'
294
+ cache: 'maven' # or 'gradle'
295
+ ```
296
+
297
+ ### Manual Cache (Any Tool)
298
+
299
+ ```yaml
300
+ - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2
301
+ id: cache-deps
302
+ with:
303
+ path: |
304
+ ~/.cache/pip
305
+ .venv
306
+ key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
307
+ restore-keys: |
308
+ ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
309
+ ${{ runner.os }}-pip-
310
+
311
+ - name: Install deps (only on cache miss)
312
+ if: steps.cache-deps.outputs.cache-hit != 'true'
313
+ run: pip install -r requirements.txt
314
+ ```
315
+
316
+ ### Docker Layer Caching
317
+
318
+ ```yaml
319
+ - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
320
+ with:
321
+ cache-from: type=gha
322
+ cache-to: type=gha,mode=max
323
+ # For registry-backed cache (cross-branch):
324
+ # cache-from: type=registry,ref=ghcr.io/myorg/myapp:buildcache
325
+ # cache-to: type=registry,ref=ghcr.io/myorg/myapp:buildcache,mode=max
326
+ ```
327
+
328
+ ---
329
+
330
+ ## OIDC Authentication (Keyless Cloud Auth)
331
+
332
+ **Never store long-lived cloud credentials as secrets.** Use OIDC to get short-lived tokens that expire automatically.
333
+
334
+ ### AWS
335
+
336
+ ```yaml
337
+ permissions:
338
+ id-token: write
339
+ contents: read
340
+
341
+ steps:
342
+ - uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
343
+ with:
344
+ role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
345
+ aws-region: us-east-1
346
+ role-session-name: GitHubActions-${{ github.run_id }}
347
+
348
+ # Trust policy on the IAM role must include:
349
+ # "token.actions.githubusercontent.com" as OIDC provider
350
+ # Condition: "repo:org/repo:ref:refs/heads/main" (restrict to branch)
351
+ ```
352
+
353
+ ### GCP (Workload Identity Federation)
354
+
355
+ ```yaml
356
+ permissions:
357
+ id-token: write
358
+ contents: read
359
+
360
+ steps:
361
+ - uses: google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f # v2.1.7
362
+ with:
363
+ workload_identity_provider: projects/123456789/locations/global/workloadIdentityPools/github-pool/providers/github-provider
364
+ service_account: github-actions@my-project.iam.gserviceaccount.com
365
+ token_format: access_token # or 'id_token'
366
+ ```
367
+
368
+ ### Azure (Federated Identity)
369
+
370
+ ```yaml
371
+ permissions:
372
+ id-token: write
373
+ contents: read
374
+
375
+ steps:
376
+ - uses: azure/login@a65d910e8af852a8061c627c456678983e180302 # v2.2.0
377
+ with:
378
+ client-id: ${{ secrets.AZURE_CLIENT_ID }}
379
+ tenant-id: ${{ secrets.AZURE_TENANT_ID }}
380
+ subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
381
+ # No client secret needed! Uses OIDC federated credentials
382
+ ```
383
+
384
+ ---
385
+
386
+ ## Environments & Deployment Protection
387
+
388
+ ```yaml
389
+ jobs:
390
+ deploy-staging:
391
+ environment:
392
+ name: staging
393
+ url: https://staging.myapp.com
394
+ runs-on: ubuntu-24.04
395
+ timeout-minutes: 30
396
+ steps:
397
+ - run: ./scripts/deploy.sh staging
398
+
399
+ deploy-production:
400
+ needs: deploy-staging
401
+ environment:
402
+ name: production
403
+ url: https://myapp.com # Shown in the GitHub UI deployment panel
404
+ runs-on: ubuntu-24.04
405
+ timeout-minutes: 30
406
+ steps:
407
+ - run: ./scripts/deploy.sh production
408
+ ```
409
+
410
+ **Configure in Settings → Environments:**
411
+ - **Required reviewers** — manual approval gate before run
412
+ - **Wait timer** — delay after approval (e.g., 10-minute buffer)
413
+ - **Branch/tag restrictions** — only `main` or `v*` tags can deploy to prod
414
+ - **Environment-specific secrets** — override repo-level secrets per environment
415
+ - **Deployment branches** — whitelist which branches can target this environment
416
+
417
+ ---
418
+
419
+ ## Secrets Management
420
+
421
+ ```yaml
422
+ # Access repo/org/environment secrets
423
+ env:
424
+ DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
425
+
426
+ # Auto-provided token — no setup needed
427
+ - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
428
+ with:
429
+ github-token: ${{ secrets.GITHUB_TOKEN }}
430
+
431
+ # Hierarchy (most specific wins):
432
+ # environment secret > repo secret > org secret
433
+ ```
434
+
435
+ ### Masking Dynamic Values
436
+
437
+ ```yaml
438
+ - name: Generate and mask dynamic token
439
+ run: |
440
+ TOKEN=$(./scripts/generate-token.sh)
441
+ echo "::add-mask::$TOKEN" # Mask in all subsequent logs
442
+ echo "DEPLOY_TOKEN=$TOKEN" >> $GITHUB_ENV
443
+ ```
444
+
445
+ ### Secrets in Composite Actions
446
+
447
+ ```yaml
448
+ # Secrets cannot be passed as inputs to composite actions
449
+ # Pass them as env vars instead:
450
+ - uses: ./.github/actions/my-action
451
+ env:
452
+ SECRET_VALUE: ${{ secrets.MY_SECRET }}
453
+ ```
454
+
455
+ ---
456
+
457
+ ## Composite Actions
458
+
459
+ Package reusable step sequences into local actions. No container spin-up, no separate workflow file needed.
460
+
461
+ ### Action Definition (`.github/actions/setup-app/action.yml`)
462
+
463
+ ```yaml
464
+ name: Setup App
465
+ description: Install and configure application dependencies
466
+
467
+ inputs:
468
+ node-version:
469
+ description: 'Node.js version'
470
+ required: false
471
+ default: '20'
472
+ install-flags:
473
+ description: 'Additional npm install flags'
474
+ required: false
475
+ default: ''
476
+
477
+ outputs:
478
+ cache-hit:
479
+ description: 'Whether the dependency cache was hit'
480
+ value: ${{ steps.cache.outputs.cache-hit }}
481
+
482
+ runs:
483
+ using: composite
484
+ steps:
485
+ - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
486
+ with:
487
+ node-version: ${{ inputs.node-version }}
488
+ cache: npm
489
+
490
+ - id: cache
491
+ uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2
492
+ with:
493
+ path: node_modules
494
+ key: ${{ runner.os }}-node-${{ inputs.node-version }}-${{ hashFiles('package-lock.json') }}
495
+
496
+ - name: Install dependencies
497
+ if: steps.cache.outputs.cache-hit != 'true'
498
+ shell: bash
499
+ env:
500
+ INSTALL_FLAGS: ${{ inputs.install-flags }}
501
+ run: |
502
+ args=()
503
+ case "$INSTALL_FLAGS" in
504
+ "") ;;
505
+ "--ignore-scripts") args+=(--ignore-scripts) ;;
506
+ *) echo "Unsupported install flags" >&2; exit 1 ;;
507
+ esac
508
+ npm ci "${args[@]}"
509
+
510
+ - name: Build
511
+ shell: bash
512
+ run: npm run build
513
+ ```
514
+
515
+ ### Usage in a Workflow
516
+
517
+ ```yaml
518
+ steps:
519
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
520
+ - uses: ./.github/actions/setup-app
521
+ with:
522
+ node-version: '22'
523
+ install-flags: '--ignore-scripts'
524
+ ```
525
+
526
+ ---
527
+
528
+ ## Self-Hosted Runners
529
+
530
+ ```yaml
531
+ jobs:
532
+ build-gpu:
533
+ runs-on: [self-hosted, linux, x64, gpu] # Label matching
534
+ timeout-minutes: 60
535
+
536
+ build-arm:
537
+ runs-on: [self-hosted, linux, arm64]
538
+ ```
539
+
540
+ ### Runner Best Practices
541
+
542
+ | Practice | Details |
543
+ |---|---|
544
+ | **Ephemeral runners** | Use Actions Runner Controller (ARC) on Kubernetes for fresh runners per job |
545
+ | **Isolation** | Never share prod runners with untrusted/fork PR workflows |
546
+ | **Cleanup hooks** | Set `ACTIONS_RUNNER_HOOK_JOB_COMPLETED` to reset environment |
547
+ | **Runner groups** | Use groups to restrict which repos/workflows can access which runners |
548
+ | **Labels** | Use custom labels (e.g., `gpu`, `high-memory`) for precise targeting |
549
+ | **Security** | Disable fork PR access to self-hosted runners in Settings |
550
+
551
+ ```bash
552
+ # Actions Runner Controller (Kubernetes) — recommended for ephemeral runners
553
+ helm install arc \
554
+ --namespace arc-systems \
555
+ --create-namespace \
556
+ oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller
557
+ ```
558
+
559
+ ---
560
+
561
+ ## Conditional Execution & Flow Control
562
+
563
+ ```yaml
564
+ # Condition on branch + event
565
+ - run: ./scripts/deploy.sh
566
+ if: github.ref == 'refs/heads/main' && github.event_name == 'push'
567
+
568
+ # Continue on error (non-blocking steps)
569
+ - run: ./scripts/lint.sh
570
+ continue-on-error: true
571
+
572
+ # Job dependency and conditional execution
573
+ jobs:
574
+ test:
575
+ runs-on: ubuntu-24.04
576
+ outputs:
577
+ result: ${{ steps.run-tests.outcome }}
578
+
579
+ deploy:
580
+ needs: [test, build]
581
+ if: |
582
+ needs.test.result == 'success' &&
583
+ needs.build.result == 'success' &&
584
+ github.ref == 'refs/heads/main'
585
+ runs-on: ubuntu-24.04
586
+
587
+ notify-failure:
588
+ needs: [test, deploy]
589
+ if: failure() # Runs even if earlier jobs fail
590
+ runs-on: ubuntu-24.04
591
+ steps:
592
+ - run: ./scripts/notify-slack.sh "Pipeline failed!"
593
+ ```
594
+
595
+ ### Passing Data Between Jobs
596
+
597
+ ```yaml
598
+ jobs:
599
+ prepare:
600
+ runs-on: ubuntu-24.04
601
+ outputs:
602
+ version: ${{ steps.get-version.outputs.version }}
603
+ should-deploy: ${{ steps.check.outputs.deploy }}
604
+
605
+ steps:
606
+ - id: get-version
607
+ run: |
608
+ VERSION=$(tr -d '\r\n' < VERSION)
609
+ case "$VERSION" in
610
+ ""|*[!0-9A-Za-z._-]*) echo "Invalid VERSION" >&2; exit 1 ;;
611
+ esac
612
+ printf 'version=%s\n' "$VERSION" >> "$GITHUB_OUTPUT"
613
+
614
+ - id: check
615
+ run: |
616
+ if git log -1 --pretty=%B | grep -q '\[deploy\]'; then
617
+ echo "deploy=true" >> $GITHUB_OUTPUT
618
+ else
619
+ echo "deploy=false" >> $GITHUB_OUTPUT
620
+ fi
621
+
622
+ build:
623
+ needs: prepare
624
+ if: needs.prepare.outputs.should-deploy == 'true'
625
+ runs-on: ubuntu-24.04
626
+ steps:
627
+ - env:
628
+ VERSION: ${{ needs.prepare.outputs.version }}
629
+ run: echo "Building version $VERSION"
630
+ ```
631
+
632
+ ---
633
+
634
+ ## Security Hardening
635
+
636
+ ### 1. Always Declare Permissions (Least Privilege)
637
+
638
+ ```yaml
639
+ # Workflow-level default — restrict everything
640
+ permissions:
641
+ contents: read
642
+
643
+ jobs:
644
+ publish:
645
+ # Job-level override — only expand what's needed
646
+ permissions:
647
+ contents: write # Only for release/publish jobs
648
+ packages: write # Only for container push jobs
649
+ pull-requests: write # Only for PR comment jobs
650
+ id-token: write # Only for OIDC auth jobs
651
+ ```
652
+
653
+ ### 2. Pin Third-Party Actions to Full Commit SHA
654
+
655
+ ```yaml
656
+ # ❌ UNSAFE — tag can be mutated or hijacked
657
+ - uses: actions/checkout@v4
658
+
659
+ # ✅ SAFE — commit SHA is immutable
660
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
661
+
662
+ # Tool to automate SHA pinning:
663
+ # npx pin-github-action .github/workflows/*.yml
664
+ # or: pip install ratchet && ratchet pin .github/workflows/
665
+ ```
666
+
667
+ ### 3. Prevent Script Injection
668
+
669
+ ```yaml
670
+ # ❌ UNSAFE — attacker controls PR title, which gets expanded in shell
671
+ - run: echo "${{ github.event.pull_request.title }}"
672
+
673
+ # ✅ SAFE — pass through environment variable (shell doesn't evaluate it)
674
+ - env:
675
+ PR_TITLE: ${{ github.event.pull_request.title }}
676
+ run: echo "$PR_TITLE"
677
+
678
+ # ✅ SAFE — expressions in if: conditions are evaluated by Actions, not shell
679
+ - if: github.event.pull_request.draft == false
680
+ run: echo "Not a draft"
681
+ ```
682
+
683
+ Never place `${{ ... }}` directly inside `run:` when the value can come from
684
+ PR metadata, workflow inputs, repository files, matrix JSON, or earlier job
685
+ outputs. Put it in `env:` first, validate allowlisted values where possible, and
686
+ reference the shell variable with quotes.
687
+
688
+ ### 4. Restrict `pull_request_target` Usage
689
+
690
+ ```yaml
691
+ # Only run when a maintainer adds a specific label — prevents untrusted execution
692
+ on:
693
+ pull_request_target:
694
+ types: [labeled]
695
+
696
+ jobs:
697
+ validate:
698
+ # Double-guard: check label name AND author_association
699
+ if: |
700
+ github.event.label.name == 'safe-to-test' &&
701
+ (github.event.pull_request.author_association == 'COLLABORATOR' ||
702
+ github.event.pull_request.author_association == 'MEMBER' ||
703
+ github.event.pull_request.author_association == 'OWNER')
704
+ ```
705
+
706
+ ### 5. Harden with StepSecurity
707
+
708
+ ```yaml
709
+ # Add to every workflow — hardens runner, monitors outbound traffic
710
+ - uses: step-security/harden-runner@4d991eb9995541a0b71d1b66f1f98a5f1bef422c # v2.11.0
711
+ with:
712
+ egress-policy: audit # Start with 'audit', move to 'block' after confirming allowlist
713
+ allowed-endpoints: >
714
+ api.github.com:443
715
+ registry.npmjs.org:443
716
+ objects.githubusercontent.com:443
717
+ ```
718
+
719
+ ---
720
+
721
+ ## Debugging Techniques
722
+
723
+ ```yaml
724
+ # Enable runner diagnostic logging via repo secrets:
725
+ # ACTIONS_RUNNER_DEBUG = true
726
+ # ACTIONS_STEP_DEBUG = true
727
+
728
+ # Dump full GitHub context for inspection
729
+ - name: Debug — dump github context
730
+ if: runner.debug == '1'
731
+ env:
732
+ GITHUB_CONTEXT: ${{ toJson(github) }}
733
+ run: echo "$GITHUB_CONTEXT" | jq '.'
734
+
735
+ # Dump all available contexts
736
+ - name: Debug — dump all contexts
737
+ if: runner.debug == '1'
738
+ run: |
739
+ echo "github: ${{ toJson(github) }}"
740
+ echo "env: ${{ toJson(env) }}"
741
+ echo "vars: ${{ toJson(vars) }}"
742
+ echo "runner: ${{ toJson(runner) }}"
743
+
744
+ # SSH into a failing runner for interactive debugging
745
+ - uses: mxschmitt/action-tmate@7b04f3521e6b0a9fc56fa8f9f50da4bcfb5fc7b5 # v3.19.0
746
+ if: failure() && runner.debug == '1'
747
+ with:
748
+ limit-access-to-actor: true # Only the workflow triggerer can SSH in
749
+ timeout-minutes: 30
750
+
751
+ # Check what's pre-installed on GitHub-hosted runners
752
+ - run: |
753
+ echo "=== Tool Versions ==="
754
+ node --version
755
+ python3 --version
756
+ go version
757
+ docker --version
758
+ echo "=== Disk Space ==="
759
+ df -h
760
+ echo "=== Memory ==="
761
+ free -h
762
+ ```
763
+
764
+ ---
765
+
766
+ ## Complete Pipeline Patterns
767
+
768
+ ### Pattern 1: Build → Test → Push → Deploy
769
+
770
+ ```yaml
771
+ name: CI/CD Pipeline
772
+
773
+ on:
774
+ push:
775
+ branches: [main]
776
+ pull_request:
777
+ branches: [main]
778
+
779
+ concurrency:
780
+ group: ${{ github.workflow }}-${{ github.ref }}
781
+ cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
782
+
783
+ permissions:
784
+ contents: read
785
+
786
+ jobs:
787
+ # ── Build & Test ──────────────────────────────────────
788
+ build-test:
789
+ runs-on: ubuntu-24.04
790
+ timeout-minutes: 20
791
+ permissions:
792
+ contents: read
793
+ checks: write # For test result reporting
794
+
795
+ steps:
796
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
797
+
798
+ - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
799
+ with:
800
+ node-version: '20'
801
+ cache: 'npm'
802
+
803
+ - run: npm ci
804
+ - run: npm run lint
805
+ - run: npm run test -- --coverage
806
+ - run: npm run build
807
+
808
+ - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
809
+ with:
810
+ name: build-artifacts
811
+ path: dist/
812
+ retention-days: 7
813
+
814
+ # ── Push Image (main branch only) ─────────────────────
815
+ push-image:
816
+ needs: build-test
817
+ if: github.ref == 'refs/heads/main'
818
+ runs-on: ubuntu-24.04
819
+ timeout-minutes: 20
820
+ permissions:
821
+ contents: read
822
+ packages: write
823
+ id-token: write # For OIDC
824
+ outputs:
825
+ image-digest: ${{ steps.push.outputs.digest }}
826
+
827
+ steps:
828
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
829
+
830
+ - uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
831
+
832
+ - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
833
+ with:
834
+ registry: ghcr.io
835
+ username: ${{ github.actor }}
836
+ password: ${{ secrets.GITHUB_TOKEN }}
837
+
838
+ - uses: docker/metadata-action@70b2cdc6480c1a8b86edf1777157f8f437de2166 # v5.5.1
839
+ id: meta
840
+ with:
841
+ images: ghcr.io/${{ github.repository }}
842
+ tags: |
843
+ type=sha,format=long
844
+ type=raw,value=latest
845
+
846
+ - id: push
847
+ uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
848
+ with:
849
+ context: .
850
+ push: true
851
+ tags: ${{ steps.meta.outputs.tags }}
852
+ labels: ${{ steps.meta.outputs.labels }}
853
+ cache-from: type=gha
854
+ cache-to: type=gha,mode=max
855
+ provenance: true # SLSA provenance attestation
856
+ sbom: true # Software Bill of Materials
857
+
858
+ # ── Deploy Staging ────────────────────────────────────
859
+ deploy-staging:
860
+ needs: push-image
861
+ runs-on: ubuntu-24.04
862
+ timeout-minutes: 30
863
+ environment:
864
+ name: staging
865
+ url: https://staging.myapp.com
866
+ steps:
867
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
868
+ - env:
869
+ IMAGE_DIGEST: ${{ needs.push-image.outputs.image-digest }}
870
+ run: ./scripts/deploy.sh staging "$IMAGE_DIGEST"
871
+
872
+ # ── Deploy Production (manual approval required) ──────
873
+ deploy-production:
874
+ needs: deploy-staging
875
+ runs-on: ubuntu-24.04
876
+ timeout-minutes: 30
877
+ environment:
878
+ name: production
879
+ url: https://myapp.com
880
+ steps:
881
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
882
+ - env:
883
+ IMAGE_DIGEST: ${{ needs.push-image.outputs.image-digest }}
884
+ run: ./scripts/deploy.sh production "$IMAGE_DIGEST"
885
+ ```
886
+
887
+ ### Pattern 2: Automated Release with Changelog
888
+
889
+ ```yaml
890
+ name: Release
891
+
892
+ on:
893
+ push:
894
+ tags: ['v[0-9]+.[0-9]+.[0-9]+']
895
+
896
+ permissions:
897
+ contents: write
898
+
899
+ jobs:
900
+ release:
901
+ runs-on: ubuntu-24.04
902
+ timeout-minutes: 15
903
+
904
+ steps:
905
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
906
+ with:
907
+ fetch-depth: 0 # Full history needed for changelog generation
908
+
909
+ - uses: softprops/action-gh-release@e7a8f85e1c67a31e6ed99a94b41bd0b71bbee6b8 # v2.0.9
910
+ with:
911
+ generate_release_notes: true # Auto-generates from PR titles and commits
912
+ make_latest: true
913
+ fail_on_unmatched_files: true
914
+ files: |
915
+ dist/**/*.tar.gz
916
+ dist/**/*.zip
917
+ ```
918
+
919
+ ### Pattern 3: Dependency Auto-Update with PR
920
+
921
+ ```yaml
922
+ name: Dependency Updates
923
+
924
+ on:
925
+ schedule:
926
+ - cron: '0 9 * * 1' # Every Monday at 9am UTC
927
+ workflow_dispatch:
928
+
929
+ permissions:
930
+ contents: write
931
+ pull-requests: write
932
+
933
+ jobs:
934
+ update-deps:
935
+ runs-on: ubuntu-24.04
936
+ timeout-minutes: 20
937
+ steps:
938
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
939
+
940
+ - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
941
+ with:
942
+ node-version: '20'
943
+
944
+ - run: npx npm-check-updates -u
945
+ - run: npm install
946
+
947
+ - uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5
948
+ with:
949
+ commit-message: 'chore: update npm dependencies'
950
+ title: 'chore: update npm dependencies'
951
+ branch: 'chore/npm-updates'
952
+ delete-branch: true
953
+ body: |
954
+ Automated dependency updates generated by the dependency update workflow.
955
+ Please review and test before merging.
956
+ ```
957
+
958
+ ### Pattern 4: Security Scanning Pipeline
959
+
960
+ ```yaml
961
+ name: Security Scan
962
+
963
+ on:
964
+ push:
965
+ branches: [main]
966
+ pull_request:
967
+ branches: [main]
968
+ schedule:
969
+ - cron: '0 6 * * *' # Daily at 6am UTC
970
+
971
+ permissions:
972
+ contents: read
973
+ security-events: write # For uploading SARIF results
974
+
975
+ jobs:
976
+ codeql:
977
+ runs-on: ubuntu-24.04
978
+ timeout-minutes: 30
979
+ permissions:
980
+ security-events: write
981
+ actions: read
982
+ contents: read
983
+ steps:
984
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
985
+ - uses: github/codeql-action/init@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1
986
+ with:
987
+ languages: javascript-typescript
988
+ - uses: github/codeql-action/autobuild@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1
989
+ - uses: github/codeql-action/analyze@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1
990
+
991
+ container-scan:
992
+ runs-on: ubuntu-24.04
993
+ timeout-minutes: 15
994
+ steps:
995
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
996
+ - uses: aquasecurity/trivy-action@6e7b7d1fd3e4fef0c5fa8cce1229c54b2c9bd0d8 # v0.28.0
997
+ with:
998
+ scan-type: 'fs'
999
+ format: 'sarif'
1000
+ output: 'trivy-results.sarif'
1001
+ severity: 'CRITICAL,HIGH'
1002
+ - uses: github/codeql-action/upload-sarif@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1
1003
+ with:
1004
+ sarif_file: 'trivy-results.sarif'
1005
+ ```
1006
+
1007
+ ---
1008
+
1009
+ ## Common Pitfalls & Fixes
1010
+
1011
+ | Problem | Cause | Fix |
1012
+ |---|---|---|
1013
+ | Workflow doesn't trigger on PR from fork | Fork PRs use restricted `GITHUB_TOKEN` | Use `pull_request` not `pull_request_target`; avoid repo secrets in fork context |
1014
+ | Secret is `***` in logs but exposed | Dynamic value not masked | Use `echo "::add-mask::$VALUE"` before using it |
1015
+ | Cache never hits across branches | Cache key too specific | Add `restore-keys` fallback without branch or hash segment |
1016
+ | Matrix job fails silently | `fail-fast: true` (default) cancels siblings | Set `fail-fast: false` during debugging |
1017
+ | Job hangs indefinitely | No `timeout-minutes` set | Always set `timeout-minutes` on every job |
1018
+ | `$GITHUB_OUTPUT` not set | Old `set-output` command used | Use `echo "key=value" >> $GITHUB_OUTPUT` |
1019
+ | OIDC token request fails | Missing `id-token: write` permission | Add to job-level `permissions` block |
1020
+ | Reusable workflow can't access caller secrets | No `secrets: inherit` | Add `secrets: inherit` or explicitly pass secrets |
1021
+
1022
+ ---
1023
+
1024
+ ## GitHub Actions Expressions Reference
1025
+
1026
+ ```yaml
1027
+ # Context objects available in expressions
1028
+ ${{ github.sha }} # Commit SHA
1029
+ ${{ github.ref }} # Branch/tag ref
1030
+ ${{ github.ref_name }} # Short branch/tag name
1031
+ ${{ github.event_name }} # Event name (push, pull_request, etc.)
1032
+ ${{ github.actor }} # Username who triggered the run
1033
+ ${{ github.repository }} # org/repo
1034
+ ${{ github.run_id }} # Unique run ID
1035
+ ${{ runner.os }} # Linux, Windows, macOS
1036
+
1037
+ # Built-in functions
1038
+ ${{ toJson(github) }} # Serialize context to JSON
1039
+ ${{ fromJson(needs.job.outputs.matrix) }} # Parse JSON string
1040
+ ${{ hashFiles('**/package-lock.json') }} # Hash file(s) for cache keys
1041
+ ${{ format('{0}/{1}', var1, var2) }} # String formatting
1042
+ ${{ join(matrix.items, ',') }} # Join array
1043
+
1044
+ # Status functions (use in if: conditions)
1045
+ ${{ success() }} # All previous steps succeeded
1046
+ ${{ failure() }} # Any previous step failed
1047
+ ${{ cancelled() }} # Workflow was cancelled
1048
+ ${{ always() }} # Always runs (success OR failure OR cancelled)
1049
+ ```
1050
+
1051
+ ---
1052
+
1053
+ ## Production Readiness Checklist
1054
+
1055
+ Before merging any workflow to `main`, verify:
1056
+
1057
+ ### Security
1058
+ - [ ] All third-party actions pinned to full commit SHA
1059
+ - [ ] `permissions:` declared at workflow and job level (least privilege)
1060
+ - [ ] No `${{ }}` expressions directly in `run:` blocks (use env vars)
1061
+ - [ ] OIDC used for cloud credentials (no long-lived secrets stored)
1062
+ - [ ] `pull_request_target` gated with label check + author_association guard
1063
+ - [ ] Secrets never echoed or logged
1064
+
1065
+ ### Reliability
1066
+ - [ ] `timeout-minutes` set on every job
1067
+ - [ ] `fail-fast: false` set for matrix builds used for debugging
1068
+ - [ ] `concurrency` configured to cancel stale runs
1069
+ - [ ] Retry logic for flaky external calls
1070
+ - [ ] Artifact retention policy set appropriately
1071
+
1072
+ ### Performance
1073
+ - [ ] Dependency caching configured (setup-* cache or actions/cache)
1074
+ - [ ] Docker layer caching enabled (`type=gha`)
1075
+ - [ ] Path filters on `push`/`pull_request` to skip unrelated changes
1076
+ - [ ] Matrix parallelism appropriate (not exhausting runner pool)
1077
+
1078
+ ### Maintainability
1079
+ - [ ] Reusable workflows used for repeated patterns
1080
+ - [ ] Composite actions used for repeated step sequences
1081
+ - [ ] Workflow names and step names are human-readable
1082
+ - [ ] `_` prefix on internal/reusable workflow files
1083
+ - [ ] Environment protection rules configured for `production`
1084
+
1085
+ ---
1086
+
1087
+ ## Related Skills
1088
+
1089
+ - `gha-security-review` — Deep security audit of existing workflow files
1090
+ - `github-actions-templates` — Copy-paste ready workflow templates
1091
+ - `docker-expert` — Container build optimization and Dockerfile best practices
1092
+ - `kubernetes-architect` — Deploying to Kubernetes from GitHub Actions
1093
+ - `gitlab-ci-patterns` — GitLab CI/CD equivalent patterns
1094
+
1095
+ ## Limitations
1096
+
1097
+ - Use this skill only when the task clearly matches the scope described above.
1098
+ - Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
1099
+ - Always test reusable workflows in a feature branch before merging to main.
1100
+ - Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.