module PWN::Plugins::Jenkins

def self.add_job_to_nested_view(opts = {})

)
job_name: 'required view path attach to a view',
view_path: 'required view path associate job',
jenkins_obj: 'required jenkins_obj returned from #connect method',
PWN::Plugins::Jenkins.add_job_to_nested_view(
Supported Method Parameters::
def self.add_job_to_nested_view(opts = {})
  jenkins_obj = opts[:jenkins_obj]
  view_path = opts[:view_path].to_s.scrub
  job_name = opts[:job_name].to_s.scrub
  jenkins_obj.api_post_request("#{view_path}/addJobToView?name=#{job_name}")
rescue StandardError => e
  raise e
end

def self.authors

def self.authors
st.pentest@0dayinc.com>

def self.clear_build_queue(opts = {})

def self.clear_build_queue(opts = {})
[:jenkins_obj]
list.each do |job_name|
learing #{job_name} Build from Queue")
stop_build(job_name)
 => e

def self.connect(opts = {})

def self.connect(opts = {})
.to_i ||= 8888
sername].to_s.scrub
ri = "https://#{ip}/ase/services".to_s.scrub
i_key].to_s.scrub
ts[:identity_file].to_s.scrub
 opts[:ssl] ||= false
[:proxy])
 proxy.scheme
.host
xy.port
ging into Jenkins Server: #{ip}")
&& api_key == ''
 == ''
JenkinsApi::Client.new(
p,
 port,
ects: true,
l,
ol: proxy_protocol,
oxy_ip,
proxy_port
JenkinsApi::Client.new(
p,
 port,
e: identity_file,
ects: true,
l,
ol: proxy_protocol,
oxy_ip,
proxy_port
lugins::AuthenticationHelper.mask_password if api_key == ''
nkinsApi::Client.new(

ort,
name,
key,
ts: true,

: proxy_protocol,
y_ip,
oxy_port
.wait_for_ready
 => e

def self.copy_job_no_fail_on_exist(opts = {})

def self.copy_job_no_fail_on_exist(opts = {})
[:jenkins_obj]
= opts[:existing_job_name]
s[:new_job_name]
nkins_obj.job.copy(existing_job_name, new_job_name)
xceptions::JobAlreadyExists => e
kins job: #{new_job_name} already exists")
 => e

def self.create_nested_view(opts = {})

def self.create_nested_view(opts = {})
[:jenkins_obj]
view_name].to_s.scrub
h = opts[:create_in_view_path].to_s.scrub
eter for modes and use case statement to build dynamically post_body
lugins.nested_view.NestedView' # Requires Jenkins Nested View Plugin to Work Properly
el.ListView'
ame,
_name,

r = [
_arr.include?(create_in_view_path)
reating Nested View in /...')
bj.api_post_request(

reating Nested View in #{create_in_view_path}...")
ath would be '/view/Projects/PROJECT_NAME/view/RELEASES'
out of the Jenkins URI when residing in the view in which
eate your view...simply drop the domain name.
bj.api_post_request(
iew_path}/createView",
xceptions::ViewAlreadyExists => e
kins view: #{view_name} already exists")
 => e

def self.create_ssh_credential(opts = {})

def self.create_ssh_credential(opts = {})
[:jenkins_obj]
sername].to_s.scrub
 opts[:private_key_path].to_s.strip.chomp.scrub
pts[:key_passphrase].to_s.scrub
ts[:credential_id].to_s.scrub
[:description].to_s.scrub
o_s.strip.chomp.scrub == 'GLOBAL' || opts[:domain].nil?
dentials/store/system/domain/_/createCredentials'
omain].to_s.strip.chomp.scrub
dentials/store/system/domain/#{domain}/createCredentials"
_s.strip.chomp.scrub == 'SYSTEM'


= ''
' => {
 scope,
 => username,
ySource' => {
-class' => 'com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource',
Key' => File.read(private_key_path)
e' => key_passphrase,
on' => description,
lass' => 'com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey'
' => {
 scope,
 => username,
ySource' => {
-class' => 'com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource',
Key' => File.read(private_key_path)
e' => key_passphrase,
edential_id,
on' => description,
lass' => 'com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey'
.api_post_request(
 => e

def self.create_user(opts = {})

def self.create_user(opts = {})
[:jenkins_obj]
sername].to_s.scrub
assword].to_s.scrub
ugins::AuthenticationHelper.mask_password if password == ''
ullname].to_s.scrub
l].to_s.scrub
ername,
assword,
assword,
llname,
,
username,
 password,
 password,
fullname,
il
ating #{username}...")
.api_post_request(
createAccountByAdmin',
:Exceptions::UserAlreadyExists => e
enkins view: #{view_name} already exists")
 => e

def self.delete_jobs_by_regex(opts = {})

def self.delete_jobs_by_regex(opts = {})
[:jenkins_obj]
x].to_s.scrub
st_all_with_details.each do |job|
name']
h?(/#{regex}/)
"Deleting #{job_name}")
b.delete(job_name)
 => e

def self.disable_jobs_by_regex(opts = {})

def self.disable_jobs_by_regex(opts = {})
[:jenkins_obj]
x].to_s.scrub
st_all_with_details.each do |job|
name']
h?(/#{regex}/)
"Disabling #{job_name}")
b.disable(job_name)
 => e

def self.disconnect(opts = {})

def self.disconnect(opts = {})
[:jenkins_obj]
connecting from Jenkins...')
 => e

def self.get_all_job_git_repos(opts = {})

def self.get_all_job_git_repos(opts = {})
[:jenkins_obj]
rieving a List of Git Repos from Every Job...')
st_all_with_details.each do |job|
kogiri::XML(jenkins_obj.job.get_config(job['name']))
this_config.xpath('//scm/userRemoteConfigs/hudson.plugins.git.UserRemoteConfig/url').text
= this_config.xpath('//scm/branches/hudson.plugins.git.BranchSpec/name').text
_repo == ''
s' git repos
}
me] = job['name']
l] = job['url']
b_state] = job['color']
t_repo] = this_git_repo
t_branch] = this_git_branch
nfig_xml_response] = this_config
h(job_git_repo)
 => e

def self.help

def self.help
self}.connect(
host/ip of Jenkins Server',
l tcp port (defaults to 8080),
ional username (functionality will be limited if ommitted)',
onal api_key (functionality will be limited if ommitted)',
 'optional ssh private key path to AuthN w/ Jenkins PREFERRED over username/api_key',
 connect over TLS (defaults to true),
al debug proxy rest api requests to jenkins (e.g. "http://127.0.0.1:8080")''
.public_methods
ser(
required - jenkins_obj returned from #connect method',
uired - user to create',
ional - password for new user (will prompt if nil)'
uired - full name of new user'
ed - email address of new user'
sh_credential(
required - jenkins_obj returned from #connect method',
uired - username for new credential'
th: 'required - path of private ssh key for new credential'
: 'optional - private key passphrase for new credential'
 'optional but recommended - useful when creating userland jobs',
optional - description of new credential'
nal - defaults to GLOBAL',
al - GLOBAL or SYSTEM (defaults to GLOBAL)'
{self}.get_all_job_git_repos(
required jenkins_obj returned from connect method'
s = #{self}.get_all_git_repo_branches_by_commit_date(
required jenkins_obj returned from #connect method',
uired jenkins job name',
ired git url for git_repo'
= #{self}.list_nested_jobs(
required jenkins_obj returned from #connect method',
quired view path list jobs'
 = #{self}.list_nested_views(
required jenkins_obj returned from #connect method',
quired view path list sub-views'
l = #{self}.create_nested_view(
required jenkins_obj returned from #connect method',
quired view path create',
_path: 'optional creates nested view within an existing nested view, defaults to / views'
d_view_resp = #{self}.add_job_to_nested_view(
required jenkins_obj returned from #connect method',
quired view path associate job',
uired view path attach to a view',
#{self}.copy_job_no_fail_on_exist(
required jenkins_obj returned from #connect method',
ame: 'required existing job to copt to new job',
'required name of new job'
jobs_by_regex(
required jenkins_obj returned from #connect method',
ed regex pattern for matching jobs to disable e.g. :regex => "^M[0-9]"',
ob_by_regex(
required jenkins_obj returned from #connect method',
ed regex pattern for matching jobs to disable e.g. :regex => "^M[0-9]"',
ild_queue(
required jenkins_obj returned from #connect method',
ct(
required jenkins_obj returned from connect method'

def self.list_nested_jobs(opts = {})

def self.list_nested_jobs(opts = {})
[:jenkins_obj]
view_path].to_s.scrub
 jenkins_obj.api_get_request(view_path)
jobs']
 => e

def self.list_nested_views(opts = {})

def self.list_nested_views(opts = {})
[:jenkins_obj]
view_path].to_s.scrub
 jenkins_obj.api_get_request(view_path)
views']
 => e