GitHub / 2020–22

Turning several acquired security tools into one product, so developers can ship secure code.

Problem
Developers wanted to ship secure code. Projects in popular languages rely on a lot of dependencies, any of which a bad actor could use to distribute malware, and the code itself has its own vulnerabilities. GitHub had acquired the tools to find both, from different companies, each with its own way of reporting a problem.
My part
Moved from Microsoft after the acquisition, as GitHub grew its team by bringing people across. Principal Designer in the Security group, hands-on, with code scanning as the main surface, plus requests and support to the Primer design system team.
The idea
Three acquired tools become one Security product. Whatever finds a problem, the developer sees it in the same form, in the pull request, on the line that caused it.
What shipped
Code scanning, generally available from September 2020 and free for public repositories, as part of one Security offering with secret scanning and dependency review.

The setting

Microsoft acquired GitHub while I was at Microsoft, and GitHub quickly grew its team by moving people across. I was one of them. Between 2020 and 2022 I worked in the Security group, which at that point was really a few technology acquisitions, CodeQL for analysing code among them, that had to become one cohesive group and one set of features.

What developers wanted was simple: to ship secure code. Projects written in popular languages like JavaScript rely on a lot of dependencies, and a bad actor could easily distribute malware through one of them. The code itself has its own vulnerabilities. GitHub now owned the tools to find both, but they had come from different companies, each with its own way of reporting a problem.

What I did

At GitHub I was a Principal Designer in the Security group. GitHub ran on a strong PED structure, product, engineering and design, with three core people assigned to each feature. The Security design team was five designers. Designers could move a little, because priorities in the tech world change rapidly, which is how I also worked on features outside Security. The screens on this page are mine. As product designers we also helped the Design System team develop Primer, the shared component library, with requests and support.

How I worked

The work happened in Figma, frame by frame, and the frames carry the thinking: the alert page still has the states I tried and switched off, and the code search frames have my reasoning written on the canvas, for engineers to read next to the design. Between the frames and the product sat design critiques, with design leaders and the rest of the Security design team, and usability tests, often. Sometimes I also helped the research team with upfront research. Feedback on what shipped came in public, on Twitter, and quickly.

The idea

The three tools had to become one Security product. Whatever found the problem (code analysis, a leaked secret or a vulnerable dependency), the developer should see it in the same form, and see it where they already work: in the pull request, on the line that caused it.

The choices

None of these were settled on paper. The alternatives below were prototyped and tested, internally and with some users, before the choice was made.

One alert, whatever found it

Chose
A single alert shape, with the same state, severity, location and history, shared by code scanning, secret scanning and dependency alerts.
Over
Each acquired tool keeping the reporting interface it came withA security dashboard alongside the repository rather than inside it

A developer doesn't care which engine found the problem; they care whether it is real, how bad it is and where it is. A shared shape meant learning one thing: the alert page at the top of this case, with its state, severity, location, affected branches and the record of how it was tracked and fixed, is that shape. In exchange, each tool's own output had to fit it: CodeQL's data-flow paths went behind a “Show paths” control, and details specific to one kind of alert only made it onto the page if they were worth the space. The Figma file still holds the states I tried and switched off along the way, ‘Fixed’, ‘Tracked in #12345’, experimental, before the set that shipped.

The finding goes in the pull request

Chose
An annotation on the changed line, with severity, one sentence on what is wrong and a link to the full alert.
Over
The whole alert inline, paths and advisories includedA summary in the checks only, with the alerts kept to the Security tab

The person who wrote the line is the one who can fix it, and the moment they can fix it cheaply is review. But a pull request is already a crowded page, so the inline version had to be short, enough to decide what to do, with the rest one click away.

A pull request on GitHub where the GitHub Security bot has annotated two lines with code scanning alerts, one Medium and one Critical, each with View details and Dismiss actions; below, the checks list shows code scanning as a required check and ‘Merging is blocked’
The same alert as it appears in the pull request: severity, a sentence, and the choice to look further or dismiss. Below it, the check that can stop the merge.

Blocking the merge is the repository's call

Chose
Code scanning as a status check that a repository can mark as required, so a finding can block the merge.
Over
Always blocking, so nothing vulnerable can be mergedNever blocking: inform and let people decide

Interrupting is a strong move, and the wrong default for a platform with every kind of project on it. Making it a check meant a repository could choose how hard the rule was, using a mechanism it already knew. The catch is that on the repositories that opt in, a false positive blocks the merge until someone deals with it. Hence the next decision.

Dismissing needs a reason

Chose
Alerts can be dismissed, with a stated reason such as a false positive or something used only in tests, and stay in the history.
Over
No dismissal, so every finding has to be fixed or lived withA silent close

If developers can't say “not this one”, they stop looking at all of them. If they can say it without a reason, the count going down stops meaning anything. A reason keeps the dismissal honest and leaves a record of why, for the next person who hits the same line.

Shipping it

Code scanning became generally available in September 2020, free for public repositories and part of Advanced Security for private ones, alongside secret scanning and dependency review under one Security tab. GitHub's own numbers at launch: during the beta it had scanned over 12,000 repositories 1.4 million times and found more than 20,000 security issues, and in the thirty days before GA developers had fixed 72% of the security errors reported in their pull requests before merging. That last figure is the one the pull request annotation was designed for.

Outside Security

I also designed for GitHub Actions and Code Search. The search work was as much writing as drawing: specifying how qualifier suggestions should narrow as a developer types, with the reasoning on the canvas beside the frames.

GitHub’s search box open on a repository page, listing result types (Repositories, Code, Commits, Issues, Discussions, Packages…), with a blue note over the page reading: selecting ‘search’ will show all the possible result types available; we could consider pre-selecting Code or Repositories depending on the page the user is
Code search with the reasoning left on the canvas: the result-type menu, and the note proposing that Code or Repositories be preselected depending on the page you search from.

Looking back

I was designing for millions of developers I couldn't see, on a platform where every choice was highly scrutinised and commented on on Twitter. The CEO was on there too, listening, and sometimes committing to things in public. That is a different discipline from working with a handful of customers: you find out what people think in public, and quickly, and the roadmap could take shape there as much as inside.

I'd keep the decision to make the alert the unit, whatever tool raised it. Settling early that a developer meets one kind of thing, wherever it came from, is what let three products become one.

If I did it again I would design the dismiss path first. Dismissal with a reason came as a consequence of blocking, but blocking is only bearable because of it, so it should have been on the table before.