Skip to content

feat: Add TPM licensing availability to registration#1908

Merged
elibosley merged 9 commits intomainfrom
codex/tpm-registration-availability
Mar 13, 2026
Merged

feat: Add TPM licensing availability to registration#1908
elibosley merged 9 commits intomainfrom
codex/tpm-registration-availability

Conversation

@elibosley
Copy link
Member

@elibosley elibosley commented Mar 13, 2026

Summary

  • expose tpmGuid through the vars API/schema and thread it through the registration page state
  • show TPM licensing availability guidance on Tools > Registration when a TPM GUID is present and differs from the flash GUID
  • update mock vars/state fixtures so TPM data is available in local testing paths and unit tests

Testing

  • pnpm --filter @unraid/api codegen
  • pnpm --filter @unraid/web codegen
  • pnpm type-check (api)
  • pnpm type-check (web)
  • pnpm test --run src/test/store/state-parsers/var.test.ts src/test/store/modules/emhttp.test.ts

Summary by CodeRabbit

  • New Features

    • TPM license transfer guidance, step-by-step flow and readiness UI added to Registration.
    • Server state now exposes TPM and flash device identifiers and an additional md state for richer UI context.
  • Documentation

    • English locale strings added/updated for TPM transfer workflow and license device labels.
  • Tests

    • Added tests for TPM transfer visibility and readiness across registration scenarios.
  • Bug Fix / UX

    • Callback modal now triggers a page reload when dismissing after a successful callback.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 13, 2026

Walkthrough

Surfaces TPM GUID (tpmGuid) and flash GUID (flashGuid) from INI through API, GraphQL, store, and frontend; adds TPM transfer UI, localization, and test updates to handle the new fields.

Changes

Cohort / File(s) Summary
Config
api/dev/states/var.ini
Added tpmGUID key to the INI state file.
GraphQL schema
api/generated-schema.graphql
Added tpmGuid: String to Vars type.
API types & resolvers
api/src/core/types/states/var.ts, api/src/store/state-parsers/var.ts, api/src/unraid-api/graph/resolvers/vars/vars.model.ts
Introduced optional tpmGuid on Var/VarIni and GraphQL model (@Field({ nullable: true })).
API tests
api/src/__test__/store/modules/emhttp.test.ts, api/src/__test__/store/state-parsers/var.test.ts, api/src/store/services/__test__/state-file-loader.test.ts
Updated fixtures and assertions to include and validate tpmGuid parsing and dispatched payloads.
Web data & store
web/src/_data/serverState.ts, web/src/store/server.ts, web/types/server.ts, web/src/store/server.fragment.ts
Added flashGuid, tpmGuid, and mdState to server data shapes, store state, payloads, and TypeScript Server interface; fragment updated.
Web GraphQL bindings
web/src/composables/gql/gql.ts, web/src/composables/gql/graphql.ts
Expanded serverState query and generated types/overloads to include flashGuid, tpmGuid, and mdState.
Web UI & tests
web/src/components/Registration.standalone.vue, web/__test__/components/Registration.test.ts
Added TPM transfer UI blocks, computed guards, and extensive tests exercising TPM-guided flows based on tpmGuid/flashGuid/mdState.
Web templates & locales
web/_webGui/testWebComponents.page, web/src/locales/en.json
Added flashGuid/tpmGuid to test payload and English localization strings for TPM transfer steps and descriptions.
Misc UI changes
web/src/components/UserProfile/CallbackFeedback.vue, web/__test__/components/CallbackFeedback.test.ts
Added optional reload behavior on callback close and tests to assert page reload and callback status reset.

Sequence Diagram(s)

sequenceDiagram
  participant UI as Web UI (Registration)
  participant Store as Client Store
  participant GQL as GraphQL Client
  participant API as Server GraphQL
  participant FS as Config / INI Parser

  UI->>Store: read flashGuid, tpmGuid, mdState
  Store->>GQL: serverState query (include vars: flashGuid, tpmGuid, mdState)
  GQL->>API: GraphQL request
  API->>FS: read `var.ini` (flashGUID, tpmGUID)
  FS-->>API: return vars with flashGUID/tpmGUID
  API-->>GQL: response with vars
  GQL-->>Store: update server state
  Store-->>UI: re-render Registration UI (show/hide TPM transfer blocks)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A hop, a nibble, GUIDs in tow,
From INI burrow into the show,
Flash and TPM dance through the stack,
Tests cheer, UI paints the track,
Rabbity hops — transfer's a go! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Add TPM licensing availability to registration' directly and clearly summarizes the main changes across the PR: exposing tpmGuid through the API/schema and displaying TPM licensing guidance on the registration page when available.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/tpm-registration-availability
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Mar 13, 2026

Codecov Report

❌ Patch coverage is 93.71429% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.96%. Comparing base (23f7836) to head (70c5101).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
web/src/store/server.ts 59.09% 9 Missing ⚠️
.../src/unraid-api/graph/resolvers/vars/vars.model.ts 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1908      +/-   ##
==========================================
+ Coverage   50.81%   50.96%   +0.14%     
==========================================
  Files        1023     1023              
  Lines       70545    70701     +156     
  Branches     7652     7699      +47     
==========================================
+ Hits        35848    36031     +183     
+ Misses      34573    34546      -27     
  Partials      124      124              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 78c4b927b4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +139 to +143
keyInstalled.value &&
bootDeviceType.value === 'flash' &&
flashGuid.value &&
tpmGuid.value &&
flashGuid.value !== tpmGuid.value

Choose a reason for hiding this comment

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

P2 Badge Gate TPM transfer notice to non-trial license states

This condition allows the TPM transfer guidance to render for TRIAL/EEXPIRED servers whenever both GUIDs are present, because keyInstalled only excludes ENOKEYFILE. In those states there is no transferable paid key, so the UI can instruct users to "move this license" when no such transfer is valid. Since showTrialExpiration is already used elsewhere to suppress transfer actions, this notice should be similarly gated to avoid misleading trial/expired users.

Useful? React with 👍 / 👎.

@elibosley elibosley changed the title Add TPM licensing availability to registration feat: Add TPM licensing availability to registration Mar 13, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
web/src/store/server.ts (1)

268-299: Add flashGuid to serverDebugPayload for parity with tpmGuid.

Line 295 includes tpmGuid, but flashGuid is also part of the new TPM-transfer decision path and is useful in diagnostics.

♻️ Suggested small parity update
   const serverDebugPayload = computed((): Server => {
     const payload = {
       apiVersion: apiVersion.value,
       avatar: avatar.value,
       connectPluginInstalled: connectPluginInstalled.value,
       connectPluginVersion: connectPluginVersion.value,
       description: description.value,
       deviceCount: deviceCount.value,
       email: email.value,
       expireTime: expireTime.value,
+      flashGuid: flashGuid.value,
       flashProduct: flashProduct.value,
       flashVendor: flashVendor.value,
       guid: guid.value,
       inIframe: inIframe.value,
       lanIp: lanIp.value,
       locale: locale.value,
       name: name.value,
       osVersion: osVersion.value,
       osVersionBranch: osVersionBranch.value,
       rebootType: rebootType.value,
       rebootVersion: rebootVersion.value,
       registered: registered.value,
       regGen: regGen.value,
       regGuid: regGuid.value,
       regTy: regTy.value,
       site: site.value,
       state: state.value,
       tpmGuid: tpmGuid.value,
       uptime: uptime.value,
       username: username.value,
       wanFQDN: wanFQDN.value,
     };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/store/server.ts` around lines 268 - 299, The serverDebugPayload
computed getter is missing flashGuid; add flashGuid: flashGuid.value to the
payload alongside the existing tpmGuid entry so diagnostics include the flash
GUID; update the payload object inside the serverDebugPayload computed function
(the same block that currently lists tpmGuid: tpmGuid.value) to include
flashGuid using the flashGuid reactive reference.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/_webGui/testWebComponents.page`:
- Line 93: The mapping for "flashGuid" reads $var['flashGUID'] directly and can
emit undefined-index notices; change the right-hand side to use a guarded
fallback (e.g. use isset($var['flashGUID']) ? $var['flashGUID'] : '' or the
null-coalescing operator $var['flashGUID'] ?? '') so "flashGuid" always gets a
defined value when $var lacks 'flashGUID'.

---

Nitpick comments:
In `@web/src/store/server.ts`:
- Around line 268-299: The serverDebugPayload computed getter is missing
flashGuid; add flashGuid: flashGuid.value to the payload alongside the existing
tpmGuid entry so diagnostics include the flash GUID; update the payload object
inside the serverDebugPayload computed function (the same block that currently
lists tpmGuid: tpmGuid.value) to include flashGuid using the flashGuid reactive
reference.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7285b2b0-0b11-48ae-999d-583eb7baa987

📥 Commits

Reviewing files that changed from the base of the PR and between 23f7836 and b7e2628.

⛔ Files ignored due to path filters (1)
  • api/src/unraid-api/cli/generated/graphql.ts is excluded by !**/generated/**
📒 Files selected for processing (18)
  • api/dev/states/var.ini
  • api/generated-schema.graphql
  • api/src/__test__/store/modules/emhttp.test.ts
  • api/src/__test__/store/state-parsers/var.test.ts
  • api/src/core/types/states/var.ts
  • api/src/store/services/__test__/state-file-loader.test.ts
  • api/src/store/state-parsers/var.ts
  • api/src/unraid-api/graph/resolvers/vars/vars.model.ts
  • web/__test__/components/Registration.test.ts
  • web/_webGui/testWebComponents.page
  • web/src/_data/serverState.ts
  • web/src/components/Registration.standalone.vue
  • web/src/composables/gql/gql.ts
  • web/src/composables/gql/graphql.ts
  • web/src/locales/en.json
  • web/src/store/server.fragment.ts
  • web/src/store/server.ts
  • web/types/server.ts

"flashProduct" => $var['flashProduct'],
"flashVendor" => $var['flashVendor'],
"flashBackupActivated" => empty($flashbackup_status['activated']) ? '' : 'true',
"flashGuid" => $var['flashGUID'],
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add a fallback for flashGuid to avoid undefined-index notices.

Line [93] directly reads $var['flashGUID'] without guarding. If the key is absent, PHP notices can leak into this test page output.

Suggested fix
-  "flashGuid" => $var['flashGUID'],
+  "flashGuid" => $var['flashGUID'] ?? '',
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"flashGuid" => $var['flashGUID'],
"flashGuid" => $var['flashGUID'] ?? '',
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/_webGui/testWebComponents.page` at line 93, The mapping for "flashGuid"
reads $var['flashGUID'] directly and can emit undefined-index notices; change
the right-hand side to use a guarded fallback (e.g. use isset($var['flashGUID'])
? $var['flashGUID'] : '' or the null-coalescing operator $var['flashGUID'] ??
'') so "flashGuid" always gets a defined value when $var lacks 'flashGUID'.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
web/__test__/components/Registration.test.ts (2)

305-343: Reduce brittleness from hardcoded copy assertions.

These assertions are heavily tied to exact English phrasing. Prefer i18n-key-driven assertions (and structure checks like step count) so copy edits don’t fail behavior tests.

As per coding guidelines: "Test component behavior and output, not implementation details."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/__test__/components/Registration.test.ts` around lines 305 - 343, The
tests in Registration.test.ts are brittle because they assert exact English
strings; update the three TPM-transfer tests (those manipulating serverStore and
querying wrapper.find('[data-testid="tpm-transfer-available"]' /
'[data-testid="tpm-transfer-ready"]')) to assert behavior via i18n keys and
structure instead: replace expect(...text()).toContain('literal copy') with
checks that the element contains the translated text by calling the component's
$t key (or verifying a data-i18n attribute or the key prop used for each line),
assert the presence/absence of specific step elements (e.g. step rows, checkmark
icons, count of steps) rather than matching full sentences, and keep the minimal
existence checks like expect(...exists()).toBe(true/false); reference wrapper,
transferNotice, serverStore.guid/tpmGuid/regGuid and data-testid selectors to
locate the changed assertions.

294-330: Make TPM preconditions explicit in tests.

These cases depend on boot mode, but bootDeviceType is not set in the scenario setup. Setting it explicitly will make the tests deterministic and less coupled to store defaults.

Suggested patch
   it('shows TPM transfer guidance when TPM licensing is available', async () => {
     serverStore.state = 'PRO';
+    serverStore.bootDeviceType = 'flash';
     serverStore.guid = '058F-6387-0000-0000F1F1E1C6';
     serverStore.flashGuid = '058F-6387-0000-0000F1F1E1C6';
     serverStore.tpmGuid = '03-V35H8S0L1QHK1SBG1XHXJNH7';
     serverStore.keyfile = 'keyfile-present';
@@
   it('shows checked TPM transfer steps after switching to TPM boot', async () => {
     serverStore.state = 'EGUID';
+    serverStore.bootDeviceType = 'tpm';
     serverStore.guid = '03-V35H8S0L1QHK1SBG1XHXJNH7';
     serverStore.tpmGuid = '03-V35H8S0L1QHK1SBG1XHXJNH7';
     serverStore.regGuid = '058F-6387-0000-0000F1F1E1C6';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/__test__/components/Registration.test.ts` around lines 294 - 330, The
tests rely on boot mode but never set serverStore.bootDeviceType, making results
dependent on store defaults; update each affected test (e.g., the cases
manipulating serverStore.state/guid/flashGuid/tpmGuid/regGuid in
Registration.test.ts) to explicitly set serverStore.bootDeviceType to the
expected value for that scenario (for example 'USB' for USB-boot scenarios and
'TPM' or 'TPM_LEGACY' for TPM-boot scenarios) before awaiting
wrapper.vm.$nextTick() so the assertions around
wrapper.find('[data-testid="tpm-transfer-available"]') and checked TPM transfer
steps are deterministic. Ensure you set it in the three blocks shown (PRO case,
TRIAL case, and EGUID case) to match the intended preconditions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@web/__test__/components/Registration.test.ts`:
- Around line 305-343: The tests in Registration.test.ts are brittle because
they assert exact English strings; update the three TPM-transfer tests (those
manipulating serverStore and querying
wrapper.find('[data-testid="tpm-transfer-available"]' /
'[data-testid="tpm-transfer-ready"]')) to assert behavior via i18n keys and
structure instead: replace expect(...text()).toContain('literal copy') with
checks that the element contains the translated text by calling the component's
$t key (or verifying a data-i18n attribute or the key prop used for each line),
assert the presence/absence of specific step elements (e.g. step rows, checkmark
icons, count of steps) rather than matching full sentences, and keep the minimal
existence checks like expect(...exists()).toBe(true/false); reference wrapper,
transferNotice, serverStore.guid/tpmGuid/regGuid and data-testid selectors to
locate the changed assertions.
- Around line 294-330: The tests rely on boot mode but never set
serverStore.bootDeviceType, making results dependent on store defaults; update
each affected test (e.g., the cases manipulating
serverStore.state/guid/flashGuid/tpmGuid/regGuid in Registration.test.ts) to
explicitly set serverStore.bootDeviceType to the expected value for that
scenario (for example 'USB' for USB-boot scenarios and 'TPM' or 'TPM_LEGACY' for
TPM-boot scenarios) before awaiting wrapper.vm.$nextTick() so the assertions
around wrapper.find('[data-testid="tpm-transfer-available"]') and checked TPM
transfer steps are deterministic. Ensure you set it in the three blocks shown
(PRO case, TRIAL case, and EGUID case) to match the intended preconditions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9c51e308-8b64-4d95-90e8-c994ef83ccce

📥 Commits

Reviewing files that changed from the base of the PR and between b7e2628 and 7abf943.

📒 Files selected for processing (3)
  • web/__test__/components/Registration.test.ts
  • web/src/components/Registration.standalone.vue
  • web/src/locales/en.json

@coderabbitai coderabbitai bot requested a review from pujitm March 13, 2026 18:14
@github-actions
Copy link
Contributor

This plugin has been deployed to Cloudflare R2 and is available for testing.
Download it at this URL:

https://preview.dl.unraid.net/unraid-api/tag/PR1908/dynamix.unraid.net.plg

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
web/__test__/components/CallbackFeedback.test.ts (1)

313-336: Well-structured test for the reload behavior.

The test correctly:

  1. Mocks window.location.reload
  2. Sets up success state conditions
  3. Triggers the Modal's close event
  4. Verifies both the callback status reset and the reload invocation

One minor suggestion: consider importing nextTick from vue and using await nextTick() instead of wrapper.vm.$nextTick() for consistency with the coding guidelines pattern.

♻️ Optional: Use imported nextTick
+import { nextTick, ref } from 'vue';
-import { ref } from 'vue';
...
     wrapper.findComponent({ name: 'Modal' }).vm.$emit('close');
-    await wrapper.vm.$nextTick();
+    await nextTick();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/__test__/components/CallbackFeedback.test.ts` around lines 313 - 336,
Replace the instance call to wrapper.vm.$nextTick() with the imported nextTick()
utility: import { nextTick } from 'vue' at the top of the test file (if not
already present) and change the await wrapper.vm.$nextTick(); line in the
'reloads the page when the modal is dismissed after a callback action' test to
await nextTick(); to match project conventions (referencing the test function
and wrapper usage around the Modal close emit).
web/src/store/server.ts (1)

270-306: Consider adding flashGuid and mdState to serverDebugPayload for consistency.

The debug payload includes tpmGuid but omits flashGuid and mdState. If these fields are useful for debugging TPM transfer issues, consider including them here as well.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/store/server.ts` around lines 270 - 306, The serverDebugPayload
computed currently builds payload without flashGuid or mdState; update the
payload object inside the serverDebugPayload computed to include flashGuid:
flashGuid.value and mdState: mdState.value (keeping the existing
Object.fromEntries filter logic so empty/null/undefined values are still
removed) so these fields are present in the debug output alongside tpmGuid and
other properties.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@web/__test__/components/CallbackFeedback.test.ts`:
- Around line 313-336: Replace the instance call to wrapper.vm.$nextTick() with
the imported nextTick() utility: import { nextTick } from 'vue' at the top of
the test file (if not already present) and change the await
wrapper.vm.$nextTick(); line in the 'reloads the page when the modal is
dismissed after a callback action' test to await nextTick(); to match project
conventions (referencing the test function and wrapper usage around the Modal
close emit).

In `@web/src/store/server.ts`:
- Around line 270-306: The serverDebugPayload computed currently builds payload
without flashGuid or mdState; update the payload object inside the
serverDebugPayload computed to include flashGuid: flashGuid.value and mdState:
mdState.value (keeping the existing Object.fromEntries filter logic so
empty/null/undefined values are still removed) so these fields are present in
the debug output alongside tpmGuid and other properties.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a28dceaa-a045-4017-857c-73ae77b18db5

📥 Commits

Reviewing files that changed from the base of the PR and between 7abf943 and 70c5101.

📒 Files selected for processing (10)
  • web/__test__/components/CallbackFeedback.test.ts
  • web/__test__/components/Registration.test.ts
  • web/src/components/Registration.standalone.vue
  • web/src/components/UserProfile/CallbackFeedback.vue
  • web/src/composables/gql/gql.ts
  • web/src/composables/gql/graphql.ts
  • web/src/locales/en.json
  • web/src/store/server.fragment.ts
  • web/src/store/server.ts
  • web/types/server.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • web/types/server.ts
  • web/src/locales/en.json
  • web/src/composables/gql/graphql.ts

@elibosley elibosley merged commit aa162eb into main Mar 13, 2026
13 checks passed
@elibosley elibosley deleted the codex/tpm-registration-availability branch March 13, 2026 19:00
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.

1 participant