From f499f0bd755ea7d3fc406c1b67b3f994824fffcc Mon Sep 17 00:00:00 2001 From: Steve Ramage Date: Sat, 23 May 2026 10:43:59 -0700 Subject: [PATCH] feat: add 6 validators - private_users, managed_oom_rules, restrict_network_interfaces, bind_network_interface, working_directory, unit_env_file (Resolves #448) Batch 3/5 of the burn-down extension. Each grammar mirrors the systemd C parser: - config_parse_private_users (.nspawn): boolean | "pick" | "identity" | uid[:range] - config_parse_managed_oom_rules: list of filename-safe rule names (string_is_safe STRING_FILENAME) - config_parse_restrict_network_interfaces: optional ~ + list of ALTERNATIVE-length ifnames - config_parse_bind_network_interface: single ALTERNATIVE-length ifname (specifier-aware) - config_parse_working_directory: optional - + (~ | absolute path) - config_parse_unit_env_file: optional - + absolute path Alternative-order gotcha (from #447): for private_users, BOOLEAN is placed LAST so its FlexibleLiteralChoice syntactic regex doesn't greedily match prefixes of "pick"/"identity" and short-circuit the AlternativeCombinator. OptionValueTest missing-function count drops 388 -> 382; found-key count rises 1812 -> 1846. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../semanticdata/optionvalues/AiGenerated.kt | 6 +++ ...figParseBindNetworkInterfaceOptionValue.kt | 23 ++++++++ .../ConfigParseManagedOomRulesOptionValue.kt | 32 ++++++++++++ .../ai/ConfigParsePrivateUsersOptionValue.kt | 40 ++++++++++++++ ...rseRestrictNetworkInterfacesOptionValue.kt | 36 +++++++++++++ .../ai/ConfigParseUnitEnvFileOptionValue.kt | 21 ++++++++ .../ConfigParseWorkingDirectoryOptionValue.kt | 27 ++++++++++ ...arseBindNetworkInterfaceOptionValueTest.kt | 45 ++++++++++++++++ ...nfigParseManagedOomRulesOptionValueTest.kt | 45 ++++++++++++++++ .../ConfigParsePrivateUsersOptionValueTest.kt | 52 +++++++++++++++++++ ...estrictNetworkInterfacesOptionValueTest.kt | 47 +++++++++++++++++ .../ConfigParseUnitEnvFileOptionValueTest.kt | 45 ++++++++++++++++ ...figParseWorkingDirectoryOptionValueTest.kt | 47 +++++++++++++++++ 13 files changed, 466 insertions(+) create mode 100644 src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseBindNetworkInterfaceOptionValue.kt create mode 100644 src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseManagedOomRulesOptionValue.kt create mode 100644 src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParsePrivateUsersOptionValue.kt create mode 100644 src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseRestrictNetworkInterfacesOptionValue.kt create mode 100644 src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseUnitEnvFileOptionValue.kt create mode 100644 src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseWorkingDirectoryOptionValue.kt create mode 100644 src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseBindNetworkInterfaceOptionValueTest.kt create mode 100644 src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseManagedOomRulesOptionValueTest.kt create mode 100644 src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParsePrivateUsersOptionValueTest.kt create mode 100644 src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseRestrictNetworkInterfacesOptionValueTest.kt create mode 100644 src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseUnitEnvFileOptionValueTest.kt create mode 100644 src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseWorkingDirectoryOptionValueTest.kt diff --git a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/AiGenerated.kt b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/AiGenerated.kt index 20538c8..ca31a46 100644 --- a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/AiGenerated.kt +++ b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/AiGenerated.kt @@ -25,6 +25,7 @@ fun getAllAIGeneratedValidators(): Map { Validator("config_parse_bare_udp_iftype", "0") to ConfigParseBareUdpIftypeOptionValue() as OptionValueInformation, Validator("config_parse_batadv_gateway_mode", "0") to ConfigParseBatadvGatewayModeOptionValue() as OptionValueInformation, Validator("config_parse_batadv_routing_algorithm", "0") to ConfigParseBatadvRoutingAlgorithmOptionValue() as OptionValueInformation, + Validator("config_parse_bind_network_interface", "0") to ConfigParseBindNetworkInterfaceOptionValue() as OptionValueInformation, Validator("config_parse_bond_ad_select", "0") to ConfigParseBondAdSelectOptionValue() as OptionValueInformation, Validator("config_parse_bond_arp_all_targets", "0") to ConfigParseBondArpAllTargetsOptionValue() as OptionValueInformation, Validator("config_parse_bond_arp_validate", "0") to ConfigParseBondArpValidateOptionValue() as OptionValueInformation, @@ -130,6 +131,7 @@ fun getAllAIGeneratedValidators(): Map { Validator("config_parse_macvlan_mode", "0") to ConfigParseMacvlanModeOptionValue() as OptionValueInformation, Validator("config_parse_managed_oom_mem_pressure_duration_sec", "0") to ConfigParseManagedOomMemPressureDurationSecOptionValue() as OptionValueInformation, Validator("config_parse_managed_oom_mem_pressure_limit", "0") to ConfigParseManagedOomMemPressureLimitOptionValue() as OptionValueInformation, + Validator("config_parse_managed_oom_rules", "1") to ConfigParseManagedOomRulesOptionValue() as OptionValueInformation, Validator("config_parse_mdi", "0") to ConfigParseMdiOptionValue() as OptionValueInformation, Validator("config_parse_pressure_watch", "0") to ConfigParseMemoryPressureWatchOptionValue() as OptionValueInformation, Validator("config_parse_mtu", "AF_INET6") to ConfigParseMtuOptionValue() as OptionValueInformation, @@ -155,10 +157,12 @@ fun getAllAIGeneratedValidators(): Map { Validator("config_parse_prefix_metric", "0") to ConfigParsePrefixMetricOptionValue() as OptionValueInformation, Validator("config_parse_private_pids", "0") to ConfigParsePrivatePidsOptionValue() as OptionValueInformation, Validator("config_parse_private_tmp", "0") to ConfigParsePrivateTmpOptionValue() as OptionValueInformation, + Validator("config_parse_private_users", "0") to ConfigParsePrivateUsersOptionValue() as OptionValueInformation, Validator("config_parse_protect_control_groups", "0") to ConfigParseProtectControlGroupsOptionValue() as OptionValueInformation, Validator("config_parse_protect_home", "0") to ConfigParseProtectHomeOptionValue() as OptionValueInformation, Validator("config_parse_protect_system", "0") to ConfigParseProtectSystemOptionValue() as OptionValueInformation, Validator("config_parse_qfq_weight", "TCLASS_KIND_QFQ") to ConfigParseQfqWeightOptionValue() as OptionValueInformation, + Validator("config_parse_restrict_network_interfaces", "0") to ConfigParseRestrictNetworkInterfacesOptionValue() as OptionValueInformation, Validator("config_parse_ring_buffer_or_channel", "0") to ConfigParseRingBufferOrChannelOptionValue() as OptionValueInformation, Validator("config_parse_route_prefix_preference", "0") to ConfigParseRoutePrefixPreferenceOptionValue() as OptionValueInformation, Validator("config_parse_route_section", "ROUTE_METRIC_FASTOPEN_NO_COOKIE") to ConfigParseRouteSectionOptionValue() as OptionValueInformation, @@ -192,12 +196,14 @@ fun getAllAIGeneratedValidators(): Map { Validator("config_parse_unit_condition_string", "CONDITION_CONTROL_GROUP_CONTROLLER") to ConfigParseUnitConditionStringOptionValue() as OptionValueInformation, Validator("config_parse_unit_condition_string", "CONDITION_CPU_FEATURE") to ConfigParseUnitConditionStringOptionValue() as OptionValueInformation, Validator("config_parse_unit_condition_string", "CONDITION_FIRST_BOOT") to ConfigParseUnitConditionStringOptionValue() as OptionValueInformation, + Validator("config_parse_unit_env_file", "0") to ConfigParseUnitEnvFileOptionValue() as OptionValueInformation, Validator("config_parse_unit_slice", "0") to ConfigParseUnitSliceOptionValue() as OptionValueInformation, Validator("config_parse_use_domains", "0") to ConfigParseUseDomainsOptionValue() as OptionValueInformation, Validator("config_parse_userns_chown", "0") to ConfigParseUsernsChownOptionValue() as OptionValueInformation, Validator("config_parse_userns_ownership", "0") to ConfigParseUsernsOwnershipOptionValue() as OptionValueInformation, Validator("config_parse_vlanid", "0") to ConfigParseVlanidOptionValue() as OptionValueInformation, Validator("config_parse_vxlan_ttl", "0") to ConfigParseVxlanTtlOptionValue() as OptionValueInformation, + Validator("config_parse_working_directory", "0") to ConfigParseWorkingDirectoryOptionValue() as OptionValueInformation, Validator("config_parse_wireguard_keepalive", "0") to ConfigParseWireguardKeepaliveOptionValue() as OptionValueInformation, Validator("config_parse_wireguard_listen_port", "0") to ConfigParseWireguardListenPortOptionValue() as OptionValueInformation, Validator("config_parse_wireguard_peer_route_priority", "0") to ConfigParseWireguardPeerRoutePriorityOptionValue() as OptionValueInformation, diff --git a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseBindNetworkInterfaceOptionValue.kt b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseBindNetworkInterfaceOptionValue.kt new file mode 100644 index 0000000..e1f92c5 --- /dev/null +++ b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseBindNetworkInterfaceOptionValue.kt @@ -0,0 +1,23 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai + +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.* + +/** + * Validator for BindNetworkInterface=. + * + * C function: config_parse_bind_network_interface in src/core/load-fragment.c. After + * unit_full_printf specifier expansion, the result must pass ifname_valid_full( + * IFNAME_VALID_ALTERNATIVE) — same rules as RestrictNetworkInterfaces= entries but the value + * is a single interface name (no whitespace-separated list, no leading "~"). + */ +class ConfigParseBindNetworkInterfaceOptionValue : SimpleGrammarOptionValues( + "config_parse_bind_network_interface", + SequenceCombinator( + RegexTerminal( + "(?!(?:all|default|\\.{1,2}|0[xX][0-9a-fA-F]+|[0-9]+)\\Z)[^\\s:/%]{1,127}", + "(?!(?:all|default|\\.{1,2}|0[xX][0-9a-fA-F]+|[0-9]+)\\Z)[^\\s:/%]{1,127}" + ), + EOF() + ) +) diff --git a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseManagedOomRulesOptionValue.kt b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseManagedOomRulesOptionValue.kt new file mode 100644 index 0000000..997c72e --- /dev/null +++ b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseManagedOomRulesOptionValue.kt @@ -0,0 +1,32 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai + +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.* + +/** + * Validator for ManagedOOMRulesets= and friends. + * + * C function: config_parse_managed_oom_rules in src/core/load-fragment.c. After an + * unsupported-unit-type check it tokenizes rvalue with extract_first_word and accepts each + * token that passes string_is_safe(STRING_FILENAME) — i.e. filename-safe characters, not + * "." / "..", no slashes, no whitespace, no shell metacharacters. The rules themselves are + * loaded from .oomrule files at runtime so the grammar only validates the per-token shape. + */ +class ConfigParseManagedOomRulesOptionValue : SimpleGrammarOptionValues( + "config_parse_managed_oom_rules", + SequenceCombinator( + RULE_NAME, + ZeroOrMore(SequenceCombinator(WhitespaceTerminal(), RULE_NAME)), + EOF() + ) +) { + companion object { + // STRING_FILENAME forbids slashes, NUL, whitespace, and shell metacharacters. The + // regex below is a conservative ASCII printable set excluding those plus the "." / + // ".." filename reservations (rejected via the negative lookahead). + private val RULE_NAME = RegexTerminal( + "(?!\\.{1,2}\\Z)[A-Za-z0-9._-][A-Za-z0-9._+-]*", + "(?!\\.{1,2}\\Z)[A-Za-z0-9._-][A-Za-z0-9._+-]*" + ) + } +} diff --git a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParsePrivateUsersOptionValue.kt b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParsePrivateUsersOptionValue.kt new file mode 100644 index 0000000..867d0b4 --- /dev/null +++ b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParsePrivateUsersOptionValue.kt @@ -0,0 +1,40 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai + +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.* + +/** + * Validator for the .nspawn PrivateUsers= setting. + * + * C function: config_parse_private_users in src/nspawn/nspawn-settings.c. Accepts (in order + * the C code checks): + * - boolean ("yes" / "no" / "1" / "0" / "true" / "false" / "on" / "off") + * - "pick" (random UID shift) + * - "identity" (UID shift 0, range 64K) + * - `uid` (single uint32, range defaults to 64K) + * - `uid:range` (two uint32 separated by colon) + * + * Alternatives are ordered from most-specific to least-specific so the colon form is tried + * before the bare uid, and BOOLEAN (FlexibleLiteralChoiceTerminal) comes last — its syntactic + * regex would otherwise greedily match tokens like "pick" or "identity" as boolean prefixes + * and short-circuit AlternativeCombinator. + */ +class ConfigParsePrivateUsersOptionValue : SimpleGrammarOptionValues( + "config_parse_private_users", + SequenceCombinator( + AlternativeCombinator( + // uid:range + SequenceCombinator( + IntegerTerminal(0, 4_294_967_296L), + LiteralChoiceTerminal(":"), + IntegerTerminal(0, 4_294_967_296L) + ), + // bare uid + IntegerTerminal(0, 4_294_967_296L), + // string aliases + LiteralChoiceTerminal("pick", "identity"), + BOOLEAN + ), + EOF() + ) +) diff --git a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseRestrictNetworkInterfacesOptionValue.kt b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseRestrictNetworkInterfacesOptionValue.kt new file mode 100644 index 0000000..b879a64 --- /dev/null +++ b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseRestrictNetworkInterfacesOptionValue.kt @@ -0,0 +1,36 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai + +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.* + +/** + * Validator for RestrictNetworkInterfaces=. + * + * C function: config_parse_restrict_network_interfaces in src/core/load-fragment.c. Optional + * leading "~" (invert / denylist mode), followed by a whitespace-separated list of interface + * names that must pass ifname_valid_full(IFNAME_VALID_ALTERNATIVE): + * - 1..127 characters (ALTIFNAMSIZ - 1) + * - no whitespace, no '/', no ':', no '%' (rejected by ifname_valid_char) + * - cannot be "." or ".." + * - cannot be "all" or "default" + * - cannot be a purely-numeric string (interpreted as ifindex) + * + * The regex mirrors the existing config_parse_ifname validator but extends the length cap + * from 15 (IFNAMSIZ) to 127 (ALTIFNAMSIZ). + */ +class ConfigParseRestrictNetworkInterfacesOptionValue : SimpleGrammarOptionValues( + "config_parse_restrict_network_interfaces", + SequenceCombinator( + ZeroOrOne(LiteralChoiceTerminal("~")), + IFNAME, + ZeroOrMore(SequenceCombinator(WhitespaceTerminal(), IFNAME)), + EOF() + ) +) { + companion object { + private val IFNAME = RegexTerminal( + "(?!(?:all|default|\\.{1,2}|0[xX][0-9a-fA-F]+|[0-9]+)\\Z)[^\\s:/%]{1,127}", + "(?!(?:all|default|\\.{1,2}|0[xX][0-9a-fA-F]+|[0-9]+)\\Z)[^\\s:/%]{1,127}" + ) + } +} diff --git a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseUnitEnvFileOptionValue.kt b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseUnitEnvFileOptionValue.kt new file mode 100644 index 0000000..0a13f71 --- /dev/null +++ b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseUnitEnvFileOptionValue.kt @@ -0,0 +1,21 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai + +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.* + +/** + * Validator for EnvironmentFile=. + * + * C function: config_parse_unit_env_file in src/core/load-fragment.c. Each line is a single + * environment file path (after unit_path_printf specifier expansion); an optional leading "-" + * marks the file as missing-OK. The resolved path must be absolute (path_simplify_and_warn + * with PATH_CHECK_ABSOLUTE). + */ +class ConfigParseUnitEnvFileOptionValue : SimpleGrammarOptionValues( + "config_parse_unit_env_file", + SequenceCombinator( + ZeroOrOne(LiteralChoiceTerminal("-")), + RegexTerminal("/\\S*", "/\\S*"), + EOF() + ) +) diff --git a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseWorkingDirectoryOptionValue.kt b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseWorkingDirectoryOptionValue.kt new file mode 100644 index 0000000..13b725b --- /dev/null +++ b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/ai/ConfigParseWorkingDirectoryOptionValue.kt @@ -0,0 +1,27 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai + +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.* + +/** + * Validator for WorkingDirectory=. + * + * C function: config_parse_working_directory in src/core/load-fragment.c. Accepts: + * - optional leading "-" (missing path is non-fatal) + * - then either "~" alone (use the user's home) OR an absolute path + * + * Path values go through unit_path_printf so "%X" specifiers may appear inline. The grammar + * allows any non-whitespace characters in the path; tighter shell-metacharacter checks happen + * in path_simplify_and_warn at runtime. + */ +class ConfigParseWorkingDirectoryOptionValue : SimpleGrammarOptionValues( + "config_parse_working_directory", + SequenceCombinator( + ZeroOrOne(LiteralChoiceTerminal("-")), + AlternativeCombinator( + LiteralChoiceTerminal("~"), + RegexTerminal("/\\S*", "/\\S*") + ), + EOF() + ) +) diff --git a/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseBindNetworkInterfaceOptionValueTest.kt b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseBindNetworkInterfaceOptionValueTest.kt new file mode 100644 index 0000000..f29206b --- /dev/null +++ b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseBindNetworkInterfaceOptionValueTest.kt @@ -0,0 +1,45 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.inspections.ai + +import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest +import net.sjrx.intellij.plugins.systemdunitfiles.inspections.InvalidValueInspection +import org.junit.Test + +class ConfigParseBindNetworkInterfaceOptionValueTest : AbstractUnitFileTest() { + + @Test + fun testValidValues() { + // language="unit file (systemd)" + val file = """ + [Service] + BindNetworkInterface=eth0 + BindNetworkInterface=lo + BindNetworkInterface=wlan0 + BindNetworkInterface=br-1234abcd + """.trimIndent() + + setupFileInEditor("file.service", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + assertSize(0, highlights) + } + + @Test + fun testInvalidValues() { + // language="unit file (systemd)" + val file = """ + [Service] + BindNetworkInterface=all + BindNetworkInterface=default + BindNetworkInterface=eth0 eth1 + BindNetworkInterface=eth0/0 + BindNetworkInterface=123 + """.trimIndent() + + setupFileInEditor("file.service", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + assertSize(5, highlights) + } +} diff --git a/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseManagedOomRulesOptionValueTest.kt b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseManagedOomRulesOptionValueTest.kt new file mode 100644 index 0000000..0047a92 --- /dev/null +++ b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseManagedOomRulesOptionValueTest.kt @@ -0,0 +1,45 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.inspections.ai + +import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest +import net.sjrx.intellij.plugins.systemdunitfiles.inspections.InvalidValueInspection +import org.junit.Test + +class ConfigParseManagedOomRulesOptionValueTest : AbstractUnitFileTest() { + + @Test + fun testValidValues() { + // language="unit file (systemd)" + val file = """ + [Service] + OOMRules=default + OOMRules=default critical + OOMRules=rule1 rule2 rule3 + OOMRules=my-rule_42 + OOMRules=rule.with.dots + """.trimIndent() + + setupFileInEditor("file.service", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + assertSize(0, highlights) + } + + @Test + fun testInvalidValues() { + // language="unit file (systemd)" + val file = """ + [Service] + OOMRules=rule/with/slash + OOMRules=. + OOMRules=.. + OOMRules=rule,other + """.trimIndent() + + setupFileInEditor("file.service", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + assertSize(4, highlights) + } +} diff --git a/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParsePrivateUsersOptionValueTest.kt b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParsePrivateUsersOptionValueTest.kt new file mode 100644 index 0000000..d4c30f7 --- /dev/null +++ b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParsePrivateUsersOptionValueTest.kt @@ -0,0 +1,52 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.inspections.ai + +import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest +import net.sjrx.intellij.plugins.systemdunitfiles.inspections.InvalidValueInspection +import org.junit.Test + +class ConfigParsePrivateUsersOptionValueTest : AbstractUnitFileTest() { + + @Test + fun testValidValues() { + // language="unit file (systemd)" + val file = """ + [Exec] + PrivateUsers=yes + PrivateUsers=no + PrivateUsers=true + PrivateUsers=false + PrivateUsers=pick + PrivateUsers=identity + PrivateUsers=1000 + PrivateUsers=0 + PrivateUsers=1000:65536 + PrivateUsers=100000:1000000 + """.trimIndent() + + setupFileInEditor("file.nspawn", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + assertSize(0, highlights) + } + + @Test + fun testInvalidValues() { + // language="unit file (systemd)" + val file = """ + [Exec] + PrivateUsers=maybe + PrivateUsers=Pick + PrivateUsers=-1 + PrivateUsers=1000: + PrivateUsers=:1000 + PrivateUsers=1000 65536 + """.trimIndent() + + setupFileInEditor("file.nspawn", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + assertSize(6, highlights) + } +} diff --git a/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseRestrictNetworkInterfacesOptionValueTest.kt b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseRestrictNetworkInterfacesOptionValueTest.kt new file mode 100644 index 0000000..a853131 --- /dev/null +++ b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseRestrictNetworkInterfacesOptionValueTest.kt @@ -0,0 +1,47 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.inspections.ai + +import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest +import net.sjrx.intellij.plugins.systemdunitfiles.inspections.InvalidValueInspection +import org.junit.Test + +class ConfigParseRestrictNetworkInterfacesOptionValueTest : AbstractUnitFileTest() { + + @Test + fun testValidValues() { + // language="unit file (systemd)" + val file = """ + [Service] + RestrictNetworkInterfaces=eth0 + RestrictNetworkInterfaces=eth0 eth1 + RestrictNetworkInterfaces=lo eth0 wlan0 + RestrictNetworkInterfaces=~eth0 + RestrictNetworkInterfaces=~lo eth0 + RestrictNetworkInterfaces=br-1234abcd + """.trimIndent() + + setupFileInEditor("file.service", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + assertSize(0, highlights) + } + + @Test + fun testInvalidValues() { + // language="unit file (systemd)" + val file = """ + [Service] + RestrictNetworkInterfaces=all + RestrictNetworkInterfaces=default + RestrictNetworkInterfaces=eth0/0 + RestrictNetworkInterfaces=eth0:0 + RestrictNetworkInterfaces=123 + """.trimIndent() + + setupFileInEditor("file.service", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + assertSize(5, highlights) + } +} diff --git a/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseUnitEnvFileOptionValueTest.kt b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseUnitEnvFileOptionValueTest.kt new file mode 100644 index 0000000..1a640ac --- /dev/null +++ b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseUnitEnvFileOptionValueTest.kt @@ -0,0 +1,45 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.inspections.ai + +import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest +import net.sjrx.intellij.plugins.systemdunitfiles.inspections.InvalidValueInspection +import org.junit.Test + +class ConfigParseUnitEnvFileOptionValueTest : AbstractUnitFileTest() { + + @Test + fun testValidValues() { + // language="unit file (systemd)" + val file = """ + [Service] + EnvironmentFile=/etc/myapp.env + EnvironmentFile=-/etc/myapp/optional.env + EnvironmentFile=/etc/sysconfig/myapp + EnvironmentFile=/var/lib/%n.env + EnvironmentFile=-/run/secrets/myapp.env + """.trimIndent() + + setupFileInEditor("file.service", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + assertSize(0, highlights) + } + + @Test + fun testInvalidValues() { + // language="unit file (systemd)" + val file = """ + [Service] + EnvironmentFile=relative/path.env + EnvironmentFile=myapp.env + EnvironmentFile=~/myapp.env + EnvironmentFile=--/etc/myapp.env + """.trimIndent() + + setupFileInEditor("file.service", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + assertSize(4, highlights) + } +} diff --git a/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseWorkingDirectoryOptionValueTest.kt b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseWorkingDirectoryOptionValueTest.kt new file mode 100644 index 0000000..8e39b9b --- /dev/null +++ b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/ai/ConfigParseWorkingDirectoryOptionValueTest.kt @@ -0,0 +1,47 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.inspections.ai + +import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest +import net.sjrx.intellij.plugins.systemdunitfiles.inspections.InvalidValueInspection +import org.junit.Test + +class ConfigParseWorkingDirectoryOptionValueTest : AbstractUnitFileTest() { + + @Test + fun testValidValues() { + // language="unit file (systemd)" + val file = """ + [Service] + WorkingDirectory=~ + WorkingDirectory=/var/lib/myapp + WorkingDirectory=/tmp + WorkingDirectory=/ + WorkingDirectory=-/var/cache/myapp + WorkingDirectory=-~ + WorkingDirectory=/var/lib/%n + """.trimIndent() + + setupFileInEditor("file.service", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + assertSize(0, highlights) + } + + @Test + fun testInvalidValues() { + // language="unit file (systemd)" + val file = """ + [Service] + WorkingDirectory=relative/path + WorkingDirectory=somepath + WorkingDirectory=/path with space + WorkingDirectory=--/path + """.trimIndent() + + setupFileInEditor("file.service", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + assertSize(4, highlights) + } +}