secure-husky-setup 1.0.8 → 1.0.10

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 (3) hide show
  1. package/lib/ci.js +104 -137
  2. package/lib/sonarqube.js +1 -1
  3. package/package.json +1 -1
package/lib/ci.js CHANGED
@@ -5,19 +5,6 @@
5
5
  // File: lib/ci.js
6
6
  // Purpose: Sets up Newman API tests + Smoke Tests as a pre-push git hook
7
7
  // and copies the GitHub Actions CI workflow into the project.
8
- //
9
- // FLEXIBILITY NOTE:
10
- // Test logic lives in scripts/run-ci-checks.sh (standalone script).
11
- // The pre-push hook simply calls that script.
12
- // To move tests to pre-commit in future, just add one line to pre-commit hook:
13
- // ./scripts/run-ci-checks.sh
14
- // No logic needs to be rewritten.
15
- //
16
- // New files introduced:
17
- // - lib/ci.js (this file)
18
- // - templates/ci-tests.yml (GitHub Actions workflow template)
19
- // Changes made to existing files:
20
- // - bin/index.js (4 new lines added — see comments there)
21
8
  // ─────────────────────────────────────────────────────────────────────────────
22
9
 
23
10
  const fs = require('fs-extra');
@@ -25,14 +12,8 @@ const path = require('path');
25
12
  const { execSync } = require('child_process');
26
13
  const { logInfo, logSuccess, logError } = require('./logger');
27
14
 
28
- // Added by Arjun — path to the CI workflow template bundled with this package
29
15
  const TEMPLATE_PATH = path.resolve(__dirname, '../templates/ci-tests.yml');
30
16
 
31
- // ─────────────────────────────────────────────────────────────────────────────
32
- // Added by Arjun — writes scripts/run-ci-checks.sh into the project
33
- // This is the STANDALONE script containing all test logic.
34
- // It can be called from pre-push, pre-commit, or any other hook.
35
- // ─────────────────────────────────────────────────────────────────────────────
36
17
  exports.setupCIScript = async () => {
37
18
  const scriptsDir = path.join(process.cwd(), 'scripts');
38
19
  const scriptPath = path.join(scriptsDir, 'run-ci-checks.sh');
@@ -51,10 +32,6 @@ exports.setupCIScript = async () => {
51
32
  logInfo("To move tests to pre-commit in future: add './scripts/run-ci-checks.sh' to .husky/pre-commit.");
52
33
  };
53
34
 
54
- // ─────────────────────────────────────────────────────────────────────────────
55
- // Added by Arjun — sets up .husky/pre-push hook
56
- // Simply calls run-ci-checks.sh — no logic lives here.
57
- // ─────────────────────────────────────────────────────────────────────────────
58
35
  exports.setupPrePushHook = async () => {
59
36
  const huskyDir = path.join(process.cwd(), '.husky');
60
37
  const hookPath = path.join(huskyDir, 'pre-push');
@@ -75,9 +52,6 @@ exports.setupPrePushHook = async () => {
75
52
  logSuccess("Pre-push hook created — calls scripts/run-ci-checks.sh.");
76
53
  };
77
54
 
78
- // ─────────────────────────────────────────────────────────────────────────────
79
- // Added by Arjun — copies ci-tests.yml into .github/workflows/
80
- // ─────────────────────────────────────────────────────────────────────────────
81
55
  exports.setupCIWorkflow = async () => {
82
56
  const targetDir = path.join(process.cwd(), '.github', 'workflows');
83
57
  const targetFile = path.join(targetDir, 'ci-tests.yml');
@@ -99,9 +73,6 @@ exports.setupCIWorkflow = async () => {
99
73
  logSuccess("GitHub Actions workflow copied to .github/workflows/ci-tests.yml");
100
74
  };
101
75
 
102
- // ─────────────────────────────────────────────────────────────────────────────
103
- // Added by Arjun — validates package.json has required scripts
104
- // ─────────────────────────────────────────────────────────────────────────────
105
76
  exports.validateProject = async () => {
106
77
  const pkgPath = path.join(process.cwd(), 'package.json');
107
78
 
@@ -128,9 +99,6 @@ exports.validateProject = async () => {
128
99
  }
129
100
  };
130
101
 
131
- // ─────────────────────────────────────────────────────────────────────────────
132
- // Added by Arjun — ensures package-lock.json exists (required by npm ci)
133
- // ─────────────────────────────────────────────────────────────────────────────
134
102
  exports.ensurePackageLock = async () => {
135
103
  const lockPath = path.join(process.cwd(), 'package-lock.json');
136
104
  const yarnPath = path.join(process.cwd(), 'yarn.lock');
@@ -149,39 +117,23 @@ exports.ensurePackageLock = async () => {
149
117
  }
150
118
  };
151
119
 
152
- // ─────────────────────────────────────────────────────────────────────────────
153
- // Pre-push hook — thin wrapper, just calls the standalone script
154
- // ─────────────────────────────────────────────────────────────────────────────
155
120
  function buildPrePushHook() {
156
121
  return `#!/bin/sh
157
122
 
158
123
  # ---------------------------------------------------------------
159
124
  # Pre-push hook — Newman + Smoke Tests
160
125
  # Delegates all logic to scripts/run-ci-checks.sh
161
- #
162
- # To move tests to pre-commit in future:
163
- # Remove this file and add this line to .husky/pre-commit:
164
- # ./scripts/run-ci-checks.sh
165
126
  # ---------------------------------------------------------------
166
127
 
167
128
  ./scripts/run-ci-checks.sh
168
129
  `;
169
130
  }
170
131
 
171
- // ─────────────────────────────────────────────────────────────────────────────
172
- // Standalone CI checks script — ALL test logic lives here
173
- // Can be called from pre-push, pre-commit, CI, or manually:
174
- // sh scripts/run-ci-checks.sh
175
- // ─────────────────────────────────────────────────────────────────────────────
176
132
  function buildCIScript() {
177
133
  return `#!/bin/sh
178
134
 
179
135
  # ---------------------------------------------------------------
180
136
  # run-ci-checks.sh — Smoke Tests + Newman API Tests
181
- #
182
- # Called by .husky/pre-push by default.
183
- # To move to pre-commit: add './scripts/run-ci-checks.sh' to .husky/pre-commit
184
- # To run manually: sh scripts/run-ci-checks.sh
185
137
  # ---------------------------------------------------------------
186
138
 
187
139
  # ---------------------------------------------------------------
@@ -214,110 +166,125 @@ echo ""
214
166
  echo "[CI Checks] Starting checks..."
215
167
 
216
168
  # ---------------------------------------------------------------
217
- # Step 1: Smoke Tests
169
+ # Check if start script exists
218
170
  # ---------------------------------------------------------------
219
- echo ""
220
- echo "[Smoke Tests] Starting server..."
171
+ START_SCRIPT=$(node -e "const p=require('./package.json'); console.log(p.scripts&&p.scripts.start?'yes':'no')" 2>/dev/null)
172
+ TEST_SCRIPT=$(node -e "const p=require('./package.json'); console.log(p.scripts&&p.scripts.test?'yes':'no')" 2>/dev/null)
221
173
 
222
- npm start &
223
- SERVER_PID=\$!
174
+ if [ "$START_SCRIPT" = "no" ]; then
175
+ echo "[Smoke Tests] No start script in package.json — skipping smoke tests."
176
+ else
224
177
 
225
- for i in \$(seq 1 30); do
226
- if curl -sf http://localhost:\${PORT:-3000}/health > /dev/null 2>&1 || \\
227
- curl -sf http://localhost:\${PORT:-3000} > /dev/null 2>&1; then
228
- echo "[Smoke Tests] Server is up."
229
- break
178
+ # ---------------------------------------------------------------
179
+ # Step 1: Smoke Tests
180
+ # ---------------------------------------------------------------
181
+ echo ""
182
+ echo "[Smoke Tests] Starting server..."
183
+
184
+ npm start &
185
+ SERVER_PID=\$!
186
+
187
+ # Auto-detect port — tries common ports
188
+ SERVER_UP=0
189
+ for i in \$(seq 1 30); do
190
+ for PORT_TRY in 3000 5000 8000 8080 4000 4200 3001; do
191
+ if curl -sf http://localhost:\$PORT_TRY > /dev/null 2>&1; then
192
+ PORT=\$PORT_TRY
193
+ SERVER_UP=1
194
+ echo "[Smoke Tests] Server is up on port \$PORT."
195
+ break 2
196
+ fi
197
+ done
198
+ echo "[Smoke Tests] Waiting for server... (\$i/30)"
199
+ sleep 1
200
+ done
201
+
202
+ if [ \$SERVER_UP -eq 0 ]; then
203
+ echo "[Smoke Tests] Server did not start in time. Aborting."
204
+ kill \$SERVER_PID 2>/dev/null
205
+ exit 1
230
206
  fi
231
- echo "[Smoke Tests] Waiting for server... (\$i/30)"
232
- sleep 1
233
- done
234
-
235
- echo "[Smoke Tests] Running npm test..."
236
- npm test
237
- SMOKE_EXIT=\$?
238
-
239
- kill \$SERVER_PID 2>/dev/null
240
207
 
241
- if [ \$SMOKE_EXIT -ne 0 ]; then
242
- echo "[Smoke Tests] Failed. Push blocked."
243
- exit 1
244
- fi
245
-
246
- echo "[Smoke Tests] Passed. ✔"
247
-
248
- # ---------------------------------------------------------------
249
- # Step 2: Newman
250
- # ---------------------------------------------------------------
251
- echo ""
252
- echo "[Newman] Looking for Postman collections..."
253
-
254
- COLLECTIONS=\$(find . \\
255
- -not -path '*/node_modules/*' \\
256
- -not -path '*/.git/*' \\
257
- -not -path '*/scripts/*' \\
258
- \\( -name "*.postman_collection.json" -o -name "collection.json" \\) \\
259
- 2>/dev/null)
260
-
261
- if [ -z "\$COLLECTIONS" ]; then
262
- echo "[Newman] No Postman collection found. Skipping."
263
- exit 0
264
- fi
265
-
266
- if ! command -v newman > /dev/null 2>&1; then
267
- echo "[Newman] Installing newman globally..."
268
- npm install -g newman newman-reporter-htmlextra
269
- fi
270
-
271
- npm start &
272
- SERVER_PID=\$!
273
-
274
- for i in \$(seq 1 30); do
275
- if curl -sf http://localhost:\${PORT:-3000}/health > /dev/null 2>&1 || \\
276
- curl -sf http://localhost:\${PORT:-3000} > /dev/null 2>&1; then
277
- echo "[Newman] Server is up."
278
- break
208
+ if [ "$TEST_SCRIPT" = "no" ]; then
209
+ echo "[Smoke Tests] No test script in package.json skipping npm test."
210
+ else
211
+ echo "[Smoke Tests] Running npm test..."
212
+ npm test
213
+ SMOKE_EXIT=\$?
214
+
215
+ if [ \$SMOKE_EXIT -ne 0 ]; then
216
+ kill \$SERVER_PID 2>/dev/null
217
+ echo "[Smoke Tests] Failed. Push blocked."
218
+ exit 1
219
+ fi
220
+ echo "[Smoke Tests] Passed. ✔"
279
221
  fi
280
- sleep 1
281
- done
282
222
 
283
- mkdir -p newman-reports
284
-
285
- ENV_FILE=\$(find . \\
286
- -not -path '*/node_modules/*' \\
287
- -not -path '*/.git/*' \\
288
- -name "*.postman_environment.json" \\
289
- 2>/dev/null | head -1)
290
-
291
- NEWMAN_EXIT=0
292
- for COLLECTION in \$COLLECTIONS; do
293
- REPORT_NAME=\$(basename "\$COLLECTION" .json)
294
- echo "[Newman] Running: \$COLLECTION"
295
-
296
- ENV_FLAG=""
297
- if [ -n "\$ENV_FILE" ]; then
298
- ENV_FLAG="--environment \$ENV_FILE"
223
+ # ---------------------------------------------------------------
224
+ # Step 2: Newman
225
+ # ---------------------------------------------------------------
226
+ echo ""
227
+ echo "[Newman] Looking for Postman collections..."
228
+
229
+ COLLECTIONS=\$(find . \\
230
+ -not -path '*/node_modules/*' \\
231
+ -not -path '*/.git/*' \\
232
+ -not -path '*/scripts/*' \\
233
+ \\( -name "*.postman_collection.json" -o -name "collection.json" \\) \\
234
+ 2>/dev/null)
235
+
236
+ if [ -z "\$COLLECTIONS" ]; then
237
+ echo "[Newman] No Postman collection found. Skipping."
238
+ kill \$SERVER_PID 2>/dev/null
239
+ exit 0
299
240
  fi
300
241
 
301
- newman run "\$COLLECTION" \\
302
- \$ENV_FLAG \\
303
- --env-var "baseUrl=http://localhost:\${PORT:-3000}" \\
304
- --reporters cli,htmlextra \\
305
- --reporter-htmlextra-export "newman-reports/\${REPORT_NAME}-report.html" \\
306
- --bail
242
+ if ! command -v newman > /dev/null 2>&1; then
243
+ echo "[Newman] Installing newman globally..."
244
+ npm install -g newman newman-reporter-htmlextra
245
+ fi
307
246
 
308
- if [ \$? -ne 0 ]; then
309
- NEWMAN_EXIT=1
247
+ mkdir -p newman-reports
248
+
249
+ ENV_FILE=\$(find . \\
250
+ -not -path '*/node_modules/*' \\
251
+ -not -path '*/.git/*' \\
252
+ -name "*.postman_environment.json" \\
253
+ 2>/dev/null | head -1)
254
+
255
+ NEWMAN_EXIT=0
256
+ for COLLECTION in \$COLLECTIONS; do
257
+ REPORT_NAME=\$(basename "\$COLLECTION" .json)
258
+ echo "[Newman] Running: \$COLLECTION"
259
+
260
+ ENV_FLAG=""
261
+ if [ -n "\$ENV_FILE" ]; then
262
+ ENV_FLAG="--environment \$ENV_FILE"
263
+ fi
264
+
265
+ newman run "\$COLLECTION" \\
266
+ \$ENV_FLAG \\
267
+ --env-var "baseUrl=http://localhost:\${PORT:-3000}" \\
268
+ --reporters cli,htmlextra \\
269
+ --reporter-htmlextra-export "newman-reports/\${REPORT_NAME}-report.html" \\
270
+ --bail
271
+
272
+ if [ \$? -ne 0 ]; then
273
+ NEWMAN_EXIT=1
274
+ fi
275
+ done
276
+
277
+ kill \$SERVER_PID 2>/dev/null
278
+
279
+ if [ \$NEWMAN_EXIT -ne 0 ]; then
280
+ echo "[Newman] One or more collections failed. Push blocked."
281
+ exit 1
310
282
  fi
311
- done
312
283
 
313
- kill \$SERVER_PID 2>/dev/null
284
+ echo "[Newman] All collections passed. ✔"
314
285
 
315
- if [ \$NEWMAN_EXIT -ne 0 ]; then
316
- echo "[Newman] One or more collections failed. Push blocked."
317
- exit 1
318
286
  fi
319
287
 
320
- echo "[Newman] All collections passed. ✔"
321
288
  exit 0
322
289
  `;
323
290
  }
package/lib/sonarqube.js CHANGED
@@ -12,7 +12,7 @@ const SONAR_PROPS_FILE = 'sonar-project.properties';
12
12
  // Switch to GCP later by changing SONAR_HOST_URL and SONAR_TOKEN
13
13
  // ---------------------------------------------------------------
14
14
  const SONAR_HOST_URL = 'http://192.168.1.72:9000';
15
- const SONAR_TOKEN = 'sqa_57476a8e9fe67dcdddfbe5a146a681c9373a3ab8';
15
+ const SONAR_TOKEN = 'sqa_4579719d9a294abff391f803ddb08ca6d32d27c5';
16
16
  // const SONAR_ORG = 'arjunlatiwala'; // only needed for SonarCloud
17
17
 
18
18
  // Auto-create project on SonarQube via API so developer never needs to do it manually
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secure-husky-setup",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Automatic Husky + Gitleaks setup for any JS project",
5
5
  "main": "bin/index.js",
6
6
  "bin": {