Skip to main content

JON GANDER

MENU

Dind and Back Again

Created: 2025-May-29


Work recently exposed me to an fun challenge: a failing linter inside a GitHub Action that produced no actionable feedback about the failure. This post will talk through how I approached the issue, then iterated on the solution until I had something that would be easy and useful for the rest of the team.

Index


Not My Problem

This story starts with me updating a README in a repository outside my team’s usual jurisdiction. I had been troubleshooting part of our AWS infrastructure, and in an effort to spare the next poor soul the same issue, I tracked down what seemed to be the most appropriate place within our many repositories to record such troubleshooting help.

After adding my changes and creating a PR, I noticed that the checks were failing. “Fair enough”, I thought, as I hadn’t run any linting locally. Then I took a look at the failures, and noticed that 4 different linters were failing, only two of which were related to Markdown. I went through a quick emotional rollercoaster, from thinking “Wow, the standards in this repo are tough!”, quickly chnanging to “Wow, linters don’t mean anything in this lawless place.”, after I noticed that the linters weren’t actually blocking PR merging, and had been broken for months.

Sweet, not my problem!

The Itch

I need to fix this. Maybe I don’t need to fix everything, but the imaginary Boy Scout training I’ve received through pop culture told me that I should leave the repository better than I found it. OK, then when I’m done, at least the Markdown linters will pass. Considering I’m just making README changes, any linters complaining about other files I can live with, but let’s at least fix this file’s Markdown.

Ok, so that leaves 2/4 linters. The GitHub Action details for the MARKDOWN linter have useful feedback. It’s a bit annoying that it’s complaining about lines I didn’t touch, but it’s Markdown, and the changes are easy to make once you know about them.

That just leaves 1: MARKDOWN_PRETTIER.

Prettier Useless

MARKDOWN_PRETTIER told me almost nothing. It told me the file it was complaining about, and that’s it. I scanned the file to see if there was anything obvious, but the obvious things had already been caught by the base MARKDOWN linter.

Time to zoom out and see what else I have to work with.

Linterless Local

I had already scanned for any locally runnable linter and come up short, but at this point I scoured. Nothing. No handy way to run the GitHub Action locally (while researching I did find act, which seemed promising, though ultimately went unexplored), no Taskfile or Makefile. Nothing in the README to indicate how to handle these opaque failures.

Solutioning

The first thing I tried was installing a VSC (Visual Studio Code) Prettier plugin, but it didn’t seem to work (more on this later), and I wasn’t 100% convinced that VSC’s Prettier and the MARKDOWN_PRETTIER where wholly the same thing… maybe there was a versioning difference, maybe they were completely different libraries named similarly. Either way, I moved on.

The next thing was to investigate the parent linter. All of the linters running in the repository were part of super-linter, and while super-linter was set up by default to run within GitHub Actions, it also provided handy documentation on running it locally.

Problem solved! (not quite)

Manifest Meltdown

The command I was attempting to run locally:

docker run -e LOG_LEVEL=WARN -e RUN_LOCAL=true -e USE_FIND_ALGORITHM=true \
 -e VALIDATE_MARKDOWN_PRETTIER=true -e \
 -v ./README.md:/tmp/lint/README.md \
 --rm ghcr.io/super-linter/super-linter:latest

Running locally produced an error: no matching manifest for linux/arm64/.... While I’m by no means a Docker expert, I’ve seen variants of this message enough to know that the super-linter image expected to be run in a proper linux/amd64 environment rather than the Linux knockoff environment that is Apple Silicon. I knew I needed a different environment, and what I was considering seemed on the verge of nonsense.

How to run a docker run command in docker?

dind

There are times in software where I catch myself thinking, “The way I’m doing things feels like a coping mechanism for novices who don’t know the correct and simpler way.”. This was such a time.

It was then a relief to find that others had trodden this path, and that their efforts had borne dind, AKA Docker IN Docker. After some experimenting and immediately-crashing containers, I settled on this configuration:

# It may not be optimized, but it works!
services:
  app:
    image: docker:dind
    privileged: true
    tty: true
    stdin_open: true
    networks:
      - default
    volumes:
      - .:/code
    working_dir:
      /code

From there I was able to run my command from within the Exec panel of Docker Desktop (or appending docker exec -it my_app to the beginning of the command).

Almost at a working solution!

Still Prettier Useless

Much to my chagrin, MARKDOWN_PRETTIER output locally was just as opaque as it was within GitHub Actions. I remembered and briefly considered trying to solve this with getting the terminal output as a file (an option I had seen within super-linter), but at this point I was pretty sure the file would be similarly unhelpful.

Looking through the super-linter options, I did find another variable I could enable which seemed like an easy way out of what had turned into quite the sidequest, so I added -e FIX_MARKDOWN_PRETTIER=true to the previous command. I had seen this earlier, and while I would have liked to know the changes it was planning to make rather than having the changes applied automatically, I settled on being able to use the git diff to see the changes after they’d been made.

Problem actually solved! Just not solved well.

dood

Now that I had a working command and usable output, I endeavoured to add some local linting steps to the readme. I wasn’t happy with the complexity of what should be a simple local linting step, but I started to write.

One wonderful thing about writing is that it encourages us to revisit previous steps, and ensure we understand what we’re doing and what we’ve done to get there. As part of that, I re-ran the docker run linting command locally (to capture the error), and to my amazement, it passed! Why????

It turns out that I had solved the issue right before stumbling down the dind rabbit hole. The solution was to simply lie to your computer: export DOCKER_DEFAULT_PLATFORM=linux/amd64. This allows Mac to work with images whose manifests aren’t build for Mac’s arm64 architecture.

dood - Docker Outside Of Docker, who woulda thunk!

I tested this a bit further by switching to a new terminal where I hadn’t exported the variable, and ran the command again. It still worked, which was an unexpected treat. Apparently once the image is downloaded, docker run doesn’t care about the platform, and runs the command against the downloaded image. Deleting the image made the manifest error reappear, so I was able to gain confidence in my knowledge of why things were happening the way they were.

Simplify

So, I was able to simplify my local linting instructions in the README, removing the need for dind. I’m still glad I had an opportunity to experiment with dind, but was even more glad I wasn’t suggesting such a cumbersome solution to my peers.

As I mentioned earlier, writing works as a great test of knowledge, and encourages us to revisit previous steps. As I’ve written this, I thought to myself, “why the heck didn’t VSC Prettier work?” and gave it another try… it worked.

I’m still not sure it’s 100% aligned with MARKDOWN_PRETTIER within super-linter, but at a cursory glance it fixed at least some of the same mistakes.

Conclusions

We are left with a bit of a tradeoff, as is often the case. On one hand, I lost a couple hours experimenting and came up with a more convoluted solution than could be accessed easily through VSC. On the other hand, I had a few “Aha!” moments while experimenting that will have lasting value.

More important from a work pespective, I was able to provide a reasonably straightforward solution to my peers that didn’t rely on which IDE they used. Not only that, but the instructions now in the README give a handy starting point to fixing the other linting errors that plague some other files I was unwilling to touch.

Repository left better than I found it.