106106 capability_preflight_input ,
107107 capability_preflight_json ,
108108 optional_text ,
109+ parse_scan_cost ,
109110 require_occurrence ,
110111 require_uuid ,
111112)
@@ -1453,12 +1454,16 @@ def pin_legacy_manifest_digest(
14531454
14541455def complete_scan (connection : sqlite3 .Connection , args : argparse .Namespace ) -> dict [str , Any ]:
14551456 scan_id = require_uuid (args .scan_id , "scan-id" )
1457+ cost_json = parse_scan_cost (args .cost_json )
14561458 with scan_completion_lock (scan_id ):
1457- return complete_scan_locked (connection , scan_id , args .claim_token )
1459+ return complete_scan_locked (connection , scan_id , args .claim_token , cost_json )
14581460
14591461
14601462def complete_scan_locked (
1461- connection : sqlite3 .Connection , scan_id : str , claim_token : str | None
1463+ connection : sqlite3 .Connection ,
1464+ scan_id : str ,
1465+ claim_token : str | None ,
1466+ cost_json : str | None ,
14621467) -> dict [str , Any ]:
14631468 scan = require_scan (connection , scan_id )
14641469 if scan ["status" ] == "complete" :
@@ -1551,10 +1556,10 @@ def complete_scan_locked(
15511556 """
15521557 UPDATE scans
15531558 SET status = 'complete', phase = 'reporting', completed_at = ?, updated_at = ?,
1554- seal_manifest_digest = ?
1559+ seal_manifest_digest = ?, cost_json = ?
15551560 WHERE id = ? AND status = 'running'
15561561 """ ,
1557- (timestamp , timestamp , manifest_digest , scan ["id" ]),
1562+ (timestamp , timestamp , manifest_digest , cost_json , scan ["id" ]),
15581563 )
15591564 if updated .rowcount != 1 :
15601565 raise SystemExit ("Only a running scan can be completed." )
@@ -1750,6 +1755,7 @@ def coverage_for_comparison(scan: sqlite3.Row) -> dict[str, Any]:
17501755
17511756def fail_scan (connection : sqlite3 .Connection , args : argparse .Namespace ) -> dict [str , Any ]:
17521757 scan_id = require_uuid (args .scan_id , "scan-id" )
1758+ cost_json = parse_scan_cost (args .cost_json )
17531759 connection .execute ("BEGIN IMMEDIATE" )
17541760 try :
17551761 timestamp = now ()
@@ -1767,10 +1773,17 @@ def fail_scan(connection: sqlite3.Connection, args: argparse.Namespace) -> dict[
17671773 updated = connection .execute (
17681774 """
17691775 UPDATE scans
1770- SET status = 'failed', failure_message = ?, completed_at = ?, updated_at = ?
1776+ SET status = 'failed', failure_message = ?, completed_at = ?, updated_at = ?,
1777+ cost_json = ?
17711778 WHERE id = ? AND status = 'running'
17721779 """ ,
1773- (optional_text (args .message , maximum = 2400 ), timestamp , timestamp , scan ["id" ]),
1780+ (
1781+ optional_text (args .message , maximum = 2400 ),
1782+ timestamp ,
1783+ timestamp ,
1784+ cost_json ,
1785+ scan ["id" ],
1786+ ),
17741787 )
17751788 if updated .rowcount != 1 :
17761789 raise SystemExit ("Only a running scan can be marked failed." )
@@ -3025,6 +3038,11 @@ def scan_result(
30253038 return {
30263039 "artifacts" : artifacts ,
30273040 "canceledAt" : scan ["canceled_at" ],
3041+ ** (
3042+ {"cost" : json .loads (scan ["cost_json" ], parse_constant = reject_non_finite_json )}
3043+ if scan ["cost_json" ] is not None
3044+ else {}
3045+ ),
30283046 "contract" : scan_contract (scan ),
30293047 "continuationThreadId" : scan ["continuation_thread_id" ],
30303048 "failureMessage" : scan ["failure_message" ],
0 commit comments