Skip to content

Add Microsoft/FileContent resource - #1676

Open
Steve Lee (SteveL-MSFT) wants to merge 4 commits into
mainfrom
stevel-msft-create-filecontent-resource
Open

Add Microsoft/FileContent resource#1676
Steve Lee (SteveL-MSFT) wants to merge 4 commits into
mainfrom
stevel-msft-create-filecontent-resource

Conversation

@SteveL-MSFT

Copy link
Copy Markdown
Member

Adds a cross-platform DSC resource for managing UTF-8 file content and verifying file integrity without exposing content from normal get operations.

Summary

  • Implements Microsoft/FileContent in Rust with get, set, explicit test, and export operations.
  • Computes SHA-256 and SHA-512 hashes using streamed file reads.
  • Compares content-only test input by hashing the desired UTF-8 content.
  • Supports file removal through _exist: false.
  • Returns content only from export while get returns file identity, existence, and hashes.
  • Adds the executable and resource manifest to Linux, macOS, and Windows package payloads.

Testing

  • Rust formatting and pedantic Clippy checks
  • Rust package build and tests
  • 9 cross-platform Pester tests covering get, set, test, export, and deletion

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings August 13, 2026 23:26

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

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 filecontent Rust resource executable with get/set/test/export operations, i18n strings, and a v3 resource manifest/schema.
  • Adds cross-platform Pester coverage for get/set/test/export and 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.

Comment thread resources/filecontent/src/main.rs
Comment thread resources/filecontent/locales/en-us.toml
Comment thread resources/filecontent/src/file.rs Outdated
Steve Lee (POWERSHELL HE/HIM) (from Dev Box) and others added 2 commits August 13, 2026 16:34
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

😐 Code Coverage Report

Changed Code Coverage

75% (70%+ coverage)

Metric Value
Changed lines analyzed 224
Lines covered by tests 170
Coverage percentage 75%

🔵 Full Codebase Coverage

82% (good)

Metric Value
Total executable lines 18972
Lines covered by tests 15601
Coverage percentage 82%

Changed code coverage measures only Rust lines added/modified in this PR.
Full codebase coverage measures all instrumented Rust lines across the project.

@kilasuit

Copy link
Copy Markdown

My only comment is could this be extended & support any other encoding but default to UTF8

@SteveL-MSFT

Steve Lee (SteveL-MSFT) commented Aug 15, 2026

Copy link
Copy Markdown
Member Author

My only comment is could this be extended & support any other encoding but default to UTF8

I considered exposing an encoding property, but the JSON/YAML itself needs to be in utf-8 encoding as that is what DSC supports. I think the majority of the world has decided on UTF8. I think if there's a need for other type of encoding, I'm planning on a FileCopy resource to follow-up that could be used instead.

Thinking about the encoding further, the JSON/YAML and therefore content would need to be UTF-8, but when written to disk, it could be a different encoding. That can still be added later if needed.

@ThomasNieto

Copy link
Copy Markdown
Collaborator

The resource should be called Microsoft/File not FileContent. Reason being is that it handles file existence.

@SteveL-MSFT

Copy link
Copy Markdown
Member Author

The resource should be called Microsoft/File not FileContent. Reason being is that it handles file existence.

I named it FileContent because a separate FileCopy resource will be coming to differentiate. FileCopy will also support _exist. Unlike the old DSC File resource, I didn't want to encapsulate multiple capabilities into one resource (like ParameterSets).

@ThomasNieto

Copy link
Copy Markdown
Collaborator

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.

@SteveL-MSFT

Copy link
Copy Markdown
Member Author

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.

Comment on lines +75 to +76
"description": "The UTF-8 content of the file.",
"writeOnly": true

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we should remove the writeOnly keyword since this property is returnable by the resource.

Suggested change
"description": "The UTF-8 content of the file.",
"writeOnly": true
"description": "The UTF-8 content of the file."

Comment on lines +78 to +89
"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}$"
},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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.

Suggested change
"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
},

Comment on lines +96 to +107
"_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
}
},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Per our documentation on canonical resources, both of these property definitions should reference the canonical property schema and bundle it into $defs:

Suggested change
"_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.

Comment on lines +17 to +43
#[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,
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

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.

@michaeltlombardi

Copy link
Copy Markdown
Collaborator

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo PRs

Development

Successfully merging this pull request may close these issues.

5 participants