i have setup a parametrized job for self-service deployments in Jenkins.
Users can select a version of the application and the environment to deploy to.
The available environments displayed to the user is currently just a static list of strings (choice parameter).
Now i want to restrict deployments to some environments based on the LDAP-groups of the current user.
The user-page in jenkins displays something like:
Jenkins Benutzer Id: maku
Groups:
adm_proj_a
nexus_admin
ROLE_ADM_PROJ_XY
ROLE_BH_KK
How do i get these groups within a groovy-script?
I tried to use dynamic choice parameter (scriptler) and get the LDAP-groups using a groovy-script but did not find my way through the Jenkins-API.
Any hints welcome
User.getAuthorities() requires the caller to have the ADMINISTER permission. (http://javadoc.jenkins-ci.org/hudson/model/User.html#getAuthorities())
An alternative is to query the SecurityRealm directly.
import hudson.model.*
import jenkins.model.*
def userid = User.current().id
def auths = Jenkins.instance.securityRealm.loadUserByUsername(userid)
.authorities.collect{a -> a.authority}
if("adm_proj_a" in auths){
...
I found a solution. Just in case anybody is interested:
Within scriptler i created a script groovy-script similar to this:
import hudson.model.*
def allowed_environments = ["dev","test","test-integration"]
if ("adm_proj_a" in User.current().getAuthorities() )
{
allowed_environments.add("production")
}
return allowed_environments
This script is used by dynamic choice parameter (scriptler) within my Jenkins-Job.
Now only users within the group adm_proj_a can see production as a choice.
Like ffghfgh wrote getAuthorities method requires administrator permission.Use the following:
def auth = hudson.model.User.current().impersonate().getAuthorities().collect {it.getAuthority()}
if ("adm_proj_a" in auth){
// do something
}
Jenkins may ask admin account to approve script in "scriptApproval" section
Related
I'm not sure if this is possible, since flow names are assigned later when a flow is actually run (aka, "creepy-lemur" or whatnot), but I'd like to define a Prefect task within a flow and have that task collect the name of the flow that ran it, so I can insert it into a database table. Has anyone figured out how to do this?
You can get the flow run name and ID from the context:
import prefect
from prefect import task, flow
#task
def print_task_context():
print("Task run context:")
print(prefect.context.get_run_context().task_run.dict())
#flow
def main_flow():
print_task_context()
print("Flow run context:")
print(prefect.context.get_run_context().flow_run.dict())
if __name__ == "__main__":
main_flow()
Here are more resources on Prefect Discourse about setting custom run names:
https://discourse.prefect.io/tag/task_run_name
https://discourse.prefect.io/tag/flow_run_name
I'm trying to create number of users with specific permissions via projectMatrixAuthorizationStrategy by groovy script. Actually, I'm able to create Users and provide permissions to the user, but when try to create another user with specific permissions, the old user access is automatically wiping out. when try to login with old user i'm getting " Overall/Read permission is missing" .
I have tried multiple ways but didn't get any solution about this. Here below is my script
import jenkins.model.*
import hudson.security.*
import hudson.model.*
import java.util.*
import com.michelin.cio.hudson.plugins.rolestrategy.*
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.common.*
import com.cloudbees.plugins.credentials.domains.*
import com.cloudbees.jenkins.plugins.sshcredentials.impl.*
def instance = Jenkins.getInstance()
def hudsonRealm = new HudsonPrivateSecurityRealm(false)
//def user = ["userInput","userPassword"]
hudsonRealm.createAccount("admin","admin")
//hudsonRealm.createAccount(userInput,userPassword)
hudsonRealm.createAccount("user","User2")
instance.setSecurityRealm(hudsonRealm)
instance.save()
def strategy = new ProjectMatrixAuthorizationStrategy()
//Overall Permission
strategy.add(Jenkins.ADMINISTER,'admin')
strategy.add(Jenkins.READ,user)
//Credential Level Permission
strategy.add(com.cloudbees.plugins.credentials.CredentialsProvider.CREATE,user)
strategy.add(com.cloudbees.plugins.credentials.CredentialsProvider.DELETE,user)
strategy.add(com.cloudbees.plugins.credentials.CredentialsProvider.UPDATE,user)
strategy.add(com.cloudbees.plugins.credentials.CredentialsProvider.VIEW,user)
//Job Level Permission
strategy.add(hudson.model.Item.BUILD,user)
strategy.add(hudson.model.Item.CANCEL,user)
strategy.add(hudson.model.Item.CONFIGURE,user)
strategy.add(hudson.model.Item.CREATE,user)
//strategy.add(hudson.model.Item.DELETE,user)
strategy.add(hudson.model.Item.DISCOVER,user)
//strategy.add(hudson.model.Item.READ,user)
strategy.add(hudson.model.Item.WORKSPACE,user)
//Build Run (Level) Permissions
//strategy.add(hudson.model.Run.DELETEuser)
strategy.add(hudson.model.Run.UPDATE,user)
//strategy.add(hudson.model.Run.REPLAY,user)
//View Level Permissions
//strategy.add(hudson.model.View.CONFIGURE,user)
//strategy.add(hudson.model.View.CREATE,user)
//strategy.add(hudson.model.View.DELETE,user)
strategy.add(hudson.model.View.READ,user)
instance.setAuthorizationStrategy(strategy)
instance.save()
}
}}
could somebody help me to sort out the issue?
Solution: Actually it is very simple thing to know.
If you don't like to wiping out old user access, you shouldn't give user name in the permission line, instead you should give 'authenticated'. see the example below..,
From
strategy.add(Jenkins.READ,user)
strategy.add(com.cloudbees.plugins.credentials.CredentialsProvider.CREATE,user)
to
strategy.add(Jenkins.READ,'authenticated')
strategy.add(com.cloudbees.plugins.credentials.CredentialsProvider.CREATE,'authenticated')
I'm starting with BDD (cucumber + capybara + selenium chromedriver) and TDD (rspec) with factory_bot and I'm getting an error on cucumber features - step_definitions.
uninitialized constant User (NameError)
With TDD, everything is ok, the factory bot is working fine. The problem is with the cucumber.
factories.rb
FactoryBot.define do
factory :user_role do
name {"Admin"}
query_name {"admin"}
end
factory :user do
id {1}
first_name {"Mary"}
last_name {"Jane"}
email {"mary_jane#gmail.com"}
password {"123"}
user_role_id {1}
created_at {'1/04/2020'}
end
end
support/env.rb
require 'capybara'
require 'capybara/cucumber'
require 'selenium-webdriver'
require 'factory_bot_rails'
Capybara.register_driver :selenium do |app|
Capybara::Selenium::Driver.new(app, browser: :chrome)
end
Capybara.configure do |config|
config.default_driver = :selenium
end
Capybara.javascript_driver = :chrome
World(FactoryBot::Syntax::Methods)
And the problem is happening here
support/hooks.rb
Before '#admin_login' do
#user = create(:user)
end
step_definitions/admin_login.rb
Given("a registered user with the email {string} with password {string} exists") do |email, password|
#user
end
I don't know why, but I can't access the user using cucumber and factory_bot.
Anybody could help me please?
I think I need to configure something on the cucumber.
What do you think guys?
First of all Luke is correct about this being a setup issue. The error is telling you that the User model cannot be found which probably means Rails is not yet loaded. I can't remember the exact details of how cucumber-rails works but one of the things it does is to make sure that each scenario becomes an extension of a Rails integration test. This ensures that all of the Rails auto-loading has taken place and that these things are available.
Secondly I'd suggest you start simpler and use a step to create your registered user rather than using a tag. Using tags for setup is a Cucumber anti-pattern.
Finally, and more controversially I'd suggest that you don't use factory-bot when cuking. FactoryBot uses a separate configuration to create model objects directly in the datastore. This bypasses any application logic around the creation of these objects, which means the objects created by FactoryBot are going to end up being different from the objects created by your application. In real life object creation involves things like auditing, sending emails, conditional logic etc. etc. To use FactoryBot you either have to duplicate that additional creation logic and behavior or ignore it (both choices are undesirable).
You can create objects for cuking much more effectively (and quicker) by using the following pattern.
Each create method in the Rails controller delegates its work to a service object e.g.
UserController
def create
#user = CreateUserService.new(params).call
end
end
Then have your cukes use a helper module to create things for you. This module will provide tools for your steps to create users, using the above service
module UserStepHelper
def create_user(params)
CreateUserService.new(default_params.merge(params))
end
def default_params
{
...
}
end
end
World UserStepHelper
Given 'there is a registered user' do
#registered_user = create_user
end
and then use that step in the background of your feature e.g.
Background:
Given there is a registered user
And I am an admin
Scenario: Admin can see registered users
When I login and view users
Then I should see a user
Notice the absence of tagging here. Its not desirable or necessary here.
You can see an extension of this approach in a sample application I did for a CukeUp talk in 2013 here https://github.com/diabolo/cuke_up/commits/master. If you follow this commit by commit starting from first commit at the bottom you will get quite a good guide to setting up a rails project with cucumber in just the first 4 or 4 commits. If you follow it through to the end (22 commits) you'll get a basic powerful framework for creating and using model objects when cuking. I realize the project is ancient and that obviously you will have to use modern versions of everything, but the principles still apply, and I use this approach in all my work and having been doing so for at least 10 years.
So if you're using rails, it's probably advised to use cucumber-rails over cucumber. This is probably an issue where your User models have not been auto-loaded in.
Cucumber auto-loads all ruby files underneath features, with env.rb first, it's almost certainly an issue with load order / load location
I have a Jenkins multi-branch pipeline for building artifacts and there are branches for master, *-dev etc.
I want to enable project based security on a per branch basis, ie only allow devs to run the *-dev branch jobs of the build not any other ones because doing so would have undesirable effects.
I know there is project based security, but I didn't see any per branch. Does this exist? We are behind in updating Jenkins and are currently running Jenkins 2.46.1.
Otherwise I am thinking I might have to have a separate upstream job to call the correct branch of the downstream one and make the downstream artifact job unable to be run by devs with the privilege to do so. (This sounds like overkill).
Or is there any way to accomplish this in the branch's Jenkinsfile?
Here's some Jenkinsfile groovy that will get you close to what you want:
// return the user id that caused this build; else empty string
#NonCPS
def user_id_cause() {
def CAUSE = currentBuild.rawBuild.getCause(
hudson.model.Cause.UserIdCause.class
);
return CAUSE ? CAUSE.getUserId() : "";
}
// return all groups to which the given user id belongs
#NonCPS
def groups(USER_ID) {
return Jenkins.instance.securityRealm.loadUserByUsername(USER_ID).authorities.collect{ it.toString() };
}
...
env.USER_ID_CAUSE = user_id_cause();
if (!env.BRANCH_NAME.endsWith('-dev')) {
if (env.USER_ID_CAUSE) {
if ('jenkins_admins' in groups(env.USER_ID_CAUSE)) {
echo("INFO: user id `${env.USER_ID_CAUSE}` is in the group `jenkins_admins`.");
} else {
currentBuild.result = 'ABORTED';
error("user id `${env.USER_ID_CAUSE}` is not in the group `jenkins_admins`.");
}
}
}
Caveats:
These tricks rely heavily on API functions that require "In-process Script Approval" by a Jenkins administrator.
The above example assumes the existence of the jenkins_admins group to which privileged users belong --- your user/groups situation may be very different.
In general, playing with objects returned from Jenkins API functions should be done within #NonCPS-annotated functions --- you risk java.io.NotSerializableException otherwise.
References:
https://github.com/jenkinsci/workflow-cps-plugin/blob/master/README.md
http://javadoc.jenkins-ci.org/hudson/model/Cause.UserCause.html
http://javadoc.jenkins-ci.org/hudson/model/Run.html#getCause-java.lang.Class-
http://javadoc.jenkins.io/hudson/security/SecurityRealm.html#loadUserByUsername-java.lang.String-
Does somebody know how I can import all members of one group into another in GitLab, rather than doing it manually one by one?
The only native feature which comes close is in lib/tasks/gitlab/bulk_add_permission.rake, which is mentioned in "User management"
# omnibus-gitlab
sudo gitlab-rake gitlab:import:all_users_to_all_groups
# installation from source
bundle exec rake gitlab:import:all_users_to_all_groups RAILS_ENV=production
You could take that as a model to develop our own task.
I am not aware of such a feature. But you can script it with the API. We use it here to add all users to one single group (all users to all groups is not feasible for our case).
Helpful documentation: http://doc.gitlab.com/ce/api/README.html, http://doc.gitlab.com/ce/api/users.html and http://doc.gitlab.com/ce/api/groups.html
There is also a respond to another question that might be helpful and lists also various modules for various programming languages: Is there a way to add users automatically into gitlab?
I was looking for a solution to Assign all Gitlab users to one particular group.
Here's the solution:
Create this file:
/opt/gitlab/embedded/service/gitlab-rails/lib/tasks/gitlab/finder_import.rake
With this content:
namespace :gitlab do namespace :finder do
desc "GitLab | Add all users to group Colaboradores (admin users are added as owners)"
task importall: :environment do |t, args|
user_ids = User.where(admin: false).pluck(:id)
admin_ids = User.where(admin: true).pluck(:id)
groups = Group.where(name: "Colaboradores")
puts "Importing #{user_ids.size} users into #{groups.size} groups"
puts "Importing #{admin_ids.size} admins into #{groups.size} groups"
groups.each do |group|
puts "Importing into #{group.name}"
group.add_users(user_ids, GroupMember::DEVELOPER)
group.add_users(admin_ids, GroupMember::OWNER)
end
end
end end
Run this command:
gitlab-rake gitlab:finder:importall