@rightkit/git 0.2.3 → 0.2.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.
package/README.md CHANGED
@@ -38,4 +38,4 @@ Node builtins only; no runtime dependencies.
38
38
 
39
39
  ## Profiles
40
40
 
41
- `profile` defaults to `node`. `rust-hybrid` requires `ci`, accepts optional `release-candidate`, installs pinned Node plus `rustup stable`, then runs product-owned package scripts. Candidate configuration is `{ buildScript, checkScript, artifactRoot }`; RightGit passes an isolated `RIGHT_GIT_ARTIFACT_ROOT`, checks it, & uploads it as an unsigned handoff. It never signs, finalizes, publishes releases, or receives signing credentials.
41
+ `profile` defaults to `node`. `rust-hybrid` requires `ci`, accepts optional `release-candidate`, installs pinned Node plus Rust, then runs product-owned package scripts. Candidate configuration is `{ buildScript, checkScript, artifactRoot, os }`; `os` selects supported release hosts from main matrix. RightGit passes isolated `RIGHT_GIT_ARTIFACT_ROOT`, checks it, & uploads it as an unsigned handoff. It never signs, finalizes, publishes releases, or receives signing credentials.
package/manifest.mjs CHANGED
@@ -141,7 +141,7 @@ export function validateManifest(manifest) {
141
141
  errors.push("candidate must be an object");
142
142
  } else {
143
143
  for (const key of Object.keys(candidate)) {
144
- if (!["buildScript", "checkScript", "artifactRoot"].includes(key)) errors.push(`unknown candidate field: ${key}`);
144
+ if (!["buildScript", "checkScript", "artifactRoot", "os"].includes(key)) errors.push(`unknown candidate field: ${key}`);
145
145
  }
146
146
  for (const key of ["buildScript", "checkScript"]) {
147
147
  if (typeof candidate[key] !== "string" || !PACKAGE_SCRIPT_RE.test(candidate[key])) {
@@ -151,6 +151,11 @@ export function validateManifest(manifest) {
151
151
  if (typeof candidate.artifactRoot !== "string" || !GATE_PATH_RE.test(candidate.artifactRoot)) {
152
152
  errors.push("candidate.artifactRoot must be one safe relative path");
153
153
  }
154
+ if (!Array.isArray(candidate.os) || candidate.os.length === 0 || candidate.os.some((value) => typeof value !== "string" || !SAFE_MATRIX_VALUE_RE.test(value))) {
155
+ errors.push("candidate.os must be a non-empty array of safe runner labels");
156
+ } else if (candidate.os.some((value) => !manifest.matrix?.os?.includes(value))) {
157
+ errors.push("candidate.os entries must also exist in matrix.os");
158
+ }
154
159
  }
155
160
  }
156
161
  if (profile === "rust-hybrid" && lanes.includes("release-candidate") && candidate === undefined) {
@@ -315,6 +320,7 @@ export function buildRenderContext(manifest, repoPath) {
315
320
  CANDIDATE_BUILD_SCRIPT: manifest.candidate?.buildScript,
316
321
  CANDIDATE_CHECK_SCRIPT: manifest.candidate?.checkScript,
317
322
  CANDIDATE_ARTIFACT_ROOT: manifest.candidate?.artifactRoot,
323
+ CANDIDATE_OS_MATRIX: yamlFlowStringList(manifest.candidate?.os ?? manifest.matrix.os),
318
324
  };
319
325
 
320
326
  if (manifest.publish?.npm) {
@@ -88,12 +88,13 @@
88
88
  },
89
89
  "candidate": {
90
90
  "type": "object",
91
- "required": ["buildScript", "checkScript", "artifactRoot"],
91
+ "required": ["buildScript", "checkScript", "artifactRoot", "os"],
92
92
  "additionalProperties": false,
93
93
  "properties": {
94
94
  "buildScript": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9:_-]*$" },
95
95
  "checkScript": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9:_-]*$" },
96
- "artifactRoot": { "type": "string", "pattern": "^(?!.*\\.\\.)(?!.*\\s)[A-Za-z0-9][A-Za-z0-9._/-]*$" }
96
+ "artifactRoot": { "type": "string", "pattern": "^(?!.*\\.\\.)(?!.*\\s)[A-Za-z0-9][A-Za-z0-9._/-]*$" },
97
+ "os": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } }
97
98
  }
98
99
  }
99
100
  }
package/manifest.test.mjs CHANGED
@@ -26,11 +26,12 @@ test("rust-hybrid supports ci plus a configured unsigned release-candidate lane"
26
26
  const candidate = {
27
27
  ...valid,
28
28
  lanes: ["ci", "release-candidate"],
29
- candidate: { buildScript: "ci:candidate", checkScript: "ci:candidate-check", artifactRoot: "legion-unsigned" },
29
+ candidate: { buildScript: "ci:candidate", checkScript: "ci:candidate-check", artifactRoot: "legion-unsigned", os: ["ubuntu-latest"] },
30
30
  };
31
31
  assert.equal(validateManifest(candidate).valid, true);
32
32
  assert.equal(validateManifest({ ...candidate, candidate: { ...candidate.candidate, buildScript: "echo unsafe" } }).valid, false);
33
33
  assert.equal(validateManifest({ ...candidate, candidate: { ...candidate.candidate, artifactRoot: "../escape" } }).valid, false);
34
+ assert.equal(validateManifest({ ...candidate, candidate: { ...candidate.candidate, os: ["windows-latest"] } }).valid, false);
34
35
  });
35
36
 
36
37
  test("rejects non-object input", () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rightkit/git",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Public-repo-only GitHub Actions workflow layer: templates, visibility gate, sync/drift/adopt/uninstall for right-git.",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "type": "module",
package/render.test.mjs CHANGED
@@ -46,6 +46,7 @@ test("rust-hybrid ci renders its pinned package manager and gate", () => {
46
46
  const manifest = { ...FULL_MANIFEST, lanes: ["ci"], profile: "rust-hybrid", gate: { path: "scripts/gate.sh" }, templateVersion: "1.1.0" };
47
47
  const content = renderTemplate(fs.readFileSync(path.join(templatesDir, "profiles/rust-hybrid/ci.yml"), "utf8"), buildRenderContext(manifest, "/repos/widgets"));
48
48
  assert.match(content, /uses: pnpm\/action-setup@[a-f0-9]{40}/);
49
+ assert.match(content, /^name: widgets-ci$/m);
49
50
  assert.match(content, /version: 11\.24\.0/);
50
51
  assert.match(content, /toolchain: 1\.98\.0/);
51
52
  assert.match(content, /bash \.\/scripts\/gate\.sh/);
@@ -57,7 +58,7 @@ test("rust-hybrid release candidate renders product scripts, artifact handoff, a
57
58
  lanes: ["ci", "release-candidate"],
58
59
  profile: "rust-hybrid",
59
60
  gate: { path: "scripts/gate.sh" },
60
- candidate: { buildScript: "ci:candidate", checkScript: "ci:candidate-check", artifactRoot: "widgets-unsigned" },
61
+ candidate: { buildScript: "ci:candidate", checkScript: "ci:candidate-check", artifactRoot: "widgets-unsigned", os: ["macos-latest", "windows-latest"] },
61
62
  templateVersion: "1.2.0",
62
63
  };
63
64
  const content = renderTemplate(
@@ -67,6 +68,7 @@ test("rust-hybrid release candidate renders product scripts, artifact handoff, a
67
68
  assert.match(content, /pnpm run ci:candidate/);
68
69
  assert.match(content, /pnpm run ci:candidate-check/);
69
70
  assert.match(content, /RIGHT_GIT_ARTIFACT_ROOT/);
71
+ assert.match(content, /os: \["macos-latest", "windows-latest"\]/);
70
72
  assert.match(content, /actions\/upload-artifact@[a-f0-9]{40}/);
71
73
  assert.doesNotMatch(content, /secrets\.|AZURE_|APPLE_|certificate|private.key/i);
72
74
  });
@@ -1,6 +1,6 @@
1
1
  # Managed by right-git — do not hand-edit. Run `right-git sync` to update.
2
2
  # Template: profiles/rust-hybrid/ci.yml | Template version: ${TEMPLATE_VERSION}
3
- name: legion-ci
3
+ name: ${ARTIFACT_PREFIX}-ci
4
4
  on:
5
5
  pull_request:
6
6
  push:
@@ -21,7 +21,7 @@ jobs:
21
21
  strategy:
22
22
  fail-fast: false
23
23
  matrix:
24
- os: ${OS_MATRIX}
24
+ os: ${CANDIDATE_OS_MATRIX}
25
25
  node: ${NODE_MATRIX}
26
26
  runs-on: ${{ matrix.os }}
27
27
  steps: