@solidnumber/cli 1.7.1 → 1.7.3
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/LICENSE +37 -0
- package/dist/commands/analytics.js +17 -10
- package/dist/commands/analytics.js.map +1 -1
- package/dist/commands/api.d.ts +10 -0
- package/dist/commands/api.d.ts.map +1 -0
- package/dist/commands/api.js +305 -0
- package/dist/commands/api.js.map +1 -0
- package/dist/commands/audit.js +1 -1
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/auth.js +16 -4
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/brand.js +122 -0
- package/dist/commands/brand.js.map +1 -1
- package/dist/commands/clone.d.ts.map +1 -1
- package/dist/commands/clone.js +67 -0
- package/dist/commands/clone.js.map +1 -1
- package/dist/commands/completion.d.ts.map +1 -1
- package/dist/commands/completion.js +22 -9
- package/dist/commands/completion.js.map +1 -1
- package/dist/commands/context.js +1 -1
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/dashboard.d.ts +11 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +158 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/demo.d.ts +12 -0
- package/dist/commands/demo.d.ts.map +1 -0
- package/dist/commands/demo.js +257 -0
- package/dist/commands/demo.js.map +1 -0
- package/dist/commands/flows.d.ts.map +1 -1
- package/dist/commands/flows.js +11 -0
- package/dist/commands/flows.js.map +1 -1
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +45 -37
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/import.d.ts.map +1 -1
- package/dist/commands/import.js +8 -1
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/inbox.js +1 -1
- package/dist/commands/inbox.js.map +1 -1
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +377 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/inventory.js +5 -5
- package/dist/commands/inventory.js.map +1 -1
- package/dist/commands/open.d.ts.map +1 -1
- package/dist/commands/open.js +29 -0
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/payment.js +101 -0
- package/dist/commands/payment.js.map +1 -1
- package/dist/commands/proposal.d.ts +9 -0
- package/dist/commands/proposal.d.ts.map +1 -0
- package/dist/commands/proposal.js +160 -0
- package/dist/commands/proposal.js.map +1 -0
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +42 -0
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/sandbox.d.ts.map +1 -1
- package/dist/commands/sandbox.js +113 -0
- package/dist/commands/sandbox.js.map +1 -1
- package/dist/commands/seo.js +6 -3
- package/dist/commands/seo.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +32 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/webhooks-listen.d.ts +12 -0
- package/dist/commands/webhooks-listen.d.ts.map +1 -0
- package/dist/commands/webhooks-listen.js +217 -0
- package/dist/commands/webhooks-listen.js.map +1 -0
- package/dist/index.js +20 -4
- package/dist/index.js.map +1 -1
- package/dist/lib/api-client.d.ts +2 -9
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +17 -13
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +4 -4
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/ui.d.ts.map +1 -1
- package/dist/lib/ui.js +38 -2
- package/dist/lib/ui.js.map +1 -1
- package/package.json +7 -5
- package/platform-docs/llms.txt +4 -4
- package/dist/__tests__/commands/auth.test.d.ts +0 -6
- package/dist/__tests__/commands/auth.test.d.ts.map +0 -1
- package/dist/__tests__/commands/auth.test.js +0 -91
- package/dist/__tests__/commands/auth.test.js.map +0 -1
- package/dist/__tests__/commands/billing.test.d.ts +0 -6
- package/dist/__tests__/commands/billing.test.d.ts.map +0 -1
- package/dist/__tests__/commands/billing.test.js +0 -141
- package/dist/__tests__/commands/billing.test.js.map +0 -1
- package/dist/__tests__/commands/company.test.d.ts +0 -6
- package/dist/__tests__/commands/company.test.d.ts.map +0 -1
- package/dist/__tests__/commands/company.test.js +0 -129
- package/dist/__tests__/commands/company.test.js.map +0 -1
- package/dist/__tests__/commands/deploy.test.d.ts +0 -8
- package/dist/__tests__/commands/deploy.test.d.ts.map +0 -1
- package/dist/__tests__/commands/deploy.test.js +0 -190
- package/dist/__tests__/commands/deploy.test.js.map +0 -1
- package/dist/__tests__/commands/history.test.d.ts +0 -8
- package/dist/__tests__/commands/history.test.d.ts.map +0 -1
- package/dist/__tests__/commands/history.test.js +0 -213
- package/dist/__tests__/commands/history.test.js.map +0 -1
- package/dist/__tests__/commands/import.test.d.ts +0 -4
- package/dist/__tests__/commands/import.test.d.ts.map +0 -1
- package/dist/__tests__/commands/import.test.js +0 -71
- package/dist/__tests__/commands/import.test.js.map +0 -1
- package/dist/__tests__/commands/logs.test.d.ts +0 -5
- package/dist/__tests__/commands/logs.test.d.ts.map +0 -1
- package/dist/__tests__/commands/logs.test.js +0 -124
- package/dist/__tests__/commands/logs.test.js.map +0 -1
- package/dist/__tests__/commands/migrate.test.d.ts +0 -9
- package/dist/__tests__/commands/migrate.test.d.ts.map +0 -1
- package/dist/__tests__/commands/migrate.test.js +0 -277
- package/dist/__tests__/commands/migrate.test.js.map +0 -1
- package/dist/__tests__/commands/pages.test.d.ts +0 -5
- package/dist/__tests__/commands/pages.test.d.ts.map +0 -1
- package/dist/__tests__/commands/pages.test.js +0 -103
- package/dist/__tests__/commands/pages.test.js.map +0 -1
- package/dist/__tests__/commands/push.test.d.ts +0 -6
- package/dist/__tests__/commands/push.test.d.ts.map +0 -1
- package/dist/__tests__/commands/push.test.js +0 -113
- package/dist/__tests__/commands/push.test.js.map +0 -1
- package/dist/__tests__/commands/sandbox.test.d.ts +0 -5
- package/dist/__tests__/commands/sandbox.test.d.ts.map +0 -1
- package/dist/__tests__/commands/sandbox.test.js +0 -132
- package/dist/__tests__/commands/sandbox.test.js.map +0 -1
- package/dist/__tests__/commands/serve.test.d.ts +0 -5
- package/dist/__tests__/commands/serve.test.d.ts.map +0 -1
- package/dist/__tests__/commands/serve.test.js +0 -115
- package/dist/__tests__/commands/serve.test.js.map +0 -1
- package/dist/__tests__/commands/site.test.d.ts +0 -5
- package/dist/__tests__/commands/site.test.d.ts.map +0 -1
- package/dist/__tests__/commands/site.test.js +0 -92
- package/dist/__tests__/commands/site.test.js.map +0 -1
- package/dist/__tests__/commands/test.test.d.ts +0 -5
- package/dist/__tests__/commands/test.test.d.ts.map +0 -1
- package/dist/__tests__/commands/test.test.js +0 -220
- package/dist/__tests__/commands/test.test.js.map +0 -1
- package/dist/__tests__/integration/smoke.test.d.ts +0 -7
- package/dist/__tests__/integration/smoke.test.d.ts.map +0 -1
- package/dist/__tests__/integration/smoke.test.js +0 -135
- package/dist/__tests__/integration/smoke.test.js.map +0 -1
- package/dist/__tests__/lib/api-client.test.d.ts +0 -6
- package/dist/__tests__/lib/api-client.test.d.ts.map +0 -1
- package/dist/__tests__/lib/api-client.test.js +0 -74
- package/dist/__tests__/lib/api-client.test.js.map +0 -1
- package/dist/__tests__/lib/company-isolation.test.d.ts +0 -19
- package/dist/__tests__/lib/company-isolation.test.d.ts.map +0 -1
- package/dist/__tests__/lib/company-isolation.test.js +0 -96
- package/dist/__tests__/lib/company-isolation.test.js.map +0 -1
- package/dist/__tests__/lib/config.test.d.ts +0 -6
- package/dist/__tests__/lib/config.test.d.ts.map +0 -1
- package/dist/__tests__/lib/config.test.js +0 -131
- package/dist/__tests__/lib/config.test.js.map +0 -1
- package/dist/__tests__/setup.d.ts +0 -4
- package/dist/__tests__/setup.d.ts.map +0 -1
- package/dist/__tests__/setup.js +0 -25
- package/dist/__tests__/setup.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"smoke.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/smoke.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Smoke tests — verify the CLI binary doesn't crash on basic operations.
|
|
4
|
-
* These run the actual compiled JS, not the TypeScript source.
|
|
5
|
-
* NO API calls — just verifies the CLI starts, shows help, and exits cleanly.
|
|
6
|
-
*/
|
|
7
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
-
if (k2 === undefined) k2 = k;
|
|
9
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
-
}
|
|
13
|
-
Object.defineProperty(o, k2, desc);
|
|
14
|
-
}) : (function(o, m, k, k2) {
|
|
15
|
-
if (k2 === undefined) k2 = k;
|
|
16
|
-
o[k2] = m[k];
|
|
17
|
-
}));
|
|
18
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
-
}) : function(o, v) {
|
|
21
|
-
o["default"] = v;
|
|
22
|
-
});
|
|
23
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
-
var ownKeys = function(o) {
|
|
25
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
-
var ar = [];
|
|
27
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
-
return ar;
|
|
29
|
-
};
|
|
30
|
-
return ownKeys(o);
|
|
31
|
-
};
|
|
32
|
-
return function (mod) {
|
|
33
|
-
if (mod && mod.__esModule) return mod;
|
|
34
|
-
var result = {};
|
|
35
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
-
__setModuleDefault(result, mod);
|
|
37
|
-
return result;
|
|
38
|
-
};
|
|
39
|
-
})();
|
|
40
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
-
const child_process_1 = require("child_process");
|
|
42
|
-
const path = __importStar(require("path"));
|
|
43
|
-
const fs = __importStar(require("fs"));
|
|
44
|
-
const CLI_PATH = path.join(__dirname, '..', '..', '..', 'dist', 'index.js');
|
|
45
|
-
function run(args) {
|
|
46
|
-
return (0, child_process_1.execSync)(`node ${CLI_PATH} ${args}`, {
|
|
47
|
-
timeout: 10000,
|
|
48
|
-
env: { ...process.env, HOME: '/tmp/solid-test-home', SOLID_API_KEY: '' },
|
|
49
|
-
}).toString();
|
|
50
|
-
}
|
|
51
|
-
function runSafe(args) {
|
|
52
|
-
try {
|
|
53
|
-
const stdout = (0, child_process_1.execSync)(`node ${CLI_PATH} ${args}`, {
|
|
54
|
-
timeout: 10000,
|
|
55
|
-
env: { ...process.env, HOME: '/tmp/solid-test-home', SOLID_API_KEY: '' },
|
|
56
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
57
|
-
}).toString();
|
|
58
|
-
return { stdout, exitCode: 0 };
|
|
59
|
-
}
|
|
60
|
-
catch (e) {
|
|
61
|
-
return { stdout: e.stdout?.toString() || '', exitCode: e.status || 1 };
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
describe('CLI Smoke Tests', () => {
|
|
65
|
-
beforeAll(() => {
|
|
66
|
-
// Verify dist exists
|
|
67
|
-
if (!fs.existsSync(CLI_PATH)) {
|
|
68
|
-
throw new Error(`CLI not built. Run: npm run build\nExpected: ${CLI_PATH}`);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
it('--version prints a valid semver', () => {
|
|
72
|
-
const output = run('--version');
|
|
73
|
-
expect(output.trim()).toMatch(/^\d+\.\d+\.\d+$/);
|
|
74
|
-
});
|
|
75
|
-
it('--version matches package.json', () => {
|
|
76
|
-
const output = run('--version').trim();
|
|
77
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', '..', 'package.json'), 'utf-8'));
|
|
78
|
-
expect(output).toBe(pkg.version);
|
|
79
|
-
});
|
|
80
|
-
it('--help shows command list', () => {
|
|
81
|
-
const output = run('--help');
|
|
82
|
-
expect(output).toContain('auth');
|
|
83
|
-
expect(output).toContain('company');
|
|
84
|
-
expect(output).toContain('pages');
|
|
85
|
-
expect(output).toContain('site');
|
|
86
|
-
expect(output).toContain('clone');
|
|
87
|
-
expect(output).toContain('billing');
|
|
88
|
-
});
|
|
89
|
-
it('completion outputs zsh script', () => {
|
|
90
|
-
const output = run('completion');
|
|
91
|
-
expect(output).toContain('#compdef solid');
|
|
92
|
-
expect(output).toContain('_solid');
|
|
93
|
-
});
|
|
94
|
-
it('completion --bash outputs bash script', () => {
|
|
95
|
-
const output = run('completion --bash');
|
|
96
|
-
expect(output).toContain('_solid_completions');
|
|
97
|
-
expect(output).toContain('complete -F');
|
|
98
|
-
});
|
|
99
|
-
it('completion --fish outputs fish script', () => {
|
|
100
|
-
const output = run('completion --fish');
|
|
101
|
-
expect(output).toContain('complete -c solid');
|
|
102
|
-
});
|
|
103
|
-
it('auth status without credentials exits without crashing', () => {
|
|
104
|
-
const result = runSafe('auth status');
|
|
105
|
-
// Should not hang or segfault — exit code 0 or 1 are both fine
|
|
106
|
-
expect(result.exitCode).toBeLessThanOrEqual(1);
|
|
107
|
-
});
|
|
108
|
-
it('unknown command shows help, not a crash', () => {
|
|
109
|
-
const result = runSafe('nonexistent-command');
|
|
110
|
-
expect(result.exitCode).toBeLessThanOrEqual(1);
|
|
111
|
-
});
|
|
112
|
-
it('pages --help does not crash', () => {
|
|
113
|
-
const output = run('pages --help');
|
|
114
|
-
expect(output).toContain('list');
|
|
115
|
-
expect(output).toContain('publish');
|
|
116
|
-
});
|
|
117
|
-
it('site --help does not crash', () => {
|
|
118
|
-
const output = run('site --help');
|
|
119
|
-
expect(output).toContain('list');
|
|
120
|
-
expect(output).toContain('create');
|
|
121
|
-
expect(output).toContain('templates');
|
|
122
|
-
});
|
|
123
|
-
it('billing --help does not crash', () => {
|
|
124
|
-
const output = run('billing --help');
|
|
125
|
-
expect(output).toContain('status');
|
|
126
|
-
expect(output).toContain('checkout-link');
|
|
127
|
-
expect(output).toContain('invoice');
|
|
128
|
-
});
|
|
129
|
-
it('seo --help does not crash', () => {
|
|
130
|
-
const output = run('seo --help');
|
|
131
|
-
expect(output).toContain('site-audit');
|
|
132
|
-
expect(output).toContain('report');
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
//# sourceMappingURL=smoke.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"smoke.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/smoke.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/lib/api-client.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* API Client tests — verifies error handling and request shapes.
|
|
4
|
-
* Mocks axios so NO real HTTP calls are made.
|
|
5
|
-
*/
|
|
6
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
-
};
|
|
9
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
const api_client_1 = require("../../lib/api-client");
|
|
11
|
-
const axios_1 = __importDefault(require("axios"));
|
|
12
|
-
describe('handleApiError', () => {
|
|
13
|
-
it('extracts detail from axios error response', () => {
|
|
14
|
-
jest.spyOn(axios_1.default, 'isAxiosError').mockReturnValue(true);
|
|
15
|
-
const error = {
|
|
16
|
-
isAxiosError: true,
|
|
17
|
-
response: { status: 404, data: { detail: 'Not found' } },
|
|
18
|
-
message: 'Request failed',
|
|
19
|
-
};
|
|
20
|
-
const result = (0, api_client_1.handleApiError)(error);
|
|
21
|
-
expect(result.message).toBe('Not found');
|
|
22
|
-
expect(result.status).toBe(404);
|
|
23
|
-
});
|
|
24
|
-
it('extracts message field when detail is missing', () => {
|
|
25
|
-
jest.spyOn(axios_1.default, 'isAxiosError').mockReturnValue(true);
|
|
26
|
-
const error = {
|
|
27
|
-
isAxiosError: true,
|
|
28
|
-
response: { status: 400, data: { message: 'Bad request' } },
|
|
29
|
-
message: 'Request failed',
|
|
30
|
-
};
|
|
31
|
-
const result = (0, api_client_1.handleApiError)(error);
|
|
32
|
-
expect(result.message).toBe('Bad request');
|
|
33
|
-
expect(result.status).toBe(400);
|
|
34
|
-
});
|
|
35
|
-
it('falls back to axios message when no response data', () => {
|
|
36
|
-
jest.spyOn(axios_1.default, 'isAxiosError').mockReturnValue(true);
|
|
37
|
-
const error = {
|
|
38
|
-
isAxiosError: true,
|
|
39
|
-
response: { status: 500, data: {} },
|
|
40
|
-
message: 'Network Error',
|
|
41
|
-
};
|
|
42
|
-
const result = (0, api_client_1.handleApiError)(error);
|
|
43
|
-
expect(result.message).toBe('Network Error');
|
|
44
|
-
});
|
|
45
|
-
it('handles non-axios Error objects', () => {
|
|
46
|
-
jest.spyOn(axios_1.default, 'isAxiosError').mockReturnValue(false);
|
|
47
|
-
const result = (0, api_client_1.handleApiError)(new Error('Connection timeout'));
|
|
48
|
-
expect(result.message).toBe('Connection timeout');
|
|
49
|
-
expect(result.status).toBe(500);
|
|
50
|
-
});
|
|
51
|
-
it('handles unknown error types', () => {
|
|
52
|
-
jest.spyOn(axios_1.default, 'isAxiosError').mockReturnValue(false);
|
|
53
|
-
const result = (0, api_client_1.handleApiError)('some string error');
|
|
54
|
-
expect(result.message).toBe('Unknown error');
|
|
55
|
-
expect(result.status).toBe(500);
|
|
56
|
-
});
|
|
57
|
-
it('handles null/undefined errors', () => {
|
|
58
|
-
jest.spyOn(axios_1.default, 'isAxiosError').mockReturnValue(false);
|
|
59
|
-
const result = (0, api_client_1.handleApiError)(null);
|
|
60
|
-
expect(result.message).toBe('Unknown error');
|
|
61
|
-
});
|
|
62
|
-
it('returns 401 status for auth errors', () => {
|
|
63
|
-
jest.spyOn(axios_1.default, 'isAxiosError').mockReturnValue(true);
|
|
64
|
-
const error = {
|
|
65
|
-
isAxiosError: true,
|
|
66
|
-
response: { status: 401, data: { detail: 'Token expired' } },
|
|
67
|
-
message: 'Unauthorized',
|
|
68
|
-
};
|
|
69
|
-
const result = (0, api_client_1.handleApiError)(error);
|
|
70
|
-
expect(result.status).toBe(401);
|
|
71
|
-
expect(result.message).toBe('Token expired');
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
//# sourceMappingURL=api-client.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.test.js","sourceRoot":"","sources":["../../../src/__tests__/lib/api-client.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Company Isolation Tests — CRITICAL SECURITY
|
|
3
|
-
*
|
|
4
|
-
* Verifies that the CLI cannot cross company boundaries.
|
|
5
|
-
* An AI agent bot with a JWT for company 42 must NEVER be able to
|
|
6
|
-
* read, write, or modify data belonging to company 43.
|
|
7
|
-
*
|
|
8
|
-
* The CLI relies on the backend for enforcement (JWT contains company_id,
|
|
9
|
-
* RLS policies on all 420 tables, middleware checks). These tests verify
|
|
10
|
-
* the CLI's CONTRIBUTION to isolation:
|
|
11
|
-
*
|
|
12
|
-
* 1. Every API call includes X-Company-ID header
|
|
13
|
-
* 2. Company switch replaces the JWT entirely (not just a header)
|
|
14
|
-
* 3. Config never falls back to a default company_id
|
|
15
|
-
* 4. Logout clears ALL company context
|
|
16
|
-
* 5. Reserved company IDs (1, 2, 3) are never used in normal operations
|
|
17
|
-
*/
|
|
18
|
-
export {};
|
|
19
|
-
//# sourceMappingURL=company-isolation.test.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"company-isolation.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/lib/company-isolation.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG"}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Company Isolation Tests — CRITICAL SECURITY
|
|
4
|
-
*
|
|
5
|
-
* Verifies that the CLI cannot cross company boundaries.
|
|
6
|
-
* An AI agent bot with a JWT for company 42 must NEVER be able to
|
|
7
|
-
* read, write, or modify data belonging to company 43.
|
|
8
|
-
*
|
|
9
|
-
* The CLI relies on the backend for enforcement (JWT contains company_id,
|
|
10
|
-
* RLS policies on all 420 tables, middleware checks). These tests verify
|
|
11
|
-
* the CLI's CONTRIBUTION to isolation:
|
|
12
|
-
*
|
|
13
|
-
* 1. Every API call includes X-Company-ID header
|
|
14
|
-
* 2. Company switch replaces the JWT entirely (not just a header)
|
|
15
|
-
* 3. Config never falls back to a default company_id
|
|
16
|
-
* 4. Logout clears ALL company context
|
|
17
|
-
* 5. Reserved company IDs (1, 2, 3) are never used in normal operations
|
|
18
|
-
*/
|
|
19
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
const config_1 = require("../../lib/config");
|
|
21
|
-
describe('Company Isolation — Security Critical', () => {
|
|
22
|
-
describe('company_id is always explicit', () => {
|
|
23
|
-
it('config.companyId is set in test environment', () => {
|
|
24
|
-
expect(config_1.config.companyId).toBe(99999);
|
|
25
|
-
});
|
|
26
|
-
it('companyId is a number, never a string', () => {
|
|
27
|
-
expect(typeof config_1.config.companyId).toBe('number');
|
|
28
|
-
});
|
|
29
|
-
it('companyId is never 0 (which could bypass RLS)', () => {
|
|
30
|
-
expect(config_1.config.companyId).not.toBe(0);
|
|
31
|
-
});
|
|
32
|
-
it('companyId is never negative', () => {
|
|
33
|
-
expect(config_1.config.companyId).toBeGreaterThan(0);
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
describe('reserved company IDs are protected', () => {
|
|
37
|
-
const RESERVED = [1, 2, 3];
|
|
38
|
-
it('company 1 (SolidNumber Dev) is never used in tests', () => {
|
|
39
|
-
expect(config_1.config.companyId).not.toBe(1);
|
|
40
|
-
});
|
|
41
|
-
it('company 2 (Template Company) is never used in tests', () => {
|
|
42
|
-
expect(config_1.config.companyId).not.toBe(2);
|
|
43
|
-
});
|
|
44
|
-
it('company 3 (SolidNumber Production) is never used in tests', () => {
|
|
45
|
-
expect(config_1.config.companyId).not.toBe(3);
|
|
46
|
-
});
|
|
47
|
-
it('test company_id 99999 is not a reserved ID', () => {
|
|
48
|
-
expect(RESERVED).not.toContain(99999);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
describe('logout clears all company context', () => {
|
|
52
|
-
it('logout is callable', () => {
|
|
53
|
-
expect(typeof config_1.config.logout).toBe('function');
|
|
54
|
-
});
|
|
55
|
-
// The actual logout behavior is tested in config.test.ts
|
|
56
|
-
// Here we verify the CONTRACT: logout must clear company_id
|
|
57
|
-
it('after logout, a re-login is required before any API call', () => {
|
|
58
|
-
// The isLoggedIn check gates every command
|
|
59
|
-
// If logout works correctly, isLoggedIn() returns false after
|
|
60
|
-
expect(config_1.config.isLoggedIn).toBeDefined();
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
describe('API key isolation', () => {
|
|
64
|
-
it('SOLID_API_KEY env var is not set in test environment', () => {
|
|
65
|
-
// Tests must NEVER use a real API key
|
|
66
|
-
const testEnvKey = process.env.SOLID_API_KEY;
|
|
67
|
-
expect(testEnvKey).toBeFalsy();
|
|
68
|
-
});
|
|
69
|
-
it('access token in test config is clearly fake', () => {
|
|
70
|
-
expect(config_1.config.accessToken).toContain('test');
|
|
71
|
-
expect(config_1.config.accessToken).not.toContain('sk_');
|
|
72
|
-
expect(config_1.config.accessToken).not.toContain('solid_');
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
describe('cross-company protection contract', () => {
|
|
76
|
-
it('API client sends X-Company-ID header from config', () => {
|
|
77
|
-
// The api-client.ts interceptor attaches X-Company-ID from config.companyId
|
|
78
|
-
// This test documents the CONTRACT — the interceptor is tested in api-client tests
|
|
79
|
-
// Backend rejects requests where JWT company_id != X-Company-ID
|
|
80
|
-
expect(config_1.config.companyId).toBeDefined();
|
|
81
|
-
});
|
|
82
|
-
it('company switch requires a new JWT, not just a header change', () => {
|
|
83
|
-
// companySwitch returns a NEW access_token + refresh_token
|
|
84
|
-
// The old JWT is replaced entirely
|
|
85
|
-
// This prevents an attacker from just changing X-Company-ID header
|
|
86
|
-
// while keeping an old JWT (backend would reject mismatched JWT)
|
|
87
|
-
expect(true).toBe(true); // Contract documentation
|
|
88
|
-
});
|
|
89
|
-
it('no fallback to company_id=1 anywhere', () => {
|
|
90
|
-
// A common vulnerability: code falls back to company_id=1 when auth fails
|
|
91
|
-
// The CLI must NEVER do this — missing auth = error, not fallback
|
|
92
|
-
expect(config_1.config.companyId).not.toBe(1);
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
//# sourceMappingURL=company-isolation.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"company-isolation.test.js","sourceRoot":"","sources":["../../../src/__tests__/lib/company-isolation.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/lib/config.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Config manager tests — verifies auth state, token expiry, logout, company isolation.
|
|
4
|
-
* Mocks filesystem so no real ~/.solid/config.json is touched.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
// Mock fs before importing config
|
|
8
|
-
jest.mock('fs', () => ({
|
|
9
|
-
existsSync: jest.fn(() => false),
|
|
10
|
-
readFileSync: jest.fn(() => '{}'),
|
|
11
|
-
writeFileSync: jest.fn(),
|
|
12
|
-
mkdirSync: jest.fn(),
|
|
13
|
-
chmodSync: jest.fn(),
|
|
14
|
-
}));
|
|
15
|
-
// Must require after mock
|
|
16
|
-
const { ConfigManager } = jest.requireActual('../../lib/config');
|
|
17
|
-
describe('ConfigManager', () => {
|
|
18
|
-
// We can't instantiate ConfigManager directly since it's not exported.
|
|
19
|
-
// Test through the exported config behavior via the mock in setup.ts.
|
|
20
|
-
// These tests verify the LOGIC, not the instance.
|
|
21
|
-
describe('isLoggedIn', () => {
|
|
22
|
-
it('returns false when no token', () => {
|
|
23
|
-
const config = { accessToken: undefined, tokenExpiresAt: undefined };
|
|
24
|
-
const isLoggedIn = () => {
|
|
25
|
-
if (!config.accessToken)
|
|
26
|
-
return false;
|
|
27
|
-
if (config.tokenExpiresAt && config.tokenExpiresAt < new Date())
|
|
28
|
-
return false;
|
|
29
|
-
return true;
|
|
30
|
-
};
|
|
31
|
-
expect(isLoggedIn()).toBe(false);
|
|
32
|
-
});
|
|
33
|
-
it('returns true when token exists and not expired', () => {
|
|
34
|
-
const config = {
|
|
35
|
-
accessToken: 'valid_token',
|
|
36
|
-
tokenExpiresAt: new Date(Date.now() + 3600000),
|
|
37
|
-
};
|
|
38
|
-
const isLoggedIn = () => {
|
|
39
|
-
if (!config.accessToken)
|
|
40
|
-
return false;
|
|
41
|
-
if (config.tokenExpiresAt && config.tokenExpiresAt < new Date())
|
|
42
|
-
return false;
|
|
43
|
-
return true;
|
|
44
|
-
};
|
|
45
|
-
expect(isLoggedIn()).toBe(true);
|
|
46
|
-
});
|
|
47
|
-
it('returns false when token is expired', () => {
|
|
48
|
-
const config = {
|
|
49
|
-
accessToken: 'expired_token',
|
|
50
|
-
tokenExpiresAt: new Date(Date.now() - 3600000), // 1 hour ago
|
|
51
|
-
};
|
|
52
|
-
const isLoggedIn = () => {
|
|
53
|
-
if (!config.accessToken)
|
|
54
|
-
return false;
|
|
55
|
-
if (config.tokenExpiresAt && config.tokenExpiresAt < new Date())
|
|
56
|
-
return false;
|
|
57
|
-
return true;
|
|
58
|
-
};
|
|
59
|
-
expect(isLoggedIn()).toBe(false);
|
|
60
|
-
});
|
|
61
|
-
it('returns true when token exists with no expiry', () => {
|
|
62
|
-
const config = {
|
|
63
|
-
accessToken: 'api_key_no_expiry',
|
|
64
|
-
tokenExpiresAt: undefined,
|
|
65
|
-
};
|
|
66
|
-
const isLoggedIn = () => {
|
|
67
|
-
if (!config.accessToken)
|
|
68
|
-
return false;
|
|
69
|
-
if (config.tokenExpiresAt && config.tokenExpiresAt < new Date())
|
|
70
|
-
return false;
|
|
71
|
-
return true;
|
|
72
|
-
};
|
|
73
|
-
expect(isLoggedIn()).toBe(true);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
describe('logout', () => {
|
|
77
|
-
it('clears all auth fields', () => {
|
|
78
|
-
const data = {
|
|
79
|
-
api_url: 'https://api.solidnumber.com',
|
|
80
|
-
environment: 'production',
|
|
81
|
-
access_token: 'token',
|
|
82
|
-
refresh_token: 'refresh',
|
|
83
|
-
token_expires_at: '2026-01-01',
|
|
84
|
-
user_id: 1,
|
|
85
|
-
user_email: 'test@test.com',
|
|
86
|
-
company_id: 42,
|
|
87
|
-
companies: [{ id: 1, name: 'Test', role: 'owner' }],
|
|
88
|
-
};
|
|
89
|
-
// Simulate logout
|
|
90
|
-
delete data.access_token;
|
|
91
|
-
delete data.refresh_token;
|
|
92
|
-
delete data.token_expires_at;
|
|
93
|
-
delete data.user_id;
|
|
94
|
-
delete data.user_email;
|
|
95
|
-
delete data.company_id;
|
|
96
|
-
delete data.companies;
|
|
97
|
-
expect(data.access_token).toBeUndefined();
|
|
98
|
-
expect(data.refresh_token).toBeUndefined();
|
|
99
|
-
expect(data.user_id).toBeUndefined();
|
|
100
|
-
expect(data.company_id).toBeUndefined();
|
|
101
|
-
expect(data.companies).toBeUndefined();
|
|
102
|
-
// api_url and environment should survive logout
|
|
103
|
-
expect(data.api_url).toBe('https://api.solidnumber.com');
|
|
104
|
-
expect(data.environment).toBe('production');
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
describe('company isolation', () => {
|
|
108
|
-
it('company_id is always scoped — never undefined in active session', () => {
|
|
109
|
-
const config = { companyId: 99999 };
|
|
110
|
-
expect(config.companyId).toBeDefined();
|
|
111
|
-
expect(typeof config.companyId).toBe('number');
|
|
112
|
-
});
|
|
113
|
-
it('setting companyId to undefined removes it', () => {
|
|
114
|
-
const data = { company_id: 42 };
|
|
115
|
-
// Simulate set companyId(undefined)
|
|
116
|
-
delete data.company_id;
|
|
117
|
-
expect(data.company_id).toBeUndefined();
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
describe('file security', () => {
|
|
121
|
-
it('config dir created with 0o700 (user-only)', () => {
|
|
122
|
-
// The actual ConfigManager calls mkdirSync with mode 0o700
|
|
123
|
-
// We verify the expected mode constant
|
|
124
|
-
expect(0o700).toBe(448); // rwx------
|
|
125
|
-
});
|
|
126
|
-
it('config file created with 0o600 (user read/write only)', () => {
|
|
127
|
-
expect(0o600).toBe(384); // rw-------
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
//# sourceMappingURL=config.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.test.js","sourceRoot":"","sources":["../../../src/__tests__/lib/config.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/dist/__tests__/setup.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Global test setup — prevents tests from touching real config, real API, or real companies.
|
|
4
|
-
*/
|
|
5
|
-
// Mock config — prevents filesystem access to ~/.solid/
|
|
6
|
-
jest.mock('../lib/config', () => ({
|
|
7
|
-
config: {
|
|
8
|
-
apiUrl: 'https://test-api.solidnumber.com',
|
|
9
|
-
companyId: 99999,
|
|
10
|
-
accessToken: 'test_token_do_not_use_in_production',
|
|
11
|
-
refreshToken: 'test_refresh_token',
|
|
12
|
-
tokenExpiresAt: new Date(Date.now() + 3600000),
|
|
13
|
-
userId: 1,
|
|
14
|
-
userEmail: 'test@solidnumber.com',
|
|
15
|
-
environment: 'development',
|
|
16
|
-
companies: [],
|
|
17
|
-
isLoggedIn: jest.fn(() => true),
|
|
18
|
-
logout: jest.fn(),
|
|
19
|
-
},
|
|
20
|
-
}));
|
|
21
|
-
// Mock process.exit so it throws instead of killing the test runner
|
|
22
|
-
jest.spyOn(process, 'exit').mockImplementation((() => {
|
|
23
|
-
throw new Error('process.exit called');
|
|
24
|
-
}));
|
|
25
|
-
//# sourceMappingURL=setup.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":";AAAA;;GAEG;AAEH,wDAAwD;AACxD,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;IAChC,MAAM,EAAE;QACN,MAAM,EAAE,kCAAkC;QAC1C,SAAS,EAAE,KAAK;QAChB,WAAW,EAAE,qCAAqC;QAClD,YAAY,EAAE,oBAAoB;QAClC,cAAc,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;QAC9C,MAAM,EAAE,CAAC;QACT,SAAS,EAAE,sBAAsB;QACjC,WAAW,EAAE,aAAa;QAC1B,SAAS,EAAE,EAAE;QACb,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;QAC/B,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE;KAClB;CACF,CAAC,CAAC,CAAC;AAEJ,oEAAoE;AACpE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC,GAAG,EAAE;IACnD,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;AACzC,CAAC,CAAQ,CAAC,CAAC"}
|