devsecops-engine-tools 1.48.1__py3-none-any.whl → 1.50.0__py3-none-any.whl

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.

Potentially problematic release.


This version of devsecops-engine-tools might be problematic. Click here for more details.

@@ -128,16 +128,17 @@ class BreakBuild:
128
128
  remediation_rate_name,
129
129
  mitigated_name,
130
130
  all_findings_name,
131
- new_industry_vulnerabilities,
131
+ new_findings,
132
132
  white_list_name,
133
+ transferred_name,
133
134
  base_image_name,
134
135
  ) = sp.symbols(
135
- "RemediationRate Mitigated AllFindings NewIndustryVulnerabilities WhiteList BaseImage"
136
+ "RemediationRate Mitigated AllFindings NewFindings WhiteList Transferred BaseImage"
136
137
  )
137
138
  formula = sp.Eq(
138
139
  remediation_rate_name,
139
140
  100
140
- * (mitigated_name / (all_findings_name - new_industry_vulnerabilities - white_list_name - base_image_name)),
141
+ * (mitigated_name / (all_findings_name - new_findings - white_list_name - transferred_name - base_image_name)),
141
142
  )
142
143
  print("\n")
143
144
  sp.pretty_print(formula)
@@ -149,18 +150,24 @@ class BreakBuild:
149
150
  for report in all_report
150
151
  if "On Whitelist" in report.risk_status and not report.mitigated
151
152
  )
153
+ transferred_list_count = sum(
154
+ 1
155
+ for report in all_report
156
+ if "Transfer Accepted" in report.risk_status and not report.mitigated
157
+ )
152
158
  base_image_count = sum(
153
159
  1
154
160
  for report in all_report
155
161
  if "Image Base" in report.vul_description
156
162
  and "On Whitelist" not in report.risk_status
163
+ and "Transfer Accepted" not in report.risk_status
157
164
  and not report.mitigated
158
165
  )
159
166
  all_findings_count = len(all_report)
160
167
  print(
161
- f"Mitigated: {mitigated_count} AllFindings: {all_findings_count} BaseImage: {base_image_count} NewIndustryVulnerabilities: {self.policy_excluded} WhiteList: {white_list_count}\n\n"
168
+ f"Mitigated: {mitigated_count} AllFindings: {all_findings_count} BaseImage: {base_image_count} NewFindings: {self.policy_excluded} Transferred: {transferred_list_count} WhiteList: {white_list_count}\n\n"
162
169
  )
163
- total = all_findings_count - self.policy_excluded - white_list_count - base_image_count
170
+ total = all_findings_count - self.policy_excluded - white_list_count - base_image_count - transferred_list_count
164
171
  remediation_rate_value = self._get_percentage(mitigated_count / total)
165
172
 
166
173
  risk_threshold = self._get_remediation_rate_threshold(total)
@@ -47,6 +47,7 @@ class IacScan:
47
47
  platform_to_scan=dict_args["platform"],
48
48
  secret_tool=secret_tool,
49
49
  secret_external_checks=dict_args["token_external_checks"],
50
+ work_folder=self.devops_platform_gateway.get_variable("temp_directory"),
50
51
  )
51
52
  else:
52
53
  print("Tool skipped by DevSecOps policy")
@@ -149,4 +150,4 @@ class IacScan:
149
150
  for folder in folders
150
151
  if re.match(patron, folder)
151
152
  ]
152
- return matching_folders
153
+ return matching_folders
@@ -211,6 +211,7 @@ class CheckovTool(ToolGateway):
211
211
  platform_to_scan,
212
212
  secret_tool,
213
213
  secret_external_checks,
214
+ **kwargs
214
215
  ):
215
216
  util = Utils()
216
217
  agent_env = util.configurate_external_checks(self.TOOL_CHECKOV,config_tool, secret_tool,secret_external_checks)
@@ -35,8 +35,8 @@ class KicsDeserealizator:
35
35
  severity = query.get("severity", "").upper()
36
36
  if severity in {"LOW", "MEDIUM", "HIGH", "CRITICAL"}:
37
37
  description = query.get("query_name", "")
38
- query_id = query.get("query_id", "")
39
38
  for file in query.get("files", []):
39
+ query_id = file.get("similarity_id", "")
40
40
  file_name = file.get("file_name", "")
41
41
  filtered_results.append({
42
42
  "severity": severity,
@@ -18,6 +18,25 @@ logger = MyLogger.__call__(**settings.SETTING_LOGGER).get_logger()
18
18
 
19
19
  class KicsTool(ToolGateway):
20
20
  TOOL_KICS = "KICS"
21
+ scan_type_platform_mapping = {
22
+ "openapi": "OpenAPI",
23
+ "terraform": "Terraform",
24
+ "k8s": "Kubernetes",
25
+ "docker": "Dockerfile",
26
+ "cloudformation": "CloudFormation",
27
+ "ansible": "Ansible",
28
+ "azureresourcemanager": "AzureResourceManager",
29
+ "bicep": "Bicep",
30
+ "buildah": "Buildah",
31
+ "cicd": "CICD",
32
+ "crossplane": "Crossplane",
33
+ "dockercompose": "DockerCompose",
34
+ "grpc": "GRPC",
35
+ "googledeploymentmanager": "GoogleDeploymentManager",
36
+ "knative": "Knative",
37
+ "pulumi": "Pulumi",
38
+ "serverlessfw": "ServerlessFW"
39
+ }
21
40
 
22
41
  def download(self, file, url):
23
42
  try:
@@ -27,105 +46,117 @@ class KicsTool(ToolGateway):
27
46
  except Exception as ex:
28
47
  logger.error(f"An error ocurred downloading {file} {ex}")
29
48
 
30
- def install_tool(self, file, url, command_prefix):
31
- utils = Utils()
32
- kics = f"./{command_prefix}/kics"
33
- installed = subprocess.run(
34
- ["which", command_prefix],
35
- stdout=subprocess.PIPE,
36
- stderr=subprocess.PIPE,
37
- )
38
- if installed.returncode == 1:
39
- try:
40
- self.download(file, url)
41
- utils.unzip_file(file, command_prefix)
42
- subprocess.run(["chmod", "+x", kics])
43
- return kics
44
- except Exception as e:
45
- logger.error(f"Error installing KICS: {e}")
46
- else:
47
- return command_prefix
48
-
49
- def install_tool_windows(self, file, url, command_prefix):
50
- try:
51
- subprocess.run(
52
- [command_prefix, "version"],
53
- stdout=subprocess.PIPE,
54
- stderr=subprocess.PIPE,
55
- )
56
- return command_prefix
57
- except:
58
- try:
59
- utils = Utils()
60
- self.download(file, url)
61
- utils.unzip_file(file, command_prefix)
62
- return f"./{command_prefix}/kics"
63
-
64
- except Exception as e:
65
- logger.error(f"Error installing KICS: {e}")
66
-
67
- def execute_kics(self, folders_to_scan, prefix):
49
+ def execute_kics(self, folders_to_scan, prefix, platform_to_scan, work_folder, os_platform, queries):
68
50
  folders = ','.join(folders_to_scan)
69
- command = [prefix, "scan", "-p", folders, "-q", "./kics_assets/assets", "--report-formats", "json", "-o", "./"]
51
+ queries = ','.join([list(query.values())[0] for query in queries])
52
+ mapped_platforms = [
53
+ self.scan_type_platform_mapping.get(platform.lower(), platform)
54
+ for platform in platform_to_scan
55
+ ]
56
+ platforms = ','.join(mapped_platforms)
57
+
58
+ command = [
59
+ prefix,
60
+ "scan",
61
+ "-p",
62
+ folders,
63
+ "-t",
64
+ platforms,
65
+ "--include-queries",
66
+ queries,
67
+ "-q",
68
+ f"{work_folder}\\kics-devsecops\\assets\\queries" if os_platform == "Windows"
69
+ else f"{work_folder}/kics-devsecops/assets/queries",
70
+ "--report-formats",
71
+ "json",
72
+ "-o",
73
+ work_folder
74
+ ]
70
75
  try:
71
76
  subprocess.run(command, capture_output=True)
72
77
  except subprocess.CalledProcessError as e:
73
78
  logger.error(f"Error during KICS execution: {e}")
74
79
 
75
- def load_results(self):
80
+ def load_results(self, work_folder, queries):
76
81
  try:
77
- with open('results.json') as f:
82
+ results_path = os.path.join(work_folder, "results.json")
83
+ with open(results_path, "r") as f:
78
84
  data = json.load(f)
85
+
86
+ for finding in data.get("queries", []):
87
+ query_ids = {list(query.values())[0] for query in queries}
88
+ if finding.get("query_id") in query_ids:
89
+ finding["custom_vuln_id"] = next(
90
+ key for query in queries for key, value in query.items() if value == finding.get("query_id")
91
+ )
92
+
93
+ with open(results_path, "w") as f:
94
+ json.dump(data, f, indent=4)
95
+
79
96
  return data
80
97
  except Exception as ex:
81
- logger.error(f"An error ocurred loading KICS results {ex}")
98
+ logger.error(f"An error occurred loading or modifying KICS results {ex}")
82
99
  return None
83
100
 
84
- def select_operative_system(self, os_platform, config_tool, path_kics):
85
- command_prefix = path_kics
86
- if os_platform == "Linux":
87
- kics_zip = "kics_linux.zip"
88
- url_kics = config_tool[self.TOOL_KICS]["KICS_LINUX"]
89
- return self.install_tool(kics_zip, url_kics, command_prefix)
90
- elif os_platform == "Windows":
91
- kics_zip = "kics_windows.zip"
92
- url_kics = config_tool[self.TOOL_KICS]["KICS_WINDOWS"]
93
- return self.install_tool_windows(kics_zip, url_kics, command_prefix)
94
- elif os_platform == "Darwin":
95
- kics_zip = "kics_macos.zip"
96
- url_kics = config_tool[self.TOOL_KICS]["KICS_MAC"]
97
- return self.install_tool(kics_zip, url_kics, command_prefix)
98
- else:
99
- logger.warning(f"{os_platform} is not supported.")
100
- return [], None
101
-
102
- def get_assets(self, kics_version):
101
+ def get_assets(self, kics_version, work_folder):
103
102
  name_zip = "assets_compressed.zip"
104
103
  assets_url = f"https://github.com/Checkmarx/kics/releases/download/v{kics_version}/extracted-info.zip"
105
104
  self.download(name_zip, assets_url)
106
105
 
107
- directory_assets = "kics_assets"
106
+ directory_assets = f"{work_folder}/kics-devsecops"
108
107
  utils = Utils()
109
108
  utils.unzip_file(name_zip, directory_assets)
110
109
 
110
+ def validate_kics(self, command_prefix):
111
+ try:
112
+ result = subprocess.run([command_prefix, "version"], capture_output=True, text=True)
113
+ if result.returncode == 0:
114
+ return True
115
+ else:
116
+ logger.error(f"KICS binary not valid: {result.stderr}")
117
+ return False
118
+ except Exception as e:
119
+ logger.error(f"Error validating KICS binary: {e}")
120
+
121
+ def get_queries(self, config_tool, platform_to_scan):
122
+ try:
123
+ queries = []
124
+ for platform in platform_to_scan:
125
+ platform = platform.strip().upper()
126
+ if f"RULES_{platform}" not in config_tool[self.TOOL_KICS]["RULES"]:
127
+ logger.error(f"Platform {platform} not found in RULES")
128
+ queries = [{key: value["checkID"]} for key, value in config_tool[self.TOOL_KICS]["RULES"][f"RULES_{platform}"].items()]
129
+ return queries
130
+ except Exception as e:
131
+ logger.error(f"Error writing queries file: {e}")
132
+
111
133
  def run_tool(
112
- self, config_tool, folders_to_scan, **kwargs
134
+ self, config_tool, folders_to_scan, work_folder, platform_to_scan, **kwargs
113
135
  ):
114
- kics_version = config_tool[self.TOOL_KICS]["VERSION"]
136
+ kics_version = config_tool[self.TOOL_KICS]["CLI_VERSION"]
115
137
  path_kics = config_tool[self.TOOL_KICS]["PATH_KICS"]
116
138
  download_kics_assets = config_tool[self.TOOL_KICS]["DOWNLOAD_KICS_ASSETS"]
117
- if download_kics_assets:
118
- self.get_assets(kics_version)
119
-
139
+
120
140
  os_platform = platform.system()
121
- command_prefix = self.select_operative_system(os_platform, config_tool, path_kics)
122
- self.execute_kics(folders_to_scan, command_prefix)
141
+ path_kics = path_kics.replace("/", "\\") if os_platform == "Windows" else path_kics
142
+ work_folder = work_folder.replace("/", "\\") if os_platform == "Windows" else work_folder
143
+
144
+ command_prefix = f"{work_folder}\\{path_kics}.exe" if os_platform == "Windows" else f"{work_folder}/{path_kics}"
145
+
146
+ if not self.validate_kics(command_prefix):
147
+ logger.info("KICS binary not found or invalid, downloading assets...")
148
+
149
+ if download_kics_assets:
150
+ self.get_assets(kics_version, work_folder)
123
151
 
124
- data = self.load_results()
152
+ queries = self.get_queries(config_tool, platform_to_scan)
153
+ self.execute_kics(folders_to_scan, command_prefix, platform_to_scan, work_folder, os_platform, queries)
154
+ data = self.load_results(work_folder, queries)
155
+
125
156
  if data:
126
157
  kics_deserealizator = KicsDeserealizator()
127
158
  total_vulnerabilities = kics_deserealizator.calculate_total_vulnerabilities(data)
128
- path_file = os.path.abspath("results.json")
159
+ path_file = os.path.join(work_folder, "results.json")
129
160
 
130
161
  if total_vulnerabilities == 0:
131
162
  return [], path_file
@@ -134,4 +165,4 @@ class KicsTool(ToolGateway):
134
165
  finding_list = kics_deserealizator.get_list_finding(filtered_results)
135
166
 
136
167
  return finding_list, path_file
137
- return [], None
168
+ return [], None
@@ -1 +1 @@
1
- version = '1.48.1'
1
+ version = '1.50.0'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: devsecops-engine-tools
3
- Version: 1.48.1
3
+ Version: 1.50.0
4
4
  Summary: Tool for DevSecOps strategy
5
5
  Home-page: https://github.com/bancolombia/devsecops-engine-tools
6
6
  Author: Bancolombia DevSecOps Team
@@ -1,5 +1,5 @@
1
1
  devsecops_engine_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- devsecops_engine_tools/version.py,sha256=fsWA33w6l-rR0RWdoXYfxoaTVXSxTBcmlhCVcZQZfyI,19
2
+ devsecops_engine_tools/version.py,sha256=IbFsfcSGQh-O_BT3I9RBywWSl3q9CYS9_0Z1DsySd80,19
3
3
  devsecops_engine_tools/engine_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  devsecops_engine_tools/engine_core/src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  devsecops_engine_tools/engine_core/src/applications/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -101,7 +101,7 @@ devsecops_engine_tools/engine_risk/src/domain/model/gateways/__init__.py,sha256=
101
101
  devsecops_engine_tools/engine_risk/src/domain/model/gateways/add_epss_gateway.py,sha256=cTm4QSxiaUt7ETCdXWZxKEus8pmEDA3e9k5b39SLDDE,178
102
102
  devsecops_engine_tools/engine_risk/src/domain/usecases/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
103
103
  devsecops_engine_tools/engine_risk/src/domain/usecases/add_data.py,sha256=4wqDj-q7hJfJscvrbMDcy7tONqxdxl-CSl_TWTRUGKA,402
104
- devsecops_engine_tools/engine_risk/src/domain/usecases/break_build.py,sha256=AgBM6p730v7alb_Um-av7K_aHGywkxhQJ6441lh5U6Y,15017
104
+ devsecops_engine_tools/engine_risk/src/domain/usecases/break_build.py,sha256=jXNb0bcpJu0L6eiQ4SAtjai9AoQbeU66fK-IGgup8pk,15324
105
105
  devsecops_engine_tools/engine_risk/src/domain/usecases/check_threshold.py,sha256=VYdmcbAuNNvdHCegRfvza7YJ8FHbFNyDosrKJrMW93I,765
106
106
  devsecops_engine_tools/engine_risk/src/domain/usecases/get_exclusions.py,sha256=1UNNq_Yhg3R78jLRSKcMNQYe8T8gl1C31C0ttBF0OAk,3992
107
107
  devsecops_engine_tools/engine_risk/src/domain/usecases/handle_filters.py,sha256=R53fnuIQYfr7YbpMz1BGPJ1d5z9jY_Hnm7EmPt99wlE,3608
@@ -146,16 +146,16 @@ devsecops_engine_tools/engine_sast/engine_iac/src/domain/model/config_tool.py,sh
146
146
  devsecops_engine_tools/engine_sast/engine_iac/src/domain/model/gateways/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
147
147
  devsecops_engine_tools/engine_sast/engine_iac/src/domain/model/gateways/tool_gateway.py,sha256=ClElxyHbwfDCW0fgcehaNfQLq00zozhO71EnyCjzt-U,182
148
148
  devsecops_engine_tools/engine_sast/engine_iac/src/domain/usecases/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
149
- devsecops_engine_tools/engine_sast/engine_iac/src/domain/usecases/iac_scan.py,sha256=4d9TF8pM_iun9EZo1c9IPZV84BrufGJvQRC8WCup3oQ,5910
149
+ devsecops_engine_tools/engine_sast/engine_iac/src/domain/usecases/iac_scan.py,sha256=BkUfDivqyYvZOTfJ8MfhvD9BMQPXRLQCmKhByjQnfvk,5998
150
150
  devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
151
151
  devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
152
152
  devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/checkov/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
153
153
  devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/checkov/checkov_config.py,sha256=qbE6wUO5_WFXF_QolL0JYelaRGEOUakPEZR_6HAKzzI,4355
154
154
  devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/checkov/checkov_deserealizator.py,sha256=l_opY909gh1m3k2ud2xDrCVnDTBe3ApYT75juBf_uMk,1836
155
- devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/checkov/checkov_tool.py,sha256=bMcPri5oZkQdzjz2cIWIb-JA3xpdsFwD7LPBp_IDUnQ,11991
155
+ devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/checkov/checkov_tool.py,sha256=buTIx2Tq3g5Rs-v4eT2GFB8NKzNh6R-FpzkofCUq9qw,12008
156
156
  devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/kics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
157
- devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/kics/kics_deserealizator.py,sha256=b1X5GWz2snJtsKZcGEsILNc178hv9p-lg-el0Jc-_Eo,2084
158
- devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/kics/kics_tool.py,sha256=8lda0A7huVSWgq2zMAN92vQv4ug0HiQMATGdXV5lgyA,5202
157
+ devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/kics/kics_deserealizator.py,sha256=tZq3jutZL2M9XIxm5K_xd3mWwTCMVmHQPFNvrslCqCM,2092
158
+ devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/kics/kics_tool.py,sha256=pVNZclcBKA6Ebm9kUfBWlHFI37ROT58CdqcczeM1UGs,6656
159
159
  devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/kubescape/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
160
160
  devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/kubescape/kubescape_deserealizator.py,sha256=bGOGmsIpJcQzTMxptJPwZCA9_2Woaua3pXmMs4kTnX8,2893
161
161
  devsecops_engine_tools/engine_sast/engine_iac/src/infrastructure/driven_adapters/kubescape/kubescape_tool.py,sha256=N17glvzoUkGQJ_1icqznpORXuKJRKEq8Ye1IleN5o1g,4544
@@ -347,8 +347,8 @@ devsecops_engine_tools/engine_utilities/utils/name_conversion.py,sha256=ADJrRGax
347
347
  devsecops_engine_tools/engine_utilities/utils/printers.py,sha256=amYAr9YQfYgR6jK9a2l26z3oovFPQ3FAKmhq6BKhEBA,623
348
348
  devsecops_engine_tools/engine_utilities/utils/session_manager.py,sha256=Z0fdhB3r-dxU0nGSD9zW_B4r2Qol1rUnUCkhFR0U-HQ,487
349
349
  devsecops_engine_tools/engine_utilities/utils/utils.py,sha256=HCjS900TBoNcHrC4LaiP-Kf9frVdtagF130qOUgnO2M,6757
350
- devsecops_engine_tools-1.48.1.dist-info/METADATA,sha256=hqIhjAzLVeg0ie74aQKly3ouyx32l_gutUl5jjWdGCo,11779
351
- devsecops_engine_tools-1.48.1.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
352
- devsecops_engine_tools-1.48.1.dist-info/entry_points.txt,sha256=MHCTFFs9bdNKo6YcWCcBW2_8X6yTisgLOlmVx-V8Rxc,276
353
- devsecops_engine_tools-1.48.1.dist-info/top_level.txt,sha256=ge6y0X_xBAU1aG3EMWFtl9djbVyg5BxuSp2r2Lg6EQU,23
354
- devsecops_engine_tools-1.48.1.dist-info/RECORD,,
350
+ devsecops_engine_tools-1.50.0.dist-info/METADATA,sha256=eT8fLJFCtv45wDxQruQSonplLFPbEY2F8h6SDb3Z3OM,11779
351
+ devsecops_engine_tools-1.50.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
352
+ devsecops_engine_tools-1.50.0.dist-info/entry_points.txt,sha256=MHCTFFs9bdNKo6YcWCcBW2_8X6yTisgLOlmVx-V8Rxc,276
353
+ devsecops_engine_tools-1.50.0.dist-info/top_level.txt,sha256=ge6y0X_xBAU1aG3EMWFtl9djbVyg5BxuSp2r2Lg6EQU,23
354
+ devsecops_engine_tools-1.50.0.dist-info/RECORD,,