Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix folder credential usage #541

Merged
merged 10 commits into from
Mar 16, 2019

Conversation

sirstrahd
Copy link
Contributor

This allows for folder credentials to be used, additionally to the current global ones. Tested it with both freestyle and pipeline (workflow) jobs, as well as the freestyle configuration dialog.
Should address #500 .


public StandardSlackService(String baseUrl, String teamDomain, String authTokenCredentialId, boolean botUser, String roomId) {
this(baseUrl, teamDomain, null, authTokenCredentialId, botUser, roomId, false);
public StandardSlackService(String baseUrl, String teamDomain, String authTokenCredentialId, boolean botUser, String roomId, Item item) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. We can't modify existing constructors as this is part of the public API unless we are sure they aren't in use, normally you would deprecate first
  2. I don't think we should be passing the Item down to this level, I haven't looked closely enough at the API but I would like to see a new constructor that passes a token that is guaranteed to be not null.
    The legacy constructors will still need to be able to find a credential but that will be deprecated and removed at a later date

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully I addressed the 2 issues. I deprecated the other constructors, but maybe it's too early for that?

Copy link
Member

@jetersen jetersen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some suggestion, when reviewing the code

public class CredentialsObtainer {

public static StringCredentials lookupCredentials(String credentialId, Item item) {
List<StringCredentials> credentials = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(StringCredentials.class, item, ACL.SYSTEM, Collections.emptyList());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please import, 187 characters hurts readability 😄

@@ -428,7 +430,14 @@ public SlackService newSlackService(AbstractBuild r, BuildListener listener) {
authToken = env.expand(authToken);
authTokenCredentialId = env.expand(authTokenCredentialId);
room = env.expand(room);
return new StandardSlackService(baseUrl, teamDomain, authToken, authTokenCredentialId, botUser, room, false, r.getProject());
final String populatedToken = CredentialsObtainer.getTokenToUse(authTokenCredentialId, r.getProject(), authToken);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r.getParent() is more correct but alas this is an AbstractBuild why is this named r 😭
Would you mind renaming the variable?

@@ -45,41 +45,70 @@
private String host = "slack.com";
private String baseUrl;
private String teamDomain;
private String token;
private String authTokenCredentialId;
private String token = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null is default 😕

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed all useless null initializations.

if (credentials != null) {
response = credentials.getSecret().getPlainText();
} else {
response = token;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this throw an exception if token is null please?
We get lots of issues falling through to the bottom because token and credential are both null

same on line 29

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All code paths on StandardSlackService should now throw an IllegalArgumentException if token is null.

if (populatedToken != null) {
return new StandardSlackService(baseUrl, teamDomain, botUser, room, false, populatedToken);
} else {
logger.log(Level.INFO, "No explicit token specified and could not obtain credentials for id: " + authTokenCredentialId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should throw an exception depending, or at least log a message to the build log as well
It shouldn't return a slack service as its not configured correctly

Copy link
Contributor Author

@sirstrahd sirstrahd Mar 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since now getTokenToUse throws an exception (as requested in another comment) this code is now unreachable so I'm removing it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... however, this will cause current misconfigured jobs to crash on notification calls, is that desirable? Should I surround the calls to slackFactory (which ends up calling this) with try catch blocks?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes given that the existing code does this we should keep doing it for now.


logger.fine("Using Integration Token.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't throw an exception if its not found,
Could this be moved to the legacy constructors instead?
and add the throwing of the exception?

final String populatedToken = CredentialsObtainer.getTokenToUse(tokenCredentialId, item, token);
if (populatedToken == null) {
listener.error(Messages
.NotificationFailedWithException(new IllegalArgumentException("the token with the provided ID could not be found and no token was specified")));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.NotificationFailedWithException(new IllegalArgumentException("the token with the provided ID could not be found and no token was specified")));
.NotificationFailedWithException(new IllegalArgumentException(String.format("The credential with ID %s could not be found and no token was specified", tokenCredentialId))));

this.botUser = botUser;
this.roomIds = roomId.split("[,; ]+");
this.replyBroadcast = replyBroadcast;
}


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove extra line break?

/**
* @deprecated use {@link #StandardSlackService(String, String, boolean, String, boolean, String)} instead}
*/
@Deprecated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check this when I test the code out, but can you make sure that none of these constructors are called anymore internally to the codebase?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just had a look, StandardSlackServiceTest are using the old constructors, could you update that please?
and any other places

Copy link
Contributor Author

@sirstrahd sirstrahd Mar 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're only used from tests. I'll adapt them.

timja and others added 2 commits March 15, 2019 18:28
Update IllegalArgumentException message

Co-Authored-By: sirstrahd <sirstrahd@gmail.com>
StringCredentials credentials = lookupCredentials(authTokenCredentialId);
private String getTokenToUse(String authTokenCredentialId, String token) {
if (!StringUtils.isEmpty(authTokenCredentialId)) {
StringCredentials credentials = CredentialsObtainer.lookupCredentials(authTokenCredentialId, null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this have an overloaded method please so we don't have to pass null around?

Suggested change
StringCredentials credentials = CredentialsObtainer.lookupCredentials(authTokenCredentialId, null);
StringCredentials credentials = CredentialsObtainer.lookupCredentials(authTokenCredentialId);

@@ -59,6 +64,7 @@
private boolean replyBroadcast;



Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert?

Suggested change

else {
jsonString = JsonOutput.toJson(step.attachments);
}
final String jsonString;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what changed in this block? tabs to spaces or something? can't tell from github

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems something got merged into master that had a mix of tabs and spaces and my IDE "fixed" it...

Copy link
Member

@timja timja left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, I'll do some manual testing and merge this within the next few days

@timja
Copy link
Member

timja commented Mar 16, 2019

Just done some testing,
Found one issue:

Pipeline syntax can't find credentials in a folder currently
Url something like:
http://127.0.0.1:8070/jenkins/job/folder/job/folder-pipeline/pipeline-syntax/

The project is null here:

public ListBoxModel doFillTokenCredentialIdItems(@AncestorInPath Project project) {

@timja
Copy link
Member

timja commented Mar 16, 2019

I've pushed a commit to fix it

@jsoref
Copy link
Contributor

jsoref commented Jun 10, 2019

Fwiw, whatever you did here resulted in totally unhelpful debugging.

The global config UI has a nice test button, and that apparently is happy w/ system scoped credentials, but the pipeline editor ui isn't happy w/ system scoped credentials.

This, amongst other things, resulted in significant confusion and pain when debugging.

@timja
Copy link
Member

timja commented Jun 11, 2019

Unfortunately that's how jenkins works =/
The credentials are scoped to the nearest Item or if none then the Jenkins system scope.
I'm not sure if there's a way to stop system credentials working in the global test configuration

Edit: I guess you can probably check the scope in the validate function

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants