Skip to content

feat(devices): add remote platform erase support - #846

Open
nmgaston wants to merge 26 commits into
mainfrom
remotePlatformErase
Open

feat(devices): add remote platform erase support#846
nmgaston wants to merge 26 commits into
mainfrom
remotePlatformErase

Conversation

@nmgaston

@nmgaston nmgaston commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

feat(devices): add remote platform erase support

NOTE: Requires real AMT 16.0+ hardware with RPE BIOS support for end-to-end testing.

Related PRs

Summary

This PR adds support for Intel Remote Platform Erase (RPE), a CSME 16.0+ feature that allows remote administrators to securely erase supported platform storage components on the next boot.

The implementation adds new API endpoints, updates feature handling to track RPE state and support, and adds the WS-Man logic needed to trigger erase operations safely.

What’s new

New API endpoints

Method Path Description
GET /api/v1/amt/boot/remoteErase/:guid Returns supported remote erase capabilities for the device
POST /api/v1/amt/boot/remoteErase/:guid Triggers remote platform erase using the requested options

New DTO fields

The feature and request payloads now use rpe terminology instead of the older remoteErase field.

Added/updated fields:

  • rpe: whether RPE is currently enabled
  • rpeSupported: whether the device BIOS supports RPE

RPE execution flow

The backend now performs the RPE setup in a firmware-safe sequence:

  1. Reset the boot service to the idle state
  2. Try to latch PlatformErase=true
  3. Read boot settings and verify RPE is enabled
  4. Switch the boot service into RPE mode
  5. Update boot settings with the selected erase options
  6. Activate the boot configuration
  7. Power cycle the system so erase runs on next boot

TLV encoding

When hardware erase targets are selected, the request bitmask is encoded into a single TLV entry and base64-encoded into UefiBootParametersArray.

Boot state handling

SetFeatures now understands both OCR and RPE and computes the correct boot-service state for:

  • OCR disabled / RPE disabled
  • OCR enabled / RPE disabled
  • OCR disabled / RPE enabled
  • OCR enabled / RPE enabled

RPE is configured before the boot-service state change to avoid firmware blocking the erase update.

Implementation updates

HTTP / OpenAPI

  • Added new Gin handlers for remote erase
  • Added OpenAPI/Fuego route registration for the new endpoints
  • Added controller tests for request/response behavior
  • Added Postman integration coverage

Device feature logic

  • Extended feature retrieval to expose RPE state and BIOS support
  • Updated feature setting logic to preserve both OCR and RPE state correctly
  • Added support for RPE capability detection from AMT boot capabilities

WS-Man support

  • Added the WS-Man call needed to execute remote erase
  • Added TLV construction for hardware erase targets
  • Added power-state selection logic to use:
    • PowerOn if the device is currently off
    • PowerCycleOffHard otherwise

Refactoring / cleanup

  • Split device-management route registration into smaller grouped helpers
  • Updated redirection setup to accept context.Context
  • Removed obsolete websocket interface code
  • Updated mocks and tests to match the new interfaces

Testing

  • Unit tests added for:
    • remote erase capability lookup
    • remote erase execution
    • TLV encoding
    • RPE/OCR boot-state selection
  • Existing feature tests updated for RPE state handling
  • Controller and OpenAPI tests added for the new routes
  • Verified on real AMT 18.1 hardware

Notes

  • 0x10000 is used as a UI-level sentinel for Unconfigure Intel CSME Firmware. It is not sent as a TLV target bit.
  • UefiBootParametersArray must be present when PlatformErase=true.
  • PowerCycleOffHard is required for erase execution; warm reset does not fully power-cycle the platform.
  • Devices without RPE support return a validation error instead of attempting the operation.

@nmgaston
nmgaston force-pushed the remotePlatformErase branch 3 times, most recently from ab3a5ce to 2a3c9f3 Compare March 18, 2026 01:13
@codecov

codecov Bot commented Mar 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.87786% with 37 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.72%. Comparing base (861e864) to head (0258052).

Files with missing lines Patch % Lines
internal/mocks/devicemanagement_mocks.go 0.00% 21 Missing ⚠️
internal/mocks/wsman_mocks.go 0.00% 8 Missing ⚠️
internal/controller/openapi/devicemanagement.go 77.77% 4 Missing ⚠️
internal/usecase/devices/features.go 95.06% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #846      +/-   ##
==========================================
+ Coverage   44.45%   49.72%   +5.27%     
==========================================
  Files         144      146       +2     
  Lines       13732    13455     -277     
==========================================
+ Hits         6105     6691     +586     
+ Misses       7054     6184     -870     
- Partials      573      580       +7     

☔ View full report in Codecov by Harness.
📢 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.

@nmgaston
nmgaston force-pushed the remotePlatformErase branch 6 times, most recently from 9963ea5 to 3fb92dc Compare March 23, 2026 22:20
Comment thread cmd/amt-stub/main.go Fixed
@nmgaston
nmgaston force-pushed the remotePlatformErase branch 2 times, most recently from c155e51 to a51bd01 Compare March 25, 2026 17:29
@nmgaston
nmgaston force-pushed the remotePlatformErase branch 3 times, most recently from 89a3df2 to ed07d81 Compare April 10, 2026 04:02
@nmgaston nmgaston linked an issue Apr 16, 2026 that may be closed by this pull request
7 tasks
@nmgaston
nmgaston force-pushed the remotePlatformErase branch 7 times, most recently from 8cb8e8b to 77d98d8 Compare April 22, 2026 01:02
@nmgaston
nmgaston marked this pull request as ready for review April 22, 2026 01:10
@nmgaston
nmgaston requested a review from rsdmike April 22, 2026 01:11
@nmgaston
nmgaston force-pushed the remotePlatformErase branch from 0b5764e to fe982f3 Compare April 22, 2026 20:20

@rsdmike rsdmike left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @nmgaston for doing this. @graikhel-intel and i have taken some time to think through and go through this. Here is our feedback:

  1. Simplify AMT features request/response to just include rpeSupported and rpe:
{
    "redirection": true,
    "KVM": true,
    "SOL": true,
    "IDER": true,
    "optInState": 0,
    "userConsent": "none",
    "kvmAvailable": true,
    "ocr": false,
    "httpsBootSupported": true,
    "winREBootSupported": true,
    "localPBABootSupported": true,
    "rpe": true,
    "rpeSupported": true,
<remove>
    "rpeCaps": 100728925,
    "rpeSecureErase": true,
    "rpeTPMClear": true,
    "rpeClearBIOSNVM": true,
    "rpeBIOSReload": true
</remove>
}

Once this is done, can update the UI on the General AMT Info screen change RPE into a checkbox which will enable/disable rpe and grey it out/disable if rpe is not supported.

  1. Currently you have GET: boot/capabilities/:guid (where is this used?) , POST: boot/rpe/:guid, and POST: remoteErase/:guid endpoints added. Consolidate this to GET boot/remoteErase/:guid -- which will fetch the supported capabilities
    and POST boot/remoteErase/:guid which will perform the desired action
 {
  "secureEraseAllSSDs": true,
  "tpmClear": true,
  "restoreBIOSToEOM": true,
  "unconfigureCSME": true
}

Note important removal of any mask representation of features. This will mean the UI needs to be updated with the new payload.

@nmgaston
nmgaston force-pushed the remotePlatformErase branch 2 times, most recently from 13fe475 to 25c62da Compare June 30, 2026 05:19
@nmgaston
nmgaston requested review from DevipriyaS17 and nbmaiti July 13, 2026 19:25
@nmgaston
nmgaston force-pushed the remotePlatformErase branch 2 times, most recently from 2cf841c to f49203a Compare July 15, 2026 01:49
Comment thread internal/controller/ws/v1/interface.go Outdated
Comment thread internal/controller/openapi/devicemanagement.go Outdated
Comment thread internal/usecase/devices/features.go
Comment thread internal/usecase/devices/features.go Outdated
@madhavilosetty-intel

Copy link
Copy Markdown
Contributor

Postman collections not updated — CLAUDE.md requires Gin handler + Fuego declaration + Postman in the same PR. integration-test/collections/console_mps_apis.postman_collection.json still references remoteErase in the features body and has no entries for the two new boot/remoteErase/:guid endpoints.

@madhavilosetty-intel

Copy link
Copy Markdown
Contributor

@nmgaston I checked the AMT SDK documentation, and bit 16 (0x10000) in AMT_BootCapabilities.PlatformErase represents OEM Custom Action, not CSME Unconfigure.

This means the current capability check is using an unrelated bit to decide whether CSME unconfigure is supported. CSME unconfigure appears to use the ConfigurationDataReset / unprovision path, which rpe.go already follows, so it likely should not be gated on a PlatformErase bit.

Could we confirm the intended feature here?

  • If this is meant to support CSME unconfigure, could we remove the bit-16 check and rely on the ConfigurationDataReset path?
  • If this is meant to support OEM Custom Action, could we rename the constant, field, and UI label accordingly?

It would also be good to replace the two separate 0x10000 definitions with one shared, correctly documented constant.

@nmgaston

Copy link
Copy Markdown
Contributor Author

@nmgaston I checked the AMT SDK documentation, and bit 16 (0x10000) in AMT_BootCapabilities.PlatformErase represents OEM Custom Action, not CSME Unconfigure.

This means the current capability check is using an unrelated bit to decide whether CSME unconfigure is supported. CSME unconfigure appears to use the ConfigurationDataReset / unprovision path, which rpe.go already follows, so it likely should not be gated on a PlatformErase bit.

Could we confirm the intended feature here?

  • If this is meant to support CSME unconfigure, could we remove the bit-16 check and rely on the ConfigurationDataReset path?
  • If this is meant to support OEM Custom Action, could we rename the constant, field, and UI label accordingly?

It would also be good to replace the two separate 0x10000 definitions with one shared, correctly documented constant.

Removed the bit 16 and using ConfigurationDataReset. We aren't supporting OEM Custom Action at this time. Fixed the magic number.

@nmgaston
nmgaston force-pushed the remotePlatformErase branch from ec6ed84 to 746081c Compare July 24, 2026 03:25
@nmgaston

Copy link
Copy Markdown
Contributor Author

Postman collections not updated — CLAUDE.md requires Gin handler + Fuego declaration + Postman in the same PR. integration-test/collections/console_mps_apis.postman_collection.json still references remoteErase in the features body and has no entries for the two new boot/remoteErase/:guid endpoints.

should be updated now.

@nmgaston
nmgaston force-pushed the remotePlatformErase branch from 0b82049 to d3507fe Compare August 3, 2026 19:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 29 out of 32 changed files in this pull request and generated 1 comment.

Files not reviewed (3)
  • internal/mocks/devicemanagement_mocks.go: Generated file
  • internal/mocks/wsman_mocks.go: Generated file
  • internal/mocks/wsv1_mocks.go: Generated file
Suppressed comments (5)

internal/usecase/devices/boot.go:32

  • uc.log.Debug is printf-style (see pkg/logger/logger.go) and will treat the extra "key/value" arguments as extra formatting args, producing %!(EXTRA ...) in logs because the message has no format verbs. Format the values into the message string instead of passing structured args.
	uc.log.Debug("getRemoteEraseCapabilities: PlatformErase capability", "guid", guid, "PlatformErase", capabilities.PlatformErase, "supported", capabilities.PlatformErase != 0, "ConfigurationDataReset", capabilities.ConfigurationDataReset)

internal/entity/dto/v1/getfeatures.go:16

  • This changes the v1 response field name from remoteErase to rpe (and adds rpeSupported). Renaming a JSON field in /api/v1/* is a breaking contract change for existing integrators; consider keeping remoteErase as a backwards-compatible alias (and mapping it to/from the new RPE fields) rather than removing it outright.
	LocalPBABootSupported bool   `json:"localPBABootSupported" binding:"required" example:"false"`
	RPE                   bool   `json:"rpe" binding:"required" example:"false"`
	RPESupported          bool   `json:"rpeSupported" example:"false"`

internal/entity/dto/v2/features.go:29

  • The v2 Features DTO renames remoteErase to rpe and adds rpeSupported. If /api/v2/amt/features/:guid has any existing consumers, this is a breaking response shape change; consider keeping the existing remoteErase field (deprecated) while adding the new RPE fields, or bumping the endpoint/version.
	OCR                   bool   `json:"httpBoot" example:"true"`
	HTTPSBootSupported    bool   `json:"httpBootSupported,omitempty" example:"true"`
	WinREBootSupported    bool   `json:"winREBootSupported,omitempty" example:"true"`
	LocalPBABootSupported bool   `json:"localPBABootSupported,omitempty" example:"true"`
	RPE                   bool   `json:"rpe" example:"true"`
	RPESupported          bool   `json:"rpeSupported" example:"true"`
}

internal/controller/httpapi/v1/boot.go:43

  • The OpenAPI adapter models this endpoint as NoContentResponse (HTTP 204), but the Gin handler currently returns 200 with a null JSON body. Align the runtime response code/body with the OpenAPI contract (or update the OpenAPI declaration/tests if 200 is intended).
	if err := r.d.SetRemoteEraseOptions(c.Request.Context(), guid, req); err != nil {
		r.l.Error(err, "http - v1 - setRemoteEraseOptions")
		ErrorResponse(c, err)

		return
	}

	c.JSON(http.StatusOK, nil)
}

internal/entity/dto/v1/features.go:37

  • Features / FeaturesRequest in v1 rename remoteEraserpe. Because /api/v1/amt/features/:guid both accepts and returns this DTO, this is a breaking request/response shape change. Keep remoteErase working (e.g., accept both on input and emit an alias) and treat rpe/rpeSupported as additive fields.
	OCR                   bool   `json:"ocr" example:"true"`
	HTTPSBootSupported    bool   `json:"httpsBootSupported" example:"true"`
	WinREBootSupported    bool   `json:"winREBootSupported" example:"true"`
	LocalPBABootSupported bool   `json:"localPBABootSupported" example:"true"`
	RPE                   bool   `json:"rpe" example:"true"`
	RPESupported          bool   `json:"rpeSupported" example:"true"`
}

type FeaturesRequest struct {
	UserConsent string `json:"userConsent" example:"kvm"`
	EnableSOL   bool   `json:"enableSOL" example:"true"`
	EnableIDER  bool   `json:"enableIDER" example:"true"`
	EnableKVM   bool   `json:"enableKVM" example:"true"`
	OCR         bool   `json:"ocr" example:"true"`
	RPE         bool   `json:"rpe" example:"true"`
}

Comment thread internal/usecase/devices/wsman/rpe.go
@nmgaston
nmgaston force-pushed the remotePlatformErase branch from 5f9175b to 30a1316 Compare August 3, 2026 20:08
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.

Add support for Remote Platform Erase in Console

5 participants