Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

How to get other field value for Custom Picker field

Jakub Gawinkowski January 10, 2025

Hi,

I’m trying to configure dynamic multi-select Custom Picker field “Hyp. Mitre Techniques“. Values show by that field should depend on value from multi-select Custom Picker field “Hyp. Mitre Tactics“.

 

“Hyp. Mitre Tactics“ is developed and working fine. I can’t read value of this field in my script for “Hyp. Mitre Techniques“. I’m trying to do it following way

import com.atlassian.jira.issue.Issue
Issue issuedef mitre_tactic = issue.getCustomFieldValue("Hyp. Mitre Tactics")
But it results in error
java.lang.NullPointerException: Cannot invoke method getCustomFieldValue() on null object	at Script285.run(Script285.groovy:6)

How can I get value of other field in Custom Picker?

Here is my code for both fields

Hyp. Mitre Tactics

 

import com.onresolve.scriptrunner.canned.jira.fields.model.PickerOption

import org.apache.commons.lang3.StringUtils

def options = [

    [tactic: "TA0001 Initial Access"],

    [tactic: "TA0002 Execution"],

    [tactic: "TA0003 Persistence"],

    [tactic: "TA0004 Privilege Escalation"],

    [tactic: "TA0005 Defense Evasion"],

    [tactic: "TA0006 Credential Access"],

    [tactic: "TA0007 Discovery"],

    [tactic: "TA0008 Lateral Movement"],

    [tactic: "TA0009 Collection"],

    [tactic: "TA0010 Exfiltration"],

    [tactic: "TA0011 Command and Control"],

    [tactic: "TA0040 Impact"],

    [tactic: "TA0042 Resource Development"],

    [tactic: "TA0043 Reconnaissance"]

]

search = { String inputValue ->

    options.findAll {

        StringUtils.containsIgnoreCase(it.tactic, inputValue)

    }

}

getItemFromId = { String id ->

    options.find { it.tactic == id }

}

toOption = { Map<String, String> option, Closure highlight ->

    new PickerOption(value: option.tactic,

            html: "${highlight(option.tactic, false)}"

    )

}

renderItemViewHtml = { Map<String, String> option ->

    "$option.tactic"

}

renderItemTextOnlyValue = { Map<String, String> option ->

    option.id

}
Hyp. Mitre Techniques

 

import com.onresolve.scriptrunner.canned.jira.fields.model.PickerOption

import org.apache.commons.lang3.StringUtils

import com.atlassian.jira.issue.Issue


Issue
issue

def mitre_tactic = issue.getCustomFieldValue("Hyp. Mitre Tactics")


def picker_options = [

    "TA0011 Command and Control": [

        [technique: "T1001 Data Obfuscation"],

        [technique: "T1008 Fallback Channels"],

        [technique: "T1071 Application Layer Protocol"],

        [technique: "T1090 Proxy"],

        [technique: "T1092 Communication Through Removable Media"],

        [technique: "T1095 Non-Application Layer Protocol"],

        [technique: "T1102 Web Service"],

        [technique: "T1104 Multi-Stage Channels"],

        [technique: "T1105 Ingress Tool Transfer"],

        [technique: "T1132 Data Encoding"],

        [technique: "T1205 Traffic Signaling"],

        [technique: "T1219 Remote Access Software"],

        [technique: "T1568 Dynamic Resolution"],

        [technique: "T1571 Non-Standard Port"],

        [technique: "T1572 Protocol Tunneling"],

        [technique: "TT1573 Encrypted Channel"]

    ],

    "TA0006 Credential Access": [

        [technique: "T1003 OS Credential Dumping"],

        [technique: "T1040 Network Sniffing"],

        [technique: "T1056 Input Capture"],

        [technique: "T1110 Brute Force"],

        [technique: "T1111 Multi-Factor Authentication Interception"],

        [technique: "T1187 Forced Authentication"],

        [technique: "T1212 Exploitation for Credential Access"],

        [technique: "T1528 Steal Application Access Token"],

        [technique: "T1539 Steal Web Session Cookie"],

        [technique: "T1552 Unsecured Credentials"],

        [technique: "T1555 Credentials from Password Stores"],

        [technique: "T1556 Modify Authentication Process"],

        [technique: "T1557 Adversary-in-the-Middle"],

        [technique: "T1558 Steal or Forge Kerberos Tickets"],

        [technique: "T1606 Forge Web Credentials"],

        [technique: "T1621 Multi-Factor Authentication Request Generation"]

    ]

]

def options = []

for (tactic in mitre_tactic){

    def tactic_options = picker_options.get(tactic)

    options.addAll(tactic_options)

}

search = { String inputValue ->

    options.findAll {

        StringUtils.containsIgnoreCase(it.technique, inputValue)

    }

}

getItemFromId = { String id ->

    options.find { it.technique == id }

}

toOption = { Map<String, String> option, Closure highlight ->

    new PickerOption(value: option.technique,

            html: "${highlight(option.technique, false)}"

    )

}

renderItemViewHtml = { Map<String, String> option ->

    "$option.technique"

}

renderItemTextOnlyValue = { Map<String, String> option ->

    option.id

}

2 answers

1 accepted

0 votes
Answer accepted
Jakub Gawinkowski January 13, 2025

I resolved my problem. I had to define issue in inputs for search function and in getItemFromId function I had to provide list of all possible options. After that I was able to read field value inside that functions.

I created additional technique_searcher function to prepare filtered options list for "search" function and all options list for "getItemFromId" function

 

 

import com.onresolve.scriptrunner.canned.jira.fields.model.PickerOption
import org.apache.commons.lang3.StringUtils
import com.atlassian.jira.issue.Issue

def technique_searcher(issue) {    

    def picker_options = [
        "TA0011 Command and Control": [
            [technique: "T1001 Data Obfuscation"],
            [technique: "T1008 Fallback Channels"],
            [technique: "T1071 Application Layer Protocol"],
            [technique: "T1090 Proxy"],
            [technique: "T1092 Communication Through Removable Media"],
            [technique: "T1095 Non-Application Layer Protocol"],
            [technique: "T1102 Web Service"],
            [technique: "T1104 Multi-Stage Channels"],
            [technique: "T1105 Ingress Tool Transfer"],
            [technique: "T1132 Data Encoding"],
            [technique: "T1205 Traffic Signaling"],
            [technique: "T1219 Remote Access Software"],
            [technique: "T1568 Dynamic Resolution"],
            [technique: "T1571 Non-Standard Port"],
            [technique: "T1572 Protocol Tunneling"],
            [technique: "T1573 Encrypted Channel"]
        ],
        "TA0006 Credential Access": [
            [technique: "T1003 OS Credential Dumping"],
            [technique: "T1040 Network Sniffing"],
            [technique: "T1056 Input Capture"],
            [technique: "T1110 Brute Force"],
            [technique: "T1111 Multi-Factor Authentication Interception"],
            [technique: "T1187 Forced Authentication"],
            [technique: "T1212 Exploitation for Credential Access"],
            [technique: "T1528 Steal Application Access Token"],
            [technique: "T1539 Steal Web Session Cookie"],
            [technique: "T1552 Unsecured Credentials"],
            [technique: "T1555 Credentials from Password Stores"],
            [technique: "T1556 Modify Authentication Process"],
            [technique: "T1557 Adversary-in-the-Middle"],
            [technique: "T1558 Steal or Forge Kerberos Tickets"],
            [technique: "T1606 Forge Web Credentials"],
            [technique: "T1621 Multi-Factor Authentication Request Generation"]
        ]
    ]

    def options = new HashSet<>()
    if (issue == null){
        picker_options.each {tactic, techniquesList ->
            options.addAll(techniquesList)
        }
    } else {
        def mitre_tactic = issue.getCustomFieldValue("Hyp. Mitre Tactics")
        for (tactic in mitre_tactic){
            def tactic_options = picker_options.get(tactic)
            if(tactic_options){
                options.addAll(tactic_options)
            }
        }
    }

    return options.toList()
}

search = { String inputValue, Issue issue ->
    def options = technique_searcher(issue)

    options.findAll {
        StringUtils.containsIgnoreCase(it.technique, inputValue)
    }

}

getItemFromId = { String id ->
    Issue issue //issue definition added. It has to be here even if it is expected null

    def options = technique_searcher(issue) 

    options.find { it.technique = id}
}

toOption = { Map<String, String> option, Closure highlight ->
    new PickerOption(value: option.technique,
            html: "${highlight(option.technique, false)}"
    )
}

renderItemViewHtml = { Map<String, String> option ->
    "$option.technique"
}

renderItemTextOnlyValue = { Map<String, String> option ->
    option.technique
}
0 votes
Tuncay Senturk _Snapbytes_
Community Champion
January 10, 2025

Hi @Jakub Gawinkowski 

In the context of ScriptRunner, you use issue directly, you don't need to define it. remove this definition

Issue issue

and use something like below

def customFieldManager = ComponentAccessor.getCustomFieldManager() 
def tacticField = customFieldManager.getCustomFieldObjectByName("Hyp. Mitre Tactics")
def mitre_tactic = issue?.getCustomFieldValue(tacticField)
if (!mitre_tactic) {
mitre_tactic = []
}
...
Jakub Gawinkowski January 12, 2025

Hi @Tuncay Senturk _Snapbytes_ 

I tried to do it like that but it shows that "issue" is undeclaredhyp Mitre Techniques.png

Tuncay Senturk _Snapbytes_
Community Champion
January 13, 2025

Did you try to run it? Sometimes the editor shows compile errors but it may run ok.

Jakub Gawinkowski January 13, 2025

Yes i tried. I returns following error

groovy.lang.MissingPropertyException: No such property: issue for class: Script269
 at Script269.run(Script269.groovy:12)

 

Suggest an answer

Log in or Sign up to answer