How I Fixed: UglifyJs Unexpected token: name (DropIn)

I’ve been trying – in vain – to build the front end for CodeReviewVideos. The issue I have been hitting upon is as follows:

ERROR in app.a2e9a6b7afa471d94d2b.js from UglifyJs
Unexpected token: name (DropIn) [./node_modules/braintree-web-drop-in-react/dist/index.js:109,0][app.a2e9a6b7afa471d94d2b.js:116396,6]

uglifyjs-unexpected-token-name-dropin

As the error states, the issue is with the UglifyJs plugin, which I use in combination with WebPack.

This is a frustrating show-stopping problem. Unless fixed, I couldn’t complete a build.

Here’s what I had in my WebPack prod config:

      new webpack.optimize.UglifyJsPlugin({
        beautify: false,
        mangle: {
          screw_ie8: true,
          keep_fnames: true
        },
        compress: {
          screw_ie8: true,
          warnings: false
        },
        comments: false
      }),

This was only in my WebPack prod config. Therefore I didn’t notice any issue until trying to build for prod.

Now, in truth, I didn’t write the code / config above. I copy / pasted from somewhere else (I forget where) and as it just worked I didn’t pay much attention to it.

When it stopped working, I got sad, then got on to trying to fix it.

My Solution

There’s a bunch of suggested general solutions to this problem. A quick Google will turn up plenty of GitHub issues. Unfortunately none of them were specific to my exact error.

In my case, as best I understand it, the Braintree Web Drop In React should have compiled the dist.js file down to ES5, but is instead, in ES6. I concluded this based on this and this.

dammit-jim-im-a-coder-not-a-webpack-genius
Dammit Jim, I’m a coder not a WebPack genius

Of course, I may be wrong.

Fixing this wasn’t that hard. I just needed to read the docs.

yarn add --dev uglifyjs-webpack-plugin

For me, this added:

"uglifyjs-webpack-plugin": "^1.2.4",

To my devDependencies in package.json.

After which I updated my prod.js WebPack config as follows:

"use strict";

const webpack = require("webpack");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = function() {
  console.log("BUILDING PRODUCTION");

  return webpackMerge(commonConfig(), {

    plugins: [

      new UglifyJsPlugin({
        test: /\.js($|\?)/i,
        sourceMap: true,
        uglifyOptions: {
          mangle: {
            keep_fnames: true,
          },
          compress: {
            warnings: false,
          },
          output: {
            beautify: false,
          },
        },
      }),

  });
};

I’ve removed everything unrelated to this specific problem.

After which I could get my build to work.

How I Fixed: “error authorizing context: authorization token required”

I love me some Dockerised GitLab. I have the full CI thing going on, with a private registry for all my Docker images that are created during the CI process.

It all works real nice.

Until that Saturday night, when suddenly, it doesn’t.

Though it sounds like I’m going off on a tangent, it’s important to this story that you know I recently I changed my home broadband ISP.

I host one of my GitLab instances at my house. All my GitLab instances are now Dockerised, managed by Rancher.

I knew that as part of switching ISPs, there might (read: 100% would) be “fun” with firewalls, and ports, and all that jazz.

I thought I’d got everything sorted, and largely, I had.

Except I decided that whilst all this commotion was taking place, I would slightly rejig my infrastructure.

I use LetsEncrypt for SSL. I use the LetsEncrypt certs for this particular GitLab’s private registry.

I had the LetsEncrypt container on one node, and I was accessing the certs via a file share. It seemed pointless, and added complexity (the afore mentioned extra firewall rules), which I could remove if I moved the container on to the same box as the GitLab instance.

I made this move.

Things worked, and I felt good.

Then, a week or so later, I made some code changes and pushed.

The build failed almost immediately. Not what I needed on a Saturday night.

In the build logs I could see this:

Error response from daemon: Get https://my.gitlab:5000/v2/: received unexpected HTTP status: 500 Internal Server Error

This happened when the CI process was trying to log in to the private registry.

After a bit of head scratching, I tried from my local machine and sure enough I got the same message.

My Solution

As so many of my problems seem to, it boiled down to permissions.

Rather than copy the certs over from the original node, I let LetsEncrypt generate some new ones. Why not, right?

This process worked.

The GitLab and the Registry containers used a bind mounted volume to access the LetsEncrypt cert inside the container on the path /certs/.

When opening each container, I would be logged in as root.

Root being root, I had full permissions. I checked each file with a cheeky cat and visually confirmed that all looked good.

GitLab doesn’t run as root, however, and as the files were owned by root, and had 600 permissions:

Completed 500 Internal Server Error in 125ms (ActiveRecord: 7.2ms)
Errno::EACCES (Permission denied @ rb_sysopen - /certs/privkey.pem):
lib/json_web_token/rsa_token.rb:20:in `read'
lib/json_web_token/rsa_token.rb:20:in `key_data'
lib/json_web_token/rsa_token.rb:24:in `key'
lib/json_web_token/rsa_token.rb:28:in `public_key'
lib/json_web_token/rsa_token.rb:33:in `kid'
lib/json_web_token/rsa_token.rb:12:in `encoded'

The user GitLab is running as doesn’t have permission to read the private key.

Some more error output that may help future Googlers:

21/01/2018 21:31:51 time="2018-01-21T21:31:51.048129504Z" level=warning msg="error authorizing context: authorization token required" go.version=go1.7.6 http.request.host="my.gitlab:5000" http.request.id=4d91b482-1c43-465d-9a6e-fab6b823a76c http.request.method=GET http.request.remoteaddr="10.42.18.141:36654" http.request.uri="/v2/" http.request.useragent="docker/17.12.0-ce go/go1.9.2 git-commit/d97c6d6 kernel/4.4.0-109-generic os/linux arch/amd64 UpstreamClient(Docker-Client/17.12.0-ce (linux))" instance.id=24bb0a87-92ce-47fc-b0ca-b9717eabf171 service=registry version=v2.6.2
21/01/2018 21:31:5110.42.16.142 - - [21/Jan/2018:21:31:51 +0000] "GET /v2/ HTTP/1.1" 401 87 "" "docker/17.12.0-ce go/go1.9.2 git-commit/d97c6d6 kernel/4.4.0-109-generic os/linux arch/amd64 UpstreamClient(Docker-Client/17.12.0-ce (linux))"

Argh.

Thankfully I hadn’t deleted the old cert, so I went back and saw that I had previously set 0640  on the private key in the old setup.

Directory permissions for the certs was set to 0750 with execute being required as well as read.

In my case this was sufficient to satisfy GitLab.

When making the change on the new node, I could then immediately log back in.

A Tip To Spot This Sooner

I would strongly recommend that you schedule your project to run a build every ~24 hours, even if nothing has changed.

This will catch weird quirks that aren’t related to your project, but have inadvertently broken your project’s build.

It’s much easier to diagnose problems whilst they are fresh in your mind.

Also, ya’ know, better documentation! This is exactly why I’m now writing this post. So in the future when I inevitable make a similar mistake, I now know where to look first 🙂

[How I Fixed] Installing Go on Ubuntu 16.04

I wanted to install Go on Ubuntu 16.04. I thought this would be easy. It kinda is, but it wasn’t super easy.

By easy I mean I found a bunch of copy / paste instructions, but not everything worked first time.

I found out about a tool called gvm , which is similar to nvm  – in other words, a Go Version Manager.

Here’s what I had to do:

bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)

This prompted me to run a further command:

source /home/chris/.gvm/scripts/gvm

When I tried to run:

gvm version

I was prompted to install bison:

sudo apt-get install bison

I then ran:

gvm listall

Which showed go1.9.2 as being the latest and greatest.

gvm install go1.9.2

Unfortunately that failed.

The instructions I found gave a suggested fix, but this didn’t work. Here’s what did work for me:

gvm install go1.4 --binary
gvm use go1.4
export GOROOT_BOOTSTRAP=$GOROOT
gvm install go1.9.2
gvm use go1.9.2

After which:

go version

go version go1.9.2 linux/amd64

Nice.

For what it’s worth:

go env

GOARCH="amd64"
GOBIN="/home/chris/go/bin"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/chris/go"
GORACE=""
GOROOT="/home/chris/.gvm/gos/go1.9.2"
GOTOOLDIR="/home/chris/.gvm/gos/go1.9.2/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build165142315=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"

I also hit on a bunch of confusing issues because I’d set my package name to be something different to main .

I’d set my package name to cfbl which resulted in this like this:

cfbl go build   
                           
cfbl go install                            
go install: no install location for directory /home/chris/Development/go/cfbl outside GOPATH
	For more details see: 'go help gopath'

cfbl go run test.go
go run: cannot run non-main package

Inside test.go (which isn’t a TDD style test, just my testing with go) I had to make sure to use package main

I hope that saves someone some confusion.

Symfony Access Decision Manager

Unamaous.

Unamouse.

Unamimous!

Yeah, I can’t spell.

I just hit upon a problem whereby I needed my Symfony security voter setup to always deny access even when one of my voters returned an Affirmative.

In this case I want to always deny.

By default Symfony will allow access if at least one voter returns GRANTED.

If you want to know more, check out this video I created about this very problem, and some potential solutions.

Conditional SerializerGroup in FOSRESTBundle

I needed to conditionally add an entry to the list of active Serializer Group entries in a FOSRESTBundle controller action.

Here’s my attempt:

    /**
     * Get a single Widget.
     *
     * @Annotations\Get(path="/widget/{id}")
     *
     * @ApiDoc(
     *   output = "AppBundle\Entity\Widget",
     *   statusCodes = {
     *     200 = "Returned when successful",
     *     404 = "Returned when not found"
     *   }
     * )
     *
     * @param int         $id    the widget slug
     *
     * @Annotations\View(serializerGroups={
     *     "Default",
     *     "timestamps",
     *     "widgets_all",
     *     "feature_summary",
     *     "sprocket_summary"
     * })
     *
     * @return View
     */
    public function getAction(int $id, WidgetRepository $widgetRepository)
    {
        $widget = $widgetRepository->findOneById($id);

        if ($widget === null) {
            return new View(null, Response::HTTP_NOT_FOUND);
        }

        $view = $this->view($widget, Response::HTTP_OK);

        if ($this->isGranted(WidgetVoter::VIEW, $widget->getSprocket())) {
            $view->getContext()->addGroup('sprocket_all');
        }

        return $view;
    }

The idea behind this code is to that a Widget should show all of its information to all users.

It should show a summary of related features to all users.

It should show a summary of the related sprocket (one-to-one) to all users.

However, if you are logged in, you should see all the sprocket information, not just a summary.

It seems to work quite well in my use case. Gotta love them sprockets!