• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mozilla / blurts-server / 84531303-2a67-4a89-957d-4fc68293adb2

pending completion
84531303-2a67-4a89-957d-4fc68293adb2

Pull #2757

circleci

GitHub
Update src/scripts/convertBreachResolutions.js
Pull Request #2757: Mntor-977: Migrate breach resolution data (step 1)

282 of 1158 branches covered (24.35%)

Branch coverage included in aggregate %.

74 of 74 new or added lines in 2 files covered. (100.0%)

959 of 3090 relevant lines covered (31.04%)

5.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/scripts/convertBreachResolutions.js
1
/**
2
 * Executes once
3
 * The purpose of the script is to convert all `subscriber.breaches_resolved` to `subscriber.breaches_resolution`
4
 * with the goal of deprecating the column
5
 */
6

7
import Knex from 'knex'
8
import knexConfig from '../db/knexfile.js'
9
import { getAllBreachesFromDb } from '../utils/hibp.js'
10
import { getAllEmailsAndBreaches } from '../utils/breaches.js'
11
import { setBreachResolution } from '../db/tables/subscribers.js'
12
import { BreachDataTypes } from '../utils/breach-resolution.js'
13
const knex = Knex(knexConfig)
×
14

15
const LIMIT = 50 // with millions of records, we have to load a few at a time
×
16
let offset = 0 // looping through all records with offset
×
17
let subscribersArr = []
×
18

19
// load all breaches for ref
20
const allBreaches = await getAllBreachesFromDb()
×
21
if (allBreaches && allBreaches.length > 0) console.log('breaches loaded successfully! ', allBreaches.length)
×
22

23
// find all subscribers who resolved any breaches in the past, convert those
24
// records into the new v2 format
25
do {
×
26
  console.log(`Converting breaches_resolved to breach_resolution - start: ${offset} limit: ${LIMIT}`)
×
27
  subscribersArr = await knex
×
28
    .select('id', 'primary_email', 'breaches_resolved', 'breach_resolution')
29
    .from('subscribers')
30
    .whereNotNull('breaches_resolved')
31
    .limit(LIMIT)
32
    .offset(offset)
33

34
  console.log(`Loaded # of subscribers: ${subscribersArr.length}`)
×
35

36
  for (const subscriber of subscribersArr) {
×
37
    const { breaches_resolved: v1, breach_resolution: v2 } = subscriber
×
38
    console.debug({ v1 })
×
39
    console.debug({ v2 })
×
40

41
    let isV2Changed = false // use a boolean to track if v2 has been changed, only upsert if so
×
42

43
    // fetch subscriber all breaches / email
44
    const subscriberBreachesEmail = await getAllEmailsAndBreaches(subscriber, allBreaches)
×
45
    console.debug(JSON.stringify(subscriberBreachesEmail.verifiedEmails))
×
46

47
    for (const [email, resolvedRecencyIndices] of Object.entries(v1)) {
×
48
      console.debug({ email })
×
49
      console.debug({ resolvedRecencyIndices })
×
50
      for (const recencyIndex of resolvedRecencyIndices) {
×
51
        console.debug({ recencyIndex })
×
52
        // find subscriber's relevant recency index breach information
53
        const ve = subscriberBreachesEmail.verifiedEmails?.filter(ve => ve.email === email)[0] || {}
×
54
        const subBreach = ve.breaches?.filter(b => Number(b.recencyIndex) === Number(recencyIndex))[0] || null
×
55
        console.debug({ subBreach })
×
56

57
        if (!subBreach || !subBreach.DataClasses) {
×
58
          console.warn(`SKIP: Cannot find subscribers breach and data types - recency: ${recencyIndex} email: ${email}`)
×
59
          continue
×
60
        }
61

62
        // if email does not exist in v2, we need to add it to the object
63
        // format: {email: { recencyIndex: { isResolved: true, resolutionsChecked: [DataTypes]}}}
64
        if (!v2[email]) {
×
65
          v2[email] = {
×
66
            [recencyIndex]: {
67
              isResolved: true,
68
              resolutionsChecked: subBreach?.DataClasses || [BreachDataTypes.General]
×
69
            }
70
          }
71

72
          isV2Changed = true
×
73
        }
74
        if (v2[email][recencyIndex]?.isResolved) {
×
75
          console.log(`recencyIndex ${recencyIndex} exists in v2 and is resolved, no changes`)
×
76
        } else {
77
          console.log(`recencyIndex ${recencyIndex} either does not exist or is not resolved, overwriting`)
×
78
          v2[email][recencyIndex] = {
×
79
            isResolved: true,
80
            resolutionsChecked: subBreach?.DataClasses
81
          }
82
          isV2Changed = true
×
83
        }
84
      }
85
    }
86

87
    // check if v2 is changed, if so, upsert the new v2
88
    if (isV2Changed) {
×
89
      await setBreachResolution(subscriber, v2)
×
90
    }
91
  }
92
  offset += LIMIT
×
93
} while (subscribersArr.length === LIMIT)
94

95
// breaking out of do..while loop
96
console.log('Reaching the end of the table, offset ended at', offset)
×
97
process.exit()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc