devtime-ei 0.2.0__tar.gz → 0.4.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.
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/PKG-INFO +4 -4
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/README.md +2 -2
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/pyproject.toml +2 -2
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/__init__.py +1 -1
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/cli.py +18 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/intelligence/verification.py +172 -1
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/scanner/signals.py +5 -1
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime_ei.egg-info/PKG-INFO +4 -4
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/LICENSE +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/setup.cfg +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/ai/__init__.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/ai/local.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/ai/prompts.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/ai/providers.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/assets/devtimeignore.starter +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/config.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/db/__init__.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/db/connection.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/db/migrations.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/db/repository.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/db/schema.sql +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/demo.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/fixtures/__init__.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/fixtures/assertions.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/fixtures/loader.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/fixtures/runner.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/intelligence/__init__.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/intelligence/claims.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/intelligence/concepts.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/intelligence/context_pack.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/intelligence/evidence.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/intelligence/lineage.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/intelligence/risk.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/intelligence/scoring.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/mcp/__init__.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/mcp/schemas.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/mcp/server.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/mcp/tools.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/mcp/transport.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/output/__init__.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/output/json_export.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/output/markdown.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/output/terminal.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/paths.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/privacy.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/.devtimeignore +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/README.md +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/docs/decisions/0001-use-jwt.md +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/package.json +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/admin/permissions.ts +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/auth/login.ts +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/auth/middleware.ts +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/auth/tokens.ts +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/billing/stripe-webhook.ts +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/billing/subscription-service.ts +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/export/export-csv.ts +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/jobs/email-worker.ts +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/jobs/queues.ts +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/tests/auth-login.test.ts +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/tests/stripe-signature.test.ts +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/scanner/__init__.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/scanner/extractors/__init__.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/scanner/extractors/base.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/scanner/extractors/config_files.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/scanner/extractors/docs.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/scanner/extractors/nextjs.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/scanner/extractors/python.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/scanner/extractors/tests.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/scanner/extractors/typescript.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/scanner/file_walker.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/scanner/ignore.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/scanner/language.py +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime_ei.egg-info/SOURCES.txt +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime_ei.egg-info/dependency_links.txt +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime_ei.egg-info/entry_points.txt +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime_ei.egg-info/requires.txt +0 -0
- {devtime_ei-0.2.0 → devtime_ei-0.4.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.
|
|
3
|
+
Version: 0.4.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.
|
|
11
|
+
Project-URL: Release Notes, https://github.com/Shakargy/devtime/releases/tag/v0.4.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.
|
|
321
|
-
|
|
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.
|
|
282
|
-
|
|
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.
|
|
3
|
+
version = "0.4.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.
|
|
53
|
+
"Release Notes" = "https://github.com/Shakargy/devtime/releases/tag/v0.4.0"
|
|
54
54
|
Demo = "https://youtu.be/1Hiu3Y9J_SI"
|
|
55
55
|
|
|
56
56
|
[project.scripts]
|
|
@@ -347,11 +347,29 @@ def risk(
|
|
|
347
347
|
conn = connection.connect()
|
|
348
348
|
try:
|
|
349
349
|
intelligence = repository.load_all_concepts(conn)
|
|
350
|
+
from devtime.intelligence.verification import claims_affected_by_paths
|
|
351
|
+
|
|
352
|
+
claim_impact = claims_affected_by_paths(conn, info.changed_files)
|
|
350
353
|
finally:
|
|
351
354
|
conn.close()
|
|
352
355
|
|
|
353
356
|
review = review_diff(info, intelligence)
|
|
354
357
|
console.print(render_risk_review(review), markup=False)
|
|
358
|
+
|
|
359
|
+
# v0.4.0: claim impact. A diff is not just risky in general - it can
|
|
360
|
+
# destabilize a previously verified claim. Only evidence files count;
|
|
361
|
+
# nothing is printed when no verified claim is affected.
|
|
362
|
+
if claim_impact:
|
|
363
|
+
console.print("\nClaim impact:", markup=False)
|
|
364
|
+
for item in claim_impact:
|
|
365
|
+
console.print(
|
|
366
|
+
f" - {item['claim_id']} (previous status: {item['previous_status']})",
|
|
367
|
+
markup=False,
|
|
368
|
+
)
|
|
369
|
+
for p in item["changed_evidence"]:
|
|
370
|
+
console.print(f" changed evidence: {p}", markup=False)
|
|
371
|
+
console.print(f" re-verify: {item['suggested_action']}", markup=False)
|
|
372
|
+
|
|
355
373
|
if review.state == STATE_REVIEW_FAILED:
|
|
356
374
|
raise typer.Exit(code=1)
|
|
357
375
|
|
|
@@ -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
|
-
|
|
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"],
|
|
@@ -441,6 +580,38 @@ def load_latest_verification(
|
|
|
441
580
|
)
|
|
442
581
|
|
|
443
582
|
|
|
583
|
+
def claims_affected_by_paths(
|
|
584
|
+
conn: sqlite3.Connection, changed_paths: list[str]
|
|
585
|
+
) -> list[dict]:
|
|
586
|
+
"""Claim impact for a set of changed paths (v0.4.0, diff integration).
|
|
587
|
+
|
|
588
|
+
For every claim with a stored verification, report it when a changed path
|
|
589
|
+
is one of its recorded evidence files. Only evidence files count: a diff
|
|
590
|
+
touching unrelated files never flags a claim. Advisory output - the caller
|
|
591
|
+
decides what to do with it.
|
|
592
|
+
"""
|
|
593
|
+
changed = set(changed_paths)
|
|
594
|
+
out: list[dict] = []
|
|
595
|
+
for slug in BUILTIN_CLAIMS:
|
|
596
|
+
latest = load_latest_verification(conn, slug)
|
|
597
|
+
if latest is None:
|
|
598
|
+
continue
|
|
599
|
+
result, fingerprints, created_at = latest
|
|
600
|
+
evidence_paths = {fp["path"] for fp in fingerprints}
|
|
601
|
+
hits = sorted(evidence_paths & changed)
|
|
602
|
+
if hits:
|
|
603
|
+
out.append(
|
|
604
|
+
{
|
|
605
|
+
"claim_id": slug,
|
|
606
|
+
"previous_status": result["status"],
|
|
607
|
+
"verified_at": created_at,
|
|
608
|
+
"changed_evidence": hits,
|
|
609
|
+
"suggested_action": f"dtc verify {slug}",
|
|
610
|
+
}
|
|
611
|
+
)
|
|
612
|
+
return out
|
|
613
|
+
|
|
614
|
+
|
|
444
615
|
def freshness_for(conn: sqlite3.Connection, slug: str) -> tuple[str, list[str]]:
|
|
445
616
|
"""Compare stored evidence fingerprints against current file hashes.
|
|
446
617
|
|
|
@@ -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.
|
|
3
|
+
Version: 0.4.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.
|
|
11
|
+
Project-URL: Release Notes, https://github.com/Shakargy/devtime/releases/tag/v0.4.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.
|
|
321
|
-
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/docs/decisions/0001-use-jwt.md
RENAMED
|
File without changes
|
|
File without changes
|
{devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/admin/permissions.ts
RENAMED
|
File without changes
|
|
File without changes
|
{devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/auth/middleware.ts
RENAMED
|
File without changes
|
|
File without changes
|
{devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/billing/stripe-webhook.ts
RENAMED
|
File without changes
|
|
File without changes
|
{devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/export/export-csv.ts
RENAMED
|
File without changes
|
{devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/src/jobs/email-worker.ts
RENAMED
|
File without changes
|
|
File without changes
|
{devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/tests/auth-login.test.ts
RENAMED
|
File without changes
|
{devtime_ei-0.2.0 → devtime_ei-0.4.0}/src/devtime/resources/demo-saas/tests/stripe-signature.test.ts
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|