Skip to content

Conversation

@rvlb
Copy link
Contributor

@rvlb rvlb commented Dec 13, 2025

Summary by Sourcery

Add VCI directory support and revocation checks to SHC verification while simplifying issuer metadata handling.

New Features:

  • Allow SHCReader to optionally resolve issuer metadata from the VCI directory snapshot via a new configuration flag.
  • Introduce explicit configuration validation for SHCReader to prevent incompatible directory options.
  • Add revocation detection for SMART Health Cards based on CRLs and VC revocation identifiers.

Enhancements:

  • Simplify SHC objects by removing embedded issuer metadata and centralizing issuer lookups in the Directory abstraction.
  • Extend the Directory API with helper methods for listing and resolving issuers by issuer identifier.

Documentation:

  • Document how to configure SHCReader with the VCI directory snapshot and clarify usage of custom Directory instances.
  • Update README examples to reflect the new Directory API and VCI directory usage.

Tests:

  • Update and expand SHC and Directory tests to cover VCI directory resolution, configuration validation, and revocation handling.
  • Refactor shared test fixtures for directory data into a common helper module.

Closes #2
Closes #4

@sourcery-ai
Copy link

sourcery-ai bot commented Dec 13, 2025

Reviewer's Guide

Adds SHC revocation handling based on issuer directory/VCI snapshot CRLs, introduces SHCReader configuration validation and new error types, and refactors directory/issuer metadata handling (including tests and docs) to use a simpler Directory API and optional VCI directory usage.

Sequence diagram for SHCReader verification with revocation and directory lookup

sequenceDiagram
  actor User
  participant SHCReader
  participant Directory
  participant VCISnapshot as VCIDirectory
  participant Issuer

  User->>SHCReader: constructor(config)
  alt issuerDirectory and useVciDirectory both set
    SHCReader-->>User: throw SHCReaderConfigError
  else valid configuration
    SHCReader-->>User: SHCReader instance
  end

  User->>SHCReader: verifySHC(jws)
  SHCReader->>SHCReader: decode and validate JWS / VC

  alt config.issuerDirectory provided
    SHCReader->>Directory: directory = issuerDirectory
  else config.useVciDirectory true
    SHCReader->>VCISnapshot: Directory.fromVCI()
    VCISnapshot-->>SHCReader: Directory instance
    SHCReader->>Directory: directory = vciDirectory
  else no directory configured
    SHCReader->>SHCReader: directory = null
  end

  alt directory is not null
    SHCReader->>Directory: getIssuerByIss(payload.iss)
    Directory-->>SHCReader: Issuer or undefined
    alt Issuer found and payload.vc.rid and issuer.crls
      loop for each CRL in issuer.crls
        SHCReader->>Issuer: check crl.rids.includes(vcRid)
        alt rid found in CRL
          SHCReader-->>User: throw SHCRevokedError
        end
      end
    end
  end

  SHCReader-->>User: new SHC(jws, originalBundle)
Loading

Updated class diagram for SHCReader, Directory, SHC, SHCIssuer, and errors

classDiagram
  class SHCReader {
    -config SHCReaderConfigParams
    -bundleProcessor FHIRBundleProcessor
    -vcProcessor VCProcessor
    +SHCReader(config SHCReaderConfigParams)
    +fromQRNumeric(qrNumericStrings string[]) Promise~SHC~
    +fromJWS(jws string) Promise~SHC~
  }

  class SHCReaderConfigParams {
    +publicKey string
    +enableQROptimization boolean
    +strictReferences boolean
    +verifyExpiration boolean
    +issuerDirectory Directory
    +useVciDirectory boolean
  }

  class Directory {
    -issuers Issuer[]
    +Directory(issuers Issuer[])
    +getIssuers() Issuer[]
    +getIssuerByIss(iss string) Issuer
    +fromVCI() Directory
  }

  class Issuer {
    +iss string
    +crls CRL[]
  }

  class CRL {
    +rids string[]
  }

  class VerifiableCredential {
    +vc VerifiableCredentialPayload
  }

  class VerifiableCredentialPayload {
    +rid string
    +credentialSubject CredentialSubject
  }

  class CredentialSubject {
    +fhirBundle FHIRBundle
  }

  class FHIRBundle {
  }

  class SHC {
    -jws string
    -originalBundle FHIRBundle
    +SHC(jws string, originalBundle FHIRBundle)
    +asJWS() string
    +asBundle() FHIRBundle
    +toQRCodes(config QRCodeConfigParams) Promise~string[]~
  }

  class SHCIssuer {
    -issuer string
    -privateKey string
    -publicKey string
    +SHCIssuer(config SHCIssuerConfig)
    +issue(fhirBundle FHIRBundle, config VerifiableCredentialParams) Promise~SHC~
  }

  class SHCError {
    +code string
    +message string
  }

  class SHCReaderConfigError {
    +SHCReaderConfigError(message string)
  }

  class SHCRevokedError {
    +SHCRevokedError(message string)
  }

  class CredentialValidationError {
    +CredentialValidationError(message string)
  }

  class QRCodeConfigParams {
  }

  class SHCIssuerConfig {
    +issuer string
    +privateKey string
    +publicKey string
  }

  class VerifiableCredentialParams {
  }

  SHCReader --> SHCReaderConfigParams
  SHCReader --> Directory : uses
  SHCReader --> VerifiableCredential : validates
  SHCReader --> SHC : returns

  Directory --> Issuer : contains
  Issuer --> CRL : has

  VerifiableCredential --> VerifiableCredentialPayload : vc
  VerifiableCredentialPayload --> CredentialSubject : credentialSubject
  CredentialSubject --> FHIRBundle : fhirBundle

  SHCIssuer --> SHCIssuerConfig
  SHCIssuer --> SHC : creates
  SHCIssuer --> VerifiableCredentialParams

  SHCError <|-- SHCReaderConfigError
  SHCError <|-- SHCRevokedError
  SHCError <|-- CredentialValidationError
Loading

File-Level Changes

Change Details Files
Add validation and new config option to SHCReader to control use of issuer directories and VCI snapshot, and enforce mutual exclusivity.
  • Add SHCReaderConfigError and use it in SHCReader constructor when both issuerDirectory and useVciDirectory are provided.
  • Extend SHCReaderConfigParams with useVciDirectory flag (default false) and persist it into SHCReader config.
  • Update SHCReader.fromJWS to optionally resolve a Directory from issuerDirectory or VCI snapshot before returning an SHC instance.
src/shc/reader.ts
src/shc/types.ts
src/shc/errors.ts
test/shc/shc.test.ts
Implement SHC revocation checks using CRLs from Directory entries and introduce an SHCRevokedError.
  • Update SHCReader.fromJWS to retrieve the issuer from Directory (by iss), read its CRLs, and compare the VC rid against CRL rids, throwing SHCRevokedError when revoked.
  • Extend VerifiableCredential type to optionally include rid used for revocation matching.
  • Add SHCRevokedError error subclass with SHC_REVOKED code.
src/shc/reader.ts
src/shc/types.ts
src/shc/errors.ts
Refine Directory API and usage by renaming internal issuer storage, exposing getIssuers/getIssuerByIss, and centralizing sample directory JSON for tests.
  • Change Directory constructor field name to issuers and replace getIssuerInfo with getIssuers plus new getIssuerByIss lookup helper.
  • Update README examples to use getIssuers instead of getIssuerInfo.
  • Move SAMPLE_DIRECTORY_JSON into shared test helpers and consume it from directory and SHC tests.
src/shc/directory.ts
test/shc/directory.test.ts
test/helpers.ts
README.md
test/shc/shc.test.ts
Simplify SHC/SHCIssuer to remove issuer metadata bundling into SHC instances.
  • Remove issuerInfo array from SHC state and delete getIssuerInfo accessor.
  • Update SHCIssuer.issue signature to stop accepting issuerInfo and construct SHC only with JWS and bundle.
  • Adjust tests that previously asserted issuerInfo bundling to new behavior focused on verification and revocation.
src/shc/shc.ts
src/shc/issuer.ts
test/shc/shc.test.ts
Expand tests to cover configuration validation, directory-based verification, and VCI snapshot usage.
  • Add test ensuring SHCReader throws SHCReaderConfigError when both issuerDirectory and useVciDirectory are set.
  • Add tests verifying SHC verification using a provided Directory (with JWKS/CRL mocks) and using the VCI snapshot directory (mocking vci_snapshot.json fetch).
  • Update directory tests to use SAMPLE_DIRECTORY_JSON and new getIssuers API.
  • Ensure mocks for global fetch are restored after tests.
test/shc/shc.test.ts
test/shc/directory.test.ts
test/helpers.ts

Possibly linked issues

  • #SHC revocation support: PR introduces revocation checks via CRLs, rid handling, and SHCRevokedError, fulfilling the SHC revocation support issue.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@vercel
Copy link

vercel bot commented Dec 13, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
medplum-shl Ready Ready Preview, Comment Dec 17, 2025 4:52pm

@github-actions
Copy link

github-actions bot commented Dec 13, 2025

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 96.04% 2065 / 2150
🔵 Statements 96.04% 2065 / 2150
🔵 Functions 98.57% 138 / 140
🔵 Branches 90.01% 649 / 721
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/shc/directory.ts 100% 88.63% 100% 100%
src/shc/errors.ts 100% 100% 100% 100%
src/shc/issuer.ts 100% 100% 100% 100%
src/shc/reader.ts 94.65% 81.15% 100% 94.65% 235-236, 238-239, 256-257, 287-288, 293-294
src/shc/shc.ts 100% 100% 100% 100%
src/shc/types.ts 0% 0% 0% 0%
src/shc/vc.ts 100% 97.05% 100% 100%
src/shc/jws/helpers.ts 100% 100% 100% 100%
src/shc/jws/index.ts 100% 100% 100% 100%
src/shc/jws/jws-processor.ts 93.33% 87.5% 100% 93.33% 232-233, 237-238, 252-257
Generated in workflow #117 for commit 7396728 by the Vitest Coverage Report Action

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • In SHCReader.fromJWS, consider caching the VCI directory when useVciDirectory is true instead of calling Directory.fromVCI() on every verification to avoid repeated network fetches and improve performance.
  • The revocation check in SHCReader.fromJWS uses issuerCrls.forEach and throws inside the callback; using some/find or an early-return loop would make the control flow clearer and avoid iterating after a revocation has already been detected.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `SHCReader.fromJWS`, consider caching the VCI directory when `useVciDirectory` is true instead of calling `Directory.fromVCI()` on every verification to avoid repeated network fetches and improve performance.
- The revocation check in `SHCReader.fromJWS` uses `issuerCrls.forEach` and throws inside the callback; using `some`/`find` or an early-return loop would make the control flow clearer and avoid iterating after a revocation has already been detected.

## Individual Comments

### Comment 1
<location> `src/shc/reader.ts:170-171` </location>
<code_context>
       if (this.config.issuerDirectory) {
-        issuerInfo = this.config.issuerDirectory.getIssuerInfo()
+        directory = this.config.issuerDirectory
+      } else if (this.config.useVciDirectory) {
+        directory = await Directory.fromVCI()
       }
-      return new SHC(jws, originalBundle, issuerInfo)
</code_context>

<issue_to_address>
**suggestion (performance):** Consider caching the VCI directory per reader instance instead of fetching on every read call.

With `useVciDirectory` enabled, each `read()` call re-runs `Directory.fromVCI()`. If this involves network I/O or heavy parsing, it will hurt throughput. Consider lazily initializing and caching the `Directory` on the `SHCReader` instance (e.g., `this.vciDirectory ??= await Directory.fromVCI()`) so it’s fetched once and reused across reads.

Suggested implementation:

```typescript
      let directory: Directory | null = null
      if (this.config.issuerDirectory) {
        directory = this.config.issuerDirectory
      } else if (this.config.useVciDirectory) {
        if (!this.vciDirectory) {
          this.vciDirectory = await Directory.fromVCI()
        }
        directory = this.vciDirectory
      }

```

To fully implement the caching behavior, the `SHCReader` class (or whatever class this method belongs to) should declare a cached directory field, for example:

- Add a private (or protected) field to the class:
```ts
private vciDirectory: Directory | null = null
```

Place this alongside the other instance fields in `src/shc/reader.ts`. Ensure the type and visibility modifiers match the existing code style (e.g., `private` vs `protected`, use of definite assignment, etc.).
</issue_to_address>

### Comment 2
<location> `src/shc/reader.ts:174-179` </location>
<code_context>
+        const vcRid = payload.vc.rid
+        if (issuerCrls && vcRid) {
+          // TODO: we must also handle the case where the SHC is set to be revoked
+          issuerCrls.forEach(crl => {
+            if (crl.rids.includes(vcRid)) {
+              throw new SHCRevokedError('This SHC has been revoked')
+            }
+          })
+        }
+      }
</code_context>

<issue_to_address>
**suggestion:** Use a more intention-revealing pattern than `forEach` with an internal `throw` when checking CRLs.

This works but makes the control flow less clear, since `forEach` doesn’t short‑circuit. Consider using an existence check instead, e.g. `if (issuerCrls.some(crl => crl.rids.includes(vcRid))) { throw new SHCRevokedError('This SHC has been revoked') }`, which better communicates intent and doesn’t rely on `throw` to end iteration.

```suggestion
      if (directory) {
        const issuer = directory.getIssuerByIss(payload.iss)
        const issuerCrls = issuer?.crls
        const vcRid = payload.vc.rid
        if (issuerCrls && vcRid) {
          // TODO: we must also handle the case where the SHC is set to be revoked
          const isRevoked = issuerCrls.some(crl => crl.rids.includes(vcRid))

          if (isRevoked) {
            throw new SHCRevokedError('This SHC has been revoked')
          }
```
</issue_to_address>

### Comment 3
<location> `test/shc/shc.test.ts:169-166` </location>
<code_context>
+    it('should verify SHC when reader created with a directory', async () => {
</code_context>

<issue_to_address>
**issue (testing):** Add tests covering SHCRevokedError when an SHC rid is present in the issuer CRL.

This only exercises the non‑revoked path with an `issuerDirectory`. Please also add tests that issue an SHC with a known `rid`, build a `Directory` whose CRL includes that `rid`, and assert that `readerWithDirectory.fromJWS(...)` rejects with `SHCRevokedError`. Cover both cases: (1) `issuerDirectory` passed directly and (2) `useVciDirectory: true` with a mocked VCI snapshot whose CRL marks the SHC as revoked, so we verify revocation is enforced in all flows.
</issue_to_address>

### Comment 4
<location> `test/shc/shc.test.ts:219-166` </location>
<code_context>
+    it('should verify SHC when reader is created with the VCI snapshot directory', async () => {
</code_context>

<issue_to_address>
**suggestion (testing):** Cover edge cases for VCI directory usage: issuer not found and SHC without `rid`.

This test only covers the happy path. Please also add cases for:

- An issuer missing from the VCI snapshot (no entry for `payload.iss`), asserting the intended behavior when directory metadata is absent.
- An SHC whose VC payload omits `rid`, asserting that verification succeeds without attempting revocation checks.

These will validate revocation behavior when directory data is incomplete or `rid` is missing.

Suggested implementation:

```typescript
      expect(verifiedBundle).toBeDefined()
      expect(verifiedBundle).toEqual(validBundle)
    })

    it('should verify SHC when reader is created with the VCI snapshot directory when issuer is missing from VCI snapshot', async () => {
      const healthCard = await issuer.issue(validBundle)
      const readerWithDirectory = new SHCReader({
        ...readerConfig,
        useVciDirectory: true,
      })

      const originalFetch = globalThis.fetch
      const fetchMock = vi.fn().mockImplementation((url: string) => {
        if (url.includes('vci_snapshot.json')) {
          // VCI snapshot without an entry for the issuer in payload.iss
          return Promise.resolve({
            ok: true,
            json: async () =>
              ({
                issuers: [],
              }) as unknown,
          } as Response)
        }

        // Defer all other requests to the original implementation
        return originalFetch(url)
      })

      globalThis.fetch = fetchMock as unknown as typeof fetch

      const verifiedHealthCard = await readerWithDirectory.fromJWS(healthCard.asJWS())
      const verifiedBundle = await verifiedHealthCard.asBundle()

      expect(verifiedBundle).toBeDefined()
      expect(verifiedBundle).toEqual(validBundle)

      globalThis.fetch = originalFetch
    })

    it('should verify SHC when VC payload omits rid using the VCI snapshot directory', async () => {
      const bundleWithoutRid = structuredClone(validBundle)

      // Remove rid from the VC payload; adjust the path to match the actual schema.
      // This example assumes rid is stored on the first entry's resource.identifier[0].value.
      if (
        bundleWithoutRid.entry?.[0]?.resource?.identifier &&
        Array.isArray(bundleWithoutRid.entry[0].resource.identifier)
      ) {
        delete bundleWithoutRid.entry[0].resource.identifier[0].value
      }

      const healthCard = await issuer.issue(bundleWithoutRid)
      const readerWithDirectory = new SHCReader({
        ...readerConfig,
        useVciDirectory: true,
      })

      const originalFetch = globalThis.fetch
      const fetchMock = vi.fn().mockImplementation((url: string) => {
        if (url.includes('vci_snapshot.json')) {
          // Minimal VCI snapshot; structure should match what the reader expects.
          return Promise.resolve({
            ok: true,
            json: async () =>
              ({
                issuers: [
                  // Add an entry if required by the reader implementation.
                  // The important part for this test is that rid is absent from the VC payload,
                  // so no revocation check is attempted.
                ],
              }) as unknown,
          } as Response)
        }

        return originalFetch(url)
      })

      globalThis.fetch = fetchMock as unknown as typeof fetch

      const verifiedHealthCard = await readerWithDirectory.fromJWS(healthCard.asJWS())
      const verifiedBundle = await verifiedHealthCard.asBundle()

      expect(verifiedBundle).toBeDefined()
      expect(verifiedBundle).toEqual(bundleWithoutRid)

      globalThis.fetch = originalFetch
    })

    it('should verify SHC when reader is created with the VCI snapshot directory', async () => {

```

1. **Confirm the rid location in the bundle**:  
   The example removes `rid` from `bundleWithoutRid.entry[0].resource.identifier[0].value`. If your schema stores `rid` elsewhere (e.g., a top-level VC claim or a different resource path), update the deletion logic to match the actual location used in your SHC/VC model so that the issued JWS truly omits `rid`.

2. **Align VCI snapshot structure with the production shape**:  
   The mocked responses for `vci_snapshot.json` return `{ issuers: [...] }` as a minimal shape. Adjust the structure and inner fields (e.g., `iss`, `name`, `status`, `revocation` metadata) to mirror the real snapshot format expected by `SHCReader` (you can copy this from the existing “happy path” VCI test or a shared fixture).

3. **Optionally assert revocation behavior more directly**:  
   If `SHCReader` hits a revocation endpoint (or calls a specific helper) when `rid` is present and issuer metadata exists, you can extend the tests to spy on that call and assert that it is **not** invoked in these two new scenarios. That will more explicitly validate “no revocation checks when issuer metadata is missing or rid is absent” instead of inferring it only from overall verification success.
</issue_to_address>

### Comment 5
<location> `test/shc/directory.test.ts:6-7` </location>
<code_context>
-}
+import { SAMPLE_DIRECTORY_JSON } from '../helpers'

 function assertDirectoryFromSampleJson(directory: Directory) {
-  const issuers = directory.getIssuerInfo()
+  const issuers = directory.getIssuers()
   expect(issuers).toHaveLength(4)

</code_context>

<issue_to_address>
**suggestion (testing):** Add tests for the new `Directory.getIssuerByIss` helper.

`getIssuerByIss` isn’t covered by tests yet, even though `SHCReader` now depends on it for revocation checks. Please add unit tests that:

- Call `getIssuerByIss` with an `iss` present in `SAMPLE_DIRECTORY_JSON` and assert the matching issuer is returned.
- Call it with an unknown `iss` and assert it returns `undefined`.

This keeps the directory lookup logic validated independently of the reader tests.

Suggested implementation:

```typescript
import { SAMPLE_DIRECTORY_JSON } from '../helpers'
import { Directory } from '../../src/shc/directory'

describe('Directory', () => {
  function createDirectoryFromSampleJson(): Directory {
    // Adjust this factory if Directory is constructed differently in your codebase
    return Directory.fromJson(SAMPLE_DIRECTORY_JSON)
  }

  describe('getIssuerByIss', () => {
    it('returns the matching issuer when iss exists in the directory', () => {
      const directory = createDirectoryFromSampleJson()
      const knownIss = SAMPLE_DIRECTORY_JSON.issuers[0].iss

      const issuer = directory.getIssuerByIss(knownIss)

      expect(issuer).toBeDefined()
      expect(issuer?.iss).toBe(knownIss)
    })

    it('returns undefined when iss is not found in the directory', () => {
      const directory = createDirectoryFromSampleJson()

      const issuer = directory.getIssuerByIss('https://unknown-issuer.example.org')

      expect(issuer).toBeUndefined()
    })
  })
})

```

You may need to make a few adjustments depending on the existing codebase:

1. **Directory import path/name**  
   - Update `import { Directory } from '../../src/shc/directory'` to match the actual location and export name of your `Directory` class (e.g. `../src/shc/Directory` or a different relative path/casing).

2. **Directory construction API**  
   - If `Directory` does not provide a `fromJson` static method, replace `Directory.fromJson(SAMPLE_DIRECTORY_JSON)` with the correct construction logic, such as:
     - `new Directory(SAMPLE_DIRECTORY_JSON)` or
     - a different factory/helper already used elsewhere in your tests.

3. **Sample JSON shape**  
   - This assumes `SAMPLE_DIRECTORY_JSON.issuers` is an array of issuers with an `iss` field. If the structure differs, adjust the access in `knownIss` and the assertion `issuer?.iss` to match the actual type (e.g. `SAMPLE_DIRECTORY_JSON[0].issuer.iss`).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@rvlb
Copy link
Contributor Author

rvlb commented Dec 16, 2025

Latest batch of changes:

  • Updated README.md to improve the explanation on how to use the directories
  • Reworked the Directory class API to improve performance when accessing the keys and CRLs data (changed from Arrays into Maps and Sets)
  • Added a way to issue the SHC providing a rid value to the VC object
  • Added the revocation check flow in the SHCReader.fromJWS method
  • Fixed the directory usage at SHCReader.fromJWS and made it use the directory public keys when available (previously it was ignoring that and always relying on JWKS API calls)
  • Reworked the existing tests to properly test the scenarios where directories are used
  • Added tests for the revocation flow
  • Refactored some helper functions to improve code reusability

@rvlb rvlb requested a review from fjsj December 16, 2025 14:10
Copy link
Member

@fjsj fjsj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM, check minor comments

Copy link
Member

@fjsj fjsj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@rvlb rvlb merged commit 01b0995 into main Dec 17, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SHC VCI Directory support SHC revocation support

3 participants