devtime-ei 0.2.0__tar.gz → 0.3.0__tar.gz

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 (77) hide show
  1. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/PKG-INFO +4 -4
  2. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/README.md +2 -2
  3. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/pyproject.toml +2 -2
  4. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/__init__.py +1 -1
  5. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/intelligence/verification.py +140 -1
  6. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/scanner/signals.py +5 -1
  7. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime_ei.egg-info/PKG-INFO +4 -4
  8. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/LICENSE +0 -0
  9. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/setup.cfg +0 -0
  10. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/ai/__init__.py +0 -0
  11. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/ai/local.py +0 -0
  12. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/ai/prompts.py +0 -0
  13. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/ai/providers.py +0 -0
  14. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/assets/devtimeignore.starter +0 -0
  15. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/cli.py +0 -0
  16. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/config.py +0 -0
  17. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/db/__init__.py +0 -0
  18. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/db/connection.py +0 -0
  19. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/db/migrations.py +0 -0
  20. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/db/repository.py +0 -0
  21. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/db/schema.sql +0 -0
  22. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/demo.py +0 -0
  23. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/fixtures/__init__.py +0 -0
  24. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/fixtures/assertions.py +0 -0
  25. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/fixtures/loader.py +0 -0
  26. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/fixtures/runner.py +0 -0
  27. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/intelligence/__init__.py +0 -0
  28. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/intelligence/claims.py +0 -0
  29. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/intelligence/concepts.py +0 -0
  30. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/intelligence/context_pack.py +0 -0
  31. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/intelligence/evidence.py +0 -0
  32. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/intelligence/lineage.py +0 -0
  33. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/intelligence/risk.py +0 -0
  34. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/intelligence/scoring.py +0 -0
  35. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/mcp/__init__.py +0 -0
  36. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/mcp/schemas.py +0 -0
  37. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/mcp/server.py +0 -0
  38. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/mcp/tools.py +0 -0
  39. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/mcp/transport.py +0 -0
  40. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/output/__init__.py +0 -0
  41. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/output/json_export.py +0 -0
  42. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/output/markdown.py +0 -0
  43. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/output/terminal.py +0 -0
  44. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/paths.py +0 -0
  45. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/privacy.py +0 -0
  46. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/.devtimeignore +0 -0
  47. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/README.md +0 -0
  48. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/docs/decisions/0001-use-jwt.md +0 -0
  49. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/package.json +0 -0
  50. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/src/admin/permissions.ts +0 -0
  51. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/src/auth/login.ts +0 -0
  52. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/src/auth/middleware.ts +0 -0
  53. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/src/auth/tokens.ts +0 -0
  54. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/src/billing/stripe-webhook.ts +0 -0
  55. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/src/billing/subscription-service.ts +0 -0
  56. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/src/export/export-csv.ts +0 -0
  57. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/src/jobs/email-worker.ts +0 -0
  58. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/src/jobs/queues.ts +0 -0
  59. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/tests/auth-login.test.ts +0 -0
  60. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/resources/demo-saas/tests/stripe-signature.test.ts +0 -0
  61. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/scanner/__init__.py +0 -0
  62. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/scanner/extractors/__init__.py +0 -0
  63. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/scanner/extractors/base.py +0 -0
  64. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/scanner/extractors/config_files.py +0 -0
  65. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/scanner/extractors/docs.py +0 -0
  66. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/scanner/extractors/nextjs.py +0 -0
  67. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/scanner/extractors/python.py +0 -0
  68. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/scanner/extractors/tests.py +0 -0
  69. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/scanner/extractors/typescript.py +0 -0
  70. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/scanner/file_walker.py +0 -0
  71. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/scanner/ignore.py +0 -0
  72. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime/scanner/language.py +0 -0
  73. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime_ei.egg-info/SOURCES.txt +0 -0
  74. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime_ei.egg-info/dependency_links.txt +0 -0
  75. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime_ei.egg-info/entry_points.txt +0 -0
  76. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime_ei.egg-info/requires.txt +0 -0
  77. {devtime_ei-0.2.0 → devtime_ei-0.3.0}/src/devtime_ei.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devtime-ei
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Local-first Engineering Intelligence for software repositories
5
5
  Author-email: Aviad Shakargi <aviad94@gmail.com>
6
6
  Maintainer-email: Aviad Shakargi <aviad94@gmail.com>
@@ -8,7 +8,7 @@ License: Apache-2.0
8
8
  Project-URL: Homepage, https://github.com/Shakargy/devtime
9
9
  Project-URL: Repository, https://github.com/Shakargy/devtime
10
10
  Project-URL: Issues, https://github.com/Shakargy/devtime/issues
11
- Project-URL: Release Notes, https://github.com/Shakargy/devtime/releases/tag/v0.2.0
11
+ Project-URL: Release Notes, https://github.com/Shakargy/devtime/releases/tag/v0.3.0
12
12
  Project-URL: Demo, https://youtu.be/1Hiu3Y9J_SI
13
13
  Keywords: devtools,cli,static-analysis,repository-analysis,engineering-intelligence,local-first
14
14
  Classifier: Development Status :: 3 - Alpha
@@ -317,8 +317,8 @@ Contradictions:
317
317
  ```
318
318
 
319
319
  Statuses are SUPPORTED, WEAK, CONTRADICTED, or UNKNOWN; contradictions always
320
- show both sides; changed evidence marks a claim STALE. One built-in claim ships
321
- in v0.2. See **[VERIFICATION.md](VERIFICATION.md)**.
320
+ show both sides; changed evidence marks a claim STALE. Two built-in claims ship
321
+ (billing webhook signatures, JWT authentication). See **[VERIFICATION.md](VERIFICATION.md)**.
322
322
 
323
323
  ## Example output
324
324
 
@@ -278,8 +278,8 @@ Contradictions:
278
278
  ```
279
279
 
280
280
  Statuses are SUPPORTED, WEAK, CONTRADICTED, or UNKNOWN; contradictions always
281
- show both sides; changed evidence marks a claim STALE. One built-in claim ships
282
- in v0.2. See **[VERIFICATION.md](VERIFICATION.md)**.
281
+ show both sides; changed evidence marks a claim STALE. Two built-in claims ship
282
+ (billing webhook signatures, JWT authentication). See **[VERIFICATION.md](VERIFICATION.md)**.
283
283
 
284
284
  ## Example output
285
285
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "devtime-ei"
3
- version = "0.2.0"
3
+ version = "0.3.0"
4
4
  description = "Local-first Engineering Intelligence for software repositories"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -50,7 +50,7 @@ dev = [
50
50
  Homepage = "https://github.com/Shakargy/devtime"
51
51
  Repository = "https://github.com/Shakargy/devtime"
52
52
  Issues = "https://github.com/Shakargy/devtime/issues"
53
- "Release Notes" = "https://github.com/Shakargy/devtime/releases/tag/v0.2.0"
53
+ "Release Notes" = "https://github.com/Shakargy/devtime/releases/tag/v0.3.0"
54
54
  Demo = "https://youtu.be/1Hiu3Y9J_SI"
55
55
 
56
56
  [project.scripts]
@@ -1,6 +1,6 @@
1
1
  """DevTime - local-first Engineering Intelligence for repository memory."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.3.0"
4
4
 
5
5
  # Version metadata (Builder Edition, Chapter 20).
6
6
  EVIDENCE_MODEL = "2026.06.1"
@@ -149,8 +149,17 @@ BUILTIN_CLAIMS: dict[str, ClaimDefinition] = {
149
149
  statement="Incoming billing webhooks verify the payment provider's signature.",
150
150
  category="billing",
151
151
  ),
152
+ "jwt-authentication": ClaimDefinition(
153
+ slug="jwt-authentication",
154
+ name="JWT Authentication",
155
+ statement="Authentication uses JWT access tokens.",
156
+ category="authentication",
157
+ ),
152
158
  }
153
159
 
160
+ # JWT library names for dependency evidence.
161
+ _JWT_DEP_TOKENS = ("jsonwebtoken", "pyjwt", "jose", "njwt", "jwt-decode", "fast-jwt")
162
+
154
163
  _LIMITATIONS = [
155
164
  "Heuristic scanner: evidence comes from static patterns, not execution.",
156
165
  "Signature verification is recognized for known provider patterns "
@@ -225,7 +234,8 @@ def verify_claim(conn: sqlite3.Connection, slug: str) -> VerificationResult:
225
234
  )
226
235
 
227
236
  rows = _load_signals(conn, scan_id)
228
- return _verify_billing_webhook_signature(definition, rows, scan_id)
237
+ evaluator = _EVALUATORS[slug]
238
+ return evaluator(definition, rows, scan_id)
229
239
 
230
240
 
231
241
  def _verify_billing_webhook_signature(
@@ -348,6 +358,135 @@ def _verify_billing_webhook_signature(
348
358
  )
349
359
 
350
360
 
361
+ def _verify_jwt_authentication(
362
+ definition: ClaimDefinition, rows: list[sqlite3.Row], scan_id: str
363
+ ) -> VerificationResult:
364
+ """Verify JWT access-token authentication, with the documentation-vs-
365
+ implementation contradiction detector.
366
+
367
+ The purpose classifier (Trust Repair v0.0.6) distinguishes access tokens
368
+ from invitation/verification tokens. Documentation claiming JWT while the
369
+ only JWT usage found is invitation-purpose is a real, both-sided conflict.
370
+ Documentation with NO usage found at all is missing evidence (WEAK), not a
371
+ contradiction: absence is not positive conflicting evidence.
372
+ """
373
+ access_usage: list[EvidenceRef] = []
374
+ invitation_usage: list[EvidenceRef] = []
375
+ unclear_usage: list[EvidenceRef] = []
376
+ jwt_docs: list[EvidenceRef] = []
377
+ jwt_deps: list[EvidenceRef] = []
378
+
379
+ for row in rows:
380
+ hay = _hay(row)
381
+ kind = row["kind"]
382
+
383
+ if kind == "token_usage":
384
+ try:
385
+ purpose = json.loads(row["metadata_json"] or "{}").get("purpose", "unclear")
386
+ except json.JSONDecodeError:
387
+ purpose = "unclear"
388
+ if purpose == "access":
389
+ access_usage.append(
390
+ _ref(row, "JWT used as an access token (login/bearer context).", "strong")
391
+ )
392
+ elif purpose == "invitation":
393
+ invitation_usage.append(
394
+ _ref(
395
+ row,
396
+ "JWT used for invitation/verification tokens, not access.",
397
+ "moderate",
398
+ )
399
+ )
400
+ else:
401
+ unclear_usage.append(
402
+ _ref(row, "JWT usage found; its purpose is unclear.", "weak")
403
+ )
404
+ elif kind in ("doc", "decision") and "jwt" in hay:
405
+ jwt_docs.append(
406
+ _ref(
407
+ row,
408
+ "Documentation or decision record references JWT.",
409
+ "moderate" if kind == "decision" else "weak",
410
+ )
411
+ )
412
+ elif kind == "dependency" and any(t in hay for t in _JWT_DEP_TOKENS):
413
+ jwt_deps.append(
414
+ _ref(row, "JWT library dependency is declared.", "weak")
415
+ )
416
+
417
+ why: list[str] = []
418
+ missing: list[str] = []
419
+ contradictions: list[Contradiction] = []
420
+ supporting: list[EvidenceRef] = []
421
+
422
+ if access_usage:
423
+ status = SUPPORTED
424
+ supporting = access_usage + jwt_docs + jwt_deps
425
+ why.append("JWT access-token usage evidence was found.")
426
+ if jwt_docs:
427
+ why.append("Documentation or a decision record corroborates JWT usage.")
428
+ else:
429
+ missing.append("A decision record explaining the JWT choice.")
430
+ elif jwt_docs and invitation_usage:
431
+ status = CONTRADICTED
432
+ supporting = invitation_usage
433
+ doc = jwt_docs[0]
434
+ inv = invitation_usage[0]
435
+ contradictions.append(
436
+ Contradiction(
437
+ summary="Documentation claims JWT authentication, but the only JWT "
438
+ "usage found is invitation/verification tokens.",
439
+ claimed_side=f"{doc.path} references JWT in a documentation or "
440
+ "decision context, implying JWT-based authentication.",
441
+ observed_side=f"{inv.path} uses JWT for invitation/verification "
442
+ "tokens. Invitation tokens are not access-token authentication, "
443
+ "and no access-token usage was found.",
444
+ evidence=[doc, inv],
445
+ )
446
+ )
447
+ why.append(
448
+ "Documentation references JWT, but no access-token usage exists; "
449
+ "the only JWT usage found is invitation-purpose."
450
+ )
451
+ missing.append("JWT access-token usage (login/bearer/authorization context).")
452
+ elif jwt_docs or jwt_deps or invitation_usage or unclear_usage:
453
+ status = WEAK
454
+ supporting = jwt_docs + jwt_deps + invitation_usage + unclear_usage
455
+ why.append(
456
+ "JWT surface exists (documentation, dependencies, or unclear usage), "
457
+ "but access-token authentication is not established."
458
+ )
459
+ missing.append("JWT access-token usage (login/bearer/authorization context).")
460
+ else:
461
+ status = UNKNOWN
462
+ why.append(
463
+ "No JWT evidence was found in the scanned files. The claim does not "
464
+ "apply, or the usage is outside scanner coverage."
465
+ )
466
+ missing.append("Any JWT usage, dependency, or documentation.")
467
+
468
+ return VerificationResult(
469
+ claim_slug=definition.slug,
470
+ claim_name=definition.name,
471
+ statement=definition.statement,
472
+ status=status,
473
+ why=why,
474
+ supporting=supporting,
475
+ contradictions=contradictions,
476
+ missing=missing,
477
+ limitations=_LIMITATIONS,
478
+ scan_id=scan_id,
479
+ verified_at=_now(),
480
+ engine_version=__version__,
481
+ )
482
+
483
+
484
+ _EVALUATORS = {
485
+ "billing-webhook-signature": _verify_billing_webhook_signature,
486
+ "jwt-authentication": _verify_jwt_authentication,
487
+ }
488
+
489
+
351
490
  def _ref(row: sqlite3.Row, observation: str, strength: str) -> EvidenceRef:
352
491
  return EvidenceRef(
353
492
  path=row["path"],
@@ -10,6 +10,7 @@ Never executes repository code, never makes network calls.
10
10
  from __future__ import annotations
11
11
 
12
12
  import hashlib
13
+ import json
13
14
  import sqlite3
14
15
  import uuid
15
16
  from dataclasses import dataclass, field
@@ -214,7 +215,10 @@ def run_scan(
214
215
  s.start_line,
215
216
  s.end_line,
216
217
  s.confidence,
217
- "{}",
218
+ # v0.3.0: persist extractor metadata (was hardcoded '{}',
219
+ # silently dropping e.g. the JWT purpose classification
220
+ # that verification reads back from the database).
221
+ json.dumps(s.metadata or {}),
218
222
  ),
219
223
  )
220
224
  conn.commit()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devtime-ei
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Local-first Engineering Intelligence for software repositories
5
5
  Author-email: Aviad Shakargi <aviad94@gmail.com>
6
6
  Maintainer-email: Aviad Shakargi <aviad94@gmail.com>
@@ -8,7 +8,7 @@ License: Apache-2.0
8
8
  Project-URL: Homepage, https://github.com/Shakargy/devtime
9
9
  Project-URL: Repository, https://github.com/Shakargy/devtime
10
10
  Project-URL: Issues, https://github.com/Shakargy/devtime/issues
11
- Project-URL: Release Notes, https://github.com/Shakargy/devtime/releases/tag/v0.2.0
11
+ Project-URL: Release Notes, https://github.com/Shakargy/devtime/releases/tag/v0.3.0
12
12
  Project-URL: Demo, https://youtu.be/1Hiu3Y9J_SI
13
13
  Keywords: devtools,cli,static-analysis,repository-analysis,engineering-intelligence,local-first
14
14
  Classifier: Development Status :: 3 - Alpha
@@ -317,8 +317,8 @@ Contradictions:
317
317
  ```
318
318
 
319
319
  Statuses are SUPPORTED, WEAK, CONTRADICTED, or UNKNOWN; contradictions always
320
- show both sides; changed evidence marks a claim STALE. One built-in claim ships
321
- in v0.2. See **[VERIFICATION.md](VERIFICATION.md)**.
320
+ show both sides; changed evidence marks a claim STALE. Two built-in claims ship
321
+ (billing webhook signatures, JWT authentication). See **[VERIFICATION.md](VERIFICATION.md)**.
322
322
 
323
323
  ## Example output
324
324
 
File without changes
File without changes