Diagrams and code analysis: drawing designs and reading repositories

How a diagram editor stores, draws, lays out and exports a graph; how to read GitHub, GitLab and Azure DevOps repositories through their APIs with read-only tokens, ETags and rate limits; how manifests become a service map without running anything; and how drift and threat rules run on a graph - step by step, with examples.

In short

A design tool and a code reader are two halves of one idea: a system is a graph of parts and connections. A diagram editor keeps that graph as data, draws it with SVG and HTML, places it with a layout engine and exports it as SVG, PNG or PDF. A code reader fetches a repository's manifests - compose files, Helm charts, package files - through the provider's REST API and turns them into the same kind of graph by static analysis. Put the two graphs side by side and you find drift; run rules over one and you have a threat model.

After this lesson you can Choose between SVG and canvas for a diagram editor and say why; lay out a graph automatically; read a repository politely with ETags and rate limits; turn manifests into a service map and run drift and threat rules on a graph.

Words you need

How a diagram editor works inside

Every serious diagram editor - draw.io, Figma, Miro, Lucidchart - keeps three things apart: the document (the data), the view (what is drawn) and the actions (what a person does). Keep them apart and undo, saving, export and checks all become simple, because they all read one document.

Why patches, not snapshots A snapshot per step copies the whole design every time someone nudges a box. A patch says only nodes, 0, x: 240 - tiny, exact, and easy to merge: {{brand}} joins all the patches of one drag or one burst of arrow-key presses into a single undo step.

SVG, HTML or canvas: how the shapes are drawn

The rule of thumb: retained mode (SVG or HTML - the browser remembers every shape) is best up to a few thousand shapes and gives you events, CSS and accessibility for free. Immediate mode (canvas or WebGL - you repaint everything yourself) wins only when the drawing is huge. An architecture or a workflow has tens to a few hundred parts, so retained mode is the right tool.

Keeping an SVG editor fast Rebuild a node's shape only when that node changed - with immutable data this is a cheap reference check - and load the heavy parts only when they are needed. {{brand}} downloads the editor when a design is opened, the layout engine on the first auto-layout and the picture exporter on the first export.

A diagram is data: the graph format

A good diagram format is self-describing and versioned: it names its format and version, gives every element a stable id, and says what each element is - a kind such as service or database - rather than how it looks. Colours and shapes are decided when it is drawn, so the same document can be shown on a canvas, printed in a PDF or written as Mermaid.

An imported file is hostile input A file someone hands you can be crafted. Refuse XML document type declarations (they can pull in other files or expand into huge text), put a cap on how far a compressed page may inflate, and count nodes, edges and characters before building anything.

Automatic layout: how a graph places itself

Placing boxes by hand is fine for ten parts. For a design drawn from code, imported from a file or written by AI, a layout engine places them. Systems and workflows have a direction - a request flows from the browser to the API to the database - so the usual choice is a layered layout, described by Sugiyama, Tagawa and Toda in 1981.

Export: SVG, PNG, PDF and diagram as code

There are two ways to make a picture of a diagram. Photograph the view: copy what is on screen, in the person's own theme. Or draw from the data: build a fresh SVG from the document alone, in a fixed print palette - which also works on a server with no browser. {{brand}} uses both, each where it fits.

The first half of that journey - copying a live page into an SVG - is what html-to-image does. A browser cannot hand you a screenshot of its own elements, so the library builds one. It clones the chosen element deeply and copies the computed style of every clone, so the copy looks right outside the page's stylesheets. It inlines what the picture would otherwise fetch later: images become data addresses and web fonts are embedded. It wraps the clone in an SVG whose foreignObject holds ordinary HTML, which the browser knows how to draw. toSvg returns that SVG; toPng loads it as an image, paints it on a canvas at the pixel ratio you ask for and reads the canvas back. Options let you set the background, the exact size, a style override such as a zoom transform, and a filter that leaves chosen elements out.

Know what the photograph is made of html-to-image's SVG is HTML in a foreignObject: browsers draw it, but Word, many editors and PDF tools may show it empty. Very large canvases at 2x can also exceed the browser's canvas size limit, and Safari has needed extra care with images and fonts. For documents, draw an SVG from the data instead, as described above.

Escape every label A label such as <script> or A & B written into SVG or XML either breaks the file or runs code when someone opens it in a browser. Escape & < > " and ' in every text you put into markup, and never fetch an image or a font that an imported file names.

The options in the market

What {{brand}} chose, and why

{{brand}} draws with React Flow because a part on the canvas is more than a box: it shows its kind, technology, inputs and badges for live health, threats and coverage. Those are ordinary React components, so they reuse the app's design system, translations and accessibility rules. Architecture diagrams stay well inside what SVG and HTML handle.

Reading a repository through its API

To compare a design with code you need some of the code's files. You could clone the repository, but that copies everything - history, binaries, files nobody needs - and needs a disk and a git binary. Every big provider also has a REST API: ask for the default branch, the head commit, the list of files at that commit, and then only the few files you want.

Never let a token wander A host can answer with a redirect. Follow redirects yourself: every hop must be https, on a host you allow, and resolve to a public address - otherwise a crafted repository address can make your server call its own private network (server-side request forgery). Send the token only to the origin it was created for, and never write it into a log, an error or an answer.

Ask for the narrowest token Prefer a token limited to read access on just the repositories you need. On some providers an older token kind can read private repositories only with a scope that also allows writing, and some providers cannot report a token's rights at all - so tell people which kind to create.

{{brand}} offers the two marked paths. A connected repository is read through the provider's API with a read-only access token, which works the same on GitHub, GitLab and Azure DevOps, in the cloud or self-hosted. Teams that would rather share no token run the CLI's scan command in their own pipeline; its dry run prints exactly what would be sent, and sends nothing.

Being polite: ETags, conditional requests and rate limits

A design follows a repository for months, and most checks find nothing new. Two habits make those checks almost free for you and for the provider: conditional requests and respecting rate limits.

Three cheap questions before an expensive one Did the head move (a 304 says no)? Did any manifest's blob id change (a digest says no)? Only then download files. Most polls stop at the first question. A push that touches only source code is dropped at once when the webhook lists its changed paths, and stops at the second question when it does not.

Push or poll: webhooks and their proofs

Polling keeps asking anything new? A webhook turns that round: the provider calls you when something happens - a push, a merged pull request. It is faster and cheaper, but the address is public, so every call must prove it came from the provider before you believe a word of it.

The proofs below rest on an HMAC: a fingerprint computed from the message and a secret that only you and the provider know. You recompute it over the body you received. If it equals the one in the header, the sender knew the secret and the body was not changed on the way. Anyone without the secret cannot produce a matching fingerprint.

Sign over the raw bytes Check the signature over the body exactly as it arrived. If your framework parses and re-serializes the JSON first, spacing or key order changes and every honest delivery fails - or, worse, you start skipping the check.

Static analysis: a service map from manifests

Static analysis learns about software without running it. Source code is hard to read reliably across dozens of languages, but manifests are short, structured and say exactly what a system is made of: which services run, what they are built from, what they depend on and which drivers they load.

Never run what you analyse Do not call npm install, dotnet restore or helm template to understand a repository: they run the repository's own scripts on your machine. Read files as text. A Helm template full of {{ }} expressions is marked as read in part, not rendered.

Detecting drift: diffing a model against reality

Drift happens to every diagram: the system changes and the drawing does not. Finding it is a graph diff between the model and the evidence - a code reading, or what API tests saw the running service answer. The hard parts are identity and honesty: knowing which box is which service, and not calling something missing when you simply have not seen it.

A move is not a change Compare what a design says, not where a box sits. Leave positions and sizes out of every diff and fingerprint, or each tidy-up looks like a redesign and reopens every review.

The same idea works one level down. A workflow step that designs POST /orders answering 201 is compared with the API's contract and with what test runs observed: Running POST /orders answers 202, the design says 201. Keep the decision about each difference beside the evidence, not inside the design.

Rules on a graph: threat modelling and architecture checks

Once a design is a graph, many review questions become graph queries. Threat modelling asks what could go wrong where data crosses a trust boundary; the classic checklist is STRIDE - spoofing, tampering, repudiation, information disclosure, denial of service and elevation of privilege. Tools such as the Microsoft Threat Modeling Tool and OWASP Threat Dragon run rules like these over data-flow diagrams.

{{brand}} decides findings with fixed rules only; AI may word the findings in plain language but never adds, removes or changes one. The same engine style - pure functions over the graph, stable keys, a fixed order - also runs the editor's architecture checks, such as parts nothing connects to and rings of synchronous calls.

Try it yourself: map a repository in an afternoon

You need Node.js and a public GitHub repository with a compose file. No token is needed for public repositories, but the rate limit without one is much lower, so run it a few times only.

Common mistakes

Interview questions

Related