Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ fun getAllAIGeneratedValidators(): Map<Validator, OptionValueInformation> {
Validator("config_parse_6rd_prefix", "0") to ConfigParse6rdPrefixOptionValue() as OptionValueInformation,
Validator("config_parse_ad_actor_sys_prio", "0") to ConfigParseAdActorSysPrioOptionValue() as OptionValueInformation,
Validator("config_parse_ad_user_port_key", "0") to ConfigParseAdUserPortKeyOptionValue() as OptionValueInformation,
Validator("config_parse_address_families", "0") to ConfigParseAddressFamiliesOptionValue() as OptionValueInformation,
Validator("config_parse_address_section", "ADDRESS_ADD_PREFIX_ROUTE") to ConfigParseAddressSectionOptionValue() as OptionValueInformation,
Validator("config_parse_address_section", "ADDRESS_AUTO_JOIN") to ConfigParseAddressSectionOptionValue() as OptionValueInformation,
Validator("config_parse_address_section", "ADDRESS_DAD") to ConfigParseAddressSectionOptionValue() as OptionValueInformation,
Expand Down Expand Up @@ -54,7 +55,9 @@ fun getAllAIGeneratedValidators(): Map<Validator, OptionValueInformation> {
Validator("config_parse_codel_bool", "QDISC_KIND_CODEL") to ConfigParseCodelBoolOptionValue() as OptionValueInformation,
Validator("config_parse_codel_u32", "QDISC_KIND_CODEL") to ConfigParseCodelU32OptionValue() as OptionValueInformation,
Validator("config_parse_collect_mode", "0") to ConfigParseCollectModeOptionValue() as OptionValueInformation,
Validator("config_parse_cpu_quota", "0") to ConfigParseCpuQuotaOptionValue() as OptionValueInformation,
Validator("config_parse_cpuset_partition", "0") to ConfigParseCpusetPartitionOptionValue() as OptionValueInformation,
Validator("config_parse_delegate", "0") to ConfigParseDelegateOptionValue() as OptionValueInformation,
Validator("config_parse_df", "0") to ConfigParseDfOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp6_client_start_mode", "0") to ConfigParseDhcp6ClientStartModeOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp6_pd_prefix_hint", "0") to ConfigParseDhcp6PdPrefixHintOptionValue() as OptionValueInformation,
Expand Down Expand Up @@ -96,6 +99,7 @@ fun getAllAIGeneratedValidators(): Map<Validator, OptionValueInformation> {
Validator("config_parse_geneve_ttl", "0") to ConfigParseGeneveTtlOptionValue() as OptionValueInformation,
Validator("config_parse_geneve_vni", "0") to ConfigParseGeneveVniOptionValue() as OptionValueInformation,
Validator("config_parse_hhf_packet_limit", "QDISC_KIND_HHF") to ConfigParseHhfPacketLimitOptionValue() as OptionValueInformation,
Validator("config_parse_htb_class_size", "TCLASS_KIND_HTB") to ConfigParseHtbClassSizeOptionValue() as OptionValueInformation,
Validator("config_parse_iaid", "AF_INET6") to ConfigParseIaidOptionValue() as OptionValueInformation,
Validator("config_parse_iaid", "AF_INET") to ConfigParseIaidOptionValue() as OptionValueInformation,
Validator("config_parse_in_addr_non_null", "AF_INET") to ConfigParseInAddrNonNullOptionValue() as OptionValueInformation,
Expand Down Expand Up @@ -138,6 +142,7 @@ fun getAllAIGeneratedValidators(): Map<Validator, OptionValueInformation> {
Validator("config_parse_nexthop_section", "NEXTHOP_ID") to ConfigParseNexthopSectionOptionValue() as OptionValueInformation,
Validator("config_parse_nexthop_section", "NEXTHOP_ONLINK") to ConfigParseNexthopSectionOptionValue() as OptionValueInformation,
Validator("config_parse_nsec", "0") to ConfigParseNsecOptionValue() as OptionValueInformation,
Validator("config_parse_pass_environ", "0") to ConfigParsePassEnvironOptionValue() as OptionValueInformation,
Validator("config_parse_permille", "0") to ConfigParsePermilleOptionValue() as OptionValueInformation,
Validator("config_parse_pfifo_size", "QDISC_KIND_PFIFO") to ConfigParsePfifoSizeOptionValue() as OptionValueInformation,
Validator("config_parse_pfifo_size", "QDISC_KIND_PFIFO_HEAD_DROP") to ConfigParsePfifoSizeOptionValue() as OptionValueInformation,
Expand Down Expand Up @@ -175,6 +180,7 @@ fun getAllAIGeneratedValidators(): Map<Validator, OptionValueInformation> {
Validator("config_parse_sr_iov_uint32", "0") to ConfigParseSrIovUint32OptionValue() as OptionValueInformation,
Validator("config_parse_sr_iov_vlan_proto", "0") to ConfigParseSrIovVlanProtoOptionValue() as OptionValueInformation,
Validator("config_parse_swap_priority", "0") to ConfigParseSwapPriorityOptionValue() as OptionValueInformation,
Validator("config_parse_syscall_errno", "0") to ConfigParseSyscallErrnoOptionValue() as OptionValueInformation,
Validator("config_parse_tasks_max", "0") to ConfigParseTasksMaxOptionValue() as OptionValueInformation,
Validator("config_parse_tbf_size", "QDISC_KIND_TBF") to ConfigParseTbfSizeOptionValue() as OptionValueInformation,
Validator("config_parse_tcp_window", "0") to ConfigParseTcpWindowOptionValue() as OptionValueInformation,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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 RestrictAddressFamilies=.
*
* C function: config_parse_address_families in src/core/load-fragment.c → parse_address_families
* in src/shared/parse-helpers.c:90. Accepts:
* - "none" (clears the set, sets allowlist)
* - optional leading "~" (invert / denylist mode), followed by a whitespace-separated list
* of address family names from af_from_name (AF_UNIX, AF_INET, AF_INET6, AF_NETLINK,
* AF_PACKET, …)
*
* The grammar matches the "AF_" prefix loosely (any uppercase/digit/underscore tail); unknown
* names slip past the grammar but fail at runtime. This is the same tradeoff as syscall_errno.
*/
class ConfigParseAddressFamiliesOptionValue : SimpleGrammarOptionValues(
"config_parse_address_families",
SequenceCombinator(
AlternativeCombinator(
LiteralChoiceTerminal("none"),
SequenceCombinator(
ZeroOrOne(LiteralChoiceTerminal("~")),
RegexTerminal("AF_[A-Z0-9_]+", "AF_[A-Z0-9_]+"),
ZeroOrMore(SequenceCombinator(
WhitespaceTerminal(),
RegexTerminal("AF_[A-Z0-9_]+", "AF_[A-Z0-9_]+")
))
)
),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
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 CPUQuota=.
*
* C function: config_parse_cpu_quota in src/core/load-fragment.c. After the empty-input check
* it calls parse_permyriad_unbounded(rvalue), which accepts N% / N.N% / N.NN% (with no upper
* bound — values over 100% are meaningful here, e.g. "200%" means 2 cores). The result must
* be strictly greater than zero, so "0%", "0.0%", "0.00%" are rejected at the C semantic
* layer; the grammar accepts them but the runtime parser will warn.
*
* Only the ASCII percent form is matched here; the ‰/‱ Unicode suffixes are vanishingly rare
* in unit files.
*/
class ConfigParseCpuQuotaOptionValue : SimpleGrammarOptionValues(
"config_parse_cpu_quota",
SequenceCombinator(
RegexTerminal("[0-9]+(\\.[0-9]{1,2})?", "[0-9]+(\\.[0-9]{1,2})?"),
LiteralChoiceTerminal("%"),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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 Delegate=.
*
* C function: config_parse_delegate in src/core/load-fragment.c. Either a boolean (toggles
* delegation for all controllers) or a whitespace-separated list of cgroup controller names
* from cgroup_controller_table in src/basic/cgroup-util.c.
*
* Note: the controller list is the first alternative because BOOLEAN is a
* FlexibleLiteralChoiceTerminal whose syntactic phase accepts any short alphanumeric token —
* if it ran first, single-controller inputs like "cpu" would syntactically consume the value
* as a (fake) boolean and AlternativeCombinator would short-circuit there.
*/
class ConfigParseDelegateOptionValue : SimpleGrammarOptionValues(
"config_parse_delegate",
SequenceCombinator(
AlternativeCombinator(
SequenceCombinator(
LiteralChoiceTerminal(
"cpu", "cpuacct", "cpuset", "io", "blkio", "memory", "devices", "pids",
"bpf-firewall", "bpf-devices", "bpf-foreign", "bpf-socket-bind",
"bpf-restrict-network-interfaces", "bpf-bind-network-interface"
),
ZeroOrMore(SequenceCombinator(
WhitespaceTerminal(),
LiteralChoiceTerminal(
"cpu", "cpuacct", "cpuset", "io", "blkio", "memory", "devices", "pids",
"bpf-firewall", "bpf-devices", "bpf-foreign", "bpf-socket-bind",
"bpf-restrict-network-interfaces", "bpf-bind-network-interface"
)
))
),
BOOLEAN
),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
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 HTB class size-style options: QuantumBytes=, MTUBytes=, OverheadBytes=,
* BufferBytes=, CeilBufferBytes=.
*
* C function: config_parse_htb_class_size(TCLASS_KIND_HTB) in src/network/tc/htb.c. After
* branching on the lvalue, it calls parse_size(rvalue, 1024, &v), so the value is a decimal
* byte count optionally suffixed with an IEC unit. Same shape as config_parse_tbf_size and
* config_parse_fq_size.
*
* The per-lvalue OverheadBytes <= UINT16_MAX bound and the general v <= UINT32_MAX bound are
* semantic checks that can't be expressed at the grammar level without lvalue access.
*/
class ConfigParseHtbClassSizeOptionValue : SimpleGrammarOptionValues(
"config_parse_htb_class_size",
SequenceCombinator(
OptionalWhitespacePrefix(BYTES),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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 PassEnvironment=.
*
* C function: config_parse_pass_environ in src/core/load-fragment.c. Whitespace-separated list
* of environment variable names. Each word is first run through unit_env_printf (resolves
* %p / %n / etc.), then env_name_is_valid: must not be empty, must not start with a digit,
* and may contain only characters in VALID_BASH_ENV_NAME_CHARS (alphanumerics and underscore).
*
* The grammar tolerates "%X" specifiers inline by including "%" in the allowed-character set,
* since the C parser resolves them before the validity check. This means a few unresolved
* specifier-heavy inputs that the runtime parser would reject will pass here — preferred over
* false positives for legitimate `PassEnvironment=%n_LOG` style usage.
*/
class ConfigParsePassEnvironOptionValue : SimpleGrammarOptionValues(
"config_parse_pass_environ",
SequenceCombinator(
RegexTerminal("[A-Za-z_%][A-Za-z0-9_%]*", "[A-Za-z_%][A-Za-z0-9_%]*"),
ZeroOrMore(SequenceCombinator(
WhitespaceTerminal(),
RegexTerminal("[A-Za-z_%][A-Za-z0-9_%]*", "[A-Za-z_%][A-Za-z0-9_%]*")
)),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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 SystemCallErrorNumber=.
*
* C function: config_parse_syscall_errno in src/core/load-fragment.c → parse_errno in
* src/basic/parse-util.c. Accepts:
* - "kill" (special, resets to SECCOMP_ERROR_NUMBER_KILL)
* - an errno name (uppercase "E"-prefixed, e.g. EPERM, ENOENT) via errno_from_name
* - an integer that maps to a valid errno via errno_is_valid (or 0)
*
* The grammar matches the errno-name pattern loosely (any uppercase E-prefixed token);
* unknown names like "ENOIENT" would slip past the grammar but fail at runtime. Numeric
* range here is 0..4095 — wider than typical valid errnos but enough to catch obvious typos.
*/
class ConfigParseSyscallErrnoOptionValue : SimpleGrammarOptionValues(
"config_parse_syscall_errno",
SequenceCombinator(
AlternativeCombinator(
LiteralChoiceTerminal("kill"),
RegexTerminal("E[A-Z][A-Z0-9]*", "E[A-Z][A-Z0-9]*"),
IntegerTerminal(0, 4096)
),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
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 ConfigParseAddressFamiliesOptionValueTest : AbstractUnitFileTest() {

@Test
fun testValidValues() {
// language="unit file (systemd)"
val file = """
[Service]
RestrictAddressFamilies=none
RestrictAddressFamilies=AF_INET
RestrictAddressFamilies=AF_INET AF_INET6
RestrictAddressFamilies=AF_UNIX AF_NETLINK
RestrictAddressFamilies=~AF_PACKET
RestrictAddressFamilies=~AF_INET AF_INET6
RestrictAddressFamilies=AF_BRIDGE AF_X25 AF_AX25
""".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]
RestrictAddressFamilies=<error descr="Invalid value">inet</error>
RestrictAddressFamilies=<error descr="Invalid value">AF_inet</error>
RestrictAddressFamilies=<error descr="Invalid value">AF_INET, AF_INET6</error>
RestrictAddressFamilies=<error descr="Invalid value">~ AF_PACKET</error>
RestrictAddressFamilies=<error descr="Invalid value">NONE</error>
""".trimIndent()

setupFileInEditor("file.service", file)
enableInspection(InvalidValueInspection::class.java)
val highlights = myFixture.doHighlighting()

assertSize(5, highlights)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
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 ConfigParseCpuQuotaOptionValueTest : AbstractUnitFileTest() {

@Test
fun testValidValues() {
// language="unit file (systemd)"
val file = """
[Service]
CPUQuota=50%
CPUQuota=100%
CPUQuota=200%
CPUQuota=12.34%
CPUQuota=1.5%
CPUQuota=0.01%
CPUQuota=99.99%
CPUQuota=1000%
""".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]
CPUQuota=<error descr="Invalid value">50</error>
CPUQuota=<error descr="Invalid value">abc</error>
CPUQuota=<error descr="Invalid value">-5%</error>
CPUQuota=<error descr="Invalid value">12.345%</error>
CPUQuota=<error descr="Invalid value">50% 60%</error>
""".trimIndent()

setupFileInEditor("file.service", file)
enableInspection(InvalidValueInspection::class.java)
val highlights = myFixture.doHighlighting()

assertSize(5, highlights)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
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 ConfigParseDelegateOptionValueTest : AbstractUnitFileTest() {

@Test
fun testValidValues() {
// language="unit file (systemd)"
val file = """
[Service]
Delegate=yes
Delegate=no
Delegate=true
Delegate=false
Delegate=cpu
Delegate=cpu memory io
Delegate=cpu cpuacct cpuset io blkio memory devices pids
Delegate=bpf-firewall bpf-devices bpf-foreign
Delegate=bpf-socket-bind bpf-restrict-network-interfaces bpf-bind-network-interface
""".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]
Delegate=<error descr="Invalid value">maybe</error>
Delegate=<error descr="Invalid value">cpu unknown</error>
Delegate=<error descr="Invalid value">CPU</error>
Delegate=<error descr="Invalid value">cpu,memory</error>
""".trimIndent()

setupFileInEditor("file.service", file)
enableInspection(InvalidValueInspection::class.java)
val highlights = myFixture.doHighlighting()

assertSize(4, highlights)
}
}
Loading
Loading