secure-repo 1.0.8 → 1.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.
Files changed (2) hide show
  1. package/bin/cli.js +128 -33
  2. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -10,7 +10,8 @@ const FREE_DIR = path.join(TEMPLATES_DIR, "free");
10
10
 
11
11
  const POLAR_ORGANIZATION_ID = "d55baa70-3a94-4549-901a-2b4c920ff122";
12
12
 
13
- const PRO_ZIP_URL = "https://github.com/sebiomoa/shipsecure/releases/latest/download/shipsecure-pro.zip";
13
+ // Pro download endpoint (server-side proxy — token never ships in client code)
14
+ const PRO_DOWNLOAD_URL = "https://shipsecure.app/api/download-pro";
14
15
 
15
16
  const args = process.argv.slice(2);
16
17
  const command = args[0];
@@ -173,37 +174,40 @@ function verifyLicense(licenseKey) {
173
174
  }
174
175
 
175
176
  // ============================================================
176
- // Download file from URL
177
+ // Download pro zip via server-side proxy
177
178
  // ============================================================
178
- function downloadFile(url, destPath) {
179
+ function downloadProZip(destPath, licenseKey) {
179
180
  return new Promise((resolve, reject) => {
180
- const file = fs.createWriteStream(destPath);
181
-
182
- function follow(url) {
183
- https.get(url, (res) => {
184
- // Follow redirects
185
- if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
186
- follow(res.headers.location);
187
- return;
188
- }
189
-
190
- if (res.statusCode !== 200) {
191
- reject(new Error(`Download failed (HTTP ${res.statusCode})`));
192
- return;
193
- }
181
+ const parsed = new URL(PRO_DOWNLOAD_URL);
182
+ const postData = JSON.stringify({ license_key: licenseKey });
183
+ const opts = {
184
+ hostname: parsed.hostname,
185
+ path: parsed.pathname,
186
+ method: "POST",
187
+ headers: {
188
+ "User-Agent": "secure-repo-cli",
189
+ "Content-Type": "application/json",
190
+ "Content-Length": Buffer.byteLength(postData),
191
+ },
192
+ };
194
193
 
195
- res.pipe(file);
196
- file.on("finish", () => {
197
- file.close();
198
- resolve();
194
+ const req = https.request(opts, (res) => {
195
+ if (res.statusCode !== 200) {
196
+ let body = "";
197
+ res.on("data", (chunk) => (body += chunk));
198
+ res.on("end", () => {
199
+ reject(new Error(`Download failed (HTTP ${res.statusCode}): ${body}`));
199
200
  });
200
- }).on("error", (err) => {
201
- fs.unlink(destPath, () => {});
202
- reject(new Error(`Download error: ${err.message}`));
203
- });
204
- }
201
+ return;
202
+ }
203
+ const file = fs.createWriteStream(destPath);
204
+ res.pipe(file);
205
+ file.on("finish", () => { file.close(); resolve(); });
206
+ });
205
207
 
206
- follow(url);
208
+ req.on("error", (err) => reject(new Error(`Network error: ${err.message}`)));
209
+ req.write(postData);
210
+ req.end();
207
211
  });
208
212
  }
209
213
 
@@ -269,6 +273,87 @@ function installFromZip(zipPath, outputDir, force) {
269
273
  }
270
274
  }
271
275
 
276
+ // ============================================================
277
+ // Agent instruction files — tell AI agents to read policy files
278
+ // ============================================================
279
+ const AGENT_INSTRUCTION = `# Security Policies — MUST READ
280
+
281
+ This project uses ShipSecure security policies. Before writing or modifying code, you MUST read and follow every policy file that exists in this repository.
282
+
283
+ ## Policy Files
284
+
285
+ Read each of these files if they exist before making changes:
286
+
287
+ ### Core
288
+ - SECURITY.md — Secrets management, attack surface, enforced architecture
289
+ - AUTH.md — Token handling, session rules, password policy, roles
290
+ - API.md — Input validation, rate limiting, error handling
291
+
292
+ ### Extended
293
+ - DATABASE.md — Query safety, access control, migrations
294
+ - ENV_VARIABLES.md — Environment variable handling, secret rotation
295
+ - DEPLOYMENT.md — Deploy pipeline, environment isolation
296
+ - INCIDENT_RESPONSE.md — Breach response, escalation procedures
297
+ - ACCESS_CONTROL.md — Role-based access, permission boundaries
298
+ - DATA_PRIVACY.md — PII handling, data retention, GDPR compliance
299
+ - PAYMENTS.md — Payment processing, PCI compliance
300
+ - FILE_UPLOADS.md — Upload validation, storage security
301
+ - RATE_LIMITING.md — Throttling, abuse prevention
302
+ - THIRD_PARTY.md — Dependency security, vendor risk
303
+ - LOGGING_PII.md — Log sanitization, PII redaction
304
+ - TESTING.md — Security test requirements
305
+ - OBSERVABILITY.md — Monitoring, alerting, audit trails
306
+ - THREAT_MODEL.md — Known threats and mitigations
307
+ - PR_CHECKLIST.md — Pre-merge security checklist
308
+ - CONTRIBUTING_SECURITY.md — Security contribution guidelines
309
+ - VULNERABILITY_REPORTING.md — Responsible disclosure process
310
+ - POLICY_INDEX.md — Index of all policies
311
+ - FULL_AUDIT_CHECKLIST.md — 100+ point security audit checklist
312
+
313
+ ### Stack Presets
314
+ - supabase-preset/ — Supabase-specific security rules (if present)
315
+ - firebase-preset/ — Firebase-specific security rules (if present)
316
+
317
+ ## Rules
318
+
319
+ 1. Always check policy files before writing code — if your task touches auth, APIs, database, payments, file uploads, or any area with a policy file, read that file first.
320
+ 2. Never violate a policy — if a policy says "never do X", do not do X. Flag it if unsure.
321
+ 3. Secrets are never hardcoded — no API keys, tokens, passwords, or credentials in source code.
322
+ 4. Validate all input — every endpoint, every form, every external data source.
323
+ 5. Follow the principle of least privilege — only request the permissions you need.
324
+ `;
325
+
326
+ function writeAgentFiles(outputDir, force) {
327
+ const agentFiles = [
328
+ { path: "CLAUDE.md", name: "Claude" },
329
+ { path: ".cursorrules", name: "Cursor" },
330
+ { path: ".github/copilot-instructions.md", name: "GitHub Copilot" },
331
+ { path: ".windsurfrules", name: "Windsurf" },
332
+ { path: ".clinerules", name: "Cline" },
333
+ ];
334
+
335
+ let written = 0;
336
+ let skipped = 0;
337
+
338
+ console.log("\n Agent instructions:");
339
+ agentFiles.forEach(({ path: filePath, name }) => {
340
+ const fullPath = path.join(outputDir, filePath);
341
+ const dir = path.dirname(fullPath);
342
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
343
+
344
+ if (fs.existsSync(fullPath) && !force) {
345
+ console.log(` [skip] ${filePath} (${name}) — use --force to overwrite`);
346
+ skipped++;
347
+ } else {
348
+ fs.writeFileSync(fullPath, AGENT_INSTRUCTION);
349
+ console.log(` [done] ${filePath} (${name})`);
350
+ written++;
351
+ }
352
+ });
353
+
354
+ return { written, skipped };
355
+ }
356
+
272
357
  // ============================================================
273
358
  // INIT — install templates (free, or free + pro with --key)
274
359
  // ============================================================
@@ -300,11 +385,14 @@ async function init() {
300
385
  console.log("\n Downloading pro templates...");
301
386
 
302
387
  try {
303
- await downloadFile(PRO_ZIP_URL, zipPath);
388
+ await downloadProZip(zipPath, licenseKey);
304
389
  const proResult = installFromZip(zipPath, outputDir, force);
305
390
 
306
- const totalCopied = freeResult.copied + proResult.copied;
307
- const totalSkipped = freeResult.skipped + proResult.skipped;
391
+ // Write agent instruction files
392
+ const agentResult = writeAgentFiles(outputDir, force);
393
+
394
+ const totalCopied = freeResult.copied + proResult.copied + agentResult.written;
395
+ const totalSkipped = freeResult.skipped + proResult.skipped + agentResult.skipped;
308
396
 
309
397
  console.log(`\n Done! ${totalCopied} files installed, ${totalSkipped} skipped.`);
310
398
  console.log("\n Next steps:");
@@ -326,7 +414,13 @@ async function init() {
326
414
  console.log(" Free templates:");
327
415
  const result = copyFiles(FREE_DIR, outputDir, force);
328
416
 
329
- console.log(`\n Done! ${result.copied} files added, ${result.skipped} skipped.`);
417
+ // Write agent instruction files
418
+ const agentResult = writeAgentFiles(outputDir, force);
419
+
420
+ const totalCopied = result.copied + agentResult.written;
421
+ const totalSkipped = result.skipped + agentResult.skipped;
422
+
423
+ console.log(`\n Done! ${totalCopied} files added, ${totalSkipped} skipped.`);
330
424
  console.log("\n Next steps:");
331
425
  console.log(" 1. Customize the templates for your project");
332
426
  console.log(" 2. Run: npx secure-repo audit");
@@ -370,9 +464,10 @@ function importPack() {
370
464
 
371
465
  try {
372
466
  const proResult = installFromZip(resolvedPath, outputDir, force);
467
+ const agentResult = writeAgentFiles(outputDir, force);
373
468
 
374
- const totalCopied = freeResult.copied + proResult.copied;
375
- const totalSkipped = freeResult.skipped + proResult.skipped;
469
+ const totalCopied = freeResult.copied + proResult.copied + agentResult.written;
470
+ const totalSkipped = freeResult.skipped + proResult.skipped + agentResult.skipped;
376
471
 
377
472
  console.log(`\n Done! ${totalCopied} files imported, ${totalSkipped} skipped.\n`);
378
473
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secure-repo",
3
- "version": "1.0.8",
3
+ "version": "1.1.0",
4
4
  "description": "Drop production-grade security standards into any repo. Audit your repo for security issues. Templates for AI-assisted development.",
5
5
  "bin": {
6
6
  "secure-repo": "./bin/cli.js"