@produtype/core 0.19.1 → 0.20.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/dist/rules/rules.js +62 -13
  2. package/package.json +1 -1
@@ -203,9 +203,24 @@ exports.rules = [
203
203
  category: 'env',
204
204
  status,
205
205
  severity: sevForStatus(status, 'medium'),
206
+ /**
207
+ * One sentence per answer.
208
+ *
209
+ * "Environment template looks available or env usage was not detected" is two
210
+ * different findings sharing a line, and sixty-two of the seventy-eight
211
+ * repositories in the corpus were shown it: nineteen that have a template, and
212
+ * forty-three that read no environment variables at all. A reader cannot tell
213
+ * which one they are, and those call for opposite actions — one is done, the
214
+ * other was never asked.
215
+ *
216
+ * The status already knew. This is the same mistake the privacy check was
217
+ * corrected for, still being made one rule above it.
218
+ */
206
219
  description: missing
207
220
  ? 'The project reads environment variables but no .env.example was detected.'
208
- : 'Environment template looks available or env usage was not detected.',
221
+ : status === 'passed'
222
+ ? 'An environment template is present alongside the variables this project reads.'
223
+ : 'Nothing here reads environment variables, so there is no template to check.',
209
224
  recommendation: 'Provide a safe .env.example containing required keys and no secrets.',
210
225
  evidence: det?.evidence ?? [],
211
226
  });
@@ -338,7 +353,19 @@ exports.rules = [
338
353
  category: 'security',
339
354
  status,
340
355
  severity: sevForStatus(status, 'medium'),
341
- description: hasRate ? 'Rate limiting signals detected.' : 'No auth-focused rate limiting detected.',
356
+ /**
357
+ * `unknown` here means the check does not apply — this detector only reads
358
+ * Express middleware, and a Django project has rate limiting somewhere it cannot
359
+ * see. Saying "no rate limiting detected" for that is reporting the analyzer's
360
+ * blind spot as the project's gap.
361
+ */
362
+ description: status === 'passed'
363
+ ? 'Rate limiting signals detected on the authentication surface.'
364
+ : status === 'missing'
365
+ ? 'No auth-focused rate limiting detected.'
366
+ : !hasAuth
367
+ ? 'Nothing here authenticates anybody, so there is no login surface to throttle.'
368
+ : 'This check reads Express middleware, and this project does not use it — any throttling it has is somewhere this cannot see.',
342
369
  recommendation: 'Apply express-rate-limit (or equivalent) to login/register/password reset endpoints.',
343
370
  /**
344
371
  * The claim is about rate limiting, so the evidence is about rate limiting.
@@ -453,7 +480,9 @@ exports.rules = [
453
480
  ? 'Uploads look publicly exposed without auth checks.'
454
481
  : status === 'partial'
455
482
  ? 'Uploads are exposed and some auth signals exist, review route protection.'
456
- : 'No obvious public upload exposure signal detected.',
483
+ : status === 'passed'
484
+ ? 'Upload handling was found, and none of it is publicly exposed.'
485
+ : 'No upload handling was found in this repository.',
457
486
  recommendation: 'Protect upload routes with authz, validate MIME/type, and prefer private object storage.',
458
487
  evidence: up?.evidence ?? [],
459
488
  });
@@ -475,7 +504,13 @@ exports.rules = [
475
504
  category: 'auth',
476
505
  status,
477
506
  severity: sevForStatus(status, 'medium'),
478
- description: status === 'missing' ? 'No clear authentication signals detected.' : 'Authentication signals detected.',
507
+ description: status === 'missing'
508
+ ? 'No clear authentication signals detected.'
509
+ : status === 'unknown'
510
+ ? 'Nothing in this repository serves requests or holds accounts, so there is nobody here to authenticate.'
511
+ : status === 'partial'
512
+ ? 'Authentication signals detected, but not a complete flow.'
513
+ : 'Authentication signals detected.',
479
514
  recommendation: 'Implement robust auth flow and secure credential handling.',
480
515
  evidence: auth?.evidence ?? [],
481
516
  });
@@ -515,7 +550,11 @@ exports.rules = [
515
550
  ? 'Permission-level authorization signals detected.'
516
551
  : status === 'partial'
517
552
  ? 'Only basic role checks detected.'
518
- : 'No resource-level authorization signals detected.',
553
+ : status === 'missing'
554
+ ? 'No resource-level authorization signals detected.'
555
+ : !hasAuth
556
+ ? 'Nothing here authenticates anybody, so there are no callers to authorize.'
557
+ : 'Nothing in this repository serves requests, so there are no records to guard.',
519
558
  recommendation: 'Add policy/resource-level checks beyond coarse role gates.',
520
559
  evidence: [...(roles?.evidence ?? []), ...(permissions?.evidence ?? []), ...(resourceLevel?.evidence ?? [])],
521
560
  });
@@ -598,9 +637,15 @@ exports.rules = [
598
637
  category: 'gdpr',
599
638
  status,
600
639
  severity: sevForStatus(status, 'medium'),
601
- description: hasUsers && !hasGdpr
640
+ description: status === 'missing'
602
641
  ? 'Auth/users signals found but no GDPR/privacy controls detected.'
603
- : 'Privacy/GDPR signals detected or not applicable from available evidence.',
642
+ : status === 'passed'
643
+ ? 'Consent, export, erasure or retention controls detected.'
644
+ : hasGdpr
645
+ ? 'Privacy controls were found, but nothing here serves requests or holds accounts for them to apply to.'
646
+ : !hasUserFacingSurface(analysis)
647
+ ? 'Nothing in this repository serves requests or holds accounts, so there is no personal data flow here to check.'
648
+ : 'No accounts or user records were detected, so there is nothing here for these duties to attach to.',
604
649
  recommendation: 'Implement consent, export/erasure workflows, and retention policies.',
605
650
  evidence: [
606
651
  ...(consent?.evidence ?? []),
@@ -771,7 +816,9 @@ exports.rules = [
771
816
  ? 'Nothing in this repository is deployed as a running service, so how it reaches people — a registry, a store, a host — is decided outside it.'
772
817
  : status === 'missing'
773
818
  ? 'No meaningful deployment artifacts or prod/runtime signals detected.'
774
- : 'Deployment artifacts or runtime production signals detected.',
819
+ : status === 'partial'
820
+ ? 'Deployment artifacts detected, but the production-aware runtime settings are incomplete.'
821
+ : 'Deployment artifacts and production-aware runtime settings detected.',
775
822
  /**
776
823
  * Graceful shutdown is left out where there is no signal to catch: PHP-FPM and
777
824
  * CGI hand each request to a worker that exits when it is done, and telling a
@@ -814,11 +861,13 @@ exports.rules = [
814
861
  category: 'deployment',
815
862
  status,
816
863
  severity: sevForStatus(status, 'low'),
817
- description: docker?.present
818
- ? 'Docker signals found.'
819
- : containerisable
820
- ? 'No Docker artifacts found.'
821
- : 'Nothing here is deployed as a container.',
864
+ description: status === 'passed'
865
+ ? 'A Dockerfile and a compose file were found.'
866
+ : status === 'partial'
867
+ ? 'Docker artifacts were found, but not the whole set — a Dockerfile without a compose file, or the reverse.'
868
+ : containerisable
869
+ ? 'No Docker artifacts found.'
870
+ : 'Nothing here is deployed as a container.',
822
871
  recommendation: containerisable ? 'Provide Dockerfile and healthchecks for reproducible deployments.' : '',
823
872
  evidence: docker?.evidence ?? [],
824
873
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@produtype/core",
3
- "version": "0.19.1",
3
+ "version": "0.20.0",
4
4
  "description": "Deterministic CLI and library that analyzes a web application repository and reports how far it is from production-ready for the kind of product it is meant to be.",
5
5
  "license": "MIT",
6
6
  "bin": {