@intentius/chant-lexicon-github 0.4.0 → 0.5.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "38ccfb873ff6b369d7e4bf2cff293c244468bc00a0c5d6f5016422ef00d7b3a7",
4
+ "manifest.json": "d00a49720e3c6f84ff3acc0744e4c1e664fd08346e48ce005b4e3dd9f05ea36a",
5
5
  "meta.json": "798c5f5f37b0174756d2451299acfdc95c014f11d06d32b9153bbdfa9f3a580c",
6
6
  "types/index.d.ts": "39c0791f0e58025bcef82e0f7a92240508f899fc2771d5dd51b2369b4d330f13",
7
7
  "rules/deprecated-action-version.ts": "d41e6e532ab7f623af1bee4ac5279fcb2baada7defa1c5d022a5bc71983e8797",
@@ -62,10 +62,10 @@
62
62
  "rules/gha056.ts": "73fa2eea80504522cb53db1e48b36e97ede0eeb7b60ed531a476d2f43d3746ae",
63
63
  "rules/gha057.ts": "78e896232d6f5c3e4c1bab873eae97960dbb8a0c108f1546f32d943aafc41a91",
64
64
  "rules/gha058.ts": "cdcb60916e3ce091b0e6c73295f24b77fca1480fb0a5907ae6d1fc5b1805f794",
65
- "rules/yaml-helpers.ts": "74b430ec4810135be1e5dcd198b907c2cd179a9cc5a339041b6dab31edb4d2a0",
65
+ "rules/yaml-helpers.ts": "40eaa2ed1c8d823dd33cc3355382f09875eb848363b2e5a7269ec50a0ea913b9",
66
66
  "skills/chant-github.md": "f3707f09634be4bbb45a6be279f17bb27f275b98e6d3337cc8872c1623ba050f",
67
67
  "skills/chant-github-patterns.md": "bb3abef289a8fdfcf07d6bb2d7289dcb2f38bc0cb0321ea320b78b45a6f548c0",
68
68
  "skills/chant-github-security.md": "aab111cb0871cad30281ce48d7da23663689619351029219e2be019a1a61e394"
69
69
  },
70
- "composite": "4df50ecc6ef70b761aaaae2acf70169357ae9a2351cf0a881c75ea817a3df94a"
70
+ "composite": "3c89124bc32b0e59ed9ce3b0fcdfa9ee5140445e8557b851e96032fae902cf52"
71
71
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "GitHub",
6
6
  "intrinsics": [
@@ -86,7 +86,7 @@ export function extractJobs(yaml: string): Map<string, ParsedJob> {
86
86
  const stepNameMatch = stepEntry.match(/name:\s+(.+)$/m);
87
87
  if (usesMatch || runMatch) {
88
88
  job.steps.push({
89
- uses: usesMatch?.[1]?.trim().replace(/^'|'$/g, ""),
89
+ uses: usesMatch?.[1] ? stripUsesComment(usesMatch[1].trim().replace(/^'|'$/g, "")) : undefined,
90
90
  run: runMatch?.[1]?.trim(),
91
91
  name: stepNameMatch?.[1]?.trim().replace(/^'|'$/g, ""),
92
92
  });
@@ -453,7 +453,17 @@ export function grantsWrite(perms: PermissionsValue): boolean {
453
453
  * Returns undefined for local (`./`, `../`) and `docker://` references, which
454
454
  * are not GitHub action repository references.
455
455
  */
456
- export function parseActionUses(uses: string): { owner: string; repo: string; slug: string; gitRef: string } | undefined {
456
+ /**
457
+ * Strip a trailing inline YAML comment from a `uses:` value. A `uses` ref
458
+ * cannot contain whitespace, so `<ref> # v1.2.3` (the recommended SHA-pin
459
+ * style) is safe to trim back to `<ref>`.
460
+ */
461
+ export function stripUsesComment(uses: string): string {
462
+ return uses.replace(/\s+#.*$/, "").trim();
463
+ }
464
+
465
+ export function parseActionUses(rawUses: string): { owner: string; repo: string; slug: string; gitRef: string } | undefined {
466
+ const uses = stripUsesComment(rawUses);
457
467
  if (uses.startsWith("./") || uses.startsWith("../") || uses.startsWith("docker://")) return undefined;
458
468
  const at = uses.lastIndexOf("@");
459
469
  const path = at === -1 ? uses : uses.slice(0, at);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-github",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "GitHub Actions lexicon for chant — declarative IaC in TypeScript",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -50,6 +50,21 @@ jobs:
50
50
  expect(diags).toHaveLength(0);
51
51
  });
52
52
 
53
+ test("does not flag a SHA pin with a trailing version comment", () => {
54
+ const yaml = `name: CI
55
+ on:
56
+ push:
57
+ jobs:
58
+ build:
59
+ runs-on: ubuntu-latest
60
+ steps:
61
+ - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
62
+ - run: echo test
63
+ `;
64
+ const diags = gha021.check(makeCtx(yaml));
65
+ expect(diags).toHaveLength(0);
66
+ });
67
+
53
68
  test("does not flag non-checkout actions", () => {
54
69
  const yaml = `name: CI
55
70
  on:
@@ -64,6 +64,21 @@ jobs:
64
64
  expect(diags).toHaveLength(0);
65
65
  });
66
66
 
67
+ test("does not flag a SHA pin with a trailing version comment", () => {
68
+ const yaml = `name: CI
69
+ on:
70
+ push:
71
+ jobs:
72
+ build:
73
+ runs-on: ubuntu-latest
74
+ steps:
75
+ - uses: actions/setup-node@1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b # v4.0.2
76
+ - run: echo build
77
+ `;
78
+ const diags = gha029.check(makeCtx(yaml));
79
+ expect(diags).toHaveLength(0);
80
+ });
81
+
67
82
  test("does not flag actions/checkout (owned by GHA021)", () => {
68
83
  const yaml = `name: CI
69
84
  on:
@@ -86,7 +86,7 @@ export function extractJobs(yaml: string): Map<string, ParsedJob> {
86
86
  const stepNameMatch = stepEntry.match(/name:\s+(.+)$/m);
87
87
  if (usesMatch || runMatch) {
88
88
  job.steps.push({
89
- uses: usesMatch?.[1]?.trim().replace(/^'|'$/g, ""),
89
+ uses: usesMatch?.[1] ? stripUsesComment(usesMatch[1].trim().replace(/^'|'$/g, "")) : undefined,
90
90
  run: runMatch?.[1]?.trim(),
91
91
  name: stepNameMatch?.[1]?.trim().replace(/^'|'$/g, ""),
92
92
  });
@@ -453,7 +453,17 @@ export function grantsWrite(perms: PermissionsValue): boolean {
453
453
  * Returns undefined for local (`./`, `../`) and `docker://` references, which
454
454
  * are not GitHub action repository references.
455
455
  */
456
- export function parseActionUses(uses: string): { owner: string; repo: string; slug: string; gitRef: string } | undefined {
456
+ /**
457
+ * Strip a trailing inline YAML comment from a `uses:` value. A `uses` ref
458
+ * cannot contain whitespace, so `<ref> # v1.2.3` (the recommended SHA-pin
459
+ * style) is safe to trim back to `<ref>`.
460
+ */
461
+ export function stripUsesComment(uses: string): string {
462
+ return uses.replace(/\s+#.*$/, "").trim();
463
+ }
464
+
465
+ export function parseActionUses(rawUses: string): { owner: string; repo: string; slug: string; gitRef: string } | undefined {
466
+ const uses = stripUsesComment(rawUses);
457
467
  if (uses.startsWith("./") || uses.startsWith("../") || uses.startsWith("docker://")) return undefined;
458
468
  const at = uses.lastIndexOf("@");
459
469
  const path = at === -1 ? uses : uses.slice(0, at);