-
Notifications
You must be signed in to change notification settings - Fork 882
Add validation to ensure that settings.configs values are dictionaries, in order to prevent misuse #1547
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add validation to ensure that settings.configs values are dictionaries, in order to prevent misuse #1547
Changes from 23 commits
0cdd80d
58cdf9b
6af2709
5c164b2
d90866f
eac4831
8d90c4a
340b8e6
1b32082
70bf933
d9ca225
53968a5
c56b072
d65fc9e
cb2f605
54081ce
24040e7
9dc8405
ca9ed3e
6b9cc59
6f7592d
79d78ca
03bcec1
a792bcc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import Foundation | ||
| import JSONUtilities | ||
|
|
||
| /// A helper for extracting and validating the `Settings` object from a JSON dictionary. | ||
| struct BuildSettingsParser { | ||
| let jsonDictionary: JSONDictionary | ||
|
|
||
| /// Attempts to extract and parse the `Settings` from the dictionary. | ||
| /// | ||
| /// - Returns: A valid `Settings` object | ||
| func parse() throws -> Settings { | ||
| do { | ||
| return try jsonDictionary.json(atKeyPath: "settings") | ||
| } catch let specParsingError as SpecParsingError { | ||
| // Re-throw `SpecParsingError` to prevent the misuse of settings.configs. | ||
| throw specParsingError | ||
| } catch { | ||
| // Ignore all errors except `SpecParsingError` | ||
| return .empty | ||
| } | ||
| } | ||
|
|
||
| /// Attempts to extract and parse setting groups from the dictionary with fallback defaults. | ||
| /// | ||
| /// - Returns: Parsed setting groups or default groups if parsing fails | ||
| func parseSettingGroups() throws -> [String: Settings] { | ||
| do { | ||
| return try jsonDictionary.json(atKeyPath: "settingGroups", invalidItemBehaviour: .fail) | ||
| } catch let specParsingError as SpecParsingError { | ||
| // Re-throw `SpecParsingError` to prevent the misuse of settingGroups. | ||
| throw specParsingError | ||
| } catch { | ||
| // Ignore all errors except `SpecParsingError` | ||
| return jsonDictionary.json(atKeyPath: "settingPresets") ?? [:] | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| name: InvalidConfigsValueNonMappingAggregateTargets | ||
|
|
||
| # This fixture tests validation of `settings.configs` under an aggregate target. | ||
| # Here, `invalid_key0` and `invalid_key1` are scalar values (not mappings), | ||
| # so parsing should throw SpecParsingError.invalidConfigsMappingFormat. | ||
| targets: | ||
| valid_target1: | ||
| type: application | ||
| platform: iOS | ||
| valid_target2: | ||
| type: application | ||
| platform: iOS | ||
|
|
||
| aggregateTargets: | ||
| invalid_target: | ||
| targets: | ||
| - valid_target1 | ||
| - valid_target2 | ||
| settings: | ||
| configs: | ||
| invalid_key0: value0 | ||
| debug: | ||
| valid_key: value1 | ||
| invalid_key1: value2 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| name: InvalidConfigsValueNonMappingSettingGroups | ||
|
|
||
| # This fixture tests validation of `settings.configs` under an aggregate target. | ||
| # Here, `invalid_key0` and `invalid_key1` are scalar values (not mappings), | ||
| # so parsing should throw SpecParsingError.invalidConfigsMappingFormat. | ||
| settingGroups: | ||
| invalid_preset: | ||
| configs: | ||
| invalid_key0: value0 | ||
| debug: | ||
| valid_key: value1 | ||
| invalid_key1: value2 | ||
| targets: | ||
| invalid_target: | ||
| type: application | ||
| platform: iOS | ||
| settings: | ||
| groups: | ||
| - invalid_preset |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| name: InvalidConfigsValueNonMappingSettings | ||
|
|
||
| # This fixture tests validation of `settings.configs` at the top level. | ||
| # Here, `invalid_key0` and `invalid_key1` are scalar values (not mappings), | ||
| # so parsing should throw SpecParsingError.invalidConfigsMappingFormat. | ||
| settings: | ||
| configs: | ||
| invalid_key0: value0 | ||
| debug: | ||
| valid_key: value1 | ||
| invalid_key1: value2 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| name: InvalidConfigsValueNonMappingTargets | ||
|
|
||
| # This fixture tests nested validation of `settings.configs` under a target. | ||
| # Here, `invalid_key0` and `invalid_key1` are scalar values (not mappings), | ||
| # so parsing should throw SpecParsingError.invalidConfigsMappingFormat. | ||
| targets: | ||
| invalid_target: | ||
| type: application | ||
| platform: iOS | ||
| settings: | ||
| configs: | ||
| invalid_key0: value0 | ||
| debug: | ||
| valid_key: value1 | ||
| invalid_key1: value2 |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,43 @@ | ||||||||
| import ProjectSpec | ||||||||
| import Testing | ||||||||
| import TestSupport | ||||||||
| import PathKit | ||||||||
|
|
||||||||
| struct invalidConfigsMappingFormatTests { | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Do we need it? Or do you remove it for other reason?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. even if we don't apply the
ref: https://developer.apple.com/documentation/testing/suite(_:_:)
yonaskolb marked this conversation as resolved.
Outdated
|
||||||||
| struct InvalidConfigsTestArguments { | ||||||||
| var fixturePath: Path | ||||||||
| var expectedError: SpecParsingError | ||||||||
| } | ||||||||
|
|
||||||||
| private static var testArguments: [InvalidConfigsTestArguments] { | ||||||||
| let invalidConfigsFixturePath: Path = fixturePath + "invalid_configs" | ||||||||
| return [ | ||||||||
| InvalidConfigsTestArguments( | ||||||||
| fixturePath: invalidConfigsFixturePath + "invalid_configs_value_non_mapping_settings.yml", | ||||||||
| expectedError: SpecParsingError.invalidConfigsMappingFormat(keys: ["invalid_key0", "invalid_key1"]) | ||||||||
| ), | ||||||||
| InvalidConfigsTestArguments( | ||||||||
| fixturePath: invalidConfigsFixturePath + "invalid_configs_value_non_mapping_targets.yml", | ||||||||
| expectedError: SpecParsingError.invalidConfigsMappingFormat(keys: ["invalid_key0", "invalid_key1"]) | ||||||||
| ), | ||||||||
| InvalidConfigsTestArguments( | ||||||||
| fixturePath: invalidConfigsFixturePath + "invalid_configs_value_non_mapping_aggregate_targets.yml", | ||||||||
| expectedError: SpecParsingError.invalidConfigsMappingFormat(keys: ["invalid_key0", "invalid_key1"]) | ||||||||
| ), | ||||||||
| InvalidConfigsTestArguments( | ||||||||
| fixturePath: invalidConfigsFixturePath + "invalid_configs_value_non_mapping_setting_groups.yml", | ||||||||
| expectedError: SpecParsingError.invalidConfigsMappingFormat(keys: ["invalid_key0", "invalid_key1"]) | ||||||||
| ) | ||||||||
| ] | ||||||||
| } | ||||||||
|
|
||||||||
| @Test("throws invalidConfigsMappingFormat for non-mapping configs entries", arguments: testArguments) | ||||||||
| func testInvalidConfigsMappingFormat(_ arguments: InvalidConfigsTestArguments) throws { | ||||||||
| #expect { | ||||||||
| try Project(path: arguments.fixturePath) | ||||||||
| } throws: { actualError in | ||||||||
| (actualError as any CustomStringConvertible).description | ||||||||
| == arguments.expectedError.description | ||||||||
| } | ||||||||
| } | ||||||||
| } | ||||||||
Uh oh!
There was an error while loading. Please reload this page.