1
- # Copyright (c) 2023 - 2023 , Oracle and/or its affiliates. All rights reserved.
1
+ # Copyright (c) 2023 - 2024 , Oracle and/or its affiliates. All rights reserved.
2
2
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
3
3
4
4
"""
10
10
11
11
For table associated with a check see the check module.
12
12
"""
13
- import hashlib
14
13
import logging
15
14
import os
16
15
import string
19
18
from typing import Any , Self
20
19
21
20
from packageurl import PackageURL
22
- from sqlalchemy import Boolean , Column , Enum , ForeignKey , Integer , String , Table , UniqueConstraint
21
+ from sqlalchemy import (
22
+ Boolean ,
23
+ CheckConstraint ,
24
+ Column ,
25
+ Enum ,
26
+ Float ,
27
+ ForeignKey ,
28
+ Integer ,
29
+ String ,
30
+ Table ,
31
+ UniqueConstraint ,
32
+ )
23
33
from sqlalchemy .orm import Mapped , mapped_column , relationship
24
34
25
35
from macaron .database .database_manager import ORMBase
26
36
from macaron .database .rfc3339_datetime import RFC3339DateTime
27
- from macaron .errors import CUEExpectationError , CUERuntimeError , InvalidPURLError
28
- from macaron .slsa_analyzer .provenance .expectations .cue import cue_validator
29
- from macaron .slsa_analyzer .provenance .expectations .expectation import Expectation
37
+ from macaron .errors import InvalidPURLError
30
38
from macaron .slsa_analyzer .slsa_req import ReqName
31
39
32
40
logger : logging .Logger = logging .getLogger (__name__ )
@@ -415,6 +423,16 @@ class CheckFacts(ORMBase):
415
423
#: The primary key.
416
424
id : Mapped [int ] = mapped_column (Integer , primary_key = True , autoincrement = True ) # noqa: A003
417
425
426
+ #: The confidence score to estimate the accuracy of the check fact. This value should be in [0.0, 1.0] with
427
+ #: a lower value depicting a lower confidence. Because some analyses used in checks may use
428
+ #: heuristics, the results can be inaccurate in certain cases.
429
+ #: We use the confidence score to enable the check designer to assign a confidence estimate.
430
+ #: This confidence is stored in the database to be used by the policy. This confidence score is
431
+ #: also used to decide which evidence should be shown to the user in the HTML/JSON report.
432
+ confidence : Mapped [float ] = mapped_column (
433
+ Float , CheckConstraint ("confidence>=0.0 AND confidence<=1.0" ), nullable = False
434
+ )
435
+
418
436
#: The foreign key to the software component.
419
437
component_id : Mapped [int ] = mapped_column (Integer , ForeignKey ("_component.id" ), nullable = False )
420
438
@@ -430,68 +448,36 @@ class CheckFacts(ORMBase):
430
448
#: A many-to-one relationship with check results.
431
449
checkresult : Mapped ["MappedCheckResult" ] = relationship (back_populates = "checkfacts" )
432
450
433
- #: The polymorphic inheritance configuration.
434
- __mapper_args__ = {
435
- "polymorphic_identity" : "CheckFacts" ,
436
- "polymorphic_on" : "check_type" ,
437
- }
438
-
451
+ def __lt__ (self , other : Self ) -> bool :
452
+ """Compare two check facts using their confidence values.
439
453
440
- class CUEExpectation (Expectation , CheckFacts ):
441
- """ORM Class for an expectation."""
454
+ This comparison function is intended to be used by a heapq, which is a Min-Heap data structure.
455
+ The root element in a heapq is the minimum element in the queue and each `confidence` value is in [0, 1].
456
+ Therefore, we need reverse the comparison function to make sure the fact with highest confidence is stored
457
+ in the root element. This implementation compares `1 - confidence` to return True if the confidence of
458
+ `fact_a` is greater than the confidence of `fact_b`.
442
459
443
- # TODO: provenance content check should store the expectation, its evaluation result,
444
- # and which PROVENANCE it was applied to rather than only linking to the repository.
460
+ .. code-block:: pycon
445
461
446
- __tablename__ = "_expectation"
462
+ >>> fact_a = CheckFacts()
463
+ >>> fact_b = CheckFacts()
464
+ >>> fact_a.confidence = 0.2
465
+ >>> fact_b.confidence = 0.7
466
+ >>> fact_b < fact_a
467
+ True
447
468
448
- #: The primary key, which is also a foreign key to the base check table.
449
- id : Mapped [int ] = mapped_column (ForeignKey ("_check_facts.id" ), primary_key = True ) # noqa: A003
469
+ Return
470
+ ------
471
+ bool
472
+ """
473
+ return (1 - self .confidence ) < (1 - other .confidence )
450
474
451
475
#: The polymorphic inheritance configuration.
452
476
__mapper_args__ = {
453
- "polymorphic_identity" : "_expectation" ,
477
+ "polymorphic_identity" : "CheckFacts" ,
478
+ "polymorphic_on" : "check_type" ,
454
479
}
455
480
456
- @classmethod
457
- def make_expectation (cls , expectation_path : str ) -> Self | None :
458
- """Construct a CUE expectation from a CUE file.
459
-
460
- Note: we require the CUE expectation file to have a "target" field.
461
-
462
- Parameters
463
- ----------
464
- expectation_path: str
465
- The path to the expectation file.
466
-
467
- Returns
468
- -------
469
- Self
470
- The instantiated expectation object.
471
- """
472
- logger .info ("Generating an expectation from file %s" , expectation_path )
473
- expectation : CUEExpectation = CUEExpectation (
474
- description = "CUE expectation" ,
475
- path = expectation_path ,
476
- target = "" ,
477
- expectation_type = "CUE" ,
478
- )
479
-
480
- try :
481
- with open (expectation_path , encoding = "utf-8" ) as expectation_file :
482
- expectation .text = expectation_file .read ()
483
- expectation .sha = str (hashlib .sha256 (expectation .text .encode ("utf-8" )).hexdigest ())
484
- expectation .target = cue_validator .get_target (expectation .text )
485
- expectation ._validator = ( # pylint: disable=protected-access
486
- lambda provenance : cue_validator .validate_expectation (expectation .text , provenance )
487
- )
488
- except (OSError , CUERuntimeError , CUEExpectationError ) as error :
489
- logger .error ("CUE expectation error: %s" , error )
490
- return None
491
-
492
- # TODO remove type ignore once mypy adds support for Self.
493
- return expectation # type: ignore
494
-
495
481
496
482
class Provenance (ORMBase ):
497
483
"""ORM class for a provenance document."""
0 commit comments