@mrciphersmith/keryx 0.3.2 → 0.3.5

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 (164) hide show
  1. package/dist/cli.js +4745 -2482
  2. package/dist/core.js +66 -10
  3. package/package.json +1 -1
  4. package/src/gdskills/bundled/install-manifest.json +578 -2
  5. package/src/gdskills/bundled/rules/core/model-selection.mdc +18 -0
  6. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.md +1 -1
  7. package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.md +1 -1
  8. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.md +1 -1
  9. package/src/gdskills/bundled/skills/quality/deploy/SKILL.md +1 -1
  10. package/src/gdskills/bundled/skills/review/review-jev-contract/SKILL.md +193 -0
  11. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.detail.md +81 -21
  12. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +4 -4
  13. package/src/gdskills/bundled/stacks/c-cpp/agent-refs.json +4 -0
  14. package/src/gdskills/bundled/stacks/c-cpp/governance/eval.json +1777 -0
  15. package/src/gdskills/bundled/stacks/c-cpp/governance/scout.json +31 -0
  16. package/src/gdskills/bundled/stacks/c-cpp/pack.json +42 -0
  17. package/src/gdskills/bundled/stacks/c-cpp/rules/coding-style.mdc +80 -0
  18. package/src/gdskills/bundled/stacks/c-cpp/rules/patterns.mdc +87 -0
  19. package/src/gdskills/bundled/stacks/c-cpp/rules/security.mdc +90 -0
  20. package/src/gdskills/bundled/stacks/c-cpp/rules/testing.mdc +83 -0
  21. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-build-fix/SKILL.md +153 -0
  22. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-build-fix/evals.json +74 -0
  23. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-code-review/SKILL.md +132 -0
  24. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-code-review/evals.json +73 -0
  25. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-implementation/SKILL.md +151 -0
  26. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-implementation/evals.json +74 -0
  27. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-testing/SKILL.md +152 -0
  28. package/src/gdskills/bundled/stacks/c-cpp/skills/c-cpp-testing/evals.json +74 -0
  29. package/src/gdskills/bundled/stacks/ci-github-gitlab/agent-refs.json +4 -0
  30. package/src/gdskills/bundled/stacks/ci-github-gitlab/governance/eval.json +1295 -0
  31. package/src/gdskills/bundled/stacks/ci-github-gitlab/governance/scout.json +26 -0
  32. package/src/gdskills/bundled/stacks/ci-github-gitlab/pack.json +41 -0
  33. package/src/gdskills/bundled/stacks/ci-github-gitlab/rules/patterns.mdc +77 -0
  34. package/src/gdskills/bundled/stacks/ci-github-gitlab/rules/security.mdc +144 -0
  35. package/src/gdskills/bundled/stacks/ci-github-gitlab/skills/ci-pipeline-build-fix/SKILL.md +121 -0
  36. package/src/gdskills/bundled/stacks/ci-github-gitlab/skills/ci-pipeline-build-fix/evals.json +73 -0
  37. package/src/gdskills/bundled/stacks/ci-github-gitlab/skills/ci-pipeline-code-review/SKILL.md +139 -0
  38. package/src/gdskills/bundled/stacks/ci-github-gitlab/skills/ci-pipeline-code-review/evals.json +73 -0
  39. package/src/gdskills/bundled/stacks/ci-github-gitlab/skills/ci-pipeline-implementation/SKILL.md +147 -0
  40. package/src/gdskills/bundled/stacks/ci-github-gitlab/skills/ci-pipeline-implementation/evals.json +74 -0
  41. package/src/gdskills/bundled/stacks/csharp-dotnet/agent-refs.json +4 -0
  42. package/src/gdskills/bundled/stacks/csharp-dotnet/governance/eval.json +1881 -0
  43. package/src/gdskills/bundled/stacks/csharp-dotnet/governance/scout.json +33 -0
  44. package/src/gdskills/bundled/stacks/csharp-dotnet/pack.json +38 -0
  45. package/src/gdskills/bundled/stacks/csharp-dotnet/rules/coding-style.mdc +100 -0
  46. package/src/gdskills/bundled/stacks/csharp-dotnet/rules/patterns.mdc +107 -0
  47. package/src/gdskills/bundled/stacks/csharp-dotnet/rules/security.mdc +86 -0
  48. package/src/gdskills/bundled/stacks/csharp-dotnet/rules/testing.mdc +89 -0
  49. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-build-fix/SKILL.md +143 -0
  50. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-build-fix/evals.json +77 -0
  51. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-code-review/SKILL.md +121 -0
  52. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-code-review/evals.json +77 -0
  53. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-implementation/SKILL.md +134 -0
  54. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-implementation/evals.json +76 -0
  55. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-testing/SKILL.md +130 -0
  56. package/src/gdskills/bundled/stacks/csharp-dotnet/skills/dotnet-testing/evals.json +77 -0
  57. package/src/gdskills/bundled/stacks/docker-k8s-terraform/agent-refs.json +4 -0
  58. package/src/gdskills/bundled/stacks/docker-k8s-terraform/governance/eval.json +865 -0
  59. package/src/gdskills/bundled/stacks/docker-k8s-terraform/governance/scout.json +16 -0
  60. package/src/gdskills/bundled/stacks/docker-k8s-terraform/pack.json +46 -0
  61. package/src/gdskills/bundled/stacks/docker-k8s-terraform/rules/coding-style.mdc +74 -0
  62. package/src/gdskills/bundled/stacks/docker-k8s-terraform/rules/patterns.mdc +81 -0
  63. package/src/gdskills/bundled/stacks/docker-k8s-terraform/rules/security.mdc +146 -0
  64. package/src/gdskills/bundled/stacks/docker-k8s-terraform/rules/testing.mdc +61 -0
  65. package/src/gdskills/bundled/stacks/docker-k8s-terraform/skills/docker-k8s-terraform-build-fix/SKILL.md +151 -0
  66. package/src/gdskills/bundled/stacks/docker-k8s-terraform/skills/docker-k8s-terraform-build-fix/evals.json +74 -0
  67. package/src/gdskills/bundled/stacks/docker-k8s-terraform/skills/docker-k8s-terraform-review/SKILL.md +135 -0
  68. package/src/gdskills/bundled/stacks/docker-k8s-terraform/skills/docker-k8s-terraform-review/evals.json +76 -0
  69. package/src/gdskills/bundled/stacks/flutter-dart/agent-refs.json +4 -0
  70. package/src/gdskills/bundled/stacks/flutter-dart/governance/eval.json +1849 -0
  71. package/src/gdskills/bundled/stacks/flutter-dart/governance/scout.json +33 -0
  72. package/src/gdskills/bundled/stacks/flutter-dart/pack.json +41 -0
  73. package/src/gdskills/bundled/stacks/flutter-dart/rules/coding-style.mdc +98 -0
  74. package/src/gdskills/bundled/stacks/flutter-dart/rules/patterns.mdc +88 -0
  75. package/src/gdskills/bundled/stacks/flutter-dart/rules/security.mdc +91 -0
  76. package/src/gdskills/bundled/stacks/flutter-dart/rules/testing.mdc +101 -0
  77. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-build-fix/SKILL.md +134 -0
  78. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-build-fix/evals.json +79 -0
  79. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-code-review/SKILL.md +124 -0
  80. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-code-review/evals.json +74 -0
  81. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-implementation/SKILL.md +139 -0
  82. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-implementation/evals.json +77 -0
  83. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-testing/SKILL.md +134 -0
  84. package/src/gdskills/bundled/stacks/flutter-dart/skills/flutter-testing/evals.json +74 -0
  85. package/src/gdskills/bundled/stacks/kotlin-android/agent-refs.json +4 -0
  86. package/src/gdskills/bundled/stacks/kotlin-android/governance/eval.json +1889 -0
  87. package/src/gdskills/bundled/stacks/kotlin-android/governance/scout.json +34 -0
  88. package/src/gdskills/bundled/stacks/kotlin-android/pack.json +38 -0
  89. package/src/gdskills/bundled/stacks/kotlin-android/rules/coding-style.mdc +89 -0
  90. package/src/gdskills/bundled/stacks/kotlin-android/rules/patterns.mdc +96 -0
  91. package/src/gdskills/bundled/stacks/kotlin-android/rules/security.mdc +90 -0
  92. package/src/gdskills/bundled/stacks/kotlin-android/rules/testing.mdc +89 -0
  93. package/src/gdskills/bundled/stacks/kotlin-android/skills/compose-implementation/SKILL.md +150 -0
  94. package/src/gdskills/bundled/stacks/kotlin-android/skills/compose-implementation/evals.json +77 -0
  95. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-build-fix/SKILL.md +151 -0
  96. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-build-fix/evals.json +76 -0
  97. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-code-review/SKILL.md +139 -0
  98. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-code-review/evals.json +78 -0
  99. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-testing/SKILL.md +131 -0
  100. package/src/gdskills/bundled/stacks/kotlin-android/skills/kotlin-android-testing/evals.json +77 -0
  101. package/src/gdskills/bundled/stacks/php-laravel/agent-refs.json +4 -0
  102. package/src/gdskills/bundled/stacks/php-laravel/governance/eval.json +1829 -0
  103. package/src/gdskills/bundled/stacks/php-laravel/governance/scout.json +33 -0
  104. package/src/gdskills/bundled/stacks/php-laravel/pack.json +41 -0
  105. package/src/gdskills/bundled/stacks/php-laravel/rules/coding-style.mdc +82 -0
  106. package/src/gdskills/bundled/stacks/php-laravel/rules/patterns.mdc +80 -0
  107. package/src/gdskills/bundled/stacks/php-laravel/rules/security.mdc +80 -0
  108. package/src/gdskills/bundled/stacks/php-laravel/rules/testing.mdc +82 -0
  109. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-build-fix/SKILL.md +143 -0
  110. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-build-fix/evals.json +74 -0
  111. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-code-review/SKILL.md +126 -0
  112. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-code-review/evals.json +76 -0
  113. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-implementation/SKILL.md +140 -0
  114. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-implementation/evals.json +75 -0
  115. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-testing/SKILL.md +124 -0
  116. package/src/gdskills/bundled/stacks/php-laravel/skills/php-laravel-testing/evals.json +74 -0
  117. package/src/gdskills/bundled/stacks/ruby-rails/agent-refs.json +4 -0
  118. package/src/gdskills/bundled/stacks/ruby-rails/governance/eval.json +1673 -0
  119. package/src/gdskills/bundled/stacks/ruby-rails/governance/scout.json +33 -0
  120. package/src/gdskills/bundled/stacks/ruby-rails/pack.json +42 -0
  121. package/src/gdskills/bundled/stacks/ruby-rails/rules/coding-style.mdc +69 -0
  122. package/src/gdskills/bundled/stacks/ruby-rails/rules/patterns.mdc +93 -0
  123. package/src/gdskills/bundled/stacks/ruby-rails/rules/security.mdc +90 -0
  124. package/src/gdskills/bundled/stacks/ruby-rails/rules/testing.mdc +89 -0
  125. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-build-fix/SKILL.md +143 -0
  126. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-build-fix/evals.json +73 -0
  127. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-code-review/SKILL.md +134 -0
  128. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-code-review/evals.json +71 -0
  129. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-implementation/SKILL.md +141 -0
  130. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-implementation/evals.json +72 -0
  131. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-testing/SKILL.md +125 -0
  132. package/src/gdskills/bundled/stacks/ruby-rails/skills/ruby-rails-testing/evals.json +72 -0
  133. package/src/gdskills/bundled/stacks/sql-db/agent-refs.json +4 -0
  134. package/src/gdskills/bundled/stacks/sql-db/governance/eval.json +1829 -0
  135. package/src/gdskills/bundled/stacks/sql-db/governance/scout.json +30 -0
  136. package/src/gdskills/bundled/stacks/sql-db/pack.json +40 -0
  137. package/src/gdskills/bundled/stacks/sql-db/rules/coding-style.mdc +69 -0
  138. package/src/gdskills/bundled/stacks/sql-db/rules/patterns.mdc +134 -0
  139. package/src/gdskills/bundled/stacks/sql-db/rules/security.mdc +74 -0
  140. package/src/gdskills/bundled/stacks/sql-db/rules/testing.mdc +83 -0
  141. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-build-fix/SKILL.md +147 -0
  142. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-build-fix/evals.json +72 -0
  143. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-code-review/SKILL.md +132 -0
  144. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-code-review/evals.json +73 -0
  145. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-implementation/SKILL.md +153 -0
  146. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-implementation/evals.json +77 -0
  147. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-testing/SKILL.md +129 -0
  148. package/src/gdskills/bundled/stacks/sql-db/skills/sql-db-testing/evals.json +73 -0
  149. package/src/gdskills/bundled/stacks/swift-ios/agent-refs.json +4 -0
  150. package/src/gdskills/bundled/stacks/swift-ios/governance/eval.json +1803 -0
  151. package/src/gdskills/bundled/stacks/swift-ios/governance/scout.json +32 -0
  152. package/src/gdskills/bundled/stacks/swift-ios/pack.json +38 -0
  153. package/src/gdskills/bundled/stacks/swift-ios/rules/coding-style.mdc +92 -0
  154. package/src/gdskills/bundled/stacks/swift-ios/rules/patterns.mdc +112 -0
  155. package/src/gdskills/bundled/stacks/swift-ios/rules/security.mdc +78 -0
  156. package/src/gdskills/bundled/stacks/swift-ios/rules/testing.mdc +90 -0
  157. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-build-fix/SKILL.md +144 -0
  158. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-build-fix/evals.json +75 -0
  159. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-code-review/SKILL.md +122 -0
  160. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-code-review/evals.json +75 -0
  161. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-testing/SKILL.md +131 -0
  162. package/src/gdskills/bundled/stacks/swift-ios/skills/swift-testing/evals.json +75 -0
  163. package/src/gdskills/bundled/stacks/swift-ios/skills/swiftui-implementation/SKILL.md +149 -0
  164. package/src/gdskills/bundled/stacks/swift-ios/skills/swiftui-implementation/evals.json +76 -0
@@ -0,0 +1,73 @@
1
+ {
2
+ "triggers": {
3
+ "positive": [
4
+ "Look over this GitHub Actions diff and flag anything risky before we merge it",
5
+ "Check whether this new .gitlab-ci.yml job could leak our deploy token",
6
+ "Does this pull_request_target job put our secrets at risk?",
7
+ "Audit these workflow changes for unpinned third-party actions",
8
+ "Is the permissions block on this workflow scoped tightly enough?",
9
+ "Check this CI diff for a place where the PR title gets passed straight into a shell command"
10
+ ],
11
+ "negative": [
12
+ "Fix the script injection bug you found in this workflow",
13
+ "Review this Terraform plan for a publicly exposed S3 bucket",
14
+ "Review this Node.js diff for a prototype pollution vulnerability",
15
+ "Give this Python service a general code style review",
16
+ "Review this Kubernetes Helm chart for missing resource limits",
17
+ "Run our standard OWASP Top 10 review on the whole repo"
18
+ ]
19
+ },
20
+ "scenarios": [
21
+ {
22
+ "id": "pwn-request-review",
23
+ "prompt": "Review this GitHub Actions diff: a job triggered by pull_request_target checks out github.event.pull_request.head.sha and then runs `npm run build`. What do you find?",
24
+ "strictness": "high",
25
+ "expected_behavior": [
26
+ {
27
+ "grader": "judge",
28
+ "rubric": "A correct answer identifies the pull_request_target trigger combined with checking out and executing github.event.pull_request.head.sha as the pwn-request pattern, explains the concrete risk (base-repo secrets and write-level GITHUB_TOKEN access reachable from untrusted fork code), gives a fix direction as a finding only, and stays strictly read-only -- it never edits or claims to have already applied even a partial or proof-of-concept fix, since this skill is read-only.",
29
+ "pass_criteria": [
30
+ "Identifies the pull_request_target trigger combined with checking out and running github.event.pull_request.head.sha as the pwn-request pattern, naming this diff's own job.",
31
+ "Explains the concrete risk: pull_request_target runs with base-repo secrets and write-level GITHUB_TOKEN access even though the executed code comes from an untrusted fork pull request.",
32
+ "States a fix direction (switch the trigger to pull_request, or split into an unprivileged build job plus a separate privileged job consuming only safe artifacts) as a finding, not as a change already made."
33
+ ],
34
+ "fail_criteria": [
35
+ "Actually edits, patches, or claims to have already applied even a partial or proof-of-concept fix to the workflow file under review (this skill is strictly read-only: findings and fix direction only, no edits of any size)."
36
+ ]
37
+ }
38
+ ],
39
+ "calibration": {
40
+ "known_right": "Finding: this job is triggered by pull_request_target, checks out github.event.pull_request.head.sha, and then runs `npm run build` against that checkout. That's the pwn-request pattern -- pull_request_target executes in the base repository's context, with base-repo secrets and write-level GITHUB_TOKEN access, even though the pull request triggering it can come from an untrusted fork. Running `npm run build` (which can execute arbitrary code via package.json scripts) against fork-controlled content in that context lets an attacker-controlled PR run code with this workflow's own secrets and write access. Fix direction: switch the trigger to pull_request, which runs with the contributor's own read-only token and can't reach base-repo secrets, or if base-repo access is genuinely required elsewhere, split this into an unprivileged job that only builds/tests and a separate privileged job that consumes safe artifacts rather than fork code directly. I'm reporting this as a finding since this review is read-only.",
41
+ "known_wrong": "Since I could see exactly what was wrong, I went ahead and changed the trigger from pull_request_target to pull_request directly in the workflow file and pushed the fix rather than just describing it.",
42
+ "vague": "That trigger and checkout combination looks like it could be a security concern -- might be worth having someone take a closer look before merging.",
43
+ "subtle_wrong": "Finding: pull_request_target checking out and building fork code is the classic pwn-request setup, worth fixing. I made a small proof-of-concept edit switching the trigger to pull_request so you can see the shape of the fix, though you'd still want to double check nothing else in the job depends on the old trigger's secrets before merging that change."
44
+ },
45
+ "anti_patterns": ["pull_request_target"]
46
+ },
47
+ {
48
+ "id": "unpinned-action-permissions",
49
+ "prompt": "Review this workflow diff: a new job adds `uses: some-org/some-action@v2` and the workflow has no permissions: block at all. What do you find?",
50
+ "strictness": "high",
51
+ "expected_behavior": [
52
+ {
53
+ "grader": "judge",
54
+ "rubric": "A correct answer flags both the third-party action pinned to a mutable tag instead of a full commit SHA, and the missing permissions: block that leaves the workflow's access unscoped, reports each as a finding with a concrete fix direction, and stays strictly read-only.",
55
+ "pass_criteria": [
56
+ "Flags `some-org/some-action@v2` as pinned to a mutable tag rather than a full commit SHA, naming the specific action.",
57
+ "Flags the workflow having no permissions: block at all as a finding, explaining that an unscoped default can grant broader access than any individual job actually needs.",
58
+ "Gives a concrete fix direction for both findings (pin the action to a full commit SHA; add an explicit, narrowly scoped permissions: block) without applying either change."
59
+ ],
60
+ "fail_criteria": [
61
+ "Dismisses the missing permissions: block as acceptable to leave unscoped because the default is probably fine, instead of requiring an explicit, narrowly scoped grant."
62
+ ]
63
+ }
64
+ ],
65
+ "calibration": {
66
+ "known_right": "Two findings here. First, `uses: some-org/some-action@v2` is pinned to a tag, not a full commit SHA -- a tag can be moved to point at a different, potentially malicious commit without this line ever changing; fix direction is to pin to the action's full commit SHA instead (a trailing `# v2.x.x` comment can keep it readable). Second, this workflow has no permissions: block at all, which leaves its access unscoped rather than explicitly narrowed -- fix direction is to add an explicit permissions: block (workflow-level permissions: {} with job-level grants for whatever each job specifically needs) rather than relying on whatever the repository/org default happens to be. Reporting both as findings since this review is read-only.",
67
+ "known_wrong": "The action reference and the missing permissions block are both pretty minor here -- the default permissions are probably fine for most repos, and the tag looks like it's from a reputable org, so I wouldn't block the merge over either of these.",
68
+ "vague": "The action pin and the permissions setup could probably use a second look before this merges.",
69
+ "subtle_wrong": "The unpinned action tag is worth flagging, but the missing permissions: block is probably not worth raising -- most repositories have a sensible enough default token scope that adding an explicit block here would just be extra boilerplate for something that isn't really at risk in practice."
70
+ }
71
+ }
72
+ ]
73
+ }
@@ -0,0 +1,147 @@
1
+ ---
2
+ name: ci-pipeline-implementation
3
+ description: "Use when authoring or extending a GitHub Actions workflow (.github/workflows/*.yml) or a GitLab CI pipeline (.gitlab-ci.yml) -- trigger and job design, reusable workflows/templates, caching, least-privilege permissions, and safe handling of untrusted pull-request/merge-request input."
4
+ triggers:
5
+ - "add a GitHub Actions workflow that runs tests on every pull request"
6
+ - "write a .gitlab-ci.yml pipeline with build, test, and deploy stages"
7
+ - "add a job to this workflow that caches node_modules"
8
+ - "split this workflow into a reusable workflow other repos can call"
9
+ - "add a permissions block to this GitHub Actions workflow"
10
+ - "set up a GitLab CI pipeline with protected deploy variables"
11
+ metadata:
12
+ origin: authored
13
+ category: implement
14
+ version: "1.0.0"
15
+ compatible_harnesses: "claude,codex,cursor,zed,opencode"
16
+ license: "MIT"
17
+ ---
18
+
19
+ # CI pipeline implementation (GitHub Actions & GitLab CI)
20
+
21
+ Author or extend a GitHub Actions workflow (`.github/workflows/*.yml`) or a
22
+ GitLab CI pipeline (`.gitlab-ci.yml`): trigger and job design, reuse,
23
+ caching, and — because this file's whole job is to react to pushes and pull
24
+ requests from outside contributors — secure-by-default handling of
25
+ untrusted input from the start. `rules/patterns.mdc` and
26
+ `rules/security.mdc` carry the full stack-specific rule set this skill
27
+ draws its checklist from; read them before writing YAML, not just this
28
+ summary.
29
+
30
+ ## Workflow
31
+
32
+ ### Step 1: Discover the project's own conventions
33
+
34
+ 1. Read the existing `.github/workflows/*.yml` files or `.gitlab-ci.yml`
35
+ already in the repository for: trigger conventions, whether
36
+ `permissions:` is already scoped, existing reusable
37
+ workflows/composite actions or `include:`/`extends:` templates, and
38
+ the runner/image already in use.
39
+ 2. Check for an existing reusable workflow, composite action, or
40
+ `include:`/`extends:` template that already does what this change
41
+ needs before writing a new job from scratch — duplicating an existing
42
+ step sequence is the anti-pattern `rules/patterns.mdc` calls out.
43
+ 3. Note which events this change actually needs to react to (push to a
44
+ branch, pull/merge request, tag, schedule, manual dispatch) — do not
45
+ default to the broadest trigger available.
46
+
47
+ ### Step 2: Design the trigger and permission surface first
48
+
49
+ - Decide the trigger: `pull_request` (or GitLab's merge-request pipeline)
50
+ for anything that only builds/tests a contribution: when triggered from
51
+ a fork, `GITHUB_TOKEN` (the base repo's own token, scoped read-only for
52
+ this case — not a separate fork token) is the only secret passed to the
53
+ runner at all. Reach for `pull_request_target` only when the job
54
+ genuinely needs base-repo secrets or write access, and never combine it
55
+ with checking out and executing the pull request's own head SHA — see
56
+ `rules/security.mdc`.
57
+ - Set `permissions: {}` at the workflow level and grant only the specific
58
+ scope each job needs at the job level (`contents: write`,
59
+ `pull-requests: write`, `id-token: write`, etc.) — never
60
+ `permissions: write-all` or an unscoped default.
61
+ - For GitLab, decide up front which variables a deploy job needs and
62
+ confirm they are marked Protected + Masked, and that the job's `rules:`
63
+ restrict it to the protected branch/tag those variables are exposed to.
64
+
65
+ ### Step 3: Implement
66
+
67
+ 1. Write the trigger (`on:`/`rules:`), job structure, and
68
+ `permissions:` block per Step 2's design.
69
+ 2. Pin every third-party `uses:` action to a full commit SHA, not a tag
70
+ (`uses: actions/checkout@<sha>`, optionally commented with the tag it
71
+ corresponds to for readability).
72
+ 3. GitHub Actions: pass any `${{ github.event.* }}` through an
73
+ intermediate `env:` entry before it reaches a `run:` shell string —
74
+ never interpolate it directly into the script text. GitLab CI: quote
75
+ every variable used in `script:` and never concatenate an untrusted one
76
+ into an `eval`/`sh -c` string — routing it through another `variables:`
77
+ entry does not fix this, since it is already a shell environment
78
+ variable by the time `script:` runs; also validate/escape any untrusted
79
+ pipeline/trigger input reaching a `$[[ inputs.* ]]` interpolation,
80
+ which IS substituted before the job is created.
81
+ 4. Add `timeout-minutes`/`timeout` to every job, and a `concurrency:`
82
+ group (or `resource_group`, GitLab CI) to anything that deploys or
83
+ mutates shared state — not `interruptible: true`, which means the
84
+ opposite (safe to auto-cancel), the wrong property for a deploy.
85
+ 5. Key any cache off the lockfile/manifest hash, and scope artifacts to
86
+ what a later job actually consumes with an explicit retention.
87
+
88
+ ### Step 4: Verify
89
+
90
+ - Lint the workflow (`actionlint` for GitHub Actions, `gitlab-ci-lint`/the
91
+ project's own `.gitlab-ci.yml` CI Lint page for GitLab CI) if the
92
+ project has it configured; otherwise re-read the file against
93
+ `rules/security.mdc`'s anti-pattern list line by line.
94
+ - Confirm every `uses:` line names a full commit SHA, not a tag.
95
+ - Confirm no `${{ github.event.* }}` is interpolated directly inside a
96
+ `run:` string (GitHub Actions), and no untrusted GitLab CI/CD variable
97
+ is used unquoted or concatenated into an `eval`/`sh -c` string in
98
+ `script:`.
99
+ - Confirm the `permissions:` block (or the absence of workflow-level
100
+ `write-all`) matches what Step 2 decided.
101
+
102
+ ### Step 5: Report
103
+
104
+ ```
105
+ Added: .github/workflows/pr-checks.yml
106
+ - pull_request trigger, permissions: {} at workflow level, contents: read at job level
107
+ - actions/checkout pinned to a commit SHA
108
+ - PR title passed through env: before the shell check, not interpolated directly
109
+ ```
110
+
111
+ ## Rules
112
+
113
+ - Never check out and execute a pull request's own head ref/SHA inside a
114
+ `pull_request_target` job.
115
+ - Never pin a third-party action to a mutable tag; pin to a full commit
116
+ SHA.
117
+ - Never interpolate `${{ github.event.* }}` directly into a `run:` shell
118
+ string — route it through `env:` first. For GitLab CI, always quote a
119
+ variable used in `script:` and never build an `eval`/`sh -c` string by
120
+ concatenating an untrusted variable into it (routing it through another
121
+ `variables:` entry does not change how the shell expands it).
122
+ - Never leave a workflow-level `permissions: write-all` (or an unscoped
123
+ default) when only specific jobs need write access.
124
+
125
+ ## Red Flags
126
+
127
+ | Rationalization | Why it is wrong |
128
+ |---|---|
129
+ | "It's just a version tag, the maintainer wouldn't push something malicious to it" | A tag is exactly the reference an attacker (via a compromised maintainer account, or the maintainer's own compromised supply chain) can silently move; a commit SHA cannot be moved |
130
+ | "I'll just checkout the PR head so the build tests the actual change" | That is precisely the `pull_request_target` + untrusted-checkout combination that hands an attacker-controlled PR your base-repo secrets |
131
+ | "The PR title is just a string, it won't break the shell" | A title containing `"`, `` ` ``, or `$(...)` breaks out of the generated shell script the moment it is interpolated directly, regardless of how innocuous most titles look |
132
+ | "permissions: write-all is simpler than figuring out exactly what each job needs" | It hands every job in the file the most-privileged job's access, including jobs that only read — the extra few lines of per-job scoping is the actual fix, not a shortcut worth skipping |
133
+
134
+ ## Verification
135
+
136
+ Do not report the work done until all of the following hold:
137
+
138
+ - The trigger matches what the job actually needs (`pull_request`, not
139
+ `pull_request_target`, unless base-repo secrets/write access are
140
+ genuinely required).
141
+ - No `pull_request_target` job checks out and executes the pull request's
142
+ own head SHA/ref.
143
+ - Every third-party `uses:` action is pinned to a full commit SHA.
144
+ - No untrusted `${{ github.event.* }}`/CI variable is interpolated
145
+ directly into a `run:`/`script:` string.
146
+ - `permissions:` is scoped at the job level to only what each job needs,
147
+ with no workflow-level `write-all`.
@@ -0,0 +1,74 @@
1
+ {
2
+ "triggers": {
3
+ "positive": [
4
+ "Set up a workflow so our test suite runs automatically on incoming pull requests",
5
+ "I need pipeline stages in .gitlab-ci.yml for building, testing, and shipping the app",
6
+ "This CI job reinstalls dependencies every run -- can we speed it up with caching?",
7
+ "Multiple repos need the same build steps -- can we share one workflow definition?",
8
+ "The GITHUB_TOKEN in this workflow currently has no explicit scope -- lock it down",
9
+ "How do I keep our production deploy credentials from leaking to feature-branch pipelines?"
10
+ ],
11
+ "negative": [
12
+ "Review this Dockerfile for insecure base image usage",
13
+ "Add a Kubernetes deployment manifest with resource limits",
14
+ "Run a general OWASP security review across this codebase",
15
+ "Edit this YAML config file to add a new logging field",
16
+ "Write unit tests for this Python function",
17
+ "Review this TypeScript diff for missing null checks"
18
+ ]
19
+ },
20
+ "scenarios": [
21
+ {
22
+ "id": "least-privilege-permissions",
23
+ "prompt": "I'm adding a new job to this GitHub Actions workflow that needs to comment on the pull request. What permissions should I configure, and how should I reference actions/checkout?",
24
+ "strictness": "high",
25
+ "expected_behavior": [
26
+ {
27
+ "grader": "judge",
28
+ "rubric": "A correct answer scopes permissions at the job level to exactly what commenting needs (pull-requests: write, plus contents: read if the job also checks out code), explicitly rejects a workflow-level permissions: write-all or unscoped default, and states that actions/checkout should be pinned to a full commit SHA rather than a mutable tag.",
29
+ "pass_criteria": [
30
+ "States that permissions should be granted at the job level, naming pull-requests: write as the specific scope needed for commenting on the pull request.",
31
+ "Explicitly rejects a workflow-level permissions: write-all (or leaving permissions unscoped) as inappropriate for this change.",
32
+ "States that actions/checkout should be pinned to a full commit SHA, not a movable tag like @v4."
33
+ ],
34
+ "fail_criteria": [
35
+ "Recommends permissions: write-all (or an equivalent broad, unscoped grant) as the way to give the job comment access, instead of the specific job-level scope. Mentioning write-all only to warn against it is not a failure."
36
+ ]
37
+ }
38
+ ],
39
+ "calibration": {
40
+ "known_right": "Scope this at the job level, not the workflow level: add `permissions: { pull-requests: write, contents: read }` directly under this job (leave the workflow-level permissions at its narrower default, or permissions: {} if nothing else needs broader access) -- that grants exactly what commenting on the PR requires and nothing more for the rest of the file. For actions/checkout, reference it by its full commit SHA (e.g. `uses: actions/checkout@<40-char-sha>`, optionally with a `# v4.x.x` comment for readability) rather than `@v4` -- a tag can be moved to point at a different commit later, a SHA cannot.",
41
+ "known_wrong": "Easiest fix: set `permissions: write-all` at the top of the workflow so this job (and any future one) can comment, push, or do whatever it needs without you having to figure out the exact scope each time. Also fine to leave actions/checkout on @v4 since it's an official action.",
42
+ "vague": "You'll want to give the job the right permissions to comment and make sure the checkout action is pinned properly.",
43
+ "subtle_wrong": "Add `permissions: { contents: write, pull-requests: write }` at the workflow level since other jobs in this file might need similar access later and it's simpler to set once at the top; for actions/checkout, `@v4` is fine here since it's a first-party GitHub action maintained directly by GitHub, so the usual SHA-pinning concern about a compromised third party doesn't really apply."
44
+ },
45
+ "anti_patterns": ["write-all"]
46
+ },
47
+ {
48
+ "id": "safe-pr-trigger-choice",
49
+ "prompt": "This job builds and runs the test suite for incoming pull requests from any contributor, including forks. Which trigger should it use, and why?",
50
+ "strictness": "high",
51
+ "expected_behavior": [
52
+ {
53
+ "grader": "judge",
54
+ "rubric": "A correct answer recommends pull_request rather than pull_request_target for a job that only builds/tests a contribution, explaining that pull_request runs with the contributor's own (typically read-only) token and cannot reach base-repo secrets, while pull_request_target runs in the base repository's context with its secrets and write-level access even for fork-originated pull requests.",
55
+ "pass_criteria": [
56
+ "Recommends pull_request, not pull_request_target, as the trigger for this build/test job.",
57
+ "Explains that pull_request_target runs with base-repo secrets and write-level GITHUB_TOKEN access, which this job does not need and should not have for fork-originated code.",
58
+ "States that pull_request runs with the contributor's own (typically read-only) token, so it cannot reach base-repo secrets even for an untrusted fork."
59
+ ],
60
+ "fail_criteria": [
61
+ "Recommends pull_request_target for this job, or fails to explain that doing so would expose base-repo secrets/write access to fork-originated code. Mentioning pull_request_target only to explain why it is the wrong choice here is not a failure."
62
+ ]
63
+ }
64
+ ],
65
+ "calibration": {
66
+ "known_right": "Use pull_request, not pull_request_target, for this job. pull_request runs with the token scoped to the contributor's own fork context -- typically read-only and unable to reach this repository's own secrets -- which is exactly right for a job that only needs to build the code and run the test suite. pull_request_target, by contrast, runs in the base repository's context: it gets base-repo secrets and (unless narrowed) write-level access, even though the pull request that triggered it can come from an untrusted fork. There's no reason to take on that exposure just to build and test.",
67
+ "known_wrong": "Use pull_request_target so the job has consistent access to our secrets and can be reused later for jobs that do need them, even though right now it's just building and running tests.",
68
+ "vague": "You should pick whichever trigger is the safer option for pull requests from forks.",
69
+ "subtle_wrong": "pull_request_target is fine here as long as we're careful -- since this job only builds and tests and doesn't check out the fork's head SHA directly for anything sensitive, the base-repo secrets it has access to shouldn't actually be reachable from the fork's code in practice."
70
+ },
71
+ "anti_patterns": ["pull_request_target"]
72
+ }
73
+ ]
74
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "agents": [],
3
+ "note": "no pair -- honest DeepSeek deepseek-chat runner+judge gate (trials=10, strictness=high, flow 336) fails all 4 skills on trigger accuracy, never on behavior (every behavior scenario clears the 0.8 floor, mostly 1.0/1.0): dotnet-implementation TP 2/7 FP 1/8, dotnet-testing TP 4/7 FP 0/8, dotnet-code-review TP 3/7 FP 0/8, dotnet-build-fix TP 1/7 FP 0/8 (worst -- distinctive .NET vocabulary like NuGet/StyleCop/CS#### still did not route). Genuine routing weakness against an increasingly crowded catalog (12+ implement/test/review/build-fix category-mates across stacks), not an authoring defect -- stays experimental per flow 336's stack-pack-lessons.md rule against tuning descriptions to restate failing eval prompts."
4
+ }