shippingszn 0.5.0 → 0.7.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/checks/dangerous.js +17 -1
- package/dist/checks/index.js +4 -2
- package/dist/checks/public-assets.js +35 -0
- package/dist/index.js +1 -1
- package/dist/items.js +10 -0
- package/package.json +4 -4
package/dist/checks/dangerous.js
CHANGED
|
@@ -23,6 +23,13 @@ const DANGEROUS_PATTERNS = [
|
|
|
23
23
|
severity: "medium",
|
|
24
24
|
message: "Wildcard CORS (Access-Control-Allow-Origin: *). Lock this down to specific origins for any authenticated endpoint.",
|
|
25
25
|
},
|
|
26
|
+
{
|
|
27
|
+
id: "shell-exec-call",
|
|
28
|
+
regex: /(^|[^A-Za-z0-9_$.])(exec|execSync)\s*\(/,
|
|
29
|
+
itemId: "common-attacks",
|
|
30
|
+
severity: "high",
|
|
31
|
+
message: "Shell execution via exec/execSync — if any argument includes user input, this is a command-injection path. Prefer execFile with an argument array, or validate input strictly against an allowlist.",
|
|
32
|
+
},
|
|
26
33
|
];
|
|
27
34
|
export async function checkDangerousPatterns(ctx) {
|
|
28
35
|
const findings = [];
|
|
@@ -32,7 +39,16 @@ export async function checkDangerousPatterns(ctx) {
|
|
|
32
39
|
if (isScanExempt(file.relPath))
|
|
33
40
|
continue;
|
|
34
41
|
const ext = path.extname(file.relPath).toLowerCase();
|
|
35
|
-
if (![
|
|
42
|
+
if (![
|
|
43
|
+
".ts",
|
|
44
|
+
".tsx",
|
|
45
|
+
".js",
|
|
46
|
+
".jsx",
|
|
47
|
+
".mjs",
|
|
48
|
+
".cjs",
|
|
49
|
+
".json",
|
|
50
|
+
".html",
|
|
51
|
+
].includes(ext))
|
|
36
52
|
continue;
|
|
37
53
|
const content = await readFileSafe(file);
|
|
38
54
|
if (!content)
|
package/dist/checks/index.js
CHANGED
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { checkHardcodedSecrets, checkConfigSecretLeaks } from "./secrets.js";
|
|
11
11
|
import { checkEnvCommitted, checkEnvExample, checkGitignore } from "./env.js";
|
|
12
|
-
import { checkRobotsTxt, checkSitemapXml, checkFavicon } from "./public-assets.js";
|
|
12
|
+
import { checkRobotsTxt, checkSitemapXml, checkFavicon, checkLlmsTxt, checkPwaManifest, } from "./public-assets.js";
|
|
13
13
|
import { checkSecurityHeaders } from "./headers.js";
|
|
14
14
|
import { checkDangerousPatterns } from "./dangerous.js";
|
|
15
15
|
import { checkLanguagePatterns, checkPythonSecretKeyEnv, checkRubySecretKeyBaseEnv, } from "./language.js";
|
|
16
16
|
import { checkPlaceholderContent } from "./quality.js";
|
|
17
17
|
export * from "./types.js";
|
|
18
|
-
export { checkHardcodedSecrets, checkConfigSecretLeaks, checkEnvCommitted, checkEnvExample, checkGitignore, checkRobotsTxt, checkSitemapXml, checkFavicon, checkSecurityHeaders, checkDangerousPatterns, checkLanguagePatterns, checkPythonSecretKeyEnv, checkRubySecretKeyBaseEnv, checkPlaceholderContent, };
|
|
18
|
+
export { checkHardcodedSecrets, checkConfigSecretLeaks, checkEnvCommitted, checkEnvExample, checkGitignore, checkRobotsTxt, checkSitemapXml, checkFavicon, checkLlmsTxt, checkPwaManifest, checkSecurityHeaders, checkDangerousPatterns, checkLanguagePatterns, checkPythonSecretKeyEnv, checkRubySecretKeyBaseEnv, checkPlaceholderContent, };
|
|
19
19
|
export const ALL_CHECKS = [
|
|
20
20
|
{ id: "hardcoded-secrets", run: checkHardcodedSecrets },
|
|
21
21
|
{ id: "config-secret-leaks", run: checkConfigSecretLeaks },
|
|
@@ -25,6 +25,8 @@ export const ALL_CHECKS = [
|
|
|
25
25
|
{ id: "robots-txt", run: checkRobotsTxt },
|
|
26
26
|
{ id: "sitemap-xml", run: checkSitemapXml },
|
|
27
27
|
{ id: "favicon", run: checkFavicon },
|
|
28
|
+
{ id: "llms-txt", run: checkLlmsTxt },
|
|
29
|
+
{ id: "pwa-manifest", run: checkPwaManifest },
|
|
28
30
|
{ id: "security-headers", run: checkSecurityHeaders },
|
|
29
31
|
{ id: "dangerous-patterns", run: checkDangerousPatterns },
|
|
30
32
|
{ id: "language-patterns", run: checkLanguagePatterns },
|
|
@@ -108,3 +108,38 @@ export async function checkFavicon(ctx) {
|
|
|
108
108
|
},
|
|
109
109
|
];
|
|
110
110
|
}
|
|
111
|
+
export async function checkLlmsTxt(ctx) {
|
|
112
|
+
const has = ctx.files.some((f) => /(^|\/)llms\.txt$/i.test(f.relPath));
|
|
113
|
+
if (has)
|
|
114
|
+
return [];
|
|
115
|
+
if (await isAssetEmittedDynamically(ctx, "llms.txt"))
|
|
116
|
+
return [];
|
|
117
|
+
const dirs = await findPublicDirs(ctx);
|
|
118
|
+
if (dirs.length === 0)
|
|
119
|
+
return [];
|
|
120
|
+
return [
|
|
121
|
+
{
|
|
122
|
+
checkId: "missing-llms-txt",
|
|
123
|
+
itemId: "aeo",
|
|
124
|
+
severity: "lower",
|
|
125
|
+
message: `No llms.txt found in any public directory (looked in: ${dirs.join(", ")}). Add one so AI crawlers (ChatGPT, Perplexity, Claude) can understand your site.`,
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
}
|
|
129
|
+
export async function checkPwaManifest(ctx) {
|
|
130
|
+
const dirs = await findPublicDirs(ctx);
|
|
131
|
+
if (dirs.length === 0)
|
|
132
|
+
return [];
|
|
133
|
+
const manifestRegex = /(^|\/)(manifest\.(json|webmanifest)|site\.webmanifest)$/i;
|
|
134
|
+
const has = ctx.files.some((f) => manifestRegex.test(f.relPath));
|
|
135
|
+
if (has)
|
|
136
|
+
return [];
|
|
137
|
+
return [
|
|
138
|
+
{
|
|
139
|
+
checkId: "missing-pwa-manifest",
|
|
140
|
+
itemId: "installable-app",
|
|
141
|
+
severity: "lower",
|
|
142
|
+
message: `No PWA manifest found in any public directory (looked in: ${dirs.join(", ")}). Add manifest.json (or site.webmanifest) so users can install your app to their phone's home screen.`,
|
|
143
|
+
},
|
|
144
|
+
];
|
|
145
|
+
}
|
package/dist/index.js
CHANGED
package/dist/items.js
CHANGED
|
@@ -39,6 +39,16 @@ export const CHECKLIST_ITEMS = {
|
|
|
39
39
|
title: "Audit what your AI builder actually shipped",
|
|
40
40
|
priority: "critical",
|
|
41
41
|
},
|
|
42
|
+
aeo: {
|
|
43
|
+
id: "aeo",
|
|
44
|
+
title: "Make AI assistants able to recommend you",
|
|
45
|
+
priority: "lower",
|
|
46
|
+
},
|
|
47
|
+
"installable-app": {
|
|
48
|
+
id: "installable-app",
|
|
49
|
+
title: "Make your app installable on phones",
|
|
50
|
+
priority: "lower",
|
|
51
|
+
},
|
|
42
52
|
};
|
|
43
53
|
export function permalinkFor(itemId, baseUrl) {
|
|
44
54
|
const trimmed = baseUrl.replace(/\/+$/, "");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shippingszn",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Read-only CLI scanner that checks a project for common pre-launch issues from the shippingszn.com launch checklist.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
"prepublishOnly": "npm run clean && npm run build && npm test"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@types/node": "
|
|
49
|
-
"tsx": "
|
|
48
|
+
"@types/node": "catalog:",
|
|
49
|
+
"tsx": "catalog:",
|
|
50
50
|
"typescript": "^5.6.3"
|
|
51
51
|
},
|
|
52
52
|
"publishConfig": {
|
|
53
53
|
"access": "public",
|
|
54
54
|
"registry": "https://registry.npmjs.org/"
|
|
55
55
|
}
|
|
56
|
-
}
|
|
56
|
+
}
|