@raishin/vanguard-frontier-agentic 3.1.0 → 3.1.1

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.
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Cloud and zero-trust agentic workflow marketplace for skills, agents, rules, MCP references, and compliance-aware architecture.",
9
- "version": "3.1.0"
9
+ "version": "3.1.1"
10
10
  },
11
11
  "plugins": [
12
12
  {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vanguard-frontier-agentic",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "Cloud and zero-trust agentic workflow marketplace for skills, agents, rules, MCP references, and compliance-aware architecture.",
5
5
  "author": {
6
6
  "name": "Raishin",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vanguard-frontier-agentic",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "Cloud and zero-trust agentic workflow marketplace for skills, agents, rules, MCP references, and compliance-aware architecture.",
5
5
  "author": {
6
6
  "name": "Raishin",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://raw.githubusercontent.com/github/copilot-cli/main/schemas/marketplace.schema.json",
3
3
  "name": "vanguard-frontier-agentic",
4
4
  "description": "Curated marketplace for cloud, zero-trust, and compliance-aware AI workflows — agents, skills, and rules spanning cloud, security, ERP, and platform providers.",
5
- "version": "3.1.0",
5
+ "version": "3.1.1",
6
6
  "owner": {
7
7
  "name": "Raishin",
8
8
  "url": "https://github.com/Raishin"
@@ -28968,7 +28968,7 @@
28968
28968
  },
28969
28969
  {
28970
28970
  "tree": "scripts",
28971
- "aggregate_sha256": "db4bd93be8066b5265477e477704183162962e9f0166fd3fe63d3e1faa6f38b3",
28971
+ "aggregate_sha256": "ce5d7d297fec4a8fb096413d766d941200fe6568f0f7e1e6f947f473efcdeadc",
28972
28972
  "files": [
28973
28973
  {
28974
28974
  "path": "scripts/apply-skill-allowed-tools.py",
@@ -28982,8 +28982,8 @@
28982
28982
  },
28983
28983
  {
28984
28984
  "path": "scripts/export-marketplace-agents.mjs",
28985
- "sha256": "c79e3e7decbb3b9ba77f33e05145a22892bcfbf6a15231a74191a1d60e47cbac",
28986
- "bytes": 27654
28985
+ "sha256": "0624a3ae7d7aa250985dd5e3763a1f9266bc46722c7f5f7620f0859dccf38f37",
28986
+ "bytes": 28726
28987
28987
  },
28988
28988
  {
28989
28989
  "path": "scripts/gen_azure_live_guards.py",
@@ -29385,7 +29385,7 @@
29385
29385
  },
29386
29386
  {
29387
29387
  "tree": "plugins",
29388
- "aggregate_sha256": "dbfc79627e60a0cdab406d60ff983cbea890a062926f6736a319c9eb1aea09af",
29388
+ "aggregate_sha256": "9bcbf79b42023ffea07ac35e7d6a57f5b945c05afdced8cda7ae50cdcab53339",
29389
29389
  "files": [
29390
29390
  {
29391
29391
  "path": "plugins/cross-platform-agent-template/.codex-plugin/plugin.json",
@@ -29399,7 +29399,7 @@
29399
29399
  },
29400
29400
  {
29401
29401
  "path": "plugins/vanguard-frontier-agentic/.codex-plugin/plugin.json",
29402
- "sha256": "dc0b9c5aae471a7bbd0647ec54b866c8151c346c1fe9479d07293f57f9aa8327",
29402
+ "sha256": "4a5ac9ae2f5a81204afcb5c1ddd8157fd0866dc64bf4b6bcb519dc10192c4119",
29403
29403
  "bytes": 1875
29404
29404
  },
29405
29405
  {
@@ -29416,7 +29416,7 @@
29416
29416
  },
29417
29417
  {
29418
29418
  "tree": ".claude-plugin",
29419
- "aggregate_sha256": "55485289fad3d6ff7e17af2e5b51dd7c418797697f445178d800297431ba9fb2",
29419
+ "aggregate_sha256": "a7c6e0414abf134bf22d1be821262175e1f23d942a4c8d238f91e9c902b792c4",
29420
29420
  "files": [
29421
29421
  {
29422
29422
  "path": ".claude-plugin/README.md",
@@ -29425,19 +29425,19 @@
29425
29425
  },
29426
29426
  {
29427
29427
  "path": ".claude-plugin/marketplace.json",
29428
- "sha256": "e751e34703e505e1c19e28979626334b970fef59acbe0d4933aef8ce00813953",
29428
+ "sha256": "6cac558ae8e51168149f96771c2ae1b350e7447b3583c16368d24f32fb4954aa",
29429
29429
  "bytes": 834
29430
29430
  },
29431
29431
  {
29432
29432
  "path": ".claude-plugin/plugin.json",
29433
- "sha256": "0a8937a0e894990c5e09c0886b48d6aec9e2a6a7e207bcd7f56f4ab1f30da501",
29433
+ "sha256": "dae34758b5252059c18d4d2c20ed6d16a09eb478541fa79985b3f27ab0ea7d30",
29434
29434
  "bytes": 54712
29435
29435
  }
29436
29436
  ]
29437
29437
  },
29438
29438
  {
29439
29439
  "tree": ".cursor-plugin",
29440
- "aggregate_sha256": "615022c865da4130652ad14cf46dac7486d256a65db611f910ac3940ea50fca1",
29440
+ "aggregate_sha256": "ca39c896a869dd5f5a7c3c6bf2b630ed13fe4749eca55dc23fad24eeecdbbb95",
29441
29441
  "files": [
29442
29442
  {
29443
29443
  "path": ".cursor-plugin/README.md",
@@ -29446,14 +29446,14 @@
29446
29446
  },
29447
29447
  {
29448
29448
  "path": ".cursor-plugin/plugin.json",
29449
- "sha256": "c97d139681e69a3d0ba17ab89ed1a527214065f03e57a683a2aa423d1d201e87",
29449
+ "sha256": "2363eda3be3e94f7aa2b0ebf13dc3de398862fe0c6c083a66566f8e9e9a911e7",
29450
29450
  "bytes": 51718
29451
29451
  }
29452
29452
  ]
29453
29453
  },
29454
29454
  {
29455
29455
  "tree": ".github/plugin",
29456
- "aggregate_sha256": "7315474adafd807d9fdea7832cceb4f3ecdcda6b62cbac1b0fd6ea1617a431f2",
29456
+ "aggregate_sha256": "0e0b126f84993b25cacefd2e3b2a0822a9373927af4e5780623e837eac9c673d",
29457
29457
  "files": [
29458
29458
  {
29459
29459
  "path": ".github/plugin/README.md",
@@ -29462,7 +29462,7 @@
29462
29462
  },
29463
29463
  {
29464
29464
  "path": ".github/plugin/marketplace.json",
29465
- "sha256": "0132338c721fa65f3770f18d78a161c203af6c38c0b14f83326dbcb8016a2945",
29465
+ "sha256": "d6c094a33713c48cb3ea799d927b90168fb8c9f7f4e57089ec3cb2464b04b1c8",
29466
29466
  "bytes": 770
29467
29467
  }
29468
29468
  ]
@@ -29485,7 +29485,7 @@
29485
29485
  },
29486
29486
  {
29487
29487
  "tree": "tests",
29488
- "aggregate_sha256": "8382df613db41b771c34920817ec5891475cd8e99cff5e1e6f2b8ddb57050cfb",
29488
+ "aggregate_sha256": "f4056e5dacbb3c0e960409c6065a627d1cadc32ce69019a5183563328d6f0ce5",
29489
29489
  "files": [
29490
29490
  {
29491
29491
  "path": "tests/AGENTS.md",
@@ -37059,8 +37059,8 @@
37059
37059
  },
37060
37060
  {
37061
37061
  "path": "tests/test-vfa-export-coverage.test.mjs",
37062
- "sha256": "d9ba3f88b05a05f433e1f9750047ae88d29263e3206c05829b9190611fc601c1",
37063
- "bytes": 45467
37062
+ "sha256": "a054c8b1e0acc8e96da9f99f7442aa7396858e46d0894c8e6f0a010119c798ea",
37063
+ "bytes": 46776
37064
37064
  },
37065
37065
  {
37066
37066
  "path": "tests/validate-agent-frontmatter-schema.py",
@@ -37213,8 +37213,8 @@
37213
37213
  },
37214
37214
  {
37215
37215
  "path": "package.json",
37216
- "sha256": "3f531aefe46a9d2b7482c3527b6f2e7d0eb44509908684f481479aef40f1d4ce",
37217
- "bytes": 5933
37216
+ "sha256": "3c58dd28c3ae02d94893f352843839c578d4583793841d042d8c2f9a25473afd",
37217
+ "bytes": 5934
37218
37218
  },
37219
37219
  {
37220
37220
  "path": ".releaserc.js",
@@ -37222,5 +37222,5 @@
37222
37222
  "bytes": 8340
37223
37223
  }
37224
37224
  ],
37225
- "aggregate_sha256": "9ff94ce2ca1a8c12f1f0c8d5447928d929238653af00ad4858b58990a39c6fb1"
37225
+ "aggregate_sha256": "6b52cc932c71df7ec6143148489857d4f876392197c9026e529504cb899faead"
37226
37226
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raishin/vanguard-frontier-agentic",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "Cloud and zero-trust agentic workflow marketplace for skills, agents, rules, MCP references, and compliance-aware architecture.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -85,10 +85,10 @@
85
85
  "@semantic-release/commit-analyzer": "13.0.1",
86
86
  "@semantic-release/exec": "7.1.0",
87
87
  "@semantic-release/git": "10.0.1",
88
- "@semantic-release/github": "12.0.8",
88
+ "@semantic-release/github": "12.0.9",
89
89
  "@semantic-release/npm": "^13.1.5",
90
90
  "@semantic-release/release-notes-generator": "14.1.1",
91
- "conventional-changelog-conventionalcommits": "9.3.1",
91
+ "conventional-changelog-conventionalcommits": "10.2.1",
92
92
  "fast-check": "^4.7.0",
93
93
  "semantic-release": "25.0.5"
94
94
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vanguard-frontier-agentic",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "Curated marketplace for cloud and zero-trust AI workflows. 331 agents, 286 skills, and rules across AWS, Azure, OCI, GCP, Alibaba Cloud, Huawei Cloud, Kubernetes, and Terraform.",
5
5
  "author": {
6
6
  "name": "Raishin",
@@ -273,16 +273,6 @@ function ensurePlatform(platform) {
273
273
  }
274
274
 
275
275
  function assertWithin(parent, child, label) {
276
- // Lexical containment check — path.resolve() is purely string-based and does
277
- // NOT follow symlinks. This guards against traversal strings (../../) and
278
- // metadata.json with absolute paths outside the repo.
279
- //
280
- // Residual TOCTOU: if an adversary races to create a symlink at `child`
281
- // AFTER this check but BEFORE the actual write, the symlink target would be
282
- // written to. copyFile()/copySkillTree() use lstatSync on source AND
283
- // destination to detect pre-existing symlinks, which closes the window for
284
- // the common case. A fully TOCTOU-proof solution requires O_NOFOLLOW at the
285
- // kernel level, which is not exposed by Node.js fs APIs.
286
276
  const resolvedParent = path.resolve(parent);
287
277
  const resolvedChild = path.resolve(child);
288
278
  const sep = path.sep;
@@ -295,6 +285,47 @@ function assertWithin(parent, child, label) {
295
285
  }
296
286
  }
297
287
 
288
+ function assertNoSymlinkAncestor(parent, child, label) {
289
+ assertWithin(parent, child, label);
290
+
291
+ const resolvedParent = path.resolve(parent);
292
+ const resolvedChild = path.resolve(child);
293
+ const relativeParent = path.dirname(path.relative(resolvedParent, resolvedChild));
294
+ if (!relativeParent || relativeParent === ".") return;
295
+
296
+ let current = resolvedParent;
297
+ for (const part of relativeParent.split(path.sep)) {
298
+ current = path.join(current, part);
299
+ let stat;
300
+ try {
301
+ stat = fs.lstatSync(current);
302
+ } catch (err) {
303
+ if (err && err.code === "ENOENT") return;
304
+ throw err;
305
+ }
306
+ if (stat.isSymbolicLink()) {
307
+ throw new Error(
308
+ `Refusing to ${label}: symbolic link ancestor '${current}' would redirect writes outside '${resolvedParent}'. ` +
309
+ `Remove the symlink and retry.`
310
+ );
311
+ }
312
+ if (!stat.isDirectory()) {
313
+ throw new Error(
314
+ `Refusing to ${label}: path ancestor '${current}' is not a directory.`
315
+ );
316
+ }
317
+ }
318
+ }
319
+
320
+ function assertSafeWriteDestination(parent, destination, label) {
321
+ // Lexical containment blocks traversal strings and absolute-path metadata.
322
+ // The ancestor walk then rejects pre-existing symlinks such as `.codex -> /x`
323
+ // before mkdir/copy can follow them. Node does not expose fully race-proof
324
+ // O_NOFOLLOW directory creation, so this intentionally closes the reachable
325
+ // planted-symlink case without pretending to solve privileged TOCTOU races.
326
+ assertNoSymlinkAncestor(parent, destination, label);
327
+ }
328
+
298
329
  function loadSkills() {
299
330
  const skillsRoot = path.join(repoRoot, "skills");
300
331
  if (!fs.existsSync(skillsRoot)) return new Map();
@@ -325,11 +356,12 @@ function loadSkills() {
325
356
  return byName;
326
357
  }
327
358
 
328
- function copySkillTree(sourceDir, destDir, force) {
359
+ function copySkillTree(sourceDir, destDir, force, targetRoot) {
329
360
  assertWithin(repoRoot, sourceDir, "read skill source");
330
361
  for (const entry of fs.readdirSync(sourceDir, { withFileTypes: true })) {
331
362
  const src = path.join(sourceDir, entry.name);
332
363
  const dst = path.join(destDir, entry.name);
364
+ assertSafeWriteDestination(targetRoot, dst, "write skill tree destination");
333
365
  if (entry.isSymbolicLink()) {
334
366
  throw new Error(`Refusing to copy symbolic link in skill tree: ${src}`);
335
367
  }
@@ -342,7 +374,7 @@ function copySkillTree(sourceDir, destDir, force) {
342
374
  );
343
375
  }
344
376
  if (entry.isDirectory()) {
345
- copySkillTree(src, dst, force);
377
+ copySkillTree(src, dst, force, targetRoot);
346
378
  continue;
347
379
  }
348
380
  if (!entry.isFile()) continue;
@@ -404,7 +436,8 @@ function resolveCompanionSkills(selectedAgents, skillsByName, role, includeAll,
404
436
  return { skillNames: [...skillNames].sort(), orphans };
405
437
  }
406
438
 
407
- function copyFile(source, destination, force) {
439
+ function copyFile(source, destination, force, targetRoot) {
440
+ assertSafeWriteDestination(targetRoot, destination, "write file destination");
408
441
  const sourceStat = fs.lstatSync(source);
409
442
  if (sourceStat.isSymbolicLink()) {
410
443
  throw new Error(`Refusing to copy symbolic link as harness source: ${source}`);
@@ -662,7 +695,7 @@ function main() {
662
695
 
663
696
  for (const operation of operations) {
664
697
  assertWithin(args.repo, operation.dest, "write destination");
665
- copyFile(operation.source, operation.dest, args.force);
698
+ copyFile(operation.source, operation.dest, args.force, args.repo);
666
699
  if (platform === "codex") {
667
700
  rewriteCodexAgentSkillPaths(operation.dest, args.repo);
668
701
  }
@@ -705,7 +738,7 @@ function main() {
705
738
  if (!sourceDir) continue;
706
739
  const destDir = path.join(args.repo, skillsDestRoot, skillName);
707
740
  assertWithin(args.repo, destDir, "write skill destination");
708
- copySkillTree(sourceDir, destDir, args.force);
741
+ copySkillTree(sourceDir, destDir, args.force, args.repo);
709
742
  console.log(`installed\tskill:${skillName}\t${platform}\t${path.relative(args.repo, destDir)}`);
710
743
  bundled += 1;
711
744
  }
@@ -864,6 +864,36 @@ const onDiskSkillNames = new Set(skillProviderByName.keys());
864
864
  }
865
865
  }
866
866
 
867
+ // F28c: codex export rejects symlinked platform directory ancestors.
868
+ {
869
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "vfa-test-codex-parent-symlink-"));
870
+ const outsideDir = fs.mkdtempSync(path.join(os.tmpdir(), "vfa-test-outside-"));
871
+ try {
872
+ fs.symlinkSync(outsideDir, path.join(tmpDir, ".codex"));
873
+ const r = run([
874
+ "--platform", "codex",
875
+ "--agents", "aws-iam-least-privilege-review-agent",
876
+ "--repo", tmpDir,
877
+ "--force",
878
+ ]);
879
+ const outsideAgent = path.join(outsideDir, "agents", "aws-iam-least-privilege-review-agent.toml");
880
+ const outsideSkill = path.join(outsideDir, "skills", "aws-iam-least-privilege-review", "SKILL.md");
881
+ if (
882
+ r.exitCode !== 0 &&
883
+ /symbolic link ancestor/i.test(r.stderr) &&
884
+ !fs.existsSync(outsideAgent) &&
885
+ !fs.existsSync(outsideSkill)
886
+ ) {
887
+ ok("F28c codex export rejects symlinked .codex ancestor without outside writes");
888
+ } else {
889
+ fail(`F28c expected symlink ancestor rejection without outside writes; exit=${r.exitCode} agentOutside=${fs.existsSync(outsideAgent)} skillOutside=${fs.existsSync(outsideSkill)} stderr=${r.stderr.slice(0, 300)}`);
890
+ }
891
+ } finally {
892
+ fs.rmSync(tmpDir, { recursive: true, force: true });
893
+ fs.rmSync(outsideDir, { recursive: true, force: true });
894
+ }
895
+ }
896
+
867
897
  // F29: two-stage installer dry-run composes marketplace-safe export path.
868
898
  {
869
899
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "vfa-test-two-stage-"));