seamshield 0.2.0 → 0.2.1
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/README.md +9 -4
- package/dist/index.js +29 -16
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ seamshield access . --format table
|
|
|
28
28
|
seamshield access . --format json
|
|
29
29
|
seamshield scan . --offline
|
|
30
30
|
seamshield fix-plan . --agent codex
|
|
31
|
+
seamshield agent-context . --codex
|
|
31
32
|
seamshield triage . --rule ss/auth/client-only-guard
|
|
32
33
|
seamshield agent-context . --claude
|
|
33
34
|
seamshield agent-context . --cursor
|
|
@@ -98,15 +99,19 @@ Writes `.seamshield/fix-plan.json` and a Markdown plan under
|
|
|
98
99
|
## Agent Guard
|
|
99
100
|
|
|
100
101
|
```bash
|
|
102
|
+
seamshield agent-context . --codex
|
|
101
103
|
seamshield agent-context . --claude
|
|
102
104
|
seamshield agent-context . --cursor
|
|
103
105
|
seamshield guard install .
|
|
104
106
|
```
|
|
105
107
|
|
|
106
|
-
`agent-context` writes
|
|
107
|
-
`
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
`agent-context --codex` writes `AGENTS.md`. `--claude` writes `CLAUDE.md`.
|
|
109
|
+
`--cursor` writes `.cursor/rules/seamshield.mdc`.
|
|
110
|
+
|
|
111
|
+
`guard install` adds a Claude Code `PreToolUse` hook that blocks
|
|
112
|
+
high-confidence risky edits such as committed dotenv files, exposed server
|
|
113
|
+
secrets, public database/storage writes, unsafe `.env` edits, dangerous shell
|
|
114
|
+
installs, and obvious privileged route exposure.
|
|
110
115
|
|
|
111
116
|
Guard behavior is fail-open: if the hook errors, it allows the tool call and
|
|
112
117
|
appends diagnostics to `.seamshield/guard.log`.
|
package/dist/index.js
CHANGED
|
@@ -1413,6 +1413,7 @@ var FORMATS = ["table", "json", "sarif"];
|
|
|
1413
1413
|
var ACCESS_FORMATS = ["table", "json"];
|
|
1414
1414
|
var FAIL_ON = ["block", "high", "warn", "never"];
|
|
1415
1415
|
var FIX_AGENTS = ["claude", "cursor", "codex", "generic"];
|
|
1416
|
+
var CONTEXT_AGENTS = ["claude", "cursor", "codex"];
|
|
1416
1417
|
function assertChoice(value, allowed, label) {
|
|
1417
1418
|
if (value && !allowed.includes(value)) {
|
|
1418
1419
|
console.error(`seamshield: unknown --${label} "${value}" (expected: ${allowed.join(", ")})`);
|
|
@@ -1470,31 +1471,33 @@ async function readScanForCommand(path, offline = true) {
|
|
|
1470
1471
|
return null;
|
|
1471
1472
|
}
|
|
1472
1473
|
}
|
|
1474
|
+
function writeSection(path, marker, body) {
|
|
1475
|
+
mkdirSync3(dirname3(path), { recursive: true });
|
|
1476
|
+
const existing = existsSync2(path) ? readFileSync6(path, "utf8") : "";
|
|
1477
|
+
const next = existing.includes(marker) ? existing.replace(new RegExp(`${marker}[\\s\\S]*?(?=\\n# |\\n?$)`), body.trimEnd()) : `${existing.trimEnd()}${existing.trim() ? "\n\n" : ""}${body}`;
|
|
1478
|
+
writeFileSync3(path, next.endsWith("\n") ? next : `${next}
|
|
1479
|
+
`);
|
|
1480
|
+
return path;
|
|
1481
|
+
}
|
|
1473
1482
|
function writeAgentContext(target, kind) {
|
|
1474
1483
|
const body = [
|
|
1475
1484
|
"# SEAMSHIELD",
|
|
1476
1485
|
"",
|
|
1477
|
-
"- Run `npx seamshield scan --offline` before committing AI-generated changes.",
|
|
1486
|
+
"- Run `npx seamshield ship .` before deploys and `npx seamshield scan --offline` before committing AI-generated changes.",
|
|
1478
1487
|
"- Never hardcode provider keys, service-role keys, private keys, or dotenv contents.",
|
|
1479
1488
|
"- Do not expose server secrets through `NEXT_PUBLIC_*` or client components.",
|
|
1480
1489
|
"- Do not rely on client-only auth for private data; enforce auth server-side.",
|
|
1481
|
-
"- Keep Supabase RLS enabled
|
|
1482
|
-
|
|
1490
|
+
"- Keep Supabase RLS enabled, Firebase rules closed by default, and Convex privileged mutations authenticated or internal.",
|
|
1491
|
+
`- If SeamShield reports findings, inspect \`npx seamshield access .\` and apply \`npx seamshield fix-plan . --agent ${kind === "codex" ? "codex" : kind}\`.`,
|
|
1483
1492
|
""
|
|
1484
1493
|
].join("\n");
|
|
1485
1494
|
if (kind === "cursor") {
|
|
1486
|
-
const
|
|
1487
|
-
mkdirSync3(dirname3(
|
|
1488
|
-
writeFileSync3(
|
|
1489
|
-
return
|
|
1495
|
+
const out = join7(target, ".cursor", "rules", "seamshield.mdc");
|
|
1496
|
+
mkdirSync3(dirname3(out), { recursive: true });
|
|
1497
|
+
writeFileSync3(out, body);
|
|
1498
|
+
return out;
|
|
1490
1499
|
}
|
|
1491
|
-
|
|
1492
|
-
const existing = existsSync2(out) ? readFileSync6(out, "utf8") : "";
|
|
1493
|
-
const marker = "# SEAMSHIELD";
|
|
1494
|
-
const next = existing.includes(marker) ? existing.replace(/# SEAMSHIELD[\s\S]*?(?=\n# |\n?$)/, body.trimEnd()) : `${existing.trimEnd()}${existing.trim() ? "\n\n" : ""}${body}`;
|
|
1495
|
-
writeFileSync3(out, next.endsWith("\n") ? next : `${next}
|
|
1496
|
-
`);
|
|
1497
|
-
return out;
|
|
1500
|
+
return writeSection(join7(target, kind === "codex" ? "AGENTS.md" : "CLAUDE.md"), "# SEAMSHIELD", body);
|
|
1498
1501
|
}
|
|
1499
1502
|
function readTriageConfig(target) {
|
|
1500
1503
|
const path = join7(target, ".seamshield", "config.yaml");
|
|
@@ -1688,9 +1691,19 @@ program.command("learn").description("Update local controls from vulnerability i
|
|
|
1688
1691
|
program.command("triage").description("Persist current false-positive decisions into .seamshield/config.yaml").argument("[path]", "directory to scan", ".").option("--rule <rule-id>", "only suppress current findings from one rule").option("--reason <text>", "suppression reason", "triaged false positive").option("--include-block", "also suppress block findings", false).option("--online", "include network-backed dependency intelligence").action(
|
|
1689
1692
|
(path, opts) => writeTriageSuppressions(path, opts)
|
|
1690
1693
|
);
|
|
1691
|
-
program.command("agent-context").description("Write SeamShield agent instructions into CLAUDE.md or Cursor rules").argument("[path]", "project directory", ".").option("--claude", "write CLAUDE.md", false).option("--cursor", "write .cursor/rules/seamshield.mdc", false).action((path, opts) => {
|
|
1694
|
+
program.command("agent-context").description("Write SeamShield agent instructions into AGENTS.md, CLAUDE.md, or Cursor rules").argument("[path]", "project directory", ".").option("--claude", "write CLAUDE.md", false).option("--cursor", "write .cursor/rules/seamshield.mdc", false).option("--codex", "write AGENTS.md", false).action((path, opts) => {
|
|
1695
|
+
const selected = [
|
|
1696
|
+
opts.claude ? "claude" : null,
|
|
1697
|
+
opts.cursor ? "cursor" : null,
|
|
1698
|
+
opts.codex ? "codex" : null
|
|
1699
|
+
].filter(Boolean);
|
|
1700
|
+
if (selected.length > 1) {
|
|
1701
|
+
console.error(`seamshield: choose one agent context (${CONTEXT_AGENTS.join(", ")})`);
|
|
1702
|
+
process.exitCode = 2;
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1692
1705
|
const target = resolve2(path);
|
|
1693
|
-
const kind =
|
|
1706
|
+
const kind = selected[0] ?? "codex";
|
|
1694
1707
|
console.log(writeAgentContext(target, kind));
|
|
1695
1708
|
});
|
|
1696
1709
|
var guard = program.command("guard").description("Claude Code guard utilities");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "seamshield",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Security scanner for AI-generated apps: finds the flaws vibecoded projects predictably ship",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"@seamshield/rules": "0.1.0"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
|
-
"build": "tsup src/index.ts --format esm --clean && tsc -p tsconfig.build.json && rm -rf rules schemas &&
|
|
60
|
+
"build": "tsup src/index.ts --format esm --clean && tsc -p tsconfig.build.json && rm -rf rules schemas && ditto ../rules/rules rules && ditto ../rules/schemas schemas",
|
|
61
61
|
"test": "vitest run"
|
|
62
62
|
}
|
|
63
63
|
}
|