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

hypercerts-org / certified-group-service / 28027792772

23 Jun 2026 12:55PM UTC coverage: 92.257%. First build
28027792772

push

github

web-flow
Merge pull request #52 from hypercerts-org/dev

Upgrade production to v0.2.0

389 of 420 branches covered (92.62%)

Branch coverage included in aggregate %.

547 of 571 new or added lines in 32 files covered. (95.8%)

1577 of 1711 relevant lines covered (92.17%)

47.88 hits per line

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

87.18
/src/api/group/finalize.ts
1
import type { AppContext } from '../../context.js'
1✔
2
import { ConflictError } from '../../errors.js'
3
import { encrypt } from '../../pds/credentials.js'
4

5
export interface FinalizeGroupParams {
6
  /** DID of the group account (created by register, or pre-existing for import). */
7
  groupDid: string
8
  /** PDS hosting the group account; stored verbatim and reused by PdsAgentPool. */
9
  pdsUrl: string
10
  /** App password the service uses to act on the account's behalf (plaintext). */
11
  appPassword: string
12
  /** DID seeded as the immutable owner. */
13
  ownerDid: string
14
  /**
15
   * Recovery-key material to store, already base64url-encoded, or `null` when
16
   * the service holds no recovery key for this group (the import case). The
17
   * `groups.encrypted_recovery_key` column is nullable.
18
   */
19
  recoveryKeyMaterial: string | null
20
  /** Audit action: distinguishes how the group entered the service. */
21
  action: 'group.register' | 'group.import'
22
  /** Resolved full handle, recorded in the audit detail. */
23
  handle: string
24
}
25

26
/**
27
 * Shared tail of `group.register` and `group.import`: persist the group's
28
 * credentials, initialise its per-group database, seed the owner, and audit-log
29
 * the operation. Everything before this differs between the two (register
30
 * creates an account and signs a PLC op; import logs in to an existing one),
31
 * but from credential storage onward the two are identical save for the
32
 * recovery key and the audit action.
33
 *
34
 * Throws `ConflictError('GroupAlreadyRegistered')` if the group DID is already
35
 * present in the `groups` table.
36
 */
37
export async function finalizeGroup(ctx: AppContext, params: FinalizeGroupParams): Promise<void> {
9✔
38
  const { groupDid, pdsUrl, appPassword, ownerDid, recoveryKeyMaterial, action, handle } = params
9✔
39

40
  const encryptionKey = Buffer.from(ctx.config.encryptionKey, 'hex')
9✔
41
  const encryptedAppPassword = encrypt(appPassword, encryptionKey)
9✔
42
  const encryptedRecoveryKey =
9✔
43
    recoveryKeyMaterial === null ? null : encrypt(recoveryKeyMaterial, encryptionKey)
9✔
44

45
  try {
9✔
46
    await ctx.globalDb
9✔
47
      .insertInto('groups')
9✔
48
      .values({
9✔
49
        did: groupDid,
9✔
50
        pds_url: pdsUrl,
9✔
51
        encrypted_app_password: encryptedAppPassword,
9✔
52
        encrypted_recovery_key: encryptedRecoveryKey,
9✔
53
      })
9✔
54
      .execute()
9✔
55
  } catch (err: unknown) {
9✔
56
    const msg = err instanceof Error ? err.message : String(err)
1!
57
    if (msg.includes('UNIQUE constraint failed') || msg.includes('PRIMARY KEY constraint failed')) {
1!
58
      throw new ConflictError('Group already registered', 'GroupAlreadyRegistered')
1✔
59
    }
1!
NEW
60
    throw err
×
NEW
61
  }
✔
62

63
  // Initialize per-group database and run migrations
64
  await ctx.groupDbs.migrateGroup(groupDid)
8✔
65

66
  // Seed owner (atomic write to both group DB and member_index)
67
  const groupDb = ctx.groupDbs.get(groupDid)
8✔
68
  const groupRaw = ctx.groupDbs.getRaw(groupDid)
8✔
69
  ctx.memberIndex.add(groupRaw, groupDid, ownerDid, 'owner', ownerDid)
8✔
70

71
  // Audit log the group creation/import
72
  await ctx.audit.log(groupDb, ownerDid, action, 'permitted', { handle })
8✔
73
}
8✔
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