@codexsploitx/schemaapi 1.1.8 ā 1.1.9
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/cli/commands/audit.d.ts +1 -0
- package/dist/cli.js +85 -3
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function handleAudit(args: string[]): void;
|
package/dist/cli.js
CHANGED
|
@@ -6865,7 +6865,7 @@ function loadSchemaApi() {
|
|
|
6865
6865
|
return {};
|
|
6866
6866
|
}
|
|
6867
6867
|
}
|
|
6868
|
-
function loadContractsModule(contractsDir) {
|
|
6868
|
+
function loadContractsModule$1(contractsDir) {
|
|
6869
6869
|
const cwd = process.cwd();
|
|
6870
6870
|
const baseDir = path__namespace.join(cwd, contractsDir || "contracts");
|
|
6871
6871
|
const candidates = ["index.js", "index.cjs", "index.ts"];
|
|
@@ -6925,7 +6925,7 @@ function generateDocs(config) {
|
|
|
6925
6925
|
if (adapter || contractsDir) {
|
|
6926
6926
|
console.log(`Using config: adapter=${adapter || "unknown"}, contractsDir=${contractsDir}`);
|
|
6927
6927
|
}
|
|
6928
|
-
const contractsModule = loadContractsModule(contractsDir);
|
|
6928
|
+
const contractsModule = loadContractsModule$1(contractsDir);
|
|
6929
6929
|
if (!contractsModule) {
|
|
6930
6930
|
console.error(`Could not find contracts entry in ${contractsDir}. Expected index.js or index.cjs`);
|
|
6931
6931
|
return;
|
|
@@ -7099,6 +7099,88 @@ function handleGenerate(args) {
|
|
|
7099
7099
|
}
|
|
7100
7100
|
}
|
|
7101
7101
|
|
|
7102
|
+
function loadContractsModule(contractsDir) {
|
|
7103
|
+
const cwd = process.cwd();
|
|
7104
|
+
const baseDir = path__namespace.join(cwd, contractsDir);
|
|
7105
|
+
const candidates = ["index.js", "index.cjs", "index.ts"];
|
|
7106
|
+
for (const file of candidates) {
|
|
7107
|
+
const fullPath = path__namespace.join(baseDir, file);
|
|
7108
|
+
if (fs__namespace.existsSync(fullPath)) {
|
|
7109
|
+
try {
|
|
7110
|
+
// We use require/import to load the contract objects
|
|
7111
|
+
// In a real TS environment, we might need ts-node/register if loading .ts directly
|
|
7112
|
+
// But assuming the user has compiled code or we are running in a compatible env:
|
|
7113
|
+
if (file.endsWith('.ts')) {
|
|
7114
|
+
require('ts-node/register');
|
|
7115
|
+
}
|
|
7116
|
+
return require(fullPath);
|
|
7117
|
+
}
|
|
7118
|
+
catch (error) {
|
|
7119
|
+
console.error(`Failed to load contracts module at ${fullPath}:`, (error && error.message) || error);
|
|
7120
|
+
return null;
|
|
7121
|
+
}
|
|
7122
|
+
}
|
|
7123
|
+
}
|
|
7124
|
+
return null;
|
|
7125
|
+
}
|
|
7126
|
+
function handleAudit(args) {
|
|
7127
|
+
const config = loadConfig();
|
|
7128
|
+
const contractsDir = config?.contractsDir || "contracts";
|
|
7129
|
+
console.log(`š Starting SchemaApi Audit in directory: ${contractsDir}`);
|
|
7130
|
+
const contractsModule = loadContractsModule(contractsDir);
|
|
7131
|
+
if (!contractsModule) {
|
|
7132
|
+
console.error(`ā Could not find contracts entry in ${contractsDir}. Make sure index.ts/js exists and exports your contracts.`);
|
|
7133
|
+
return;
|
|
7134
|
+
}
|
|
7135
|
+
let totalIssues = 0;
|
|
7136
|
+
const candidates = Object.values(contractsModule).filter((value) => value &&
|
|
7137
|
+
typeof value === "object" &&
|
|
7138
|
+
typeof value.docs === "function" // Duck typing for Contract
|
|
7139
|
+
);
|
|
7140
|
+
if (candidates.length === 0) {
|
|
7141
|
+
console.warn("ā ļø No contracts found exported in the entry file.");
|
|
7142
|
+
return;
|
|
7143
|
+
}
|
|
7144
|
+
candidates.forEach((contract, index) => {
|
|
7145
|
+
const docs = contract.docs(); // This returns the contract structure
|
|
7146
|
+
const routes = docs.routes || [];
|
|
7147
|
+
console.log(`\nš Contract #${index + 1}: Found ${routes.length} routes`);
|
|
7148
|
+
routes.forEach((route) => {
|
|
7149
|
+
const issues = [];
|
|
7150
|
+
const method = route.method;
|
|
7151
|
+
const pathStr = route.path;
|
|
7152
|
+
const fullRoute = `${method} ${pathStr}`;
|
|
7153
|
+
// 1. Security Check: Roles
|
|
7154
|
+
if (!route.roles || route.roles.length === 0) {
|
|
7155
|
+
issues.push(`ā ļø [Security] No roles defined. Endpoint is public? Consider adding explicit roles or 'public'.`);
|
|
7156
|
+
}
|
|
7157
|
+
// 2. Validation Check: Params
|
|
7158
|
+
// Basic check: if path has :param, schema should have it
|
|
7159
|
+
const pathParams = (pathStr.match(/:[a-zA-Z0-9_]+/g) || []).map((p) => p.substring(1));
|
|
7160
|
+
if (pathParams.length > 0) ;
|
|
7161
|
+
// 3. Completeness: Errors
|
|
7162
|
+
if (!route.errors || Object.keys(route.errors).length === 0) {
|
|
7163
|
+
issues.push(`ā¹ļø [Best Practice] No error status codes defined. Clients won't know what errors to expect.`);
|
|
7164
|
+
}
|
|
7165
|
+
if (issues.length > 0) {
|
|
7166
|
+
console.log(` šø ${fullRoute}`);
|
|
7167
|
+
issues.forEach(issue => console.log(` ${issue}`));
|
|
7168
|
+
totalIssues += issues.length;
|
|
7169
|
+
}
|
|
7170
|
+
else {
|
|
7171
|
+
console.log(` ā
${fullRoute}`);
|
|
7172
|
+
}
|
|
7173
|
+
});
|
|
7174
|
+
});
|
|
7175
|
+
console.log(`\nš Audit complete.`);
|
|
7176
|
+
if (totalIssues > 0) {
|
|
7177
|
+
console.log(`Found ${totalIssues} potential issues.`);
|
|
7178
|
+
}
|
|
7179
|
+
else {
|
|
7180
|
+
console.log(`No obvious issues found. Great job! š`);
|
|
7181
|
+
}
|
|
7182
|
+
}
|
|
7183
|
+
|
|
7102
7184
|
async function cli(args) {
|
|
7103
7185
|
const command = args[0];
|
|
7104
7186
|
switch (command) {
|
|
@@ -7109,7 +7191,7 @@ async function cli(args) {
|
|
|
7109
7191
|
handleGenerate(args.slice(1));
|
|
7110
7192
|
break;
|
|
7111
7193
|
case 'audit':
|
|
7112
|
-
|
|
7194
|
+
handleAudit(args.slice(1));
|
|
7113
7195
|
break;
|
|
7114
7196
|
case 'adapters':
|
|
7115
7197
|
console.log(`
|