@intentius/chant-lexicon-github 0.0.18 → 0.0.22

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 (61) hide show
  1. package/dist/integrity.json +14 -4
  2. package/dist/manifest.json +1 -1
  3. package/dist/rules/gha020.ts +40 -0
  4. package/dist/rules/gha021.ts +48 -0
  5. package/dist/rules/gha022.ts +50 -0
  6. package/dist/rules/gha023.ts +44 -0
  7. package/dist/rules/gha024.ts +42 -0
  8. package/dist/rules/gha025.ts +42 -0
  9. package/dist/rules/gha026.ts +40 -0
  10. package/dist/rules/gha027.ts +57 -0
  11. package/dist/rules/gha028.ts +37 -0
  12. package/dist/skills/chant-github.md +1 -1
  13. package/dist/skills/github-actions-security.md +87 -0
  14. package/package.json +20 -2
  15. package/src/codegen/docs.test.ts +19 -0
  16. package/src/codegen/generate.test.ts +12 -0
  17. package/src/codegen/package.test.ts +8 -0
  18. package/src/coverage.test.ts +23 -0
  19. package/src/import/roundtrip.test.ts +206 -0
  20. package/src/lint/post-synth/gha006.test.ts +56 -0
  21. package/src/lint/post-synth/gha009.test.ts +56 -0
  22. package/src/lint/post-synth/gha011.test.ts +61 -0
  23. package/src/lint/post-synth/gha017.test.ts +51 -0
  24. package/src/lint/post-synth/gha018.test.ts +66 -0
  25. package/src/lint/post-synth/gha019.test.ts +66 -0
  26. package/src/lint/post-synth/gha020.test.ts +66 -0
  27. package/src/lint/post-synth/gha020.ts +40 -0
  28. package/src/lint/post-synth/gha021.test.ts +67 -0
  29. package/src/lint/post-synth/gha021.ts +48 -0
  30. package/src/lint/post-synth/gha022.test.ts +45 -0
  31. package/src/lint/post-synth/gha022.ts +50 -0
  32. package/src/lint/post-synth/gha023.test.ts +52 -0
  33. package/src/lint/post-synth/gha023.ts +44 -0
  34. package/src/lint/post-synth/gha024.test.ts +67 -0
  35. package/src/lint/post-synth/gha024.ts +42 -0
  36. package/src/lint/post-synth/gha025.test.ts +65 -0
  37. package/src/lint/post-synth/gha025.ts +42 -0
  38. package/src/lint/post-synth/gha026.test.ts +65 -0
  39. package/src/lint/post-synth/gha026.ts +40 -0
  40. package/src/lint/post-synth/gha027.test.ts +48 -0
  41. package/src/lint/post-synth/gha027.ts +57 -0
  42. package/src/lint/post-synth/gha028.test.ts +48 -0
  43. package/src/lint/post-synth/gha028.ts +37 -0
  44. package/src/lint/rules/deprecated-action-version.test.ts +26 -0
  45. package/src/lint/rules/detect-secrets.test.ts +25 -0
  46. package/src/lint/rules/extract-inline-structs.test.ts +25 -0
  47. package/src/lint/rules/file-job-limit.test.ts +28 -0
  48. package/src/lint/rules/job-timeout.test.ts +31 -0
  49. package/src/lint/rules/missing-recommended-inputs.test.ts +26 -0
  50. package/src/lint/rules/no-hardcoded-secrets.test.ts +31 -0
  51. package/src/lint/rules/no-raw-expressions.test.ts +31 -0
  52. package/src/lint/rules/suggest-cache.test.ts +25 -0
  53. package/src/lint/rules/use-condition-builders.test.ts +31 -0
  54. package/src/lint/rules/use-matrix-builder.test.ts +25 -0
  55. package/src/lint/rules/use-typed-actions.test.ts +39 -0
  56. package/src/lint/rules/validate-concurrency.test.ts +31 -0
  57. package/src/plugin.test.ts +1 -1
  58. package/src/plugin.ts +30 -2
  59. package/src/skills/github-actions-security.md +87 -0
  60. package/src/validate.ts +14 -1
  61. package/src/variables.test.ts +48 -0
@@ -0,0 +1,87 @@
1
+ ---
2
+ skill: github-actions-security
3
+ description: GitHub Actions security best practices — secret scanning, OIDC, permissions hardening, supply chain security
4
+ ---
5
+
6
+ # GitHub Actions Security Playbook
7
+
8
+ ## Permissions Hardening
9
+
10
+ Always set the minimum required permissions at the workflow level:
11
+
12
+ ```typescript
13
+ new Workflow({
14
+ name: "CI",
15
+ on: { push: { branches: ["main"] } },
16
+ permissions: { contents: "read" },
17
+ });
18
+ ```
19
+
20
+ For deployments that need write access, scope it to the job:
21
+
22
+ ```typescript
23
+ new Job({
24
+ "runs-on": "ubuntu-latest",
25
+ permissions: { contents: "read", "id-token": "write" },
26
+ steps: [...],
27
+ });
28
+ ```
29
+
30
+ ## Pin Actions by SHA
31
+
32
+ Never use mutable tags like `@v4`. Pin to a full commit SHA:
33
+
34
+ ```typescript
35
+ new Step({
36
+ uses: "actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11", // v4.1.1
37
+ })
38
+ ```
39
+
40
+ ## OIDC for Cloud Providers
41
+
42
+ Use OpenID Connect instead of long-lived secrets:
43
+
44
+ ```typescript
45
+ // AWS
46
+ new Step({
47
+ uses: "aws-actions/configure-aws-credentials@v4",
48
+ with: {
49
+ "role-to-assume": "arn:aws:iam::123456789012:role/deploy",
50
+ "aws-region": "us-east-1",
51
+ },
52
+ })
53
+ ```
54
+
55
+ ## Secret Scanning
56
+
57
+ - Never echo secrets in `run:` steps
58
+ - Use `environment` protection rules for production secrets
59
+ - Rotate secrets regularly and audit access logs
60
+
61
+ ## Supply Chain Security
62
+
63
+ - Use `permissions: {}` (empty) as a baseline, then grant only what each job needs
64
+ - Avoid `pull_request_target` with `actions/checkout` (code injection risk)
65
+ - Use Dependabot or Renovate to keep action versions current
66
+ - Add `concurrency` blocks to prevent parallel deploys
67
+
68
+ ## Concurrency Control
69
+
70
+ ```typescript
71
+ new Concurrency({
72
+ group: "${{ github.workflow }}-${{ github.ref }}",
73
+ "cancel-in-progress": true,
74
+ })
75
+ ```
76
+
77
+ ## Job Timeouts
78
+
79
+ Always set timeouts to prevent runaway jobs:
80
+
81
+ ```typescript
82
+ new Job({
83
+ "runs-on": "ubuntu-latest",
84
+ "timeout-minutes": 30,
85
+ steps: [...],
86
+ });
87
+ ```
package/src/validate.ts CHANGED
@@ -2,7 +2,8 @@
2
2
  * Validate generated lexicon-github artifacts.
3
3
  */
4
4
 
5
- import { dirname } from "path";
5
+ import { dirname, join } from "path";
6
+ import { existsSync } from "fs";
6
7
  import { fileURLToPath } from "url";
7
8
  import { validateLexiconArtifacts, type ValidateResult } from "@intentius/chant/codegen/validate";
8
9
 
@@ -23,6 +24,18 @@ const REQUIRED_NAMES = [
23
24
  */
24
25
  export async function validate(opts?: { basePath?: string }): Promise<ValidateResult> {
25
26
  const basePath = opts?.basePath ?? dirname(dirname(fileURLToPath(import.meta.url)));
27
+ const generatedDir = join(basePath, "src", "generated");
28
+
29
+ if (!existsSync(generatedDir)) {
30
+ return {
31
+ success: false,
32
+ checks: [{
33
+ name: "generated-dir",
34
+ ok: false,
35
+ error: 'src/generated/ not found — run "chant dev generate" first',
36
+ }],
37
+ };
38
+ }
26
39
 
27
40
  return validateLexiconArtifacts({
28
41
  lexiconJsonFilename: "lexicon-github.json",
@@ -0,0 +1,48 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { GitHub, Runner } from "./variables";
3
+
4
+ describe("GitHub context variables", () => {
5
+ test("GitHub.Ref resolves to github.ref expression", () => {
6
+ expect(GitHub.Ref.toString()).toBe("${{ github.ref }}");
7
+ });
8
+
9
+ test("GitHub.Sha resolves to github.sha expression", () => {
10
+ expect(GitHub.Sha.toString()).toBe("${{ github.sha }}");
11
+ });
12
+
13
+ test("GitHub.Actor resolves to github.actor expression", () => {
14
+ expect(GitHub.Actor.toString()).toBe("${{ github.actor }}");
15
+ });
16
+
17
+ test("GitHub has all expected properties", () => {
18
+ const keys = Object.keys(GitHub);
19
+ expect(keys).toContain("Ref");
20
+ expect(keys).toContain("Sha");
21
+ expect(keys).toContain("Actor");
22
+ expect(keys).toContain("Repository");
23
+ expect(keys).toContain("EventName");
24
+ expect(keys).toContain("Token");
25
+ expect(keys).toContain("Workspace");
26
+ expect(keys.length).toBe(25);
27
+ });
28
+ });
29
+
30
+ describe("Runner context variables", () => {
31
+ test("Runner.Os resolves to runner.os expression", () => {
32
+ expect(Runner.Os.toString()).toBe("${{ runner.os }}");
33
+ });
34
+
35
+ test("Runner.Arch resolves to runner.arch expression", () => {
36
+ expect(Runner.Arch.toString()).toBe("${{ runner.arch }}");
37
+ });
38
+
39
+ test("Runner has all expected properties", () => {
40
+ const keys = Object.keys(Runner);
41
+ expect(keys).toContain("Os");
42
+ expect(keys).toContain("Arch");
43
+ expect(keys).toContain("Name");
44
+ expect(keys).toContain("Temp");
45
+ expect(keys).toContain("ToolCache");
46
+ expect(keys.length).toBe(5);
47
+ });
48
+ });