agentic-workflow-manager 8.0.0 → 8.1.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.
- package/dist/src/commands/sensors/compatibility/contract.js +142 -21
- package/dist/src/commands/sensors/compatibility/discovery.js +1 -1
- package/dist/src/commands/sensors/compatibility/live.js +40 -7
- package/dist/src/commands/sensors/compatibility/manifest.js +13 -3
- package/dist/src/commands/sensors/compatibility/materialize.js +9 -1
- package/dist/src/commands/sensors/compatibility/probe.js +9 -9
- package/dist/src/commands/sensors/compatibility/resolve.js +3 -0
- package/dist/src/commands/sensors/exec.js +106 -12
- package/dist/src/commands/sensors/init.js +6 -3
- package/dist/src/commands/sensors/run.js +1 -1
- package/dist/src/commands/sensors/status.js +1 -1
- package/dist/tests/commands/sensors/compatibility/contract.test.js +95 -0
- package/dist/tests/commands/sensors/compatibility/live.test.js +124 -0
- package/dist/tests/commands/sensors/compatibility/manifest.test.js +9 -0
- package/dist/tests/commands/sensors/compatibility/materialize.test.js +19 -0
- package/dist/tests/commands/sensors/compatibility/probe.test.js +10 -0
- package/dist/tests/commands/sensors/compatibility/python-venv-fixture.js +29 -0
- package/dist/tests/commands/sensors/compatibility/resolve.test.js +8 -0
- package/dist/tests/commands/sensors/exec-windows.test.js +58 -10
- package/dist/tests/commands/sensors/exec.test.js +51 -3
- package/dist/tests/commands/sensors/init.test.js +72 -0
- package/dist/tests/structural/r3-cli-major-version.test.js +3 -3
- package/package.json +1 -1
|
@@ -24,6 +24,12 @@ function fakeChild(pid = 4242) {
|
|
|
24
24
|
child.unref = jest.fn();
|
|
25
25
|
return child;
|
|
26
26
|
}
|
|
27
|
+
function restoreEnvironment(name, value) {
|
|
28
|
+
if (value === undefined)
|
|
29
|
+
delete process.env[name];
|
|
30
|
+
else
|
|
31
|
+
process.env[name] = value;
|
|
32
|
+
}
|
|
27
33
|
describe('runCommand — win32', () => {
|
|
28
34
|
const originalPlatform = process.platform;
|
|
29
35
|
beforeEach(() => {
|
|
@@ -58,11 +64,35 @@ describe('runCommand — win32', () => {
|
|
|
58
64
|
expect(mockSpawn).toHaveBeenCalledWith(path_1.default.join(dir, 'tool.exe'), ['literal;&'], expect.objectContaining({ shell: false, detached: false }));
|
|
59
65
|
child.emit('close', 0, null);
|
|
60
66
|
await expect(pending).resolves.toMatchObject({ code: 0 });
|
|
61
|
-
expect(() => (0, exec_1.runStructuredCommand)({ executable: 'tool.cmd', resolution: 'path', args: [] }, { timeout: 5000, cwd: dir })).toThrow(/wrappers/);
|
|
67
|
+
expect(() => (0, exec_1.runStructuredCommand)({ executable: 'tool.cmd', resolution: 'path', args: ['--version'] }, { timeout: 5000, cwd: dir })).toThrow(/wrappers/);
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
restoreEnvironment('PATH', savedPath);
|
|
71
|
+
restoreEnvironment('PATHEXT', savedPathExt);
|
|
72
|
+
fs_1.default.rmSync(dir, { recursive: true, force: true });
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
it('spawns the allowlisted flat-config environment for ESLint 8', async () => {
|
|
76
|
+
const dir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-structured-win-env-'));
|
|
77
|
+
const savedPath = process.env.PATH;
|
|
78
|
+
const savedPathExt = process.env.PATHEXT;
|
|
79
|
+
try {
|
|
80
|
+
fs_1.default.writeFileSync(path_1.default.join(dir, 'tool.exe'), 'fixture');
|
|
81
|
+
process.env.PATH = dir;
|
|
82
|
+
process.env.PATHEXT = '.EXE';
|
|
83
|
+
const child = fakeChild();
|
|
84
|
+
mockSpawn.mockReturnValue(child);
|
|
85
|
+
const pending = (0, exec_1.runStructuredCommand)({ executable: 'tool', resolution: 'path', args: ['--version'], environment: { ESLINT_USE_FLAT_CONFIG: 'true' } }, { timeout: 5000, cwd: dir });
|
|
86
|
+
expect(mockSpawn).toHaveBeenCalledWith(path_1.default.join(dir, 'tool.exe'), ['--version'], expect.objectContaining({
|
|
87
|
+
shell: false,
|
|
88
|
+
env: expect.objectContaining({ ESLINT_USE_FLAT_CONFIG: 'true' }),
|
|
89
|
+
}));
|
|
90
|
+
child.emit('close', 0, null);
|
|
91
|
+
await expect(pending).resolves.toMatchObject({ code: 0 });
|
|
62
92
|
}
|
|
63
93
|
finally {
|
|
64
|
-
|
|
65
|
-
|
|
94
|
+
restoreEnvironment('PATH', savedPath);
|
|
95
|
+
restoreEnvironment('PATHEXT', savedPathExt);
|
|
66
96
|
fs_1.default.rmSync(dir, { recursive: true, force: true });
|
|
67
97
|
}
|
|
68
98
|
});
|
|
@@ -80,14 +110,14 @@ describe('runCommand — win32', () => {
|
|
|
80
110
|
process.env.PATHEXT = '.EXE';
|
|
81
111
|
const child = fakeChild();
|
|
82
112
|
mockSpawn.mockReturnValue(child);
|
|
83
|
-
const pending = (0, exec_1.runStructuredCommand)({ executable: 'tool', resolution: 'node-modules-bin', args: [] }, { timeout: 5000, cwd: dir });
|
|
84
|
-
expect(mockSpawn).toHaveBeenCalledWith(path_1.default.join(localBin, 'tool.exe'), [], expect.objectContaining({ shell: false }));
|
|
113
|
+
const pending = (0, exec_1.runStructuredCommand)({ executable: 'tool', resolution: 'node-modules-bin', args: ['--version'] }, { timeout: 5000, cwd: dir });
|
|
114
|
+
expect(mockSpawn).toHaveBeenCalledWith(path_1.default.join(localBin, 'tool.exe'), ['--version'], expect.objectContaining({ shell: false }));
|
|
85
115
|
child.emit('close', 0, null);
|
|
86
116
|
await expect(pending).resolves.toMatchObject({ code: 0 });
|
|
87
117
|
}
|
|
88
118
|
finally {
|
|
89
|
-
|
|
90
|
-
|
|
119
|
+
restoreEnvironment('PATH', savedPath);
|
|
120
|
+
restoreEnvironment('PATHEXT', savedPathExt);
|
|
91
121
|
fs_1.default.rmSync(dir, { recursive: true, force: true });
|
|
92
122
|
fs_1.default.rmSync(global, { recursive: true, force: true });
|
|
93
123
|
}
|
|
@@ -100,16 +130,34 @@ describe('runCommand — win32', () => {
|
|
|
100
130
|
fs_1.default.writeFileSync(path_1.default.join(global, 'tool.exe'), 'global');
|
|
101
131
|
process.env.PATH = global;
|
|
102
132
|
mockSpawn.mockReturnValue(fakeChild());
|
|
103
|
-
expect(() => (0, exec_1.runStructuredCommand)({ executable: 'tool', resolution: 'node-modules-bin', args: [] }, { timeout: 5000, cwd: dir }))
|
|
133
|
+
expect(() => (0, exec_1.runStructuredCommand)({ executable: 'tool', resolution: 'node-modules-bin', args: ['--version'] }, { timeout: 5000, cwd: dir }))
|
|
104
134
|
.toThrow(/node_modules.*not found locally/i);
|
|
105
135
|
expect(mockSpawn).not.toHaveBeenCalled();
|
|
106
136
|
}
|
|
107
137
|
finally {
|
|
108
|
-
|
|
138
|
+
restoreEnvironment('PATH', savedPath);
|
|
109
139
|
fs_1.default.rmSync(dir, { recursive: true, force: true });
|
|
110
140
|
fs_1.default.rmSync(global, { recursive: true, force: true });
|
|
111
141
|
}
|
|
112
142
|
});
|
|
143
|
+
it('fails closed when PATHEXT contains no safe executable extension', () => {
|
|
144
|
+
const dir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-structured-win-pathext-'));
|
|
145
|
+
const savedPath = process.env.PATH;
|
|
146
|
+
const savedPathExt = process.env.PATHEXT;
|
|
147
|
+
try {
|
|
148
|
+
fs_1.default.writeFileSync(path_1.default.join(dir, 'tool.cmd'), 'wrapper');
|
|
149
|
+
process.env.PATH = dir;
|
|
150
|
+
process.env.PATHEXT = '.CMD';
|
|
151
|
+
expect(() => (0, exec_1.runStructuredCommand)({ executable: 'tool', resolution: 'path', args: ['--version'] }, { timeout: 5000, cwd: dir }))
|
|
152
|
+
.toThrow(/safe Windows executable|PATHEXT/i);
|
|
153
|
+
expect(mockSpawn).not.toHaveBeenCalled();
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
restoreEnvironment('PATH', savedPath);
|
|
157
|
+
restoreEnvironment('PATHEXT', savedPathExt);
|
|
158
|
+
fs_1.default.rmSync(dir, { recursive: true, force: true });
|
|
159
|
+
}
|
|
160
|
+
});
|
|
113
161
|
it('rejects a missing Python environment executable instead of falling back to a same-named global command', () => {
|
|
114
162
|
const dir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-python-env-missing-win-'));
|
|
115
163
|
const global = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-python-env-global-win-'));
|
|
@@ -123,7 +171,7 @@ describe('runCommand — win32', () => {
|
|
|
123
171
|
expect(mockSpawn).not.toHaveBeenCalled();
|
|
124
172
|
}
|
|
125
173
|
finally {
|
|
126
|
-
|
|
174
|
+
restoreEnvironment('PATH', savedPath);
|
|
127
175
|
fs_1.default.rmSync(dir, { recursive: true, force: true });
|
|
128
176
|
fs_1.default.rmSync(global, { recursive: true, force: true });
|
|
129
177
|
}
|
|
@@ -27,7 +27,7 @@ describe('runCommand — exit codes and output', () => {
|
|
|
27
27
|
const literal = `;touch ${marker}`;
|
|
28
28
|
const received = path_1.default.join(dir, 'received');
|
|
29
29
|
const result = await (0, exec_1.runStructuredCommand)({
|
|
30
|
-
executable:
|
|
30
|
+
executable: 'node',
|
|
31
31
|
resolution: 'path',
|
|
32
32
|
args: ['-e', "require('fs').writeFileSync(process.argv[1], process.argv[2])", received, literal],
|
|
33
33
|
}, { timeout: 5000, cwd: dir });
|
|
@@ -130,6 +130,36 @@ describe('runCommand — spawn failure', () => {
|
|
|
130
130
|
expect(r.code).not.toBe(0);
|
|
131
131
|
});
|
|
132
132
|
});
|
|
133
|
+
describe('runStructuredCommand — public boundary validation', () => {
|
|
134
|
+
it.each(['sh', 'cmd.exe', '/usr/bin/node', 'nested/tool', 'nested\\tool'])('rejects unsafe executable %j before resolution', executable => {
|
|
135
|
+
expect(() => (0, exec_1.runStructuredCommand)({ executable, resolution: 'path', args: ['--version'] }, { timeout: 5000, cwd: process.cwd() }))
|
|
136
|
+
.toThrow(/safe executable name|shell/i);
|
|
137
|
+
});
|
|
138
|
+
it('normalizes package-manager spellings while requiring an equivalent explicit selection', () => {
|
|
139
|
+
expect(() => (0, exec_1.runStructuredCommand)({ executable: 'NPM.exe', resolution: 'path', args: ['--version'] }, { timeout: 5000, cwd: process.cwd() }))
|
|
140
|
+
.toThrow(/packageManager/);
|
|
141
|
+
expect(() => (0, exec_1.runStructuredCommand)({ executable: 'NPM.exe', resolution: 'path', args: ['--version'], packageManager: 'pnpm' }, { timeout: 5000, cwd: process.cwd() }))
|
|
142
|
+
.toThrow(/packageManager/);
|
|
143
|
+
});
|
|
144
|
+
it.each([
|
|
145
|
+
{ ESLINT_USE_FLAT_CONFIG: 'invalid' },
|
|
146
|
+
{ ESLINT_USE_FLAT_CONFIG: 'true', OTHER: 'value' },
|
|
147
|
+
])('rejects an unknown or expanded environment mapping at the public boundary', environment => {
|
|
148
|
+
expect(() => (0, exec_1.runStructuredCommand)({ executable: 'node', resolution: 'path', args: ['--version'], environment }, { timeout: 5000, cwd: process.cwd() }))
|
|
149
|
+
.toThrow(/exact allowlisted/);
|
|
150
|
+
});
|
|
151
|
+
it.each([
|
|
152
|
+
[{ executable: 'node', resolution: 'path', args: [] }, /nonempty array/],
|
|
153
|
+
[{ executable: 'node', resolution: 'path', args: [''] }, /nonempty single-line/],
|
|
154
|
+
[{ executable: 'node', resolution: 'path', args: ['one\ntwo'] }, /single-line/],
|
|
155
|
+
[{ executable: 'node', resolution: 'path', args: ['{files}'] }, /requires fileInput/],
|
|
156
|
+
[{ executable: 'node', resolution: 'path', args: ['prefix{files}'], fileInput: { placeholder: '{files}', extensions: ['.ts'] } }, /must not embed/],
|
|
157
|
+
[{ executable: 'node', resolution: 'path', args: ['{files}', '{files}'], fileInput: { placeholder: '{files}', extensions: ['.ts'] } }, /exactly one/],
|
|
158
|
+
[{ executable: 'node', resolution: 'path', args: ['--check'], fileInput: { placeholder: '{files}', extensions: ['.ts'] } }, /exactly one/],
|
|
159
|
+
])('rejects malformed args or file input at the public boundary', (command, message) => {
|
|
160
|
+
expect(() => (0, exec_1.runStructuredCommand)(command, { timeout: 5000, cwd: process.cwd() })).toThrow(message);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
133
163
|
onPosix('runStructuredCommand — local node_modules binaries', () => {
|
|
134
164
|
it('follows an npm-style contained shim but rejects one escaping node_modules', async () => {
|
|
135
165
|
const dir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-local-bin-symlink-'));
|
|
@@ -143,11 +173,11 @@ onPosix('runStructuredCommand — local node_modules binaries', () => {
|
|
|
143
173
|
fs_1.default.writeFileSync(outside, '#!/bin/sh\necho outside\n', { mode: 0o755 });
|
|
144
174
|
fs_1.default.mkdirSync(bin, { recursive: true });
|
|
145
175
|
fs_1.default.symlinkSync('../tool/bin/tool', path_1.default.join(bin, 'tool'));
|
|
146
|
-
await expect((0, exec_1.runStructuredCommand)({ executable: 'tool', resolution: 'node-modules-bin', args: [] }, { timeout: 5000, cwd: dir }))
|
|
176
|
+
await expect((0, exec_1.runStructuredCommand)({ executable: 'tool', resolution: 'node-modules-bin', args: ['--version'] }, { timeout: 5000, cwd: dir }))
|
|
147
177
|
.resolves.toMatchObject({ code: 0, stdout: 'contained\n' });
|
|
148
178
|
fs_1.default.unlinkSync(path_1.default.join(bin, 'tool'));
|
|
149
179
|
fs_1.default.symlinkSync(outside, path_1.default.join(bin, 'tool'));
|
|
150
|
-
expect(() => (0, exec_1.runStructuredCommand)({ executable: 'tool', resolution: 'node-modules-bin', args: [] }, { timeout: 5000, cwd: dir }))
|
|
180
|
+
expect(() => (0, exec_1.runStructuredCommand)({ executable: 'tool', resolution: 'node-modules-bin', args: ['--version'] }, { timeout: 5000, cwd: dir }))
|
|
151
181
|
.toThrow(/node_modules.*contain|local/i);
|
|
152
182
|
}
|
|
153
183
|
finally {
|
|
@@ -156,6 +186,24 @@ onPosix('runStructuredCommand — local node_modules binaries', () => {
|
|
|
156
186
|
});
|
|
157
187
|
});
|
|
158
188
|
onPosix('runStructuredCommand — Python environments', () => {
|
|
189
|
+
it.each(['.venv', 'venv'])('rejects a symlinked %s ancestor instead of executing outside the project', environment => {
|
|
190
|
+
const dir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-python-env-ancestor-'));
|
|
191
|
+
const outside = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-python-env-outside-'));
|
|
192
|
+
const marker = path_1.default.join(dir, 'must-not-exist');
|
|
193
|
+
try {
|
|
194
|
+
const executable = path_1.default.join(outside, 'bin', 'semgrep');
|
|
195
|
+
fs_1.default.mkdirSync(path_1.default.dirname(executable), { recursive: true });
|
|
196
|
+
fs_1.default.writeFileSync(executable, `#!/bin/sh\ntouch ${marker}\n`, { mode: 0o755 });
|
|
197
|
+
fs_1.default.symlinkSync(outside, path_1.default.join(dir, environment));
|
|
198
|
+
expect(() => (0, exec_1.runStructuredCommand)({ executable: 'semgrep', resolution: 'python-environment', pythonEnvironmentRoot: environment, args: ['--validate'] }, { timeout: 5000, cwd: dir }))
|
|
199
|
+
.toThrow(/python.*environment.*local|contained/i);
|
|
200
|
+
expect(fs_1.default.existsSync(marker)).toBe(false);
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
fs_1.default.rmSync(dir, { recursive: true, force: true });
|
|
204
|
+
fs_1.default.rmSync(outside, { recursive: true, force: true });
|
|
205
|
+
}
|
|
206
|
+
});
|
|
159
207
|
it('rejects a missing project Python executable instead of falling back to PATH', () => {
|
|
160
208
|
const dir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-python-env-missing-'));
|
|
161
209
|
const global = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-python-env-global-'));
|
|
@@ -7,6 +7,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const os_1 = __importDefault(require("os"));
|
|
9
9
|
const init_1 = require("../../../src/commands/sensors/init");
|
|
10
|
+
const status_1 = require("../../../src/commands/sensors/status");
|
|
10
11
|
// Build a throwaway registry with a js-ts pack.json (the single source of truth
|
|
11
12
|
// init now reads from). `defaultCmd` uses the {{SOURCE_DIRS}} placeholder for depcheck.
|
|
12
13
|
function makeRegistry() {
|
|
@@ -45,9 +46,11 @@ function makeV2Registry() {
|
|
|
45
46
|
const packDir = path_1.default.join(registryRoot, 'sensor-packs', 'js-ts');
|
|
46
47
|
fs_1.default.mkdirSync(packDir, { recursive: true });
|
|
47
48
|
fs_1.default.writeFileSync(path_1.default.join(packDir, 'eslint.config.awm.mjs'), 'export default []\n');
|
|
49
|
+
fs_1.default.writeFileSync(path_1.default.join(packDir, 'tsconfig.awm.json'), '{ "compilerOptions": { "strict": true } }\n');
|
|
48
50
|
fs_1.default.writeFileSync(path_1.default.join(packDir, 'pack.json'), JSON.stringify({
|
|
49
51
|
schemaVersion: 2, name: 'js-ts', description: 'fixture', detects: ['package.json'],
|
|
50
52
|
coverage: { schemaVersion: 1, classes: { lint: { description: 'lint', detectors: [{ sensor: 'lint' }], remedy: { summary: 'fix lint', command: 'awm sensors init --pack js-ts' } } } },
|
|
53
|
+
hardening: { 'typescript-strict': { assets: ['tsconfig.awm.json'] } },
|
|
51
54
|
sensors: { lint: { applicability: { allFiles: ['package.json'] }, variants: [{
|
|
52
55
|
id: 'eslint-10', priority: 10, certifiedRange: '>=10.0.0 <11.0.0',
|
|
53
56
|
requirements: { tool: 'eslint', toolRange: '>=10.0.0 <11.0.0', runtime: 'node', runtimeRange: '>=0.0.0' },
|
|
@@ -57,6 +60,23 @@ function makeV2Registry() {
|
|
|
57
60
|
}));
|
|
58
61
|
return registryRoot;
|
|
59
62
|
}
|
|
63
|
+
function makeGenericV2Registry() {
|
|
64
|
+
const registryRoot = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-reg-generic-v2-'));
|
|
65
|
+
const packDir = path_1.default.join(registryRoot, 'sensor-packs', 'generic');
|
|
66
|
+
fs_1.default.mkdirSync(packDir, { recursive: true });
|
|
67
|
+
fs_1.default.writeFileSync(path_1.default.join(packDir, 'generic.config'), 'fixture\n');
|
|
68
|
+
fs_1.default.writeFileSync(path_1.default.join(packDir, 'pack.json'), JSON.stringify({
|
|
69
|
+
schemaVersion: 2, name: 'generic', description: 'fixture', detects: ['README.md'],
|
|
70
|
+
coverage: { schemaVersion: 1, classes: { security: { description: 'security', detectors: [{ sensor: 'security' }], remedy: { summary: 'run security', command: 'awm sensors init --pack generic' } } } },
|
|
71
|
+
sensors: { security: { applicability: { kind: 'explicit-or-supported-language' }, variants: [{
|
|
72
|
+
id: 'eslint-10', priority: 10, certifiedRange: '>=10.0.0 <11.0.0',
|
|
73
|
+
requirements: { tool: 'eslint', toolRange: '>=10.0.0 <11.0.0', runtime: 'node', runtimeRange: '>=0.0.0', configFiles: ['generic.config'] },
|
|
74
|
+
assets: ['generic.config'], formatter: 'eslint-llm', probe: { kind: 'config-present' },
|
|
75
|
+
command: { executable: 'eslint', resolution: 'node-modules-bin', args: ['.'] },
|
|
76
|
+
}] } },
|
|
77
|
+
}));
|
|
78
|
+
return registryRoot;
|
|
79
|
+
}
|
|
60
80
|
describe('detectStack', () => {
|
|
61
81
|
let tmpDir;
|
|
62
82
|
beforeEach(() => { tmpDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-init-')); });
|
|
@@ -277,6 +297,58 @@ describe('initSensors', () => {
|
|
|
277
297
|
fs_1.default.rmSync(v2Registry, { recursive: true, force: true });
|
|
278
298
|
}
|
|
279
299
|
});
|
|
300
|
+
it('persists an explicit generic selection for live revalidation without promoting automatic generic fallback', async () => {
|
|
301
|
+
const v2Registry = makeGenericV2Registry();
|
|
302
|
+
try {
|
|
303
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, 'node_modules', 'eslint'), { recursive: true });
|
|
304
|
+
fs_1.default.writeFileSync(path_1.default.join(tmpDir, 'node_modules', 'eslint', 'package.json'), JSON.stringify({ version: '10.0.0' }));
|
|
305
|
+
const automatic = await (0, init_1.initSensors)({ cwd: tmpDir, registryRoot: v2Registry, configure: false });
|
|
306
|
+
expect(automatic.manifest).toMatchObject({ schemaVersion: 2, pack: 'generic', sensors: {} });
|
|
307
|
+
expect(automatic.manifest.packSelection).toBeUndefined();
|
|
308
|
+
const explicit = await (0, init_1.initSensors)({ cwd: tmpDir, registryRoot: v2Registry, pack: 'generic' });
|
|
309
|
+
const written = JSON.parse(fs_1.default.readFileSync(path_1.default.join(tmpDir, '.awm', 'sensors.json'), 'utf8'));
|
|
310
|
+
expect(explicit.manifest).toMatchObject({ schemaVersion: 2, pack: 'generic', packSelection: 'explicit', sensors: { security: { variantId: 'eslint-10' } } });
|
|
311
|
+
expect(written.packSelection).toBe('explicit');
|
|
312
|
+
await expect((0, status_1.computeSensorStatus)(tmpDir)).resolves.toMatchObject({ overall: 'HEALTHY', checks: { security: { ok: true } } });
|
|
313
|
+
}
|
|
314
|
+
finally {
|
|
315
|
+
fs_1.default.rmSync(v2Registry, { recursive: true, force: true });
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
it('never materializes an opt-in hardening asset during ordinary v2 init', async () => {
|
|
319
|
+
const v2Registry = makeV2Registry();
|
|
320
|
+
try {
|
|
321
|
+
fs_1.default.writeFileSync(path_1.default.join(tmpDir, 'package.json'), JSON.stringify({ devDependencies: { eslint: '^10.0.0' } }));
|
|
322
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, 'node_modules', 'eslint'), { recursive: true });
|
|
323
|
+
fs_1.default.writeFileSync(path_1.default.join(tmpDir, 'node_modules', 'eslint', 'package.json'), JSON.stringify({ version: '10.0.0' }));
|
|
324
|
+
await (0, init_1.initSensors)({ cwd: tmpDir, registryRoot: v2Registry });
|
|
325
|
+
expect(fs_1.default.existsSync(path_1.default.join(tmpDir, 'eslint.config.awm.mjs'))).toBe(true);
|
|
326
|
+
expect(fs_1.default.existsSync(path_1.default.join(tmpDir, 'tsconfig.awm.json'))).toBe(false);
|
|
327
|
+
}
|
|
328
|
+
finally {
|
|
329
|
+
fs_1.default.rmSync(v2Registry, { recursive: true, force: true });
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
it('initializes a selected v2 variant with an explicitly empty assets list', async () => {
|
|
333
|
+
const v2Registry = makeV2Registry();
|
|
334
|
+
try {
|
|
335
|
+
const packPath = path_1.default.join(v2Registry, 'sensor-packs', 'js-ts', 'pack.json');
|
|
336
|
+
const pack = JSON.parse(fs_1.default.readFileSync(packPath, 'utf8'));
|
|
337
|
+
pack.sensors.lint.variants[0].assets = [];
|
|
338
|
+
fs_1.default.writeFileSync(packPath, JSON.stringify(pack));
|
|
339
|
+
fs_1.default.writeFileSync(path_1.default.join(tmpDir, 'package.json'), JSON.stringify({ devDependencies: { eslint: '^10.0.0' } }));
|
|
340
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, 'node_modules', 'eslint'), { recursive: true });
|
|
341
|
+
fs_1.default.writeFileSync(path_1.default.join(tmpDir, 'node_modules', 'eslint', 'package.json'), JSON.stringify({ version: '10.0.0' }));
|
|
342
|
+
await expect((0, init_1.initSensors)({ cwd: tmpDir, registryRoot: v2Registry })).resolves.toMatchObject({
|
|
343
|
+
manifest: { schemaVersion: 2, sensors: { lint: { assets: [] } } },
|
|
344
|
+
configured: [],
|
|
345
|
+
});
|
|
346
|
+
expect(fs_1.default.existsSync(path_1.default.join(tmpDir, 'eslint.config.awm.mjs'))).toBe(false);
|
|
347
|
+
}
|
|
348
|
+
finally {
|
|
349
|
+
fs_1.default.rmSync(v2Registry, { recursive: true, force: true });
|
|
350
|
+
}
|
|
351
|
+
});
|
|
280
352
|
it('preserves enabled and fast choices when a valid v2 manifest is re-initialized', async () => {
|
|
281
353
|
const v2Registry = makeV2Registry();
|
|
282
354
|
try {
|
|
@@ -8,7 +8,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
8
8
|
const child_process_1 = require("child_process");
|
|
9
9
|
const CLI_ROOT = path_1.default.resolve(__dirname, '../..');
|
|
10
10
|
const DIST_ENTRYPOINT = path_1.default.join(CLI_ROOT, 'dist', 'src', 'index.js');
|
|
11
|
-
const TARGET_VERSION = '
|
|
11
|
+
const TARGET_VERSION = '8.0.0';
|
|
12
12
|
function readJson(file) {
|
|
13
13
|
return JSON.parse(fs_1.default.readFileSync(path_1.default.join(CLI_ROOT, file), 'utf8'));
|
|
14
14
|
}
|
|
@@ -22,7 +22,7 @@ function runCompiledCli(...args) {
|
|
|
22
22
|
return `${result.stdout}${result.stderr}`;
|
|
23
23
|
}
|
|
24
24
|
describe('R3 public major CLI release contract', () => {
|
|
25
|
-
it('declares
|
|
25
|
+
it('declares 8.0.0 consistently in package metadata and the lockfile root', () => {
|
|
26
26
|
const pkg = readJson('package.json');
|
|
27
27
|
const lock = readJson('package-lock.json');
|
|
28
28
|
const root = lock.packages[''];
|
|
@@ -30,7 +30,7 @@ describe('R3 public major CLI release contract', () => {
|
|
|
30
30
|
expect(lock.version).toBe(TARGET_VERSION);
|
|
31
31
|
expect(root.version).toBe(TARGET_VERSION);
|
|
32
32
|
});
|
|
33
|
-
it('exposes
|
|
33
|
+
it('exposes 8.0.0 from the compiled CLI while retaining its help banner', () => {
|
|
34
34
|
expect(runCompiledCli('--version').trim()).toBe(TARGET_VERSION);
|
|
35
35
|
expect(runCompiledCli('--help')).toContain('Usage: awm');
|
|
36
36
|
});
|