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 @@ -10,6 +10,15 @@ import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai.*
fun getAllAIGeneratedValidators(): Map<Validator, OptionValueInformation> {
val allValidators = mapOf(
Validator("config_parse_6rd_prefix", "0") to ConfigParse6rdPrefixOptionValue() as OptionValueInformation,
Validator("config_parse_set_credential", "0") to ConfigParseSetCredentialOptionValue() as OptionValueInformation,
Validator("config_parse_set_credential", "1") to ConfigParseSetCredentialOptionValue() as OptionValueInformation,
Validator("config_parse_load_credential", "0") to ConfigParseLoadCredentialOptionValue() as OptionValueInformation,
Validator("config_parse_load_credential", "1") to ConfigParseLoadCredentialOptionValue() as OptionValueInformation,
Validator("config_parse_log_namespace", "0") to ConfigParseLogNamespaceOptionValue() as OptionValueInformation,
Validator("config_parse_log_extra_fields", "0") to ConfigParseLogExtraFieldsOptionValue() as OptionValueInformation,
Validator("config_parse_exec_selinux_context", "0") to ConfigParseExecSelinuxContextOptionValue() as OptionValueInformation,
Validator("config_parse_exec_smack_process_label", "0") to ConfigParseExecSmackProcessLabelOptionValue() as OptionValueInformation,
Validator("config_parse_unset_environ", "0") to ConfigParseUnsetEnvironOptionValue() as OptionValueInformation,
Validator("config_parse_unit_string_printf", "0") to ConfigParseUnitStringPrintfOptionValue() as OptionValueInformation,
Validator("config_parse_ip_filter_bpf_progs", "0") to ConfigParseIpFilterBpfProgsOptionValue() as OptionValueInformation,
Validator("config_parse_user_group_compat", "0") to ConfigParseUserGroupCompatOptionValue() as OptionValueInformation,
Expand Down
Original file line number Diff line number Diff line change
@@ -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 SELinuxContext=.
*
* C function: config_parse_exec_selinux_context in src/core/load-fragment.c. An optional leading
* '-' marks the assignment as "ignore failures"; the remainder is run through unit_full_printf()
* (specifier expansion) and stored verbatim -- there is no constraint on the context string
* itself. So, as with config_parse_unit_string_printf, the only meaningful check is specifier
* validity: every '%' must be '%%' or a valid unit specifier. The empty value resets the field.
*/
class ConfigParseExecSelinuxContextOptionValue : SimpleGrammarOptionValues(
"config_parse_exec_selinux_context",
SequenceCombinator(
RegexTerminal(".*", "-?(?:[^%]|%%|%[iIjJnNpPfyYcrRCdDELSthsaAbBHlqmMovwWgGuUTV])*"),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -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 SmackProcessLabel=.
*
* C function: config_parse_exec_smack_process_label in src/core/load-fragment.c. Identical shape
* to SELinuxContext=: an optional leading '-' marks "ignore failures"; the remainder is run
* through unit_full_printf() and stored verbatim with no constraint on the label string. The only
* meaningful check is specifier validity ('%' must be '%%' or a valid unit specifier). The empty
* value resets the field.
*/
class ConfigParseExecSmackProcessLabelOptionValue : SimpleGrammarOptionValues(
"config_parse_exec_smack_process_label",
SequenceCombinator(
RegexTerminal(".*", "-?(?:[^%]|%%|%[iIjJnNpPfyYcrRCdDELSthsaAbBHlqmMovwWgGuUTV])*"),
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 LoadCredential= (ltype 0) and LoadCredentialEncrypted= (ltype 1).
*
* C function: config_parse_load_credential in src/core/load-fragment.c. The value is "<id>" or
* "<id>:<source>": the id must satisfy credential_name_valid() (non-empty, not "."/"..", no '/',
* no ':', no control, <= NAME_MAX); the optional source is either an absolute (normalized) path or
* another credential name. The source is left loosely constrained (any non-control text) to avoid
* false positives.
*
* Composed as id + optional(':' + source) so an invalid id localizes to the id.
*/
class ConfigParseLoadCredentialOptionValue : SimpleGrammarOptionValues(
"config_parse_load_credential",
SequenceCombinator(
RegexTerminal("[^:]+", "(?!\\.\\.?(?::|$))[^/:\\x00-\\x1F]{1,255}"),
ZeroOrOne(SequenceCombinator(LiteralChoiceTerminal(":"), RegexTerminal(".*", "[^\\x00-\\x1F]*"))),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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 LogExtraFields=.
*
* C function: config_parse_log_extra_fields in src/core/load-fragment.c. The value is a
* whitespace-separated list of "FIELD=value" entries; each FIELD must be a valid journal field
* name (journal_field_valid, src/libsystemd/sd-journal): 1-64 characters, only A-Z 0-9 '_', not
* starting with a digit or '_'. The value after '=' is arbitrary (binary-safe). Each entry must
* contain a '='.
*
* Composed from per-token combinators (field name, '=', value) repeated over whitespace so that an
* invalid entry localizes to that entry rather than invalidating the whole value.
*/
private val LOG_EXTRA_FIELD_ENTRY = SequenceCombinator(
RegexTerminal("[^=\\s]+", "[A-Z][A-Z0-9_]{0,63}"),
LiteralChoiceTerminal("="),
RegexTerminal("[^\\s]*", "[^\\s]*")
)

class ConfigParseLogExtraFieldsOptionValue : SimpleGrammarOptionValues(
"config_parse_log_extra_fields",
SequenceCombinator(
LOG_EXTRA_FIELD_ENTRY,
ZeroOrMore(SequenceCombinator(WhitespaceTerminal(), LOG_EXTRA_FIELD_ENTRY)),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -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 LogNamespace=.
*
* C function: config_parse_log_namespace in src/core/load-fragment.c -> log_namespace_name_valid()
* in src/basic/syslog-util.c. After specifier expansion the value must be string_is_safe with
* STRING_FILENAME semantics (no '/', not "."/"..", no control characters), a valid unit instance
* name, and <= LOG_NAMESPACE_MAX characters.
*
* Grammar: a single token of non-control, non-'/' characters (not "."/".."), <= 255 chars; '%'
* is allowed for specifier syntax. The empty value resets the field.
*/
class ConfigParseLogNamespaceOptionValue : SimpleGrammarOptionValues(
"config_parse_log_namespace",
SequenceCombinator(
RegexTerminal(".+", "(?!\\.\\.?$)[^/\\x00-\\x1F]{1,255}"),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
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 SetCredential= (ltype 0) and SetCredentialEncrypted= (ltype 1).
*
* C function: config_parse_set_credential in src/core/load-fragment.c. The value is "<id>:<data>":
* extract_first_word(sep ":") yields the id, which must satisfy credential_name_valid()
* (= filename_is_valid && fdname_is_valid, i.e. non-empty, not "."/"..", no '/', no ':', no
* control characters, <= NAME_MAX); the remainder is the credential data (an arbitrary
* C-unescaped string for ltype 0, Base64 for ltype 1). The data itself is left unconstrained (so
* invalid Base64 is a false-negative rather than a false-positive). The empty value resets the list.
*
* Composed as id + ':' + data so an invalid id localizes to the id rather than the whole value.
*/
class ConfigParseSetCredentialOptionValue : SimpleGrammarOptionValues(
"config_parse_set_credential",
SequenceCombinator(
RegexTerminal("[^:]+", "(?!\\.\\.?:)[^/:\\x00-\\x1F]{1,255}"),
LiteralChoiceTerminal(":"),
RegexTerminal(".*", ".*"),
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 UnsetEnvironment=.
*
* C function: config_parse_unset_environ in src/core/load-fragment.c. The value is a
* whitespace-separated list where each entry must be either a valid environment variable name
* (env_name_is_valid) or a full assignment (env_assignment_is_valid). An environment variable
* name matches [A-Za-z_][A-Za-z0-9_]*; an assignment is "NAME=value" with an arbitrary value.
*
* Composed from per-token combinators (name, optional '=' value) repeated over whitespace so that
* an invalid entry localizes to that entry rather than invalidating the whole value.
*/
private val UNSET_ENVIRON_ENTRY = SequenceCombinator(
RegexTerminal("[^=\\s]+", "[A-Za-z_][A-Za-z0-9_]*"),
ZeroOrOne(SequenceCombinator(LiteralChoiceTerminal("="), RegexTerminal("[^\\s]*", "[^\\s]*")))
)

class ConfigParseUnsetEnvironOptionValue : SimpleGrammarOptionValues(
"config_parse_unset_environ",
SequenceCombinator(
UNSET_ENVIRON_ENTRY,
ZeroOrMore(SequenceCombinator(WhitespaceTerminal(), UNSET_ENVIRON_ENTRY)),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
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 ConfigParseExecSelinuxContextOptionValueTest : AbstractUnitFileTest() {

@Test
fun testValidValues() {
// language=unit file (systemd)
val file = """
[Service]
SELinuxContext=system_u:system_r:httpd_t:s0
SELinuxContext=-system_u:object_r:foo_t
SELinuxContext=context for %i
""".trimIndent()

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

assertSize(0, highlights)
}

@Test
fun testInvalidValues() {
// Unknown specifier (%e) and a trailing bare '%'.
// language=unit file (systemd)
val file = """
[Service]
SELinuxContext=bad %e specifier
SELinuxContext=ends with %
""".trimIndent()

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

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

@Test
fun testValidValues() {
// language=unit file (systemd)
val file = """
[Service]
SmackProcessLabel=my-label
SmackProcessLabel=-optional-label
SmackProcessLabel=label-%i
""".trimIndent()

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

assertSize(0, highlights)
}

@Test
fun testInvalidValues() {
// Unknown specifier (%e) and a trailing bare '%'.
// language=unit file (systemd)
val file = """
[Service]
SmackProcessLabel=bad %e label
SmackProcessLabel=ends with %
""".trimIndent()

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

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

@Test
fun testValidValues() {
// language=unit file (systemd)
val file = """
[Service]
LoadCredential=mycred:/etc/mycred
LoadCredentialEncrypted=other:/run/creds/other
LoadCredential=justid
""".trimIndent()

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

assertSize(0, highlights)
}

@Test
fun testInvalidValues() {
// A '/' in the id and a ".." id are rejected by credential_name_valid.
// language=unit file (systemd)
val file = """
[Service]
LoadCredential=bad/id:/secret
LoadCredentialEncrypted=..:/secret
""".trimIndent()

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

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

@Test
fun testValidValues() {
// language=unit file (systemd)
val file = """
[Service]
LogExtraFields=FIELD=value
LogExtraFields=PRIORITY=6 MESSAGE_ID=abc
LogExtraFields=EMPTY=
""".trimIndent()

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

assertSize(0, highlights)
}

@Test
fun testInvalidValues() {
// Journal field names must be uppercase and each entry needs a '='.
// language=unit file (systemd)
val file = """
[Service]
LogExtraFields=lowercase=value
LogExtraFields=NOEQUALS
""".trimIndent()

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

assertSize(2, highlights)
}
}
Loading
Loading