ccs-digitalmarketplace-frameworks 3.11.0 → 3.11.2

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 (19) hide show
  1. package/.github/workflows/test.yml +2 -2
  2. package/.pre-commit-config.yaml +15 -17
  3. package/.python-version +1 -1
  4. package/frameworks/digital-outcomes-and-specialists-7/questions/services/chiefDigitalAndDataRolesChiefInformationSecurityOfficerBasicDayRate.yml +1 -1
  5. package/frameworks/digital-outcomes-and-specialists-7/questions/services/chiefDigitalAndDataRolesChiefInformationSecurityOfficerBasicDayRateSpecialist.yml +1 -1
  6. package/frameworks/digital-outcomes-and-specialists-7/questions/services/chiefDigitalAndDataRolesChiefInformationSecurityOfficerBasicLocations.yml +2 -2
  7. package/frameworks/digital-outcomes-and-specialists-7/questions/services/chiefDigitalAndDataRolesChiefInformationSecurityOfficerBasicUkDayRate.yml +1 -1
  8. package/frameworks/digital-outcomes-and-specialists-7/questions/services/chiefDigitalAndDataRolesChiefInformationSecurityOfficerRoles.yml +2 -2
  9. package/frameworks/digital-outcomes-and-specialists-7/questions/services/multiqChiefDigitalAndDataRolesChiefInformationSecurityOfficerBasic.yml +2 -2
  10. package/frameworks/digital-outcomes-and-specialists-7/questions/services/multiqChiefDigitalAndDataRolesChiefInformationSecurityOfficerBasicDCDP.yml +3 -3
  11. package/frameworks/digital-outcomes-and-specialists-7/questions/services/multiqCyberSecurityRolesCyberSecurity.yml +2 -0
  12. package/frameworks/digital-outcomes-and-specialists-7/questions/services/multiqCyberSecurityRolesCyberSecurityDCDP.yml +2 -0
  13. package/frameworks/digital-outcomes-and-specialists-7/questions/services/studioLocationPostcode.yml +2 -2
  14. package/package.json +1 -1
  15. package/requirements-dev.txt +5 -15
  16. package/requirements.in +2 -2
  17. package/requirements.txt +4 -6
  18. package/schema_generator/validation.py +65 -3
  19. package/scripts/generate-validation-schemas.py +5 -0
@@ -6,7 +6,7 @@ jobs:
6
6
  strategy:
7
7
  fail-fast: false
8
8
  matrix:
9
- python-version: [ '3.10' ]
9
+ python-version: [ '3.11' ]
10
10
 
11
11
  steps:
12
12
  - uses: actions/checkout@v4
@@ -35,7 +35,7 @@ jobs:
35
35
  runs-on: ubuntu-latest
36
36
  strategy:
37
37
  matrix:
38
- python-version: [ '3.10' ]
38
+ python-version: [ '3.11' ]
39
39
  script:
40
40
  - scripts/generate-assessment-schema.py g-cloud-14
41
41
  - scripts/generate-search-config.py g-cloud-14 services --output-path=/tmp
@@ -1,18 +1,16 @@
1
- # See https://pre-commit.com for more information
2
- # See https://pre-commit.com/hooks.html for more hooks
1
+ ---
3
2
  repos:
4
- - repo: https://github.com/pre-commit/pre-commit-hooks
5
- rev: d6d3bd94604578adbd918c5a00d531d98350d86f # v2.3.0
6
- hooks:
7
- - id: detect-private-key
8
- - repo: https://github.com/Yelp/detect-secrets
9
- rev: a3e7998bfa4924b13df3f9cb49070abdbdff8802 # v0.13.1
10
- hooks:
11
- - id: detect-secrets
12
- args: ['--baseline', '.secrets.baseline']
13
- exclude: .*/keys/.*|
14
- (?x)(
15
- ^package-lock.json$/|
16
- ^Pipfile/|
17
- ^pyproject.toml
18
- )
3
+ - repo: https://github.com/pre-commit/pre-commit-hooks
4
+ rev: v5.0.0
5
+ hooks:
6
+ - id: trailing-whitespace
7
+ - id: end-of-file-fixer
8
+ - id: check-yaml
9
+ - id: check-added-large-files
10
+ - id: detect-private-key
11
+
12
+ - repo: https://github.com/PyCQA/flake8
13
+ rev: 7.0.0
14
+ hooks:
15
+ - id: flake8
16
+ pass_filenames: false
package/.python-version CHANGED
@@ -1 +1 @@
1
- 3.10
1
+ 3.11
@@ -20,7 +20,7 @@ digit_limits:
20
20
  validations:
21
21
  - name: answer_required
22
22
  field: chiefDigitalAndDataRolesChiefInformationSecurityOfficerBasicPriceMax
23
- message: Enter the amount you will charge for a chief data officer
23
+ message: Enter the amount you will charge for a chief information security officer
24
24
  - name: not_money_format
25
25
  field: chiefDigitalAndDataRolesChiefInformationSecurityOfficerBasicPriceMax
26
26
  message: Maximum price must be a number less than 10,000, without units, like 99.95
@@ -20,7 +20,7 @@ digit_limits:
20
20
  validations:
21
21
  - name: answer_required
22
22
  field: chiefDigitalAndDataRolesChiefInformationSecurityOfficerBasicPriceMax
23
- message: Enter the amount you will charge for a chief data officer
23
+ message: Enter the amount you will charge for a chief information security officer
24
24
  - name: not_money_format
25
25
  field: chiefDigitalAndDataRolesChiefInformationSecurityOfficerBasicPriceMax
26
26
  message: Maximum price must be a number less than 10,000, without units, like 99.95
@@ -1,6 +1,6 @@
1
- name: Where will your chief data officer work?
1
+ name: Where will your chief information security officer work?
2
2
  question: |
3
- <p class="govuk-!-margin-bottom-2"><span class="govuk-fieldset__legend--s">Where will your chief data officer work?</span></p>
3
+ <p class="govuk-!-margin-bottom-2"><span class="govuk-fieldset__legend--s">Where will your chief information security officer work?</span></p>
4
4
  <p class="govuk-!-margin-bottom-0"><span class="govuk-fieldset__legend--s">Choose all the locations where the specialist can work at buyer’s sites, and whether they can work offsite.</span></p>
5
5
  hint: |
6
6
  ‘Offsite’ means the supplier will not be working at the buyer’s own sites.
@@ -20,7 +20,7 @@ digit_limits:
20
20
  validations:
21
21
  - name: answer_required
22
22
  field: chiefDigitalAndDataRolesChiefInformationSecurityOfficerBasicUkPriceMax
23
- message: Enter the amount you will charge for a chief data officer
23
+ message: Enter the amount you will charge for a chief information security officer
24
24
  - name: not_money_format
25
25
  field: chiefDigitalAndDataRolesChiefInformationSecurityOfficerBasicUkPriceMax
26
26
  message: Maximum price must be a number less than 10,000, without units, like 99.95
@@ -10,9 +10,9 @@ depends:
10
10
  type: checkboxes
11
11
 
12
12
  options:
13
- - label: Chief data officer
13
+ - label: Chief information security officer
14
14
  value: basic
15
- description: <a class="govuk-link" target="_blank" rel="noopener noreferrer" href="https://ddat-capability-framework.service.gov.uk/role/chief-information-security-officer#chief-data-officer">View role description <span class="govuk-visually-hidden">for Chief data officer </span>(opens in new tab)</a>
15
+ description: <a class="govuk-link" target="_blank" rel="noopener noreferrer" href="https://ddat-capability-framework.service.gov.uk/role/chief-information-security-officer#chief-information-security-officer">View role description <span class="govuk-visually-hidden">for Chief information security officer </span>(opens in new tab)</a>
16
16
 
17
17
  followup:
18
18
  multiqChiefDigitalAndDataRolesChiefInformationSecurityOfficerBasic:
@@ -1,5 +1,5 @@
1
- name: Chief data officer
2
- question: Chief data officer
1
+ name: Chief information security officer
2
+ question: Chief information security officer
3
3
  question_advice:
4
4
  Framework maximum rates are fixed for the duration of the agreement
5
5
 
@@ -1,8 +1,8 @@
1
- name: Chief data officer
2
- question: Chief data officer
1
+ name: Chief information security officer
2
+ question: Chief information security officer
3
3
  question_advice:
4
4
  <p>
5
- <a class="govuk-link" target="_blank" rel="noopener noreferrer" href="https://ddat-capability-framework.service.gov.uk/role/chief-information-security-officer#chief-data-officer">View role description <span class="govuk-visually-hidden">for Chief data officer </span>(opens in new tab)</a>.
5
+ <a class="govuk-link" target="_blank" rel="noopener noreferrer" href="https://ddat-capability-framework.service.gov.uk/role/chief-information-security-officer#chief-information-security-officer">View role description <span class="govuk-visually-hidden">for Chief information security officer </span>(opens in new tab)</a>.
6
6
  </p>
7
7
  <p>
8
8
  Framework maximum rates are fixed for the duration of the agreement.
@@ -1,5 +1,7 @@
1
1
  name: Cyber security
2
2
  question: Cyber security
3
+ hint:
4
+ The role is responsible for protecting an organisation's systems, networks, and data from unauthorised access, cyberattacks, and security breaches. Individuals in these roles perform a variety of tasks that involve identifying potential threats, responding and recovering from incidents, and ensuring that appropriate security measures are in place to safeguard critical information.
3
5
 
4
6
  depends:
5
7
  - "on": lot
@@ -1,5 +1,7 @@
1
1
  name: Cyber security
2
2
  question: Cyber security
3
+ hint:
4
+ The role is responsible for protecting an organisation's systems, networks, and data from unauthorised access, cyberattacks, and security breaches. Individuals in these roles perform a variety of tasks that involve identifying potential threats, responding and recovering from incidents, and ensuring that appropriate security measures are in place to safeguard critical information.
3
5
 
4
6
  depends:
5
7
  - "on": lot
@@ -1,5 +1,5 @@
1
- name: Potscode
2
- question: Potscode
1
+ name: Postcode
2
+ question: Postcode
3
3
 
4
4
  depends:
5
5
  - "on": lot
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccs-digitalmarketplace-frameworks",
3
- "version": "3.11.0",
3
+ "version": "3.11.2",
4
4
  "description": "Data files for Digital Marketplace’s procurement frameworks",
5
5
  "repository": "git@github.com:Crown-Commercial-Service/ccs-digitalmarketplace-frameworks",
6
6
  "author": "enquiries@digitalmarketplace.service.gov.uk"
@@ -1,13 +1,9 @@
1
1
  #
2
- # This file is autogenerated by pip-compile with Python 3.10
2
+ # This file is autogenerated by pip-compile with Python 3.11
3
3
  # by the following command:
4
4
  #
5
5
  # pip-compile requirements-dev.in
6
6
  #
7
- async-timeout==4.0.3
8
- # via
9
- # -r requirements.txt
10
- # redis
11
7
  attrs==23.1.0
12
8
  # via
13
9
  # hypothesis
@@ -30,13 +26,13 @@ cachelib==0.13.0
30
26
  # via
31
27
  # -r requirements.txt
32
28
  # flask-session
33
- ccs-digitalmarketplace-apiclient==27.3.0
29
+ ccs-digitalmarketplace-apiclient==28.0.0
34
30
  # via
35
31
  # -r requirements.txt
36
32
  # ccs-digitalmarketplace-utils
37
- ccs-digitalmarketplace-content-loader==12.0.1
33
+ ccs-digitalmarketplace-content-loader==13.0.0
38
34
  # via -r requirements.txt
39
- ccs-digitalmarketplace-utils==68.1.0
35
+ ccs-digitalmarketplace-utils==69.0.0
40
36
  # via
41
37
  # -r requirements.txt
42
38
  # ccs-digitalmarketplace-content-loader
@@ -76,10 +72,6 @@ docopt==0.6.2
76
72
  # via
77
73
  # -r requirements.txt
78
74
  # notifications-python-client
79
- exceptiongroup==1.1.3
80
- # via
81
- # hypothesis
82
- # pytest
83
75
  flake8==7.1.1
84
76
  # via -r requirements-dev.in
85
77
  flask==3.0.3
@@ -116,7 +108,7 @@ govuk-country-register==0.5.0
116
108
  # via
117
109
  # -r requirements.txt
118
110
  # ccs-digitalmarketplace-utils
119
- hypothesis==6.116.0
111
+ hypothesis==6.119.3
120
112
  # via -r requirements-dev.in
121
113
  idna==3.7
122
114
  # via
@@ -238,8 +230,6 @@ six==1.16.0
238
230
  # python-dateutil
239
231
  sortedcontainers==2.3.0
240
232
  # via hypothesis
241
- tomli==2.0.1
242
- # via pytest
243
233
  unicodecsv==0.14.1
244
234
  # via
245
235
  # -r requirements.txt
package/requirements.in CHANGED
@@ -1,5 +1,5 @@
1
1
  docopt==0.6.2
2
2
  deepmerge==2.0
3
3
  python-json-logger==2.0.7
4
- ccs-digitalmarketplace-content-loader==12.0.1
5
- ccs-digitalmarketplace-utils==68.1.0
4
+ ccs-digitalmarketplace-content-loader==13.0.0
5
+ ccs-digitalmarketplace-utils==69.0.0
package/requirements.txt CHANGED
@@ -1,11 +1,9 @@
1
1
  #
2
- # This file is autogenerated by pip-compile with Python 3.10
2
+ # This file is autogenerated by pip-compile with Python 3.11
3
3
  # by the following command:
4
4
  #
5
5
  # pip-compile requirements.in
6
6
  #
7
- async-timeout==4.0.3
8
- # via redis
9
7
  blinker==1.8.2
10
8
  # via flask
11
9
  boto3==1.34.144
@@ -16,11 +14,11 @@ botocore==1.34.144
16
14
  # s3transfer
17
15
  cachelib==0.13.0
18
16
  # via flask-session
19
- ccs-digitalmarketplace-apiclient==27.3.0
17
+ ccs-digitalmarketplace-apiclient==28.0.0
20
18
  # via ccs-digitalmarketplace-utils
21
- ccs-digitalmarketplace-content-loader==12.0.1
19
+ ccs-digitalmarketplace-content-loader==13.0.0
22
20
  # via -r requirements.in
23
- ccs-digitalmarketplace-utils==68.1.0
21
+ ccs-digitalmarketplace-utils==69.0.0
24
22
  # via
25
23
  # -r requirements.in
26
24
  # ccs-digitalmarketplace-content-loader
@@ -29,6 +29,10 @@ MANIFESTS = {
29
29
  'question_set': 'additional-lot-questions',
30
30
  'manifest': 'evaluations'
31
31
  },
32
+ 'assign-evaluations': {
33
+ 'question_set': 'additional-lot-questions',
34
+ 'manifest': 'evaluations'
35
+ },
32
36
  'agreements': {
33
37
  'question_set': 'agreements',
34
38
  'manifest': 'agreement'
@@ -231,6 +235,17 @@ SCHEMAS = {
231
235
  "user-research-studios-and-participants",
232
236
  ],
233
237
  ),
238
+ 'assign-evaluations': _get_schema_title_and_slugs(
239
+ "Assign evaluation framework lot questions",
240
+ "digital-outcomes-and-specialists",
241
+ exclude_lots=[
242
+ "digital-outcomes",
243
+ "digital-specialists",
244
+ "user-research-studios",
245
+ "user-research-participants",
246
+ "user-research-studios-and-participants",
247
+ ],
248
+ ),
234
249
  'additional-lot-questions': _get_schema_title_and_slugs(
235
250
  "Additional lot questions",
236
251
  "digital-outcomes-and-specialists",
@@ -262,7 +277,7 @@ SCHEMAS = {
262
277
  }
263
278
 
264
279
 
265
- def load_questions(schema_type, framework_slug, lot_slug_or_agreement_version):
280
+ def _load_manifest(schema_type, framework_slug, lot_slug_or_agreement_version):
266
281
  loader = ContentLoader('./')
267
282
  print(
268
283
  f'{framework_slug}/{lot_slug_or_agreement_version} '
@@ -281,15 +296,25 @@ def load_questions(schema_type, framework_slug, lot_slug_or_agreement_version):
281
296
  else:
282
297
  filter_key = 'lot'
283
298
 
284
- manifest = loader.get_manifest(framework_slug, MANIFESTS[schema_type]['manifest']).filter(
299
+ return loader.get_manifest(framework_slug, MANIFESTS[schema_type]['manifest']).filter(
285
300
  {filter_key: lot_slug_or_agreement_version},
286
301
  dynamic=False,
287
302
  ignore_depends_on_follow_up=True
288
303
  )
289
304
 
305
+
306
+ def load_questions(schema_type, framework_slug, lot_slug_or_agreement_version):
307
+ manifest = _load_manifest(schema_type, framework_slug, lot_slug_or_agreement_version)
308
+
290
309
  return {q['id']: q for q in sum((s.questions for s in manifest.sections), [])}
291
310
 
292
311
 
312
+ def load_sections(schema_type, framework_slug, lot_slug_or_agreement_version):
313
+ manifest = _load_manifest(schema_type, framework_slug, lot_slug_or_agreement_version)
314
+
315
+ return {s['slug']: s for s in manifest.sections}
316
+
317
+
293
318
  def merge_schemas(a, b):
294
319
  if not (isinstance(a, dict) and isinstance(b, dict)):
295
320
  raise TypeError("Error merging unsupported types '{}' and '{}'".format(
@@ -986,7 +1011,7 @@ def _multiquestion_dependencies(questions):
986
1011
  return {'dependencies': dependencies} if dependencies else {}
987
1012
 
988
1013
 
989
- def generate_schema(schema_type, schema_name, framework_slug, lot_slug):
1014
+ def _generate_question_schema(schema_type, schema_name, framework_slug, lot_slug):
990
1015
  questions = load_questions(schema_type, framework_slug, lot_slug)
991
1016
  drop_non_schema_questions(questions)
992
1017
  schema = empty_schema(schema_name)
@@ -998,6 +1023,43 @@ def generate_schema(schema_type, schema_name, framework_slug, lot_slug):
998
1023
  return schema
999
1024
 
1000
1025
 
1026
+ def _generate_assign_evaluations_schema(schema_type, schema_name, framework_slug, lot_slug):
1027
+ sections = load_sections(schema_type, framework_slug, lot_slug)
1028
+ schema = empty_schema(schema_name)
1029
+
1030
+ schema['properties'].update({
1031
+ "evaluatorFrameworkLots": {
1032
+ "type": "array",
1033
+ "items": {
1034
+ "type": "integer"
1035
+ }
1036
+ },
1037
+ "frameworkSlug": {
1038
+ "type": "string",
1039
+ },
1040
+ "lotSlug": {
1041
+ "type": "string",
1042
+ },
1043
+ "sectionSlug": {
1044
+ "enum": list(sections)
1045
+ }
1046
+ })
1047
+
1048
+ schema['required'].extend(schema['properties'].keys())
1049
+ schema['required'].sort()
1050
+
1051
+ return schema
1052
+
1053
+
1054
+ def generate_schema(schema_type, schema_name, framework_slug, lot_slug):
1055
+ if schema_type == 'assign-evaluations':
1056
+ generate_schema_method = _generate_assign_evaluations_schema
1057
+ else:
1058
+ generate_schema_method = _generate_question_schema
1059
+
1060
+ return generate_schema_method(schema_type, schema_name, framework_slug, lot_slug)
1061
+
1062
+
1001
1063
  def generate_schema_todir(dir_path, schema_type, schema_name, framework_slug, lot_slug):
1002
1064
  start_t = time.perf_counter()
1003
1065
  schema = generate_schema(schema_type, schema_name, framework_slug, lot_slug)
@@ -3,6 +3,7 @@
3
3
 
4
4
  Usage:
5
5
  generate-validation-schemas.py --output-path=<output_path> [--framework=<framework_slug>] [--lot=<lot_slug>]
6
+ [--manifest=<manifest>]
6
7
 
7
8
  """
8
9
  import os
@@ -22,6 +23,7 @@ if __name__ == '__main__':
22
23
  OUTPUT_DIR = arguments['--output-path']
23
24
  FRAMEWORK_SLUG = arguments.get('--framework')
24
25
  LOT_SLUG = arguments.get('--lot')
26
+ MANIFEST = arguments.get('--manifest')
25
27
  if not os.path.exists(OUTPUT_DIR):
26
28
  print("Creating {} directory".format(OUTPUT_DIR))
27
29
  os.makedirs(OUTPUT_DIR)
@@ -34,6 +36,9 @@ if __name__ == '__main__':
34
36
  if LOT_SLUG:
35
37
  schemas = [schema for schema in schemas if schema[3] == LOT_SLUG]
36
38
 
39
+ if MANIFEST:
40
+ schemas = [schema for schema in schemas if schema[0] == MANIFEST]
41
+
37
42
  with Pool(processes=5) as pool:
38
43
  results = pool.starmap(
39
44
  partial(