@vibe-agent-toolkit/utils 0.2.0-rc.3 → 0.2.0-rc.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 (86) hide show
  1. package/README.md +21 -13
  2. package/dist/crawl-timing.d.ts +43 -66
  3. package/dist/crawl-timing.d.ts.map +1 -1
  4. package/dist/crawl-timing.js +35 -79
  5. package/dist/crawl-timing.js.map +1 -1
  6. package/dist/crawl.d.ts +2 -4
  7. package/dist/crawl.d.ts.map +1 -1
  8. package/dist/crawl.js +2 -4
  9. package/dist/crawl.js.map +1 -1
  10. package/dist/fs-utils.d.ts +15 -6
  11. package/dist/fs-utils.d.ts.map +1 -1
  12. package/dist/fs-utils.js +15 -6
  13. package/dist/fs-utils.js.map +1 -1
  14. package/dist/git-tracker.d.ts +32 -1
  15. package/dist/git-tracker.d.ts.map +1 -1
  16. package/dist/git-tracker.js +32 -1
  17. package/dist/git-tracker.js.map +1 -1
  18. package/dist/git.d.ts +11 -4
  19. package/dist/git.d.ts.map +1 -1
  20. package/dist/git.js +11 -4
  21. package/dist/git.js.map +1 -1
  22. package/dist/index.d.ts +19 -20
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +19 -41
  25. package/dist/index.js.map +1 -1
  26. package/dist/project.d.ts +7 -5
  27. package/dist/project.d.ts.map +1 -1
  28. package/dist/project.js +7 -5
  29. package/dist/project.js.map +1 -1
  30. package/dist/safe-exec.js +0 -1
  31. package/dist/safe-exec.js.map +1 -1
  32. package/dist/spawn-hardened.js +0 -1
  33. package/dist/spawn-hardened.js.map +1 -1
  34. package/dist/testing.d.ts +73 -3
  35. package/dist/testing.d.ts.map +1 -1
  36. package/dist/testing.js +93 -3
  37. package/dist/testing.js.map +1 -1
  38. package/dist/timing-dump.d.ts +22 -5
  39. package/dist/timing-dump.d.ts.map +1 -1
  40. package/dist/timing-dump.js +89 -23
  41. package/dist/timing-dump.js.map +1 -1
  42. package/eslint/index.cjs +9 -0
  43. package/eslint/index.d.cts +14 -7
  44. package/eslint/rules/no-process-exit-in-phase.cjs +117 -0
  45. package/package.json +5 -7
  46. package/dist/link-auth/build-headers.d.ts +0 -34
  47. package/dist/link-auth/build-headers.d.ts.map +0 -1
  48. package/dist/link-auth/build-headers.js +0 -58
  49. package/dist/link-auth/build-headers.js.map +0 -1
  50. package/dist/link-auth/expand-macro.d.ts +0 -38
  51. package/dist/link-auth/expand-macro.d.ts.map +0 -1
  52. package/dist/link-auth/expand-macro.js +0 -139
  53. package/dist/link-auth/expand-macro.js.map +0 -1
  54. package/dist/link-auth/macros.yaml +0 -50
  55. package/dist/link-auth/resolve-token.d.ts +0 -83
  56. package/dist/link-auth/resolve-token.d.ts.map +0 -1
  57. package/dist/link-auth/resolve-token.js +0 -115
  58. package/dist/link-auth/resolve-token.js.map +0 -1
  59. package/dist/link-auth/resolve.d.ts +0 -102
  60. package/dist/link-auth/resolve.d.ts.map +0 -1
  61. package/dist/link-auth/resolve.js +0 -66
  62. package/dist/link-auth/resolve.js.map +0 -1
  63. package/dist/link-auth/rewrite.d.ts +0 -52
  64. package/dist/link-auth/rewrite.d.ts.map +0 -1
  65. package/dist/link-auth/rewrite.js +0 -102
  66. package/dist/link-auth/rewrite.js.map +0 -1
  67. package/dist/link-auth/select-provider.d.ts +0 -30
  68. package/dist/link-auth/select-provider.d.ts.map +0 -1
  69. package/dist/link-auth/select-provider.js +0 -55
  70. package/dist/link-auth/select-provider.js.map +0 -1
  71. package/dist/link-auth/template.d.ts +0 -40
  72. package/dist/link-auth/template.d.ts.map +0 -1
  73. package/dist/link-auth/template.js +0 -89
  74. package/dist/link-auth/template.js.map +0 -1
  75. package/dist/link-auth/transforms.d.ts +0 -46
  76. package/dist/link-auth/transforms.d.ts.map +0 -1
  77. package/dist/link-auth/transforms.js +0 -52
  78. package/dist/link-auth/transforms.js.map +0 -1
  79. package/dist/template-entry.d.ts +0 -10
  80. package/dist/template-entry.d.ts.map +0 -1
  81. package/dist/template-entry.js +0 -10
  82. package/dist/template-entry.js.map +0 -1
  83. package/dist/template.d.ts +0 -7
  84. package/dist/template.d.ts.map +0 -1
  85. package/dist/template.js +0 -18
  86. package/dist/template.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibe-agent-toolkit/utils",
3
- "version": "0.2.0-rc.3",
3
+ "version": "0.2.0-rc.5",
4
4
  "type": "module",
5
5
  "description": "Core utility functions shared across the vibe-agent-toolkit packages",
6
6
  "sideEffects": [
@@ -54,9 +54,9 @@
54
54
  "types": "./dist/zod.d.ts",
55
55
  "import": "./dist/zod.js"
56
56
  },
57
- "./template": {
58
- "types": "./dist/template-entry.d.ts",
59
- "import": "./dist/template-entry.js"
57
+ "./skill-test": {
58
+ "types": "./dist/skill-test/index.d.ts",
59
+ "import": "./dist/skill-test/index.js"
60
60
  },
61
61
  "./yaml": {
62
62
  "types": "./dist/yaml.d.ts",
@@ -90,17 +90,15 @@
90
90
  "README.md"
91
91
  ],
92
92
  "scripts": {
93
- "build": "rimraf --glob dist \"*.tsbuildinfo\" && tsc && tsx ../dev-tools/src/copy-yaml-assets.ts",
93
+ "build": "rimraf --glob dist \"*.tsbuildinfo\" && tsc",
94
94
  "test:unit": "vitest run",
95
95
  "test:integration": "vitest run --config vitest.integration.config.ts",
96
- "test:system": "vitest run --config vitest.system.config.ts",
97
96
  "test:watch": "vitest",
98
97
  "typecheck": "tsc --noEmit",
99
98
  "clean": "rimraf dist *.tsbuildinfo"
100
99
  },
101
100
  "dependencies": {
102
101
  "@vibe-validate/git": "0.20.1",
103
- "handlebars": "^4.7.8",
104
102
  "ignore": "^7.0.5",
105
103
  "picomatch": "^4.0.3",
106
104
  "which": "^5.0.0",
@@ -1,34 +0,0 @@
1
- /**
2
- * Render auth-header templates with rendered values, and a structural
3
- * redaction helper for serialization.
4
- *
5
- * `buildHeaders` renders each header value template against a context that
6
- * carries `${token}` plus any named captures / vars from the rewrite step.
7
- * `redactHeaders` masks `Authorization` values for any caller that needs to
8
- * serialize headers into logs, errors, or cache entries — the design's §8
9
- * "tokens never leak" claim depends on every such site routing through this.
10
- *
11
- * Per design issue #113 §4 (auth.headers vocabulary) and §8 (redaction is
12
- * structural; Authorization values never appear in serialized output).
13
- */
14
- export declare const REDACTED_VALUE = "<redacted>";
15
- /**
16
- * Render a map of header templates into a map of concrete header values.
17
- *
18
- * @throws {TemplateMissingVarError} if a header template references an
19
- * unknown context key
20
- * @throws {TemplateSyntaxError} from a malformed template expression
21
- * @throws {UnknownTransformError} from a template calling an unknown transform
22
- */
23
- export declare function buildHeaders(templates: Record<string, string>, context: Record<string, string>): Record<string, string>;
24
- /**
25
- * Return a copy of `headers` with sensitive values replaced by `REDACTED_VALUE`.
26
- * Header-name matching is case-insensitive but exact (no prefix matching) — a
27
- * header like `X-Authorization-Foo` is NOT considered sensitive.
28
- *
29
- * **Input must be a plain key-value object.** A `Headers` instance (Web Fetch
30
- * API) or a `Map` yields `[]` from `Object.entries` and would silently no-op
31
- * redaction — converting to a plain object is the caller's responsibility.
32
- */
33
- export declare function redactHeaders(headers: Record<string, string>): Record<string, string>;
34
- //# sourceMappingURL=build-headers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"build-headers.d.ts","sourceRoot":"","sources":["../../src/link-auth/build-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,eAAO,MAAM,cAAc,eAAe,CAAC;AAc3C;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMrF"}
@@ -1,58 +0,0 @@
1
- /**
2
- * Render auth-header templates with rendered values, and a structural
3
- * redaction helper for serialization.
4
- *
5
- * `buildHeaders` renders each header value template against a context that
6
- * carries `${token}` plus any named captures / vars from the rewrite step.
7
- * `redactHeaders` masks `Authorization` values for any caller that needs to
8
- * serialize headers into logs, errors, or cache entries — the design's §8
9
- * "tokens never leak" claim depends on every such site routing through this.
10
- *
11
- * Per design issue #113 §4 (auth.headers vocabulary) and §8 (redaction is
12
- * structural; Authorization values never appear in serialized output).
13
- */
14
- import { renderTemplate } from './template.js';
15
- export const REDACTED_VALUE = '<redacted>';
16
- /**
17
- * Header names whose values must be masked when serialized.
18
- *
19
- * v1 ships only `authorization` because that is the only secret-bearing
20
- * header the current macros emit. **Omission is the security risk** — any
21
- * future macro that emits a header carrying a secret (`Cookie`,
22
- * `Proxy-Authorization`, `X-API-Key`, custom bearer-style headers) must add
23
- * that name here, or the token will silently leak through serialization.
24
- * Extending the set is not the dangerous edit; forgetting to extend it is.
25
- */
26
- const SENSITIVE_HEADER_NAMES = new Set(['authorization']);
27
- /**
28
- * Render a map of header templates into a map of concrete header values.
29
- *
30
- * @throws {TemplateMissingVarError} if a header template references an
31
- * unknown context key
32
- * @throws {TemplateSyntaxError} from a malformed template expression
33
- * @throws {UnknownTransformError} from a template calling an unknown transform
34
- */
35
- export function buildHeaders(templates, context) {
36
- const headers = Object.create(null);
37
- for (const [name, template] of Object.entries(templates)) {
38
- headers[name] = renderTemplate(template, context);
39
- }
40
- return headers;
41
- }
42
- /**
43
- * Return a copy of `headers` with sensitive values replaced by `REDACTED_VALUE`.
44
- * Header-name matching is case-insensitive but exact (no prefix matching) — a
45
- * header like `X-Authorization-Foo` is NOT considered sensitive.
46
- *
47
- * **Input must be a plain key-value object.** A `Headers` instance (Web Fetch
48
- * API) or a `Map` yields `[]` from `Object.entries` and would silently no-op
49
- * redaction — converting to a plain object is the caller's responsibility.
50
- */
51
- export function redactHeaders(headers) {
52
- const redacted = Object.create(null);
53
- for (const [name, value] of Object.entries(headers)) {
54
- redacted[name] = SENSITIVE_HEADER_NAMES.has(name.toLowerCase()) ? REDACTED_VALUE : value;
55
- }
56
- return redacted;
57
- }
58
- //# sourceMappingURL=build-headers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"build-headers.js","sourceRoot":"","sources":["../../src/link-auth/build-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAE3C;;;;;;;;;GASG;AACH,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AAE/E;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,SAAiC,EACjC,OAA+B;IAE/B,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAA2B,CAAC;IAC9D,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,OAA+B;IAC3D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAA2B,CAAC;IAC/D,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,QAAQ,CAAC,IAAI,CAAC,GAAG,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC;IAC3F,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -1,38 +0,0 @@
1
- /**
2
- * Macro loader + expander.
3
- *
4
- * Loads the bundled `macros.yaml` once at module init and exposes
5
- * `expandMacro(name, overrides?)` which deep-merges the named macro with any
6
- * adopter overrides. The merge is "adopter wins": objects merge recursively,
7
- * arrays and primitives are replaced wholesale (no element-wise array merge).
8
- *
9
- * The shipped macro file is at `link-auth/macros.yaml`, copied into the dist
10
- * tree by `packages/dev-tools/src/copy-yaml-assets.ts` during build so the
11
- * runtime `fs.readFileSync(new URL('./macros.yaml', import.meta.url))`
12
- * resolves in both source-mode (vitest) and built-mode (dist).
13
- *
14
- * Per design issue #113 §5 (macros are config, not a privileged code path).
15
- */
16
- /**
17
- * Thrown when a `use: <name>` references a macro not in the shipped set.
18
- * Message lists the available macros so a typo surfaces clearly.
19
- */
20
- export declare class UnknownMacroError extends Error {
21
- constructor(name: string, available: readonly string[]);
22
- }
23
- /**
24
- * Look up a macro by name and deep-merge optional adopter overrides on top.
25
- *
26
- * Merge semantics:
27
- * - Plain objects merge recursively (sibling keys preserved).
28
- * - Arrays are replaced wholesale (override's array wins; no concat).
29
- * - Primitives are replaced.
30
- * - `undefined` in an override is treated as "not provided" (base wins).
31
- *
32
- * The returned object and all nested plain objects use null prototypes so
33
- * `__proto__` / `constructor` keys can never poison consumers.
34
- *
35
- * @throws {UnknownMacroError} if `name` is not in the shipped macro set
36
- */
37
- export declare function expandMacro(name: string, overrides?: Record<string, unknown>): Record<string, unknown>;
38
- //# sourceMappingURL=expand-macro.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"expand-macro.d.ts","sourceRoot":"","sources":["../../src/link-auth/expand-macro.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA+CH;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE;CAIvD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYzB"}
@@ -1,139 +0,0 @@
1
- /**
2
- * Macro loader + expander.
3
- *
4
- * Loads the bundled `macros.yaml` once at module init and exposes
5
- * `expandMacro(name, overrides?)` which deep-merges the named macro with any
6
- * adopter overrides. The merge is "adopter wins": objects merge recursively,
7
- * arrays and primitives are replaced wholesale (no element-wise array merge).
8
- *
9
- * The shipped macro file is at `link-auth/macros.yaml`, copied into the dist
10
- * tree by `packages/dev-tools/src/copy-yaml-assets.ts` during build so the
11
- * runtime `fs.readFileSync(new URL('./macros.yaml', import.meta.url))`
12
- * resolves in both source-mode (vitest) and built-mode (dist).
13
- *
14
- * Per design issue #113 §5 (macros are config, not a privileged code path).
15
- */
16
- import { readFileSync } from 'node:fs';
17
- import { fileURLToPath } from 'node:url';
18
- import { parse as parseYaml } from 'yaml';
19
- let macrosCache;
20
- /**
21
- * Load macros lazily on first use rather than at module init.
22
- *
23
- * Why lazy: vitest tests elsewhere in the repo mock `node:fs` (replacing
24
- * `readFileSync` with `vi.fn()` that returns `undefined`). If we eagerly read
25
- * at module load, any unrelated test that imports `@vibe-agent-toolkit/utils`
26
- * and mocks fs crashes inside `parseYaml(undefined)` — module-init code runs
27
- * unconditionally, before the mock-setup intent reaches our file.
28
- *
29
- * Lazy load makes module import side-effect-free; only callers of
30
- * `expandMacro` pay the fs cost. `macrosPath` is also computed here (not at
31
- * module top level) so that merely importing this module leaves no `new URL()`
32
- * reference for bundler static analysis to trip over.
33
- */
34
- function getMacros() {
35
- if (macrosCache !== undefined)
36
- return macrosCache;
37
- // Path is derived from `import.meta.url`, not user input — points at the
38
- // shipped macros.yaml asset next to this module in both src and dist trees.
39
- const macrosPath = fileURLToPath(new URL('./macros.yaml', import.meta.url));
40
- // Not a content read: `macros.yaml` is an asset THIS PACKAGE authors, commits
41
- // and publishes beside this module, so the encoding was chosen at the write
42
- // rather than discovered at the read. Left on the raw reader deliberately —
43
- // the lazy-load note above documents that tests elsewhere mock
44
- // `readFileSync`, and routing this through another module's import of it is
45
- // gratuitous risk for a file whose bytes we control.
46
- // eslint-disable-next-line security/detect-non-literal-fs-filename, local/no-raw-text-decode -- our own published asset; writer is this package
47
- const macrosFileContent = readFileSync(macrosPath, 'utf8');
48
- const parsed = parseYaml(macrosFileContent);
49
- if (!isPlainObject(parsed)) {
50
- throw new Error('macros.yaml: expected top-level object mapping macro name → provider config.');
51
- }
52
- macrosCache = freezeMacros(parsed);
53
- return macrosCache;
54
- }
55
- /**
56
- * Thrown when a `use: <name>` references a macro not in the shipped set.
57
- * Message lists the available macros so a typo surfaces clearly.
58
- */
59
- export class UnknownMacroError extends Error {
60
- constructor(name, available) {
61
- super(`Unknown macro "${name}". Available: ${available.join(', ')}.`);
62
- this.name = 'UnknownMacroError';
63
- }
64
- }
65
- /**
66
- * Look up a macro by name and deep-merge optional adopter overrides on top.
67
- *
68
- * Merge semantics:
69
- * - Plain objects merge recursively (sibling keys preserved).
70
- * - Arrays are replaced wholesale (override's array wins; no concat).
71
- * - Primitives are replaced.
72
- * - `undefined` in an override is treated as "not provided" (base wins).
73
- *
74
- * The returned object and all nested plain objects use null prototypes so
75
- * `__proto__` / `constructor` keys can never poison consumers.
76
- *
77
- * @throws {UnknownMacroError} if `name` is not in the shipped macro set
78
- */
79
- export function expandMacro(name, overrides) {
80
- const macros = getMacros();
81
- const base = macros[name];
82
- if (base === undefined) {
83
- throw new UnknownMacroError(name, Object.keys(macros));
84
- }
85
- if (overrides === undefined) {
86
- return cloneWithNullProto(base);
87
- }
88
- const merged = deepMerge(base, overrides);
89
- // Top-level result is guaranteed object here because base is.
90
- return merged;
91
- }
92
- function deepMerge(base, override) {
93
- if (override === undefined)
94
- return base;
95
- if (!isPlainObject(base) || !isPlainObject(override))
96
- return cloneValue(override);
97
- const result = Object.create(null);
98
- for (const [key, value] of Object.entries(base)) {
99
- result[key] = cloneValue(value);
100
- }
101
- for (const [key, value] of Object.entries(override)) {
102
- const existing = Object.hasOwn(result, key) ? result[key] : undefined;
103
- if (isPlainObject(existing) && isPlainObject(value)) {
104
- result[key] = deepMerge(existing, value);
105
- }
106
- else {
107
- result[key] = cloneValue(value);
108
- }
109
- }
110
- return result;
111
- }
112
- function cloneValue(value) {
113
- if (Array.isArray(value))
114
- return value.map(cloneValue);
115
- if (isPlainObject(value))
116
- return cloneWithNullProto(value);
117
- return value;
118
- }
119
- function cloneWithNullProto(obj) {
120
- const cloned = Object.create(null);
121
- for (const [key, value] of Object.entries(obj)) {
122
- cloned[key] = cloneValue(value);
123
- }
124
- return cloned;
125
- }
126
- function freezeMacros(parsed) {
127
- const frozen = Object.create(null);
128
- for (const [name, value] of Object.entries(parsed)) {
129
- if (!isPlainObject(value)) {
130
- throw new Error(`macros.yaml: macro "${name}" is not an object.`);
131
- }
132
- frozen[name] = cloneWithNullProto(value);
133
- }
134
- return frozen;
135
- }
136
- function isPlainObject(v) {
137
- return typeof v === 'object' && v !== null && !Array.isArray(v);
138
- }
139
- //# sourceMappingURL=expand-macro.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"expand-macro.js","sourceRoot":"","sources":["../../src/link-auth/expand-macro.ts"],"names":[],"mappings":"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"}
@@ -1,50 +0,0 @@
1
- # linkAuth provider macros — shipped defaults referenced by `use: <name>` in
2
- # adopter `vibe-agent-toolkit.config.yaml` files.
3
- #
4
- # Each entry is a full provider config in the §4 vocabulary (match, rewrite,
5
- # auth, token, check). Adopters reference a macro by name and may deep-merge
6
- # overrides on top — see design issue #113 §5.
7
- #
8
- # Adding a new host is intended to be a config-only PR: append an entry here
9
- # and add unit tests. Only `vocabulary` changes (e.g. a new transform) require
10
- # engine code.
11
-
12
- github:
13
- match:
14
- host: github.com
15
- rewrite:
16
- - when: '^https://github\.com/(?<owner>[^/]+)/(?<repo>[^/]+)/(?:blob|tree)/(?<ref>[^/]+)/(?<path>.+)$'
17
- to: 'https://api.github.com/repos/${owner}/${repo}/contents/${path}?ref=${ref}'
18
- auth:
19
- headers:
20
- Authorization: 'Bearer ${token}'
21
- Accept: application/vnd.github+json
22
- token:
23
- - command: gh auth token
24
- - env: GITHUB_TOKEN
25
- check:
26
- method: GET
27
- aliveStatus: [200]
28
- notFoundMeaning: ambiguous
29
-
30
- sharepoint:
31
- match:
32
- host: '*.sharepoint.com'
33
- excludeHost:
34
- - '*-my.sharepoint.com'
35
- rewrite:
36
- - when: '^(?<u>https://.+)$'
37
- vars:
38
- shareId: 'u!${base64url(u)}'
39
- to: 'https://graph.microsoft.com/v1.0/shares/${shareId}/driveItem'
40
- auth:
41
- headers:
42
- Authorization: 'Bearer ${token}'
43
- # SharePoint has no zero-config token source (design §5.1 note): a SharePoint-
44
- # scoped token requires an Entra app registration; the stock `az` token does
45
- # not work. Adopter must supply their own token command.
46
- token: []
47
- check:
48
- method: GET
49
- aliveStatus: [200]
50
- notFoundMeaning: dead
@@ -1,83 +0,0 @@
1
- /**
2
- * Token resolution — ordered, first-non-empty-wins.
3
- *
4
- * Iterates a provider's `token` source list and returns the first source that
5
- * yields a non-empty value. Two source shapes:
6
- * - `{ env: "NAME" }` — read from process env (no trimming)
7
- * - `{ command: argv }` — run a command, return trimmed stdout
8
- * - `{ command: "gh auth token" }` — convenience: whitespace-tokenized into
9
- * argv. **Not** passed through a shell — operators (`|`, `&&`, `$(...)`)
10
- * become literal argv elements, per the design's §6.1 sharp-edge note.
11
- *
12
- * Command sources can be disabled at runtime with `VAT_LINKAUTH_ALLOW_COMMAND=0`
13
- * (or by passing `allowCommand: false` in deps). Useful in security-sensitive
14
- * environments where arbitrary command execution is undesirable.
15
- *
16
- * Returns `undefined` if every source fails or yields an empty/whitespace
17
- * value — the caller's `resolveAuthenticatedUrl` translates that to the
18
- * `unverified` outcome (surfaced as `LINK_AUTH_UNVERIFIED` by the validator).
19
- *
20
- * Per design issue #113 §4 (token vocabulary) and §6.1 (command execution,
21
- * `safeExecSync`-backed, `shell: false`).
22
- */
23
- export type TokenSource = {
24
- readonly env: string;
25
- } | {
26
- readonly command: string | readonly string[];
27
- };
28
- export interface TokenResolutionDeps {
29
- /**
30
- * Environment lookup map. Defaults to `process.env`. Injectable for tests so
31
- * unit tests don't depend on ambient environment state.
32
- */
33
- readonly env: Record<string, string | undefined>;
34
- /**
35
- * Command runner. Defaults to `safeExecResult`-wrapped invocation. Injectable
36
- * for tests. Receives argv; returns `success` + `stdout`. Should NOT throw
37
- * for normal exec failures (return `success: false` instead). Throws are
38
- * propagated by `resolveToken` — they indicate operator-level bugs.
39
- */
40
- readonly runCommand: (argv: readonly string[]) => {
41
- success: boolean;
42
- stdout: string;
43
- };
44
- /**
45
- * Whether `{ command: ... }` sources are allowed. Defaults to reading
46
- * `VAT_LINKAUTH_ALLOW_COMMAND` from the resolved `env` map (not ambient
47
- * `process.env`), so a caller supplying a curated `deps.env` can control the
48
- * flag without touching real process state. Set to `false` (or set
49
- * `VAT_LINKAUTH_ALLOW_COMMAND=0` in the env) to skip all command sources and
50
- * rely solely on env-var sources — useful in locked-down CI or security reviews.
51
- */
52
- readonly allowCommand: boolean;
53
- }
54
- /**
55
- * Return a copy of the given env with all `GIT_*` keys removed. Case-insensitive
56
- * on the key so Windows env vars (which are case-insensitive at the OS level,
57
- * though `process.env` preserves original case) can't sneak through as e.g.
58
- * `Git_Dir`.
59
- *
60
- * Exported for unit testing and for callers assembling their own `runCommand`
61
- * who want the exact same scrub `defaultRunCommand` applies.
62
- *
63
- * Rationale: `vat resources validate` is often invoked from git pre-commit
64
- * hooks, which pre-set `GIT_DIR` / `GIT_WORK_TREE` / `GIT_INDEX_FILE`. These
65
- * poison any nested tool that shells out to git, notably `gh auth token`.
66
- */
67
- export declare function scrubGitEnv(source: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
68
- /**
69
- * Default `runCommand` implementation — exported so callers that want to
70
- * memoize per-validate-run can wrap it without duplicating the spawn logic.
71
- * Forwards to `safeExecResult` (no shell, argv-based), with `GIT_*` vars
72
- * stripped from the child env — see {@link scrubGitEnv}.
73
- */
74
- export declare const defaultRunCommand: TokenResolutionDeps['runCommand'];
75
- /**
76
- * Resolve a token from an ordered list of sources.
77
- *
78
- * @returns the first non-empty value, or `undefined` if every source failed.
79
- * @throws whatever the injected `runCommand` throws (operator-level bug; not
80
- * swallowed). Standard `safeExecResult` does not throw under normal use.
81
- */
82
- export declare function resolveToken(sources: readonly TokenSource[], deps?: Partial<TokenResolutionDeps>): string | undefined;
83
- //# sourceMappingURL=resolve-token.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"resolve-token.d.ts","sourceRoot":"","sources":["../../src/link-auth/resolve-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAEtG,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAEjD;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAEvF;;;;;;;OAOG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAIxE;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,mBAAmB,CAAC,YAAY,CAqB/D,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,IAAI,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAClC,MAAM,GAAG,SAAS,CAWpB"}
@@ -1,115 +0,0 @@
1
- /**
2
- * Token resolution — ordered, first-non-empty-wins.
3
- *
4
- * Iterates a provider's `token` source list and returns the first source that
5
- * yields a non-empty value. Two source shapes:
6
- * - `{ env: "NAME" }` — read from process env (no trimming)
7
- * - `{ command: argv }` — run a command, return trimmed stdout
8
- * - `{ command: "gh auth token" }` — convenience: whitespace-tokenized into
9
- * argv. **Not** passed through a shell — operators (`|`, `&&`, `$(...)`)
10
- * become literal argv elements, per the design's §6.1 sharp-edge note.
11
- *
12
- * Command sources can be disabled at runtime with `VAT_LINKAUTH_ALLOW_COMMAND=0`
13
- * (or by passing `allowCommand: false` in deps). Useful in security-sensitive
14
- * environments where arbitrary command execution is undesirable.
15
- *
16
- * Returns `undefined` if every source fails or yields an empty/whitespace
17
- * value — the caller's `resolveAuthenticatedUrl` translates that to the
18
- * `unverified` outcome (surfaced as `LINK_AUTH_UNVERIFIED` by the validator).
19
- *
20
- * Per design issue #113 §4 (token vocabulary) and §6.1 (command execution,
21
- * `safeExecSync`-backed, `shell: false`).
22
- */
23
- import { safeExecResult } from '../safe-exec.js';
24
- /**
25
- * Return a copy of the given env with all `GIT_*` keys removed. Case-insensitive
26
- * on the key so Windows env vars (which are case-insensitive at the OS level,
27
- * though `process.env` preserves original case) can't sneak through as e.g.
28
- * `Git_Dir`.
29
- *
30
- * Exported for unit testing and for callers assembling their own `runCommand`
31
- * who want the exact same scrub `defaultRunCommand` applies.
32
- *
33
- * Rationale: `vat resources validate` is often invoked from git pre-commit
34
- * hooks, which pre-set `GIT_DIR` / `GIT_WORK_TREE` / `GIT_INDEX_FILE`. These
35
- * poison any nested tool that shells out to git, notably `gh auth token`.
36
- */
37
- export function scrubGitEnv(source) {
38
- return Object.fromEntries(Object.entries(source).filter(([k]) => !k.toUpperCase().startsWith('GIT_')));
39
- }
40
- /**
41
- * Default `runCommand` implementation — exported so callers that want to
42
- * memoize per-validate-run can wrap it without duplicating the spawn logic.
43
- * Forwards to `safeExecResult` (no shell, argv-based), with `GIT_*` vars
44
- * stripped from the child env — see {@link scrubGitEnv}.
45
- */
46
- export const defaultRunCommand = (argv) => {
47
- if (argv.length === 0)
48
- return { success: false, stdout: '' };
49
- const [bin, ...args] = argv;
50
- if (bin === undefined)
51
- return { success: false, stdout: '' };
52
- const result = safeExecResult(bin, [...args], {
53
- encoding: 'utf8',
54
- env: scrubGitEnv(process.env),
55
- // The operator chose this argv; VAT neither composed it nor knows whether it
56
- // means a path or the ambient repository, so the usual "say which you mean"
57
- // refusal has nobody to ask. `git credential fill` and friends are ordinary
58
- // things to configure here. The env is already handled above, and more
59
- // strictly than runGit would: every GIT_* key, case-insensitively.
60
- allowGit: true,
61
- });
62
- // Not a file read: these bytes are the stdout of the credential helper spawned
63
- // three lines up, and its encoding is that program's contract, not a property
64
- // of any file. `safeExecResult` was already asked for `encoding: 'utf8'`, so
65
- // this branch only runs when it handed back a Buffer anyway.
66
- // eslint-disable-next-line local/no-raw-text-decode -- subprocess stdout; producer is the credential helper spawned above
67
- const stdout = typeof result.stdout === 'string' ? result.stdout : result.stdout.toString('utf8');
68
- return { success: result.success, stdout };
69
- };
70
- /**
71
- * Resolve a token from an ordered list of sources.
72
- *
73
- * @returns the first non-empty value, or `undefined` if every source failed.
74
- * @throws whatever the injected `runCommand` throws (operator-level bug; not
75
- * swallowed). Standard `safeExecResult` does not throw under normal use.
76
- */
77
- export function resolveToken(sources, deps) {
78
- const env = deps?.env ?? process.env;
79
- const runCommand = deps?.runCommand ?? defaultRunCommand;
80
- const allowCommand = deps?.allowCommand ?? (env['VAT_LINKAUTH_ALLOW_COMMAND'] !== '0');
81
- for (const source of sources) {
82
- if (!allowCommand && 'command' in source)
83
- continue;
84
- const value = tryResolveSource(source, env, runCommand);
85
- if (value !== undefined && value.length > 0)
86
- return value;
87
- }
88
- return undefined;
89
- }
90
- function tryResolveSource(source, env, runCommand) {
91
- if ('env' in source) {
92
- // Object.hasOwn defends against env names like "__proto__" returning
93
- // Object.prototype via the prototype chain.
94
- if (!Object.hasOwn(env, source.env))
95
- return undefined;
96
- return env[source.env];
97
- }
98
- const argv = toArgv(source.command);
99
- if (argv.length === 0)
100
- return undefined;
101
- const result = runCommand(argv);
102
- if (!result.success)
103
- return undefined;
104
- const trimmed = result.stdout.trim();
105
- return trimmed.length === 0 ? undefined : trimmed;
106
- }
107
- function toArgv(command) {
108
- if (Array.isArray(command))
109
- return command;
110
- // Whitespace-tokenize the string form. Empty segments (from multiple spaces)
111
- // are filtered. Shell operators ('|', '&&', etc.) become literal argv, NOT
112
- // pipes — see design §6.1.
113
- return command.split(/\s+/).filter((s) => s.length > 0);
114
- }
115
- //# sourceMappingURL=resolve-token.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"resolve-token.js","sourceRoot":"","sources":["../../src/link-auth/resolve-token.ts"],"names":[],"mappings":"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"}