Repository navigation
(GH-1729) Make nonfunctional secret extension manifests invalid - #1745
Gijs Reijn (Gijsreyn) wants to merge 5 commits into
Conversation
9604a96 to
773af9b
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Validation currently permits an ambiguous argument object, can discard entire manifest lists, and has diagnostic, localization, and test-isolation issues.
5 open findings
Skip invalid manifest entries without discarding valid resources · New Preserve extension type for missing args diagnostics · New Reject unknown fields in untagged argument variants · New Restore previous DSC_RESTRICTED_PATH value · New Localize hard-coded schema titles and validation messages · New
What changed in this PR
Strengthens secret-extension manifests by enforcing required name/vault argument constraints during schema validation, discovery, and invocation.
Changes:
- Adds secret argument validation and schema constraints.
- Updates test tooling, manifests, and automated coverage.
- Documents the stricter contract and compatibility impact.
| File | Description |
|---|---|
tools/dsctest/src/main.rs |
Ignores no-op arguments. |
tools/dsctest/src/args.rs |
Allows trailing no-op arguments. |
tools/dsctest/deprecated/deprecated.dsc.manifests.json |
Fixes deprecated secret manifest. |
lib/dsc-lib/src/extensions/secret.rs |
Implements validation, invocation safeguards, schema rules, and tests. |
lib/dsc-lib/src/discovery/command_discovery.rs |
Rejects invalid secret extensions during discovery. |
lib/dsc-lib/locales/en-us.toml |
Adds validation diagnostics. |
dsc/tests/dsc_extension_secret.tests.ps1 |
Tests valid and invalid manifests. |
docs/reference/schemas/extension/manifest/secret.md |
Documents strict secret arguments. |
docs/reference/schemas/extension/manifest/root.md |
Updates root manifest guidance. |
CHANGELOG.md |
Records the breaking validation change. |
🧠 Review effort: Balanced
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
| /// | ||
| /// The subschemas are defined separately so that each failure reports a specific message. | ||
| /// The `errorMessage` keyword is only emitted in the VS Code form of the schema. | ||
| fn transform_args_constraints(schema: &mut Schema) { |
Mikey Lombardi (He/Him) (michaeltlombardi)
left a comment
There was a problem hiding this comment.
Added a few notes on addressing the schema change.
Another option to consider is to define a newtype wrapper around Vec<SecretArgKind>, like (not tested, just quickly scribbled out):
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(try_from = "Vec<serde_json::Value>")]
#[schemars(inline, !try_from)]
pub struct SecretArgs(Vec<SecretArgKind>);
impl SecretArgs {
pub fn from_values(values: Vec<serde_json::Value>) -> Result<Self, DscError> {
Self::validate(&values)?;
// Construction logic
}
fn validate(values: &Vec<serde_json::Value>) -> Result<(), DscError> {
// Validation logic for an array of values
}
}
impl TryFrom<Vec<serde_json::Value>> for SecretArgs {
type Error = DscError;
fn try_from(values: Vec<serde_json::Value>) -> Result<Self, Self::Error> {
SecretArgs::from_values(values)
}
}Which lets us pull the validation into the deserialization process and provide meaningful messages. Generally, we want to raise an error when we can't deserialize data because it fails constraints - this way we can just use the deserialized data in the rest of the code without needing to validate it repeatedly.
773af9b to
6fcd53d
Compare
https://github.com/Gijsreyn/operation-methods into PowerShellgh-1729/main/feat-secret-extension-contract
…ation - Validate secret args during deserialization through a SecretArgs newtype - Define the schema constraints with the schemars attribute and localize them - Reject argument objects with unknown properties - Restore DSC_RESTRICTED_PATH in the new tests
| pub fn new(args: Vec<SecretArgKind>) -> Result<Self, DscError> { | ||
| Self::validate(&args)?; | ||
| Ok(Self(args)) | ||
| } |
There was a problem hiding this comment.
Rather than naming this function new(), I think this should be from_args.


PR Summary
This change:
secretcommand to also define itsargs, with exactly one secret name input argument (nameArg) and at most one vault input argument (vaultArg).secretcommand, so editors flag the problem while the manifest is being written. The VS Code form of the schema carries a specific error message for each rule.no-opsubcommand ofdsctestto accept and ignore arguments, and fixes the deprecated test extension, which was itself a nonfunctional secret extension.PR Context
Prior to this change, the
argsfield for thesecretcommand was optional, and nothing checked whether it contained the secret name input argument. An extension could define asecretcommand that DSC was happy to invoke but could never tell which secret to retrieve: the name was silently dropped from the argument list, and whatever the extension wrote to stdout was treated as the secret. Nothing in the output ofdsc extension listor in the trace messages told the author that something was wrong.The hand-written YAML schema source under
schemas/srcalready described the intended contract:argsrequired, exactly one name argument, at most one vault argument. The published schemas are now generated from the Rust types, though, and those carried none of these constraints. The repository's own deprecated test extension shows how easy it was to get wrong: itssecretcommand passed onlyno-optodsctestand nothing else.The working group chose the first option from the issue, making the contract strict and treating a missing name argument as an error, rather than the second option of appending the secret name as a trailing argument.
The check lives in the loader that turns an extension manifest into a discovered extension, next to the existing checks for the other commands. When it fails, the manifest is rejected the same way as a manifest that doesn't parse, so the behavior is consistent for extension authors: the extension doesn't appear in the list, and running
dsc --trace-level info extension listshows why.Remark on compatibility
This is a breaking change for extension manifests that omit
argsor the name argument. Those manifests loaded before, but the resulting extension couldn't retrieve a specific secret, so the change only excludes definitions that never worked as intended. The Azure CLI example and the test extensions in this repository were already compliant.Remark on the message level
The skipped-manifest message is logged at the info level, matching every other invalid manifest. If this case should be louder, a warning from the loader is a one-line change.
Remark on the published schemas
The checked-in schemas under
schemas/v3aren't regenerated in this change. They don't yet contain thesecretorimportcommand schemas at all, so regenerating them appears to be a separate release-time step rather than something each change is expected to do.