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
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 

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

Tuncay Senturk
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