<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://carolinahpinto.github.io/portfolio/feed.xml" rel="self" type="application/atom+xml" /><link href="https://carolinahpinto.github.io/portfolio/" rel="alternate" type="text/html" /><updated>2026-11-04T16:23:40-05:00</updated><id>https://carolinahpinto.github.io/portfolio/feed.xml</id><title type="html">Carolina Pinto</title><subtitle>Cybersecurity portfolio of Carolina Pinto: GRC, incident response, vulnerability management and hands-on security projects.</subtitle><author><name>Carolina Pinto</name></author><entry><title type="html">Business Continuity and Disaster Recovery: Planning for When Things Go Wrong</title><link href="https://carolinahpinto.github.io/portfolio/blog/2026/11/business-continuity-and-disaster-recovery/" rel="alternate" type="text/html" title="Business Continuity and Disaster Recovery: Planning for When Things Go Wrong" /><published>2026-11-04T00:00:00-05:00</published><updated>2026-11-04T00:00:00-05:00</updated><id>https://carolinahpinto.github.io/portfolio/blog/2026/11/business-continuity-and-disaster-recovery</id><content type="html" xml:base="https://carolinahpinto.github.io/portfolio/blog/2026/11/business-continuity-and-disaster-recovery/"><![CDATA[<p>Security teams work hard to keep threats out, but no defense is perfect. Sometimes an incident happens anyway. A breach can mean lost profits, lost customers, and a damaged reputation, so organizations need a plan for what to do next.</p>

<p>Think of it like a fire drill. Nobody expects a fire, but when one starts, you don’t want people improvising. Two plans handle this in security: the <strong>business continuity plan</strong> and the <strong>disaster recovery plan</strong>.</p>

<h2 id="where-these-plans-fit-a-four-part-process">Where these plans fit: a four-part process</h2>

<p>Most security teams follow four steps to protect an organization, and the continuity and recovery plans come last:</p>

<ol>
  <li><strong>Identify</strong> the assets that must be protected.</li>
  <li><strong>Determine</strong> the threats that could harm those assets.</li>
  <li><strong>Implement</strong> tools and processes to detect those threats.</li>
  <li><strong>Create</strong> the business continuity and disaster recovery plans. This is usually handled by IT or the appropriate business function, and the two plans are made together.</li>
</ol>

<p>Notice the order. You can’t plan a recovery for assets you haven’t identified.</p>

<h2 id="the-business-continuity-plan">The business continuity plan</h2>

<p>A <strong>business continuity plan</strong> is a document outlining the procedures to keep business operations going during and after a significant disruption. Its goal is to limit damage like lost profits and customers.</p>

<p>There are four essential steps:</p>

<ol>
  <li><strong>Conduct a business impact analysis.</strong> Look at the possible effects a disruption of business functions could have on the organization.</li>
  <li><strong>Identify, document, and implement recovery steps</strong> for critical business functions and processes. This gives the team actionable steps to respond to a security event.</li>
  <li><strong>Organize a business continuity team.</strong> This brings together people from departments like cybersecurity, IT, HR, communications, and operations to carry out the plan if needed.</li>
  <li><strong>Train the team.</strong> Training exercises walk through different risk scenarios so the team is prepared for real threats.</li>
</ol>

<h2 id="the-disaster-recovery-plan">The disaster recovery plan</h2>

<p>A <strong>disaster recovery plan</strong> outlines the steps the security team takes to minimize the impact of a security incident and resolve the threat. Imagine a ransomware attack that stops the manufacturing team from retrieving certain data. The disaster recovery plan is what guides the response.</p>

<p>Its steps include:</p>

<ul>
  <li>Implementing recovery strategies to restore software</li>
  <li>Implementing recovery strategies to restore hardware functionality</li>
  <li>Identifying applications and data that might be affected after an incident</li>
</ul>

<h2 id="how-they-differ">How they differ</h2>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>Business continuity plan</th>
      <th>Disaster recovery plan</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Focus</strong></td>
      <td>Keeping the business running</td>
      <td>Restoring systems and resolving the threat</td>
    </tr>
    <tr>
      <td><strong>Question it answers</strong></td>
      <td>How do we keep operating during and after a disruption?</td>
      <td>How do we get our software, hardware, and data back?</td>
    </tr>
    <tr>
      <td><strong>Created</strong></td>
      <td>Alongside the other plan</td>
      <td>Alongside the other plan</td>
    </tr>
  </tbody>
</table>

<p>Both aim at the same goal: minimizing the damage of a successful attack.</p>

<p><em>See recovery planning in action in my <a href="/portfolio/projects/icmp-flood-incident/">ICMP Flood DoS incident report</a>.</em></p>

<h2 id="key-takeaways">Key takeaways</h2>

<ul>
  <li>Continuity and recovery plans are the final step of a four-part process: identify assets, determine threats, implement detection, create the plans.</li>
  <li>A business continuity plan keeps operations running during and after a disruption.</li>
  <li>A disaster recovery plan restores software, hardware, and data and helps resolve the threat.</li>
  <li>The two plans are created together and strengthen an organization’s overall security posture.</li>
  <li>Having plans in place means the organization keeps moving forward even when an incident occurs.</li>
</ul>]]></content><author><name>Carolina Pinto</name></author><category term="GRC &amp; Frameworks" /><category term="business continuity" /><category term="disaster recovery" /><category term="incident response" /><category term="grc" /><summary type="html"><![CDATA[Where continuity and recovery plans fit in protecting an organization, what goes into each, and how they differ.]]></summary></entry><entry><title type="html">Data and Asset Classification: Not All Information Is Created Equal</title><link href="https://carolinahpinto.github.io/portfolio/blog/2026/11/data-and-asset-classification/" rel="alternate" type="text/html" title="Data and Asset Classification: Not All Information Is Created Equal" /><published>2026-11-02T00:00:00-05:00</published><updated>2026-11-02T00:00:00-05:00</updated><id>https://carolinahpinto.github.io/portfolio/blog/2026/11/data-and-asset-classification</id><content type="html" xml:base="https://carolinahpinto.github.io/portfolio/blog/2026/11/data-and-asset-classification/"><![CDATA[<p>Picture an office building. The lobby is open to anyone, the staff areas need a badge, and the vault in the basement needs a badge, a second approval, and a signed agreement. Nobody would guard the lobby the way they guard the vault, because the cost of losing what’s inside is completely different.</p>

<p>Security professionals think about data the same way. Protecting an organization’s operations and assets from threats, risks, and vulnerabilities is the whole job, but you can’t protect everything equally. You need to know what matters most. That’s what <strong>data classification</strong> is for.</p>

<h2 id="the-four-data-types">The four data types</h2>

<p>Most organizations sort data into four categories, from least to most protected.</p>

<h3 id="public-data">Public data</h3>

<p>This is information that’s already accessible to the public and poses minimal risk if someone views or shares it. Examples include press releases, job descriptions, and marketing materials.</p>

<p>“Public” doesn’t mean “unprotected.” Basic security measures still apply, because attackers could still tamper with it, such as defacing a web page.</p>

<h3 id="private-data">Private data</h3>

<p>Private data should be kept from the public. If someone gains unauthorized access, it could pose a serious risk to the organization. Examples include company email addresses, employee identification numbers, and an organization’s research data.</p>

<h3 id="sensitive-data">Sensitive data</h3>

<p>Sensitive data must be protected from everyone who doesn’t have authorized access. A leak can seriously damage an organization’s finances and reputation. This category includes:</p>

<ul>
  <li><strong>PII:</strong> personally identifiable information</li>
  <li><strong>SPII:</strong> sensitive personally identifiable information</li>
  <li><strong>PHI:</strong> protected health information</li>
</ul>

<p>Examples are bank account numbers, usernames and passwords, Social Security numbers, passport numbers, and medical information.</p>

<h3 id="confidential-data">Confidential data</h3>

<p>Confidential data is vital to an organization’s ongoing business operations. Access is often limited to a small number of people, and may even require signing a <strong>non-disclosure agreement (NDA)</strong>, a legal contract that binds parties to protect the information. Examples include trade secrets, financial records, and sensitive government data.</p>

<table>
  <thead>
    <tr>
      <th>Type</th>
      <th>Risk if exposed</th>
      <th>Examples</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Public</td>
      <td>Minimal</td>
      <td>Press releases, job descriptions, marketing materials</td>
    </tr>
    <tr>
      <td>Private</td>
      <td>Serious</td>
      <td>Company emails, employee ID numbers, research data</td>
    </tr>
    <tr>
      <td>Sensitive</td>
      <td>Significant financial and reputation damage</td>
      <td>PII, SPII, PHI, passwords, bank accounts</td>
    </tr>
    <tr>
      <td>Confidential</td>
      <td>Threatens ongoing business operations</td>
      <td>Trade secrets, financial records, sensitive government data</td>
    </tr>
  </tbody>
</table>

<h2 id="asset-classification-low-level-to-high-level">Asset classification: low-level to high-level</h2>

<p><strong>Asset classification</strong> means labeling assets based on how sensitive and important they are to the organization. Assets range from low-level to high-level:</p>

<ul>
  <li><strong>Low-level assets:</strong> Public data falls here. It’s readily available, and the organization won’t suffer if it’s compromised. A company’s website address is a good example.</li>
  <li><strong>High-level assets:</strong> Sensitive and confidential data fall here. If leaked, they can cost a company its competitive edge, reputation, and customer trust. An internal email discussing trade secrets is a good example.</li>
</ul>

<p>Notice that the label depends on the <strong>impact of a compromise</strong>, not on how “technical” the data looks.</p>

<h2 id="why-this-matters-to-you">Why this matters to you</h2>

<p>Classification tells you where to spend your attention. It helps you:</p>

<ul>
  <li>Prioritize which data needs the most protection</li>
  <li>Recognize which assets need higher levels of security and which need only minimal security</li>
</ul>

<p>Every company has its own data classification policy that spells out what falls into each category. Part of your job as a new security professional is to learn that policy early.</p>

<p><em>See what happens when classification breaks down in my <a href="/portfolio/projects/data-leak/">Data Leak Analysis</a> project.</em></p>

<h2 id="key-takeaways">Key takeaways</h2>

<ul>
  <li>The four common data types are public, private, sensitive, and confidential.</li>
  <li>Public data is a low-level asset. Sensitive and confidential data are high-level assets.</li>
  <li>Even public data needs basic protection.</li>
  <li>Classification helps you prioritize what to protect most.</li>
  <li>Always learn your organization’s own data classification policy.</li>
</ul>]]></content><author><name>Carolina Pinto</name></author><category term="GRC &amp; Frameworks" /><category term="data classification" /><category term="asset management" /><category term="pii" /><category term="grc" /><summary type="html"><![CDATA[Public, private, sensitive and confidential: how the four data types map to low- and high-level assets, and why classification tells you where to focus.]]></summary></entry><entry><title type="html">Debugging in Python: How to Find and Fix Your Mistakes</title><link href="https://carolinahpinto.github.io/portfolio/blog/2026/10/python-debugging-for-beginners/" rel="alternate" type="text/html" title="Debugging in Python: How to Find and Fix Your Mistakes" /><published>2026-10-29T00:00:00-04:00</published><updated>2026-10-29T00:00:00-04:00</updated><id>https://carolinahpinto.github.io/portfolio/blog/2026/10/python-debugging-for-beginners</id><content type="html" xml:base="https://carolinahpinto.github.io/portfolio/blog/2026/10/python-debugging-for-beginners/"><![CDATA[<p>Every programmer writes code that doesn’t work the first time. Security analysts are no exception. Getting an error message isn’t a sign you’re doing something wrong. It’s a normal part of the job, and the real skill is knowing how to track down the problem and fix it.</p>

<p>Think of debugging as being a detective. Every error leaves clues, and once you know what kind of error you’re dealing with, you know where to look.</p>

<h2 id="the-three-types-of-errors">The three types of errors</h2>

<h3 id="1-syntax-errors-breaking-the-grammar-rules">1. Syntax errors: breaking the grammar rules</h3>

<p>A <strong>syntax error</strong> means you used the Python language incorrectly. Common culprits are a forgotten colon after a function header, a missing closing bracket on a list, or a quotation mark that never closes.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">message</span> <span class="o">=</span> <span class="s">"You are debugging a syntax error
print(message)
</span></code></pre></div></div>

<p>Python refuses to run this and points to the exact line and part of the code where it got confused. Syntax errors are labeled <code class="language-plaintext highlighter-rouge">SyntaxError</code>, followed by a description (the wording varies a bit between Python versions, such as “unterminated string literal” or “invalid syntax”). The fix here is to add the missing quotation mark.</p>

<p>You may also see an <code class="language-plaintext highlighter-rouge">IndentationError</code>, which is a special kind of syntax error that happens when a line’s indentation is wrong.</p>

<p>The good news is that syntax errors are usually the easiest to fix, because the message tells you where to look.</p>

<h3 id="2-logic-errors-the-code-runs-but-the-answer-is-wrong">2. Logic errors: the code runs, but the answer is wrong</h3>

<p>A <strong>logic error</strong> happens when your code is valid but doesn’t do what you intended. There’s no error message, because as far as Python is concerned, nothing is wrong. That makes these the sneakiest bugs.</p>

<p>A classic cause is using the wrong operator, like <code class="language-plaintext highlighter-rouge">&gt;=</code> when you meant <code class="language-plaintext highlighter-rouge">&lt;</code>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">login_attempts</span> <span class="o">=</span> <span class="mi">5</span>
<span class="k">if</span> <span class="n">login_attempts</span> <span class="o">&gt;=</span> <span class="mi">5</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"User has not reached maximum number of login attempts."</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"User has reached maximum number of login attempts."</span><span class="p">)</span>
</code></pre></div></div>

<p>With five attempts used, this prints that the user has <em>not</em> reached the maximum, which is the opposite of the truth. The condition should have been <code class="language-plaintext highlighter-rouge">login_attempts &lt; 5</code>. Similarly, using <code class="language-plaintext highlighter-rouge">&lt;</code> when you needed <code class="language-plaintext highlighter-rouge">&lt;=</code> can quietly leave out a value you needed.</p>

<p>Logic errors can also come from assigning the wrong value or from indentation that makes a line run when you didn’t plan for it.</p>

<h3 id="3-exceptions-valid-code-that-cant-be-executed">3. Exceptions: valid code that can’t be executed</h3>

<p>An <strong>exception</strong> happens when your syntax is fine but Python still can’t carry out an instruction. Here are the ones you’ll meet most often:</p>

<table>
  <thead>
    <tr>
      <th>Exception</th>
      <th>What caused it</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">NameError</code></td>
      <td>Using a variable that was never assigned, or a function that was never defined (often just a typo)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">IndexError</code></td>
      <td>Using an index that doesn’t exist, like <code class="language-plaintext highlighter-rouge">usernames[3]</code> in a three-item list</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">TypeError</code></td>
      <td>Using the wrong data type, like adding a string to an integer</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ZeroDivisionError</code></td>
      <td>Dividing by zero</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">FileNotFoundError</code></td>
      <td>Opening a file that isn’t where you said it was</td>
    </tr>
  </tbody>
</table>

<p>Here’s a <code class="language-plaintext highlighter-rouge">NameError</code> in action:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">username</span> <span class="o">=</span> <span class="s">"elarson"</span>
<span class="n">total_logins</span> <span class="o">=</span> <span class="mi">75</span>
<span class="n">failed_logins</span> <span class="o">=</span> <span class="mi">18</span>

<span class="k">print</span><span class="p">(</span><span class="s">"Total logins:"</span><span class="p">,</span> <span class="n">total_logins</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Failed logins:"</span><span class="p">,</span> <span class="n">failed_logins</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Unusual logins:"</span><span class="p">,</span> <span class="n">unusual_logins</span><span class="p">)</span>
</code></pre></div></div>

<p>The error message names <code class="language-plaintext highlighter-rouge">unusual_logins</code>, and the fix is to give that variable a value (or correct a misspelling if that’s what caused it).</p>

<p>One more thing to know: if your code has several problems, Python reports them <strong>one at a time</strong>, starting with the first one it hits. Fix it, run again, and the next one appears.</p>

<h2 id="debugging-technique-1-print-statements">Debugging technique 1: print statements</h2>

<p>Syntax errors and many exceptions explain themselves. Logic errors don’t, so you have to investigate. The simplest tool is the humble <code class="language-plaintext highlighter-rouge">print()</code>. By dropping temporary print statements around your code, you can see exactly which parts run and in what order.</p>

<p>Here’s a function meant to add new users to an approved list, skipping anyone already on it:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">new_users</span> <span class="o">=</span> <span class="p">[</span><span class="s">"sgilmore"</span><span class="p">,</span> <span class="s">"bmoreno"</span><span class="p">]</span>
<span class="n">approved_users</span> <span class="o">=</span> <span class="p">[</span><span class="s">"bmoreno"</span><span class="p">,</span> <span class="s">"tshah"</span><span class="p">,</span> <span class="s">"elarson"</span><span class="p">]</span>

<span class="k">def</span> <span class="nf">add_users</span><span class="p">():</span>
    <span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">new_users</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">approved_users</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="s">"already in list"</span><span class="p">)</span>
        <span class="n">approved_users</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>

<span class="n">add_users</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="n">approved_users</span><span class="p">)</span>
</code></pre></div></div>

<p>The output says <code class="language-plaintext highlighter-rouge">bmoreno already in list</code>, yet the final list contains <code class="language-plaintext highlighter-rouge">bmoreno</code> twice. Something’s off. Let’s add print statements with descriptive labels:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">add_users</span><span class="p">():</span>
    <span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">new_users</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"line 5 - inside for loop"</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">approved_users</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="s">"line 7 - inside if statement"</span><span class="p">)</span>
            <span class="k">print</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="s">"already in list"</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"line 9 - before .append method"</span><span class="p">)</span>
        <span class="n">approved_users</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
</code></pre></div></div>

<p>Reading the output:</p>

<ul>
  <li>“inside for loop” prints twice, once per new user. That’s expected.</li>
  <li>“inside if statement” prints once, since only one user was already on the list. Also expected.</li>
  <li>“before .append method” prints twice. <strong>That’s the clue.</strong> <code class="language-plaintext highlighter-rouge">.append()</code> runs for both users, including the one who’s already approved.</li>
</ul>

<p>The bug is isolated: <code class="language-plaintext highlighter-rouge">.append()</code> needs to be inside an <code class="language-plaintext highlighter-rouge">else</code> block so it only runs when the user is <em>not</em> already in the list:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">add_users</span><span class="p">():</span>
    <span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">new_users</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">approved_users</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="s">"already in list"</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">approved_users</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
</code></pre></div></div>

<p>Notice that the final version has the print statements removed. Once the bug is fixed, delete your debugging prints so your code stays clean and efficient.</p>

<h3 id="another-logic-error-order-matters">Another logic error: order matters</h3>

<p>Sometimes the fix is simply reordering your code. Consider this function:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">login_status</span><span class="p">(</span><span class="n">attempts</span><span class="p">):</span>
    <span class="k">return</span> <span class="s">"Account active"</span>
    <span class="k">if</span> <span class="n">attempts</span> <span class="o">&gt;=</span> <span class="mi">5</span><span class="p">:</span>
        <span class="k">return</span> <span class="s">"Account locked"</span>
</code></pre></div></div>

<p>It always returns “Account active.” Once Python hits a <code class="language-plaintext highlighter-rouge">return</code> statement, the function ends immediately, so the <code class="language-plaintext highlighter-rouge">if</code> check below it never gets evaluated. Adding a print statement above the <code class="language-plaintext highlighter-rouge">if</code> would show that it never runs, which is a strong hint. The fix is to move the conditional before the return:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">login_status</span><span class="p">(</span><span class="n">attempts</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">attempts</span> <span class="o">&gt;=</span> <span class="mi">5</span><span class="p">:</span>
        <span class="k">return</span> <span class="s">"Account locked"</span>
    <span class="k">return</span> <span class="s">"Account active"</span>
</code></pre></div></div>

<h2 id="debugging-technique-2-debuggers">Debugging technique 2: debuggers</h2>

<p>When the code gets bigger, print statements everywhere can get messy. That’s where a <strong>debugger</strong> helps. This is a tool built into many IDEs (Integrated Development Environments, which are programs for writing code with editing and error-checking help).</p>

<p>Debuggers work with <strong>breakpoints</strong>, markers you place on specific lines. The program runs up to a breakpoint and stops, letting you test sections of your code one at a time to isolate the problem. Many debuggers also let you watch the values stored in your variables as they change, which is especially useful for catching the exact moment something goes wrong in a logic error. Debuggers help with both logic errors and exceptions.</p>

<h2 id="a-word-on-ai-coding-assistants">A word on AI coding assistants</h2>

<p>Many IDEs now offer AI assistants that can help analyze code, spot errors, and suggest fixes. They can be a big time-saver, but their suggestions may not always be accurate, optimal, or secure. Treat them like a helpful co-pilot: review and validate anything they give you before you run it, and stay responsible for your final code.</p>

<h2 id="key-takeaways">Key takeaways</h2>

<ul>
  <li><strong>Syntax errors</strong> break Python’s grammar rules. The error message usually shows you where.</li>
  <li><strong>Logic errors</strong> run without complaint but give wrong results, so you have to investigate.</li>
  <li><strong>Exceptions</strong> are valid code that can’t be executed, like <code class="language-plaintext highlighter-rouge">NameError</code>, <code class="language-plaintext highlighter-rouge">IndexError</code>, <code class="language-plaintext highlighter-rouge">TypeError</code>, and <code class="language-plaintext highlighter-rouge">FileNotFoundError</code>.</li>
  <li>Python reports errors one at a time, so fix and re-run.</li>
  <li><strong>Print statements</strong> let you trace which parts of your code run. Remove them once the bug is fixed.</li>
  <li><strong>Debuggers</strong> and breakpoints let you pause and inspect your code piece by piece.</li>
  <li>Check and validate any AI-assisted suggestions before relying on them.</li>
</ul>

<p>Bugs are inevitable, but with these techniques you’ll spend a lot less time stuck on them.</p>]]></content><author><name>Carolina Pinto</name></author><category term="Python" /><category term="python" /><category term="debugging" /><category term="beginners" /><summary type="html"><![CDATA[Syntax errors, logic errors and exceptions, plus print statements, debuggers and a word on AI coding assistants.]]></summary></entry><entry><title type="html">Working with Files in Python: Reading Logs Like a Security Analyst</title><link href="https://carolinahpinto.github.io/portfolio/blog/2026/10/working-with-files-in-python/" rel="alternate" type="text/html" title="Working with Files in Python: Reading Logs Like a Security Analyst" /><published>2026-10-22T00:00:00-04:00</published><updated>2026-10-22T00:00:00-04:00</updated><id>https://carolinahpinto.github.io/portfolio/blog/2026/10/working-with-files-in-python</id><content type="html" xml:base="https://carolinahpinto.github.io/portfolio/blog/2026/10/working-with-files-in-python/"><![CDATA[<p>In the last post, we wrote scripts that checked logins, but we typed our data directly into the code. Real security data doesn’t work that way. It lives in files, mostly <strong>logs</strong>, which are records of events that happen on an organization’s systems. A log might hold login attempts, software update records, or errors from applications that someone is attacking.</p>

<p>Reading those files with Python is what turns your scripts from practice exercises into real tools. By the end of this post, you’ll build a program that spots suspicious login attempts from a log file.</p>

<h2 id="opening-a-file">Opening a file</h2>

<p>Here’s the standard way to open a file for reading:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"update_log.txt"</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">updates</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="n">updates</span><span class="p">)</span>
</code></pre></div></div>

<p>There’s a lot packed into that first line, so let’s take it apart.</p>

<p><strong><code class="language-plaintext highlighter-rouge">with</code></strong> handles errors and manages outside resources for you. In this case, it automatically closes the file when you leave the indented block. You can use <code class="language-plaintext highlighter-rouge">open()</code> without <code class="language-plaintext highlighter-rouge">with</code>, but then you have to remember to close the file yourself.</p>

<p><strong><code class="language-plaintext highlighter-rouge">open()</code></strong> opens the file. It takes two inputs:</p>

<ol>
  <li><strong>The file name</strong> (as a string, in quotes), including the extension like <code class="language-plaintext highlighter-rouge">.txt</code>. If the file sits in the same folder as your Python file, the name alone is enough. If it lives somewhere else, you need the full file path starting from the root, like <code class="language-plaintext highlighter-rouge">"/home/analyst/logs/access_log.txt"</code>.</li>
  <li><strong>The mode</strong>, which says what you want to do:</li>
</ol>

<table>
  <thead>
    <tr>
      <th>Mode</th>
      <th>Meaning</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">"r"</code></td>
      <td>Read the file</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">"w"</code></td>
      <td>Write to the file, replacing everything in it (or create a new file)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">"a"</code></td>
      <td>Append to the end, keeping what’s already there</td>
    </tr>
  </tbody>
</table>

<p><strong><code class="language-plaintext highlighter-rouge">as file</code></strong> gives the open file a variable name so you can use it inside the indented block. You can call it anything, but <code class="language-plaintext highlighter-rouge">file</code> is a common choice.</p>

<p>Don’t forget the colon at the end of the line.</p>

<h2 id="reading-a-file">Reading a file</h2>

<p>Inside the block, <code class="language-plaintext highlighter-rouge">.read()</code> converts the file’s contents into a string:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"update_log.txt"</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">updates</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
</code></pre></div></div>

<p>Once it’s a string stored in <code class="language-plaintext highlighter-rouge">updates</code>, you can do everything you already know: <code class="language-plaintext highlighter-rouge">len()</code>, <code class="language-plaintext highlighter-rouge">.index()</code>, slicing, and so on.</p>

<h2 id="writing-to-a-file">Writing to a file</h2>

<p>Analysts write files too, for example to create an allow list of approved usernames. Use <code class="language-plaintext highlighter-rouge">"w"</code> or <code class="language-plaintext highlighter-rouge">"a"</code> along with the <code class="language-plaintext highlighter-rouge">.write()</code> method:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">line</span> <span class="o">=</span> <span class="s">"jrafael,192.168.243.140,4:56:27,True"</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"access_log.txt"</span><span class="p">,</span> <span class="s">"a"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="nb">file</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
</code></pre></div></div>

<p>Because the mode is <code class="language-plaintext highlighter-rouge">"a"</code>, this adds the line to the end of <code class="language-plaintext highlighter-rouge">access_log.txt</code> and leaves the existing records alone. With <code class="language-plaintext highlighter-rouge">"w"</code>, the old contents would be wiped out first, so choose carefully.</p>

<h2 id="parsing-making-data-usable">Parsing: making data usable</h2>

<p>Raw file contents are usually one big string, which isn’t very convenient. <strong>Parsing</strong> means converting data into a more readable or more usable format. Two methods do most of the heavy lifting.</p>

<p><strong><code class="language-plaintext highlighter-rouge">.split()</code>: string to list</strong>
It breaks a string into a list at a character you choose:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">approved_users</span> <span class="o">=</span> <span class="s">"elarson,bmoreno,tshah,sgilmore,eraab"</span>
<span class="k">print</span><span class="p">(</span><span class="n">approved_users</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">","</span><span class="p">))</span>
<span class="c1"># ['elarson', 'bmoreno', 'tshah', 'sgilmore', 'eraab']
</span></code></pre></div></div>

<p>If you pass nothing in, it splits at any whitespace (spaces, new lines, and so on):</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">removed_users</span> <span class="o">=</span> <span class="s">"wjaffrey jsoto abernard jhill awilliam"</span>
<span class="k">print</span><span class="p">(</span><span class="n">removed_users</span><span class="p">.</span><span class="n">split</span><span class="p">())</span>
<span class="c1"># ['wjaffrey', 'jsoto', 'abernard', 'jhill', 'awilliam']
</span></code></pre></div></div>

<p><strong><code class="language-plaintext highlighter-rouge">.join()</code>: list to string</strong>
This goes the other way, and its syntax looks backwards at first. You attach <code class="language-plaintext highlighter-rouge">.join()</code> to the separator and pass the list in:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">approved_users</span> <span class="o">=</span> <span class="p">[</span><span class="s">"elarson"</span><span class="p">,</span> <span class="s">"bmoreno"</span><span class="p">,</span> <span class="s">"tshah"</span><span class="p">,</span> <span class="s">"sgilmore"</span><span class="p">,</span> <span class="s">"eraab"</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="s">","</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">approved_users</span><span class="p">))</span>
<span class="c1"># elarson,bmoreno,tshah,sgilmore,eraab
</span></code></pre></div></div>

<p>You’ll need <code class="language-plaintext highlighter-rouge">.join()</code> before writing, since <code class="language-plaintext highlighter-rouge">.write()</code> only accepts strings. Using <code class="language-plaintext highlighter-rouge">"\n"</code> as the separator puts each element on its own line.</p>

<p>A typical read-modify-write flow looks like this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"update_log.txt"</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">updates</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">updates</span> <span class="o">=</span> <span class="n">updates</span><span class="p">.</span><span class="n">split</span><span class="p">()</span>       <span class="c1"># work with it as a list...
# ...make your changes here...
</span><span class="n">updates</span> <span class="o">=</span> <span class="s">" "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">updates</span><span class="p">)</span>     <span class="c1"># ...then turn it back into a string
</span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"update_log.txt"</span><span class="p">,</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="nb">file</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">updates</span><span class="p">)</span>
</code></pre></div></div>

<p>Notice that the <code class="language-plaintext highlighter-rouge">.split()</code> line is <em>not</em> indented under the first <code class="language-plaintext highlighter-rouge">with</code>. The file closes as soon as we’ve read it, which keeps the code tidy.</p>

<h2 id="putting-it-together-detecting-suspicious-logins">Putting it together: detecting suspicious logins</h2>

<p>Now for the main event. Our goal is to flag any user with <strong>three or more failed login attempts</strong>.</p>

<p>Suppose we have a text file called <code class="language-plaintext highlighter-rouge">failed_login_log.txt</code> where each entry is a username from one failed attempt:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tshah elarson tshah bmoreno tshah
</code></pre></div></div>

<h3 id="step-1-plan-the-algorithm">Step 1: Plan the algorithm</h3>

<p>Break the problem into small steps:</p>

<ol>
  <li>Import the log file, split its contents, and store the usernames in a list called <code class="language-plaintext highlighter-rouge">usernames</code>.</li>
  <li>Loop through that list. For each element, check if it matches the user we’re investigating (<code class="language-plaintext highlighter-rouge">current_user</code>).</li>
  <li>Each time it matches, add 1 to a counter.</li>
  <li>If the counter reaches three or more, raise an alert. Otherwise, the user is fine.</li>
</ol>

<h3 id="step-2-import-the-data">Step 2: Import the data</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"failed_login_log.txt"</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">usernames</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">usernames</span> <span class="o">=</span> <span class="n">usernames</span><span class="p">.</span><span class="n">split</span><span class="p">()</span>
</code></pre></div></div>

<h3 id="step-3-wrap-the-logic-in-a-function">Step 3: Wrap the logic in a function</h3>

<p>We’ll define a function called <code class="language-plaintext highlighter-rouge">login_check()</code> that takes the list of failed attempts and the user to check:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">login_check</span><span class="p">(</span><span class="n">login_list</span><span class="p">,</span> <span class="n">current_user</span><span class="p">):</span>
    <span class="n">failed_attempts</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">username</span> <span class="ow">in</span> <span class="n">login_list</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">username</span> <span class="o">==</span> <span class="n">current_user</span><span class="p">:</span>
            <span class="n">failed_attempts</span> <span class="o">+=</span> <span class="mi">1</span>
    <span class="k">if</span> <span class="n">failed_attempts</span> <span class="o">&gt;=</span> <span class="mi">3</span><span class="p">:</span>
        <span class="k">return</span> <span class="s">"ALERT: "</span> <span class="o">+</span> <span class="n">current_user</span> <span class="o">+</span> <span class="s">"'s account is locked."</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">current_user</span> <span class="o">+</span> <span class="s">" can log in."</span>
</code></pre></div></div>

<h3 id="step-4-run-it">Step 4: Run it</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">print</span><span class="p">(</span><span class="n">login_check</span><span class="p">(</span><span class="n">usernames</span><span class="p">,</span> <span class="s">"tshah"</span><span class="p">))</span>     <span class="c1"># ALERT: tshah's account is locked.
</span><span class="k">print</span><span class="p">(</span><span class="n">login_check</span><span class="p">(</span><span class="n">usernames</span><span class="p">,</span> <span class="s">"elarson"</span><span class="p">))</span>   <span class="c1"># elarson can log in.
</span></code></pre></div></div>

<p>Look at how many pieces you’ve used: a variable (the counter), a <code class="language-plaintext highlighter-rouge">for</code> loop to visit every entry, an <code class="language-plaintext highlighter-rouge">if</code> statement to match users, a second <code class="language-plaintext highlighter-rouge">if-else</code> to make the decision, a function so it’s reusable for any user, and file handling with <code class="language-plaintext highlighter-rouge">.split()</code> to get the data in. This is exactly the kind of script analysts write to review huge logs in seconds.</p>

<h2 id="key-takeaways">Key takeaways</h2>

<ul>
  <li>Logs are records of system events, and most security data starts in files like these.</li>
  <li>Open files with <code class="language-plaintext highlighter-rouge">with open("filename", "mode") as file:</code>. The <code class="language-plaintext highlighter-rouge">with</code> keyword manages resources and closes the file for you.</li>
  <li>Modes: <code class="language-plaintext highlighter-rouge">"r"</code> reads, <code class="language-plaintext highlighter-rouge">"w"</code> writes (and overwrites), and <code class="language-plaintext highlighter-rouge">"a"</code> appends.</li>
  <li><code class="language-plaintext highlighter-rouge">.read()</code> converts file contents to a string, and <code class="language-plaintext highlighter-rouge">.write()</code> writes a string to a file.</li>
  <li>Parsing makes data usable: <code class="language-plaintext highlighter-rouge">.split()</code> turns a string into a list, and <code class="language-plaintext highlighter-rouge">.join()</code> turns a list back into a string.</li>
  <li>Combining file handling with loops, conditionals, and functions lets you automate real investigations, like flagging accounts with repeated failed logins.</li>
</ul>

<p>Next time you face a mountain of log data, you’ll know how to let Python do the reading for you.</p>]]></content><author><name>Carolina Pinto</name></author><category term="Python" /><category term="python" /><category term="files" /><category term="parsing" /><category term="log analysis" /><summary type="html"><![CDATA[Opening, reading, writing and parsing files, then building a script that flags accounts with repeated failed logins.]]></summary></entry><entry><title type="html">Automating Security Tasks with Python: Putting It All Together</title><link href="https://carolinahpinto.github.io/portfolio/blog/2026/10/automating-security-tasks-with-python/" rel="alternate" type="text/html" title="Automating Security Tasks with Python: Putting It All Together" /><published>2026-10-19T00:00:00-04:00</published><updated>2026-10-19T00:00:00-04:00</updated><id>https://carolinahpinto.github.io/portfolio/blog/2026/10/automating-security-tasks-with-python</id><content type="html" xml:base="https://carolinahpinto.github.io/portfolio/blog/2026/10/automating-security-tasks-with-python/"><![CDATA[<p>Over this series, we’ve collected a pile of tools: strings, lists, and regular expressions. Now it’s time to build something with them. Think of it like moving from collecting LEGO bricks to assembling a working model. The model we’re building today is <strong>automation</strong>.</p>

<p>Automation means using technology to cut down the manual effort of common, repetitive tasks. For a security analyst, that’s most of Python’s value. Nobody wants to read through thousands of login records by hand, and humans get tired and miss things. A script doesn’t.</p>

<h2 id="the-building-blocks">The building blocks</h2>

<p>Every automation script you write will lean on the same handful of components:</p>

<table>
  <thead>
    <tr>
      <th>Component</th>
      <th>What it does for automation</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Variables</td>
      <td>Store data once so you don’t retype values for every action</td>
    </tr>
    <tr>
      <td>Conditional statements</td>
      <td>Check whether something meets a condition before acting on it</td>
    </tr>
    <tr>
      <td>Iterative statements (<code class="language-plaintext highlighter-rouge">for</code>, <code class="language-plaintext highlighter-rouge">while</code>)</td>
      <td>Repeat the same steps without retyping code. A <code class="language-plaintext highlighter-rouge">for</code> loop repeats over a sequence, a <code class="language-plaintext highlighter-rouge">while</code> loop repeats while a condition holds</td>
    </tr>
    <tr>
      <td>Functions</td>
      <td>Package code you can define once and reuse anywhere</td>
    </tr>
    <tr>
      <td>Strings and lists</td>
      <td>Hold and slice up the data you’ll work with: usernames, IPs, log lines</td>
    </tr>
    <tr>
      <td>Files</td>
      <td>Where your security data usually starts out (more on this below)</td>
    </tr>
  </tbody>
</table>

<p>Let’s see them work together in three real security scenarios.</p>

<h2 id="example-1-enforcing-a-login-timeout">Example 1: Enforcing a login timeout</h2>

<p>Imagine a database that should lock a user out if they take too long to log in after typing their username. That slows down attackers who are guessing passwords. Python can track how long it takes from the moment a username is entered until the correct password is provided, then compare that to a time limit.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">TIMEOUT_SECONDS</span> <span class="o">=</span> <span class="mi">30</span>

<span class="k">def</span> <span class="nf">check_login_time</span><span class="p">(</span><span class="n">username_entered_at</span><span class="p">,</span> <span class="n">password_correct_at</span><span class="p">):</span>
    <span class="n">elapsed</span> <span class="o">=</span> <span class="n">password_correct_at</span> <span class="o">-</span> <span class="n">username_entered_at</span>
    <span class="k">if</span> <span class="n">elapsed</span> <span class="o">&gt;</span> <span class="n">TIMEOUT_SECONDS</span><span class="p">:</span>
        <span class="k">return</span> <span class="s">"Locked out: login took too long"</span>
    <span class="k">return</span> <span class="s">"Login allowed"</span>

<span class="c1"># Timestamps in seconds
</span><span class="k">print</span><span class="p">(</span><span class="n">check_login_time</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="mi">112</span><span class="p">))</span>   <span class="c1"># Login allowed
</span><span class="k">print</span><span class="p">(</span><span class="n">check_login_time</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="mi">160</span><span class="p">))</span>   <span class="c1"># Locked out: login took too long
</span></code></pre></div></div>

<p>Here a variable holds the limit, a function packages the check, and a conditional makes the decision. (In a real system, you’d get the timestamps from Python’s <code class="language-plaintext highlighter-rouge">time</code> module instead of typing them in.)</p>

<h2 id="example-2-tracking-user-logins">Example 2: Tracking user logins</h2>

<p>Next, suppose you want to review each login for warning signs: odd hours, unapproved locations, or the same account logging in from multiple IP addresses at once. Python can check the timestamps, IP addresses, and locations attached to each login and flag anything suspicious.</p>

<p>Here’s a simplified version that checks the hour of day and the location:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">approved_locations</span> <span class="o">=</span> <span class="p">[</span><span class="s">"Miami"</span><span class="p">,</span> <span class="s">"Chicago"</span><span class="p">]</span>

<span class="n">logins</span> <span class="o">=</span> <span class="p">[</span>
    <span class="p">[</span><span class="s">"bmoreno"</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="s">"Miami"</span><span class="p">],</span>
    <span class="p">[</span><span class="s">"tshah"</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="s">"Lagos"</span><span class="p">],</span>
    <span class="p">[</span><span class="s">"sgilmore"</span><span class="p">,</span> <span class="mi">14</span><span class="p">,</span> <span class="s">"Chicago"</span><span class="p">],</span>
<span class="p">]</span>

<span class="k">for</span> <span class="n">username</span><span class="p">,</span> <span class="n">hour</span><span class="p">,</span> <span class="n">location</span> <span class="ow">in</span> <span class="n">logins</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">hour</span> <span class="o">&lt;</span> <span class="mi">6</span> <span class="ow">or</span> <span class="n">hour</span> <span class="o">&gt;</span> <span class="mi">20</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Flag:"</span><span class="p">,</span> <span class="n">username</span><span class="p">,</span> <span class="s">"logged in at an unusual hour"</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">location</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">approved_locations</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Flag:"</span><span class="p">,</span> <span class="n">username</span><span class="p">,</span> <span class="s">"logged in from an unapproved location"</span><span class="p">)</span>
</code></pre></div></div>

<p>Output:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Flag: tshah logged in at an unusual hour
Flag: tshah logged in from an unapproved location
</code></pre></div></div>

<p>The list holds the data, the loop visits every login, and the conditionals decide what’s worth flagging. Notice that <code class="language-plaintext highlighter-rouge">for username, hour, location in logins</code> unpacks each small list into three variables, which keeps the code readable.</p>

<h2 id="example-3-monitoring-failed-password-attempts">Example 3: Monitoring failed password attempts</h2>

<p>Many failed logins in a short period is a classic sign of password guessing. This data usually lives in log files, so Python needs to <strong>parse</strong> each line, meaning pull out the useful pieces like the username, IP address, timestamp, and login status.</p>

<p>First, a reusable counting function. This is the “count the logins for a flagged user” pattern: a <code class="language-plaintext highlighter-rouge">for</code> loop, a conditional, and a counter variable.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">count_occurrences</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="n">items</span><span class="p">):</span>
    <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">item</span> <span class="o">==</span> <span class="n">target</span><span class="p">:</span>
            <span class="n">count</span> <span class="o">+=</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="n">count</span>
</code></pre></div></div>

<p>Now we can parse some log lines. Each line holds comma-separated values, and the string method <code class="language-plaintext highlighter-rouge">.split(",")</code> breaks a line into a list of pieces:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">log_lines</span> <span class="o">=</span> <span class="p">[</span>
    <span class="s">"tshah,192.168.1.10,2026-10-19 09:15:02,FAILED"</span><span class="p">,</span>
    <span class="s">"tshah,192.168.1.10,2026-10-19 09:15:09,FAILED"</span><span class="p">,</span>
    <span class="s">"bmoreno,10.0.0.5,2026-10-19 09:15:30,FAILED"</span><span class="p">,</span>
    <span class="s">"tshah,192.168.1.10,2026-10-19 09:15:14,FAILED"</span><span class="p">,</span>
    <span class="s">"sgilmore,172.16.0.8,2026-10-19 09:16:01,SUCCESS"</span><span class="p">,</span>
<span class="p">]</span>

<span class="n">failed_users</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">log_lines</span><span class="p">:</span>
    <span class="n">username</span><span class="p">,</span> <span class="n">ip</span><span class="p">,</span> <span class="n">timestamp</span><span class="p">,</span> <span class="n">status</span> <span class="o">=</span> <span class="n">line</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">","</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">status</span> <span class="o">==</span> <span class="s">"FAILED"</span><span class="p">:</span>
        <span class="n">failed_users</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">username</span><span class="p">)</span>

<span class="n">flagged</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">failed_users</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">count_occurrences</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="n">failed_users</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">3</span> <span class="ow">and</span> <span class="n">user</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">flagged</span><span class="p">:</span>
        <span class="n">flagged</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>

<span class="k">print</span><span class="p">(</span><span class="n">flagged</span><span class="p">)</span>   <span class="c1"># ['tshah']
</span></code></pre></div></div>

<p>Strings, lists, loops, conditionals, and a function all showed up in one small script. This version simply counts failures, but a production version would also compare the timestamps to catch attempts bunched into a short window.</p>

<h2 id="a-note-on-files">A note on files</h2>

<p>In real work, you won’t type log lines into your script. Security data typically starts in <strong>log files</strong>, which are records of events on a system, with new lines added as time passes. The two most common formats are:</p>

<ul>
  <li><strong>.txt files:</strong> plain text with no required structure (values might be separated by spaces or anything else)</li>
  <li><strong>.csv files:</strong> “comma-separated values,” where each value on a line is separated by a comma</li>
</ul>

<p>Both are plain text, with no fonts, colors, or images, which makes them easy for Python to read, extract data from, and convert. Reading and writing files is the next skill to learn.</p>

<h2 id="bonus-automation-inside-the-software-pipeline">Bonus: automation inside the software pipeline</h2>

<p>Automation isn’t just for analyzing logs. Teams also build Python security checks directly into their <strong>CI/CD pipelines</strong>, the automated processes that build, test, and release software. This approach is called <strong>DevSecOps</strong> (Development, Security, and Operations working together), and the idea is that security is built in from the start instead of bolted on at the end.</p>

<p>Python scripts can run inside tools like Jenkins, GitLab CI, and CircleCI to handle jobs such as:</p>

<ul>
  <li>Running code and dependency scans, then stopping a release if serious problems appear</li>
  <li>Scanning for passwords and keys accidentally written into code</li>
  <li>Checking that releases follow security policies and compliance rules</li>
</ul>

<p>The benefits are the same as everywhere else in automation: checks run faster, consistently every time, and early, when problems are cheapest to fix. It also frees security teams from repetitive work so they can focus on bigger problems.</p>

<h2 id="key-takeaways">Key takeaways</h2>

<ul>
  <li>Automation reduces manual effort on repetitive tasks, and it’s one of the main reasons analysts use Python.</li>
  <li>The core components are variables, conditionals, loops, functions, and techniques for working with strings and lists.</li>
  <li>Python can enforce login timeouts, track suspicious logins (odd hours, unapproved locations, multiple IPs), and monitor failed password attempts by parsing logs.</li>
  <li>Security data usually starts in <code class="language-plaintext highlighter-rouge">.txt</code> or <code class="language-plaintext highlighter-rouge">.csv</code> log files, so file handling is the next essential skill.</li>
  <li>Python also powers DevSecOps, building security checks right into CI/CD pipelines.</li>
</ul>

<p>You now have the pieces to start writing real security scripts. Next up: opening, reading, and writing files so your code can work with actual logs.</p>]]></content><author><name>Carolina Pinto</name></author><category term="Python" /><category term="python" /><category term="automation" /><category term="devsecops" /><category term="log analysis" /><summary type="html"><![CDATA[Login timeouts, suspicious-login tracking and failed-password monitoring: three security scripts built from the basics.]]></summary></entry><entry><title type="html">Python Strings for Beginners: A Security Analyst’s Toolkit</title><link href="https://carolinahpinto.github.io/portfolio/blog/2026/10/python-strings-for-beginners/" rel="alternate" type="text/html" title="Python Strings for Beginners: A Security Analyst’s Toolkit" /><published>2026-10-15T00:00:00-04:00</published><updated>2026-10-15T00:00:00-04:00</updated><id>https://carolinahpinto.github.io/portfolio/blog/2026/10/python-strings-for-beginners</id><content type="html" xml:base="https://carolinahpinto.github.io/portfolio/blog/2026/10/python-strings-for-beginners/"><![CDATA[<p>Think of strings as LEGO bricks. You can measure them, snap them together, take them apart, and repaint them. Strings are also one of the most common data types you’ll meet in cybersecurity, because things like IP addresses, usernames, URLs, and employee IDs are all stored as text.</p>

<h2 id="what-is-a-string">What is a string?</h2>

<p>A string is an ordered sequence of characters. It’s used for information you won’t do math on (you’d never divide a username by 2). Here’s a sample device ID we’ll use throughout: <code class="language-plaintext highlighter-rouge">"h32rb17"</code>.</p>

<h2 id="every-character-has-an-address-indices">Every character has an address (indices)</h2>

<p>Each character in a string has a position number called an <strong>index</strong>, and Python starts counting at 0:</p>

<table>
  <thead>
    <tr>
      <th>character</th>
      <th>h</th>
      <th>3</th>
      <th>2</th>
      <th>r</th>
      <th>b</th>
      <th>1</th>
      <th>7</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>index</td>
      <td>0</td>
      <td>1</td>
      <td>2</td>
      <td>3</td>
      <td>4</td>
      <td>5</td>
      <td>6</td>
    </tr>
    <tr>
      <td>negative index</td>
      <td>-7</td>
      <td>-6</td>
      <td>-5</td>
      <td>-4</td>
      <td>-3</td>
      <td>-2</td>
      <td>-1</td>
    </tr>
  </tbody>
</table>

<p>Negative indices count backward from the end, so <code class="language-plaintext highlighter-rouge">-1</code> is always the last character.</p>

<h2 id="grabbing-pieces-with-bracket-notation">Grabbing pieces with bracket notation</h2>

<p>Put an index in square brackets to pull out a character:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">device_id</span> <span class="o">=</span> <span class="s">"h32rb17"</span>
<span class="k">print</span><span class="p">(</span><span class="n">device_id</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>   <span class="c1"># h
</span></code></pre></div></div>

<p>You can also take a <strong>slice</strong> (more than one character):</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">print</span><span class="p">(</span><span class="n">device_id</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">3</span><span class="p">])</span>   <span class="c1"># h32
</span></code></pre></div></div>

<p>The slice starts at index 0 but stops <em>before</em> index 3, so the end number is excluded. Analysts use slices to pull out part of an IP address or URL.</p>

<h2 id="your-string-toolbox">Your string toolbox</h2>

<p><strong>Measuring your tower: <code class="language-plaintext highlighter-rouge">len()</code></strong>
This counts the characters in a string. If your company’s device IDs must be seven characters long, you can check:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="s">"h32rb17"</span><span class="p">)</span> <span class="o">==</span> <span class="mi">7</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"The device ID has 7 characters."</span><span class="p">)</span>
</code></pre></div></div>

<p><strong>Changing the type: <code class="language-plaintext highlighter-rouge">str()</code></strong>
Say you have an employee ID like <code class="language-plaintext highlighter-rouge">19329302</code>. As a number, you can’t slice or search it. Convert it first:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">string_id</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="mi">19329302</span><span class="p">)</span>
</code></pre></div></div>

<p><strong>Joining bricks: concatenation</strong>
Use <code class="language-plaintext highlighter-rouge">+</code> to connect strings:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">print</span><span class="p">(</span><span class="s">"Hello"</span> <span class="o">+</span> <span class="s">"world"</span><span class="p">)</span>   <span class="c1"># Helloworld
</span></code></pre></div></div>

<p>Unlike numbers, strings can’t be subtracted.</p>

<p><strong>Repainting: <code class="language-plaintext highlighter-rouge">.upper()</code> and <code class="language-plaintext highlighter-rouge">.lower()</code></strong>
These are <strong>methods</strong>, special tools that belong to a data type, so you attach them right after the string:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">print</span><span class="p">(</span><span class="s">"Hello"</span><span class="p">.</span><span class="n">upper</span><span class="p">())</span>   <span class="c1"># HELLO
</span><span class="k">print</span><span class="p">(</span><span class="s">"Hello"</span><span class="p">.</span><span class="n">lower</span><span class="p">())</span>   <span class="c1"># hello
</span></code></pre></div></div>

<p><strong>Finding things: <code class="language-plaintext highlighter-rouge">.index()</code></strong>
This returns the position of the first match:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">print</span><span class="p">(</span><span class="s">"h32rb17"</span><span class="p">.</span><span class="n">index</span><span class="p">(</span><span class="s">"r"</span><span class="p">))</span>   <span class="c1"># 3
</span></code></pre></div></div>

<p>It also works on substrings, returning the index of the first character:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">print</span><span class="p">(</span><span class="s">"tsnow, tshah, bmoreno - updated"</span><span class="p">.</span><span class="n">index</span><span class="p">(</span><span class="s">"tshah"</span><span class="p">))</span>   <span class="c1"># 7
</span></code></pre></div></div>

<p>Watch out for two gotchas:</p>

<ul>
  <li>If the text isn’t found, Python raises an error (<code class="language-plaintext highlighter-rouge">"h32rb17".index("a")</code> fails).</li>
  <li>Only the <strong>first</strong> match is returned, so searching for <code class="language-plaintext highlighter-rouge">"ts"</code> above gives <code class="language-plaintext highlighter-rouge">0</code> (from “tsnow”), not <code class="language-plaintext highlighter-rouge">7</code>.</li>
</ul>

<h2 id="strings-are-immutable">Strings are immutable</h2>

<p>Once a string is created, you can’t change its individual characters, like writing in permanent marker or carving words into a stone tablet. If you want a different message, you carve a new tablet. That’s why <code class="language-plaintext highlighter-rouge">.upper()</code> and <code class="language-plaintext highlighter-rouge">.lower()</code> return a <em>copy</em> of the string instead of altering the original.</p>

<h2 id="key-takeaways">Key takeaways</h2>

<ul>
  <li>Strings are ordered sequences of characters, and indices start at 0.</li>
  <li>Use brackets for characters (<code class="language-plaintext highlighter-rouge">[0]</code>) and slices (<code class="language-plaintext highlighter-rouge">[0:3]</code>, where the end is excluded).</li>
  <li><code class="language-plaintext highlighter-rouge">len()</code> measures, <code class="language-plaintext highlighter-rouge">str()</code> converts, and <code class="language-plaintext highlighter-rouge">+</code> joins.</li>
  <li><code class="language-plaintext highlighter-rouge">.upper()</code>, <code class="language-plaintext highlighter-rouge">.lower()</code>, and <code class="language-plaintext highlighter-rouge">.index()</code> are string methods.</li>
  <li>Strings can’t be edited in place. You create new ones.</li>
</ul>

<p>Master these basics and you’ll be ready to validate usernames, parse logs, and slice up IP addresses.</p>]]></content><author><name>Carolina Pinto</name></author><category term="Python" /><category term="python" /><category term="strings" /><category term="beginners" /><summary type="html"><![CDATA[Indices, slices, len(), str(), concatenation and string methods, with a sample device ID as the running example.]]></summary></entry><entry><title type="html">Python Cheat Sheet: Security Automation</title><link href="https://carolinahpinto.github.io/portfolio/blog/2026/10/python-cheat-sheet-security-automation/" rel="alternate" type="text/html" title="Python Cheat Sheet: Security Automation" /><published>2026-10-12T00:00:00-04:00</published><updated>2026-10-12T00:00:00-04:00</updated><id>https://carolinahpinto.github.io/portfolio/blog/2026/10/python-cheat-sheet-security-automation</id><content type="html" xml:base="https://carolinahpinto.github.io/portfolio/blog/2026/10/python-cheat-sheet-security-automation/"><![CDATA[<p><em>Google Cybersecurity Certificate, Course 7. Built from the Course 7 reference guide plus the labs and practice questions.</em></p>

<h2 id="1-why-automate-security-tasks">1. Why automate security tasks</h2>

<ul>
  <li><strong>Saves time:</strong> the computer does repetitive jobs, like checking logs.</li>
  <li><strong>Fewer mistakes:</strong> a program runs the same steps the same way every time.</li>
  <li><strong>Faster response:</strong> it can spot problems, like many failed logins, right away.</li>
  <li><strong>More time for hard work:</strong> people can focus on complex problems.</li>
</ul>

<p>Suspicious activity Python can track:</p>

<ul>
  <li>Several failed login attempts in a short time</li>
  <li>Logins from IP addresses outside established work zones</li>
  <li>Logins outside normal work hours</li>
</ul>

<p>Python cannot track phishing that happens through in-person interactions.</p>

<h2 id="2-comments">2. Comments</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Single-line comment
</span><span class="s">"""
Multi-line comment / docstring.
Use when you need more than 79 characters.
"""</span>
</code></pre></div></div>

<h2 id="3-conditional-statements">3. Conditional statements</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="n">device_id</span> <span class="o">!=</span> <span class="s">"la858zn"</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"unknown device"</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">status</span> <span class="o">==</span> <span class="mi">500</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"server error"</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"ok"</span><span class="p">)</span>
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">if</code> starts the check. <code class="language-plaintext highlighter-rouge">elif</code> runs only if earlier conditions were False. <code class="language-plaintext highlighter-rouge">else</code> runs only if all earlier conditions were False.</li>
  <li>The keyword is <code class="language-plaintext highlighter-rouge">elif</code>, not <code class="language-plaintext highlighter-rouge">elsif</code>.</li>
  <li>Every <code class="language-plaintext highlighter-rouge">if</code>, <code class="language-plaintext highlighter-rouge">elif</code>, <code class="language-plaintext highlighter-rouge">else</code>, <code class="language-plaintext highlighter-rouge">for</code>, <code class="language-plaintext highlighter-rouge">while</code> and <code class="language-plaintext highlighter-rouge">def</code> line ends with a colon, and the code inside is indented.</li>
</ul>

<p><strong>Logical operators</strong></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="n">username</span> <span class="o">==</span> <span class="s">"bmoreno"</span> <span class="ow">and</span> <span class="n">login_attempts</span> <span class="o">&lt;</span> <span class="mi">5</span><span class="p">:</span>   <span class="c1"># both must be True
</span><span class="k">if</span> <span class="n">status</span> <span class="o">==</span> <span class="mi">100</span> <span class="ow">or</span> <span class="n">status</span> <span class="o">==</span> <span class="mi">102</span><span class="p">:</span>                 <span class="c1"># at least one True
</span><span class="k">if</span> <span class="ow">not</span> <span class="n">account_status</span> <span class="o">==</span> <span class="s">"removed"</span><span class="p">:</span>                <span class="c1"># flips True/False
</span><span class="k">if</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">approved_list</span><span class="p">:</span>                          <span class="c1"># membership check
</span></code></pre></div></div>

<p>Comparison operators: <code class="language-plaintext highlighter-rouge">==</code> equal, <code class="language-plaintext highlighter-rouge">!=</code> not equal, <code class="language-plaintext highlighter-rouge">&lt;</code> <code class="language-plaintext highlighter-rouge">&gt;</code> <code class="language-plaintext highlighter-rouge">&lt;=</code> <code class="language-plaintext highlighter-rouge">&gt;=</code></p>

<p><code class="language-plaintext highlighter-rouge">=</code> assigns a value. <code class="language-plaintext highlighter-rouge">==</code> compares two values.</p>

<h2 id="4-loops-iterative-statements">4. Loops (iterative statements)</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># for loop: go through a sequence
</span><span class="k">for</span> <span class="n">username</span> <span class="ow">in</span> <span class="p">[</span><span class="s">"bmoreno"</span><span class="p">,</span> <span class="s">"tshah"</span><span class="p">,</span> <span class="s">"elarson"</span><span class="p">]:</span>
    <span class="k">print</span><span class="p">(</span><span class="n">username</span><span class="p">)</span>

<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>   <span class="c1"># i = 0, 1, ... 9
</span>    <span class="k">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>

<span class="c1"># while loop: repeat while a condition is True
</span><span class="k">while</span> <span class="n">login_attempts</span> <span class="o">&lt;</span> <span class="mi">5</span><span class="p">:</span>
    <span class="n">login_attempts</span> <span class="o">=</span> <span class="n">login_attempts</span> <span class="o">+</span> <span class="mi">1</span>
</code></pre></div></div>

<ul>
  <li><strong>for loop:</strong> does the same action a set number of times, based on a sequence (a list of IP addresses, log entries, and so on).</li>
  <li><strong>while loop:</strong> repeats based on a condition. Something inside must change the condition, or it never ends.</li>
  <li><code class="language-plaintext highlighter-rouge">break</code> exits the loop completely. <code class="language-plaintext highlighter-rouge">continue</code> skips to the next iteration.</li>
  <li><code class="language-plaintext highlighter-rouge">range(start, stop, step)</code>: start is included, stop is excluded. Defaults are start = 0 and step = 1, so <code class="language-plaintext highlighter-rouge">range(5)</code> gives 0 to 4.</li>
</ul>

<h2 id="5-counter-pattern-loop--conditional--counter">5. Counter pattern (loop + conditional + counter)</h2>

<p>Example: count systems that need updates.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">systems</span> <span class="o">=</span> <span class="p">[</span><span class="s">"OS 1"</span><span class="p">,</span> <span class="s">"OS 2"</span><span class="p">,</span> <span class="s">"OS 3"</span><span class="p">,</span> <span class="s">"OS 4"</span><span class="p">]</span>
<span class="n">needs_update</span> <span class="o">=</span> <span class="p">[</span><span class="s">"OS 2"</span><span class="p">,</span> <span class="s">"OS 4"</span><span class="p">]</span>
<span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>

<span class="k">for</span> <span class="n">system</span> <span class="ow">in</span> <span class="n">systems</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">system</span> <span class="ow">in</span> <span class="n">needs_update</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="n">system</span><span class="p">,</span> <span class="s">"needs an update"</span><span class="p">)</span>
        <span class="n">count</span> <span class="o">=</span> <span class="n">count</span> <span class="o">+</span> <span class="mi">1</span>

<span class="k">print</span><span class="p">(</span><span class="s">"Total systems needing updates:"</span><span class="p">,</span> <span class="n">count</span><span class="p">)</span>
</code></pre></div></div>

<ul>
  <li>The loop checks every item.</li>
  <li>The <code class="language-plaintext highlighter-rouge">if</code> decides whether the item matches.</li>
  <li>The counter adds 1 each time it does.</li>
</ul>

<h2 id="6-user-defined-functions">6. User-defined functions</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">greet_employee</span><span class="p">():</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Welcome"</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">calculate_fails</span><span class="p">(</span><span class="n">total_attempts</span><span class="p">,</span> <span class="n">failed_attempts</span><span class="p">):</span>
    <span class="n">fail_percentage</span> <span class="o">=</span> <span class="n">failed_attempts</span> <span class="o">/</span> <span class="n">total_attempts</span>
    <span class="k">return</span> <span class="n">fail_percentage</span>   <span class="c1"># exits the function and sends back a value
</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">calculate_fails</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span>
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">def</code> defines a function. Names inside the parentheses are parameters.</li>
  <li>Define a function before you call it.</li>
  <li><code class="language-plaintext highlighter-rouge">return</code> sends a value back and ends the function.</li>
  <li>Benefit of a function: you write the steps once and reuse them with different inputs.</li>
</ul>

<h2 id="7-built-in-functions">7. Built-in functions</h2>

<table>
  <thead>
    <tr>
      <th>Function</th>
      <th>What it does</th>
      <th>Example</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">print()</code></td>
      <td>Outputs to the screen</td>
      <td><code class="language-plaintext highlighter-rouge">print("login success")</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">type()</code></td>
      <td>Returns the data type</td>
      <td><code class="language-plaintext highlighter-rouge">type(51.1)</code> gives <code class="language-plaintext highlighter-rouge">float</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">range()</code></td>
      <td>Generates a sequence of numbers</td>
      <td><code class="language-plaintext highlighter-rouge">range(0, 5, 1)</code> gives 0,1,2,3,4</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">max()</code></td>
      <td>Largest value</td>
      <td><code class="language-plaintext highlighter-rouge">max(10, 15, 5)</code> gives 15</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">min()</code></td>
      <td>Smallest value</td>
      <td><code class="language-plaintext highlighter-rouge">min(10, 15, 5)</code> gives 5</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">sorted()</code></td>
      <td>Sorts a list (smallest to largest, or A to Z)</td>
      <td><code class="language-plaintext highlighter-rouge">sorted([10, 15, 5])</code> gives <code class="language-plaintext highlighter-rouge">[5, 10, 15]</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">str()</code></td>
      <td>Converts to a string</td>
      <td><code class="language-plaintext highlighter-rouge">str(10)</code> gives <code class="language-plaintext highlighter-rouge">"10"</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">len()</code></td>
      <td>Number of elements or characters</td>
      <td><code class="language-plaintext highlighter-rouge">len("security")</code> gives 8</td>
    </tr>
  </tbody>
</table>

<h2 id="8-importing-modules-and-libraries">8. Importing modules and libraries</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">statistics</span>                      <span class="c1"># whole module
</span><span class="kn">from</span> <span class="nn">statistics</span> <span class="kn">import</span> <span class="n">mean</span>            <span class="c1"># one function
</span><span class="kn">from</span> <span class="nn">statistics</span> <span class="kn">import</span> <span class="n">mean</span><span class="p">,</span> <span class="n">median</span>
</code></pre></div></div>

<h2 id="9-string-methods">9. String methods</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">"Security"</span><span class="p">.</span><span class="n">upper</span><span class="p">()</span>      <span class="c1"># "SECURITY"
</span><span class="s">"Security"</span><span class="p">.</span><span class="n">lower</span><span class="p">()</span>      <span class="c1"># "security"
</span><span class="s">"Security"</span><span class="p">.</span><span class="n">index</span><span class="p">(</span><span class="s">"c"</span><span class="p">)</span>   <span class="c1"># 2 (first occurrence)
</span></code></pre></div></div>

<h2 id="10-list-methods">10. List methods</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">users</span> <span class="o">=</span> <span class="p">[</span><span class="s">"elarson"</span><span class="p">,</span> <span class="s">"fgarcia"</span><span class="p">,</span> <span class="s">"tshah"</span><span class="p">]</span>
<span class="n">users</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s">"wjaffrey"</span><span class="p">)</span>   <span class="c1"># add at index 2
</span><span class="n">users</span><span class="p">.</span><span class="n">remove</span><span class="p">(</span><span class="s">"elarson"</span><span class="p">)</span>       <span class="c1"># remove first match
</span><span class="n">users</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="s">"btang"</span><span class="p">)</span>         <span class="c1"># add to the end
</span><span class="n">users</span><span class="p">.</span><span class="n">index</span><span class="p">(</span><span class="s">"tshah"</span><span class="p">)</span>          <span class="c1"># find index of first match
</span></code></pre></div></div>

<h2 id="11-working-with-strings-and-lists">11. Working with strings and lists</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Concatenation with +
</span><span class="n">device_id</span> <span class="o">=</span> <span class="s">"IT"</span> <span class="o">+</span> <span class="s">"nwp12"</span>                                <span class="c1"># "ITnwp12"
</span><span class="n">users</span> <span class="o">=</span> <span class="p">[</span><span class="s">"elarson"</span><span class="p">,</span> <span class="s">"bmoreno"</span><span class="p">]</span> <span class="o">+</span> <span class="p">[</span><span class="s">"tshah"</span><span class="p">,</span> <span class="s">"btang"</span><span class="p">]</span>       <span class="c1"># combined list
</span>
<span class="c1"># Bracket notation (indexing and slicing)
</span><span class="s">"h32rb17"</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>          <span class="c1"># "h" (indexes start at 0)
</span><span class="s">"h32rb17"</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">3</span><span class="p">]</span>        <span class="c1"># "h32" (start included, end excluded)
</span><span class="n">username_list</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>      <span class="c1"># third element of a list
</span><span class="n">username_list</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>     <span class="c1"># last element of a list
</span></code></pre></div></div>

<p><strong>Index rule:</strong> a list with 5 items has indexes 0 to 4. Using index 5 raises an <code class="language-plaintext highlighter-rouge">IndexError</code>.</p>

<h2 id="12-regular-expressions">12. Regular expressions</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">re</span>
<span class="n">re</span><span class="p">.</span><span class="n">findall</span><span class="p">(</span><span class="n">pattern</span><span class="p">,</span> <span class="n">string</span><span class="p">)</span>   <span class="c1"># returns a list of all matches
</span></code></pre></div></div>

<p>Example string: <code class="language-plaintext highlighter-rouge">"a53-32c .E"</code></p>

<table>
  <thead>
    <tr>
      <th>Symbol</th>
      <th>Matches</th>
      <th>Result</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">a53</code></td>
      <td>The literal text</td>
      <td><code class="language-plaintext highlighter-rouge">["a53"]</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">\w</code></td>
      <td>Any alphanumeric character or underscore</td>
      <td><code class="language-plaintext highlighter-rouge">["a","5","3","3","2","c","E"]</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">.</code></td>
      <td>Any character, including symbols</td>
      <td>every character</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">\d</code></td>
      <td>A single digit</td>
      <td><code class="language-plaintext highlighter-rouge">["5","3","3","2"]</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">\s</code></td>
      <td>A single whitespace</td>
      <td><code class="language-plaintext highlighter-rouge">[" "]</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">\.</code></td>
      <td>A literal period</td>
      <td><code class="language-plaintext highlighter-rouge">["."]</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">+</code></td>
      <td>One or more of the previous character</td>
      <td><code class="language-plaintext highlighter-rouge">\w+</code> gives <code class="language-plaintext highlighter-rouge">["a53","32c","E"]</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">*</code></td>
      <td>Zero or more of the previous character</td>
      <td><code class="language-plaintext highlighter-rouge">\w*</code> also returns empty matches</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">{n}</code></td>
      <td>Exactly n of the previous character</td>
      <td><code class="language-plaintext highlighter-rouge">\w{3}</code> gives <code class="language-plaintext highlighter-rouge">["a53","32c"]</code></td>
    </tr>
  </tbody>
</table>

<h2 id="13-file-operations">13. File operations</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Read
</span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"login_attempts.txt"</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">file_text</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>   <span class="c1"># whole file as one string
</span>
<span class="c1"># Write (overwrites existing content)
</span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"update_log.txt"</span><span class="p">,</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="nb">file</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="s">"new content"</span><span class="p">)</span>

<span class="c1"># Append (adds to the end)
</span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"access_log.txt"</span><span class="p">,</span> <span class="s">"a"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="nb">file</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="s">"jrafael"</span><span class="p">)</span>
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>Mode</th>
      <th>Meaning</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">"r"</code></td>
      <td>Read</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">"w"</code></td>
      <td>Write (replaces contents, or creates the file if it doesn’t exist)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">"a"</code></td>
      <td>Append (adds to the end)</td>
    </tr>
  </tbody>
</table>

<p><strong>What <code class="language-plaintext highlighter-rouge">with open("ip_addresses.txt", "r") as file:</code> does</strong></p>

<ul>
  <li>Opens the file in read mode (it does not create it or write to it).</li>
  <li>Stores the file object in the variable <code class="language-plaintext highlighter-rouge">file</code> while inside the <code class="language-plaintext highlighter-rouge">with</code> block.</li>
  <li>Closes the file automatically when the block ends, even if an error happens.</li>
</ul>

<p><strong>Other file notes</strong></p>

<ul>
  <li>Syntax is <code class="language-plaintext highlighter-rouge">open(filename, mode)</code>. The filename comes first.</li>
  <li><code class="language-plaintext highlighter-rouge">.read()</code> is called on the file object and returns a string.</li>
  <li><code class="language-plaintext highlighter-rouge">.write()</code> writes a string to the file.</li>
  <li>Common security log formats: <code class="language-plaintext highlighter-rouge">.txt</code> and <code class="language-plaintext highlighter-rouge">.csv</code>. (Not <code class="language-plaintext highlighter-rouge">.jpeg</code> or <code class="language-plaintext highlighter-rouge">.gif</code>.)</li>
  <li>Security information is often found in log files, so file skills matter for automation.</li>
  <li><code class="language-plaintext highlighter-rouge">.write()</code> adds no new line by itself. If an appended entry runs into the last line, use <code class="language-plaintext highlighter-rouge">file.write("\n" + entry)</code>.</li>
</ul>

<h2 id="14-parsing">14. Parsing</h2>

<p>Parsing means converting data into a format that is easier to read and work with, such as turning a string into a list.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># split(): string to list
</span><span class="s">"wjaffrey jsoto abernard"</span><span class="p">.</span><span class="n">split</span><span class="p">()</span>          <span class="c1"># splits on whitespace
</span><span class="s">"elarson,bmoreno,tshah"</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">","</span><span class="p">)</span>         <span class="c1"># splits on a comma (the delimiter)
</span>
<span class="c1"># join(): list to string
</span><span class="s">","</span><span class="p">.</span><span class="n">join</span><span class="p">([</span><span class="s">"elarson"</span><span class="p">,</span> <span class="s">"bmoreno"</span><span class="p">,</span> <span class="s">"tshah"</span><span class="p">])</span>  <span class="c1"># "elarson,bmoreno,tshah"
</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">ip_list</span><span class="p">)</span>                         <span class="c1"># one item per line
</span></code></pre></div></div>

<p><strong>Splitting a log entry</strong></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">log_entry</span> <span class="o">=</span> <span class="s">"jrafael,192.168.243.140,4:56:27,2022-05-09"</span>
<span class="n">pieces</span> <span class="o">=</span> <span class="n">log_entry</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">","</span><span class="p">)</span>
<span class="c1"># ['jrafael', '192.168.243.140', '4:56:27', '2022-05-09']
</span><span class="n">pieces</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>   <span class="c1"># the IP address
</span></code></pre></div></div>

<ul>
  <li>For a whole log file, split the text into lines first, then split each line by commas.</li>
  <li><code class="language-plaintext highlighter-rouge">.split()</code> and <code class="language-plaintext highlighter-rouge">.join()</code> are string methods. Call them on a string: <code class="language-plaintext highlighter-rouge">ip_addresses.split()</code>, not <code class="language-plaintext highlighter-rouge">split.ip_addresses()</code>.</li>
</ul>

<h2 id="15-workflow-read-a-log-parse-it-filter-it">15. Workflow: read a log, parse it, filter it</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"logs.txt"</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">log_text</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>

<span class="n">logins</span> <span class="o">=</span> <span class="n">log_text</span><span class="p">.</span><span class="n">split</span><span class="p">()</span>        <span class="c1"># string to list
</span><span class="n">failed_logins</span> <span class="o">=</span> <span class="p">[]</span>

<span class="k">for</span> <span class="n">login</span> <span class="ow">in</span> <span class="n">logins</span><span class="p">:</span>             <span class="c1"># loop through each item
</span>    <span class="k">if</span> <span class="s">"failed"</span> <span class="ow">in</span> <span class="n">login</span><span class="p">:</span>        <span class="c1"># check a condition
</span>        <span class="n">failed_logins</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">login</span><span class="p">)</span>
</code></pre></div></div>

<p>This pattern uses a <code class="language-plaintext highlighter-rouge">for</code> loop, an <code class="language-plaintext highlighter-rouge">if</code> statement and <code class="language-plaintext highlighter-rouge">.split()</code>. Add a counter only if the task asks you to count.</p>

<h2 id="16-algorithm-update-an-allow-list">16. Algorithm: update an allow list</h2>

<p>Goal: remove IP addresses on a remove list from a file of allowed IP addresses.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">import_file</span> <span class="o">=</span> <span class="s">"allow_list.txt"</span>
<span class="n">remove_list</span> <span class="o">=</span> <span class="p">[</span><span class="s">"192.168.97.225"</span><span class="p">,</span> <span class="s">"192.168.158.170"</span><span class="p">]</span>

<span class="c1"># 1. Read the file into a string
</span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">import_file</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">ip_addresses</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>

<span class="c1"># 2. Convert the string to a list
</span><span class="n">ip_addresses</span> <span class="o">=</span> <span class="n">ip_addresses</span><span class="p">.</span><span class="n">split</span><span class="p">()</span>

<span class="c1"># 3. Loop through the remove list
</span><span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">remove_list</span><span class="p">:</span>
    <span class="c1"># 4. Only remove if it is in the allow list
</span>    <span class="k">if</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">ip_addresses</span><span class="p">:</span>
        <span class="n">ip_addresses</span><span class="p">.</span><span class="n">remove</span><span class="p">(</span><span class="n">element</span><span class="p">)</span>

<span class="c1"># 5. Convert the list back to a string
</span><span class="n">ip_addresses</span> <span class="o">=</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">ip_addresses</span><span class="p">)</span>

<span class="c1"># 6. Write the result over the original file
</span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">import_file</span><span class="p">,</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="nb">file</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">ip_addresses</span><span class="p">)</span>
</code></pre></div></div>

<p><strong>Same algorithm as a reusable function</strong></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">update_file</span><span class="p">(</span><span class="n">import_file</span><span class="p">,</span> <span class="n">remove_list</span><span class="p">):</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">import_file</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
        <span class="n">ip_addresses</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
    <span class="n">ip_addresses</span> <span class="o">=</span> <span class="n">ip_addresses</span><span class="p">.</span><span class="n">split</span><span class="p">()</span>
    <span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">remove_list</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">ip_addresses</span><span class="p">:</span>
            <span class="n">ip_addresses</span><span class="p">.</span><span class="n">remove</span><span class="p">(</span><span class="n">element</span><span class="p">)</span>
    <span class="n">ip_addresses</span> <span class="o">=</span> <span class="s">" "</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">ip_addresses</span><span class="p">)</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">import_file</span><span class="p">,</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
        <span class="nb">file</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">ip_addresses</span><span class="p">)</span>

<span class="n">update_file</span><span class="p">(</span><span class="s">"allow_list.txt"</span><span class="p">,</span> <span class="p">[</span><span class="s">"192.168.25.60"</span><span class="p">,</span> <span class="s">"192.168.140.81"</span><span class="p">])</span>
</code></pre></div></div>

<p><strong>Why each step</strong></p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">.read()</code> gets the file text so Python can work with it.</li>
  <li><code class="language-plaintext highlighter-rouge">.split()</code> makes a list so each IP address can be removed on its own.</li>
  <li>The <code class="language-plaintext highlighter-rouge">for</code> loop checks each address on the remove list.</li>
  <li>The <code class="language-plaintext highlighter-rouge">if element in ip_addresses</code> check prevents an error, because <code class="language-plaintext highlighter-rouge">.remove()</code> fails if the item is not in the list.</li>
  <li>Using <code class="language-plaintext highlighter-rouge">.remove()</code> this way works because there are no duplicates in the list.</li>
  <li><code class="language-plaintext highlighter-rouge">.join()</code> turns the list back into a string, which <code class="language-plaintext highlighter-rouge">.write()</code> needs.</li>
  <li>Mode <code class="language-plaintext highlighter-rouge">"w"</code> replaces the old file contents with the updated list.</li>
</ul>

<p><strong>Creating a new file:</strong> open it with <code class="language-plaintext highlighter-rouge">"w"</code> and write a string to it.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"allow_list.txt"</span><span class="p">,</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="nb">file</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">ip_addresses</span><span class="p">)</span>
</code></pre></div></div>

<p><em>See this algorithm in my <a href="/portfolio/projects/python-allow-list/">IP allow list project</a>.</em></p>

<h2 id="17-debugging">17. Debugging</h2>

<p>Debugging is the practice of identifying and fixing errors in code.</p>

<p><strong>Types of errors</strong></p>

<table>
  <thead>
    <tr>
      <th>Error type</th>
      <th>What it is</th>
      <th>Example</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Syntax error</td>
      <td>Breaks Python’s rules, so the code won’t run</td>
      <td>Missing colon, missing quote or comma, unbalanced parentheses, <code class="language-plaintext highlighter-rouge">=</code> instead of <code class="language-plaintext highlighter-rouge">==</code>, <code class="language-plaintext highlighter-rouge">elsif</code> instead of <code class="language-plaintext highlighter-rouge">elif</code></td>
    </tr>
    <tr>
      <td>Exception</td>
      <td>An error that happens while the code runs</td>
      <td><code class="language-plaintext highlighter-rouge">IndexError</code>, <code class="language-plaintext highlighter-rouge">NameError</code>, <code class="language-plaintext highlighter-rouge">IndentationError</code></td>
    </tr>
    <tr>
      <td>Logic error</td>
      <td>Code runs but gives the wrong result, with no error message</td>
      <td>Wrong list index, missing <code class="language-plaintext highlighter-rouge">else</code>, wrong operator</td>
    </tr>
  </tbody>
</table>

<p><strong>Common exceptions</strong></p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">NameError</code>: using a variable or function that doesn’t exist, often a typo (<code class="language-plaintext highlighter-rouge">username_list</code> instead of <code class="language-plaintext highlighter-rouge">usernames_list</code>).</li>
  <li><code class="language-plaintext highlighter-rouge">IndexError</code>: list index out of range (<code class="language-plaintext highlighter-rouge">usernames_list[5]</code> on a 5-item list).</li>
  <li><code class="language-plaintext highlighter-rouge">IndentationError</code>: code that should be indented under <code class="language-plaintext highlighter-rouge">if</code>, <code class="language-plaintext highlighter-rouge">for</code>, <code class="language-plaintext highlighter-rouge">with</code> or <code class="language-plaintext highlighter-rouge">def</code> is not.</li>
  <li><code class="language-plaintext highlighter-rouge">SyntaxError: unexpected EOF while parsing</code>: the code ends early, such as a <code class="language-plaintext highlighter-rouge">with</code> or <code class="language-plaintext highlighter-rouge">for</code> line with no body, or an unclosed parenthesis.</li>
</ul>

<p><strong>Debugging tips</strong></p>

<ul>
  <li>Read the error message. It gives the error type and the line number.</li>
  <li>Fix one error at a time, and run the code after each fix. Some errors only appear after the earlier ones are fixed.</li>
  <li>Logic errors give no warning. Test different input values and check the output.</li>
  <li>Place <code class="language-plaintext highlighter-rouge">print()</code> statements in and around a function to see values at each step.</li>
</ul>

<p><strong>Fixes from the lab</strong></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>                                  <span class="c1"># add the missing colon
</span>    <span class="k">print</span><span class="p">(</span><span class="s">"Connection cannot be established"</span><span class="p">)</span>

<span class="n">usernames</span> <span class="o">=</span> <span class="p">[</span><span class="s">"tbailey"</span><span class="p">,</span> <span class="s">"zdutchma"</span><span class="p">,</span> <span class="s">"esmith"</span><span class="p">]</span>        <span class="c1"># close the quote, add the comma
</span>
<span class="k">print</span><span class="p">(</span><span class="s">"update needed"</span><span class="p">.</span><span class="n">upper</span><span class="p">())</span>                       <span class="c1"># close the parenthesis
</span>
<span class="k">for</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">usernames_list</span><span class="p">:</span>                          <span class="c1"># spell the variable correctly
</span>    <span class="k">if</span> <span class="n">name</span> <span class="o">==</span> <span class="n">username</span><span class="p">:</span>                             <span class="c1"># == to compare
</span>        <span class="k">print</span><span class="p">(</span><span class="s">"The user is an approved user"</span><span class="p">)</span>        <span class="c1"># indent under the if
</span>
<span class="k">if</span> <span class="n">username</span> <span class="o">==</span> <span class="n">usernames_list</span><span class="p">[</span><span class="mi">4</span><span class="p">]:</span>                    <span class="c1"># last of 5 items (or use [-1])
</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">import_file</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>                 <span class="c1"># add the colon
</span><span class="n">ip_addresses</span> <span class="o">=</span> <span class="n">ip_addresses</span><span class="p">.</span><span class="n">split</span><span class="p">()</span>                  <span class="c1"># call split on the string
</span>
<span class="c1"># Logic error: match each OS to the right index
</span><span class="k">if</span> <span class="n">system</span> <span class="o">==</span> <span class="s">"OS 1"</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Patch date:"</span><span class="p">,</span> <span class="n">patch_schedule</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="k">elif</span> <span class="n">system</span> <span class="o">==</span> <span class="s">"OS 2"</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Patch date:"</span><span class="p">,</span> <span class="n">patch_schedule</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="k">elif</span> <span class="n">system</span> <span class="o">==</span> <span class="s">"OS 3"</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Patch date:"</span><span class="p">,</span> <span class="n">patch_schedule</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
</code></pre></div></div>

<p><strong>Missing else example</strong></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">check_user</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">name</span> <span class="o">==</span> <span class="s">"jhill"</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"user flagged"</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"user okay"</span><span class="p">)</span>
</code></pre></div></div>

<h2 id="18-common-mistakes-checklist">18. Common mistakes checklist</h2>

<ul>
  <li>Forgetting the colon after <code class="language-plaintext highlighter-rouge">if</code>, <code class="language-plaintext highlighter-rouge">elif</code>, <code class="language-plaintext highlighter-rouge">else</code>, <code class="language-plaintext highlighter-rouge">for</code>, <code class="language-plaintext highlighter-rouge">while</code>, <code class="language-plaintext highlighter-rouge">def</code> and <code class="language-plaintext highlighter-rouge">with</code>.</li>
  <li>Mixing up <code class="language-plaintext highlighter-rouge">=</code> (assign) and <code class="language-plaintext highlighter-rouge">==</code> (compare).</li>
  <li>Typing <code class="language-plaintext highlighter-rouge">elsif</code> instead of <code class="language-plaintext highlighter-rouge">elif</code>.</li>
  <li>Off-by-one errors: indexes start at 0, and slice and <code class="language-plaintext highlighter-rouge">range()</code> end values are excluded.</li>
  <li>Calling a function before it is defined.</li>
  <li>Using <code class="language-plaintext highlighter-rouge">open("r", "logs.txt")</code>. The filename goes first, then the mode.</li>
  <li>Forgetting that <code class="language-plaintext highlighter-rouge">.split()</code> with no argument splits on whitespace.</li>
  <li>Using <code class="language-plaintext highlighter-rouge">"w"</code> when you meant <code class="language-plaintext highlighter-rouge">"a"</code>. Write mode erases the existing contents.</li>
  <li>Forgetting to convert a list back to a string with <code class="language-plaintext highlighter-rouge">.join()</code> before <code class="language-plaintext highlighter-rouge">.write()</code>.</li>
</ul>

<h2 id="19-quick-answers">19. Quick answers</h2>

<ul>
  <li>Types of errors while debugging: syntax errors, logic errors, exceptions.</li>
  <li>Program sends data to the wrong place but runs fine: logic error.</li>
  <li>Error message about an unknown index: exception (<code class="language-plaintext highlighter-rouge">IndexError</code>).</li>
  <li>Same action a set number of times over a sequence: <code class="language-plaintext highlighter-rouge">for</code> loop.</li>
  <li>Log file formats: <code class="language-plaintext highlighter-rouge">.txt</code>, <code class="language-plaintext highlighter-rouge">.csv</code>.</li>
  <li>String to list: <code class="language-plaintext highlighter-rouge">.split()</code>. List to string: <code class="language-plaintext highlighter-rouge">.join()</code>.</li>
  <li>Read / append / write: <code class="language-plaintext highlighter-rouge">"r"</code> / <code class="language-plaintext highlighter-rouge">"a"</code> / <code class="language-plaintext highlighter-rouge">"w"</code>.</li>
</ul>]]></content><author><name>Carolina Pinto</name></author><category term="Python" /><category term="python" /><category term="cheatsheet" /><category term="automation" /><category term="regex" /><category term="debugging" /><summary type="html"><![CDATA[Everything from Course 7 of the Google Cybersecurity Certificate in one place: conditionals, loops, functions, regex, files, parsing and debugging.]]></summary></entry><entry><title type="html">Network Security 101: Locks, Rooms, and Guards</title><link href="https://carolinahpinto.github.io/portfolio/blog/2026/10/network-security-101/" rel="alternate" type="text/html" title="Network Security 101: Locks, Rooms, and Guards" /><published>2026-10-08T00:00:00-04:00</published><updated>2026-10-08T00:00:00-04:00</updated><id>https://carolinahpinto.github.io/portfolio/blog/2026/10/network-security-101</id><content type="html" xml:base="https://carolinahpinto.github.io/portfolio/blog/2026/10/network-security-101/"><![CDATA[<p><em>No tech degree required.</em></p>

<p>If you’ve ever felt lost when someone starts talking about firewalls, VLANs, and WAFs, you’re not alone. Network security sounds intimidating, but honestly, most of it maps to things we already understand from everyday life. Let’s break it down.</p>

<h2 id="the-firewall-your-buildings-security-guard">The Firewall: Your Building’s Security Guard</h2>

<p>Picture an office building with a security guard at the front door. Every person who walks in gets checked — do they have a badge? Are they on the approved list? Should they be let through, or turned away?</p>

<p>That’s exactly what a <strong>firewall</strong> does for a network. It sits at the edge, inspecting all the traffic trying to come in or go out, and it decides what’s allowed and what gets blocked based on a set of rules.</p>

<p>But here’s the important nuance: a firewall isn’t just a single “yes or no” checkpoint. It’s constantly making decisions based on things like where traffic is coming from, what port or service it’s trying to reach, and whether it matches patterns that look suspicious. Think of the guard not just checking a badge once, but also noting: “Wait, why is this person trying to enter through the loading dock at 3 AM instead of the front door during business hours?” Without that guard, anyone — including people with bad intentions — could just walk right into your network, poke around, and cause damage.</p>

<h2 id="network-segmentation-locked-rooms-inside-the-building">Network Segmentation: Locked Rooms Inside the Building</h2>

<p>Okay, so the guard let some people into the building — maybe they’re employees, maybe they’re delivery drivers with legitimate business there. But you probably don’t want the delivery driver wandering into the HR office or the server room, right?</p>

<p>This is where <strong>network segmentation</strong> comes in. Instead of one big open floor plan where everyone can go anywhere, you divide the building into separate locked rooms. In networking terms, this is often done with <strong>VLANs</strong> (virtual dividers within the same physical network), <strong>subnets</strong> (smaller sub-networks), or <strong>internal firewalls</strong> placed between segments, not just at the edge.</p>

<p>Why does this matter so much? Because in real-world breaches, attackers rarely get everything in one shot. They usually get a small foothold first — maybe by tricking one employee into clicking a bad link — and then try to move sideways through the network to find something valuable, like a database of customer records. This sideways movement is called <strong>lateral movement</strong>, and it’s exactly what segmentation is designed to stop.</p>

<p>If the network is one big open room, a single compromised laptop can become a highway straight to the crown jewels. But if that laptop is stuck in its own segmented “room,” the attacker hits a locked door. They’d need to break through another layer of security just to keep going, which buys time for the security team to notice and respond, and often stops the attack cold.</p>

<p>Segmentation also lets organizations apply different levels of security to different areas — the “room” holding financial records can have much stricter rules than the “room” for guest Wi-Fi.</p>

<h2 id="putting-it-into-action-a-real-threat-scenario">Putting It Into Action: A Real Threat Scenario</h2>

<p>Let’s make this concrete. Imagine an attacker is trying to break into a company’s web application by exploiting a known software vulnerability — kind of like someone finding a specific weak lock they know how to pick, based on a flaw the manufacturer hasn’t fixed yet.</p>

<p>A regular firewall might not catch this, because the traffic looks like normal web traffic on the surface — it’s going to the right port, using the right protocol, nothing obviously “blocked” about it. What you need is a <strong>Web Application Firewall (WAF)</strong> — think of it as a specialist guard who doesn’t just check IDs at the door, but actually understands the specific tricks people use to pick that particular lock.</p>

<p>A WAF inspects the actual content of web traffic — the data typed into a web form, the parameters in a URL, the structure of a request — looking for known attack patterns. Two common examples:</p>

<ul>
  <li><strong>SQL injection:</strong> where an attacker sneaks malicious database commands into an input field, tricking the application into revealing or altering data it shouldn’t.</li>
  <li><strong>Cross-site scripting (XSS):</strong> where an attacker injects malicious code that runs in other users’ browsers when they visit the site.</li>
</ul>

<p>Because the WAF operates at the application layer rather than just the network layer, it can catch these tricks that a standard firewall would completely miss, blocking them before they ever reach the vulnerable application.</p>

<h2 id="the-takeaway">The Takeaway</h2>

<p>Network security isn’t one tool doing everything — it’s layers working together, each covering a gap the others leave open:</p>

<ul>
  <li><strong>Firewalls</strong> guard the front door, controlling who gets in and out at the network’s edge.</li>
  <li><strong>Segmentation</strong> keeps intruders contained if they do get inside, limiting how far damage can spread.</li>
  <li><strong>Specialized tools like WAFs</strong> defend specific weak points, like web applications, that general-purpose tools aren’t built to inspect closely.</li>
</ul>

<p>None of this requires deep technical wizardry to understand. Once you see it as guards, locked rooms, and specialists, the whole picture clicks into place — and honestly, thinking about your own home or workplace security this way makes the “why” behind these tools a lot more intuitive.</p>]]></content><author><name>Carolina Pinto</name></author><category term="Networking" /><category term="firewalls" /><category term="segmentation" /><category term="waf" /><category term="network security" /><summary type="html"><![CDATA[Firewalls, network segmentation and web application firewalls, explained with no tech degree required.]]></summary></entry><entry><title type="html">Learning Python, Week Three: I Stopped Typing the Same Line Four Times</title><link href="https://carolinahpinto.github.io/portfolio/blog/2026/10/python-loops/" rel="alternate" type="text/html" title="Learning Python, Week Three: I Stopped Typing the Same Line Four Times" /><published>2026-10-01T00:00:00-04:00</published><updated>2026-10-01T00:00:00-04:00</updated><id>https://carolinahpinto.github.io/portfolio/blog/2026/10/python-loops</id><content type="html" xml:base="https://carolinahpinto.github.io/portfolio/blog/2026/10/python-loops/"><![CDATA[<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0 I stopped typing the same line four times
1 I stopped typing the same line four times
2 I stopped typing the same line four times
3 I stopped typing the same line four times
</code></pre></div></div>

<p>Loops were the first thing in Python that made me feel like the computer was actually working for me. Here is what finally made them click.</p>

<p>While learning how to check login attempts without writing the same few lines four times over, I ran into <strong>iterative statements</strong> — most people just call them <strong>loops</strong>. A loop is code that runs the same set of instructions repeatedly, so you write it once and let the computer handle the repetition instead of typing it out by hand.</p>

<p>Depending on what you tell it, a loop might run zero times, four times, or keep going until something changes. There are two kinds you will meet first: <code class="language-plaintext highlighter-rouge">for</code> loops and <code class="language-plaintext highlighter-rouge">while</code> loops. They solve slightly different problems, and knowing which is which is most of the battle.</p>

<h2 id="for-loops-when-you-know-what-you-are-looping-through">For loops: when you know what you are looping through</h2>

<p>Use a <code class="language-plaintext highlighter-rouge">for</code> loop when you already have a sequence in hand. A list of usernames, a list of assets, the characters in a word. You are saying: go through these, one at a time, and do this thing to each one.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="p">[</span><span class="s">"elarson"</span><span class="p">,</span> <span class="s">"bmoreno"</span><span class="p">,</span> <span class="s">"tshah"</span><span class="p">,</span> <span class="s">"sgilmore"</span><span class="p">]:</span>
    <span class="k">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</code></pre></div></div>

<p>What it prints:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>elarson
bmoreno
tshah
sgilmore
</code></pre></div></div>

<p>Two lines. Four usernames. That first line is the <strong>loop header</strong>, and it has four parts worth naming, because being able to name them is what lets you fix your own mistakes later:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">for</code> starts the loop.</li>
  <li><code class="language-plaintext highlighter-rouge">i</code> is the <strong>loop variable</strong>. It holds one item at a time. On the first pass it is <code class="language-plaintext highlighter-rouge">"elarson"</code>, on the second it is <code class="language-plaintext highlighter-rouge">"bmoreno"</code>, and so on.</li>
  <li><code class="language-plaintext highlighter-rouge">in</code> comes right before the sequence you are looping through.</li>
  <li><strong>The colon</strong> at the end. Forget it and Python stops and complains. I forgot it constantly.</li>
</ul>

<p>Everything underneath is the <strong>loop body</strong>, and it has to be indented further than the header. That indentation is not decoration. It is how Python knows which lines belong to the loop. This is the other mistake I made every day for a week.</p>

<p>The loop variable can be named anything. Naming it something meaningful makes the code read like a sentence:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">computer_assets</span> <span class="o">=</span> <span class="p">[</span><span class="s">"laptop1"</span><span class="p">,</span> <span class="s">"desktop20"</span><span class="p">,</span> <span class="s">"smartphone03"</span><span class="p">]</span>
<span class="k">for</span> <span class="n">asset</span> <span class="ow">in</span> <span class="n">computer_assets</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="n">asset</span><span class="p">)</span>
</code></pre></div></div>

<p>What it prints:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>laptop1
desktop20
smartphone03
</code></pre></div></div>

<p>“For asset in computer assets, print asset.” You can almost read it out loud. If you are heading toward security work, this is the shape of a lot of real tasks: you have a list of devices, or IP addresses, or employees, and you need to check each one against something.</p>

<p>Strings work too, which surprised me. Loop over a string and you get one character at a time:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">string</span> <span class="o">=</span> <span class="s">"security"</span>
<span class="k">for</span> <span class="n">character</span> <span class="ow">in</span> <span class="n">string</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="n">character</span><span class="p">)</span>
</code></pre></div></div>

<p>What it prints:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>s
e
c
u
r
i
t
y
</code></pre></div></div>

<h2 id="when-you-just-want-to-repeat-something-n-times">When you just want to repeat something N times</h2>

<p>Sometimes there is no list. You just want to do something ten times. That is what <code class="language-plaintext highlighter-rouge">range()</code> is for: it generates a sequence of numbers on demand. You give it a start, a stop, and how much to count by.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">1</span><span class="p">):</span>
    <span class="k">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</code></pre></div></div>

<p>What it prints:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0
1
2
3
4
</code></pre></div></div>

<p>Look at that output again. You asked for 0 to 5 and got 0 through 4. This is the thing that tripped me up hardest: <strong>the start is included, the stop is not.</strong> The loop stops one short of the number you named. It feels wrong until you have been bitten by it once, and then it never feels wrong again.</p>

<p>The start and the step have defaults of 0 and 1, so if that is what you want, you can leave them out. This does exactly the same thing as the version above:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
    <span class="k">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</code></pre></div></div>

<p>The stop point is the one you always have to write. If you want to start somewhere other than 0, or count by something other than 1, spell those out.</p>

<h2 id="while-loops-when-you-do-not-know-how-many-times">While loops: when you do not know how many times</h2>

<p>A <code class="language-plaintext highlighter-rouge">while</code> loop does not walk through a sequence. It keeps going as long as a condition is true, and stops the moment that condition becomes false. You use it when the number of repetitions depends on what happens.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">i</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">while</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">5</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
    <span class="n">i</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span>
</code></pre></div></div>

<p>What it prints:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1
2
3
4
</code></pre></div></div>

<p>Notice the difference from a <code class="language-plaintext highlighter-rouge">for</code> loop. There is no loop variable in the header. You create <code class="language-plaintext highlighter-rouge">i</code> yourself on the line before, and then <strong>you are responsible for changing it inside the loop</strong>. That last line, <code class="language-plaintext highlighter-rouge">i = i + 1</code>, is the loop’s off switch. Leave it out and <code class="language-plaintext highlighter-rouge">i</code> stays at 1 forever, the condition stays true forever, and your program never stops.</p>

<p>Counting is the common case. Say you want to track login attempts:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">login_attempts</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">while</span> <span class="n">login_attempts</span> <span class="o">&lt;</span> <span class="mi">5</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Login attempts:"</span><span class="p">,</span> <span class="n">login_attempts</span><span class="p">)</span>
    <span class="n">login_attempts</span> <span class="o">=</span> <span class="n">login_attempts</span> <span class="o">+</span> <span class="mi">1</span>
</code></pre></div></div>

<p>What it prints:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Login attempts: 0
Login attempts: 1
Login attempts: 2
Login attempts: 3
Login attempts: 4
</code></pre></div></div>

<p>Five lines, ending at 4. Same off-by-one feeling as <code class="language-plaintext highlighter-rouge">range()</code>, same reason: the check happens before each pass, and once the count hits 5 the condition is false and the loop is done.</p>

<p>The condition does not have to be a number. It can be a <code class="language-plaintext highlighter-rouge">True</code> or <code class="language-plaintext highlighter-rouge">False</code> value that something else in the loop flips:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">login_status</span> <span class="o">=</span> <span class="bp">True</span>
<span class="k">while</span> <span class="n">login_status</span> <span class="o">==</span> <span class="bp">True</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Try again."</span><span class="p">)</span>
    <span class="n">count</span> <span class="o">=</span> <span class="n">count</span> <span class="o">+</span> <span class="mi">1</span>
    <span class="k">if</span> <span class="n">count</span> <span class="o">==</span> <span class="mi">4</span><span class="p">:</span>
        <span class="n">login_status</span> <span class="o">=</span> <span class="bp">False</span>
</code></pre></div></div>

<p>What it prints:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Try again.
Try again.
Try again.
Try again.
</code></pre></div></div>

<p>This one runs an indeterminate number of times as far as the header is concerned. It keeps going until something inside decides to turn the switch off. That is the real personality of a <code class="language-plaintext highlighter-rouge">while</code> loop.</p>

<h2 id="two-words-that-give-you-an-escape-hatch">Two words that give you an escape hatch</h2>

<p>Once your loops are running, you will want more control than “do this to every single item.” Two keywords handle almost everything, and both live inside an <code class="language-plaintext highlighter-rouge">if</code> statement in the loop body.</p>

<h3 id="break-stops-the-whole-loop"><code class="language-plaintext highlighter-rouge">break</code> stops the whole loop</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">computer_assets</span> <span class="o">=</span> <span class="p">[</span><span class="s">"laptop1"</span><span class="p">,</span> <span class="s">"desktop20"</span><span class="p">,</span> <span class="s">"smartphone03"</span><span class="p">]</span>
<span class="k">for</span> <span class="n">asset</span> <span class="ow">in</span> <span class="n">computer_assets</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">asset</span> <span class="o">==</span> <span class="s">"desktop20"</span><span class="p">:</span>
        <span class="k">break</span>
    <span class="k">print</span><span class="p">(</span><span class="n">asset</span><span class="p">)</span>
</code></pre></div></div>

<p>What it prints:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>laptop1
</code></pre></div></div>

<p>The loop reaches <code class="language-plaintext highlighter-rouge">"desktop20"</code> on the second pass and walks out entirely. <code class="language-plaintext highlighter-rouge">"smartphone03"</code> never gets a turn, even though it was sitting right there in the list.</p>

<h3 id="continue-skips-one-and-keeps-going"><code class="language-plaintext highlighter-rouge">continue</code> skips one and keeps going</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">computer_assets</span> <span class="o">=</span> <span class="p">[</span><span class="s">"laptop1"</span><span class="p">,</span> <span class="s">"desktop20"</span><span class="p">,</span> <span class="s">"smartphone03"</span><span class="p">]</span>
<span class="k">for</span> <span class="n">asset</span> <span class="ow">in</span> <span class="n">computer_assets</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">asset</span> <span class="o">==</span> <span class="s">"desktop20"</span><span class="p">:</span>
        <span class="k">continue</span>
    <span class="k">print</span><span class="p">(</span><span class="n">asset</span><span class="p">)</span>
</code></pre></div></div>

<p>What it prints:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>laptop1
smartphone03
</code></pre></div></div>

<p>Same list, same condition, one word different. <code class="language-plaintext highlighter-rouge">"desktop20"</code> gets skipped, and the loop carries on to the next item. I remember it as: <strong><code class="language-plaintext highlighter-rouge">break</code> leaves the building, <code class="language-plaintext highlighter-rouge">continue</code> skips the meeting.</strong></p>

<h2 id="about-the-loop-that-never-ends">About the loop that never ends</h2>

<p>You will write one. Everyone does. An <strong>infinite loop</strong> is a loop whose condition never becomes false, usually because you forgot to change the variable it depends on. Your program just sits there, or floods the screen, and nothing you click helps.</p>

<p>Press <strong>Ctrl-C</strong> (or Ctrl-Z) to stop it. That is it. That is the whole fix. It is not a crash and you have not broken anything.</p>

<p>Worth knowing: infinite loops are not always a bug. A web server or a monitoring service is often a loop that is supposed to run until someone shuts it down. The difference is whether you meant it.</p>

<h2 id="the-three-mistakes-i-kept-making">The three mistakes I kept making</h2>

<ul>
  <li><strong>Missing the colon.</strong> The loop header ends with <code class="language-plaintext highlighter-rouge">:</code>. Every time. Python’s error message for this is more helpful than it looks once you know what you are looking at.</li>
  <li><strong>Wrong indentation.</strong> If the body is not indented past the header, Python does not know it belongs to the loop. If a line is indented when it should not be, it runs on every pass instead of once at the end.</li>
  <li><strong>Forgetting to increment.</strong> Only a <code class="language-plaintext highlighter-rouge">while</code> loop problem, and only ever solved by Ctrl-C and a sigh.</li>
</ul>

<h2 id="where-this-leaves-you">Where this leaves you</h2>

<p>The short version: reach for a <code class="language-plaintext highlighter-rouge">for</code> loop when you have a sequence to go through or a fixed number of repetitions, and a <code class="language-plaintext highlighter-rouge">while</code> loop when you are waiting for a condition to change. Use <code class="language-plaintext highlighter-rouge">break</code> to leave early and <code class="language-plaintext highlighter-rouge">continue</code> to skip an item.</p>

<p>If you are learning this for security work, this is genuinely a large chunk of the job. Checking a list of devices against an approved list, going through log entries one at a time, stopping as soon as you find the thing you were looking for. It is all loops. The syntax stops feeling strange faster than you would expect, and then you get to spend your attention on the actual problem instead of on typing the same line four times.</p>

<p><strong>Best way to make any of this stick:</strong> open a Python file and retype these examples by hand instead of copying them. Then break one on purpose and read what Python tells you.</p>]]></content><author><name>Carolina Pinto</name></author><category term="Python" /><category term="python" /><category term="loops" /><category term="automation" /><category term="beginners" /><summary type="html"><![CDATA[For loops, while loops, range(), break and continue, and the three mistakes I kept making.]]></summary></entry><entry><title type="html">Why Your Computer’s “Diary” Matters More Than You Think: A Beginner’s Guide to Logs</title><link href="https://carolinahpinto.github.io/portfolio/blog/2026/09/understanding-logs/" rel="alternate" type="text/html" title="Why Your Computer’s “Diary” Matters More Than You Think: A Beginner’s Guide to Logs" /><published>2026-09-24T00:00:00-04:00</published><updated>2026-09-24T00:00:00-04:00</updated><id>https://carolinahpinto.github.io/portfolio/blog/2026/09/understanding-logs</id><content type="html" xml:base="https://carolinahpinto.github.io/portfolio/blog/2026/09/understanding-logs/"><![CDATA[<p>Ever wonder how IT and security teams figure out exactly what happened when something goes wrong? Like, how do they know that someone logged into a system at 2am from a weird location, or that malware tried to sneak past a firewall? The answer is simpler than you’d think: <strong>logs</strong>.</p>

<p>Let’s break down what logs are, why they matter, and how to actually read them — without the jargon overload.</p>

<h2 id="logs-are-basically-a-diary-for-your-devices">Logs Are Basically a Diary for Your Devices</h2>

<p>Think about it this way: every time something happens on your phone, laptop, or a company’s server — a login, an error, a file getting deleted — the system writes it down. That written record is a log, and each individual entry is like one diary entry describing a single event.</p>

<p>Originally, logs were just for troubleshooting. Your app crashed? Check the error log to see what went wrong. But today, logs do so much more — especially in security. When something suspicious happens, security analysts dig through logs to answer the same questions a detective would ask: who did it, what happened, when, where, and why.</p>

<p>Security teams usually don’t dig through logs on individual devices one by one (imagine how exhausting that would be). Instead, they use <strong>SIEM tools</strong> — think of these as a big filing cabinet that pulls in logs from everywhere in the organization into one central place, so analysts can search through everything at once.</p>

<h2 id="not-all-logs-are-created-equal">Not All Logs Are Created Equal</h2>

<p>Just like your diary might have entries about school, work, and your weekend plans, organizations generate different types of logs depending on what’s producing them:</p>

<ul>
  <li><strong>Network logs</strong> — from routers, firewalls, switches (the “traffic cops” of your network)</li>
  <li><strong>System logs</strong> — from the operating system itself (Windows, macOS, Linux)</li>
  <li><strong>Application logs</strong> — from specific software, like a banking app logging when you check your balance</li>
  <li><strong>Security logs</strong> — from antivirus or intrusion detection tools</li>
  <li><strong>Authentication logs</strong> — literally just “who logged in, and when”</li>
</ul>

<p>Here’s a simple authentication log entry:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Login Event [05:45:15] User1 Authenticated successfully
</code></pre></div></div>

<p>Nice and short. But you can also crank up the detail with <strong>verbose logging</strong>, which is like the difference between texting “omw” versus giving someone your exact GPS coordinates, your route, and your ETA:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Login Event [2022/11/16 05:45:15.892673] auth_performer.cc:470 User1 Authenticated successfully from device1 (192.168.1.2)
</code></pre></div></div>

<p>Same event, way more context.</p>

<h2 id="the-golden-rule-dont-log-everything">The Golden Rule: Don’t Log Everything</h2>

<p>Here’s a mistake beginners (and honestly, a lot of orgs) make: thinking “more logging = better security.” Nope.</p>

<p>Imagine keeping a diary where you write down literally every single thing you do all day — every step you take, every blink. Sure, you’d technically have “all the data,” but good luck finding the one entry that actually matters when you need it. That’s basically what <strong>overlogging</strong> does. It jacks up storage costs, slows systems down, and buries the important stuff under a mountain of noise.</p>

<p>There’s also the privacy angle — things like phone numbers, emails, and names count as <strong>personally identifiable information (PII)</strong>, and depending on where you operate, you might not even be legally allowed to log that stuff without special handling.</p>

<p>And speaking of legal stuff — certain industries have rules about how long you have to keep logs around (this is called <strong>log retention</strong>). Healthcare has HIPAA, finance has PCI DSS and SOX, government has FISMA. It’s basically the compliance version of “keep your receipts for tax season.”</p>

<h2 id="protecting-the-diary-from-getting-rewritten">Protecting the Diary from Getting Rewritten</h2>

<p>Here’s a scary thought: what if a burglar broke into your house, but before leaving, they edited your diary to remove any evidence they were ever there?</p>

<p>That’s exactly what attackers try to do with logs — tamper with them to erase their tracks. That’s why storing logs on a <strong>centralized server</strong>, separate from the original device, is so important. It puts a wall between the attacker and the evidence, so even if they compromise one machine, they can’t quietly rewrite the whole story.</p>

<h2 id="okay-but-what-do-logs-actually-look-like">Okay, But What Do Logs Actually Look Like?</h2>

<p>This is where it gets fun. Logs come in different formats, kind of like how a recipe could be written as a numbered list, a paragraph, or a table — same information, different structure. Here are the five you’ll run into most.</p>

<h3 id="1-json--the-neatly-labeled-boxes-format">1. JSON — The “Neatly Labeled Boxes” Format</h3>

<p>JSON (JavaScript Object Notation) is probably the friendliest format for beginners because it’s basically labeled data. Think of it like a form with clearly marked fields:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"Alert"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Malware"</span><span class="w">
</span></code></pre></div></div>

<p>That’s a <strong>key-value pair</strong> — “Alert” is the label (key), “Malware” is the actual info (value). Add curly brackets <code class="language-plaintext highlighter-rouge">{ }</code> to group related info together (called an <strong>object</strong>), and square brackets <code class="language-plaintext highlighter-rouge">[ ]</code> when you want an ordered list (called an <strong>array</strong>):</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"User"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1234"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"user"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"role"</span><span class="p">:</span><span class="w"> </span><span class="s2">"engineer"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>It’s readable almost like plain English once you get the hang of it — no wonder it’s everywhere in web apps and cloud platforms.</p>

<h3 id="2-syslog--the-og-standard">2. Syslog — The OG Standard</h3>

<p>If JSON is the new kid, syslog is the classic that’s been around forever, especially on Unix/Linux systems. A syslog entry has three parts: a <strong>header</strong> (timestamp, hostname, app name), <strong>structured data</strong> (extra details in brackets), and a <strong>message</strong>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;236&gt;1 2022-03-21T01:11:11.003Z virtual.machine.com evntslog - ID01 [user@32473 iut="1" eventSource="Application" eventID="9999"] This is a log entry!
</code></pre></div></div>

<p>Yeah, it looks intimidating at first glance, but break it into chunks and it’s not so bad:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">&lt;236&gt;</code> = priority (lower number = more urgent, kind of like a hospital triage system)</li>
  <li>Timestamp, hostname, app name = the “who/when/where”</li>
  <li>The bracketed stuff = extra details</li>
  <li>The final sentence = the actual message</li>
</ul>

<p>Syslog is also a <em>protocol</em> (a way to ship logs to a central server) and a <em>service</em> (that does the shipping) — same name, three jobs.</p>

<h3 id="3-xml--windows-favorite">3. XML — Windows’ Favorite</h3>

<p>XML uses tags that wrap around data, like little labeled envelopes:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Event&gt;</span>
  <span class="nt">&lt;EventID&gt;</span>4688<span class="nt">&lt;/EventID&gt;</span>
  <span class="nt">&lt;Version&gt;</span>5<span class="nt">&lt;/Version&gt;</span>
<span class="nt">&lt;/Event&gt;</span>
</code></pre></div></div>

<p>Here, <code class="language-plaintext highlighter-rouge">&lt;Event&gt;</code> is the “parent,” and <code class="language-plaintext highlighter-rouge">&lt;EventID&gt;</code> and <code class="language-plaintext highlighter-rouge">&lt;Version&gt;</code> are its “children” tucked inside. Tags can also carry extra <strong>attributes</strong>, like a nametag with additional info pinned to it:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Data</span> <span class="na">Name=</span><span class="s">'SubjectUserName'</span><span class="nt">&gt;</span>JSMITH<span class="nt">&lt;/Data&gt;</span>
</code></pre></div></div>

<h3 id="4-csv--the-spreadsheet-format">4. CSV — The Spreadsheet Format</h3>

<p>CSV is exactly what it sounds like — comma-separated values, like a spreadsheet squished into one line of text. The catch? The field names often aren’t included, so you need to already know what each position means (kind of like memorizing that in a friend’s contact info, it’s always “name, phone, email” in that order, even if they never label it):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2009-11-24T21:27:09.534255,ALERT,192.168.2.7,1041,x.x.250.50,80,TCP,ALLOWED,1:2001999:9,"ET MALWARE BTGrab.com Spyware Downloading Ads",1
</code></pre></div></div>

<h3 id="5-cef--the-security-specific-format">5. CEF — The Security-Specific Format</h3>

<p>Common Event Format (CEF) is built specifically for security tools and uses pipes <code class="language-plaintext highlighter-rouge">|</code> to separate its main fields, then key-value pairs for extra details:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Sep 29 08:26:10 host CEF:1|Security|threatmanager|1.0|100|worm successfully stopped|10|src=10.0.0.2 dst=2.1.2.2 spt=1232
</code></pre></div></div>

<p>Translation: “On Sep 29 at 8:26am, a security tool called threatmanager stopped a worm from spreading from 10.0.0.2 to 2.1.2.2 through port 1232, and rated it a high-severity (10) event.” Once you know the pattern, it reads almost like a headline.</p>

<h2 id="the-takeaway">The Takeaway</h2>

<p>Logs might look like walls of confusing text at first, but they’re really just detailed diaries — and once you know the format, they tell a clear story. The real skill isn’t memorizing every format perfectly; it’s learning to recognize the pattern so you can quickly spot the who, what, when, where, and why when it actually matters.</p>]]></content><author><name>Carolina Pinto</name></author><category term="Risk &amp; Threats" /><category term="logs" /><category term="siem" /><category term="log formats" /><category term="incident response" /><summary type="html"><![CDATA[What logs are, why overlogging hurts, and how to read the five formats you'll see most: JSON, syslog, XML, CSV and CEF.]]></summary></entry></feed>