Add Microsoft/FileContent resource - #1676
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a new cross-platform DSC resource (Microsoft/FileContent) implemented in Rust to manage UTF-8 file content via set, verify integrity via get/test hash outputs, and emit full content only via export. This extends the resource catalog and updates packaging/build inputs so the new resource ships across Linux/macOS/Windows.
Changes:
- Introduces the
filecontentRust resource executable withget/set/test/exportoperations, i18n strings, and a v3 resource manifest/schema. - Adds cross-platform Pester coverage for
get/set/test/exportand delete (_exist: false) behavior. - Registers the new resource in the workspace/build metadata and package payload lists.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| resources/filecontent/src/main.rs | Resource CLI entrypoint and JSON input parsing for operations. |
| resources/filecontent/src/file.rs | Core file I/O + hashing logic for get/set/test/export. |
| resources/filecontent/src/types.rs | Input/output DTOs for resource operations. |
| resources/filecontent/locales/en-us.toml | Localized user-facing strings via rust-i18n. |
| resources/filecontent/filecontent.dsc.resource.json | Resource manifest + embedded JSON schema for Microsoft/FileContent. |
| resources/filecontent/Cargo.toml | New resource crate definition and dependencies. |
| resources/filecontent/.project.data.json | Build metadata for including the resource binary + manifest. |
| resources/filecontent/tests/filecontent_get.tests.ps1 | Pester tests validating get hashes and no content leakage. |
| resources/filecontent/tests/filecontent_set.tests.ps1 | Pester tests validating set writes and _exist: false deletion. |
| resources/filecontent/tests/filecontent_test.tests.ps1 | Pester tests validating test hash-based desired state evaluation. |
| resources/filecontent/tests/filecontent_export.tests.ps1 | Pester tests validating export returns content + hashes. |
| data.build.json | Adds the new resource artifacts to platform payload lists and project catalog. |
| Cargo.toml | Adds the new resource crate to workspace members/default members and introduces sha2 workspace dep. |
| Cargo.lock | Records the new filecontent package and dependency linkage. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
😐 Code Coverage ReportChanged Code Coverage75% (70%+ coverage)
🔵 Full Codebase Coverage82% (good)
|
|
My only comment is could this be extended & support any other encoding but default to UTF8 |
I considered exposing an Thinking about the encoding further, the JSON/YAML and therefore |
|
The resource should be called |
I named it |
|
Why don't we want to have multiple different usages in a single resource? Json schema gives us that capability. I'm not a fan of having multiple resources managing the same underlying item. |
|
Thomas Nieto (@ThomasNieto) Let's discuss at next WG, I'm of the opinion it's confusing to users similar to having multiple parametersets. Note that multiple resources can be handled by the same exe. |
| "description": "The UTF-8 content of the file.", | ||
| "writeOnly": true |
There was a problem hiding this comment.
I think we should remove the writeOnly keyword since this property is returnable by the resource.
| "description": "The UTF-8 content of the file.", | |
| "writeOnly": true | |
| "description": "The UTF-8 content of the file." |
| "sha256": { | ||
| "type": "string", | ||
| "title": "SHA-256", | ||
| "description": "The SHA-256 hash of the file content.", | ||
| "pattern": "^[A-Fa-f0-9]{64}$" | ||
| }, | ||
| "sha512": { | ||
| "type": "string", | ||
| "title": "SHA-512", | ||
| "description": "The SHA-512 hash of the file content.", | ||
| "pattern": "^[A-Fa-f0-9]{128}$" | ||
| }, |
There was a problem hiding this comment.
I think both of these properties should be marked as read-only, per our guidance for resource properties:
Resources can define read-only properties to describe information about an instance that the resource can retrieve but not directly set. For example, file APIs don't generally allow a user to set the property describing the last time the file was modified.
Generally, you shouldn't include read-only properties when defining the desired state for an instance. Assertion resources that don't support the Set operation can include read-only properties you can use for validating system state for conditional behavior.
| "sha256": { | |
| "type": "string", | |
| "title": "SHA-256", | |
| "description": "The SHA-256 hash of the file content.", | |
| "pattern": "^[A-Fa-f0-9]{64}$" | |
| }, | |
| "sha512": { | |
| "type": "string", | |
| "title": "SHA-512", | |
| "description": "The SHA-512 hash of the file content.", | |
| "pattern": "^[A-Fa-f0-9]{128}$" | |
| }, | |
| "sha256": { | |
| "type": "string", | |
| "title": "SHA-256", | |
| "description": "The SHA-256 hash of the file content.", | |
| "pattern": "^[A-Fa-f0-9]{64}$", | |
| "readOnly": true, | |
| }, | |
| "sha512": { | |
| "type": "string", | |
| "title": "SHA-512", | |
| "description": "The SHA-512 hash of the file content.", | |
| "pattern": "^[A-Fa-f0-9]{128}$", | |
| "readOnly": true | |
| }, |
| "_exist": { | ||
| "type": "boolean", | ||
| "title": "Exists", | ||
| "description": "Indicates whether the file should exist. Set to false to remove the file." | ||
| }, | ||
| "_inDesiredState": { | ||
| "type": "boolean", | ||
| "title": "In desired state", | ||
| "description": "Indicates whether the file is in the desired state. Only returned by test.", | ||
| "readOnly": true | ||
| } | ||
| }, |
There was a problem hiding this comment.
Per our documentation on canonical resources, both of these property definitions should reference the canonical property schema and bundle it into $defs:
| "_exist": { | |
| "type": "boolean", | |
| "title": "Exists", | |
| "description": "Indicates whether the file should exist. Set to false to remove the file." | |
| }, | |
| "_inDesiredState": { | |
| "type": "boolean", | |
| "title": "In desired state", | |
| "description": "Indicates whether the file is in the desired state. Only returned by test.", | |
| "readOnly": true | |
| } | |
| }, | |
| "_exist": { | |
| "$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json", | |
| }, | |
| "_inDesiredState": { | |
| "$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json" | |
| } | |
| }, | |
| "$defs": { | |
| "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json": { | |
| "$schema": "https://json-schema.org/draft/2020-12/schema", | |
| "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json", | |
| "title": "Instance should exist", | |
| "description": "Indicates whether the DSC resource instance should exist.", | |
| "type": "boolean", | |
| "default": true, | |
| "enum": [ | |
| false, | |
| true | |
| ] | |
| }, | |
| "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json": { | |
| "$schema": "https://json-schema.org/draft/2020-12/schema", | |
| "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json", | |
| "title": "Instance is in the Desired State", | |
| "description": "Indicates whether the instance is in the desired state. This property is only returned by the `test` method.", | |
| "type": [ | |
| "boolean", | |
| "null" | |
| ], | |
| "readOnly": true | |
| } | |
| } |
Note
We have to bundle the canonical property schemas for now because we don't yet use a schema registry with an in-memory retriever to be able to lookup the property references. Eventually resource authors will be able to just define the property with the $ref keyword and DSC will correctly validate the instance.
| #[derive(Debug, Serialize)] | ||
| #[serde(rename_all = "camelCase")] | ||
| pub struct FileState { | ||
| pub path: String, | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub sha256: Option<String>, | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub sha512: Option<String>, | ||
| #[serde(rename = "_exist")] | ||
| pub exist: bool, | ||
| #[serde(rename = "_inDesiredState", skip_serializing_if = "Option::is_none")] | ||
| pub in_desired_state: Option<bool>, | ||
| } | ||
|
|
||
| #[derive(Debug, Serialize)] | ||
| #[serde(rename_all = "camelCase")] | ||
| pub struct ExportState { | ||
| pub path: String, | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub content: Option<String>, | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub sha256: Option<String>, | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub sha512: Option<String>, | ||
| #[serde(rename = "_exist")] | ||
| pub exist: bool, | ||
| } |
There was a problem hiding this comment.
As a user, I think I would be surprised to invoke the get operation and not get the file content:
dsc resource get -r Microsoft/FileContent -i '{"path":"example.txt"}'path: example.txt
_exist: true
sha256: <sha-256>
sha512: <sha-512>In general, without specifying a write-only property to control the behavior, resources should always return the full representation of the resource state for an instance in all operations.
To support minimizing the return data, I think we should use a write-only property like omitContent to opt into this behavior.
Otherwise, the only way for a user to effectively query for the current content of a file with the resource is to use the export operation.
I raised this point in #1539 but we haven't written that document to guide development for built-in resources yet.
There was a problem hiding this comment.
Let's discuss this in the WG, current design is only return content on export particularly since it can be large and the hash is an easier way to detect a diff for the user.
|
Agree on discussion in WG, we should review in context of #567 (comment), where I made some recommendations and linked to prior art on designing a resource for this purpose. |
Adds a cross-platform DSC resource for managing UTF-8 file content and verifying file integrity without exposing content from normal get operations.
Summary
Microsoft/FileContentin Rust with get, set, explicit test, and export operations._exist: false.Testing