Issue Summary

When a hook script is triggered, if the authenticated user doesn’t have an e-mail address (normal for service users, but also possible for users synchronized via LDAP), invoking the hook script will fail. For pre-update hook scripts, this will block the update. For post-update hook scripts the update will have already completed, but whatever action(s) the hook script is intended to apply will not run.

Environment

Hook scripts are only usable via third-party add-ons, such as External Hooks, so such an add-on must be installed to trigger this issue.

Steps to Reproduce

  • Install a third-party hooks app
  • Set up a hook script
  • Trigger an update using a service user account (SSH access keys, for example) or a normal user account without an e-mail address
  • Expected Results

    Hook scripts are invoked.

    Actual Results

    Preparing the environment for the hook script fails and the hook script is not invoked. If the hook script is pre-update, the update is rejected.

    The below exception is logged:

    java.lang.NullPointerException: null value in entry: BB_USER_EMAIL=null
    at com.google.common.collect.CollectPreconditions.checkEntryNotNull(CollectPreconditions.java:32)
    at com.google.common.collect.ImmutableMap.entryOf(ImmutableMap.java:176)
    at com.google.common.collect.ImmutableMap$Builder.put(ImmutableMap.java:285)
    at com.atlassian.stash.internal.hook.script.DefaultHookScriptEnvironmentProvider.userDetails(DefaultHookScriptEnvironmentProvider.java:203)
    at com.atlassian.stash.internal.hook.script.DefaultHookScriptEnvironmentProvider.create(DefaultHookScriptEnvironmentProvider.java:115)
    at com.atlassian.stash.internal.hook.script.DefaultHookScriptInvoker.lambda$prepareEnvironment$1(DefaultHookScriptInvoker.java:286)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
    at com.atlassian.stash.internal.hook.script.DefaultHookScriptInvoker.prepareEnvironment(DefaultHookScriptInvoker.java:287)
    at com.atlassian.stash.internal.hook.script.DefaultHookScriptInvoker.postUpdate(DefaultHookScriptInvoker.java:114)
    at com.atlassian.stash.internal.plugin.OsgiSafeProxyProvider$1.invoke(OsgiSafeProxyProvider.java:95)
    at com.atlassian.stash.internal.hook.script.ScriptRepositoryHook.postUpdate(ScriptRepositoryHook.java:35)
    at com.atlassian.stash.internal.hook.repository.DefaultRepositoryHookService.postUpdate(DefaultRepositoryHookService.java:760)
    at com.atlassian.stash.internal.hook.repository.DefaultRepositoryHookService.lambda$doPostUpdate$7(DefaultRepositoryHookService.java:542)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
    at com.atlassian.stash.internal.hook.repository.DefaultRepositoryHookService.doPostUpdate(DefaultRepositoryHookService.java:526)
    at com.atlassian.stash.internal.hook.repository.DefaultRepositoryHookService.postUpdateSynchronous(DefaultRepositoryHookService.java:336)
    at com.atlassian.stash.internal.hook.DefaultBuiltInHookHandlerFactory.lambda$postReceive$1(DefaultBuiltInHookHandlerFactory.java:69)
    at com.atlassian.stash.internal.hook.DefaultHookService.doHandleRequest(DefaultHookService.java:301)
    at com.atlassian.stash.internal.hook.DefaultHookService.handleRequest(DefaultHookService.java:287)
    at com.atlassian.stash.internal.hook.DefaultHookService.handleRawRequest(DefaultHookService.java:221)
    at com.atlassian.stash.internal.hook.DefaultHookService$1.lambda$run$0(DefaultHookService.java:188)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.lang.Thread.run(Thread.java:748)
    

    Notes

    Reported via External Hooks issue #60.

    Workaround

    For normal users, update the user account to add an e-mail address. For service users there is no workaround.