<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Madalin Ilie</title>
    <description>The latest articles on DEV Community by Madalin Ilie (@ludovicianul).</description>
    <link>https://dev.to/ludovicianul</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F196231%2F56610f35-21e3-4970-ab3f-d634ce7accb2.png</url>
      <title>DEV Community: Madalin Ilie</title>
      <link>https://dev.to/ludovicianul</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ludovicianul"/>
    <language>en</language>
    <item>
      <title>The Invisible Character That Cost Me Too Much Debugging Time</title>
      <dc:creator>Madalin Ilie</dc:creator>
      <pubDate>Wed, 10 Sep 2025 18:01:45 +0000</pubDate>
      <link>https://dev.to/ludovicianul/the-invisible-character-that-cost-me-too-much-debugging-time-3a13</link>
      <guid>https://dev.to/ludovicianul/the-invisible-character-that-cost-me-too-much-debugging-time-3a13</guid>
      <description>&lt;h1&gt;
  
  
  The Problem
&lt;/h1&gt;

&lt;p&gt;Imagine this: someone tells you they can't log in.&lt;br&gt;
At first, it feels like the kind of bug you can squash before finishing your coffee. Maybe they fat-fingered their&lt;br&gt;
password. Maybe their browser cache is holding onto stale session cookies. Easy.&lt;/p&gt;

&lt;p&gt;Except it isn't.&lt;/p&gt;

&lt;p&gt;You check the admin panel. The email is there: &lt;code&gt;james.bond​@mi6.com&lt;/code&gt;. Looks fine. The password hash matches what the user typed in. Logs show the request hitting the system cleanly. No obvious anomalies. And yet, every attempt comes back as “invalid credentials.”&lt;/p&gt;

&lt;p&gt;You start peeling layers. Caching? No. Database encoding? No. By mid-afternoon, you're questioning whether you've misunderstood something as fundamental as string equality.&lt;/p&gt;

&lt;p&gt;Finally, desperation pushes you into a hex editor. You copy the email from the database, paste it in, and there it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;E2 80 8B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A zero-width space. An invisible Unicode character sitting between bond and @. Your eyes missed it, but the system&lt;br&gt;
didn't.&lt;/p&gt;

&lt;p&gt;What looked identical to a human was actually two different strings at the byte level.&lt;/p&gt;
&lt;h1&gt;
  
  
  How does something like this even happen?
&lt;/h1&gt;

&lt;p&gt;Ghost characters are present more often than you'd expect. Some common causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copy-paste from PDFs or Word docs: Rich-text formats often inject hidden control characters.&lt;/li&gt;
&lt;li&gt;Email clients and chat apps: Some insert soft hyphens, directionality markers, or non-breaking spaces.&lt;/li&gt;
&lt;li&gt;Keyboards and IMEs: Certain language input systems add combining marks or zero-width joiners.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The registration pipeline happily accepted it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regex validation? Passed.&lt;/li&gt;
&lt;li&gt;Database insertion? No complaint.&lt;/li&gt;
&lt;li&gt;API payload? Looked fine in JSON.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But during login, when the user typed the email manually (without the phantom character) the system compared apples to&lt;br&gt;
almost-apples. Result: &lt;code&gt;authentication failure&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And it's not just zero-width spaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Soft hyphen (&lt;code&gt;U+00AD&lt;/code&gt;): invisible unless line breaks occur.&lt;/li&gt;
&lt;li&gt;Left-to-right / right-to-left markers (U+200E, U+200F): wreak havoc on string rendering.&lt;/li&gt;
&lt;li&gt;Homoglyphs: characters from different scripts that look identical (Latin a vs Cyrillic а).&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Testing What You Can't See
&lt;/h1&gt;

&lt;p&gt;The truth is most test suites don't cover this.&lt;br&gt;
Think about your own testing. If I've asked you now, would you know exactly how your API&lt;br&gt;
handles these edge cases? You probably check for bad input, missing fields, maybe even SQL injection. But do you&lt;br&gt;
test what happens if a username has a zero-width space? Or if someone's password contains a right-to-left marker? Or if&lt;br&gt;
two strings that look the same aren't really the same?&lt;/p&gt;

&lt;p&gt;Of course not. Few do. And it's usually after you got burned by it.&lt;/p&gt;
&lt;h1&gt;
  
  
  Enter Dochia
&lt;/h1&gt;

&lt;p&gt;That's where Dochia comes in. It's focused on systematic testing, not just ad-hoc bug reproductions.&lt;/p&gt;

&lt;p&gt;The core idea: automate negative and boundary testing for real-world APIs, with a focus on invisible, hard-to-spot input bugs boundary cases,&lt;br&gt;
missing required fields, oversized inputs, etc. Everything that's predictable and typically independent on the business logic.&lt;/p&gt;

&lt;p&gt;Dochia takes an OpenAPI spec and generates smart payloads. Think of it as an&lt;br&gt;
engine tuned specifically for negative and boundary testing.&lt;/p&gt;

&lt;p&gt;It's as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dochia &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; api-spec.yml &lt;span class="nt"&gt;-s&lt;/span&gt; http://localhost:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It sends crafted requests and produces a report with concrete reproductions: the exact payload, the response, and why&lt;br&gt;
it's suspicious. All within seconds.&lt;/p&gt;
&lt;h1&gt;
  
  
  Additional Bugs it Found
&lt;/h1&gt;

&lt;p&gt;The zero-width space was one example. Dochia surfaced many others:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Passwords with null bytes (\x00)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The backend silently truncated at the null, so &lt;code&gt;hunter2\0evil&lt;/code&gt; matched &lt;code&gt;hunter2&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Result: partial-password login bypass.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Unicode minus sign bug (U+2212)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input: –25 (using a Unicode minus, not ASCII -).&lt;/li&gt;
&lt;li&gt;System accepted negative ages during registration.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Duplicate usernames bypass&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;john&lt;/code&gt; vs &lt;code&gt;john&amp;lt;U+200B&amp;gt;&lt;/code&gt; stored as distinct records. &lt;/li&gt;
&lt;li&gt;Duplicate-check logic missed it, leading to collisions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Emoji handling&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API accepted alex🙂.&lt;/li&gt;
&lt;li&gt;DB stored it fine (UTF-8).&lt;/li&gt;
&lt;li&gt;UI list view exploded when rendering, because the frontend assumed fixed byte width per character.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples are from different projects, but follow similar pattern: missing edge-cases in the system, leading to unexpected behavior.&lt;/p&gt;
&lt;h1&gt;
  
  
  Why Share This?
&lt;/h1&gt;

&lt;p&gt;Because these are not “big company problems.”&lt;br&gt;
They're the kind of bugs that any developer can hit when their system meets messy, unpredictable user input.&lt;/p&gt;

&lt;p&gt;So Dochia is free and open source:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;dochia-dev/tap/dochia-cli
dochia &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; openapi.yaml &lt;span class="nt"&gt;-s&lt;/span&gt; http://localhost:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it, and you'll see what bugs it can find.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Reality of User Input
&lt;/h1&gt;

&lt;p&gt;Users don't type raw ASCII. They paste from documents, switch keyboard layouts, run browser extensions, sit behind&lt;br&gt;
proxies that rewrite headers. Every layer introduces noise.&lt;/p&gt;

&lt;p&gt;If your system assumes “well-formed UTF-8 strings without weirdness,” you'll eventually burn hours, days, chasing&lt;br&gt;
invisible bugs.&lt;/p&gt;

&lt;p&gt;And you can either find those surprises early… or waste three days chasing an invisible space.&lt;/p&gt;

&lt;p&gt;Don't be me.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dochia.dev" rel="noopener noreferrer"&gt;dochia.dev&lt;/a&gt; – main site&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dochia-dev/dochia-cli" rel="noopener noreferrer"&gt;github.com/dochia-dev/dochia-cli&lt;/a&gt; – source code&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.dochia.dev" rel="noopener noreferrer"&gt;docs.dochia.dev&lt;/a&gt; – documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Got a weird bug story? I'm collecting them. That zero-width space was just the beginning.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>api</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>uGYWtH</title>
      <dc:creator>Madalin Ilie</dc:creator>
      <pubDate>Wed, 20 Apr 2022 10:15:40 +0000</pubDate>
      <link>https://dev.to/ludovicianul/ugywth-1noj</link>
      <guid>https://dev.to/ludovicianul/ugywth-1noj</guid>
      <description>&lt;p&gt;z03Zz7v0yruzl42KV&lt;/p&gt;

</description>
      <category>umdt5bp</category>
    </item>
    <item>
      <title>Make sure you know which Unicode version is supported by your programming language version</title>
      <dc:creator>Madalin Ilie</dc:creator>
      <pubDate>Fri, 16 Jul 2021 13:42:49 +0000</pubDate>
      <link>https://dev.to/ludovicianul/make-sure-you-know-which-unicode-version-is-supported-by-your-programming-language-version-5blb</link>
      <guid>https://dev.to/ludovicianul/make-sure-you-know-which-unicode-version-is-supported-by-your-programming-language-version-5blb</guid>
      <description>&lt;p&gt;While enhancing &lt;a href="https://github.com/Endava/cats"&gt;CATS&lt;/a&gt; I recently added a feature to send requests that include single and multi code point emojis. This is a single code point emoji: &lt;code&gt;🥶&lt;/code&gt;, which can be represented in Java as the &lt;code&gt;\uD83E\uDD76&lt;/code&gt; string.&lt;br&gt;
The test case is simple: inject emojis within strings and expect that the REST endpoint will sanitize the input and remove them entirely (I appreciate this might not be a valid case for all APIs, this is why the behaviour is configurable in CATS, but not the focus of this article).&lt;/p&gt;

&lt;p&gt;I usually recommend that any REST endpoint should sanitize input before validating it and remove special characters. A typical regex for this would be &lt;code&gt;[\p{C}\p{Z}\p{So}]+&lt;/code&gt; (although you should enhance it to allow spaces between words), which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;p{C}&lt;/code&gt; - match Unicode invisible Control Chars (&lt;code&gt;\u000D&lt;/code&gt; - carriage return for example)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;p{Z}&lt;/code&gt; - match Unicode whitespace and invisible separators (&lt;code&gt;\u2028&lt;/code&gt; - line separator for example)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;p{So}&lt;/code&gt; - matches various symbols that are not math symbols, currency signs, or combining characters; this also includes emojis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have a test service I use for testing new CATS fuzzers. The idea was to simply use the String's &lt;code&gt;replaceAll()&lt;/code&gt; method to remove all these characters from the String.&lt;/p&gt;

&lt;p&gt;So let's take the following simple code which aims to sanitize a given input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"this is a great \uD83E\uDD76 article"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replaceAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[\\p{C}\\p{So}]+"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"input = "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output = "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While running this with Java 11, I get the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input = this is a great 🥶 article
output = this is a great  article
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which works as expected. The &lt;code&gt;🥶&lt;/code&gt; emoji was removed from the String as expected. &lt;/p&gt;

&lt;p&gt;Even though I have CATS compiled to Java 8, I mainly use JDK11+ for development. At some point I had CATS running in a CD pipeline with JRE8. &lt;br&gt;
The emoji test cases generated by the CATS Fuzzers, started to fail, even though they were successfully passing on my local box (and on other CD pipelines). &lt;br&gt;
I went through the log files, the request payloads were initially constructed and displayed ok, with the emoji properly printed, but while running some &lt;a href="https://github.com/Endava/cats/blob/df4699eeac4ed97d42a04a0ec7cb461d1bd4ac47/src/main/java/com/endava/cats/model/FuzzingStrategy.java#L65"&gt;pattern matching on the string&lt;/a&gt;&lt;br&gt;
the result was printed as &lt;code&gt;sometext?andanother&lt;/code&gt;. The &lt;code&gt;?&lt;/code&gt; is where the emoji was supposed to be. &lt;br&gt;
Further investigation led to the conclusion that what caused the mishandling of the emoji was the JRE version (which might be obvious for the 99.999% of Java devs out there). &lt;br&gt;
Which is actually expected as Java 8 is compatible with Unicode 6.2, while 🥶 is &lt;a href="https://emojipedia.org/cold-face/"&gt;part of Unicode 11&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Going back to the previous example, if I run it with Java 8, I get the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input = this is a great 🥶 article
output = this is a great ? article
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Even though a Java version can receive, write/store and forward the latest Unicode characters, any attempt to manipulate them might result in weird &lt;code&gt;?&lt;/code&gt; symbols if the Unicode char is not from the version supported by your JRE version&lt;/li&gt;
&lt;li&gt;Independent on how you compile the code, it's the JRE that decides how the Unicode chars are handled i.e. a Java program compiled as Java 8 will have different behaviour in JRE 8 vs JRE 14&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>security</category>
      <category>unicode</category>
    </item>
    <item>
      <title>An incomplete list of practices to improve security of your (micro)services</title>
      <dc:creator>Madalin Ilie</dc:creator>
      <pubDate>Tue, 06 Jul 2021 13:01:24 +0000</pubDate>
      <link>https://dev.to/ludovicianul/an-incomplete-list-of-practical-security-for-mortals-136l</link>
      <guid>https://dev.to/ludovicianul/an-incomplete-list-of-practical-security-for-mortals-136l</guid>
      <description>&lt;p&gt;Software security is hard and complex. Many people think about it as something aside from the typical development process. It's usually seen as a responsibility of &lt;br&gt;
&lt;code&gt;some security people that only care about security and don't understand that we need to deliver business value fast in an already complicated microservices-event-driven-api-frist-ha-cloud ecosystem&lt;/code&gt;.&lt;br&gt;
I could add a lot more dashes to &lt;code&gt;microservices-event-driven-api-frist-ha-cloud&lt;/code&gt;. &lt;br&gt;
And I think this is the main reason it might seem overwhelming to think early about security and all the possible cases something or someone can break your system.&lt;br&gt;
It's yet another complex thing in an already complex environment. It's not just all the technical complexities of modern architectures, it's also all the additional stuff: need to go to market fast, hard deadlines, team chemistry issues, underperformers, too many processes, meetings, etc.&lt;br&gt;
And it's a complex thing that will not break your system in day 1. It might take months/years until someone will find a vulnerability. Why focus on this from day 1? &lt;br&gt;
Well, you might be right. The chances of something happening from day 1 are low.&lt;br&gt;
And it's very tempting to focus on something with immediate value (actual functiola features), rather than mitigating some future possibilities. &lt;br&gt;
The thing is, when a security issue happens, it can bring your entire system down. And this will be very bad for you and your users.&lt;/p&gt;

&lt;p&gt;I see it similar to airport security. We do all these checks, we scan people, we forbid them to take things onboard and so on, although &lt;code&gt;99.99..9%&lt;/code&gt; of people don't plan to hijack the plane. &lt;br&gt;
It's for the &lt;code&gt;0.00..1%&lt;/code&gt; of the cases that we have all these measures in place. Because the consequences are big.&lt;/p&gt;

&lt;p&gt;So how do you balance between not over-engineering security and be paranoiac about everything while still focusing on the business value? &lt;br&gt;
You make it a &lt;strong&gt;mindset&lt;/strong&gt;, rather than a separate concern. I'm not saying that everyone needs to become a security expert and know everything. &lt;br&gt;
I'm saying that people should develop &lt;strong&gt;secure software&lt;/strong&gt; just like they develop &lt;strong&gt;software&lt;/strong&gt;. They do it in a way that will minimize the probability of introducing vulnerabilities.&lt;/p&gt;

&lt;p&gt;The best way to instill this mindset is through a set of &lt;strong&gt;standards&lt;/strong&gt; and &lt;strong&gt;practices&lt;/strong&gt; that will create &lt;strong&gt;habits&lt;/strong&gt;. &lt;br&gt;
Going back to airport security, you don't let all the decisions on each individual security person. &lt;br&gt;
&lt;em&gt;"This person looks nice. Let them have the scissors, and a knife in their hand luggage"&lt;/em&gt;. &lt;em&gt;"You sir look very dehydrated, you can take your big bottle of liquid with you in the plane!"&lt;/em&gt;&lt;br&gt;
You create a set of rules, procedures (i.e., &lt;strong&gt;standards&lt;/strong&gt;) that will apply equally to everyone. And you also create a set of guidelines (i.e., &lt;strong&gt;practices&lt;/strong&gt;) on how to handle specific situations: if you see something suspicious in a hand luggage, you inspect it separately.&lt;/p&gt;

&lt;p&gt;In the next sections I'll detail standards and practices that cover the entire SDLC. &lt;br&gt;
They are not meant to be self-sufficient for all sections (i.e., you might add a lot more to cover that section from a general good practices perspective). But they will make you questioning things and think about cases that are not maybe that obvious.&lt;/p&gt;

&lt;h1&gt;
  
  
  Where is Security focused
&lt;/h1&gt;

&lt;p&gt;I'll do a simple split of Security concerns into two main areas: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;infrastructure security&lt;/strong&gt;: anything related to how the application is being deployed and operating in production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;application security&lt;/strong&gt;: anything related to how the application is being implemented, with the specifics of the business context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are plenty of resources on how to tackle both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.pcisecuritystandards.org/"&gt;PCI Security Requirements&lt;/a&gt;: focused on financial software, but can be used as best practice for any other system&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://safecode.org/category/resource-publications/"&gt;Safe Code&lt;/a&gt;: general practices on dev, testing, arch, devops&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://wiki.sei.cmu.edu/confluence/display/seccode/Top+10+Secure+Coding+Practices"&gt;SEI Top 10 Secure Coding Practices&lt;/a&gt;: secure coding practices focused on specific programming languages, but also some general ones&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cheatsheetseries.owasp.org/index.html"&gt;OWASP Cheatsheet Series&lt;/a&gt;: cheatsheets for most of the software development areas&lt;/li&gt;
&lt;li&gt;plus many others&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are lengthy, comprehensive and include a lot of details and practices on how to tackle security in SDLC. &lt;br&gt;
It will be great if every developer will go through all these periodically in order to keep their information fresh. But in practice, this doesn't happen quite often.&lt;br&gt;
I'll try to summarize below which are the most important things to consider, agnostic of the business domain. It's not a full list, nor a silver bullet. &lt;br&gt;
But it will establish a solid foundation which will minimize the possibility for security issues to happen.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tackling Security
&lt;/h1&gt;

&lt;p&gt;Infrastructure Security it's more predictable to address, mainly due to the use of products or cloud services. &lt;br&gt;
They already have the security features build-it and implemented well i.e., if you use a Web Application Firewall, you trust the product to do its job, you won't actually implement its logic.&lt;br&gt;
I'm not saying it's easier, but you have more control.&lt;/p&gt;

&lt;p&gt;Application Security it's less predictable. You mainly rely on people skills to implement stuff securely. You need to make sure they don't do stupid things like storing clear text passwords in source files.&lt;/p&gt;

&lt;p&gt;Below is a list of the most important practices which I think will help you build a security mindset. It's intended for the &lt;code&gt;regular&lt;/code&gt; developer. When I say &lt;code&gt;regular&lt;/code&gt;, I just mean people actually implementing, rather than all the others focused on designing, planning or managing.&lt;br&gt;
They are all focused on &lt;strong&gt;Application Security for building (REST) APIs&lt;/strong&gt;. At a first glance they might not seem all directly related to security. But in the end, they will minimize the probability to introduce security issues.&lt;/p&gt;

&lt;p&gt;Majority of examples will use Java.&lt;/p&gt;

&lt;h1&gt;
  
  
  Standards
&lt;/h1&gt;

&lt;p&gt;As mentioned above, the usage of standards is the main mechanism to build a mindset. All projects should have a set fo standards. Not everyone is a fan of standards and feel they limit people's choices and creativity. &lt;br&gt;
But I think it's an easy way to get consistency, especially when having many teams working on the same platform. It allows both easier onboarding for new joiners and limit the possibility of introducing bugs or inconsistencies or argue for stupid things (spaces vs tabs ;)). &lt;br&gt;
It gives you more time for meaningful discussions and debates.&lt;br&gt;
Standards do not have to be very detailed, at least not in all areas. The majority of the standards should state principles and choices you've made based on existing sets of good practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;document your code interfaces and API contracts&lt;/li&gt;
&lt;li&gt;define your documentation strategy:

&lt;ul&gt;
&lt;li&gt;what is your overall documentation strategy? &lt;/li&gt;
&lt;li&gt;what do you put in the README.md file of the project?&lt;/li&gt;
&lt;li&gt;do you need to update a wider documentation?&lt;/li&gt;
&lt;li&gt;what tool do you use for diagrams? &lt;/li&gt;
&lt;li&gt;do you use &lt;a href="https://adr.github.io/"&gt;lightweight architecture decision records&lt;/a&gt;?&lt;/li&gt;
&lt;li&gt;do you store the documentation along with the project in Git? or maybe use a separate tool?&lt;/li&gt;
&lt;li&gt;if you store it within the project, what is the recommended folder structure?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  General (micro)services design guidelines
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use a blueprint/template/archetype as a starting point for all your (micro)services&lt;/li&gt;
&lt;li&gt;have the blueprint already bundled with all the common libraries, plugins, etc. and aligned to the standards&lt;/li&gt;
&lt;li&gt;each (micro)service must start with one command&lt;/li&gt;
&lt;li&gt;(micro)services will process data only through APIs/events; there is no back-door&lt;/li&gt;
&lt;li&gt;(micro)services are self-contained&lt;/li&gt;
&lt;li&gt;all (micro)services are &lt;a href="https://12factor.net/"&gt;12 factor apps&lt;/a&gt; and &lt;a href="https://tanzu.vmware.com/content/blog/beyond-the-twelve-factor-app"&gt;even more&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Code formatting/styling
&lt;/h2&gt;

&lt;p&gt;Just choose one and apply it consistently. Auto-format before commit if possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Naming conventions
&lt;/h2&gt;

&lt;p&gt;Just choose one and apply it consistently.&lt;/p&gt;

&lt;h2&gt;
  
  
  API standards
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;follow REST naming practices (nouns, plurals, the usual stuff) - pick one, &lt;a href="https://www.google.com/search?q=rest+naming+best+practices&amp;amp;oq=rest+naming+practices"&gt;the internet is full of guidelines&lt;/a&gt;, &lt;strong&gt;but be consistent&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;be consistent with the naming; this applies for everything, not only the endpoints: payload object naming, properties etc. camelCase, snake_case, kebab-case/hyphen-case etc. Again, just choose something, &lt;strong&gt;but be consistent&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;make &lt;code&gt;POST, PUT, PATCH&lt;/code&gt; return bodies with meaningful responses&lt;/li&gt;
&lt;li&gt;use meaningful &lt;a href="https://en.wikipedia.org/wiki/List_of_HTTP_status_codes"&gt;HTTP status codes&lt;/a&gt;, rather than &lt;code&gt;400&lt;/code&gt; for everything that goes wrong&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;all&lt;/strong&gt; endpoints must return meaningful error cases&lt;/li&gt;
&lt;li&gt;use an error catalogue (more details in the Error Handling section)&lt;/li&gt;
&lt;li&gt;consider something like &lt;a href="https://www.openapis.org/"&gt;OpenAPI&lt;/a&gt; and consider also doing contract-first development i.e., write the OpenAPI contract initially, socialize it with your (internal) consumers; this also enables better parallel development&lt;/li&gt;
&lt;li&gt;document your OpenAPI contracts with meaningful descriptions and examples&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;all&lt;/strong&gt; (internal) APIs must use CorrelationId/TraceId headers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;all&lt;/strong&gt; API inputs must be very restrictive by default&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;all&lt;/strong&gt; APIs (internal or external) must be authenticated and ideally also with authorization in place&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;all&lt;/strong&gt; APIs must re-use the same common data structures; either generic ones like Address, Person, Country, etc, but also define business specific ones&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;all&lt;/strong&gt; APIs (internal or external) are exposed over &lt;strong&gt;HTTPS&lt;/strong&gt; only&lt;/li&gt;
&lt;li&gt;for the relevant APIs consider returning security headers within the response like: &lt;code&gt;Cache-Control: no-store, Content-Security-Policy: frame-ancestors 'none', Content-Type, Strict-Transport-Security, X-Content-Type-Options: nosniff, X-Frame-Options: DENY&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;internal APIs do not communicate to each others via the internet (unless this is something deliberate or required by the architecture)&lt;/li&gt;
&lt;li&gt;do not expose management endpoints over the internet; if this is something required, use authentication&lt;/li&gt;
&lt;li&gt;make sure &lt;strong&gt;all&lt;/strong&gt; APIs are enforcing strict validation for the received requests: do not allow undocumented JSON fields, reject malformed JSONs, etc&lt;/li&gt;
&lt;li&gt;make proper use of data types; don't have everything as a String&lt;/li&gt;
&lt;li&gt;use enumerated values whenever possible&lt;/li&gt;
&lt;li&gt;add length restrictions for strings and min/max for numbers&lt;/li&gt;
&lt;li&gt;add patterns restricting input for each string&lt;/li&gt;
&lt;li&gt;for some properties it's easier to find patterns as they have clear definitions; a country code will always follow the &lt;code&gt;[A-Z]+&lt;/code&gt;; for others, it's a bit more difficult; a &lt;code&gt;lastName&lt;/code&gt; property needs to be quite loose, considering all names in all languages;
the recommendation is at least to prevent strange characters like the Unicode control chars, separators or symbol; a recommended pattern object is the following: &lt;code&gt;^[^\p{C}\p{Z}\p{So}]*[^\p{C}\p{so}]+[^\p{C}\p{Z}\p{So}]*$&lt;/code&gt;; this doesn't mean that you are now
protected from any type of injection; you still need to have a good understanding where the data goes and how it is processed, but at least you won't get &lt;a href="https://www.vice.com/en/article/gv5jgy/iphone-emoji-break-apps"&gt;an emoji breaking your system&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Logging standards
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;logging format: comma separated &lt;code&gt;key=value&lt;/code&gt; pairs? json objects? choose something which is friendly to your tooling&lt;/li&gt;
&lt;li&gt;always include the &lt;code&gt;CorrelationId/TraceId&lt;/code&gt; in each log line; this will make it easier for tools to create dashboards&lt;/li&gt;
&lt;li&gt;include information in logs that will make it easier to understand what's happening: for which entity? business area? is it success? failure?&lt;/li&gt;
&lt;li&gt;some &lt;a href="https://www.javacodegeeks.com/2011/01/10-tips-proper-application-logging.html"&gt;good practices&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;use an abstraction over the actual logging implementation; for example in Java: &lt;a href="http://www.slf4j.org/"&gt;slf4j&lt;/a&gt; with &lt;a href="http://logback.qos.ch/"&gt;logback&lt;/a&gt; as implementation&lt;/li&gt;
&lt;li&gt;treat logging as a cross-cutting-concern; leverage &lt;a href="https://en.wikipedia.org/wiki/Aspect-oriented_programming"&gt;Aspects&lt;/a&gt;; log within methods only exceptionally; this will limit people from logging sensitive stuff&lt;/li&gt;
&lt;li&gt;don't treat logging like &lt;code&gt;let's log everything and see if we needed it afterwards&lt;/code&gt; and dump full requests/responses; be deliberate in what you log, even when logging with &lt;code&gt;debug&lt;/code&gt; or lower levels&lt;/li&gt;
&lt;li&gt;more on &lt;a href=""&gt;Logging Data&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Data standards
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use existing ISO standards for widely known objects: &lt;a href="https://en.wikipedia.org/wiki/ISO_4217"&gt;Currencies&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/ISO_8601"&gt;Dates&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/ISO_4217"&gt;Amounts&lt;/a&gt; just to name a few&lt;/li&gt;
&lt;li&gt;define business specific objects to be re-used&lt;/li&gt;
&lt;li&gt;apply these standards for API objects, database entities and events&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Processing Data
&lt;/h3&gt;

&lt;p&gt;Key things toc consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sanitize data before processing it; this is a good sanitization regex &lt;code&gt;^[^\p{C}\p{Z}\p{So}]*[^\p{C}\p{so}]+[^\p{C}\p{Z}\p{So}]*$&lt;/code&gt;; it won't prevent all problems, but it will strip weird chars that &lt;a href="https://www.instana.com/blog/how-a-slack-zero-width-space-character-broke-a-kubernetes-deployment/"&gt;can cause your system to crash&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;make sure that you don't transmit data from input towards internal elevated access operations like database queries, command line execution etc.; use parametrized queries for DB, be very specific around what you get and what you pass forward&lt;/li&gt;
&lt;li&gt;favor whitelisting instead of blacklisting when you need to make decisions or when plan to restrict processing for specific input&lt;/li&gt;
&lt;li&gt;overall favor &lt;a href="https://en.wikipedia.org/wiki/Defensive_programming"&gt;defensive programming practices&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;make sure you use efficient XML parsers that are not vulnerable to &lt;a href="https://owasp.org/www-community/vulnerabilities/XML_External_Entity_%28XXE%29_Processing"&gt;XXE&lt;/a&gt; or similar attacks; ideally do not accept XML as input unless forced by the context&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Logging Data
&lt;/h3&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;don't log sensitive data; if you still need it for some reason, mask/obfuscate the data; what &lt;code&gt;sensitive&lt;/code&gt; means depends on your business and regulations&lt;/li&gt;
&lt;li&gt;create/use a library that &lt;strong&gt;masks by default&lt;/strong&gt; the most sensitive data within your platform; for example if you're processing payments, card numbers must be masked by default; &lt;strong&gt;you shouldn't leave this decision to each individual&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;consider extending the library each time new sensitive data is added; you must also balance performance when adding too much data&lt;/li&gt;
&lt;li&gt;the logging library must also allow specific configuration so that each individual service can mask additional data without extending the library&lt;/li&gt;
&lt;li&gt;the logging library must provide on-demand sanitization (i.e., by calling specific methods); this will make sure the same sanitization techniques are applied for all cases&lt;/li&gt;
&lt;li&gt;the logging library must sanitize data before logging it (for example by removing all the characters matching &lt;code&gt;\p{Z}\p{C}\p{So}&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;the logging library must also remove CR and LF characters in order to prevent &lt;a href="https://owasp.org/www-community/vulnerabilities/CRLF_Injection"&gt;CRLF injection&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;have a clear log archiving strategy&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Storing Data
&lt;/h3&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;data must not be store &lt;code&gt;in case you need it&lt;/code&gt;; you must only store data that is relevant in current context or foreseeable future&lt;/li&gt;
&lt;li&gt;storing data introduces compliance obligations; make sure you are aware of those&lt;/li&gt;
&lt;li&gt;some data cannot be stored in clear (one example is credit card numbers); use hardware or software &lt;a href="https://en.wikipedia.org/wiki/Hardware_security_module"&gt;HSM&lt;/a&gt; for encryption&lt;/li&gt;
&lt;li&gt;don't store secrets (passwords, encryption keys, ssh keys, private keys) in version control on plain text files; use dedicated products or services for this like Vaults, HSMs&lt;/li&gt;
&lt;li&gt;use &lt;a href="https://en.wikipedia.org/wiki/Salt_(cryptography)"&gt;salt&lt;/a&gt; and/or &lt;a href="https://en.wikipedia.org/wiki/Pepper_(cryptography)"&gt;pepper&lt;/a&gt; when encrypting or hashing sensitive data; this will prevent brute-force attacks&lt;/li&gt;
&lt;li&gt;consider building (or using) a centralized service that will &lt;a href="https://en.wikipedia.org/wiki/Tokenization_(data_security)"&gt;tokenize sensitive data&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;you should tokenize any data that is under some sort of regulation: card data, PII data, etc.; use tokens instead of the actual data in all (micro)services and detokenize only when needed; this will minimize the compliance footprint and will also give better control around the data&lt;/li&gt;
&lt;li&gt;enhance the security of the tokenization solution; do not allow external access to its APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Events/messaging standards
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create an event catalogue so that everyone is aware of the purpose of each event&lt;/li&gt;
&lt;li&gt;use event schemas for validation&lt;/li&gt;
&lt;li&gt;avoid using generic events where you dump everything; you might leak sensitive information without wanting it&lt;/li&gt;
&lt;li&gt;consider exchanging Tokens instead of the actual data for sensitive information&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuration handling
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;avoid hardcoding configuration in source files&lt;/li&gt;
&lt;li&gt;consider using &lt;a href="https://docs.microsoft.com/en-us/dotnet/architecture/cloud-native/centralized-configuration"&gt;centralized configuration management&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;segregate configuration by environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;do not store secrets (passwords, api keys, ssh keys, private keys, etc) in source files or in version control&lt;/strong&gt;; use proper &lt;a href="https://www.vaultproject.io/"&gt;Secrets Vault systems&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;do not leave default credentials&lt;/strong&gt; for any deployable unit (either cloud service, off the shelf products, or your own (micro)services)&lt;/li&gt;
&lt;li&gt;do not put test-only code or configuration in production&lt;/li&gt;
&lt;li&gt;don't build &lt;code&gt;test only&lt;/code&gt; backdoors inside your (micro)service&lt;/li&gt;
&lt;li&gt;use version control to track configuration changes&lt;/li&gt;
&lt;li&gt;have mechanisms in place for configuration integrity checking&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Error handling
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;consider treating exception and errors as a cross-cutting concern; leverage &lt;a href="https://en.wikipedia.org/wiki/Aspect-oriented_programming"&gt;Aspects&lt;/a&gt;, use something like &lt;a href="https://www.baeldung.com/exception-handling-for-rest-with-spring"&gt;ControllerAdvices&lt;/a&gt; or similar&lt;/li&gt;
&lt;li&gt;consider embedding the logic for the most common exceptions/errors (validation issues, resource not found, malformed messages) into a shared library; this will make the interaction between (micro)services predictable and with less friction&lt;/li&gt;
&lt;li&gt;use an error catalogue&lt;/li&gt;
&lt;li&gt;use error codes (e.g. &lt;code&gt;MICRO-4221&lt;/code&gt; - bad request due to structural validation, &lt;code&gt;MICRO-4222&lt;/code&gt; - bad request due to business validation)&lt;/li&gt;
&lt;li&gt;do not leak internal state in responses; avoid passing &lt;code&gt;e.getMessage()&lt;/code&gt;; each error returned must be deliberately created from the root cause, but without leaking internal data&lt;/li&gt;
&lt;li&gt;use a catch-all mechanism in order to avoid leaking internal state for unexpected exceptions; you can just catch &lt;code&gt;Exception&lt;/code&gt; in the global error handler and return a &lt;code&gt;500&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;return the same object for all errors to enable a consistent experience&lt;/li&gt;
&lt;li&gt;document all error cases in your API documentation with the appropriate HTTP Status code; if you use OpenAPI, document all possible HTTP status codes, even if they return the same OpenAPI object&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Branching strategy and commits
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use a &lt;a href="https://martinfowler.com/articles/branching-patterns.html#LookingAtSomeBranchingPolicies"&gt;simple branching strategy&lt;/a&gt;; trunk-based, github-flow, etc.; just pick one&lt;/li&gt;
&lt;li&gt;use meaningful names for your repos and branches&lt;/li&gt;
&lt;li&gt;use &lt;a href="https://chris.beams.io/posts/git-commit/"&gt;descriptive commits&lt;/a&gt;; it will make it easier to trace changes in the future&lt;/li&gt;
&lt;li&gt;use small commits to better isolate changes&lt;/li&gt;
&lt;li&gt;use smart commits i.e., provide a link to the task from the task management system&lt;/li&gt;
&lt;li&gt;consider using pre-commit hooks to validate the commits&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;do not include sensitive information in commit messages&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pay attention when enabling remote access to your repos; especially when repos are hosted in cloud&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Code review
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;do code reviews (be kind, assertive, specific, &lt;a href="https://mtlynch.io/code-review-love/"&gt;all the good stuff&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;let the boring stuff to the tools and focus on the functional aspects and alignment to standards and practices&lt;/li&gt;
&lt;li&gt;if you find the same issue repeated over and over, add it within the standards&lt;/li&gt;
&lt;li&gt;consider using checklists, at least initially until people make it a habit on focusing on the same stuff&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tooling and 3rd party libraries
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;have a process in place for introducing new tooling; do a trade-off analysis and present it in a wider group to get acceptance/agreement and make sure you address wider cases&lt;/li&gt;
&lt;li&gt;when selecting open source software pay attention to &lt;a href="https://en.wikipedia.org/wiki/Comparison_of_free_and_open-source_software_licences"&gt;the license(s)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;create a list with licenses that can be used without asking, licenses that needs to be discussed and licenses which are not allowed to be used&lt;/li&gt;
&lt;li&gt;don't take the first (or latest) shiny tool/library/product you find; consider things like: is it stable?, is it maintained? does it have a track record? &lt;/li&gt;
&lt;li&gt;consider using tools such as &lt;a href="https://owasp.org/www-project-dependency-check/"&gt;OWASP Dependency Check&lt;/a&gt;, &lt;a href="https://www.mojohaus.org/license-maven-plugin/"&gt;License Plugin&lt;/a&gt; or even more complex tools such as &lt;a href="https://www.blackducksoftware.com/"&gt;Black Duck&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;create a list with the agreed tooling/libraries where people can choose from&lt;/li&gt;
&lt;li&gt;update your dependencies frequently&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Code Analysis
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use one or multiple tools to analyze your code&lt;/li&gt;
&lt;li&gt;you must have (at least) one tool focused on the general coding practices and (at least) one focused on security practices&lt;/li&gt;
&lt;li&gt;some good tools for general code analysis (Java): &lt;a href="https://www.sonarqube.org/"&gt;Sonarqube&lt;/a&gt;, &lt;a href="https://pmd.github.io/"&gt;PMD&lt;/a&gt;, &lt;a href="https://spotbugs.github.io/"&gt;SpotBugs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;some good tools for security code analysis: &lt;a href="https://www.veracode.com/"&gt;Veracode&lt;/a&gt;, &lt;a href="https://www.checkmarx.com/"&gt;Checkmarx&lt;/a&gt;, &lt;a href="https://www.sonarqube.org/"&gt;Sonarqube&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;you don't need to agree with all the practices that are part of the standard rule sets of these tools (although usually they are aligned with industry recommendations); you can create a subset of rules tailored to your context&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;automate testing at all levels: unit, integration, component, API, end-to-end, etc.&lt;/li&gt;
&lt;li&gt;focus on negative and boundary testing, not only on happy scenarios; &lt;a href="https://github.com/Endava/cats"&gt;CATS&lt;/a&gt; is a good option for API testing&lt;/li&gt;
&lt;li&gt;don't ignore failing tests, even those failing intermittently; they might hide a serious underlying issues&lt;/li&gt;
&lt;li&gt;tests must be resilient and self-sufficient&lt;/li&gt;
&lt;li&gt;tests must use a similar and predictable approach&lt;/li&gt;
&lt;li&gt;tests must not depend on complicated external setup; they must either be self-sufficient by mocking dependencies, using in-memory setups or &lt;a href="https://www.testcontainers.org/"&gt;testcontainers&lt;/a&gt; or just depend on the (micro)service being deployed; any other steps will just complicate the setup and introduce complexity&lt;/li&gt;
&lt;li&gt;consider adding some &lt;a href="https://www.zaproxy.org/"&gt;security testing inside the pipeline&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;consider &lt;a href="https://en.wikipedia.org/wiki/Mutation_testing"&gt;mutation testing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  CI/CD
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;include &lt;a href="https://martinfowler.com/articles/is-quality-worth-cost.html#HighQualitySoftwareIsCheaperToProduce"&gt;Quality Gates&lt;/a&gt; for the most important stuff; they must act as checkpoints and fail the build if they are not met&lt;/li&gt;
&lt;li&gt;Quality Gates must be inline with these standards and automate the process of checking that each (micro)service is aligned&lt;/li&gt;
&lt;li&gt;a sample CI/CD pipeline might look like this:

&lt;ul&gt;
&lt;li&gt;compile and build&lt;/li&gt;
&lt;li&gt;check formatting&lt;/li&gt;
&lt;li&gt;run tests and check coverage&lt;/li&gt;
&lt;li&gt;run mutation testing&lt;/li&gt;
&lt;li&gt;run code analysis&lt;/li&gt;
&lt;li&gt;run secure code analysis&lt;/li&gt;
&lt;li&gt;check 3rd party libraries for vulnerabilities&lt;/li&gt;
&lt;li&gt;check 3rd party library licenses&lt;/li&gt;
&lt;li&gt;deploy&lt;/li&gt;
&lt;li&gt;run API tests&lt;/li&gt;
&lt;li&gt;run other types of testing&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;this might seem too much (or lengthy), but for a microservice this is quite fast&lt;/li&gt;
&lt;li&gt;script your pipeline&lt;/li&gt;
&lt;li&gt;don't couple the pipeline to the (micro)services&lt;/li&gt;
&lt;li&gt;use a template pipeline for all (micro)services&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Authentication and Authorisation
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;don't roll your own authentication and authorisation; use standards products and services&lt;/li&gt;
&lt;li&gt;authenticate all your APIs, internal and external; &lt;a href="https://dzone.com/articles/four-most-used-rest-api-authentication-methods"&gt;just pick something proven&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;use separate authentication and authorisation mechanism for external and internal calls i.e., use one set of credentials/mechanism to authenticate external calls and a separate one for internal calls&lt;/li&gt;
&lt;li&gt;credentials are always encrypted both in-flight and at-rest&lt;/li&gt;
&lt;li&gt;use HTTPS for all APIs, internal or external&lt;/li&gt;
&lt;li&gt;do not accept authentication credentials via HTTP GET; use only HTTP headers or HTTP POST/PUT&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;do not log credentials&lt;/strong&gt; not even when &lt;code&gt;debug&lt;/code&gt; on; have your logging library also act as &lt;code&gt;catch all&lt;/code&gt; for credentials&lt;/li&gt;
&lt;li&gt;make sure your authorisation and authentication mechanism allows granular control and management i.e., you can restrict number of calls per operation, revoke access, issue additional credentials, etc.&lt;/li&gt;
&lt;li&gt;consider using a centralized Identity Provider and common libraries&lt;/li&gt;
&lt;li&gt;use enhanced security controls for highly sensitive APIs/services (&lt;a href="https://en.wikipedia.org/wiki/Mutual_authentication"&gt;mutual TLS&lt;/a&gt; for APIs, &lt;a href="https://en.wikipedia.org/wiki/Multi-factor_authentication"&gt;MFA&lt;/a&gt; for access to services)&lt;/li&gt;
&lt;li&gt;use &lt;a href="https://support.kraken.com/hc/en-us/articles/360000906023-What-is-a-nonce-"&gt;nonces&lt;/a&gt; to prevent replay attacks&lt;/li&gt;
&lt;li&gt;always design and build with the &lt;a href="https://us-cert.cisa.gov/bsi/articles/knowledge/principles/least-privilege"&gt;least privilege principle&lt;/a&gt; in mind&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  General Security Practices
&lt;/h2&gt;

&lt;p&gt;Key things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;don't ever roll your own encryption&lt;/strong&gt;; you cannot reinvent the wheel in this space&lt;/li&gt;
&lt;li&gt;use industry recommended algorithms: &lt;a href="https://en.wikipedia.org/wiki/Advanced_Encryption_Standard"&gt;AES&lt;/a&gt; 256; &lt;a href="https://en.wikipedia.org/wiki/RSA_(cryptosystem)"&gt;RSA&lt;/a&gt; 2048+, &lt;a href="https://en.wikipedia.org/wiki/SHA-2"&gt;SHA-2&lt;/a&gt; 512.&lt;/li&gt;
&lt;li&gt;use TLS 1.3+ for transport security&lt;/li&gt;
&lt;li&gt;use &lt;a href="https://en.wikipedia.org/wiki/Salt_(cryptography)"&gt;salt&lt;/a&gt; and/or &lt;a href="https://en.wikipedia.org/wiki/Pepper_(cryptography)"&gt;pepper&lt;/a&gt; when encrypting or hashing sensitive data; this will prevent brute-force attacks&lt;/li&gt;
&lt;li&gt;check your programming language practices for dealing with sensitive information; for example in Java you must use &lt;code&gt;byte[]&lt;/code&gt; rather than &lt;code&gt;String&lt;/code&gt; to handle password, card numbers, social security numbers, etc.; you must minimize the time the data stays in memory and clear the objcts after use&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quality attributes
&lt;/h2&gt;

&lt;p&gt;As we've seen above, SDLC standards and practices are not always directly related to security. Same applies for quality attributes. &lt;br&gt;
Shortcomings in current design and approach can cause your application to go down, even if it is not caused by a  &lt;code&gt;true&lt;/code&gt; security problem.&lt;/p&gt;

&lt;p&gt;Key things to consider for &lt;code&gt;Performance&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use pooling for connection to expensive resources like DB, APIs, etc.&lt;/li&gt;
&lt;li&gt;use thread pools&lt;/li&gt;
&lt;li&gt;use caching&lt;/li&gt;
&lt;li&gt;use proper collections when manipulating data&lt;/li&gt;
&lt;li&gt;use parallel programming if applicable&lt;/li&gt;
&lt;li&gt;make sure you understand how your ORM generates queries&lt;/li&gt;
&lt;li&gt;avoid loading big resources in memory, use data streams&lt;/li&gt;
&lt;li&gt;baseline your performance per (micro)service instance so that you know when to scale&lt;/li&gt;
&lt;li&gt;do regular load and performance testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key things to consider for &lt;code&gt;Resilience&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use circuit breakers, retries, timeouts, rate-limiting&lt;/li&gt;
&lt;li&gt;have clear fallback strategies when dependent APIs are not available&lt;/li&gt;
&lt;li&gt;some great resources on the topic: &lt;a href="https://engineering.grab.com/designing-resilient-systems-part-1"&gt;Resilient Systems Part 1&lt;/a&gt; and &lt;a href="https://engineering.grab.com/designing-resilient-systems-part-2"&gt;Resilient System Part 2&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;make all APIs &lt;a href="https://stripe.com/blog/idempotency"&gt;Idempotent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;don't store state within one (micro)service instance; use a distributed cache for that&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key things to consider for &lt;code&gt;Availability and Scalability&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;don't make your (micro)services design limit horizontal scaling&lt;/li&gt;
&lt;li&gt;plan for failure, have automated mechanisms in place for auto-scaling based on load&lt;/li&gt;
&lt;li&gt;consider sharding, read-only replicas&lt;/li&gt;
&lt;li&gt;use multi-region deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key things to consider for &lt;code&gt;Observability and Monitoring&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;all (micro)services must expose health endpoints covering both application and the underlying container&lt;/li&gt;
&lt;li&gt;the health endpoint must return information about all its dependencies: db, encryption service, APIs it connects to, event bus, etc.&lt;/li&gt;
&lt;li&gt;leverage the standardized logging to create meaningful operational dashboards&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Automate
&lt;/h2&gt;

&lt;p&gt;Automate everything. Automation makes it predictable and consistent. &lt;br&gt;
The CI/CD pipeline should be the place where you automate all checks that will assess your (micro)service from a quality perspective.&lt;br&gt;
Tools like &lt;a href="https://semgrep.dev/"&gt;Semgrep&lt;/a&gt; can bring automation with less effort for standards not obviously suited for automation.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;This isn't a final list, it's more like a brain dump. It's a starting point for building a security mindset. Once you apply all these, you are ready to deep dive. &lt;br&gt;
Applying all these practices won't give you only security benefits, but also more structure and alignment. &lt;br&gt;
This is particularly important in systems developing too fast, either brand new or legacy. &lt;br&gt;
You don't need to go with all these from day 1, it might seem overwhelming especially if you are not used to following common standards and think it will limit your options.&lt;br&gt;
But maybe you can try it for a while and see what happens!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Pretty Logger for Java - build nice looking command line apps in Java</title>
      <dc:creator>Madalin Ilie</dc:creator>
      <pubDate>Mon, 07 Dec 2020 12:39:02 +0000</pubDate>
      <link>https://dev.to/ludovicianul/pretty-logger-for-java-build-nice-looking-command-line-apps-in-java-1fla</link>
      <guid>https://dev.to/ludovicianul/pretty-logger-for-java-build-nice-looking-command-line-apps-in-java-1fla</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffl60cu8c46tjtsu0hahu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffl60cu8c46tjtsu0hahu.png" alt="Default Theme"&gt;&lt;/a&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm3a662ud4jhsluqju0x1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm3a662ud4jhsluqju0x1.png" alt="Gestures Theme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;Java might not be the first choice when wanting to build command line applications, but as a Java developer myself, I don't see any reason for not doing so. With the rise of frameworks like &lt;a href="https://spring.io/projects/spring-boot" rel="noopener noreferrer"&gt;Spring Boot&lt;/a&gt; or &lt;a href="https://quarkus.io/" rel="noopener noreferrer"&gt;Quarkus&lt;/a&gt; and &lt;a href="https://www.graalvm.org/" rel="noopener noreferrer"&gt;GraalVM&lt;/a&gt; you can create fast, performant and powerful command line apps with ease.&lt;/p&gt;

&lt;p&gt;What you display in the console when your application is doing its magic is one of the key aspects that you need to get right. There are plenty of good practices out there on how to output quality content that will help users understand what is going on, but another important thing is aesthetics.&lt;/p&gt;

&lt;h1&gt;
  
  
  Improving aesthetics
&lt;/h1&gt;

&lt;p&gt;There are several ways of making your output more eye-catching using libraries like &lt;a href="https://github.com/fusesource/jansi" rel="noopener noreferrer"&gt;jansi&lt;/a&gt; but it usually requires either to build some common routines for formatting or treat each output individually. &lt;/p&gt;

&lt;p&gt;This is why I've created the &lt;a href="https://github.com/ludovicianul/pl4j" rel="noopener noreferrer"&gt;PL4J library&lt;/a&gt; (Pretty Logger for Java). It's a decorator for SLF4J (so that you don't need to change your logging patterns) that enriches the number of logging levels you have available and adds colourful &lt;code&gt;symbols&lt;/code&gt; and &lt;code&gt;labels&lt;/code&gt; for better aesthetics. &lt;/p&gt;

&lt;p&gt;Getting starting it's easy:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="nc"&gt;PrettyLogger&lt;/span&gt; &lt;span class="n"&gt;prettyLogger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PrettyLoggerFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TestClass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//same declaration as SLF4J&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and you have multiple levels available:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"received response from: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"http://google.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;awaiting&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"parsing input data"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;complete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"finish processing"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value is: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"190"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"not able to connect to: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"http://google.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fatal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"something went terribly wrong"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"url to connect to: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"http://google.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;note&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"remember to run CATS"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pause&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"process was paused"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;santa&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ho! ho! ho!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;star&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"run CATS next time"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"process started"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"process paused"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;prettyLogger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;warning&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unable to normalize string"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can also control &lt;code&gt;labels&lt;/code&gt;'s and &lt;code&gt;symbols&lt;/code&gt;'s &lt;code&gt;colour&lt;/code&gt;, &lt;code&gt;bold&lt;/code&gt;, &lt;code&gt;underline&lt;/code&gt; as well as setting global themes to get different &lt;code&gt;symbols&lt;/code&gt; sets entirely.&lt;/p&gt;

&lt;p&gt;You can check the entire set of features on GitHub: &lt;a href="https://github.com/ludovicianul/pl4j" rel="noopener noreferrer"&gt;https://github.com/ludovicianul/pl4j&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>logging</category>
      <category>cli</category>
    </item>
    <item>
      <title>Some small tips for improving the GitHub API</title>
      <dc:creator>Madalin Ilie</dc:creator>
      <pubDate>Mon, 09 Nov 2020 15:57:58 +0000</pubDate>
      <link>https://dev.to/ludovicianul/how-i-ended-up-with-1k-github-repos-while-testing-the-github-api-with-cats-2lj5</link>
      <guid>https://dev.to/ludovicianul/how-i-ended-up-with-1k-github-repos-while-testing-the-github-api-with-cats-2lj5</guid>
      <description>&lt;h1&gt;
  
  
  Disclaimer
&lt;/h1&gt;

&lt;p&gt;&lt;span&gt;&lt;strong&gt;!!! WARNING !!! If you choose to run the steps in this article, please note that you will end up with a significant number of dummy GitHub repos under your username. Over 1k in my case.&lt;br&gt;
There is a script at the end of the article that you can use to delete them. Be careful not to delete your real repos though!&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Fgithub_repos.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Fgithub_repos.png" alt="Repos"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  The Beginning
&lt;/h1&gt;

&lt;p&gt;Building good APIs is hard. There are plenty of resources out there with plenty of good advice on how to achieve this. While some of the things are a must, like following the &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP REST Security Practices&lt;/a&gt;,&lt;br&gt;
some others might be debatable, based on preference, "like using &lt;code&gt;snake_case&lt;/code&gt; or &lt;code&gt;camelCase&lt;/code&gt; for naming JSON objects". (I plan to write a more detailed article in the next weeks on what I consider good practices.)&lt;br&gt;
As the number of APIs usually grows significantly, even when dealing with simple systems, it's very important to have quick ways to make sure the APIs are meeting good practices consistently.&lt;/p&gt;

&lt;p&gt;I've shown in a &lt;a href="https://ludovicianul.github.io/2020/09/09/cats/" rel="noopener noreferrer"&gt;previous article&lt;/a&gt; how easy it is to use a tool like &lt;a href="https://github.com/Endava/cats" rel="noopener noreferrer"&gt;CATS&lt;/a&gt; to quickly verify OpenAPI endpoints &lt;br&gt;
while covering a significant number of tests cases. But that was a purely didactic showcase using the OpenAPI demo &lt;code&gt;petstore&lt;/code&gt; app. Which was obviously not built as a production ready service.&lt;br&gt;
Today I'll pick a real-life API, specifically the GitHub API, which recently published &lt;a href="https://github.com/github/rest-api-description/blob/main/descriptions/ghes-2.22/ghes-2.22.yaml" rel="noopener noreferrer"&gt;their OpenAPI specs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I've downloaded the 2.22 version and saved the file locally as &lt;code&gt;github.yml&lt;/code&gt;. Before we start, we need to &lt;a href="https://github.com/settings/tokens/new" rel="noopener noreferrer"&gt;create an access token&lt;/a&gt; in order to be able to call the APIs. Make sure it has proper scopes for repo creation (and deletion when using the script at the end of the article).&lt;br&gt;
Also, as the API is quite rich (the file has 59k lines), I've only selected the &lt;code&gt;/user/repos&lt;/code&gt; path for this showcase. You'll see that there are plenty of findings only using this endpoint.&lt;/p&gt;

&lt;p&gt;You can run &lt;code&gt;CATS&lt;/code&gt; as a blackbox testing tool and incrementally add minimal bits of context until you end up with consistent issues or a green suite. &lt;/p&gt;

&lt;p&gt;As shown in the &lt;a href="https://ludovicianul.github.io/2020/09/09/cats/" rel="noopener noreferrer"&gt;previous article&lt;/a&gt;, running &lt;a href="https://github.com/Endava/cats" rel="noopener noreferrer"&gt;CATS&lt;/a&gt; is quite simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./cats.jar &lt;span class="nt"&gt;--contract&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;github.yml &lt;span class="nt"&gt;--server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://api.github.com &lt;span class="nt"&gt;--paths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/user/repos"&lt;/span&gt; &lt;span class="nt"&gt;--headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;headers_github.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the &lt;code&gt;headers_github.yml&lt;/code&gt; having the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;token XXXXXXXXXXXXX&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see what we get on a first run:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Ffirst_run_github.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Ffirst_run_github.png" alt="First Run"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;We have &lt;code&gt;42 warnings&lt;/code&gt; and &lt;code&gt;156 errors&lt;/code&gt;. Let's go through the errors first. Looking at the result of &lt;code&gt;Test 118&lt;/code&gt; we see that a request failed due to the name of the repository not being unique. &lt;br&gt;
Indeed, &lt;code&gt;CATS&lt;/code&gt;, for each Fuzzer, preserves an initial payload that will be used to fuzz each of the request fields. This means that we need a way to force &lt;code&gt;CATS&lt;/code&gt; to send unique names for the &lt;code&gt;name&lt;/code&gt; field. Noted!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Ftest_118_github.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Ftest_118_github.png" alt="Test 118"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Test 426&lt;/code&gt; says that &lt;code&gt;If you specify visibility or affiliation, you cannot specify type.&lt;/code&gt;. Let's note this down also.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Ftest_426_github.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Ftest_426_github.png" alt="Test 426"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Considering the above 2 problems are reported consistently, let's give it another go with a &lt;a href="https://github.com/Endava/cats#reference-data-file" rel="noopener noreferrer"&gt;Reference Data File&lt;/a&gt;.&lt;br&gt;
This is the &lt;code&gt;refData_github.yml&lt;/code&gt; file that will be used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;/user/repos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;T(org.apache.commons.lang3.RandomStringUtils).random(5,true,true)"&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cats_remove_field"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;CATS&lt;/code&gt; supports &lt;a href="https://github.com/Endava/cats#dynamic-values-in-configuration-files" rel="noopener noreferrer"&gt;dynamic values in properties values&lt;/a&gt; via the &lt;a href="https://docs.spring.io/spring-framework/docs/3.0.x/reference/expressions.html" rel="noopener noreferrer"&gt;Spring Expression Language&lt;/a&gt;.&lt;br&gt;
Using the above &lt;code&gt;refData&lt;/code&gt; file, &lt;code&gt;CATS&lt;/code&gt; will now generate a new random &lt;code&gt;name&lt;/code&gt; everytime it will execute a request to the GitHub API.&lt;br&gt;
Also, using the &lt;code&gt;cats_remove_field&lt;/code&gt; value, &lt;code&gt;CATS&lt;/code&gt; will remove this field from all requests before sending them to the endpoint. More details on this feature &lt;a href="https://github.com/Endava/cats#removing-fields" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;CATS&lt;/code&gt; again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./cats.jar &lt;span class="nt"&gt;--contract&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;github.yml &lt;span class="nt"&gt;--server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://api.github.com &lt;span class="nt"&gt;--paths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/user/repos"&lt;/span&gt; &lt;span class="nt"&gt;--headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;headers_github.yml &lt;span class="nt"&gt;--refData&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;refData_github.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now get &lt;code&gt;17 warnings&lt;/code&gt; and &lt;code&gt;90 errors&lt;/code&gt;. Again, looking though the tests failures/warnings there are some tests which are failing due to the fact the &lt;code&gt;since&lt;/code&gt; and &lt;code&gt;before&lt;/code&gt; are not sent in ISO8061 timestamp format (more on this inconsistency in the Findings section).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Fsecond_run_github.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Fsecond_run_github.png" alt="Second Run"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll now update the &lt;code&gt;refData&lt;/code&gt; file to look as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;/user/repos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;before&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;T(java.time.Instant).now().toString()"&lt;/span&gt;
  &lt;span class="na"&gt;since&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;T(java.time.Instant).now().minusSeconds(86400).toString()"&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;T(org.apache.commons.lang3.RandomStringUtils).random(5,true,false)"&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cats_remove_field"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and run &lt;code&gt;CATS&lt;/code&gt; again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./cats.jar &lt;span class="nt"&gt;--contract&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;github.yml &lt;span class="nt"&gt;--server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://api.github.com &lt;span class="nt"&gt;--paths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/user/repos"&lt;/span&gt; &lt;span class="nt"&gt;--headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;headers_github.yml &lt;span class="nt"&gt;--refData&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;refData_github.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Fthird_run_github.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Fthird_run_github.png" alt="Third Run"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We now get &lt;code&gt;5 warnings&lt;/code&gt; and &lt;code&gt;83 errors&lt;/code&gt;. Looking through the errors and warnings, there is a significant amount which I consider legit issues while some are debatable points, depending on preference/standards being followed. &lt;br&gt;
Let's go through the findings. &lt;/p&gt;
&lt;h1&gt;
  
  
  Findings
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Invalid values for boolean fields implicitly converted to false
&lt;/h2&gt;

&lt;p&gt;One of the Fuzzers that &lt;code&gt;CATS&lt;/code&gt; has is the &lt;code&gt;BooleanFieldsFuzzer&lt;/code&gt;. &lt;br&gt;
This Fuzzer works on the assumption that if you send an invalid value into a &lt;code&gt;boolean&lt;/code&gt; field, the service should return a validation error.&lt;br&gt;
Obviously, the GitHub API does not do this, but is rather silently converting the value to &lt;code&gt;false&lt;/code&gt;. It's true this is a consistent behaviour, applying for all boolean fields like &lt;code&gt;auto_init&lt;/code&gt;, &lt;code&gt;allow_merge_commits&lt;/code&gt;, etc, but I would personally choose to return a validation error in these cases.&lt;/p&gt;

&lt;p&gt;This is in contradiction with the &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html#input-validation" rel="noopener noreferrer"&gt;OWASP recommendation&lt;/a&gt; around strong input validation and data type enforcing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Invalid values for enumerated fields implicitly converted to the default value (?)
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;InvalidValuesInEnumsFieldsFuzzer&lt;/code&gt; will send invalid values in enum fields. It expects a validation error in return. &lt;br&gt;
The GitHub API does not seem to reject invalid values, but rather convert them to a default value and respond successfully to the request.&lt;/p&gt;

&lt;p&gt;This is in contradiction with the &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html#input-validation" rel="noopener noreferrer"&gt;OWASP recommendation&lt;/a&gt; around strong input validation and data type enforcing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Integer fields accepting decimal or large negative or positive values
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;DecimalValuesInIntegerFieldsFuzzer&lt;/code&gt; expects an error when it sends a &lt;code&gt;decimal&lt;/code&gt; value inside an &lt;code&gt;integer&lt;/code&gt; field. The GitHub API seems to accept these invalid values in the &lt;code&gt;team_id&lt;/code&gt; field without returning any error, but rather resulting in a successful processing of the request.&lt;br&gt;
Same applies for &lt;code&gt;ExtremePositiveValueInIntegerFieldsFuzzer&lt;/code&gt; and &lt;code&gt;ExtremeNegativeValueIntegerFieldsFuzzer&lt;/code&gt; which will send values such as &lt;code&gt;9223372036854775807&lt;/code&gt; or &lt;code&gt;-9223372036854775808&lt;/code&gt; in the &lt;code&gt;team_id&lt;/code&gt; field.&lt;br&gt;
Strings also seem to be accepted in the &lt;code&gt;team_id&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;This is in contradiction with the &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html#input-validation" rel="noopener noreferrer"&gt;OWASP recommendation&lt;/a&gt; around strong input validation and data type enforcing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Accepts unsupported or dummy Content-Type headers
&lt;/h2&gt;

&lt;p&gt;The GitHub API seems to successfully accept and process requests containing unsupported (according to the OpenAPI contract) &lt;code&gt;Content-Type&lt;/code&gt; headers such as: &lt;code&gt;image/gif&lt;/code&gt;, &lt;code&gt;multipart/related&lt;/code&gt;, etc. or dummy ones such as &lt;code&gt;application/cats&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This is in contradiction with the &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html#validate-content-types" rel="noopener noreferrer"&gt;OWASP recommendation&lt;/a&gt; around validation around content types.&lt;/p&gt;
&lt;h2&gt;
  
  
  Accepts duplicate headers
&lt;/h2&gt;

&lt;p&gt;The GitHub API does not reject requests that contain duplicate headers. The HTTP standard itself allows duplicate headers for specific cases, but allowing duplicate headers might lead to hidden bugs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Spaces are not trimmed from values
&lt;/h2&gt;

&lt;p&gt;If the request fields are prefixed or trailed with spaces, they are rejected as invalid values. For example sending a &lt;code&gt;Haskell&lt;/code&gt; space-prefixed value in the &lt;code&gt;gitignore_template&lt;/code&gt; will cause the service to return an error.&lt;br&gt;
Although this is inconsistent with the fact that if you trail or prefix the &lt;code&gt;since&lt;/code&gt; and &lt;code&gt;before&lt;/code&gt; fields with spaces, the values get trimmed successfully and converted to dates.&lt;br&gt;
As a common approach I think that services should consistently trim spaces by default (maybe with some business-driven special cases) for all request fields and perform the validation after.&lt;/p&gt;
&lt;h2&gt;
  
  
  Accepting new fields in the request
&lt;/h2&gt;

&lt;p&gt;The GitHub API seems to allow injection of new json fields inside the requests. The &lt;code&gt;NewFieldsFuzzer&lt;/code&gt; adds a new &lt;code&gt;catsField&lt;/code&gt; inside a request, but GitHub API accepts it as valid.&lt;br&gt;
This is again in contradiction with the &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html#input-validation" rel="noopener noreferrer"&gt;OWASP recommendation&lt;/a&gt; which suggests rejecting unexpected content.&lt;/p&gt;
&lt;h2&gt;
  
  
  Doesn't make proper use of enumerated values
&lt;/h2&gt;

&lt;p&gt;There are cases when it makes sense to use enums rather than free text. Some examples are the &lt;code&gt;gitignore_template&lt;/code&gt; field or the &lt;code&gt;license_template&lt;/code&gt; field, which are rejecting invalid values. They are obviously having a pre-defined list of values, but do not enforce this in any way in the contract.&lt;br&gt;
Having them listed as enums will also make it easier to understand what are all supported templates for example.&lt;/p&gt;
&lt;h1&gt;
  
  
  Fields are not making proper use of the format
&lt;/h1&gt;

&lt;p&gt;There are 2 fields called &lt;code&gt;since&lt;/code&gt; and &lt;code&gt;before&lt;/code&gt; which seem to actually be a &lt;code&gt;date-time&lt;/code&gt;, although in the OpenAPI contract they are only marked as &lt;code&gt;string&lt;/code&gt; without any additional &lt;code&gt;format&lt;/code&gt; information. In the description of the fields it states that this is actually an ISO date, but it will also be good to leverage &lt;a href="https://swagger.io/docs/specification/data-models/data-types/" rel="noopener noreferrer"&gt;the features of OpenAPI&lt;/a&gt; and mark them accordingly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Fdate_time_github.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Fdate_time_github.png" alt="Date-Time Error"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Mismatch of validation between front-end driven calls and direct API calls
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;homepage&lt;/code&gt; field seems to accept any values when doing a direct API call, but when you try to set this from the UI, you will get an error saying that you need to enter a valid URL. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Fui_error_github.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fludovicianul%2Fludovicianul.github.io%2Fraw%2Fmaster%2Fimages%2Fui_error_github.png" alt="Validation Error from the UI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having the same level of validation for backend and frontend is another good practice for making sure you don't end up with inconsistent data.&lt;/p&gt;
&lt;h1&gt;
  
  
  Additional findings
&lt;/h1&gt;

&lt;p&gt;There are some other failures which might seem debatable or not applicable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt; accepts very large strings (50k characters sent by CATS), although the GitHub API doesn't actually have constraint information in the contract; again this is not necessarily a problem, but it's important for the contract to enforce constraints&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;RecommendedHeadersFuzzer&lt;/code&gt; expects a &lt;code&gt;CorrelationId/TraceId&lt;/code&gt; to be defined in the headers, but this being a public API, it's not actually applicable&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;CheckSecurityHeadersFuzzer&lt;/code&gt; expects a &lt;code&gt;Cache-Control: no-store&lt;/code&gt; as per the OWASP recommendations, but the endpoint does not operate critical data, so allowing caching of the information is fine&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Cleaning Up
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Before proceeding, please be careful to not delete your real repos&lt;/strong&gt;.&lt;br&gt;
This is the script I've used to delete the repos. Run it incrementally and please check the &lt;code&gt;repos&lt;/code&gt; file before deleting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# get the latest 100 repos (by creation date)&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"https://api.github.com/users/ludovicianul/repos?sort=created&amp;amp;direction=desc&amp;amp;per_page=100"&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.[].name'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; repos

&lt;span class="c"&gt;# Maybe check them a bit before deleting them to make sure you don't delete real repos&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;URL &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;repos&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  curl &lt;span class="nt"&gt;-X&lt;/span&gt; DELETE &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: token PERSONAL_TOKEN'&lt;/span&gt; https://api.github.com/repos/ludovicianul/&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;# delete the file&lt;/span&gt;
&lt;span class="nb"&gt;rm &lt;/span&gt;repos

&lt;span class="c"&gt;#start over until you delete everything&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need to run it several times as it deletes in batches of 100.&lt;/p&gt;

&lt;h1&gt;
  
  
  Final Conclusions
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;CATS&lt;/code&gt; can be very powerful and can save lots of time while testing APIs. Because it tests every single field within a request, it's easy to spot inconsistencies or cases when the APIs are not as explicit as it should.&lt;br&gt;
Although I only tested a single endpoint from the GitHub API, I suspect most the findings will apply to all the other endpoints.&lt;br&gt;
Why not &lt;a href="https://github.com/Endava/cats" rel="noopener noreferrer"&gt;give it a try&lt;/a&gt; for your API?&lt;/p&gt;

</description>
      <category>java</category>
      <category>webdev</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How to write self-healing functional API tests with no coding effort</title>
      <dc:creator>Madalin Ilie</dc:creator>
      <pubDate>Thu, 10 Sep 2020 07:33:22 +0000</pubDate>
      <link>https://dev.to/ludovicianul/how-to-write-self-healing-functional-api-tests-with-no-coding-effort-13</link>
      <guid>https://dev.to/ludovicianul/how-to-write-self-healing-functional-api-tests-with-no-coding-effort-13</guid>
      <description>&lt;h1&gt;
  
  
  Context
&lt;/h1&gt;

&lt;p&gt;APIs are everywhere, and it's critical to have ways to efficiently test that they work correctly. &lt;br&gt;
There are several tools out there that are used for API testing, and the vast majority will require you to write the tests from scratch, even though in essence you test similar scenarios and apply the same testing techniques as you did in other apps/contexts.&lt;br&gt;
This article will show you a better way to tackle API testing that requires less effort on the "similar scenarios" part and allows you to focus on the more complex part of the activities.&lt;/p&gt;
&lt;h1&gt;
  
  
  Testing APIs
&lt;/h1&gt;

&lt;p&gt;When thinking about testing APIs, from a functional perspective, there are several dimensions which come to mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;verifying the structure of the exchanged data i.e. &lt;strong&gt;structural validations&lt;/strong&gt; (length, data type, patterns, etc). This is where you send a 2 character string when the API say the minimum is 3, you put a slightly invalid email address, an slightly invalid format for a date field and so on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;boundary testing and negative scenarios&lt;/strong&gt;, similar a bit to the above, but focusing on "breaking" the application. This is where you go to the extreme: you send extremely large values in Strings, extremely positive or negative values in Integers and so on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;behaviour according to documentation i.e. APIs are &lt;strong&gt;responding as expected&lt;/strong&gt; in terms of HTTP status codes or response payloads. This is where you check that the service responds as documented: with a proper HTTP response code (2XX for a success, 400 for a bad request, etc) and a proper response body.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;functional scenarios i.e. APIS are &lt;strong&gt;working as expected&lt;/strong&gt; in terms of expected business behaviour. This is where you check that the response body contains the right business information: when you perform an action (like creating an entity, altering its state) the service correctly responds that the action was performed and with relevant information.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;linked functional scenarios i.e. you create an entity and you get its details after to check they are the same. This is where you get a bit more end-to-end and you perform an action (like creating an entity) and with the return identifier you go and check the existence (you do a GET based on the identifier) &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ideally all the above scenarios must be automated. And it's achievable to do this for the last 2 categories, but when having complex APIs with lots and lots of fields within the request payload, it becomes very hard to make sure you create negative and boundary testing scenarios for &lt;strong&gt;all&lt;/strong&gt; fields.&lt;/p&gt;
&lt;h1&gt;
  
  
  What are the options for API test automation
&lt;/h1&gt;

&lt;p&gt;There are several frameworks and tools on the market which can help to automate all these. Just to name a few: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://rest-assured.io/"&gt;Rest Assured&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://square.github.io/retrofit/"&gt;Retrofit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.postman.com/"&gt;Postman&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.soapui.org/"&gt;SoapUI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are all great tools and frameworks. You start writing test cases for the above categories. The tools/frameworks will provide different sets of facilities which might reduce specific effort during implementation, but ultimately you end up writing the actual tests to be executed (i.e. code). &lt;br&gt;
Even if you've done this before, and you know exactly what to test, even if you create a mini-framework that provides facilities for the common elements, you still need to write a considerable amount of code in order to automate all your testing scenarios.&lt;/p&gt;

&lt;p&gt;And what happens when the API changes a bit? Some fields might be more restrictive in terms of validation, some might change the type, some might get renamed and so on. And then the API changes &lt;strong&gt;a bit more&lt;/strong&gt;?&lt;br&gt;
This is usually not very rewarding work. Software engineers are usually &lt;strong&gt;creative creatures&lt;/strong&gt;, and they like &lt;strong&gt;challenges&lt;/strong&gt; and &lt;strong&gt;solving problems&lt;/strong&gt;, not doing boring stuff. &lt;br&gt;
There are cases when one might choose to leave the API as is in order to prevent changing too many test cases.&lt;/p&gt;
&lt;h1&gt;
  
  
  Is there a better way?
&lt;/h1&gt;

&lt;p&gt;But what if there is an alternative to this, and the first 3 categories above can be fully automated, including the &lt;strong&gt;actual writing&lt;/strong&gt; of the test case. &lt;br&gt;
And also make the next 2 categories extremely simple to write and maintain. This is the reason I wrote &lt;a href="https://github.com/Endava/cats"&gt;CATs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Endava/cats"&gt;CATs&lt;/a&gt; has 3 main goals in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;remove the boring activities&lt;/strong&gt; when testing APIs by automating the entire testing lifecycle: write, execute and report of test cases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;auto-heal&lt;/strong&gt; when APIs change&lt;/li&gt;
&lt;li&gt;make writing &lt;strong&gt;functional scenarios&lt;/strong&gt; as &lt;strong&gt;simple&lt;/strong&gt; as possible by entirely removing the need to write code, while still leveraging the first 2 points&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;CATs&lt;/code&gt; has built-in &lt;a href="https://github.com/Endava/cats#how-the-fuzzing-works"&gt;Fuzzers&lt;/a&gt; which are actually pre-defined test cases with expected results that will validate if the API response as expected for a bunch of scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;send string values in numeric fields&lt;/li&gt;
&lt;li&gt;send outside the boundary values where constraints exist&lt;/li&gt;
&lt;li&gt;send values not matching pre-defined regex patterns&lt;/li&gt;
&lt;li&gt;remove fields from reuqests&lt;/li&gt;
&lt;li&gt;add new fields inside the requests&lt;/li&gt;
&lt;li&gt;and so on...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find a list of all the available &lt;code&gt;Fuzzers&lt;/code&gt; here: &lt;a href="https://github.com/Endava/cats#available-fuzzers"&gt;https://github.com/Endava/cats#available-fuzzers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is one catch though. Your API must provide an &lt;a href="https://swagger.io/specification/"&gt;OpenAPI&lt;/a&gt; contract/spec. But this shouldn't be an issue in my opinion. It's good practice having your API documented in a tools-friendly format. &lt;br&gt;
Many companies are building &lt;a href="https://github.blog/2020-07-27-introducing-githubs-openapi-description/"&gt;OpenAPI specs for their API&lt;/a&gt; for easier tools integration.&lt;/p&gt;
&lt;h1&gt;
  
  
  Using CATs
&lt;/h1&gt;

&lt;p&gt;Let's take an example to show exactly how &lt;code&gt;CATs&lt;/code&gt; works. I've chosen the &lt;a href="https://github.com/OpenAPITools/openapi-petstore"&gt;Pet-Store&lt;/a&gt; application from the OpenAPITools example section.&lt;br&gt;
The OpenAPI spec is available in the same repo: &lt;a href="https://github.com/OpenAPITools/openapi-petstore/blob/master/src/main/resources/openapi.yaml"&gt;https://github.com/OpenAPITools/openapi-petstore/blob/master/src/main/resources/openapi.yaml&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Looking at the contract, how much time would you estimate would take to create an automation suite to properly test this API? 1 Day? 2 Days? Several days?&lt;br&gt;
Using &lt;code&gt;CATs&lt;/code&gt; this will probably be a couple of hours. &lt;/p&gt;

&lt;p&gt;Let's start the pet-store application on the local box first (you need to have &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; installed):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull openapitools/openapi-petstore
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;OPENAPI_BASE_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/v3 &lt;span class="nt"&gt;-p&lt;/span&gt; 80:8080 openapitools/openapi-petstore
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will make the app available at &lt;code&gt;http://localhost&lt;/code&gt; for the Swagger UI, and the API will be available at &lt;code&gt;http://localhost/v3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Download the &lt;a href="https://github.com/Endava/cats/releases"&gt;latest CATs version&lt;/a&gt;. Download also the &lt;a href="https://github.com/OpenAPITools/openapi-petstore/blob/master/src/main/resources/openapi.yaml"&gt;openapi.yml&lt;/a&gt; from above.&lt;/p&gt;

&lt;p&gt;Before running &lt;code&gt;CATs&lt;/code&gt;, please &lt;a href="https://github.com/Endava/cats#how-the-fuzzing-works"&gt;read how it works&lt;/a&gt; in order to better interpret the results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the built-in test cases
&lt;/h2&gt;

&lt;p&gt;Suppose both &lt;code&gt;cats.jar&lt;/code&gt; and the &lt;code&gt;openapi.yml&lt;/code&gt; are in the same folder, you can now run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;./cats.jar &lt;span class="nt"&gt;--server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost/v3 &lt;span class="nt"&gt;--contract&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;openapi.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You will get something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2FW_QeYD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/eg07pcwio5jk6zob6j4h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2FW_QeYD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/eg07pcwio5jk6zob6j4h.png" alt="First Run"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not bad! We just generated &lt;code&gt;437&lt;/code&gt; test cases, out of which &lt;code&gt;78&lt;/code&gt; were already successful, and we've potentially found &lt;code&gt;181&lt;/code&gt; bugs. To view the entire report, just open &lt;code&gt;test-report/index.html&lt;/code&gt;. You will see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RqBFiDsO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/83pxe355lfwhkauldgma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RqBFiDsO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/83pxe355lfwhkauldgma.png" alt="Test Report First Run"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's check if the reported &lt;code&gt;errors&lt;/code&gt; are actually bugs or just configuration issues. We will deal with the &lt;code&gt;warnings&lt;/code&gt; after.&lt;br&gt;
Checking the first failing test (just click on the table row) we can see that the reason for failing is actually due to the fact that we didn't send any form of authentication along with the requests.&lt;br&gt;
Looking in the &lt;code&gt;openapi.yml&lt;/code&gt; we can see that some endpoints require authentication while some others require an &lt;code&gt;api_key&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YwCFoHk---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/t2pk58viv1uf1dzksmqu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YwCFoHk---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/t2pk58viv1uf1dzksmqu.png" alt="Auth Required"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CATs&lt;/code&gt; supports &lt;a href="https://github.com/Endava/cats#headers-file"&gt;passing any type of headers with the requests&lt;/a&gt;.&lt;br&gt;
Let's create the following &lt;code&gt;headers.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bearer 5cc40680-4b7d-4b81-87db-fd9e750b060b&lt;/span&gt;
   &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;special-key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can obtain the &lt;code&gt;Bearer&lt;/code&gt; token by authenticating in the Swagger UI. The &lt;code&gt;api_key&lt;/code&gt; has a fixed value as stated in the &lt;a href="https://github.com/OpenAPITools/openapi-petstore"&gt;pet-store documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's do another run, including now the &lt;code&gt;headers.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;./cats.jar &lt;span class="nt"&gt;--contract&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;openapu.yml &lt;span class="nt"&gt;--server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost/v3 &lt;span class="nt"&gt;--headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;headers.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A bit better now. &lt;code&gt;93&lt;/code&gt; successful and &lt;code&gt;140&lt;/code&gt; potential bugs. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9l-poB4R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rg0e9v7rq3g4d42345vw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9l-poB4R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rg0e9v7rq3g4d42345vw.png" alt="Second Run"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Again, let's check if there are any configuration issues, or they are valid &lt;code&gt;errors&lt;/code&gt;. Looking at &lt;code&gt;test 1253&lt;/code&gt; we can see that the target endpoint has a parameter inside the url. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VzOXcSfq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/iqs7i8sh6idg13v2m1qt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VzOXcSfq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/iqs7i8sh6idg13v2m1qt.png" alt="Test 1253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a limitation of &lt;code&gt;CATs&lt;/code&gt; as it cannot both fuzz the URL and the payloads for &lt;code&gt;POST, PUT and PATCH&lt;/code&gt; requests. And looking at the contract, indeed, there are several other endpoints that are in the same situation.&lt;br&gt;
For this particular cases &lt;code&gt;CATs&lt;/code&gt; uses the &lt;code&gt;urlParams&lt;/code&gt; argument in order to pass some fixed values for these parameters. The provided values must result in existing HTTP resources so that the fuzzing works as expected.&lt;/p&gt;

&lt;p&gt;We run &lt;code&gt;CATs&lt;/code&gt; again, considering also the &lt;code&gt;urlParams&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;./cats.jar r &lt;span class="nt"&gt;--contract&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;openapi.yml &lt;span class="nt"&gt;--server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost/v3 &lt;span class="nt"&gt;--headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;headers.yml &lt;span class="nt"&gt;--urlParams&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"username:username,petId:10,orderId=1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;91&lt;/code&gt; passed test cases and "just" &lt;code&gt;81&lt;/code&gt; potential bugs. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HwtuNfay--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tcfnc4lctwgz8nciodaz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HwtuNfay--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tcfnc4lctwgz8nciodaz.png" alt="Third Run"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's check again if these are actual &lt;code&gt;errors&lt;/code&gt;. This time, they all seem to be valid bugs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Test 429&lt;/code&gt;: the server returns a &lt;code&gt;500 Internal Error&lt;/code&gt; instead of a normal &lt;code&gt;200&lt;/code&gt; empty response&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Test 520&lt;/code&gt;: &lt;code&gt;CATs&lt;/code&gt; injects a new field inside the request, but the server still responds with &lt;code&gt;200&lt;/code&gt; instead of returning a &lt;code&gt;400 Bad Request&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Test 523&lt;/code&gt;: &lt;code&gt;CATs&lt;/code&gt; sends a null value in a non-required field (according to the contract) and expects a &lt;code&gt;2xx&lt;/code&gt; response, while the server replies with &lt;code&gt;500 evend ID cannot be null&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;and so on...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We now truely have &lt;code&gt;81&lt;/code&gt; bugs which must be fixed in order to have a stable service.&lt;/p&gt;

&lt;p&gt;Now, going into the &lt;code&gt;warnings&lt;/code&gt; zone, these are usually tests which fail "just a bit". The server usually responds withing the expected HTTP response code family, but either the HTTP status code is not documented inside the contract, or the response body doesn't match the one documented in the contract.&lt;br&gt;
Either way, these also must be fixed as it shows that the OpenAPI spec is incomplete or that the actual implementation deviated from it.&lt;/p&gt;

&lt;p&gt;Looking at what we've got at the end, with a small effort investment we were able to "write", run and report 430 test cases which otherwise would have taken significant more effort to implement and run.&lt;br&gt;
We have both validation that the service works well in certain areas, it must update the OpenAPI specs or tweak the service to response as expected and got a list of bugs for behaviour which is not working properly.&lt;/p&gt;
&lt;h2&gt;
  
  
  Running custom test cases
&lt;/h2&gt;

&lt;p&gt;But we can do even more. As mentioned previously &lt;code&gt;CATs&lt;/code&gt; also supports running custom tests with minimal effort. This is done using the &lt;a href="https://github.com/Endava/cats#customfuzzer"&gt;CustomFuzzer&lt;/a&gt;.&lt;br&gt;
The &lt;code&gt;CustomFuzzer&lt;/code&gt; will run tests configured within a &lt;code&gt;customFuzzer&lt;/code&gt; file that has a straightforward syntax. &lt;br&gt;
The cool think about the custom tests is that you &lt;strong&gt;don't need to fill in all the details within the request, just the fields that you care about&lt;/strong&gt;.&lt;br&gt;
Below is an example of running 2 simple test cases that create a &lt;code&gt;Pet&lt;/code&gt; and verify the details of a &lt;code&gt;Pet&lt;/code&gt;. This is saved as &lt;code&gt;customFuzzer-pet.yml&lt;/code&gt;. (Ideally we should correlate these 2, but it seems that the pet-store API is not returning an ID when you create a Pet).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;/pet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create a new Pet&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CATs"&lt;/span&gt;
    &lt;span class="na"&gt;expectedResponseCode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;
&lt;span class="s"&gt;/pet/{petId}&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get the details of a given Pet&lt;/span&gt;
    &lt;span class="na"&gt;petId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;11&lt;/span&gt;
    &lt;span class="na"&gt;expectedResponseCode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;
    &lt;span class="na"&gt;verify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;11&lt;/span&gt;
      &lt;span class="s"&gt;category#id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We now run &lt;code&gt;CATs&lt;/code&gt; again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;./cats.jar  &lt;span class="nt"&gt;--contract&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;openapi.yml &lt;span class="nt"&gt;--server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost/v3 &lt;span class="nt"&gt;--headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;header_pet.yml &lt;span class="nt"&gt;--fuzzers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;CustomFuzzer &lt;span class="nt"&gt;--customFuzzerFile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;customFuzzer-pet.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And we get the following result:&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GibaLoOb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cs9qy8izrthwcsd8w0xg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GibaLoOb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cs9qy8izrthwcsd8w0xg.png" alt="Custom Fuzzer"&gt;&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The 2 &lt;code&gt;warnings&lt;/code&gt; are also due to the fact that the response codes are not proeprly documented in the OpenApi contract.&lt;/p&gt;

&lt;p&gt;And you get the same benefits as when writing the test cases using actual code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you can choose the elements to verify in the responses, using the &lt;code&gt;verify&lt;/code&gt; section&lt;/li&gt;
&lt;li&gt;you can check for expected HTTP status codes using &lt;code&gt;expectedResponseCode&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;and you can even pass values from one test to another using &lt;code&gt;output&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As mentioned above, ideally, when getting the Pet details, you should pass an ID received when initially creating the Pet to make sure that is the same Pet. The &lt;code&gt;customFuzzer-pet.yml&lt;/code&gt; will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt; &lt;span class="s"&gt;/pet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;test1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create a new Pet&lt;/span&gt;
     &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CATs"&lt;/span&gt;
     &lt;span class="na"&gt;expectedResponseCode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;
     &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;pet_d&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
 &lt;span class="s"&gt;/pet/{petId}&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;test2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get the details of a given Pet&lt;/span&gt;
     &lt;span class="na"&gt;petId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${pet_id}&lt;/span&gt;
     &lt;span class="na"&gt;expectedResponseCode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;
     &lt;span class="na"&gt;verify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CATs"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  What about auto-healing
&lt;/h1&gt;

&lt;p&gt;Auto-healing is built in. As &lt;code&gt;CATs&lt;/code&gt; generates all its tests from the OpenAPI contract, when the API updates i.e the OpenAPI contract updates also, &lt;code&gt;CATs&lt;/code&gt; will generate the tests accordingly.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusions
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;CATs&lt;/code&gt; is not intended to replace your existing tooling (although it might do it to a considerable extent). &lt;br&gt;
It's a simple way to remove some of the boring parts of API testing by proving built-in test cases which can be run out-of-the box.&lt;br&gt;
It also makes sure it covers &lt;strong&gt;all fields&lt;/strong&gt; from request bodies and has a good tolerance for API changes.&lt;/p&gt;

&lt;p&gt;In the same time, it might be appealing for people that want to automate API test cases, but might not have the necessary skills to use tools required significant coding.&lt;/p&gt;

&lt;p&gt;Why not &lt;a href="https://github.com/Endava/cats"&gt;give it a try&lt;/a&gt;?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>opensource</category>
      <category>api</category>
    </item>
  </channel>
</rss>
